6.3 KiB
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
# 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
# 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 routinginput_event_manager.py- Keyboard/mouse input processinginput_event.py- Input event data structuresfocus_manager.py- Focus tracking across applications
Accessibility Layer (ax_ files):*
ax_object.py- Core accessible object abstractionax_utilities.py- Common accessibility utilitiesax_utilities_role.py- Role-based accessibility helpersax_utilities_collection.py- Collection traversal utilitiesax_text.py,ax_table.py,ax_component.py- Specialized interfaces
Output Systems:
speech.py,speechdispatcherfactory.py- Speech synthesisbraille.py,braille_generator.py- Braille display supportspeech_generator.py- Generate speech from accessible objectssound.py,sound_generator.py- Audio cue generation
Script System:
script_manager.py- Loads/manages application-specific scriptsscript.py- Base script classscripts/default.py- Default behavior for all applicationsscripts/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 withcthulhu_hookimpldecoratorplugin_system_manager.py- Plugin discovery and lifecycleplugins/- 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 persistencesettings.py- Default settings valuescthulhu_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/:
-
Update
src/cthulhu/meson.build- Add the.pyfile tocthulhu_python_sources -
For new script modules (e.g.,
scripts/newmodule/):- Create the directory with
__init__.pyandscript.py - Add
meson.buildin the new directory - Add subdirectory to
src/cthulhu/scripts/meson.build
- Create the directory with
-
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
- Create directory under
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:
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
# 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 preferencesCthulhu+H- Enter learn modeCthulhu+Ctrl+Alt+Shift+Q- Toggle sleep mode for current applicationCthulhu+Q- Quit Cthulhu
Self-Voicing Interface
External applications can speak through Cthulhu via Unix socket:
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