diff --git a/source/editableText.py b/source/editableText.py index 5441c628d4d..e94cf4559af 100755 --- a/source/editableText.py +++ b/source/editableText.py @@ -85,27 +85,34 @@ def _hasCaretMoved(self, bookmark, retryInterval=0.01, timeout=None, origWord=No if eventHandler.isPendingEvents("gainFocus"): log.debug("Focus event. Elapsed %g sec" % elapsed) return (True,None) + # Caret events are unreliable in some controls. + # Only use them if we consider them safe to rely on for a particular control, + # and only if they arrive within C{_useEvents_maxTimeoutSec} seconds + # after causing the event to occur. + if ( + elapsed <= self._useEvents_maxTimeoutSec + and self.caretMovementDetectionUsesEvents + and (eventHandler.isPendingEvents("caret") or eventHandler.isPendingEvents("textChange")) + ): + log.debug( + "Caret move detected using event. Elapsed %g sec, retries %d" + % (elapsed, retries) + ) + # We must fetch the caret here rather than above the isPendingEvents check + # to avoid a race condition where an event is queued from a background + # thread just after we query the caret. In that case, the caret info we + # retrieved might be stale. + try: + newInfo = self.makeTextInfo(textInfos.POSITION_CARET) + except (RuntimeError, NotImplementedError): + newInfo = None + return (True, newInfo) # If the focus changes after this point, fetching the caret may fail, # but we still want to stay in this loop. try: newInfo = self.makeTextInfo(textInfos.POSITION_CARET) - except (RuntimeError,NotImplementedError): + except (RuntimeError, NotImplementedError): newInfo = None - else: - # Caret events are unreliable in some controls. - # Only use them if we consider them safe to rely on for a particular control, - # and only if they arrive within C{_useEvents_maxTimeoutSec} seconds - # after causing the event to occur. - if ( - elapsed <= self._useEvents_maxTimeoutSec - and self.caretMovementDetectionUsesEvents - and (eventHandler.isPendingEvents("caret") or eventHandler.isPendingEvents("textChange")) - ): - log.debug( - "Caret move detected using event. Elapsed %g sec, retries %d" - % (elapsed, retries) - ) - return (True,newInfo) # Try to detect with bookmarks. newBookmark = None if newInfo: diff --git a/user_docs/en/changes.md b/user_docs/en/changes.md index c3e240a0bb7..6acc84858d0 100644 --- a/user_docs/en/changes.md +++ b/user_docs/en/changes.md @@ -59,6 +59,7 @@ Unicode CLDR has also been updated. * NVDA will correctly announce selection changes when editing a cell's text in Microsoft Excel. (#15843) * In applications using Java Access Bridge, NVDA will now correctly read the last blank line of a text instead of repeating the previous line. (#9376, @dmitrii-drobotov) * In LibreOffice Writer (version 24.8 and newer), when toggling text formatting (bold, italic, underline, subscript/superscript, alignment) using the corresponding keyboard shortcut, NVDA announces the new formatting attribute (e.g. "Bold on", "Bold off"). (#4248, @michaelweghorn) +* When navigating with the cursor keys in text boxes in applications which use UI Automation, NVDA no longer sometimes reports the wrong character, word, etc. (#16711, @jcsteh) ### Changes for Developers