Started porting over some bug fixes and modernizations from Orca.

This commit is contained in:
Storm Dragon
2026-01-06 12:09:40 -05:00
parent 21cfec55ee
commit 3c4cbe3c3f
5 changed files with 18 additions and 39 deletions
+1 -1
View File
@@ -540,7 +540,7 @@ class Component(Region):
been scrolled off the display."""
if cthulhu_state.activeScript and cthulhu_state.activeScript.utilities.\
grabFocusBeforeRouting(self.accessible, offset):
grabFocusBeforeRouting(self.accessible):
if AXObject.supports_component(self.accessible):
try:
Atspi.Component.grab_focus(self.accessible)
+1 -2
View File
@@ -560,13 +560,12 @@ class Utilities:
return False
def grabFocusBeforeRouting(self, obj, offset):
def grabFocusBeforeRouting(self, obj):
"""Whether or not we should perform a grabFocus before routing
the cursor via the braille cursor routing keys.
Arguments:
- obj: the accessible object where the cursor should be routed
- offset: the offset to which it should be routed
Returns True if we should do an explicit grabFocus on obj prior
to routing the cursor.
@@ -81,9 +81,6 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
if not self._script.utilities.inDocumentContent(obj):
return super()._generateAncestors(obj, **args)
if self._script.inSayAll() and obj == cthulhu_state.locusOfFocus:
return []
result = []
priorObj = args.get('priorObj')
if priorObj and self._script.utilities.inDocumentContent(priorObj):
+4
View File
@@ -651,6 +651,10 @@ class SpeechGenerator(generator.Generator):
Note that a 'role' attribute in args will override the
accessible role of the obj.
"""
# Prevent role repetition when object is same as prior object
if obj == args.get("priorObj"):
return []
if _settingsManager.getSetting('onlySpeakDisplayedText'):
return []
+12 -33
View File
@@ -596,15 +596,11 @@ class StructuralNavigation:
#
self.lastTableCell = [-1, -1]
self._objectCache = {}
self._inModalDialog = False
def clearCache(self, document=None):
if document:
self._objectCache[hash(document)] = {}
else:
self._objectCache = {}
"""No-op for backwards compatibility. Caching has been removed."""
pass
def structuralNavigationObjectCreator(self, name):
"""This convenience method creates a StructuralNavigationObject
@@ -794,7 +790,11 @@ class StructuralNavigation:
structuralNavigationObject.present(cell, arg)
def _getAll(self, structuralNavigationObject, arg=None):
"""Returns all the instances of structuralNavigationObject."""
"""Returns all the instances of structuralNavigationObject.
Queries fresh each time without caching to ensure accurate results
when returning to a page after switching applications.
"""
modalDialog = self._script.utilities.getModalDialog(cthulhu_state.locusOfFocus)
inModalDialog = bool(modalDialog)
@@ -804,29 +804,11 @@ class StructuralNavigation:
f"{self._inModalDialog} to {inModalDialog}"
)
debug.printMessage(debug.LEVEL_INFO, msg, True)
self.clearCache()
self._inModalDialog = inModalDialog
def filterZombies(matchList):
if not matchList:
return []
return [match for match in matchList if not self._script.utilities.isZombie(match)]
document = self._script.utilities.documentFrame()
cache = self._objectCache.get(hash(document), {})
key = f"{structuralNavigationObject.objType}:{arg}"
matches = cache.get(key, [])
if matches:
matches = filterZombies(matches)
if matches:
tokens = ["STRUCTURAL NAVIGATION: Returning", len(matches), "matches from cache"]
debug.printTokens(debug.LEVEL_INFO, tokens, True)
return matches.copy()
tokens = ["STRUCTURAL NAVIGATION: Cached matches are zombies; refreshing"]
debug.printTokens(debug.LEVEL_INFO, tokens, True)
cache.pop(key, None)
self._objectCache[hash(document)] = cache
if not document:
return []
if structuralNavigationObject.getter:
matches = structuralNavigationObject.getter(document, arg)
@@ -843,15 +825,12 @@ class StructuralNavigation:
if inModalDialog:
originalSize = len(matches)
matches = [m for m in matches if AXObject.find_ancestor(m, lambda x: x == modalDialog)]
tokens = ["STRUCTURAL NAVIGATION: Removed", {originalSize - len(matches)},
tokens = ["STRUCTURAL NAVIGATION: Removed", originalSize - len(matches),
"objects outside of modal dialog", modalDialog]
debug.printTokens(debug.LEVEL_INFO, tokens, True)
matches = filterZombies(matches)
rv = matches.copy()
cache[key] = matches
self._objectCache[hash(document)] = cache
return rv
# Filter out zombie objects and return
return [m for m in matches if not self._script.utilities.isZombie(m)]
def goEdge(self, structuralNavigationObject, isStart, container=None, arg=None):
if container is None: