Files
cthulhu/CLAUDE.md

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 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:

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 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:

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