Skip to content

Commit 46b0888

Browse files
Merge fe3cda9 into 6fc6637
2 parents 6fc6637 + fe3cda9 commit 46b0888

1 file changed

Lines changed: 41 additions & 26 deletions

File tree

source/NVDAObjects/UIA/winConsoleUIA.py

Lines changed: 41 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -25,19 +25,29 @@ class consoleUIATextInfo(UIATextInfo):
2525
_expandCollapseBeforeReview = False
2626

2727
def __init__(self, obj, position, _rangeObj=None):
28+
# We want to limit textInfos to just the visible part of the console.
29+
# Therefore we specifically handle POSITION_FIRST, POSITION_LAST and POSITION_ALL.
30+
# We could use IUIAutomationTextRange::getVisibleRanges, but it seems very broken in consoles
31+
# once more than a few screens worth of content has been written to the console.
32+
# Therefore we resort to using IUIAutomationTextPattern::rangeFromPoint
33+
# for the top left, and bottom right of the console window.
34+
if position is textInfos.POSITION_FIRST:
35+
_rangeObj = self.__class__(obj, obj.location.topLeft)._rangeObj
36+
elif position is textInfos.POSITION_LAST:
37+
# Asking for the range at the bottom right of the window
38+
# Seems to sometimes ignore the x coordinate.
39+
# Therefore use the bottom left, then move the to last character on that line.
40+
tempInfo = self.__class__(obj, obj.location.bottomLeft)
41+
tempInfo.expand(textInfos.UNIT_LINE)
42+
UIATextInfo.move(tempInfo,textInfos.UNIT_CHARACTER,-1,endPoint="end")
43+
tempInfo.setEndPoint(tempInfo,"startToEnd")
44+
_rangeObj = tempInfo._rangeObj
45+
elif position is textInfos.POSITION_ALL:
46+
first = self.__class__(obj, textInfos.POSITION_FIRST)
47+
last = self.__class__(obj, textInfos.POSITION_LAST)
48+
first.setEndPoint(last, "endToEnd")
49+
_rangeObj = first._rangeObj
2850
super(consoleUIATextInfo, self).__init__(obj, position, _rangeObj)
29-
# Re-implement POSITION_FIRST and POSITION_LAST in terms of
30-
# visible ranges to fix review top/bottom scripts.
31-
if position == textInfos.POSITION_FIRST:
32-
visiRanges = self.obj.UIATextPattern.GetVisibleRanges()
33-
firstVisiRange = visiRanges.GetElement(0)
34-
self._rangeObj = firstVisiRange
35-
self.collapse()
36-
elif position == textInfos.POSITION_LAST:
37-
visiRanges = self.obj.UIATextPattern.GetVisibleRanges()
38-
lastVisiRange = visiRanges.GetElement(visiRanges.length - 1)
39-
self._rangeObj = lastVisiRange
40-
self.collapse(True)
4151

4252
def collapse(self, end=False):
4353
"""Works around a UIA bug on Windows 10 1803 and later."""
@@ -54,14 +64,12 @@ def collapse(self, end=False):
5464
)
5565

5666
def move(self, unit, direction, endPoint=None):
57-
oldRange = None
67+
oldInfo = None
5868
if self.basePosition != textInfos.POSITION_CARET:
5969
# Insure we haven't gone beyond the visible text.
6070
# UIA adds thousands of blank lines to the end of the console.
61-
visiRanges = self.obj.UIATextPattern.GetVisibleRanges()
62-
visiLength = visiRanges.length
63-
if visiLength > 0:
64-
oldRange = self._rangeObj.clone()
71+
boundingInfo = self.obj.makeTextInfo(textInfos.POSITION_ALL)
72+
oldInfo = self.copy()
6573
if unit == textInfos.UNIT_WORD and direction != 0:
6674
# UIA doesn't implement word movement, so we need to do it manually.
6775
# Relative to the current line, calculate our offset
@@ -118,11 +126,17 @@ def move(self, unit, direction, endPoint=None):
118126
endPoint)
119127
try:
120128
if (
121-
oldRange
122-
and isTextRangeOffscreen(self._rangeObj, visiRanges)
123-
and not isTextRangeOffscreen(oldRange, visiRanges)
129+
oldInfo
130+
and (
131+
self.compareEndPoints(boundingInfo, "startToStart") < 0 or
132+
self.compareEndPoints(boundingInfo, "startToEnd") >= 0
133+
)
134+
and not (
135+
oldInfo.compareEndPoints(boundingInfo, "startToStart") < 0 or
136+
oldInfo.compareEndPoints(boundingInfo, "startToEnd") >= 0
137+
)
124138
):
125-
self._rangeObj = oldRange
139+
self._rangeObj = oldInfo._rangeObj
126140
return 0
127141
except (COMError, RuntimeError):
128142
pass
@@ -273,11 +287,12 @@ def _get_TextInfo(self):
273287
return consoleUIATextInfo
274288

275289
def _getTextLines(self):
276-
# Filter out extraneous empty lines from UIA
277-
ptr = self.UIATextPattern.GetVisibleRanges()
278-
res = [ptr.GetElement(i).GetText(-1) for i in range(ptr.length)]
279-
return res
280-
290+
# This override of _getTextLines takes advantage of the fact that
291+
# the console text contains linefeeds for every line
292+
# Thus a simple string splitlines is much faster than splitting by unit line.
293+
ti = self.makeTextInfo(textInfos.POSITION_ALL)
294+
text = ti.text or ""
295+
return text.splitlines()
281296

282297
def findExtraOverlayClasses(obj, clsList):
283298
if obj.UIAElement.cachedAutomationId == "Text Area":

0 commit comments

Comments
 (0)