Skip to content

Commit

Permalink
Merge bb55e64 into c22509b
Browse files Browse the repository at this point in the history
  • Loading branch information
codeofdusk authored May 7, 2021
2 parents c22509b + bb55e64 commit 64348e2
Showing 1 changed file with 36 additions and 24 deletions.
60 changes: 36 additions & 24 deletions source/NVDAObjects/UIA/winConsoleUIA.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# A part of NonVisual Desktop Access (NVDA)
# This file is covered by the GNU General Public License.
# See the file COPYING for more details.
# Copyright (C) 2019-2020 Bill Dengler
# Copyright (C) 2019-2021 Bill Dengler

import ctypes
import NVDAHelper
Expand All @@ -16,7 +16,7 @@
from ..window import Window


class consoleUIATextInfo(UIATextInfo):
class TextInfo(UIATextInfo):
def __init__(self, obj, position, _rangeObj=None):
collapseToEnd = None
# We want to limit textInfos to just the visible part of the console.
Expand All @@ -33,7 +33,7 @@ def __init__(self, obj, position, _rangeObj=None):
log.warning("Couldn't get bounding range for console", exc_info=True)
# Fall back to presenting the entire buffer.
_rangeObj, collapseToEnd = None, None
super(consoleUIATextInfo, self).__init__(obj, position, _rangeObj)
super(TextInfo, self).__init__(obj, position, _rangeObj)
if collapseToEnd is not None:
self.collapse(end=collapseToEnd)

Expand Down Expand Up @@ -90,7 +90,7 @@ def move(self, unit, direction, endPoint=None):

def _move(self, unit, direction, endPoint=None):
"Perform a move without respect to bounding."
return super(consoleUIATextInfo, self).move(unit, direction, endPoint)
return super(TextInfo, self).move(unit, direction, endPoint)

def __ne__(self, other):
"""Support more accurate caret move detection."""
Expand All @@ -99,17 +99,17 @@ def __ne__(self, other):
def _get_text(self):
# #10036: return a space if the text range is empty.
# Consoles don't actually store spaces, the character is merely left blank.
res = super(consoleUIATextInfo, self)._get_text()
res = super(TextInfo, self)._get_text()
if not res:
return ' '
else:
return res


class consoleUIATextInfoPre21H1(consoleUIATextInfo):
"""Fixes expand/collapse on end inclusive UIA text ranges, uses rangeFromPoint
instead of broken GetVisibleRanges for bounding, and implements word
movement support."""
class TextInfoWorkaroundEndInclusive(TextInfo):
"""Implementation of various workarounds for pre-microsoft/terminal#4018
conhost: fixes expand/collapse, uses rangeFromPoint instead of broken
GetVisibleRanges for bounding, and implements word movement support."""
def _getBoundingRange(self, obj, position):
# 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.
Expand Down Expand Up @@ -139,12 +139,12 @@ def _getBoundingRange(self, obj, position):
return (_rangeObj, None)

def collapse(self, end=False):
"""Works around a UIA bug on Windows 10 versions before 21H1.
"""Works around a UIA bug on conhost versions before microsoft/terminal#4018.
When collapsing, consoles seem to incorrectly push the start of the
textRange back one character.
Correct this by bringing the start back up to where the end is."""
oldInfo = self.copy()
super(consoleUIATextInfo, self).collapse(end=end)
super(TextInfo, self).collapse(end=end)
if not end:
self._rangeObj.MoveEndpointByRange(
UIAHandler.TextPatternRangeEndpoint_Start,
Expand All @@ -153,7 +153,7 @@ def collapse(self, end=False):
)

def compareEndPoints(self, other, which):
"""Works around a UIA bug on Windows 10 versions before 21H1.
"""Works around a UIA bug on conhost versions before microsoft/terminal#4018.
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.
Expand All @@ -168,7 +168,7 @@ def compareEndPoints(self, other, which):

def setEndPoint(self, other, which):
"""Override of L{textInfos.TextInfo.setEndPoint}.
Works around a UIA bug on Windows 10 versions before 21H1 that means we can
Works around a UIA bug on conhost versions before microsoft/terminal#4018 that means we can
not trust the "end" endpoint of a collapsed (empty) text range
for comparisons.
"""
Expand Down Expand Up @@ -205,11 +205,11 @@ def expand(self, unit):
wordEndPoints[1]
)
else:
return super(consoleUIATextInfo, self).expand(unit)
return super(TextInfo, self).expand(unit)

def _move(self, unit, direction, endPoint=None):
if unit == textInfos.UNIT_WORD and direction != 0:
# On Windows 10 versions before 21H1, UIA doesn't implement word
# On conhost versions before microsoft/terminal#4018, UIA doesn't implement word
# movement, so we need to do it manually.
# Relative to the current line, calculate our offset
# and the current word's offsets.
Expand Down Expand Up @@ -261,7 +261,7 @@ def _move(self, unit, direction, endPoint=None):
endPoint=endPoint
)
else: # moving by a unit other than word
res = super(consoleUIATextInfo, self).move(unit, direction,
res = super(TextInfo, self).move(unit, direction,
endPoint)
if not endPoint:
# #10191: IUIAutomationTextRange::move in consoles does not correctly produce a collapsed range
Expand Down Expand Up @@ -309,7 +309,7 @@ def _getWordOffsetsInThisLine(self, offset, lineInfo):
)

def _isCollapsed(self):
"""Works around a UIA bug on Windows 10 versions before 21H1 that means we
"""Works around a UIA bug on conhost versions before microsoft/terminal#4018 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
Expand Down Expand Up @@ -348,19 +348,31 @@ def _get_windowThreadID(self):
threadID = super().windowThreadID
return threadID

def _get_is21H1Plus(self):
"Returns whether this is a newer version of Windows Console with an improved UIA implementation."
def _get_isImprovedTextRangeAvailable(self):
"""This property determines whether microsoft/terminal#4495
and by extension microsoft/terminal#4018 are present in this conhost.
In consoles before these PRs, a number of workarounds were needed
in our UIA implementation. However, these do not fix all bugs and are
problematic on newer console releases. This property is therefore used
internally to determine whether to activate workarounds and as a
convenience when debugging.
"""
# microsoft/terminal#4495: In newer consoles,
# IUIAutomationTextRange::getVisibleRanges returns one visible range.
# Therefore, if exactly one range is returned, it is almost definitely a newer console.
return self.UIATextPattern.GetVisibleRanges().length == 1

def _get_TextInfo(self):
"""Overriding _get_TextInfo and thus the TextInfo property
on NVDAObjects.UIA.UIA
consoleUIATextInfo bounds review to the visible text.
ConsoleUIATextInfoPre21H1 fixes expand/collapse and implements word
movement."""
return consoleUIATextInfo if self.is21H1Plus else consoleUIATextInfoPre21H1
TextInfo bounds review to the visible text.
TextInfoWorkaroundEndInclusive fixes expand/collapse and implements
word movement."""
return (
TextInfo
if self.isImprovedTextRangeAvailable
else TextInfoWorkaroundEndInclusive
)

def detectPossibleSelectionChange(self):
try:
Expand All @@ -384,4 +396,4 @@ def findExtraOverlayClasses(obj, clsList):

class WinTerminalUIA(EnhancedTermTypedCharSupport):
def _get_TextInfo(self):
return consoleUIATextInfo
return TextInfo

0 comments on commit 64348e2

Please sign in to comment.