192 lines
6.3 KiB
Markdown
192 lines
6.3 KiB
Markdown
# CLAUDE.md
|
|
|
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
|
|
## Project Overview
|
|
|
|
Cthulhu is a fork of the Orca screen reader, designed as a desktop-agnostic screen reader for Linux. It works with applications supporting AT-SPI (Assistive Technology Service Provider Interface) including GTK+, Qt, Java Swing, LibreOffice, Gecko, and WebKitGtk.
|
|
|
|
**Key differentiators from Orca:**
|
|
- Desktop-agnostic: Works on KDE, XFCE, i3, Sway, and other environments (not just GNOME)
|
|
- Extensible plugin architecture using pluggy framework
|
|
- D-Bus remote control interface for external automation
|
|
- Enhanced support for tiling window managers
|
|
|
|
## Build Commands
|
|
|
|
```bash
|
|
# Local development build (installs to ~/.local)
|
|
./build-local.sh
|
|
|
|
# Test local installation
|
|
./test-local.sh
|
|
|
|
# Run local version
|
|
~/.local/bin/cthulhu
|
|
|
|
# Clean build artifacts and local installation
|
|
./clean-local.sh
|
|
./clean-local.sh --build-only # Clean only build artifacts
|
|
./clean-local.sh --install-only # Remove only local installation
|
|
|
|
# Manual Meson build
|
|
meson setup _build --prefix=$HOME/.local
|
|
meson compile -C _build
|
|
meson install -C _build
|
|
```
|
|
|
|
## Testing
|
|
|
|
```bash
|
|
# Run all tests
|
|
test/harness/runall.sh
|
|
|
|
# Run single test
|
|
test/harness/runone.sh <test.py> <app-name>
|
|
|
|
# App-specific tests
|
|
test/harness/runall.sh -a /path/to/app/tests
|
|
```
|
|
|
|
## Architecture Overview
|
|
|
|
### Core Components (`src/cthulhu/`)
|
|
|
|
**Event & Input Processing:**
|
|
- `event_manager.py` - Central AT-SPI event handling and routing
|
|
- `input_event_manager.py` - Keyboard/mouse input processing
|
|
- `input_event.py` - Input event data structures
|
|
- `focus_manager.py` - Focus tracking across applications
|
|
|
|
**Accessibility Layer (ax_* files):**
|
|
- `ax_object.py` - Core accessible object abstraction
|
|
- `ax_utilities.py` - Common accessibility utilities
|
|
- `ax_utilities_role.py` - Role-based accessibility helpers
|
|
- `ax_utilities_collection.py` - Collection traversal utilities
|
|
- `ax_text.py`, `ax_table.py`, `ax_component.py` - Specialized interfaces
|
|
|
|
**Output Systems:**
|
|
- `speech.py`, `speechdispatcherfactory.py` - Speech synthesis
|
|
- `braille.py`, `braille_generator.py` - Braille display support
|
|
- `speech_generator.py` - Generate speech from accessible objects
|
|
- `sound.py`, `sound_generator.py` - Audio cue generation
|
|
|
|
**Script System:**
|
|
- `script_manager.py` - Loads/manages application-specific scripts
|
|
- `script.py` - Base script class
|
|
- `scripts/default.py` - Default behavior for all applications
|
|
- `scripts/apps/` - Application-specific customizations (Firefox, LibreOffice, etc.)
|
|
- `scripts/toolkits/` - Toolkit-specific scripts (GTK, Qt, WebKitGtk)
|
|
- `scripts/web/` - Web content handling
|
|
|
|
**Plugin System:**
|
|
- `plugin.py` - Base plugin class with `cthulhu_hookimpl` decorator
|
|
- `plugin_system_manager.py` - Plugin discovery and lifecycle
|
|
- `plugins/` - Built-in plugins (OCR, Clipboard, SpeechHistory, etc.)
|
|
|
|
**D-Bus Remote Control:**
|
|
- `dbus_service.py` - D-Bus service implementation
|
|
- Service: `org.stormux.Cthulhu.Service`
|
|
- Path: `/org/stormux/Cthulhu/Service`
|
|
|
|
**Settings & State:**
|
|
- `settings_manager.py` - User preferences persistence
|
|
- `settings.py` - Default settings values
|
|
- `cthulhu_state.py` - Runtime state (active script, focus, etc.)
|
|
|
|
### Key Design Patterns
|
|
|
|
**Script Inheritance:** Application scripts extend `default.Script`, overriding methods for custom behavior. The script manager selects scripts based on the focused application.
|
|
|
|
**Event Flow:** AT-SPI events → `event_manager` → active script's event handler → generators → output systems (speech/braille)
|
|
|
|
**Plugin Hooks:** Plugins implement hooks via `@cthulhu_hookimpl` decorator. Use `registerGestureByString()` for keybindings.
|
|
|
|
## Adding New Modules
|
|
|
|
When adding new Python modules under `src/cthulhu/`:
|
|
|
|
1. **Update `src/cthulhu/meson.build`** - Add the `.py` file to `cthulhu_python_sources`
|
|
|
|
2. **For new script modules** (e.g., `scripts/newmodule/`):
|
|
- Create the directory with `__init__.py` and `script.py`
|
|
- Add `meson.build` in the new directory
|
|
- Add subdirectory to `src/cthulhu/scripts/meson.build`
|
|
|
|
3. **For new plugins**:
|
|
- Create directory under `src/cthulhu/plugins/` with:
|
|
- `__init__.py`, `plugin.py`, `plugin.info`, `meson.build`
|
|
- Add subdirectory to `src/cthulhu/plugins/meson.build`
|
|
|
|
## Plugin Structure
|
|
|
|
```
|
|
src/cthulhu/plugins/MyPlugin/
|
|
├── __init__.py # from .plugin import *
|
|
├── plugin.py # Main implementation extending Plugin
|
|
├── plugin.info # Metadata (name, version, description, etc.)
|
|
└── meson.build # install_data for .py and .info files
|
|
```
|
|
|
|
Example plugin.py:
|
|
```python
|
|
from cthulhu.plugin import Plugin, cthulhu_hookimpl
|
|
|
|
class MyPlugin(Plugin):
|
|
@cthulhu_hookimpl
|
|
def activate(self, plugin=None):
|
|
if plugin is not None and plugin is not self:
|
|
return
|
|
self.registerGestureByString(self.myHandler, "description", "kb:cthulhu+key")
|
|
|
|
def myHandler(self, script=None, inputEvent=None):
|
|
self.app.getDynamicApiManager().getAPI('CthulhuState').activeScript.presentMessage('Message')
|
|
return True
|
|
```
|
|
|
|
## D-Bus Testing
|
|
|
|
```bash
|
|
# Check service availability
|
|
busctl --user list | grep Cthulhu
|
|
|
|
# Get version
|
|
busctl --user call org.stormux.Cthulhu.Service /org/stormux/Cthulhu/Service \
|
|
org.stormux.Cthulhu.Service GetVersion
|
|
|
|
# Present message
|
|
busctl --user call org.stormux.Cthulhu.Service /org/stormux/Cthulhu/Service \
|
|
org.stormux.Cthulhu.Service PresentMessage s "Hello"
|
|
|
|
# Introspect available methods
|
|
busctl --user introspect org.stormux.Cthulhu.Service /org/stormux/Cthulhu/Service
|
|
```
|
|
|
|
## Key Keybindings
|
|
|
|
- `Cthulhu+Space` - Open preferences
|
|
- `Cthulhu+H` - Enter learn mode
|
|
- `Cthulhu+Ctrl+Alt+Shift+Q` - Toggle sleep mode for current application
|
|
- `Cthulhu+Q` - Quit Cthulhu
|
|
|
|
## Self-Voicing Interface
|
|
|
|
External applications can speak through Cthulhu via Unix socket:
|
|
```bash
|
|
echo "Hello world" | socat - UNIX-CLIENT:/tmp/cthulhu.sock
|
|
echo "<!#APPEND#!>Without interrupt" | socat - UNIX-CLIENT:/tmp/cthulhu.sock
|
|
```
|
|
|
|
## Dependencies
|
|
|
|
**Core:** Python 3.9+, pygobject-3.0, gtk+-3.0, AT-SPI2, ATK
|
|
**Speech:** python-speechd, gstreamer-1.0
|
|
**Plugins:** pluggy, python-dasbus (optional, for D-Bus)
|
|
**Braille:** BrlTTY, BrlAPI, liblouis (optional)
|
|
|
|
## Repository
|
|
|
|
- **Main repo:** https://git.stormux.org/storm/cthulhu
|
|
- **Community:** IRC #stormux on irc.stormux.org
|
|
- **Email patches:** storm_dragon@stormux.org
|