Skip to content

Commit

Permalink
UIA in Win Console: fix setEndPoint/compareEndPoints (PR #10057)
Browse files Browse the repository at this point in the history
Closes #10035
Related to #9614
Identical to #10043

Works around a UIA bug on Windows 10 1803 and later that means we can
not trust the "end" endpoint of a collapsed (empty) text range for comparisons. 
The console incorrectly reports the "end" as being past the "start" endpoint.

This stops braille being able to properly track the system caret in Windows Console.

Instead use getText(1) on the textRange to attempt to fetch 1 character.
getText returns an empty string for a collapsed range. By definition, the "start" and
"end" endpoints for a collapsed range are equivalent, thus read from the "start"
endpoint of a collapsed range instead of the "end" endpoint.
  • Loading branch information
codeofdusk authored and feerrenrut committed Aug 12, 2019
1 parent 7085172 commit 39d20e2
Showing 1 changed file with 37 additions and 3 deletions.
40 changes: 37 additions & 3 deletions source/NVDAObjects/UIA/winConsoleUIA.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,15 +153,49 @@ def expand(self, unit):
else:
return super(consoleUIATextInfo, self).expand(unit)

def _get_isCollapsed(self):
def compareEndPoints(self, other, which):
"""Works around a UIA bug on Windows 10 1803 and later."""
# Even when a console textRange's start and end have been moved to the
# same position, the console incorrectly reports the end as being
# past the start.
# Therefore to decide if the textRange is collapsed,
# Check if it has no text.
# Compare to the start (not the end) when collapsed.
selfEndPoint, otherEndPoint = which.split("To")
if selfEndPoint == "end" and not self._isCollapsed():
selfEndPoint = "start"
if otherEndPoint == "End" and not other._isCollapsed():
otherEndPoint = "Start"
which = f"{selfEndPoint}To{otherEndPoint}"
return super().compareEndPoints(other, which=which)

def setEndPoint(self, other, which):
"""Override of L{textInfos.TextInfo.setEndPoint}.
Works around a UIA bug on Windows 10 1803 and later that means we can
not trust the "end" endpoint of a collapsed (empty) text range
for comparisons.
"""
selfEndPoint, otherEndPoint = which.split("To")
# In this case, there is no need to check if self is collapsed
# since the point of this method is to change its text range, modifying the "end" endpoint of a collapsed
# text range is fine.
if otherEndPoint == "End" and not other._isCollapsed():
otherEndPoint = "Start"
which = f"{selfEndPoint}To{otherEndPoint}"
return super().setEndPoint(other, which=which)

def _isCollapsed(self):
"""Works around a UIA bug on Windows 10 1803 and later that means we
cannot trust the "end" endpoint of a collapsed (empty) text range
for comparisons.
Instead we check to see if we can get the first character from the
text range. A collapsed range will not have any characters
and will return an empty string."""
return not bool(self._rangeObj.getText(1))

def _get_isCollapsed(self):
# To decide if the textRange is collapsed,
# Check if it has no text.
return self._isCollapsed

def _getCurrentOffsetInThisLine(self, lineInfo):
"""
Given a caret textInfo expanded to line, returns the index into the
Expand Down

0 comments on commit 39d20e2

Please sign in to comment.