Attempt to get pluggy working.

This commit is contained in:
Storm Dragon 2025-04-03 20:10:54 -04:00
parent 6bbe6e47fc
commit 084d4fe85f
21 changed files with 320 additions and 153 deletions

@ -46,6 +46,7 @@ AM_PATH_PYTHON(3.3)
AM_CHECK_PYMOD(gi,,,[AC_MSG_ERROR(Could not find python module: gi)]) AM_CHECK_PYMOD(gi,,,[AC_MSG_ERROR(Could not find python module: gi)])
AM_CHECK_PYMOD(json,,,[AC_MSG_ERROR(Could not find python module: json)]) AM_CHECK_PYMOD(json,,,[AC_MSG_ERROR(Could not find python module: json)])
AM_CHECK_PYMOD(pluggy,,[pluggy_available="yes"],[pluggy_available="no"])
AM_CHECK_PYMOD(brlapi,,[brlapi_available="yes"],[brlapi_available="no"]) AM_CHECK_PYMOD(brlapi,,[brlapi_available="yes"],[brlapi_available="no"])
AM_CHECK_PYMOD(speechd,,[speechd_available="yes"],[speechd_available="no"]) AM_CHECK_PYMOD(speechd,,[speechd_available="yes"],[speechd_available="no"])
AC_ARG_WITH([liblouis], AC_ARG_WITH([liblouis],
@ -168,6 +169,7 @@ if test "$have_libpeas" = "no"; then
fi fi
echo echo
echo Use pluggy: $pluggy_available
echo Use speech-dispatcher: $speechd_available echo Use speech-dispatcher: $speechd_available
echo Use brltty: $brlapi_available echo Use brltty: $brlapi_available
echo Use liblouis: $louis_available echo Use liblouis: $louis_available

@ -34,6 +34,94 @@ __copyright__ = "Copyright (c) 2004-2009 Sun Microsystems Inc." \
__license__ = "LGPL" __license__ = "LGPL"
import faulthandler import faulthandler
class APIHelper:
"""Helper class for plugin API interactions, including keybindings."""
def __init__(self, app):
"""Initialize the APIHelper.
Arguments:
- app: the Cthulhu application
"""
self.app = app
self._gestureBindings = {}
def registerGestureByString(self, function, name, gestureString,
inputEventType='default', normalizer='cthulhu',
learnModeEnabled=True, contextName=None):
"""Register a gesture by string.
Arguments:
- function: the function to call when the gesture is performed
- name: a human-readable name for this gesture
- gestureString: string representation of the gesture (e.g., 'kb:cthulhu+z')
- inputEventType: the type of input event
- normalizer: the normalizer to use
- learnModeEnabled: whether this should be available in learn mode
- contextName: the context for this gesture (e.g., plugin name)
Returns the binding ID or None if registration failed
"""
if not gestureString.startswith("kb:"):
return None
# Extract the key portion from the gesture string
key = gestureString.split(":", 1)[1]
# Handle Cthulhu modifier specially
if "cthulhu+" in key.lower():
from . import keybindings
key = key.lower().replace("cthulhu+", "")
# Create a keybinding handler
class GestureHandler:
def __init__(self, function, description):
self.function = function
self.description = description
def __call__(self, script, inputEvent):
return self.function(script, inputEvent)
handler = GestureHandler(function, name)
# Register the binding with the active script
from . import cthulhu_state
if cthulhu_state.activeScript:
bindings = cthulhu_state.activeScript.getKeyBindings()
binding = keybindings.KeyBinding(
key,
keybindings.defaultModifierMask,
keybindings.CTHULHU_MODIFIER_MASK,
handler)
bindings.add(binding)
# Store binding for later reference
if contextName not in self._gestureBindings:
self._gestureBindings[contextName] = []
self._gestureBindings[contextName].append(binding)
return binding
return None
def unregisterShortcut(self, binding, contextName=None):
"""Unregister a previously registered shortcut.
Arguments:
- binding: the binding to unregister
- contextName: the context for this gesture
"""
# Remove from script's keybindings
from . import cthulhu_state
if cthulhu_state.activeScript:
bindings = cthulhu_state.activeScript.getKeyBindings()
bindings.remove(binding)
# Remove from our tracking
if contextName in self._gestureBindings:
if binding in self._gestureBindings[contextName]:
self._gestureBindings[contextName].remove(binding)
import gi import gi
import importlib import importlib
import os import os
@ -927,6 +1015,7 @@ class Cthulhu(GObject.Object):
self.dynamicApiManager = dynamic_api_manager.DynamicApiManager(self) self.dynamicApiManager = dynamic_api_manager.DynamicApiManager(self)
self.translationManager = translation_manager.TranslationManager(self) self.translationManager = translation_manager.TranslationManager(self)
self.debugManager = debug self.debugManager = debug
self.APIHelper = APIHelper(self)
self.createCompatAPI() self.createCompatAPI()
self.pluginSystemManager = plugin_system_manager.PluginSystemManager(self) self.pluginSystemManager = plugin_system_manager.PluginSystemManager(self)
def getAPIHelper(self): def getAPIHelper(self):
@ -986,6 +1075,7 @@ class Cthulhu(GObject.Object):
# cthulhu lets say, special compat handling.... # cthulhu lets say, special compat handling....
self.getDynamicApiManager().registerAPI('EmitRegionChanged', emitRegionChanged) self.getDynamicApiManager().registerAPI('EmitRegionChanged', emitRegionChanged)
self.getDynamicApiManager().registerAPI('LoadUserSettings', loadUserSettings) self.getDynamicApiManager().registerAPI('LoadUserSettings', loadUserSettings)
self.getDynamicApiManager().registerAPI('APIHelper', self.APIHelper)
cthulhuApp = Cthulhu() cthulhuApp = Cthulhu()

@ -193,7 +193,7 @@ class CthulhuSetupGUI(cthulhu_gtkbuilder.GtkBuilderWrapper):
# ***** Key Bindings treeview initialization ***** # ***** Key Bindings treeview initialization *****
self.keyBindView = self.get_widget("keyBindingsTreeview") self.keyBindView = self.get_widget("keyBindingsTreeview")
if self.keyBindView.get_columns(): if self.keyBindView.get_columns():
for column in self.keyBindView.get_columns(): for column in self.keyBindView.get_columns():
self.keyBindView.remove_column(column) self.keyBindView.remove_column(column)
@ -337,7 +337,7 @@ class CthulhuSetupGUI(cthulhu_gtkbuilder.GtkBuilderWrapper):
column.set_resizable(True) column.set_resizable(True)
column.set_sort_column_id(EDITABLE) column.set_sort_column_id(EDITABLE)
self.keyBindView.append_column(column) self.keyBindView.append_column(column)
# Populates the treeview with all the keybindings: # Populates the treeview with all the keybindings:
# #
self._populateKeyBindings() self._populateKeyBindings()
@ -582,7 +582,7 @@ class CthulhuSetupGUI(cthulhu_gtkbuilder.GtkBuilderWrapper):
self.get_widget("rateScale").set_value(rate) self.get_widget("rateScale").set_value(rate)
else: else:
self.get_widget("rateScale").set_value(50.0) self.get_widget("rateScale").set_value(50.0)
pitch = self._getPitchForVoiceType(voiceType) pitch = self._getPitchForVoiceType(voiceType)
if pitch is not None: if pitch is not None:
self.get_widget("pitchScale").set_value(pitch) self.get_widget("pitchScale").set_value(pitch)
@ -1150,7 +1150,7 @@ class CthulhuSetupGUI(cthulhu_gtkbuilder.GtkBuilderWrapper):
grid = self.get_widget('flashMessageDurationGrid') grid = self.get_widget('flashMessageDurationGrid')
grid.set_sensitive(not checkbox.get_active()) grid.set_sensitive(not checkbox.get_active())
self.prefsDict["flashIsPersistent"] = checkbox.get_active() self.prefsDict["flashIsPersistent"] = checkbox.get_active()
def textAttributeSpokenToggled(self, cell, path, model): def textAttributeSpokenToggled(self, cell, path, model):
"""The user has toggled the state of one of the text attribute """The user has toggled the state of one of the text attribute
checkboxes to be spoken. Update our model to reflect this, then checkboxes to be spoken. Update our model to reflect this, then
@ -1596,7 +1596,7 @@ class CthulhuSetupGUI(cthulhu_gtkbuilder.GtkBuilderWrapper):
elif dateFormat == messages.DATE_FORMAT_ABBREVIATED_YMD: elif dateFormat == messages.DATE_FORMAT_ABBREVIATED_YMD:
indexdate = DATE_FORMAT_ABBREVIATED_YMD indexdate = DATE_FORMAT_ABBREVIATED_YMD
combobox2.set_active (indexdate) combobox2.set_active (indexdate)
combobox3 = self.get_widget("timeFormatCombo") combobox3 = self.get_widget("timeFormatCombo")
self.populateComboBox(combobox3, self.populateComboBox(combobox3,
[sdtime(messages.TIME_FORMAT_LOCALE, ltime()), [sdtime(messages.TIME_FORMAT_LOCALE, ltime()),
@ -1757,7 +1757,7 @@ class CthulhuSetupGUI(cthulhu_gtkbuilder.GtkBuilderWrapper):
prefs["enableEchoByWord"]) prefs["enableEchoByWord"])
self.get_widget("enableEchoBySentenceCheckButton").set_active( \ self.get_widget("enableEchoBySentenceCheckButton").set_active( \
prefs["enableEchoBySentence"]) prefs["enableEchoBySentence"])
# Text attributes pane. # Text attributes pane.
# #
self._createTextAttributesTreeView() self._createTextAttributesTreeView()
@ -1785,7 +1785,7 @@ class CthulhuSetupGUI(cthulhu_gtkbuilder.GtkBuilderWrapper):
self.get_widget("generalDesktopButton").set_active(True) self.get_widget("generalDesktopButton").set_active(True)
else: else:
self.get_widget("generalLaptopButton").set_active(True) self.get_widget("generalLaptopButton").set_active(True)
combobox = self.get_widget("sayAllStyle") combobox = self.get_widget("sayAllStyle")
self.populateComboBox(combobox, [guilabels.SAY_ALL_STYLE_LINE, self.populateComboBox(combobox, [guilabels.SAY_ALL_STYLE_LINE,
guilabels.SAY_ALL_STYLE_SENTENCE]) guilabels.SAY_ALL_STYLE_SENTENCE])
@ -2748,7 +2748,7 @@ class CthulhuSetupGUI(cthulhu_gtkbuilder.GtkBuilderWrapper):
elif dateFormatCombo == DATE_FORMAT_ABBREVIATED_YMD: elif dateFormatCombo == DATE_FORMAT_ABBREVIATED_YMD:
newFormat = messages.DATE_FORMAT_ABBREVIATED_YMD newFormat = messages.DATE_FORMAT_ABBREVIATED_YMD
self.prefsDict["presentDateFormat"] = newFormat self.prefsDict["presentDateFormat"] = newFormat
def timeFormatChanged(self, widget): def timeFormatChanged(self, widget):
"""Signal handler for the "changed" signal for the timeFormat """Signal handler for the "changed" signal for the timeFormat
GtkComboBox widget. Set the 'timeFormat' preference to the GtkComboBox widget. Set the 'timeFormat' preference to the

@ -66,7 +66,7 @@ class DynamicApiManager():
def getAPI(self, key, application = '', fallback = True): def getAPI(self, key, application = '', fallback = True):
# get dynamic API # get dynamic API
api = None api = None
try: try:
api = self.api[application][key] api = self.api[application][key]
return api return api
@ -83,5 +83,5 @@ class DynamicApiManager():
api = self.api[application][''] api = self.api[application]['']
except: except:
print('API Key: "{}/{}" not found,'.format(application, key)) print('API Key: "{}/{}" not found,'.format(application, key))
return api return api

@ -44,7 +44,7 @@ CTHULHU_SHIFT_MODIFIER_MASK = keybindings.CTHULHU_SHIFT_MODIFIER_MASK
CTHULHU_CTRL_MODIFIER_MASK = keybindings.CTHULHU_CTRL_MODIFIER_MASK CTHULHU_CTRL_MODIFIER_MASK = keybindings.CTHULHU_CTRL_MODIFIER_MASK
keymap = ( keymap = (
("9", defaultModifierMask, CTHULHU_MODIFIER_MASK, ("9", defaultModifierMask, CTHULHU_MODIFIER_MASK,
"routePointerToItemHandler"), "routePointerToItemHandler"),

@ -19,6 +19,12 @@ try:
except ImportError: except ImportError:
# Fallback if pluggy is not available # Fallback if pluggy is not available
def cthulhu_hookimpl(func=None, **kwargs): def cthulhu_hookimpl(func=None, **kwargs):
"""Fallback decorator when pluggy is not available.
This is a no-op decorator that returns the original function.
It allows the code to continue working without pluggy, though
plugins will be disabled.
"""
if func is None: if func is None:
return lambda f: f return lambda f: f
return func return func

@ -270,6 +270,9 @@ class PluginSystemManager:
plugin_instance = plugin_class() plugin_instance = plugin_class()
pluginInfo.instance = plugin_instance pluginInfo.instance = plugin_instance
# Ensure plugins have a reference to the app
plugin_instance.app = self.getApp()
if hasattr(plugin_instance, 'set_app'): if hasattr(plugin_instance, 'set_app'):
plugin_instance.set_app(self.getApp()) plugin_instance.set_app(self.getApp())

@ -1,6 +0,0 @@
[Plugin]
Module=ByeCthulhu
Loader=python3
Name=Stop announcement for cthulhu
Description=Test plugin for cthulhu
Authors=Chrys chrys@linux-a11y.org

@ -1,52 +0,0 @@
#!/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
import time
class ByeCthulhu(GObject.Object, Peas.Activatable, plugin.Plugin):
#__gtype_name__ = 'ByeCthulhu'
object = GObject.Property(type=GObject.Object)
def __init__(self):
plugin.Plugin.__init__(self)
def do_activate(self):
API = self.object
self.connectSignal("stop-application-completed", self.process)
def do_deactivate(self):
API = self.object
def do_update_state(self):
API = self.object
def process(self, app):
messages = app.getDynamicApiManager().getAPI('Messages')
activeScript = app.getDynamicApiManager().getAPI('CthulhuState').activeScript
activeScript.presentationInterrupt()
activeScript.presentMessage(messages.STOP_CTHULHU, resetStyles=False)

@ -1,7 +1,7 @@
cthulhu_python_PYTHON = \ cthulhu_python_PYTHON = \
__init__.py \ __init__.py \
ByeCthulhu.plugin \ plugin.info \
ByeCthulhu.py plugin.py
cthulhu_pythondir=$(pkgpythondir)/plugins/ByeCthulhu cthulhu_pythondir=$(pkgpythondir)/plugins/ByeCthulhu

@ -0,0 +1,8 @@
name = Bye Cthulhu
version = 1.0.0
description = Says goodbye when Cthulhu is shutting down
authors = Stormux <storm_dragon@stormux.org>
website = https://stormux.org
copyright = Copyright 2025
builtin = false
hidden = false

@ -0,0 +1,74 @@
#!/usr/bin/env python3
#
# Copyright (c) 2025 Stormux
#
# 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.
"""Bye Cthulhu plugin for Cthulhu."""
import logging
import time
from cthulhu.plugin import Plugin, cthulhu_hookimpl
logger = logging.getLogger(__name__)
class ByeCthulhu(Plugin):
"""Plugin that speaks a goodbye message when Cthulhu is shutting down."""
def __init__(self, *args, **kwargs):
"""Initialize the plugin."""
super().__init__(*args, **kwargs)
logger.info("ByeCthulhu plugin initialized")
self._signal_handler_id = None
@cthulhu_hookimpl
def activate(self, plugin=None):
"""Activate the plugin."""
# Skip if this activation call isn't for us
if plugin is not None and plugin is not self:
return
logger.info("Activating ByeCthulhu plugin")
try:
# Connect to the stop-application-completed signal
signal_manager = self.app.getSignalManager()
self._signal_handler_id = signal_manager.connectSignal(
"stop-application-completed",
self.process
)
except Exception as e:
logger.error(f"Error activating ByeCthulhu plugin: {e}")
@cthulhu_hookimpl
def deactivate(self, plugin=None):
"""Deactivate the plugin."""
# Skip if this deactivation call isn't for us
if plugin is not None and plugin is not self:
return
logger.info("Deactivating ByeCthulhu plugin")
try:
# Disconnect signal if we have an ID
if self._signal_handler_id is not None:
signal_manager = self.app.getSignalManager()
signal_manager.disconnectSignal(
"stop-application-completed",
self._signal_handler_id
)
self._signal_handler_id = None
except Exception as e:
logger.error(f"Error deactivating ByeCthulhu plugin: {e}")
def process(self, app):
"""Process the stop-application-completed signal."""
try:
messages = app.getDynamicApiManager().getAPI('Messages')
state = app.getDynamicApiManager().getAPI('CthulhuState')
if state.activeScript:
state.activeScript.presentationInterrupt()
state.activeScript.presentMessage(messages.STOP_CTHULHU, resetStyles=False)
except Exception as e:
logger.error(f"Error in ByeCthulhu process: {e}")

@ -1,6 +0,0 @@
[Plugin]
Module=DisplayVersion
Loader=python3
Name=Display Version
Description=Announce the current version of Cthulhu
Authors=Storm Dragon <storm_dragon@stormux.org>

@ -1,61 +0,0 @@
#!/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

@ -1,7 +1,7 @@
cthulhu_python_PYTHON = \ cthulhu_python_PYTHON = \
__init__.py \ __init__.py \
DisplayVersion.plugin \ plugin.info \
DisplayVersion.py plugin.py
cthulhu_pythondir=$(pkgpythondir)/plugins/DisplayVersion cthulhu_pythondir=$(pkgpythondir)/plugins/DisplayVersion

@ -0,0 +1,8 @@
name = Display Version
version = 1.0.0
description = Announces the Cthulhu version with Cthulhu+Shift+V
authors = Stormux <storm_dragon@stormux.org>
website = https://stormux.org
copyright = Copyright 2025
builtin = false
hidden = false

@ -0,0 +1,68 @@
#!/usr/bin/env python3
#
# Copyright (c) 2025 Stormux
#
# 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.
"""Display Version plugin for Cthulhu."""
import logging
from cthulhu.plugin import Plugin, cthulhu_hookimpl
from cthulhu import cthulhuVersion
logger = logging.getLogger(__name__)
class DisplayVersion(Plugin):
"""Plugin that announces the current Cthulhu version."""
def __init__(self, *args, **kwargs):
"""Initialize the plugin."""
super().__init__(*args, **kwargs)
logger.info("DisplayVersion plugin initialized")
self._kb_binding = None
@cthulhu_hookimpl
def activate(self, plugin=None):
"""Activate the plugin."""
# Skip if this activation call isn't for us
if plugin is not None and plugin is not self:
return
try:
logger.info("Activating DisplayVersion plugin")
# Register keyboard shortcut
self._kb_binding = self.registerGestureByString(
self.speakText,
f'Cthulhu screen reader version {cthulhuVersion.version}-{cthulhuVersion.codeName}',
'kb:cthulhu+shift+v'
)
except Exception as e:
logger.error(f"Error activating DisplayVersion plugin: {e}")
@cthulhu_hookimpl
def deactivate(self, plugin=None):
"""Deactivate the plugin."""
# Skip if this deactivation call isn't for us
if plugin is not None and plugin is not self:
return
logger.info("Deactivating DisplayVersion plugin")
def speakText(self, script=None, inputEvent=None):
"""Speak the Cthulhu version when shortcut is pressed."""
try:
if self.app:
state = self.app.getDynamicApiManager().getAPI('CthulhuState')
if state.activeScript:
state.activeScript.presentMessage(
f'Cthulhu screen reader version {cthulhuVersion.version}-{cthulhuVersion.codeName}',
resetStyles=False
)
return True
except Exception as e:
logger.error(f"Error in DisplayVersion speakText: {e}")
return False

@ -0,0 +1,33 @@
# Hello World Plugin for Cthulhu
This is a simple test plugin for the Cthulhu screen reader that demonstrates how to use the pluggy-based plugin system.
## Features
- Registers a keyboard shortcut (Cthulhu+z) that speaks "hello world" when pressed
- Demonstrates how to use the Plugin base class
- Shows how to use cthulhu_hookimpl for hook implementation
## Implementation Details
The plugin uses the following key features:
- `pluggy` for hook specification and implementation
- The `Plugin` base class from cthulhu.plugin
- The `cthulhu_hookimpl` decorator to mark functions as plugin hooks
- The `registerGestureByString` method to register keyboard shortcuts
## Structure
- `plugin.py`: The main plugin implementation
- `plugin.info`: Metadata about the plugin
## Requirements
Requires the pluggy package to be installed:
```
pip install pluggy
```
## Usage
The plugin will be automatically loaded when Cthulhu starts if it's listed in the activePlugins setting.

@ -113,7 +113,7 @@ class ResourceContext():
self.settings[profile][application] = {} self.settings[profile][application] = {}
# add entry # add entry
self.settings[profile][application][sub_setting_name] = entry self.settings[profile][application][sub_setting_name] = entry
print('add', 'settings', self.getName(), profile, application, entry.getResourceText()) print('add', 'settings', self.getName(), profile, application, entry.getResourceText())
@ -214,7 +214,7 @@ class ResourceContext():
self.unregisterAllAPI() self.unregisterAllAPI()
except Exception as e: except Exception as e:
print(e) print(e)
def unregisterAllAPI(self): def unregisterAllAPI(self):
dynamicApiManager = self.app.getDynamicApiManager() dynamicApiManager = self.app.getDynamicApiManager()
for application, value in self.getAPIs().copy().items(): for application, value in self.getAPIs().copy().items():
@ -226,7 +226,7 @@ class ResourceContext():
print('unregister api ', self.getName(), entry.getEntryType(), entry.getResourceText()) print('unregister api ', self.getName(), entry.getEntryType(), entry.getResourceText())
def unregisterAllGestures(self): def unregisterAllGestures(self):
APIHelper = self.app.getAPIHelper() APIHelper = self.app.getAPIHelper()
for profile, profileValue in self.getGestures().copy().items(): for profile, profileValue in self.getGestures().copy().items():
for application, applicationValue in profileValue.copy().items(): for application, applicationValue in profileValue.copy().items():
for gesture, entry in applicationValue.copy().items(): for gesture, entry in applicationValue.copy().items():
@ -272,12 +272,12 @@ class ResourceManager():
def removeResourceContext(self, contextName): def removeResourceContext(self, contextName):
if not contextName: if not contextName:
return return
try: try:
self.resourceContextDict[contextName].unregisterAllResources() self.resourceContextDict[contextName].unregisterAllResources()
except: except:
pass pass
# temp # temp
try: try:
print('_________', 'summery', self.resourceContextDict[contextName].getName(), '_________') print('_________', 'summery', self.resourceContextDict[contextName].getName(), '_________')
@ -302,7 +302,7 @@ class ResourceManager():
return self.resourceContextDict[contextName] return self.resourceContextDict[contextName]
except KeyError: except KeyError:
return None return None
def addAPI(self, application, api, contextName = None): def addAPI(self, application, api, contextName = None):
if not contextName: if not contextName:
return return

@ -3558,10 +3558,10 @@ class Utilities:
@staticmethod @staticmethod
def unicodeValueString(character): def unicodeValueString(character):
""" Returns a four hex digit representation of the given character """ Returns a four hex digit representation of the given character
Arguments: Arguments:
- The character to return representation - The character to return representation
Returns a string representaition of the given character unicode vlue Returns a string representaition of the given character unicode vlue
""" """

@ -69,7 +69,7 @@ class SpeechServer(speechserver.SpeechServer):
# See the parent class for documentation. # See the parent class for documentation.
_active_servers = {} _active_servers = {}
DEFAULT_SERVER_ID = 'default' DEFAULT_SERVER_ID = 'default'
_SERVER_NAMES = {DEFAULT_SERVER_ID: guilabels.DEFAULT_SYNTHESIZER} _SERVER_NAMES = {DEFAULT_SERVER_ID: guilabels.DEFAULT_SYNTHESIZER}
@ -93,7 +93,7 @@ class SpeechServer(speechserver.SpeechServer):
Attempt to create the server if it doesn't exist yet. Returns None Attempt to create the server if it doesn't exist yet. Returns None
when it is not possible to create the server. when it is not possible to create the server.
""" """
if serverId not in cls._active_servers: if serverId not in cls._active_servers:
cls(serverId) cls(serverId)
@ -781,16 +781,16 @@ class SpeechServer(speechserver.SpeechServer):
def reset(self, text=None, acss=None): def reset(self, text=None, acss=None):
self._client.close() self._client.close()
self._init() self._init()
def list_output_modules(self): def list_output_modules(self):
"""Return names of available output modules as a tuple of strings. """Return names of available output modules as a tuple of strings.
This method is not a part of Cthulhu speech API, but is used internally This method is not a part of Cthulhu speech API, but is used internally
by the Speech Dispatcher backend. by the Speech Dispatcher backend.
The returned tuple can be empty if the information can not be The returned tuple can be empty if the information can not be
obtained (e.g. with an older Speech Dispatcher version). obtained (e.g. with an older Speech Dispatcher version).
""" """
try: try:
return self._send_command(self._client.list_output_modules) return self._send_command(self._client.list_output_modules)