diff --git a/configure.ac b/configure.ac index fd91038..c303ac0 100644 --- a/configure.ac +++ b/configure.ac @@ -31,7 +31,7 @@ PKG_CHECK_MODULES([PYGOBJECT], [pygobject-3.0 >= pygobject_required_version]) PKG_CHECK_MODULES([ATSPI2], [atspi-2 >= atspi_required_version]) PKG_CHECK_MODULES([ATKBRIDGE], [atk-bridge-2.0 >= atkbridge_required_version]) PKG_CHECK_MODULES([GSTREAMER], [gstreamer-1.0], [gstreamer="yes"], [gstreamer="no"]) -PKG_CHECK_MODULES([LIBPEAS], [libpeas-1.0], [libpeas="yes"], [libpeas="no"]) +PKG_CHECK_MODULES([LIBPEAS], [libpeas-1.0]) dnl Needed programs AC_PROG_INSTALL @@ -110,6 +110,7 @@ src/cthulhu/scripts/apps/SeaMonkey/Makefile src/cthulhu/scripts/apps/smuxi-frontend-gnome/Makefile src/cthulhu/scripts/apps/Thunderbird/Makefile src/cthulhu/scripts/apps/xfwm4/Makefile +src/cthulhu/scripts/sleepmode/Makefile src/cthulhu/scripts/switcher/Makefile src/cthulhu/scripts/terminal/Makefile src/cthulhu/scripts/web/Makefile @@ -127,6 +128,7 @@ src/cthulhu/plugins/ByeCthulhu/Makefile src/cthulhu/plugins/HelloCthulhu/Makefile src/cthulhu/plugins/PluginManager/Makefile src/cthulhu/plugins/Clipboard/Makefile +src/cthulhu/plugins/DisplayVersion/Makefile src/cthulhu/plugins/HelloWorld/Makefile src/cthulhu/plugins/CapsLockHack/Makefile src/cthulhu/plugins/SelfVoice/Makefile diff --git a/src/cthulhu/cmdnames.py b/src/cthulhu/cmdnames.py index 66afd7a..f62959c 100644 --- a/src/cthulhu/cmdnames.py +++ b/src/cthulhu/cmdnames.py @@ -460,6 +460,9 @@ TOGGLE_SPEECH = _("Toggle the silencing of speech") # This string describes that command. TOGGLE_SPEECH_VERBOSITY = _("Toggle speech verbosity level") +# Translators: this string is associated with the keyboard shortcut to toggle sleepmode +TOGGLE_SLEEP_MODE = _("Toggle sleep mode") + # Translators: this string is associated with the keyboard shortcut to quit # Cthulhu. QUIT_CTHULHU = _("Quit the screen reader") diff --git a/src/cthulhu/common_keyboardmap.py b/src/cthulhu/common_keyboardmap.py index 9bcde94..3b6268f 100644 --- a/src/cthulhu/common_keyboardmap.py +++ b/src/cthulhu/common_keyboardmap.py @@ -57,6 +57,9 @@ keymap = ( ("BackSpace", defaultModifierMask, CTHULHU_MODIFIER_MASK, "bypassNextCommandHandler"), + ("q", defaultModifierMask, CTHULHU_CTRL_ALT_MODIFIER_MASK, CTHULHU_SHIFT_MODIFIER_MASK, + "toggleSleepModeHandler"), + ("q", defaultModifierMask, CTHULHU_MODIFIER_MASK, "shutdownHandler"), diff --git a/src/cthulhu/messages.py b/src/cthulhu/messages.py index ffb4f36..2187fad 100644 --- a/src/cthulhu/messages.py +++ b/src/cthulhu/messages.py @@ -2299,7 +2299,12 @@ SPOKEN_ELLIPSIS = _(" dot dot dot") START_CTHULHU = _("Cthulhu welcomes you.") # Translators: This message is presented to the user when Cthulhu is quit. -STOP_CTHULHU = _("Cthulhu lerks beneath the waves.") +STOP_CTHULHU = _("Cthulhu lurks beneath the waves.") + +# Sleep Mode +# Translators: This message is presented to the user when Cthulhu enters or leaves sleep mode. +SLEEP_MODE_ENABLED_FOR = _("Sleep mode enabled for %s") +SLEEP_MODE_DISABLED_FOR = _("Sleep mode disabled for %s") # Translators: This message means speech synthesis is not installed or working. SPEECH_UNAVAILABLE = _("Speech is unavailable.") diff --git a/src/cthulhu/plugins/DisplayVersion/DisplayVersion.plugin b/src/cthulhu/plugins/DisplayVersion/DisplayVersion.plugin new file mode 100644 index 0000000..4529805 --- /dev/null +++ b/src/cthulhu/plugins/DisplayVersion/DisplayVersion.plugin @@ -0,0 +1,6 @@ +[Plugin] +Module=DisplayVersion +Loader=python3 +Name=Display Version +Description=Announce the current version of Cthulhu +Authors=Storm Dragon diff --git a/src/cthulhu/plugins/DisplayVersion/DisplayVersion.py b/src/cthulhu/plugins/DisplayVersion/DisplayVersion.py new file mode 100644 index 0000000..406dff2 --- /dev/null +++ b/src/cthulhu/plugins/DisplayVersion/DisplayVersion.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python3 +# +# 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 +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., Franklin Street, Fifth Floor, +# Boston MA 02110-1301 USA. +# +# Fork of Orca Screen Reader (GNOME) +# Original source: https://gitlab.gnome.org/GNOME/orca + +from cthulhu import plugin + +import gi +gi.require_version('Peas', '1.0') +from gi.repository import GObject +from gi.repository import Peas +from cthulhu import cthulhuVersion + +class DisplayVersion(GObject.Object, Peas.Activatable, plugin.Plugin): + __gtype_name__ = 'displayversion' + + object = GObject.Property(type=GObject.Object) + + def __init__(self): + plugin.Plugin.__init__(self) + self._api = None + + def do_activate(self): + self._api = self.object + self.registerGestureByString( + self.speakText, + _(f'Cthulhu screen reader version {cthulhuVersion.version}-{cthulhuVersion.codeName}'), + 'kb:cthulhu+shift+v' + ) + + def do_deactivate(self): + self._api = None + + def speakText(self, script=None, inputEvent=None): + if not self._api: + return False + self._api.app.getDynamicApiManager().getAPI('CthulhuState').activeScript.presentMessage( + f'Cthulhu screen reader version {cthulhuVersion.version}-{cthulhuVersion.codeName}', + resetStyles=False + ) + return True diff --git a/src/cthulhu/plugins/DisplayVersion/Makefile.am b/src/cthulhu/plugins/DisplayVersion/Makefile.am new file mode 100644 index 0000000..0cf43a4 --- /dev/null +++ b/src/cthulhu/plugins/DisplayVersion/Makefile.am @@ -0,0 +1,7 @@ +cthulhu_python_PYTHON = \ + __init__.py \ + DisplayVersion.plugin \ + DisplayVersion.py + +cthulhu_pythondir=$(pkgpythondir)/plugins/DisplayVersion + diff --git a/src/cthulhu/plugins/DisplayVersion/__init__.py b/src/cthulhu/plugins/DisplayVersion/__init__.py new file mode 100644 index 0000000..782103c --- /dev/null +++ b/src/cthulhu/plugins/DisplayVersion/__init__.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python3 +# +# 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 +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., Franklin Street, Fifth Floor, +# Boston MA 02110-1301 USA. +# +# Fork of Orca Screen Reader (GNOME) +# Original source: https://gitlab.gnome.org/GNOME/orca + diff --git a/src/cthulhu/plugins/Makefile.am b/src/cthulhu/plugins/Makefile.am index f34a494..fc36845 100644 --- a/src/cthulhu/plugins/Makefile.am +++ b/src/cthulhu/plugins/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = Clipboard HelloWorld SelfVoice Time MouseReview Date ByeCthulhu HelloCthulhu PluginManager CapsLockHack SimplePluginSystem +SUBDIRS = Clipboard DisplayVersion HelloWorld SelfVoice Time MouseReview Date ByeCthulhu HelloCthulhu PluginManager CapsLockHack SimplePluginSystem cthulhu_pythondir=$(pkgpythondir)/plugins diff --git a/src/cthulhu/scripts/Makefile.am b/src/cthulhu/scripts/Makefile.am index 879ac6e..37b53ee 100644 --- a/src/cthulhu/scripts/Makefile.am +++ b/src/cthulhu/scripts/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = apps toolkits switcher terminal web +SUBDIRS = apps toolkits sleepmode switcher terminal web cthulhu_python_PYTHON = \ __init__.py \ diff --git a/src/cthulhu/scripts/default.py b/src/cthulhu/scripts/default.py index 5a19f7a..2b119fa 100644 --- a/src/cthulhu/scripts/default.py +++ b/src/cthulhu/scripts/default.py @@ -204,6 +204,11 @@ class Script(script.Script): Script.processBrailleCutLine, cmdnames.PROCESS_BRAILLE_CUT_LINE) + self.inputEventHandlers["toggleSleepModeHandler"] = \ + input_event.InputEventHandler( + Script.toggleSleepMode, + cmdnames.TOGGLE_SLEEP_MODE) + self.inputEventHandlers["shutdownHandler"] = \ input_event.InputEventHandler( cthulhu.quitCthulhu, @@ -732,6 +737,13 @@ class Script(script.Script): # # ######################################################################## + def toggleSleepMode(self, input_event=None): + """Toggles between sleep mode and regular mode.""" + script_manager = _scriptManager + sleepScript = script_manager.createScript("sleepmode", self.app) + script_manager.setActiveScript(sleepScript, "Sleep mode toggled") + return True + def bypassNextCommand(self, inputEvent=None): """Causes the next keyboard command to be ignored by Cthulhu and passed along to the current application. diff --git a/src/cthulhu/scripts/sleepmode/Makefile.am b/src/cthulhu/scripts/sleepmode/Makefile.am new file mode 100644 index 0000000..39c7ea1 --- /dev/null +++ b/src/cthulhu/scripts/sleepmode/Makefile.am @@ -0,0 +1,6 @@ +cthulhu_python_PYTHON = \ + __init__.py \ + script.py \ + script_utilities.py + +cthulhu_pythondir=$(pkgpythondir)/scripts/terminal diff --git a/src/cthulhu/scripts/sleepmode/__init__.py b/src/cthulhu/scripts/sleepmode/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/cthulhu/scripts/sleepmode/script.py b/src/cthulhu/scripts/sleepmode/script.py new file mode 100644 index 0000000..942bd65 --- /dev/null +++ b/src/cthulhu/scripts/sleepmode/script.py @@ -0,0 +1,216 @@ +#!/usr/bin/env python3 +# +# 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 +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., Franklin Street, Fifth Floor, +# Boston MA 02110-1301 USA. +# +# Fork of Orca Screen Reader (GNOME) +# Original source: https://gitlab.gnome.org/GNOME/orca + +"""Script for sleep mode where Cthulhu ignores events and commands.""" + +__id__ = "$Id$" +__version__ = "$Revision$" +__date__ = "$Date$" +__copyright__ = "Copyright (c) 2024 Stormux" +__license__ = "LGPL" + +import cthulhu.debug as debug +import cthulhu.scripts.default as default +import cthulhu.input_event as input_event +import cthulhu.keybindings as keybindings +import cthulhu.messages as messages +from cthulhu.ax_object import AXObject +from cthulhu.ax_utilities import AXUtilities + +class Script(default.Script): + """The sleep-mode script.""" + + def __init__(self, app): + super().__init__(app) + self.presentIfInactive = True + + def activate(self): + """Called when this script is activated.""" + tokens = ["SLEEP MODE: Activating script for", self.app] + debug.printTokens(debug.LEVEL_INFO, tokens, True) + + # Only keep the sleep mode toggle binding active + self.removeKeyGrabs() + self.addKeyGrabs() + + # Present sleep mode status + self.clearBraille() + self.presentMessage(messages.SLEEP_MODE_ENABLED_FOR % AXObject.get_name(self.app)) + + def deactivate(self): + """Called when this script is deactivated.""" + tokens = ["SLEEP MODE: De-activating script for", self.app] + debug.printTokens(debug.LEVEL_INFO, tokens, True) + self.removeKeyGrabs() + + def getKeyBindings(self): + """Only provide the key binding needed to exit sleep mode.""" + keyBindings = keybindings.KeyBindings() + + keyBindings.load([("q", keybindings.defaultModifierMask, + keybindings.CTHULHU_CTRL_ALT_MODIFIER_MASK | keybindings.SHIFT_ALT_MODIFIER_MASK, + "toggleSleepModeHandler")], + self.inputEventHandlers) + return keyBindings + + def setupInputEventHandlers(self): + """Sets up the input event handlers for sleep mode.""" + super().setupInputEventHandlers() + self.inputEventHandlers["toggleSleepModeHandler"] = \ + input_event.InputEventHandler( + Script.toggleSleepMode, + "Toggles sleep mode on/off") + + def toggleSleepMode(self, input_event=None): + """Toggles between sleep mode and regular mode.""" + script_manager = _scriptManager + script_manager.setActiveScript(script_manager.getDefaultScript(), "Sleep mode toggled") + self.presentMessage(messages.SLEEP_MODE_DISABLED_FOR % AXObject.get_name(self.app)) + return True + + def locusOfFocusChanged(self, event, oldLocusOfFocus, newLocusOfFocus): + """Handles changes of focus of interest to the script.""" + tokens = ["SLEEP MODE: focus changed from", oldLocusOfFocus, "to", newLocusOfFocus] + debug.printTokens(debug.LEVEL_INFO, tokens, True) + if oldLocusOfFocus is None and AXUtilities.is_application(AXObject.get_parent(newLocusOfFocus)): + self.clearBraille() + self.presentMessage(messages.SLEEP_MODE_ENABLED_FOR % AXObject.get_name(self.app)) + return + + msg = "SLEEP MODE: Ignoring event." + debug.printMessage(debug.LEVEL_INFO, msg, True) + + def presentKeyboardEvent(self, event): + """Prevents keyboard echo in sleep mode.""" + msg = "SLEEP MODE: Not presenting keyboard event." + debug.printMessage(debug.LEVEL_INFO, msg, True) + return True + + def updateBraille(self, obj, **args): + """Don't update braille in sleep mode.""" + msg = "SLEEP MODE: Not updating braille." + debug.printMessage(debug.LEVEL_INFO, msg, True) + + # Event handler overrides - all do nothing + def onActiveChanged(self, event): + msg = "SLEEP MODE: Ignoring event." + debug.printMessage(debug.LEVEL_INFO, msg, True) + + def onActiveDescendantChanged(self, event): + msg = "SLEEP MODE: Ignoring event." + debug.printMessage(debug.LEVEL_INFO, msg, True) + + def onBusyChanged(self, event): + msg = "SLEEP MODE: Ignoring event." + debug.printMessage(debug.LEVEL_INFO, msg, True) + + def onCaretMoved(self, event): + msg = "SLEEP MODE: Ignoring event." + debug.printMessage(debug.LEVEL_INFO, msg, True) + + def onCheckedChanged(self, event): + msg = "SLEEP MODE: Ignoring event." + debug.printMessage(debug.LEVEL_INFO, msg, True) + + def onChildrenAdded(self, event): + msg = "SLEEP MODE: Ignoring event." + debug.printMessage(debug.LEVEL_INFO, msg, True) + + def onChildrenRemoved(self, event): + msg = "SLEEP MODE: Ignoring event." + debug.printMessage(debug.LEVEL_INFO, msg, True) + + def onColumnReordered(self, event): + msg = "SLEEP MODE: Ignoring event." + debug.printMessage(debug.LEVEL_INFO, msg, True) + + def onDocumentLoadComplete(self, event): + msg = "SLEEP MODE: Ignoring event." + debug.printMessage(debug.LEVEL_INFO, msg, True) + + def onDocumentLoadStopped(self, event): + msg = "SLEEP MODE: Ignoring event." + debug.printMessage(debug.LEVEL_INFO, msg, True) + + def onDocumentReload(self, event): + msg = "SLEEP MODE: Ignoring event." + debug.printMessage(debug.LEVEL_INFO, msg, True) + + def onExpandedChanged(self, event): + msg = "SLEEP MODE: Ignoring event." + debug.printMessage(debug.LEVEL_INFO, msg, True) + + def onFocus(self, event): + msg = "SLEEP MODE: Ignoring event." + debug.printMessage(debug.LEVEL_INFO, msg, True) + + def onFocusedChanged(self, event): + msg = "SLEEP MODE: Ignoring event." + debug.printMessage(debug.LEVEL_INFO, msg, True) + + def onMouseButton(self, event): + msg = "SLEEP MODE: Ignoring event." + debug.printMessage(debug.LEVEL_INFO, msg, True) + + def onNameChanged(self, event): + msg = "SLEEP MODE: Ignoring event." + debug.printMessage(debug.LEVEL_INFO, msg, True) + + def onSelectedChanged(self, event): + msg = "SLEEP MODE: Ignoring event." + debug.printMessage(debug.LEVEL_INFO, msg, True) + + def onSelectionChanged(self, event): + msg = "SLEEP MODE: Ignoring event." + debug.printMessage(debug.LEVEL_INFO, msg, True) + + def onShowingChanged(self, event): + msg = "SLEEP MODE: Ignoring event." + debug.printMessage(debug.LEVEL_INFO, msg, True) + + def onTextAttributesChanged(self, event): + msg = "SLEEP MODE: Ignoring event." + debug.printMessage(debug.LEVEL_INFO, msg, True) + + def onTextDeleted(self, event): + msg = "SLEEP MODE: Ignoring event." + debug.printMessage(debug.LEVEL_INFO, msg, True) + + def onTextInserted(self, event): + msg = "SLEEP MODE: Ignoring event." + debug.printMessage(debug.LEVEL_INFO, msg, True) + + def onTextSelectionChanged(self, event): + msg = "SLEEP MODE: Ignoring event." + debug.printMessage(debug.LEVEL_INFO, msg, True) + + def onWindowActivated(self, event): + """Callback for window:activate accessibility events.""" + self.clearBraille() + self.presentMessage(messages.SLEEP_MODE_ENABLED_FOR % AXObject.get_name(self.app)) + + def onWindowDeactivated(self, event): + msg = "SLEEP MODE: Ignoring event." + debug.printMessage(debug.LEVEL_INFO, msg, True) diff --git a/src/cthulhu/scripts/sleepmode/script_utilities.py b/src/cthulhu/scripts/sleepmode/script_utilities.py new file mode 100644 index 0000000..13c5ee5 --- /dev/null +++ b/src/cthulhu/scripts/sleepmode/script_utilities.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python3 +# +# 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 +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., Franklin Street, Fifth Floor, +# Boston MA 02110-1301 USA. +# +# Fork of Orca Screen Reader (GNOME) +# Original source: https://gitlab.gnome.org/GNOME/orca + +"""Utilities for Sleep Mode. Helps ensure we do nothing. When nothing is done, nothing is left undone.""" + +__id__ = "$Id$" +__version__ = "$Revision$" +__date__ = "$Date$" +__copyright__ = "Copyright (c) 2024 Stormux" +__license__ = "LGPL" + +import cthulhu.debug as debug +import cthulhu.script_utilities as script_utilities + +class Utilities(script_utilities.Utilities): + """Utilities class for the sleep-mode script.""" + + def willEchoCharacter(self, event): + """Returns True if we'll echo this character.""" + + msg = "SLEEP MODE: Will not echo character." + debug.printMessage(debug.LEVEL_INFO, msg, True) + return False + + def displayRegionChanged(self, obj, start, end, mode): + """Don't track changes in sleep mode.""" + + msg = "SLEEP MODE: Will not track display changes." + debug.printMessage(debug.LEVEL_INFO, msg, True) + return False + + def shouldPresentContext(self): + """Don't present context in sleep mode.""" + + msg = "SLEEP MODE: Will not present context." + debug.printMessage(debug.LEVEL_INFO, msg, True) + return False diff --git a/src/cthulhu/settings.py b/src/cthulhu/settings.py index 5ab4f32..5952280 100644 --- a/src/cthulhu/settings.py +++ b/src/cthulhu/settings.py @@ -413,4 +413,4 @@ presentChatRoomLast = False presentLiveRegionFromInactiveTab = False # Plugins -activePlugins = ['Clipboard', 'MouseReview', 'Date', 'ByeCthulhu', 'Time', 'HelloCthulhu', 'HelloWorld', 'SelfVoice', 'PluginManager', 'SimplePluginSystem'] +activePlugins = ['Clipboard', 'DisplayVersion', 'MouseReview', 'Date', 'ByeCthulhu', 'Time', 'HelloCthulhu', 'SelfVoice', 'PluginManager', 'SimplePluginSystem']