From 41ba9af0da2df7072777617e7a5dad2d5151fc24 Mon Sep 17 00:00:00 2001 From: Bill Dengler Date: Mon, 5 Aug 2019 11:40:00 -0400 Subject: [PATCH 01/10] Re-implement CompareEndPoints for ConsoleUIATextInfo objects. --- source/NVDAObjects/UIA/winConsoleUIA.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/source/NVDAObjects/UIA/winConsoleUIA.py b/source/NVDAObjects/UIA/winConsoleUIA.py index b7f0c750cc0..4efd96c7129 100644 --- a/source/NVDAObjects/UIA/winConsoleUIA.py +++ b/source/NVDAObjects/UIA/winConsoleUIA.py @@ -153,14 +153,20 @@ 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. - return not bool(self._rangeObj.getText(1)) + # To work around this, compare to the start, not the end, + # when collapsed. + src, target = which.split("To") + if src == "end" and not self._rangeObj.GetText(1): + src = "Start" + if target == "End" and not other._rangeObj.GetText(1): + target = "Start" + which = f"{src}To{target}" + return super().compareEndPoints(other, which) def _getCurrentOffsetInThisLine(self, lineInfo): """ From 1c4f6897feb666548e8652952c1bee6c1a28989d Mon Sep 17 00:00:00 2001 From: Bill Dengler Date: Tue, 6 Aug 2019 09:09:37 -0400 Subject: [PATCH 02/10] Also normalize endPoints for setEndPoint. --- source/NVDAObjects/UIA/winConsoleUIA.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/source/NVDAObjects/UIA/winConsoleUIA.py b/source/NVDAObjects/UIA/winConsoleUIA.py index 4efd96c7129..bf913233785 100644 --- a/source/NVDAObjects/UIA/winConsoleUIA.py +++ b/source/NVDAObjects/UIA/winConsoleUIA.py @@ -155,6 +155,20 @@ def expand(self, unit): def compareEndPoints(self, other, which): """Works around a UIA bug on Windows 10 1803 and later.""" + return super().compareEndPoints( + other, + self._endPointHelper(other, which) + ) + + def setEndPoint(self, other, which): + """Works around a UIA bug on Windows 10 1803 and later.""" + return super().compareEndPoints( + other, + self._endPointHelper(other, which) + ) + + def _endPointHelper(self, other, which): + """Returns normalized endPoints to work around a Windows bug.""" # 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. @@ -165,8 +179,7 @@ def compareEndPoints(self, other, which): src = "Start" if target == "End" and not other._rangeObj.GetText(1): target = "Start" - which = f"{src}To{target}" - return super().compareEndPoints(other, which) + return f"{src}To{target}" def _getCurrentOffsetInThisLine(self, lineInfo): """ From b11480015c1ad04b93018a8556f494b521741660 Mon Sep 17 00:00:00 2001 From: Bill Dengler Date: Tue, 6 Aug 2019 09:36:30 -0400 Subject: [PATCH 03/10] Only normalize the source in compareEndPoints. --- source/NVDAObjects/UIA/winConsoleUIA.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/source/NVDAObjects/UIA/winConsoleUIA.py b/source/NVDAObjects/UIA/winConsoleUIA.py index bf913233785..8a62cf26e25 100644 --- a/source/NVDAObjects/UIA/winConsoleUIA.py +++ b/source/NVDAObjects/UIA/winConsoleUIA.py @@ -164,10 +164,11 @@ def setEndPoint(self, other, which): """Works around a UIA bug on Windows 10 1803 and later.""" return super().compareEndPoints( other, - self._endPointHelper(other, which) + self._endPointHelper(other, which), + normalizeSrc=False ) - def _endPointHelper(self, other, which): + def _endPointHelper(self, other, which, normalizeSource=True): """Returns normalized endPoints to work around a Windows bug.""" # Even when a console textRange's start and end have been moved to the # same position, the console incorrectly reports the end as being @@ -175,7 +176,7 @@ def _endPointHelper(self, other, which): # To work around this, compare to the start, not the end, # when collapsed. src, target = which.split("To") - if src == "end" and not self._rangeObj.GetText(1): + if normalizeSrc and src == "end" and not self._rangeObj.GetText(1): src = "Start" if target == "End" and not other._rangeObj.GetText(1): target = "Start" From 134a46a9c0e2bb064ff6892759d8533b629cab4b Mon Sep 17 00:00:00 2001 From: Bill Dengler Date: Tue, 6 Aug 2019 09:39:43 -0400 Subject: [PATCH 04/10] Fixes. --- source/NVDAObjects/UIA/winConsoleUIA.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/source/NVDAObjects/UIA/winConsoleUIA.py b/source/NVDAObjects/UIA/winConsoleUIA.py index 8a62cf26e25..28a255c18d5 100644 --- a/source/NVDAObjects/UIA/winConsoleUIA.py +++ b/source/NVDAObjects/UIA/winConsoleUIA.py @@ -164,11 +164,10 @@ def setEndPoint(self, other, which): """Works around a UIA bug on Windows 10 1803 and later.""" return super().compareEndPoints( other, - self._endPointHelper(other, which), - normalizeSrc=False + self._endPointHelper(other, which, normalizeSrc=False) ) - def _endPointHelper(self, other, which, normalizeSource=True): + def _endPointHelper(self, other, which, normalizeSrc=True): """Returns normalized endPoints to work around a Windows bug.""" # Even when a console textRange's start and end have been moved to the # same position, the console incorrectly reports the end as being From b1b2bca59ff3507f6844859f313bdefba927c455 Mon Sep 17 00:00:00 2001 From: Bill Dengler Date: Tue, 6 Aug 2019 09:50:56 -0400 Subject: [PATCH 05/10] Fixes. --- source/NVDAObjects/UIA/winConsoleUIA.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/NVDAObjects/UIA/winConsoleUIA.py b/source/NVDAObjects/UIA/winConsoleUIA.py index 28a255c18d5..d31933756a1 100644 --- a/source/NVDAObjects/UIA/winConsoleUIA.py +++ b/source/NVDAObjects/UIA/winConsoleUIA.py @@ -162,7 +162,7 @@ def compareEndPoints(self, other, which): def setEndPoint(self, other, which): """Works around a UIA bug on Windows 10 1803 and later.""" - return super().compareEndPoints( + return super().setEndPoint( other, self._endPointHelper(other, which, normalizeSrc=False) ) @@ -176,7 +176,7 @@ def _endPointHelper(self, other, which, normalizeSrc=True): # when collapsed. src, target = which.split("To") if normalizeSrc and src == "end" and not self._rangeObj.GetText(1): - src = "Start" + src = "start" if target == "End" and not other._rangeObj.GetText(1): target = "Start" return f"{src}To{target}" From 68a5927f1bcaf48c30f067a8750a42b76eb793b7 Mon Sep 17 00:00:00 2001 From: Bill Dengler Date: Wed, 7 Aug 2019 10:04:07 -0400 Subject: [PATCH 06/10] Update docstring. --- source/NVDAObjects/UIA/winConsoleUIA.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/source/NVDAObjects/UIA/winConsoleUIA.py b/source/NVDAObjects/UIA/winConsoleUIA.py index d31933756a1..6509a6fe902 100644 --- a/source/NVDAObjects/UIA/winConsoleUIA.py +++ b/source/NVDAObjects/UIA/winConsoleUIA.py @@ -168,12 +168,12 @@ def setEndPoint(self, other, which): ) def _endPointHelper(self, other, which, normalizeSrc=True): - """Returns normalized endPoints to work around a Windows bug.""" - # 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. - # To work around this, compare to the start, not the end, - # when collapsed. + """ + 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. + Returns normalized endPoints to work around this.""" + # Compare to the start (not the end) when collapsed. src, target = which.split("To") if normalizeSrc and src == "end" and not self._rangeObj.GetText(1): src = "start" From 6a03087ef6e1cf3bafeb17a2b8d2676d61a135c0 Mon Sep 17 00:00:00 2001 From: Bill Dengler Date: Wed, 7 Aug 2019 10:28:15 -0400 Subject: [PATCH 07/10] Bring back _get_isCollapsed. --- source/NVDAObjects/UIA/winConsoleUIA.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/source/NVDAObjects/UIA/winConsoleUIA.py b/source/NVDAObjects/UIA/winConsoleUIA.py index 6509a6fe902..c7be0d1f3c4 100644 --- a/source/NVDAObjects/UIA/winConsoleUIA.py +++ b/source/NVDAObjects/UIA/winConsoleUIA.py @@ -167,6 +167,12 @@ def setEndPoint(self, other, which): self._endPointHelper(other, which, normalizeSrc=False) ) + def _get_isCollapsed(self): + """Works around a UIA bug on Windows 10 1803 and later.""" + # To decide if the textRange is collapsed, + # Check if it has no text. + return not bool(self._rangeObj.getText(1)) + def _endPointHelper(self, other, which, normalizeSrc=True): """ Even when a console textRange's start and end have been moved to the @@ -175,9 +181,9 @@ def _endPointHelper(self, other, which, normalizeSrc=True): Returns normalized endPoints to work around this.""" # Compare to the start (not the end) when collapsed. src, target = which.split("To") - if normalizeSrc and src == "end" and not self._rangeObj.GetText(1): + if normalizeSrc and src == "end" and not self.isCollapsed: src = "start" - if target == "End" and not other._rangeObj.GetText(1): + if target == "End" and not other.isCollapsed: target = "Start" return f"{src}To{target}" From 5544edeeda0f496e234277263f2ac90f59eb61ee Mon Sep 17 00:00:00 2001 From: Bill Dengler Date: Thu, 8 Aug 2019 05:30:21 -0400 Subject: [PATCH 08/10] Review actions. --- source/NVDAObjects/UIA/winConsoleUIA.py | 48 +++++++++++++------------ 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/source/NVDAObjects/UIA/winConsoleUIA.py b/source/NVDAObjects/UIA/winConsoleUIA.py index c7be0d1f3c4..d9b40e430b3 100644 --- a/source/NVDAObjects/UIA/winConsoleUIA.py +++ b/source/NVDAObjects/UIA/winConsoleUIA.py @@ -155,37 +155,39 @@ def expand(self, unit): def compareEndPoints(self, other, which): """Works around a UIA bug on Windows 10 1803 and later.""" - return super().compareEndPoints( - other, - self._endPointHelper(other, which) - ) + # 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. + # Compare to the start (not the end) when collapsed. + selfEndPoint, otherEndPoint = which.split("To") + if selfEndPoint == "end" and not self.hasNoText: + selfEndPoint = "start" + if otherEndPoint == "End" and not other.hasNoText: + otherEndPoint = "Start" + which = f"{selfEndPoint}To{otherEndPoint}" + return super().compareEndPoints(other, which=which) def setEndPoint(self, other, which): """Works around a UIA bug on Windows 10 1803 and later.""" - return super().setEndPoint( - other, - self._endPointHelper(other, which, normalizeSrc=False) - ) + # 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. + selfEndPoint, otherEndPoint = which.split("To") + # In this case, there is no need to check selfEndPoint + # since it is about to be overwritten in the super call. + if otherEndPoint == "End" and not other.hasNoText: + otherEndPoint = "Start" + which = f"{selfEndPoint}To{otherEndPoint}" + return super().setEndPoint(other, which=which) + + def _get_hasNoText(self): + return not bool(self._rangeObj.getText(1)) def _get_isCollapsed(self): """Works around a UIA bug on Windows 10 1803 and later.""" # To decide if the textRange is collapsed, # Check if it has no text. - return not bool(self._rangeObj.getText(1)) - - def _endPointHelper(self, other, which, normalizeSrc=True): - """ - 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. - Returns normalized endPoints to work around this.""" - # Compare to the start (not the end) when collapsed. - src, target = which.split("To") - if normalizeSrc and src == "end" and not self.isCollapsed: - src = "start" - if target == "End" and not other.isCollapsed: - target = "Start" - return f"{src}To{target}" + return self.hasNoText def _getCurrentOffsetInThisLine(self, lineInfo): """ From 6e131adb25e96608d36c095b960a96dcaf6d2c72 Mon Sep 17 00:00:00 2001 From: Bill Dengler Date: Thu, 8 Aug 2019 09:32:46 -0400 Subject: [PATCH 09/10] Apply suggestions from code review Co-Authored-By: Reef Turner --- source/NVDAObjects/UIA/winConsoleUIA.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/source/NVDAObjects/UIA/winConsoleUIA.py b/source/NVDAObjects/UIA/winConsoleUIA.py index d9b40e430b3..560cdf4e832 100644 --- a/source/NVDAObjects/UIA/winConsoleUIA.py +++ b/source/NVDAObjects/UIA/winConsoleUIA.py @@ -168,19 +168,23 @@ def compareEndPoints(self, other, which): return super().compareEndPoints(other, which=which) def setEndPoint(self, other, which): - """Works around a UIA bug on Windows 10 1803 and later.""" + """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. + """ # 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. selfEndPoint, otherEndPoint = which.split("To") - # In this case, there is no need to check selfEndPoint - # since it is about to be overwritten in the super call. + # 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 + # textrange is fine. if otherEndPoint == "End" and not other.hasNoText: otherEndPoint = "Start" which = f"{selfEndPoint}To{otherEndPoint}" return super().setEndPoint(other, which=which) - def _get_hasNoText(self): + def _get__isCollapsed(self): return not bool(self._rangeObj.getText(1)) def _get_isCollapsed(self): From 41e637f48b9575b6f8bee10d1f69b7cb7a9c57a8 Mon Sep 17 00:00:00 2001 From: Bill Dengler Date: Thu, 8 Aug 2019 09:42:28 -0400 Subject: [PATCH 10/10] Review actions. --- source/NVDAObjects/UIA/winConsoleUIA.py | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/source/NVDAObjects/UIA/winConsoleUIA.py b/source/NVDAObjects/UIA/winConsoleUIA.py index 560cdf4e832..34848792d4a 100644 --- a/source/NVDAObjects/UIA/winConsoleUIA.py +++ b/source/NVDAObjects/UIA/winConsoleUIA.py @@ -160,9 +160,9 @@ def compareEndPoints(self, other, which): # past the start. # Compare to the start (not the end) when collapsed. selfEndPoint, otherEndPoint = which.split("To") - if selfEndPoint == "end" and not self.hasNoText: + if selfEndPoint == "end" and not self._isCollapsed: selfEndPoint = "start" - if otherEndPoint == "End" and not other.hasNoText: + if otherEndPoint == "End" and not other._isCollapsed: otherEndPoint = "Start" which = f"{selfEndPoint}To{otherEndPoint}" return super().compareEndPoints(other, which=which) @@ -172,26 +172,24 @@ def setEndPoint(self, other, which): 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. """ - # 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. 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 - # textrange is fine. - if otherEndPoint == "End" and not other.hasNoText: + # 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 _get__isCollapsed(self): + """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. + 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): - """Works around a UIA bug on Windows 10 1803 and later.""" # To decide if the textRange is collapsed, # Check if it has no text. - return self.hasNoText + return self._isCollapsed def _getCurrentOffsetInThisLine(self, lineInfo): """