Compare commits

..

3 Commits

Author SHA1 Message Date
Storm Dragon
f01374d15e One more try before sleep. 2025-04-14 05:04:59 -04:00
Storm Dragon
0347b7feea Another attempt at fixing plugin keyboard shortcuts. 2025-04-14 04:54:48 -04:00
Storm Dragon
0580dda131 A few documentation updates. 2025-04-11 13:17:26 -04:00
5 changed files with 45 additions and 28 deletions

View File

@ -1 +0,0 @@
See http://wiki.gnome.org/Projects/Cthulhu

View File

@ -1,5 +1,10 @@
# Cthulhu # Cthulhu
## Note
If you somehow stumbled across this while looking for a desktop screen reader for Linux, you most likely want [Orca](https://orca.gnome.org/) instead. Cthulhu is currently a supplemental screen reader that fills a nitch for some advanced users. E.g. some older QT based programs may work with Cthulhu, and if you use certain window managers like i3, Mozilla applications like Firefox and Thunderbird may work better.
## Introduction ## Introduction
Cthulhu is a free, open source, flexible, and extensible screen reader Cthulhu is a free, open source, flexible, and extensible screen reader
@ -20,7 +25,7 @@ Cthulhu has the following dependencies:
* Python 3 - Python platform * Python 3 - Python platform
* pygobject-3.0 - Python bindings for the GObject library * pygobject-3.0 - Python bindings for the GObject library
* libpeas - GObject based Plugin engine * pluggy - Plugin and hook calling mechanisms for python
* gtk+-3.0 - GTK+ toolkit * gtk+-3.0 - GTK+ toolkit
* json-py - a JSON (<https://json.org/>) reader and writer in Python * json-py - a JSON (<https://json.org/>) reader and writer in Python
* python-speechd - Python bindings for Speech Dispatcher (optional) * python-speechd - Python bindings for Speech Dispatcher (optional)
@ -30,7 +35,6 @@ Cthulhu has the following dependencies:
* py-setproctitle - Python library to set the process title (optional) * py-setproctitle - Python library to set the process title (optional)
* gstreamer-1.0 - GStreamer - Streaming media framework (optional) * gstreamer-1.0 - GStreamer - Streaming media framework (optional)
* socat - Used for self-voicing functionality. * socat - Used for self-voicing functionality.
* libpeas - For the plugin system.
You are strongly encouraged to also have the latest stable versions You are strongly encouraged to also have the latest stable versions
of AT-SPI2 and ATK. of AT-SPI2 and ATK.

View File

@ -47,11 +47,9 @@ class APIHelper:
self.app = app self.app = app
self._gestureBindings = {} self._gestureBindings = {}
def registerGestureByString(self, function, name, gestureString, def registerGestureByString(self, function, name, gestureString, inputEventType='default', normalizer='cthulhu', learnModeEnabled=True, contextName=None):
inputEventType='default', normalizer='cthulhu',
learnModeEnabled=True, contextName=None):
"""Register a gesture by string. """Register a gesture by string.
Arguments: Arguments:
- function: the function to call when the gesture is performed - function: the function to call when the gesture is performed
- name: a human-readable name for this gesture - name: a human-readable name for this gesture
@ -60,23 +58,23 @@ class APIHelper:
- normalizer: the normalizer to use - normalizer: the normalizer to use
- learnModeEnabled: whether this should be available in learn mode - learnModeEnabled: whether this should be available in learn mode
- contextName: the context for this gesture (e.g., plugin name) - contextName: the context for this gesture (e.g., plugin name)
Returns the binding ID or None if registration failed Returns the binding ID or None if registration failed
""" """
if not gestureString.startswith("kb:"): if not gestureString.startswith("kb:"):
return None return None
# Extract the key portion from the gesture string # Extract the key portion from the gesture string
key = gestureString.split(":", 1)[1] key = gestureString.split(":", 1)[1]
# Handle Cthulhu modifier specially # Handle Cthulhu modifier specially
if "cthulhu+" in key.lower(): if "cthulhu+" in key.lower():
from . import keybindings from . import keybindings
key_parts = key.lower().split("+") key_parts = key.lower().split("+")
# Determine appropriate modifier mask # Determine appropriate modifier mask
modifiers = keybindings.CTHULHU_MODIFIER_MASK modifiers = keybindings.CTHULHU_MODIFIER_MASK
# Extract the final key (without modifiers) # Extract the final key (without modifiers)
final_key = key_parts[-1] final_key = key_parts[-1]
@ -87,18 +85,23 @@ class APIHelper:
modifiers = keybindings.CTHULHU_CTRL_MODIFIER_MASK modifiers = keybindings.CTHULHU_CTRL_MODIFIER_MASK
elif "alt" in key_parts: elif "alt" in key_parts:
modifiers = keybindings.CTHULHU_ALT_MODIFIER_MASK modifiers = keybindings.CTHULHU_ALT_MODIFIER_MASK
# Create a keybinding handler # Create a keybinding handler
class GestureHandler: class GestureHandler:
def __init__(self, function, description): def __init__(self, function, description):
self.function = function self.function = function
self.description = description self.description = description
def __call__(self, script, inputEvent): def __call__(self, script, inputEvent):
return self.function(script, inputEvent) try:
return function(script, inputEvent)
except Exception as e:
import logging
logging.getLogger(__name__).error(f"Error in keybinding handler: {e}")
return True
handler = GestureHandler(function, name) handler = GestureHandler(function, name)
# Register the binding with the active script # Register the binding with the active script
from . import cthulhu_state from . import cthulhu_state
if cthulhu_state.activeScript: if cthulhu_state.activeScript:
@ -108,20 +111,29 @@ class APIHelper:
keybindings.defaultModifierMask, keybindings.defaultModifierMask,
modifiers, modifiers,
handler) handler)
bindings.add(binding)
# Add the binding to the active script
bindings.add(binding)
# Store binding for later reference # Store binding for later reference
if contextName not in self._gestureBindings: if contextName not in self._gestureBindings:
self._gestureBindings[contextName] = [] self._gestureBindings[contextName] = []
self._gestureBindings[contextName].append(binding) self._gestureBindings[contextName].append(binding)
# Register key grab at the system level
grab_ids = cthulhu.addKeyGrab(binding)
# For later removal
if grab_ids:
binding._grab_ids = grab_ids
return binding return binding
return None return None
def unregisterShortcut(self, binding, contextName=None): def unregisterShortcut(self, binding, contextName=None):
"""Unregister a previously registered shortcut. """Unregister a previously registered shortcut.
Arguments: Arguments:
- binding: the binding to unregister - binding: the binding to unregister
- contextName: the context for this gesture - contextName: the context for this gesture
@ -131,11 +143,18 @@ class APIHelper:
if cthulhu_state.activeScript: if cthulhu_state.activeScript:
bindings = cthulhu_state.activeScript.getKeyBindings() bindings = cthulhu_state.activeScript.getKeyBindings()
bindings.remove(binding) bindings.remove(binding)
# Remove key grab at system level
if hasattr(binding, '_grab_ids'):
for grab_id in binding._grab_ids:
self.app.removeKeyGrab(grab_id)
# Remove from our tracking # Remove from tracking
if contextName in self._gestureBindings: if contextName in self._gestureBindings:
if binding in self._gestureBindings[contextName]: if binding in self._gestureBindings[contextName]:
self._gestureBindings[contextName].remove(binding) self._gestureBindings[contextName].remove(binding)
import gi import gi
import importlib import importlib
import os import os

View File

@ -23,5 +23,5 @@
# Fork of Orca Screen Reader (GNOME) # Fork of Orca Screen Reader (GNOME)
# Original source: https://gitlab.gnome.org/GNOME/orca # Original source: https://gitlab.gnome.org/GNOME/orca
version = "2025.04.04" version = "2025.04.14"
codeName = "testing" codeName = "testing"

View File

@ -1,9 +1,6 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# #
# Copyright (c) 2024 Stormux # Copyright (c) 2024 Stormux
# Copyright (c) 2010-2012 The Orca Team
# Copyright (c) 2012 Igalia, S.L.
# Copyright (c) 2005-2010 Sun Microsystems Inc.
# #
# This library is free software; you can redistribute it and/or # This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public # modify it under the terms of the GNU Lesser General Public
@ -20,8 +17,6 @@
# Free Software Foundation, Inc., Franklin Street, Fifth Floor, # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA. # Boston MA 02110-1301 USA.
# #
# Fork of Orca Screen Reader (GNOME)
# Original source: https://gitlab.gnome.org/GNOME/orca
"""Self Voice plugin for Cthulhu screen reader.""" """Self Voice plugin for Cthulhu screen reader."""