From 1a8e690c3851474fef00b5687baa971b12a3a76c Mon Sep 17 00:00:00 2001 From: Michael Curran Date: Fri, 29 Nov 2019 12:55:12 +1000 Subject: [PATCH 01/11] WinConsoleUIATextInfo: As IUIAutomationTextPattern::getVisibleRanges is very broken, use IUIAutomationTextPattern::rangeFromPoint for the top left and bottom right of the console window. --- source/NVDAObjects/UIA/winConsoleUIA.py | 39 +++++++++++++------------ 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/source/NVDAObjects/UIA/winConsoleUIA.py b/source/NVDAObjects/UIA/winConsoleUIA.py index 61b119de230..1eb46f40f91 100644 --- a/source/NVDAObjects/UIA/winConsoleUIA.py +++ b/source/NVDAObjects/UIA/winConsoleUIA.py @@ -25,19 +25,27 @@ class consoleUIATextInfo(UIATextInfo): _expandCollapseBeforeReview = False def __init__(self, obj, position, _rangeObj=None): + # We want to limit textInfos to just the visible part of the console. + # Therefore we specifically handle POSITION_FIRST, POSITION_LAST and POSITION_ALL. + # We could use IUIAutomationTextRange::getVisibleRanges, but it seems very broken in consoles + # once more than a few screens worth of content has been written to the console. + # Therefore we resort to using IUIAutomationTextPattern::rangeFromPoint + # for the top left, and bottom right of the console window. + if position is textInfos.POSITION_FIRST: + _rangeObj = self.__class__(obj, obj.location.topLeft)._rangeObj + elif position is textInfos.POSITION_LAST: + tempInfo = self.__class__(obj, obj.location.bottomRight) + # Consoles sometimes do not honor the x coordinate, + # so therefore ensure we are really at the end of the line. + tempInfo.expand(textInfos.UNIT_LINE) + tempInfo.collapse(end=True) + _rangeObj = tempInfo._rangeObj + elif position is textInfos.POSITION_ALL: + first = self.__class__(obj, textInfos.POSITION_FIRST) + last = self.__class__(obj, textInfos.POSITION_LAST) + first.setEndPoint(last,"endToEnd") + _rangeObj = first._rangeObj super(consoleUIATextInfo, self).__init__(obj, position, _rangeObj) - # Re-implement POSITION_FIRST and POSITION_LAST in terms of - # visible ranges to fix review top/bottom scripts. - if position == textInfos.POSITION_FIRST: - visiRanges = self.obj.UIATextPattern.GetVisibleRanges() - firstVisiRange = visiRanges.GetElement(0) - self._rangeObj = firstVisiRange - self.collapse() - elif position == textInfos.POSITION_LAST: - visiRanges = self.obj.UIATextPattern.GetVisibleRanges() - lastVisiRange = visiRanges.GetElement(visiRanges.length - 1) - self._rangeObj = lastVisiRange - self.collapse(True) def collapse(self, end=False): """Works around a UIA bug on Windows 10 1803 and later.""" @@ -272,13 +280,6 @@ def _get_TextInfo(self): bounds review to the visible text.""" return consoleUIATextInfo - def _getTextLines(self): - # Filter out extraneous empty lines from UIA - ptr = self.UIATextPattern.GetVisibleRanges() - res = [ptr.GetElement(i).GetText(-1) for i in range(ptr.length)] - return res - - def findExtraOverlayClasses(obj, clsList): if obj.UIAElement.cachedAutomationId == "Text Area": clsList.append(WinConsoleUIA) From 3087fd39bbea94db02b7971cd27e9d9844e023d0 Mon Sep 17 00:00:00 2001 From: Michael Curran Date: Fri, 29 Nov 2019 16:13:46 +1000 Subject: [PATCH 02/11] Fix linting issues. --- source/NVDAObjects/UIA/winConsoleUIA.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/NVDAObjects/UIA/winConsoleUIA.py b/source/NVDAObjects/UIA/winConsoleUIA.py index 1eb46f40f91..e131bb3afb6 100644 --- a/source/NVDAObjects/UIA/winConsoleUIA.py +++ b/source/NVDAObjects/UIA/winConsoleUIA.py @@ -35,7 +35,7 @@ def __init__(self, obj, position, _rangeObj=None): _rangeObj = self.__class__(obj, obj.location.topLeft)._rangeObj elif position is textInfos.POSITION_LAST: tempInfo = self.__class__(obj, obj.location.bottomRight) - # Consoles sometimes do not honor the x coordinate, + # Consoles sometimes do not honor the x coordinate, # so therefore ensure we are really at the end of the line. tempInfo.expand(textInfos.UNIT_LINE) tempInfo.collapse(end=True) @@ -43,7 +43,7 @@ def __init__(self, obj, position, _rangeObj=None): elif position is textInfos.POSITION_ALL: first = self.__class__(obj, textInfos.POSITION_FIRST) last = self.__class__(obj, textInfos.POSITION_LAST) - first.setEndPoint(last,"endToEnd") + first.setEndPoint(last, "endToEnd") _rangeObj = first._rangeObj super(consoleUIATextInfo, self).__init__(obj, position, _rangeObj) From 32b4e30eb44d31643480cb5940b3d3b3e4ebefbb Mon Sep 17 00:00:00 2001 From: Michael Curran Date: Mon, 2 Dec 2019 07:57:28 +1000 Subject: [PATCH 03/11] WinConsoleUIA: override _getTextLines with a faster implementation that just uses Python string splitlines. --- source/NVDAObjects/UIA/winConsoleUIA.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/source/NVDAObjects/UIA/winConsoleUIA.py b/source/NVDAObjects/UIA/winConsoleUIA.py index e131bb3afb6..d912d1f5a1f 100644 --- a/source/NVDAObjects/UIA/winConsoleUIA.py +++ b/source/NVDAObjects/UIA/winConsoleUIA.py @@ -280,6 +280,14 @@ def _get_TextInfo(self): bounds review to the visible text.""" return consoleUIATextInfo + def _getTextLines(self): + # This override of _getTextLines takes advantage of the fact that + # the console text contains linefeeds for every line + # Thus a simple string splitlines is much faster than splitting by unit line. + ti = self.makeTextInfo(textInfos.POSITION_ALL) + text = ti.text or "" + return text.splitlines() + def findExtraOverlayClasses(obj, clsList): if obj.UIAElement.cachedAutomationId == "Text Area": clsList.append(WinConsoleUIA) From 44cb3702443420b8d4fb9cba20dd313e92587a2e Mon Sep 17 00:00:00 2001 From: Michael Curran Date: Mon, 2 Dec 2019 08:14:40 +1000 Subject: [PATCH 04/11] Fix linting issues. --- source/NVDAObjects/UIA/winConsoleUIA.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/NVDAObjects/UIA/winConsoleUIA.py b/source/NVDAObjects/UIA/winConsoleUIA.py index d912d1f5a1f..8c2a1607221 100644 --- a/source/NVDAObjects/UIA/winConsoleUIA.py +++ b/source/NVDAObjects/UIA/winConsoleUIA.py @@ -281,7 +281,7 @@ def _get_TextInfo(self): return consoleUIATextInfo def _getTextLines(self): - # This override of _getTextLines takes advantage of the fact that + # This override of _getTextLines takes advantage of the fact that # the console text contains linefeeds for every line # Thus a simple string splitlines is much faster than splitting by unit line. ti = self.makeTextInfo(textInfos.POSITION_ALL) From fe3cda9fea0668be5f9fdfeca773ba2d9b2dd7c1 Mon Sep 17 00:00:00 2001 From: Michael Curran Date: Tue, 3 Dec 2019 11:22:20 +1000 Subject: [PATCH 05/11] Don't use isTextRangeOffscreen, and further improve POSITION_LAST to fix review bounds. --- source/NVDAObjects/UIA/winConsoleUIA.py | 32 +++++++++++++++---------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/source/NVDAObjects/UIA/winConsoleUIA.py b/source/NVDAObjects/UIA/winConsoleUIA.py index 8c2a1607221..bb5889b4922 100644 --- a/source/NVDAObjects/UIA/winConsoleUIA.py +++ b/source/NVDAObjects/UIA/winConsoleUIA.py @@ -34,11 +34,13 @@ def __init__(self, obj, position, _rangeObj=None): if position is textInfos.POSITION_FIRST: _rangeObj = self.__class__(obj, obj.location.topLeft)._rangeObj elif position is textInfos.POSITION_LAST: - tempInfo = self.__class__(obj, obj.location.bottomRight) - # Consoles sometimes do not honor the x coordinate, - # so therefore ensure we are really at the end of the line. + # Asking for the range at the bottom right of the window + # Seems to sometimes ignore the x coordinate. + # Therefore use the bottom left, then move the to last character on that line. + tempInfo = self.__class__(obj, obj.location.bottomLeft) tempInfo.expand(textInfos.UNIT_LINE) - tempInfo.collapse(end=True) + UIATextInfo.move(tempInfo,textInfos.UNIT_CHARACTER,-1,endPoint="end") + tempInfo.setEndPoint(tempInfo,"startToEnd") _rangeObj = tempInfo._rangeObj elif position is textInfos.POSITION_ALL: first = self.__class__(obj, textInfos.POSITION_FIRST) @@ -62,14 +64,12 @@ def collapse(self, end=False): ) def move(self, unit, direction, endPoint=None): - oldRange = None + oldInfo = None if self.basePosition != textInfos.POSITION_CARET: # Insure we haven't gone beyond the visible text. # UIA adds thousands of blank lines to the end of the console. - visiRanges = self.obj.UIATextPattern.GetVisibleRanges() - visiLength = visiRanges.length - if visiLength > 0: - oldRange = self._rangeObj.clone() + boundingInfo = self.obj.makeTextInfo(textInfos.POSITION_ALL) + oldInfo = self.copy() if unit == textInfos.UNIT_WORD and direction != 0: # UIA doesn't implement word movement, so we need to do it manually. # Relative to the current line, calculate our offset @@ -126,11 +126,17 @@ def move(self, unit, direction, endPoint=None): endPoint) try: if ( - oldRange - and isTextRangeOffscreen(self._rangeObj, visiRanges) - and not isTextRangeOffscreen(oldRange, visiRanges) + oldInfo + and ( + self.compareEndPoints(boundingInfo, "startToStart") < 0 or + self.compareEndPoints(boundingInfo, "startToEnd") >= 0 + ) + and not ( + oldInfo.compareEndPoints(boundingInfo, "startToStart") < 0 or + oldInfo.compareEndPoints(boundingInfo, "startToEnd") >= 0 + ) ): - self._rangeObj = oldRange + self._rangeObj = oldInfo._rangeObj return 0 except (COMError, RuntimeError): pass From 598b83f22e27f77fdb1db731a37e4c40dddea825 Mon Sep 17 00:00:00 2001 From: Michael Curran Date: Tue, 3 Dec 2019 11:37:00 +1000 Subject: [PATCH 06/11] Fix linting issues. --- source/NVDAObjects/UIA/winConsoleUIA.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/source/NVDAObjects/UIA/winConsoleUIA.py b/source/NVDAObjects/UIA/winConsoleUIA.py index bb5889b4922..93ae59b1872 100644 --- a/source/NVDAObjects/UIA/winConsoleUIA.py +++ b/source/NVDAObjects/UIA/winConsoleUIA.py @@ -36,11 +36,11 @@ def __init__(self, obj, position, _rangeObj=None): elif position is textInfos.POSITION_LAST: # Asking for the range at the bottom right of the window # Seems to sometimes ignore the x coordinate. - # Therefore use the bottom left, then move the to last character on that line. + # Therefore use the bottom left, then move the to last character on that line. tempInfo = self.__class__(obj, obj.location.bottomLeft) tempInfo.expand(textInfos.UNIT_LINE) - UIATextInfo.move(tempInfo,textInfos.UNIT_CHARACTER,-1,endPoint="end") - tempInfo.setEndPoint(tempInfo,"startToEnd") + UIATextInfo.move(tempInfo, textInfos.UNIT_CHARACTER, -1, endPoint="end") + tempInfo.setEndPoint(tempInfo, "startToEnd") _rangeObj = tempInfo._rangeObj elif position is textInfos.POSITION_ALL: first = self.__class__(obj, textInfos.POSITION_FIRST) @@ -128,12 +128,12 @@ def move(self, unit, direction, endPoint=None): if ( oldInfo and ( - self.compareEndPoints(boundingInfo, "startToStart") < 0 or - self.compareEndPoints(boundingInfo, "startToEnd") >= 0 + self.compareEndPoints(boundingInfo, "startToStart") < 0 + or self.compareEndPoints(boundingInfo, "startToEnd") >= 0 ) and not ( - oldInfo.compareEndPoints(boundingInfo, "startToStart") < 0 or - oldInfo.compareEndPoints(boundingInfo, "startToEnd") >= 0 + oldInfo.compareEndPoints(boundingInfo, "startToStart") < 0 + or oldInfo.compareEndPoints(boundingInfo, "startToEnd") >= 0 ) ): self._rangeObj = oldInfo._rangeObj From 2224f50c46e3acc0bcc3e234464974914cb8921f Mon Sep 17 00:00:00 2001 From: Michael Curran Date: Tue, 3 Dec 2019 12:25:46 +1000 Subject: [PATCH 07/11] WinConsoleUIATextInfo: ensure ranges are collapsed after moves. --- source/NVDAObjects/UIA/winConsoleUIA.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source/NVDAObjects/UIA/winConsoleUIA.py b/source/NVDAObjects/UIA/winConsoleUIA.py index 93ae59b1872..e7bf78577c5 100644 --- a/source/NVDAObjects/UIA/winConsoleUIA.py +++ b/source/NVDAObjects/UIA/winConsoleUIA.py @@ -124,6 +124,11 @@ def move(self, unit, direction, endPoint=None): else: # moving by a unit other than word res = super(consoleUIATextInfo, self).move(unit, direction, endPoint) + if not endPoint: + # #10191: IUIAutomationTextRange::move in consoles does not correctly produce a collapsed range + # after moving. + # Therefore manually collapse. + self.collapse() try: if ( oldInfo From 2642e759be94f53694d4c088d400824b3116221e Mon Sep 17 00:00:00 2001 From: Michael Curran Date: Tue, 3 Dec 2019 12:29:35 +1000 Subject: [PATCH 08/11] Remove TextInfo._expandCollapseBeforeReview as WinConsoleUIA no longer needs it. --- source/NVDAObjects/UIA/winConsoleUIA.py | 5 ----- source/globalCommands.py | 30 ++++++++++--------------- source/textInfos/__init__.py | 4 ---- 3 files changed, 12 insertions(+), 27 deletions(-) diff --git a/source/NVDAObjects/UIA/winConsoleUIA.py b/source/NVDAObjects/UIA/winConsoleUIA.py index e7bf78577c5..1bc3563fe17 100644 --- a/source/NVDAObjects/UIA/winConsoleUIA.py +++ b/source/NVDAObjects/UIA/winConsoleUIA.py @@ -18,11 +18,6 @@ class consoleUIATextInfo(UIATextInfo): - #: At least on Windows 10 1903, expanding then collapsing the text info - #: caused review to get stuck, so disable it. - #: There may be no need to disable this anymore, but doing so doesn't seem - #: to do much good either. - _expandCollapseBeforeReview = False def __init__(self, obj, position, _rangeObj=None): # We want to limit textInfos to just the visible part of the console. diff --git a/source/globalCommands.py b/source/globalCommands.py index 03788c8752c..59df3f7714d 100755 --- a/source/globalCommands.py +++ b/source/globalCommands.py @@ -1026,9 +1026,8 @@ def script_review_top(self,gesture): def script_review_previousLine(self,gesture): info=api.getReviewPosition().copy() - if info._expandCollapseBeforeReview: - info.expand(textInfos.UNIT_LINE) - info.collapse() + info.expand(textInfos.UNIT_LINE) + info.collapse() res=info.move(textInfos.UNIT_LINE,-1) if res==0: # Translators: a message reported when review cursor is at the top line of the current navigator object. @@ -1058,9 +1057,8 @@ def script_review_currentLine(self,gesture): def script_review_nextLine(self,gesture): info=api.getReviewPosition().copy() - if info._expandCollapseBeforeReview: - info.expand(textInfos.UNIT_LINE) - info.collapse() + info.expand(textInfos.UNIT_LINE) + info.collapse() res=info.move(textInfos.UNIT_LINE,1) if res==0: # Translators: a message reported when review cursor is at the bottom line of the current navigator object. @@ -1086,9 +1084,8 @@ def script_review_bottom(self,gesture): def script_review_previousWord(self,gesture): info=api.getReviewPosition().copy() - if info._expandCollapseBeforeReview: - info.expand(textInfos.UNIT_WORD) - info.collapse() + info.expand(textInfos.UNIT_WORD) + info.collapse() res=info.move(textInfos.UNIT_WORD,-1) if res==0: # Translators: a message reported when review cursor is at the top line of the current navigator object. @@ -1117,9 +1114,8 @@ def script_review_currentWord(self,gesture): def script_review_nextWord(self,gesture): info=api.getReviewPosition().copy() - if info._expandCollapseBeforeReview: - info.expand(textInfos.UNIT_WORD) - info.collapse() + info.expand(textInfos.UNIT_WORD) + info.collapse() res=info.move(textInfos.UNIT_WORD,1) if res==0: # Translators: a message reported when review cursor is at the bottom line of the current navigator object. @@ -1148,9 +1144,8 @@ def script_review_previousCharacter(self,gesture): lineInfo=api.getReviewPosition().copy() lineInfo.expand(textInfos.UNIT_LINE) charInfo=api.getReviewPosition().copy() - if charInfo._expandCollapseBeforeReview: - charInfo.expand(textInfos.UNIT_CHARACTER) - charInfo.collapse() + charInfo.expand(textInfos.UNIT_CHARACTER) + charInfo.collapse() res=charInfo.move(textInfos.UNIT_CHARACTER,-1) if res==0 or charInfo.compareEndPoints(lineInfo,"startToStart")<0: # Translators: a message reported when review cursor is at the leftmost character of the current navigator object's text. @@ -1195,9 +1190,8 @@ def script_review_nextCharacter(self,gesture): lineInfo=api.getReviewPosition().copy() lineInfo.expand(textInfos.UNIT_LINE) charInfo=api.getReviewPosition().copy() - if charInfo._expandCollapseBeforeReview: - charInfo.expand(textInfos.UNIT_CHARACTER) - charInfo.collapse() + charInfo.expand(textInfos.UNIT_CHARACTER) + charInfo.collapse() res=charInfo.move(textInfos.UNIT_CHARACTER,1) if res==0 or charInfo.compareEndPoints(lineInfo,"endToEnd")>=0: # Translators: a message reported when review cursor is at the rightmost character of the current navigator object's text. diff --git a/source/textInfos/__init__.py b/source/textInfos/__init__.py index 32c71bb924c..0dc623ff00b 100755 --- a/source/textInfos/__init__.py +++ b/source/textInfos/__init__.py @@ -280,10 +280,6 @@ class TextInfo(baseObject.AutoPropertyObject): @type bookmark: L{Bookmark} """ - #: whether this textInfo should be expanded then collapsed around its enclosing unit before review. - #: This can be problematic for some implementations. - _expandCollapseBeforeReview = True - def __init__(self,obj,position): """Constructor. Subclasses must extend this, calling the superclass method first. From f9201d9ba11230d0c49c00eaccf843d2219bdbf8 Mon Sep 17 00:00:00 2001 From: Michael Curran Date: Tue, 3 Dec 2019 13:02:02 +1000 Subject: [PATCH 09/11] WinConsoleUIATextInfo: when calculating word / line offsets, grab text directly with IUIAutomationTextRange::getText as WinConsoleUIATextInfo.text has been changed to return a space for empty ranges. --- source/NVDAObjects/UIA/winConsoleUIA.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/NVDAObjects/UIA/winConsoleUIA.py b/source/NVDAObjects/UIA/winConsoleUIA.py index f98dd46e0dd..a4a1c43aecf 100644 --- a/source/NVDAObjects/UIA/winConsoleUIA.py +++ b/source/NVDAObjects/UIA/winConsoleUIA.py @@ -221,12 +221,12 @@ def _getCurrentOffsetInThisLine(self, lineInfo): # position a textInfo from the start of the line up to the current position. charInfo = lineInfo.copy() charInfo.setEndPoint(self, "endToStart") - text = charInfo.text + text = charInfo._rangeObj.getText(-1) offset = textUtils.WideStringOffsetConverter(text).wideStringLength return offset def _getWordOffsetsInThisLine(self, offset, lineInfo): - lineText = lineInfo.text or u" " + lineText = lineInfo._rangeObj.getText(-1) # Convert NULL and non-breaking space to space to make sure # that words will break on them lineText = lineText.translate({0: u' ', 0xa0: u' '}) From d1cadc5b395ef5db11285cf159be619c3c229c96 Mon Sep 17 00:00:00 2001 From: Michael Curran Date: Wed, 4 Dec 2019 18:34:31 +1000 Subject: [PATCH 10/11] Address review actions. --- source/NVDAObjects/UIA/winConsoleUIA.py | 43 +++++++++++++++---------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/source/NVDAObjects/UIA/winConsoleUIA.py b/source/NVDAObjects/UIA/winConsoleUIA.py index a4a1c43aecf..4b47d85c81a 100644 --- a/source/NVDAObjects/UIA/winConsoleUIA.py +++ b/source/NVDAObjects/UIA/winConsoleUIA.py @@ -31,9 +31,13 @@ def __init__(self, obj, position, _rangeObj=None): elif position is textInfos.POSITION_LAST: # Asking for the range at the bottom right of the window # Seems to sometimes ignore the x coordinate. - # Therefore use the bottom left, then move the to last character on that line. + # Therefore use the bottom left, then move to the last character on that line. tempInfo = self.__class__(obj, obj.location.bottomLeft) tempInfo.expand(textInfos.UNIT_LINE) + # We must pull back the end by one character otherwise when we collapse to end, + # a console bug results in a textRange covering the entire console buffer! + # Strangely the *very* last character is a special blank point + # so we never seem to miss a real character. UIATextInfo.move(tempInfo, textInfos.UNIT_CHARACTER, -1, endPoint="end") tempInfo.setEndPoint(tempInfo, "startToEnd") _rangeObj = tempInfo._rangeObj @@ -124,22 +128,27 @@ def move(self, unit, direction, endPoint=None): # after moving. # Therefore manually collapse. self.collapse() - try: - if ( - oldInfo - and ( - self.compareEndPoints(boundingInfo, "startToStart") < 0 - or self.compareEndPoints(boundingInfo, "startToEnd") >= 0 - ) - and not ( - oldInfo.compareEndPoints(boundingInfo, "startToStart") < 0 - or oldInfo.compareEndPoints(boundingInfo, "startToEnd") >= 0 - ) - ): - self._rangeObj = oldInfo._rangeObj - return 0 - except (COMError, RuntimeError): - pass + # Console textRanges have access to the entire console buffer. + # However, we want to limit ourselves to onscreen text. + # Therefore, if the textInfo was originally visible, + # but we are now aboe or below the visible range, + # Restore the original textRange and pretend the move didn't work. + if oldInfo: + try: + if ( + ( + self.compareEndPoints(boundingInfo, "startToStart") < 0 + or self.compareEndPoints(boundingInfo, "startToEnd") >= 0 + ) + and not ( + oldInfo.compareEndPoints(boundingInfo, "startToStart") < 0 + or oldInfo.compareEndPoints(boundingInfo, "startToEnd") >= 0 + ) + ): + self._rangeObj = oldInfo._rangeObj + return 0 + except (COMError, RuntimeError): + pass return res def expand(self, unit): From ed458b3eee8166cb0409a91e32116c5bad14fdfb Mon Sep 17 00:00:00 2001 From: Michael Curran Date: Wed, 4 Dec 2019 18:55:36 +1000 Subject: [PATCH 11/11] Update source/NVDAObjects/UIA/winConsoleUIA.py Co-Authored-By: Leonard de Ruijter --- source/NVDAObjects/UIA/winConsoleUIA.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/NVDAObjects/UIA/winConsoleUIA.py b/source/NVDAObjects/UIA/winConsoleUIA.py index 4b47d85c81a..a987c4105e3 100644 --- a/source/NVDAObjects/UIA/winConsoleUIA.py +++ b/source/NVDAObjects/UIA/winConsoleUIA.py @@ -131,7 +131,7 @@ def move(self, unit, direction, endPoint=None): # Console textRanges have access to the entire console buffer. # However, we want to limit ourselves to onscreen text. # Therefore, if the textInfo was originally visible, - # but we are now aboe or below the visible range, + # but we are now above or below the visible range, # Restore the original textRange and pretend the move didn't work. if oldInfo: try: