diff --git a/source/NVDAObjects/IAccessible/ia2TextMozilla.py b/source/NVDAObjects/IAccessible/ia2TextMozilla.py index 0d485c7017f..3e23e78a7ce 100644 --- a/source/NVDAObjects/IAccessible/ia2TextMozilla.py +++ b/source/NVDAObjects/IAccessible/ia2TextMozilla.py @@ -29,9 +29,9 @@ def _getRawTextInfo(obj) -> Type[offsets.OffsetsTextInfo]: - if obj.TextInfo is NVDAObjectTextInfo: - return NVDAObjectTextInfo - return IA2TextTextInfo + if hasattr(obj, "IAccessibleTextObject"): + return IA2TextTextInfo + return NVDAObjectTextInfo def _getEmbedded(obj, offset) -> typing.Optional[IAccessible]: diff --git a/source/NVDAObjects/IAccessible/ia2Web.py b/source/NVDAObjects/IAccessible/ia2Web.py index 8f68fbb2fb6..fc4641dbaca 100644 --- a/source/NVDAObjects/IAccessible/ia2Web.py +++ b/source/NVDAObjects/IAccessible/ia2Web.py @@ -107,7 +107,7 @@ class Ia2Web(IAccessible): # The IAccessibleText implementation in web browsers exposes embedded object # characters which need to be traversed to read the content. That isn't useful # to users. - _shouldUseTextInfoForReading = False + TextInfo = NVDAObjects.NVDAObjectTextInfo def isDescendantOf(self, obj: "NVDAObjects.NVDAObject") -> bool: if obj.windowHandle != self.windowHandle: diff --git a/source/NVDAObjects/__init__.py b/source/NVDAObjects/__init__.py index 4ef45093c48..d741c51196c 100644 --- a/source/NVDAObjects/__init__.py +++ b/source/NVDAObjects/__init__.py @@ -1605,12 +1605,6 @@ def _get__hasNavigableText(self): else: return False - #: Whether the TextInfo should be used for the review cursor, the read current - #: line command, etc. This should be False where the TextInfo is only used - #: internally and doesn't provide text that is suitable for presentation to the - #: user; e.g. it includes raw embedded object characters. - _shouldUseTextInfoForReading: bool = True - def _get_hasIrrelevantLocation(self): """Returns whether the location of this object is irrelevant for mouse or magnification tracking or highlighting, either because it is programatically hidden (State.INVISIBLE), off screen or the object has no location.""" diff --git a/source/globalCommands.py b/source/globalCommands.py index a95c2d5e867..c79206a66f4 100755 --- a/source/globalCommands.py +++ b/source/globalCommands.py @@ -262,22 +262,15 @@ def script_toggleCurrentAppSleepMode(self, gesture): def script_reportCurrentLine(self, gesture): obj = api.getFocusObject() treeInterceptor = obj.treeInterceptor - useTextInfo: bool = False if ( isinstance(treeInterceptor, treeInterceptorHandler.DocumentTreeInterceptor) and not treeInterceptor.passThrough ): obj = treeInterceptor - useTextInfo = True - else: - useTextInfo = obj._shouldUseTextInfoForReading - if useTextInfo: - try: - info = obj.makeTextInfo(textInfos.POSITION_CARET) - except (NotImplementedError, RuntimeError): - info = obj.makeTextInfo(textInfos.POSITION_FIRST) - else: - info = NVDAObjectTextInfo(obj, textInfos.POSITION_FIRST) + try: + info = obj.makeTextInfo(textInfos.POSITION_CARET) + except (NotImplementedError, RuntimeError): + info = obj.makeTextInfo(textInfos.POSITION_FIRST) info.expand(textInfos.UNIT_LINE) scriptCount = getLastScriptRepeatCount() if scriptCount == 0: @@ -2792,6 +2785,7 @@ def _getNvdaObjWithAnnotationUnderCaret(self) -> Optional[NVDAObject]: relation' in that range, and we don't yet have a way for the user to select which one to report. For now, we minimise this risk by only reporting details at the current location. """ + _isDebugLogCatEnabled = bool(config.conf["debugLog"]["annotations"]) try: # Common cases use Caret Position: vbuf available or object supports text range # Eg editable text, or regular web content @@ -2799,28 +2793,26 @@ def _getNvdaObjWithAnnotationUnderCaret(self) -> Optional[NVDAObject]: caret: textInfos.TextInfo = api.getCaretPosition() except RuntimeError: log.debugWarning("Unable to get the caret position.", exc_info=True) - return None - caret.expand(textInfos.UNIT_CHARACTER) - objAtStart: NVDAObject = caret.NVDAObjectAtStart - _isDebugLogCatEnabled = bool(config.conf["debugLog"]["annotations"]) - if _isDebugLogCatEnabled: - log.debug(f"Trying with nvdaObject : {objAtStart}") - - if objAtStart.annotations: + else: + caret.expand(textInfos.UNIT_CHARACTER) + objAtStart: NVDAObject = caret.NVDAObjectAtStart if _isDebugLogCatEnabled: - log.debug("NVDAObjectAtStart of caret has details") - return objAtStart - elif api.getFocusObject(): + log.debug(f"Trying with nvdaObject : {objAtStart}") + if objAtStart.annotations: + if _isDebugLogCatEnabled: + log.debug("NVDAObjectAtStart of caret has details") + return objAtStart + + focus: NVDAObject = api.getFocusObject() + if focus: # If fetching from the caret position fails, try via the focus object # This case is to support where there is no virtual buffer or text interface and a caret position can # not be fetched. # There may still be an object with focus that has details. - # There isn't a known test case for this, however there isn't a known downside to attempt this. - focus = api.getFocusObject() if _isDebugLogCatEnabled: log.debug(f"Trying focus object: {focus}") - if objAtStart.annotations: + if focus.annotations: if _isDebugLogCatEnabled: log.debug("focus object has details, able to proceed") return focus diff --git a/source/review.py b/source/review.py index a9cf90dda61..0dfc14854ef 100644 --- a/source/review.py +++ b/source/review.py @@ -26,22 +26,18 @@ def getObjectPosition(obj: NVDAObject) -> tuple[textInfos.TextInfo, ScriptableOb :param obj: the NVDAObject to review :return: the TextInfo instance and the Scriptable object the TextInfo instance is referencing, or None on error. """ - useTextInfo: bool = obj._shouldUseTextInfoForReading - if useTextInfo: + try: + pos = obj.makeTextInfo(textInfos.POSITION_CARET) + except (NotImplementedError, RuntimeError): + # No caret supported, try first position instead try: - pos = obj.makeTextInfo(textInfos.POSITION_CARET) + pos = obj.makeTextInfo(textInfos.POSITION_FIRST) except (NotImplementedError, RuntimeError): - # No caret supported, try first position instead - try: - pos = obj.makeTextInfo(textInfos.POSITION_FIRST) - except (NotImplementedError, RuntimeError): - log.debugWarning( - f"{obj.TextInfo} does not support POSITION_FIRST, falling back to NVDAObjectTextInfo", - ) - # First position not supported either, return first position from a generic NVDAObjectTextInfo - useTextInfo = False - if not useTextInfo: - return NVDAObjectTextInfo(obj, textInfos.POSITION_FIRST), obj + log.debugWarning( + "%s does not support POSITION_FIRST, falling back to NVDAObjectTextInfo" % obj.TextInfo, + ) + # First position not supported either, return first position from a generic NVDAObjectTextInfo + return NVDAObjectTextInfo(obj, textInfos.POSITION_FIRST), obj return pos, pos.obj diff --git a/user_docs/en/changes.md b/user_docs/en/changes.md index 37feb02c838..9a0e91accd6 100644 --- a/user_docs/en/changes.md +++ b/user_docs/en/changes.md @@ -9,6 +9,8 @@ ### Changes ### Bug Fixes +* In focus mode in web browsers, it is now possible to review and spell the labels of controls when those labels are specifically provided for accessibility; e.g. via aria-label or aria-labelledby. (#15159, @jcsteh) +* In Mozilla Firefox, reporting annotation details now works correctly in focus mode on controls which are not editable text. (#20132, @jcsteh) ### Changes for Developers @@ -93,7 +95,6 @@ The setting is disabled by default. (#20013, @LeonarddeR) * Fixed NVDA freezing when navigating in JetBrains IDEs. (#16741, @christopherpross) * Speech dictionary entries of type Whole word now correctly handle words containing Unicode combining marks (e.g. Hebrew niqqud, Arabic harakat). (#20013, @LeonarddeR) * In particular, Whole word entries no longer incorrectly match inside larger words when those words contain combining marks. -* In focus mode in web browsers, it is now possible to review and spell the labels of controls when those labels are specifically provided for accessibility; e.g. via aria-label or aria-labelledby. (#15159, @jcsteh) ### Changes for Developers