11# A part of NonVisual Desktop Access (NVDA)
22# This file is covered by the GNU General Public License.
33# See the file COPYING for more details.
4- # Copyright (C) 2019-2020 Bill Dengler
4+ # Copyright (C) 2019-2021 Bill Dengler
55
66import ctypes
77import NVDAHelper
1616from ..window import Window
1717
1818
19- class consoleUIATextInfo (UIATextInfo ):
19+ class TextInfo (UIATextInfo ):
2020 def __init__ (self , obj , position , _rangeObj = None ):
2121 collapseToEnd = None
2222 # We want to limit textInfos to just the visible part of the console.
@@ -33,7 +33,7 @@ def __init__(self, obj, position, _rangeObj=None):
3333 log .warning ("Couldn't get bounding range for console" , exc_info = True )
3434 # Fall back to presenting the entire buffer.
3535 _rangeObj , collapseToEnd = None , None
36- super (consoleUIATextInfo , self ).__init__ (obj , position , _rangeObj )
36+ super (TextInfo , self ).__init__ (obj , position , _rangeObj )
3737 if collapseToEnd is not None :
3838 self .collapse (end = collapseToEnd )
3939
@@ -90,7 +90,7 @@ def move(self, unit, direction, endPoint=None):
9090
9191 def _move (self , unit , direction , endPoint = None ):
9292 "Perform a move without respect to bounding."
93- return super (consoleUIATextInfo , self ).move (unit , direction , endPoint )
93+ return super (TextInfo , self ).move (unit , direction , endPoint )
9494
9595 def __ne__ (self , other ):
9696 """Support more accurate caret move detection."""
@@ -99,17 +99,17 @@ def __ne__(self, other):
9999 def _get_text (self ):
100100 # #10036: return a space if the text range is empty.
101101 # Consoles don't actually store spaces, the character is merely left blank.
102- res = super (consoleUIATextInfo , self )._get_text ()
102+ res = super (TextInfo , self )._get_text ()
103103 if not res :
104104 return ' '
105105 else :
106106 return res
107107
108108
109- class consoleUIATextInfoPre21H1 ( consoleUIATextInfo ):
110- """Fixes expand/collapse on end inclusive UIA text ranges, uses rangeFromPoint
111- instead of broken GetVisibleRanges for bounding, and implements word
112- movement support."""
109+ class TextInfoWorkaroundEndInclusive ( TextInfo ):
110+ """Implementation of various workarounds for pre-microsoft/terminal#4018
111+ conhost: fixes expand/collapse, uses rangeFromPoint instead of broken
112+ GetVisibleRanges for bounding, and implements word movement support."""
113113 def _getBoundingRange (self , obj , position ):
114114 # We could use IUIAutomationTextRange::getVisibleRanges, but it seems very broken in consoles
115115 # once more than a few screens worth of content has been written to the console.
@@ -139,12 +139,12 @@ def _getBoundingRange(self, obj, position):
139139 return (_rangeObj , None )
140140
141141 def collapse (self , end = False ):
142- """Works around a UIA bug on Windows 10 versions before 21H1 .
142+ """Works around a UIA bug on conhost versions before microsoft/terminal#4018 .
143143 When collapsing, consoles seem to incorrectly push the start of the
144144 textRange back one character.
145145 Correct this by bringing the start back up to where the end is."""
146146 oldInfo = self .copy ()
147- super (consoleUIATextInfo , self ).collapse (end = end )
147+ super (TextInfo , self ).collapse (end = end )
148148 if not end :
149149 self ._rangeObj .MoveEndpointByRange (
150150 UIAHandler .TextPatternRangeEndpoint_Start ,
@@ -153,7 +153,7 @@ def collapse(self, end=False):
153153 )
154154
155155 def compareEndPoints (self , other , which ):
156- """Works around a UIA bug on Windows 10 versions before 21H1 .
156+ """Works around a UIA bug on conhost versions before microsoft/terminal#4018 .
157157 Even when a console textRange's start and end have been moved to the
158158 same position, the console incorrectly reports the end as being
159159 past the start.
@@ -168,7 +168,7 @@ def compareEndPoints(self, other, which):
168168
169169 def setEndPoint (self , other , which ):
170170 """Override of L{textInfos.TextInfo.setEndPoint}.
171- Works around a UIA bug on Windows 10 versions before 21H1 that means we can
171+ Works around a UIA bug on conhost versions before microsoft/terminal#4018 that means we can
172172 not trust the "end" endpoint of a collapsed (empty) text range
173173 for comparisons.
174174 """
@@ -205,11 +205,11 @@ def expand(self, unit):
205205 wordEndPoints [1 ]
206206 )
207207 else :
208- return super (consoleUIATextInfo , self ).expand (unit )
208+ return super (TextInfo , self ).expand (unit )
209209
210210 def _move (self , unit , direction , endPoint = None ):
211211 if unit == textInfos .UNIT_WORD and direction != 0 :
212- # On Windows 10 versions before 21H1 , UIA doesn't implement word
212+ # On conhost versions before microsoft/terminal#4018 , UIA doesn't implement word
213213 # movement, so we need to do it manually.
214214 # Relative to the current line, calculate our offset
215215 # and the current word's offsets.
@@ -261,7 +261,7 @@ def _move(self, unit, direction, endPoint=None):
261261 endPoint = endPoint
262262 )
263263 else : # moving by a unit other than word
264- res = super (consoleUIATextInfo , self ).move (unit , direction ,
264+ res = super (TextInfo , self ).move (unit , direction ,
265265 endPoint )
266266 if not endPoint :
267267 # #10191: IUIAutomationTextRange::move in consoles does not correctly produce a collapsed range
@@ -309,7 +309,7 @@ def _getWordOffsetsInThisLine(self, offset, lineInfo):
309309 )
310310
311311 def _isCollapsed (self ):
312- """Works around a UIA bug on Windows 10 versions before 21H1 that means we
312+ """Works around a UIA bug on conhost versions before microsoft/terminal#4018 that means we
313313 cannot trust the "end" endpoint of a collapsed (empty) text range
314314 for comparisons.
315315 Instead we check to see if we can get the first character from the
@@ -348,19 +348,31 @@ def _get_windowThreadID(self):
348348 threadID = super ().windowThreadID
349349 return threadID
350350
351- def _get_is21H1Plus (self ):
352- "Returns whether this is a newer version of Windows Console with an improved UIA implementation."
351+ def _get_isImprovedTextRangeAvailable (self ):
352+ """This property determines whether microsoft/terminal#4495
353+ and by extension microsoft/terminal#4018 are present in this conhost.
354+ In consoles before these PRs, a number of workarounds were needed
355+ in our UIA implementation. However, these do not fix all bugs and are
356+ problematic on newer console releases. This property is therefore used
357+ internally to determine whether to activate workarounds and as a
358+ convenience when debugging.
359+ """
353360 # microsoft/terminal#4495: In newer consoles,
354361 # IUIAutomationTextRange::getVisibleRanges returns one visible range.
362+ # Therefore, if exactly one range is returned, it is almost definitely a newer console.
355363 return self .UIATextPattern .GetVisibleRanges ().length == 1
356364
357365 def _get_TextInfo (self ):
358366 """Overriding _get_TextInfo and thus the TextInfo property
359367 on NVDAObjects.UIA.UIA
360- consoleUIATextInfo bounds review to the visible text.
361- ConsoleUIATextInfoPre21H1 fixes expand/collapse and implements word
362- movement."""
363- return consoleUIATextInfo if self .is21H1Plus else consoleUIATextInfoPre21H1
368+ TextInfo bounds review to the visible text.
369+ TextInfoWorkaroundEndInclusive fixes expand/collapse and implements
370+ word movement."""
371+ return (
372+ TextInfo
373+ if self .isImprovedTextRangeAvailable
374+ else TextInfoWorkaroundEndInclusive
375+ )
364376
365377 def detectPossibleSelectionChange (self ):
366378 try :
@@ -384,4 +396,4 @@ def findExtraOverlayClasses(obj, clsList):
384396
385397class WinTerminalUIA (EnhancedTermTypedCharSupport ):
386398 def _get_TextInfo (self ):
387- return consoleUIATextInfo
399+ return TextInfo
0 commit comments