diff --git a/src/cthulhu/ax_utilities_role.py b/src/cthulhu/ax_utilities_role.py index 269d39d..7428867 100644 --- a/src/cthulhu/ax_utilities_role.py +++ b/src/cthulhu/ax_utilities_role.py @@ -40,6 +40,7 @@ from gi.repository import Atspi from . import debug from . import object_properties +from . import role_keys from .ax_object import AXObject from .ax_utilities_state import AXUtilitiesState @@ -386,7 +387,7 @@ class AXUtilitiesRole: return object_properties.ROLE_PROLOGUE if AXUtilitiesRole.is_dpub_toc(obj, role): return object_properties.ROLE_TOC - elif role == "ROLE_DPUB_SECTION": + elif role == role_keys.ROLE_DPUB_SECTION: if AXUtilitiesRole.is_dpub_abstract(obj, role): return object_properties.ROLE_ABSTRACT if AXUtilitiesRole.is_dpub_colophon(obj, role): diff --git a/src/cthulhu/braille_generator.py b/src/cthulhu/braille_generator.py index d8021d8..33f3001 100644 --- a/src/cthulhu/braille_generator.py +++ b/src/cthulhu/braille_generator.py @@ -40,6 +40,7 @@ from . import debug from . import generator from . import messages from . import object_properties +from . import role_keys from . import cthulhu_state from . import settings from . import settings_manager @@ -453,7 +454,7 @@ class BrailleGenerator(generator.Generator): # We will provide the support for someone to override this, # however, so we use REAL_ROLE_SCROLL_PANE here. # - oldRole = self._overrideRole('REAL_ROLE_SCROLL_PANE', args) + oldRole = self._overrideRole(role_keys.REAL_ROLE_SCROLL_PANE, args) result.extend(self.generate(obj, **args)) self._restoreRole(oldRole, args) return result diff --git a/src/cthulhu/formatting.py b/src/cthulhu/formatting.py index 929c4a1..6c253a6 100644 --- a/src/cthulhu/formatting.py +++ b/src/cthulhu/formatting.py @@ -44,6 +44,7 @@ gi.require_version("Atspi", "2.0") from gi.repository import Atspi from . import object_properties +from . import role_keys TUTORIAL = '(tutorial and (pause + tutorial) or [])' MNEMONIC = '(mnemonic and (pause + mnemonic + lineBreak) or [])' @@ -153,7 +154,7 @@ formatting = { 'focused': 'labelOrName + roleName', 'unfocused': 'labelOrName + roleName + pause + currentLineText + allTextSelection', }, - 'ROLE_ARTICLE_IN_FEED' : { + role_keys.ROLE_ARTICLE_IN_FEED: { 'unfocused': '(labelOrName or currentLineText or roleName) + pause + positionInList', }, Atspi.Role.BLOCK_QUOTE: { @@ -197,25 +198,25 @@ formatting = { 'unfocused': 'labelOrName + roleName + pause + currentLineText + allTextSelection', }, # TODO - JD: When we bump dependencies to 2.34, remove this fake role and use the real one. - 'ROLE_CONTENT_DELETION': { + role_keys.ROLE_CONTENT_DELETION: { 'focused': 'leaving or deletionStart', 'unfocused': 'deletionStart + pause + displayedText + pause + deletionEnd', }, - 'ROLE_CONTENT_ERROR': { + role_keys.ROLE_CONTENT_ERROR: { 'unfocused': 'displayedText + pause + invalid', }, # TODO - JD: When we bump dependencies to 2.34, remove this fake role and use the real one. - 'ROLE_CONTENT_INSERTION': { + role_keys.ROLE_CONTENT_INSERTION: { 'focused': 'leaving or insertionStart', 'unfocused': 'insertionStart + pause + displayedText + pause + insertionEnd', }, # TODO - JD: When we bump dependencies to 2.36, remove this fake role and use the real one. - 'ROLE_CONTENT_MARK': { + role_keys.ROLE_CONTENT_MARK: { 'focused': 'leaving or markStart', 'unfocused': 'markStart + pause + displayedText + pause + markEnd', }, # TODO - JD: When we bump dependencies to 2.36, remove this fake role and use the real one. - 'ROLE_CONTENT_SUGGESTION': { + role_keys.ROLE_CONTENT_SUGGESTION: { 'focused': 'leaving or roleName', }, Atspi.Role.DESCRIPTION_LIST: { @@ -247,11 +248,11 @@ formatting = { 'basicWhereAmI': 'labelOrName + readOnly + textRole + textContent + anyTextSelection + ' + MNEMONIC, 'detailedWhereAmI': 'labelorName + readOnly + textRole + textContentWithAttributes + anyTextSelection + ' + MNEMONIC }, - 'ROLE_DPUB_LANDMARK': { + role_keys.ROLE_DPUB_LANDMARK: { 'focused': 'leaving or labelOrName', 'unfocused': 'labelOrName + currentLineText + allTextSelection' }, - 'ROLE_DPUB_SECTION': { + role_keys.ROLE_DPUB_SECTION: { 'focused': 'leaving or (labelOrName + roleName)', 'unfocused': 'labelOrName + currentLineText + allTextSelection' }, @@ -265,7 +266,7 @@ formatting = { 'basicWhereAmI': 'labelOrName + readOnly + textRole + (textContent or placeholderText) + anyTextSelection + required + pause + invalid + ' + MNEMONIC, 'detailedWhereAmI': 'labelOrName + readOnly + textRole + (textContentWithAttributes or placeholderText) + anyTextSelection + required + pause + invalid + ' + MNEMONIC, }, - 'ROLE_FEED': { + role_keys.ROLE_FEED: { 'focused': 'leaving or (labelOrName + pause + (numberOfChildren or roleName))', 'unfocused': 'labelOrName + pause + (numberOfChildren or roleName)', }, @@ -341,11 +342,11 @@ formatting = { 'unfocused': 'math', }, # TODO - JD: When we bump dependencies to TBD, remove this fake role and use the real one. - 'ROLE_MATH_ENCLOSED': { + role_keys.ROLE_MATH_ENCLOSED: { 'unfocused': 'enclosedBase + enclosedEnclosures', }, # TODO - JD: When we bump dependencies to TBD, remove this fake role and use the real one. - 'ROLE_MATH_FENCED': { + role_keys.ROLE_MATH_FENCED: { 'unfocused': 'fencedStart + pause + fencedContents + pause + fencedEnd', }, Atspi.Role.MATH_FRACTION: { @@ -355,23 +356,23 @@ formatting = { 'unfocused': 'rootStart + rootBase + pause + rootEnd + pause', }, # TODO - JD: When we bump dependencies to TBD, remove this fake role and use the real one. - 'ROLE_MATH_MULTISCRIPT': { + role_keys.ROLE_MATH_MULTISCRIPT: { 'unfocused': 'scriptBase + pause + scriptPrescripts + pause + scriptPostscripts + pause', }, # TODO - JD: When we bump dependencies to TBD, remove this fake role and use the real one. - 'ROLE_MATH_SCRIPT_SUBSUPER': { + role_keys.ROLE_MATH_SCRIPT_SUBSUPER: { 'unfocused': 'scriptBase + pause + scriptSubscript + pause + scriptSuperscript + pause', }, # TODO - JD: When we bump dependencies to TBD, remove this fake role and use the real one. - 'ROLE_MATH_SCRIPT_UNDEROVER': { + role_keys.ROLE_MATH_SCRIPT_UNDEROVER: { 'unfocused': 'scriptBase + pause + scriptUnderscript + pause + scriptOverscript + pause', }, # TODO - JD: When we bump dependencies to TBD, remove this fake role and use the real one. - 'ROLE_MATH_TABLE': { + role_keys.ROLE_MATH_TABLE: { 'unfocused': 'mathTableStart + pause + mathTableRows + pause + mathTableEnd + pause', }, # TODO - JD: When we bump dependencies to TBD, remove this fake role and use the real one. - 'ROLE_MATH_TABLE_ROW': { + role_keys.ROLE_MATH_TABLE_ROW: { 'unfocused': 'mathRow', }, Atspi.Role.MENU: { @@ -440,7 +441,7 @@ formatting = { 'unfocused': 'labelOrName + radioState + roleName + availability + ' + MNEMONIC + ' + accelerator + positionInList', 'basicWhereAmI': 'ancestors + labelOrName + roleName + radioState + accelerator + positionInList + ' + MNEMONIC }, - 'ROLE_REGION': { + role_keys.ROLE_REGION: { 'focused': 'leaving or (roleName + labelOrName)', 'unfocused': 'labelOrName + roleName + currentLineText + allTextSelection' }, @@ -492,7 +493,7 @@ formatting = { Atspi.Role.SUPERSCRIPT: { 'unfocused': 'roleName + currentLineText + allTextSelection', }, - 'ROLE_SWITCH': { + role_keys.ROLE_SWITCH: { 'focused': 'switchState', 'unfocused': 'labelOrName + roleName + switchState + availability + ' + MNEMONIC + ' + accelerator', 'basicWhereAmI': 'labelOrName + roleName + switchState' @@ -509,7 +510,7 @@ formatting = { 'basicWhereAmI': 'parentRoleName + pause + columnHeader + pause + rowHeader + pause + roleName + pause + cellCheckedState + pause + (realActiveDescendantDisplayedText or imageDescription + image) + pause + columnAndRow + pause + expandableState + pause + nodeLevel + pause', 'detailedWhereAmI': 'parentRoleName + pause + columnHeader + pause + rowHeader + pause + roleName + pause + cellCheckedState + pause + (realActiveDescendantDisplayedText or imageDescription + image) + pause + columnAndRow + pause + tableCellRow + pause + expandableState + pause + nodeLevel + pause', }, - 'REAL_ROLE_TABLE_CELL': { + role_keys.REAL_ROLE_TABLE_CELL: { # the real cell information # note that Atspi.Role.TABLE_CELL is used to work out if we need to # read a whole row. It calls REAL_ROLE_TABLE_CELL internally. @@ -630,7 +631,7 @@ formatting = { or ([Component(obj, asString(labelAndName + roleName))]\ + (childWidget and ([Region(" ")] + childWidget))))' }, - 'ROLE_ARTICLE_IN_FEED': { + role_keys.ROLE_ARTICLE_IN_FEED: { 'unfocused': '((substring and ' + BRAILLE_TEXT + ')\ or ([Component(obj, asString(labelOrName + roleName))]))' }, @@ -830,7 +831,7 @@ formatting = { 'unfocused': '[Component(obj, asString(labelOrName + roleName))]\ + [Region(" ")] + statusBar', }, - 'ROLE_SWITCH' : { + role_keys.ROLE_SWITCH: { 'unfocused': '[Component(obj,\ asString((labelOrName or description) + roleName),\ indicator=asString(switchState))]' @@ -840,7 +841,7 @@ formatting = { Atspi.Role.TABLE_CELL: { 'unfocused': '((substring and ' + BRAILLE_TEXT + ') or tableCellRow)', }, - 'REAL_ROLE_TABLE_CELL': { + role_keys.REAL_ROLE_TABLE_CELL: { 'unfocused': '((tableCell2ChildToggle + tableCell2ChildLabel)\ or (substring and ' + BRAILLE_TEXT + ') \ or (cellCheckedState\ @@ -992,7 +993,7 @@ formatting = { 'focused': 'percentage', 'unfocused': 'roleName + percentage + availability', }, - 'ROLE_SWITCH': { + role_keys.ROLE_SWITCH: { 'focused': 'switchState', 'unfocused': 'switchState + availability', }, diff --git a/src/cthulhu/generator.py b/src/cthulhu/generator.py index b6b4f13..26756f7 100644 --- a/src/cthulhu/generator.py +++ b/src/cthulhu/generator.py @@ -48,6 +48,7 @@ from . import braille from . import debug from . import messages from . import object_properties +from . import role_keys from . import settings from . import settings_manager from .ax_object import AXObject @@ -954,7 +955,7 @@ class Generator: cells. """ result = [] - oldRole = self._overrideRole('REAL_ROLE_TABLE_CELL', args) + oldRole = self._overrideRole(role_keys.REAL_ROLE_TABLE_CELL, args) result.extend(self.generate(obj, **args)) self._restoreRole(oldRole, args) return result @@ -1299,62 +1300,113 @@ class Generator: self._activeProgressBars[obj] = lastTime, lastValue def _getAlternativeRole(self, obj, **args): - if self._script.utilities.isMath(obj): - if self._script.utilities.isMathSubOrSuperScript(obj): - return 'ROLE_MATH_SCRIPT_SUBSUPER' - if self._script.utilities.isMathUnderOrOverScript(obj): - return 'ROLE_MATH_SCRIPT_UNDEROVER' - if self._script.utilities.isMathMultiScript(obj): - return 'ROLE_MATH_MULTISCRIPT' - if self._script.utilities.isMathEnclose(obj): - return 'ROLE_MATH_ENCLOSED' - if self._script.utilities.isMathFenced(obj): - return 'ROLE_MATH_FENCED' - if self._script.utilities.isMathTable(obj): - return 'ROLE_MATH_TABLE' - if self._script.utilities.isMathTableRow(obj): - return 'ROLE_MATH_TABLE_ROW' - if self._script.utilities.isDPub(obj): - if self._script.utilities.isLandmark(obj): - return 'ROLE_DPUB_LANDMARK' - if AXUtilities.is_section(obj): - return 'ROLE_DPUB_SECTION' + role = self._getMathAlternativeRole(obj) + if role: + return role + + role = self._getDPubAlternativeRole(obj) + if role: + return role + + role = self._getSwitchOrSpecialRole(obj) + if role: + return role + + role = self._getContentAlternativeRole(obj) + if role: + return role + + role = self._getDescriptionListRole(obj) + if role: + return role + + role = self._getFeedAlternativeRole(obj) + if role: + return role + + role = self._getLandmarkAlternativeRole(obj) + if role: + return role + + if self._script.utilities.isDocument(obj) and AXObject.supports_image(obj): + return Atspi.Role.IMAGE + + return args.get('role', AXObject.get_role(obj)) + + def _getMathAlternativeRole(self, obj): + if not self._script.utilities.isMath(obj): + return None + if self._script.utilities.isMathSubOrSuperScript(obj): + return role_keys.ROLE_MATH_SCRIPT_SUBSUPER + if self._script.utilities.isMathUnderOrOverScript(obj): + return role_keys.ROLE_MATH_SCRIPT_UNDEROVER + if self._script.utilities.isMathMultiScript(obj): + return role_keys.ROLE_MATH_MULTISCRIPT + if self._script.utilities.isMathEnclose(obj): + return role_keys.ROLE_MATH_ENCLOSED + if self._script.utilities.isMathFenced(obj): + return role_keys.ROLE_MATH_FENCED + if self._script.utilities.isMathTable(obj): + return role_keys.ROLE_MATH_TABLE + if self._script.utilities.isMathTableRow(obj): + return role_keys.ROLE_MATH_TABLE_ROW + return None + + def _getDPubAlternativeRole(self, obj): + if not self._script.utilities.isDPub(obj): + return None + if self._script.utilities.isLandmark(obj): + return role_keys.ROLE_DPUB_LANDMARK + if AXUtilities.is_section(obj): + return role_keys.ROLE_DPUB_SECTION + return None + + def _getSwitchOrSpecialRole(self, obj): if self._script.utilities.isSwitch(obj): - return 'ROLE_SWITCH' + return role_keys.ROLE_SWITCH if self._script.utilities.isAnchor(obj): return Atspi.Role.STATIC if self._script.utilities.isBlockquote(obj): return Atspi.Role.BLOCK_QUOTE if self._script.utilities.isComment(obj): return Atspi.Role.COMMENT + return None + + def _getContentAlternativeRole(self, obj): if self._script.utilities.isContentDeletion(obj): - return 'ROLE_CONTENT_DELETION' + return role_keys.ROLE_CONTENT_DELETION if self._script.utilities.isContentError(obj): - return 'ROLE_CONTENT_ERROR' + return role_keys.ROLE_CONTENT_ERROR if self._script.utilities.isContentInsertion(obj): - return 'ROLE_CONTENT_INSERTION' + return role_keys.ROLE_CONTENT_INSERTION if self._script.utilities.isContentMarked(obj): - return 'ROLE_CONTENT_MARK' + return role_keys.ROLE_CONTENT_MARK if self._script.utilities.isContentSuggestion(obj): - return 'ROLE_CONTENT_SUGGESTION' + return role_keys.ROLE_CONTENT_SUGGESTION + return None + + def _getDescriptionListRole(self, obj): if self._script.utilities.isDescriptionList(obj): return Atspi.Role.DESCRIPTION_LIST if self._script.utilities.isDescriptionListTerm(obj): return Atspi.Role.DESCRIPTION_TERM if self._script.utilities.isDescriptionListDescription(obj): return Atspi.Role.DESCRIPTION_VALUE - if self._script.utilities.isFeedArticle(obj): - return 'ROLE_ARTICLE_IN_FEED' - if self._script.utilities.isFeed(obj): - return 'ROLE_FEED' - if self._script.utilities.isLandmark(obj): - if self._script.utilities.isLandmarkRegion(obj): - return 'ROLE_REGION' - return Atspi.Role.LANDMARK - if self._script.utilities.isDocument(obj) and AXObject.supports_image(obj): - return Atspi.Role.IMAGE + return None - return args.get('role', AXObject.get_role(obj)) + def _getFeedAlternativeRole(self, obj): + if self._script.utilities.isFeedArticle(obj): + return role_keys.ROLE_ARTICLE_IN_FEED + if self._script.utilities.isFeed(obj): + return role_keys.ROLE_FEED + return None + + def _getLandmarkAlternativeRole(self, obj): + if not self._script.utilities.isLandmark(obj): + return None + if self._script.utilities.isLandmarkRegion(obj): + return role_keys.ROLE_REGION + return Atspi.Role.LANDMARK def getLocalizedRoleName(self, obj, **args): role = args.get('role', AXObject.get_role(obj)) @@ -1435,7 +1487,7 @@ class Generator: return object_properties.ROLE_PROLOGUE if self._script.utilities.isDPubToc(obj): return object_properties.ROLE_TOC - elif role == "ROLE_DPUB_SECTION": + elif role == role_keys.ROLE_DPUB_SECTION: if self._script.utilities.isDPubAbstract(obj): return object_properties.ROLE_ABSTRACT if self._script.utilities.isDPubColophon(obj): diff --git a/src/cthulhu/meson.build b/src/cthulhu/meson.build index c239c0e..e1d13b1 100644 --- a/src/cthulhu/meson.build +++ b/src/cthulhu/meson.build @@ -77,6 +77,7 @@ cthulhu_python_sources = files([ 'pronunciation_dict.py', 'punctuation_settings.py', 'resource_manager.py', + 'role_keys.py', 'script.py', 'script_manager.py', 'script_utilities.py', diff --git a/src/cthulhu/role_keys.py b/src/cthulhu/role_keys.py new file mode 100644 index 0000000..617ccf8 --- /dev/null +++ b/src/cthulhu/role_keys.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python3 +# +# Copyright (c) 2026 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. +# +# Forked from Orca screen reader. +# Cthulhu project: https://git.stormux.org/storm/cthulhu + +"""Shared role key constants for formatting and generators.""" + +__id__ = "$Id$" +__version__ = "$Revision$" +__date__ = "$Date$" +__copyright__ = "Copyright (c) 2005-2008 Sun Microsystems Inc." +__license__ = "LGPL" + +# Custom role keys used by formatting and role override logic. +ROLE_ARTICLE_IN_FEED = 'ROLE_ARTICLE_IN_FEED' +ROLE_CONTENT_DELETION = 'ROLE_CONTENT_DELETION' +ROLE_CONTENT_ERROR = 'ROLE_CONTENT_ERROR' +ROLE_CONTENT_INSERTION = 'ROLE_CONTENT_INSERTION' +ROLE_CONTENT_MARK = 'ROLE_CONTENT_MARK' +ROLE_CONTENT_SUGGESTION = 'ROLE_CONTENT_SUGGESTION' +ROLE_DPUB_LANDMARK = 'ROLE_DPUB_LANDMARK' +ROLE_DPUB_SECTION = 'ROLE_DPUB_SECTION' +ROLE_FEED = 'ROLE_FEED' +ROLE_MATH_ENCLOSED = 'ROLE_MATH_ENCLOSED' +ROLE_MATH_FENCED = 'ROLE_MATH_FENCED' +ROLE_MATH_MULTISCRIPT = 'ROLE_MATH_MULTISCRIPT' +ROLE_MATH_SCRIPT_SUBSUPER = 'ROLE_MATH_SCRIPT_SUBSUPER' +ROLE_MATH_SCRIPT_UNDEROVER = 'ROLE_MATH_SCRIPT_UNDEROVER' +ROLE_MATH_TABLE = 'ROLE_MATH_TABLE' +ROLE_MATH_TABLE_ROW = 'ROLE_MATH_TABLE_ROW' +ROLE_REGION = 'ROLE_REGION' +ROLE_SWITCH = 'ROLE_SWITCH' +ROLE_SPREADSHEET_CELL = 'ROLE_SPREADSHEET_CELL' + +# Formatting override keys (not real Atspi roles). +REAL_ROLE_TABLE_CELL = 'REAL_ROLE_TABLE_CELL' +REAL_ROLE_SCROLL_PANE = 'REAL_ROLE_SCROLL_PANE' diff --git a/src/cthulhu/scripts/apps/soffice/formatting.py b/src/cthulhu/scripts/apps/soffice/formatting.py index de453f1..74fbfaf 100644 --- a/src/cthulhu/scripts/apps/soffice/formatting.py +++ b/src/cthulhu/scripts/apps/soffice/formatting.py @@ -43,6 +43,7 @@ gi.require_version("Atspi", "2.0") from gi.repository import Atspi import cthulhu.formatting +import cthulhu.role_keys import cthulhu.settings formatting = { @@ -53,11 +54,11 @@ formatting = { 'basicWhereAmI': 'parentRoleName + pause + columnHeader + pause + rowHeader + pause + roleName + pause + cellCheckedState + pause + (realActiveDescendantDisplayedText or imageDescription + image) + pause + columnAndRow + pause + expandableState + pause + nodeLevel + pause', 'detailedWhereAmI': 'parentRoleName + pause + columnHeader + pause + rowHeader + pause + roleName + pause + cellCheckedState + pause + (realActiveDescendantDisplayedText or imageDescription + image) + pause + columnAndRow + pause + tableCellRow + pause + expandableState + pause + nodeLevel + pause' }, - 'REAL_ROLE_TABLE_CELL': { + cthulhu.role_keys.REAL_ROLE_TABLE_CELL: { 'focused': 'newRowHeader + newColumnHeader + realActiveDescendantDisplayedText', 'unfocused': 'newRowHeader + newColumnHeader + realActiveDescendantDisplayedText', }, - 'ROLE_SPREADSHEET_CELL': { + cthulhu.role_keys.ROLE_SPREADSHEET_CELL: { # We treat spreadsheet cells differently from other table cells in # whereAmI. # diff --git a/src/cthulhu/scripts/apps/soffice/speech_generator.py b/src/cthulhu/scripts/apps/soffice/speech_generator.py index db8645c..e94f2ba 100644 --- a/src/cthulhu/scripts/apps/soffice/speech_generator.py +++ b/src/cthulhu/scripts/apps/soffice/speech_generator.py @@ -36,6 +36,7 @@ gi.require_version("Atspi", "2.0") from gi.repository import Atspi import cthulhu.messages as messages +import cthulhu.role_keys as role_keys import cthulhu.settings_manager as settings_manager import cthulhu.speech_generator as speech_generator from cthulhu.ax_object import AXObject @@ -75,7 +76,7 @@ class SpeechGenerator(speech_generator.SpeechGenerator): # Treat a paragraph which is inside of a spreadsheet cell as # a spreadsheet cell. # - elif role == 'ROLE_SPREADSHEET_CELL': + elif role == role_keys.ROLE_SPREADSHEET_CELL: oldRole = self._overrideRole(Atspi.Role.TABLE_CELL, args) override = True result.extend(speech_generator.SpeechGenerator._generateRoleName( @@ -502,7 +503,7 @@ class SpeechGenerator(speech_generator.SpeechGenerator): result = [] if args.get('formatType', 'unfocused') == 'basicWhereAmI' \ and self._script.utilities.isSpreadSheetCell(obj): - oldRole = self._overrideRole('ROLE_SPREADSHEET_CELL', args) + oldRole = self._overrideRole(role_keys.ROLE_SPREADSHEET_CELL, args) # In addition, if focus is in a cell being edited, we cannot # query the accessible table interface for coordinates and the # like because we're temporarily in an entirely different object diff --git a/src/cthulhu/scripts/web/speech_generator.py b/src/cthulhu/scripts/web/speech_generator.py index 6147ddf..9ecc402 100644 --- a/src/cthulhu/scripts/web/speech_generator.py +++ b/src/cthulhu/scripts/web/speech_generator.py @@ -41,6 +41,7 @@ from cthulhu import debug from cthulhu import input_event_manager from cthulhu import messages from cthulhu import object_properties +from cthulhu import role_keys from cthulhu import cthulhu_state from cthulhu import settings from cthulhu import settings_manager @@ -491,7 +492,7 @@ class SpeechGenerator(speech_generator.SpeechGenerator): roles = [Atspi.Role.DESCRIPTION_LIST, Atspi.Role.LIST, Atspi.Role.LIST_BOX, - 'ROLE_FEED'] + role_keys.ROLE_FEED] role = args.get('role', AXObject.get_role(obj)) if role not in roles: return super()._generateNumberOfChildren(obj, **args) @@ -510,7 +511,7 @@ class SpeechGenerator(speech_generator.SpeechGenerator): if self._script.utilities.isDescriptionList(obj): result = [messages.descriptionListTermCount(setsize)] - elif role == 'ROLE_FEED': + elif role == role_keys.ROLE_FEED: result = [messages.feedArticleCount(setsize)] else: result = [messages.listItemCount(setsize)] @@ -597,7 +598,7 @@ class SpeechGenerator(speech_generator.SpeechGenerator): doNotSpeak.append(Atspi.Role.TEXT) doNotSpeak.append(Atspi.Role.STATIC) if args.get('string'): - doNotSpeak.append("ROLE_CONTENT_SUGGESTION") + doNotSpeak.append(role_keys.ROLE_CONTENT_SUGGESTION) if args.get('formatType', 'unfocused') != 'basicWhereAmI': doNotSpeak.append(Atspi.Role.LIST_ITEM) doNotSpeak.append(Atspi.Role.LIST) diff --git a/src/cthulhu/sound_generator.py b/src/cthulhu/sound_generator.py index 9a3727f..8bcd115 100644 --- a/src/cthulhu/sound_generator.py +++ b/src/cthulhu/sound_generator.py @@ -39,6 +39,7 @@ import os from . import cthulhu # Need access to cthulhuApp from . import generator +from . import role_keys from . import settings_manager from .ax_object import AXObject from .ax_utilities import AXUtilities @@ -373,7 +374,7 @@ class SoundGenerator(generator.Generator): role = args.get('role', AXObject.get_role(obj)) if isinstance(role, str): - if role == "ROLE_SWITCH": + if role == role_keys.ROLE_SWITCH: role = Atspi.Role.SWITCH else: return [] diff --git a/src/cthulhu/sound_theme_manager.py b/src/cthulhu/sound_theme_manager.py index 9c9680c..f77f194 100644 --- a/src/cthulhu/sound_theme_manager.py +++ b/src/cthulhu/sound_theme_manager.py @@ -41,6 +41,7 @@ from gi.repository import GLib from gi.repository import Atspi from . import debug +from . import role_keys from . import sound from .sound_generator import Icon @@ -244,7 +245,7 @@ class SoundThemeManager: def _normalizeRole(self, role): if isinstance(role, str): - if role == "ROLE_SWITCH": + if role == role_keys.ROLE_SWITCH: return Atspi.Role.SWITCH return None return role @@ -395,4 +396,3 @@ def getManager(): _manager = SoundThemeManager(cthulhu.cthulhuApp) return _manager - diff --git a/src/cthulhu/speech_generator.py b/src/cthulhu/speech_generator.py index 2f39be6..0b533e1 100644 --- a/src/cthulhu/speech_generator.py +++ b/src/cthulhu/speech_generator.py @@ -48,6 +48,7 @@ from . import debug from . import generator from . import messages from . import object_properties +from . import role_keys from . import settings from . import settings_manager from . import sound_theme_manager @@ -275,7 +276,7 @@ class SpeechGenerator(generator.Generator): def _getRoleNameStripCandidates(self, obj, role=None): normalizedRole = role if isinstance(normalizedRole, str): - if normalizedRole == "ROLE_SWITCH": + if normalizedRole == role_keys.ROLE_SWITCH: normalizedRole = Atspi.Role.SWITCH else: normalizedRole = None @@ -1199,7 +1200,7 @@ class SpeechGenerator(generator.Generator): cell itself. The string, 'blank', is added for empty cells. """ result = [] - oldRole = self._overrideRole('REAL_ROLE_TABLE_CELL', args) + oldRole = self._overrideRole(role_keys.REAL_ROLE_TABLE_CELL, args) result.extend(self.generate(obj, **args)) self._restoreRole(oldRole, args) if not (result and result[0]) \ @@ -1970,19 +1971,19 @@ class SpeechGenerator(generator.Generator): def _getEnabledAndDisabledContextRoles(self): allRoles = [Atspi.Role.BLOCK_QUOTE, - 'ROLE_CONTENT_DELETION', - 'ROLE_CONTENT_INSERTION', - 'ROLE_CONTENT_MARK', - 'ROLE_CONTENT_SUGGESTION', - 'ROLE_DPUB_LANDMARK', - 'ROLE_DPUB_SECTION', + role_keys.ROLE_CONTENT_DELETION, + role_keys.ROLE_CONTENT_INSERTION, + role_keys.ROLE_CONTENT_MARK, + role_keys.ROLE_CONTENT_SUGGESTION, + role_keys.ROLE_DPUB_LANDMARK, + role_keys.ROLE_DPUB_SECTION, Atspi.Role.DESCRIPTION_LIST, - 'ROLE_FEED', + role_keys.ROLE_FEED, Atspi.Role.FORM, Atspi.Role.LANDMARK, Atspi.Role.LIST, Atspi.Role.PANEL, - 'ROLE_REGION', + role_keys.ROLE_REGION, Atspi.Role.TABLE, Atspi.Role.TOOL_TIP] @@ -1991,19 +1992,19 @@ class SpeechGenerator(generator.Generator): if cthulhu.cthulhuApp.settingsManager.getSetting('sayAllContextBlockquote'): enabled.append(Atspi.Role.BLOCK_QUOTE) if cthulhu.cthulhuApp.settingsManager.getSetting('sayAllContextLandmark'): - enabled.extend([Atspi.Role.LANDMARK, 'ROLE_DPUB_LANDMARK']) + enabled.extend([Atspi.Role.LANDMARK, role_keys.ROLE_DPUB_LANDMARK]) if cthulhu.cthulhuApp.settingsManager.getSetting('sayAllContextList'): enabled.append(Atspi.Role.LIST) enabled.append(Atspi.Role.DESCRIPTION_LIST) - enabled.append('ROLE_FEED') + enabled.append(role_keys.ROLE_FEED) if cthulhu.cthulhuApp.settingsManager.getSetting('sayAllContextPanel'): enabled.extend([Atspi.Role.PANEL, Atspi.Role.TOOL_TIP, - 'ROLE_CONTENT_DELETION', - 'ROLE_CONTENT_INSERTION', - 'ROLE_CONTENT_MARK', - 'ROLE_CONTENT_SUGGESTION', - 'ROLE_DPUB_SECTION']) + role_keys.ROLE_CONTENT_DELETION, + role_keys.ROLE_CONTENT_INSERTION, + role_keys.ROLE_CONTENT_MARK, + role_keys.ROLE_CONTENT_SUGGESTION, + role_keys.ROLE_DPUB_SECTION]) if cthulhu.cthulhuApp.settingsManager.getSetting('sayAllContextNonLandmarkForm'): enabled.append(Atspi.Role.FORM) if cthulhu.cthulhuApp.settingsManager.getSetting('sayAllContextTable'): @@ -2012,19 +2013,20 @@ class SpeechGenerator(generator.Generator): if cthulhu.cthulhuApp.settingsManager.getSetting('speakContextBlockquote'): enabled.append(Atspi.Role.BLOCK_QUOTE) if cthulhu.cthulhuApp.settingsManager.getSetting('speakContextLandmark'): - enabled.extend([Atspi.Role.LANDMARK, 'ROLE_DPUB_LANDMARK', 'ROLE_REGION']) + enabled.extend([Atspi.Role.LANDMARK, role_keys.ROLE_DPUB_LANDMARK, + role_keys.ROLE_REGION]) if cthulhu.cthulhuApp.settingsManager.getSetting('speakContextList'): enabled.append(Atspi.Role.LIST) enabled.append(Atspi.Role.DESCRIPTION_LIST) - enabled.append('ROLE_FEED') + enabled.append(role_keys.ROLE_FEED) if cthulhu.cthulhuApp.settingsManager.getSetting('speakContextPanel'): enabled.extend([Atspi.Role.PANEL, Atspi.Role.TOOL_TIP, - 'ROLE_CONTENT_DELETION', - 'ROLE_CONTENT_INSERTION', - 'ROLE_CONTENT_MARK', - 'ROLE_CONTENT_SUGGESTION', - 'ROLE_DPUB_SECTION']) + role_keys.ROLE_CONTENT_DELETION, + role_keys.ROLE_CONTENT_INSERTION, + role_keys.ROLE_CONTENT_MARK, + role_keys.ROLE_CONTENT_SUGGESTION, + role_keys.ROLE_DPUB_SECTION]) if cthulhu.cthulhuApp.settingsManager.getSetting('speakContextNonLandmarkForm'): enabled.append(Atspi.Role.FORM) if cthulhu.cthulhuApp.settingsManager.getSetting('speakContextTable'): @@ -2058,7 +2060,7 @@ class SpeechGenerator(generator.Generator): result.append(messages.leavingNLists(count)) else: result.append(messages.LEAVING_LIST) - elif role == 'ROLE_FEED': + elif role == role_keys.ROLE_FEED: result.append(messages.LEAVING_FEED) elif role == Atspi.Role.PANEL: if self._script.utilities.isFigure(obj): @@ -2069,7 +2071,7 @@ class SpeechGenerator(generator.Generator): result = [''] elif role == Atspi.Role.TABLE and self._script.utilities.isTextDocumentTable(obj): result.append(messages.LEAVING_TABLE) - elif role == 'ROLE_DPUB_LANDMARK': + elif role == role_keys.ROLE_DPUB_LANDMARK: if self._script.utilities.isDPubAcknowledgments(obj): result.append(messages.LEAVING_ACKNOWLEDGMENTS) elif self._script.utilities.isDPubAfterword(obj): @@ -2108,7 +2110,7 @@ class SpeechGenerator(generator.Generator): result.append(messages.LEAVING_PROLOGUE) elif self._script.utilities.isDPubToc(obj): result.append(messages.LEAVING_TOC) - elif role == 'ROLE_DPUB_SECTION': + elif role == role_keys.ROLE_DPUB_SECTION: if self._script.utilities.isDPubAbstract(obj): result.append(messages.LEAVING_ABSTRACT) elif self._script.utilities.isDPubColophon(obj): @@ -2148,13 +2150,13 @@ class SpeechGenerator(generator.Generator): result.append(messages.LEAVING_FORM) elif role == Atspi.Role.TOOL_TIP: result.append(messages.LEAVING_TOOL_TIP) - elif role == 'ROLE_CONTENT_DELETION': + elif role == role_keys.ROLE_CONTENT_DELETION: result.append(messages.CONTENT_DELETION_END) - elif role == 'ROLE_CONTENT_INSERTION': + elif role == role_keys.ROLE_CONTENT_INSERTION: result.append(messages.CONTENT_INSERTION_END) - elif role == 'ROLE_CONTENT_MARK': + elif role == role_keys.ROLE_CONTENT_MARK: result.append(messages.CONTENT_MARK_END) - elif role == 'ROLE_CONTENT_SUGGESTION' \ + elif role == role_keys.ROLE_CONTENT_SUGGESTION \ and not self._script.utilities.isInlineSuggestion(obj): result.append(messages.LEAVING_SUGGESTION) else: @@ -2305,16 +2307,16 @@ class SpeechGenerator(generator.Generator): Atspi.Role.DESCRIPTION_LIST, Atspi.Role.FORM, Atspi.Role.LANDMARK, - 'ROLE_CONTENT_DELETION', - 'ROLE_CONTENT_INSERTION', - 'ROLE_CONTENT_MARK', - 'ROLE_CONTENT_SUGGESTION', - 'ROLE_DPUB_LANDMARK', - 'ROLE_DPUB_SECTION', - 'ROLE_FEED', + role_keys.ROLE_CONTENT_DELETION, + role_keys.ROLE_CONTENT_INSERTION, + role_keys.ROLE_CONTENT_MARK, + role_keys.ROLE_CONTENT_SUGGESTION, + role_keys.ROLE_DPUB_LANDMARK, + role_keys.ROLE_DPUB_SECTION, + role_keys.ROLE_FEED, Atspi.Role.LIST, Atspi.Role.PANEL, - 'ROLE_REGION', + role_keys.ROLE_REGION, Atspi.Role.TABLE, Atspi.Role.TOOL_TIP]