diff --git a/source/NVDAObjects/UIA/winConsoleUIA.py b/source/NVDAObjects/UIA/winConsoleUIA.py index cae4c4f8417..2b25e33bc51 100644 --- a/source/NVDAObjects/UIA/winConsoleUIA.py +++ b/source/NVDAObjects/UIA/winConsoleUIA.py @@ -13,6 +13,7 @@ import UIAHandler from scriptHandler import script +from UIAUtils import isTextRangeOffscreen from winVersion import isWin10 from . import UIATextInfo from ..behaviors import Terminal @@ -50,8 +51,6 @@ def move(self, unit, direction, endPoint=None): visiRanges = self.obj.UIATextPattern.GetVisibleRanges() visiLength = visiRanges.length if visiLength > 0: - firstVisiRange = visiRanges.GetElement(0) - lastVisiRange = visiRanges.GetElement(visiLength - 1) oldRange = self._rangeObj.clone() if unit == textInfos.UNIT_WORD and direction != 0: # UIA doesn't implement word movement, so we need to do it manually. @@ -108,13 +107,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 oldRange and ( - self._rangeObj.CompareEndPoints( - UIAHandler.TextPatternRangeEndpoint_Start, firstVisiRange, - UIAHandler.TextPatternRangeEndpoint_Start) < 0 - or self._rangeObj.CompareEndPoints( - UIAHandler.TextPatternRangeEndpoint_Start, lastVisiRange, - UIAHandler.TextPatternRangeEndpoint_End) >= 0): + if ( + oldRange + and isTextRangeOffscreen(self._rangeObj, visiRanges) + and not isTextRangeOffscreen(oldRange, visiRanges) + ): self._rangeObj = oldRange return 0 return res diff --git a/source/UIAUtils.py b/source/UIAUtils.py index 7704b12aa2d..5acedf8cc4c 100644 --- a/source/UIAUtils.py +++ b/source/UIAUtils.py @@ -172,6 +172,24 @@ def getChildrenWithCacheFromUIATextRange(textRange,cacheRequest): c=CacheableUIAElementArray(c) return c +def isTextRangeOffscreen(range, visiRanges): + """Given a UIA text range and a visible ranges array (returned from obj.UIATextPattern.GetVisibleRanges), determines if the given range is not within the visible ranges.""" + visiLength = visiRanges.length + if visiLength > 0: + firstVisiRange = visiRanges.GetElement(0) + lastVisiRange = visiRanges.GetElement(visiLength - 1) + return range.CompareEndPoints( + UIAHandler.TextPatternRangeEndpoint_Start, firstVisiRange, + UIAHandler.TextPatternRangeEndpoint_Start + ) < 0 or range.CompareEndPoints( + UIAHandler.TextPatternRangeEndpoint_Start, lastVisiRange, + UIAHandler.TextPatternRangeEndpoint_End) >= 0 + else: + # Visible ranges not available, so fail gracefully. + log.warning("UIA visible ranges not available.") + return True + + class UIATextRangeAttributeValueFetcher(object): def __init__(self,textRange):