From 092dd05ade9f9b823767a091f62cc1999ca85390 Mon Sep 17 00:00:00 2001 From: Bill Dengler Date: Tue, 14 May 2019 11:16:41 -0400 Subject: [PATCH 01/24] Add a feature flag for UIA console support. At the moment, it merely disables NVDA's existing console support, falling back to what UIA support is available in NVDA. The option is currently called `ConsoleUIA`, but we'll need to change this once autodetection is implemented (as there will be three options at that point). Typed characters are now spoken in UIA consoles, but characters are doubled when typing quickly, leading to incorrect typed word reporting. --- source/NVDAHelper.py | 2 +- source/NVDAObjects/window/__init__.py | 4 +++- source/_UIAHandler.py | 8 +++++--- source/config/configSpec.py | 1 + source/gui/settingsDialogs.py | 8 ++++++++ source/keyboardHandler.py | 2 +- source/winConsoleHandler.py | 1 - 7 files changed, 19 insertions(+), 7 deletions(-) diff --git a/source/NVDAHelper.py b/source/NVDAHelper.py index 4a615f1ca41..ce4f4b06261 100755 --- a/source/NVDAHelper.py +++ b/source/NVDAHelper.py @@ -382,7 +382,7 @@ def nvdaControllerInternal_inputLangChangeNotify(threadID,hkl,layoutString): @WINFUNCTYPE(c_long,c_long,c_wchar) def nvdaControllerInternal_typedCharacterNotify(threadID,ch): focus=api.getFocusObject() - if focus.windowClassName!="ConsoleWindowClass": + if config.conf['UIA']['consoleUIA'] or focus.windowClassName!="ConsoleWindowClass": eventHandler.queueEvent("typedCharacter",focus,ch=ch) return 0 diff --git a/source/NVDAObjects/window/__init__.py b/source/NVDAObjects/window/__init__.py index db715b2a3b6..dbc434294ca 100644 --- a/source/NVDAObjects/window/__init__.py +++ b/source/NVDAObjects/window/__init__.py @@ -12,6 +12,7 @@ from logHandler import log import controlTypes import api +import config import displayModel import eventHandler from NVDAObjects import NVDAObject @@ -121,7 +122,8 @@ def findOverlayClasses(self,clsList): elif windowClassName in ("AkelEditW", "AkelEditA"): from .akelEdit import AkelEdit as newCls elif windowClassName=="ConsoleWindowClass": - from .winConsole import WinConsole as newCls + if not config.conf['UIA']['consoleUIA']: + from .winConsole import WinConsole as newCls elif windowClassName=="EXCEL7": from .excel import Excel7Window as newCls if newCls: diff --git a/source/_UIAHandler.py b/source/_UIAHandler.py index 3181cff98ec..87841832955 100644 --- a/source/_UIAHandler.py +++ b/source/_UIAHandler.py @@ -59,13 +59,15 @@ "SysListView32", "EXCEL7", "Button", - # #7497: Windows 10 Fall Creators Update has an incomplete UIA implementation for console windows, therefore for now we should ignore it. - # It does not implement caret/selection, and probably has no new text events. - "ConsoleWindowClass", # #8944: The Foxit UIA implementation is incomplete and should not be used for now. "FoxitDocWnd", ] +# #7497: Windows 10 Fall Creators Update has an incomplete UIA implementation for console windows, therefore for now we should ignore it. +# It does not implement caret/selection, and probably has no new text events. +if not config.conf['UIA']['consoleUIA']: + badUIAWindowClassNames.append("ConsoleWindowClass") + # #8405: used to detect UIA dialogs prior to Windows 10 RS5. UIADialogClassNames=[ "#32770", diff --git a/source/config/configSpec.py b/source/config/configSpec.py index 0d7e05f4bb4..ba973765279 100644 --- a/source/config/configSpec.py +++ b/source/config/configSpec.py @@ -187,6 +187,7 @@ [UIA] enabled = boolean(default=true) useInMSWordWhenAvailable = boolean(default=false) + consoleUIA = boolean(default=false) [update] autoCheck = boolean(default=true) diff --git a/source/gui/settingsDialogs.py b/source/gui/settingsDialogs.py index ee9fd251d35..c2d20fbaa6b 100644 --- a/source/gui/settingsDialogs.py +++ b/source/gui/settingsDialogs.py @@ -2050,6 +2050,13 @@ def __init__(self, parent): self.UIAInMSWordCheckBox.SetValue(config.conf["UIA"]["useInMSWordWhenAvailable"]) self.UIAInMSWordCheckBox.defaultValue = self._getDefaultValue(["UIA", "useInMSWordWhenAvailable"]) + # Translators: This is the label for a checkbox in the + # Advanced settings panel. + label = _("Use UI Automation to access the Windows Console (highly experimental)") + self.ConsoleUIACheckBox=UIAGroup.addItem(wx.CheckBox(self, label=label)) + self.ConsoleUIACheckBox.SetValue(config.conf["UIA"]["consoleUIA"]) + self.ConsoleUIACheckBox.defaultValue = self._getDefaultValue(["UIA", "consoleUIA"]) + # Translators: This is the label for a group of advanced options in the # Advanced settings panel label = _("Browse mode") @@ -2152,6 +2159,7 @@ def onSave(self): log.debug("Saving advanced config") config.conf["development"]["enableScratchpadDir"]=self.scratchpadCheckBox.IsChecked() config.conf["UIA"]["useInMSWordWhenAvailable"]=self.UIAInMSWordCheckBox.IsChecked() + config.conf["UIA"]["consoleUIA"]=self.ConsoleUIACheckBox.IsChecked() config.conf["virtualBuffers"]["autoFocusFocusableElements"] = self.autoFocusFocusableElementsCheckBox.IsChecked() config.conf["editableText"]["caretMoveTimeoutMs"]=self.caretMoveTimeoutSpinControl.GetValue() for index,key in enumerate(self.logCategories): diff --git a/source/keyboardHandler.py b/source/keyboardHandler.py index dc72a32d301..b46e87866a5 100644 --- a/source/keyboardHandler.py +++ b/source/keyboardHandler.py @@ -206,7 +206,7 @@ def internal_keyDownEvent(vkCode,scanCode,extended,injected): and not isNVDAModifierKey(vkCode,extended) and not vkCode in KeyboardInputGesture.NORMAL_MODIFIER_KEYS and ( # Either of # We couldn't inject in-process, and its not a console window (console windows have their own specific typed character support) - (not focus.appModule.helperLocalBindingHandle and focus.windowClassName!='ConsoleWindowClass') + (not focus.appModule.helperLocalBindingHandle and (config.conf['UIA']['consoleUIA'] or focus.windowClassName!='ConsoleWindowClass')) # or the focus is within a UWP app, where WM_CHAR never gets sent or focus.windowClassName.startswith('Windows.UI.Core') ) diff --git a/source/winConsoleHandler.py b/source/winConsoleHandler.py index 62d7e74a2d8..96a06d8a990 100755 --- a/source/winConsoleHandler.py +++ b/source/winConsoleHandler.py @@ -46,7 +46,6 @@ COMMON_LVB_UNDERSCORE=0x8000 - @wincon.PHANDLER_ROUTINE def _consoleCtrlHandler(event): if event in (wincon.CTRL_C_EVENT,wincon.CTRL_BREAK_EVENT): From a9feea73704dd3395e95337683ba0448e6990091 Mon Sep 17 00:00:00 2001 From: Bill Dengler Date: Fri, 17 May 2019 21:14:05 -0400 Subject: [PATCH 02/24] Disable in-process injection for speak typed characters for now. This fixes the doubled characters bug, making speaked typed words function as intended, but it may have other implications. --- source/NVDAHelper.py | 2 +- source/keyboardHandler.py | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/source/NVDAHelper.py b/source/NVDAHelper.py index ce4f4b06261..4a615f1ca41 100755 --- a/source/NVDAHelper.py +++ b/source/NVDAHelper.py @@ -382,7 +382,7 @@ def nvdaControllerInternal_inputLangChangeNotify(threadID,hkl,layoutString): @WINFUNCTYPE(c_long,c_long,c_wchar) def nvdaControllerInternal_typedCharacterNotify(threadID,ch): focus=api.getFocusObject() - if config.conf['UIA']['consoleUIA'] or focus.windowClassName!="ConsoleWindowClass": + if focus.windowClassName!="ConsoleWindowClass": eventHandler.queueEvent("typedCharacter",focus,ch=ch) return 0 diff --git a/source/keyboardHandler.py b/source/keyboardHandler.py index b46e87866a5..77f68a729b7 100644 --- a/source/keyboardHandler.py +++ b/source/keyboardHandler.py @@ -205,10 +205,12 @@ def internal_keyDownEvent(vkCode,scanCode,extended,injected): # and not if this gesture is a modifier key and not isNVDAModifierKey(vkCode,extended) and not vkCode in KeyboardInputGesture.NORMAL_MODIFIER_KEYS and ( # Either of - # We couldn't inject in-process, and its not a console window (console windows have their own specific typed character support) - (not focus.appModule.helperLocalBindingHandle and (config.conf['UIA']['consoleUIA'] or focus.windowClassName!='ConsoleWindowClass')) + # We couldn't inject in-process, and its not a legacy console window (console windows have their own specific typed character support) + (not focus.appModule.helperLocalBindingHandle and focus.windowClassName!='ConsoleWindowClass') # or the focus is within a UWP app, where WM_CHAR never gets sent or focus.windowClassName.startswith('Windows.UI.Core') + #Or this is a UIA console window, where WM_CHAR messages are doubled + or focus.windowClassName == "ConsoleWindowClass" and config.conf['UIA']['consoleUIA'] ) ): keyStates=(ctypes.c_byte*256)() From b6ae17b0872ad27df5d6a0a648951a4e912777c1 Mon Sep 17 00:00:00 2001 From: Bill Dengler Date: Tue, 21 May 2019 00:27:17 -0400 Subject: [PATCH 03/24] Receive textChanged events from UIA and add consoleUIA and consoleUIATextInfo classes to implement automatic readout and work around a caret movement bug in Windows 10 version 1903. The consoleUIA class inherits from NVDAObjects.behaviors.Terminal, which serves as the foundation for automatic readout support. At the moment, it is likely that such support will either be not functional at all or report extraneous text from user input. --- source/NVDAObjects/UIA/ConsoleUIA.py | 25 +++++++++++++++++++++++++ source/NVDAObjects/UIA/__init__.py | 4 ++++ source/NVDAObjects/window/__init__.py | 5 ++--- source/_UIAHandler.py | 2 +- 4 files changed, 32 insertions(+), 4 deletions(-) create mode 100644 source/NVDAObjects/UIA/ConsoleUIA.py diff --git a/source/NVDAObjects/UIA/ConsoleUIA.py b/source/NVDAObjects/UIA/ConsoleUIA.py new file mode 100644 index 00000000000..4a0812bb802 --- /dev/null +++ b/source/NVDAObjects/UIA/ConsoleUIA.py @@ -0,0 +1,25 @@ +#NVDAObjects/UIA/ConsoleUIA.py +#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 Bill Dengler + +import textInfos +import UIAHandler + +from winVersion import winVersion +from . import UIATextInfo +from ..behaviors import Terminal + + +class ConsoleUIATextInfo(UIATextInfo): + def __init__(self,obj,position,_rangeObj=None): + super(ConsoleUIATextInfo, self).__init__(obj,position,_rangeObj) + if position==textInfos.POSITION_CARET: + if winVersion.build >= 18362: #Windows 10 version 1903 + # The UIA implementation in 1903 causes the caret to be off-by-one, so move it one position to the right to compensate. + self._rangeObj.MoveEndpointByUnit(UIAHandler.TextPatternRangeEndpoint_Start,UIAHandler.NVDAUnitsToUIAUnits['character'],1) + + +class consoleUIA(Terminal): + _TextInfo=ConsoleUIATextInfo \ No newline at end of file diff --git a/source/NVDAObjects/UIA/__init__.py b/source/NVDAObjects/UIA/__init__.py index f434d638da9..b48ea632475 100644 --- a/source/NVDAObjects/UIA/__init__.py +++ b/source/NVDAObjects/UIA/__init__.py @@ -858,6 +858,10 @@ def findOverlayClasses(self,clsList): except ValueError: pass + # Support Windows Console's UIA interface + if self.windowClassName == "ConsoleWindowClass" and self.UIAElement.cachedAutomationId == "Text Area" and config.conf['UIA']['consoleUIA']: + from .ConsoleUIA import consoleUIA + clsList.append(consoleUIA) # Add editableText support if UIA supports a text pattern if self.TextInfo==UIATextInfo: clsList.append(EditableTextWithoutAutoSelectDetection) diff --git a/source/NVDAObjects/window/__init__.py b/source/NVDAObjects/window/__init__.py index dbc434294ca..98d8ae69cda 100644 --- a/source/NVDAObjects/window/__init__.py +++ b/source/NVDAObjects/window/__init__.py @@ -121,9 +121,8 @@ def findOverlayClasses(self,clsList): from .scintilla import Scintilla as newCls elif windowClassName in ("AkelEditW", "AkelEditA"): from .akelEdit import AkelEdit as newCls - elif windowClassName=="ConsoleWindowClass": - if not config.conf['UIA']['consoleUIA']: - from .winConsole import WinConsole as newCls + elif windowClassName=="ConsoleWindowClass" and not config.conf['UIA']['consoleUIA']: + from .winConsole import WinConsole as newCls elif windowClassName=="EXCEL7": from .excel import Excel7Window as newCls if newCls: diff --git a/source/_UIAHandler.py b/source/_UIAHandler.py index 87841832955..dbd5b9e2e49 100644 --- a/source/_UIAHandler.py +++ b/source/_UIAHandler.py @@ -142,7 +142,7 @@ UIAEventIdsToNVDAEventNames={ UIA_LiveRegionChangedEventId:"liveRegionChange", - #UIA_Text_TextChangedEventId:"textChanged", + UIA_Text_TextChangedEventId:"textChanged", UIA_SelectionItem_ElementSelectedEventId:"UIA_elementSelected", UIA_MenuOpenedEventId:"gainFocus", UIA_SelectionItem_ElementAddedToSelectionEventId:"stateChange", From b3565326e664eb9e1219bce5d96998f61c225300 Mon Sep 17 00:00:00 2001 From: Bill Dengler Date: Tue, 21 May 2019 15:40:11 -0400 Subject: [PATCH 04/24] Introduce basic automatic readout support, and rename ConsoleUIATextInfo->consoleUIATextInfo for consistency. See the source code comments in this commit for some steps still incomplete. --- source/NVDAObjects/UIA/ConsoleUIA.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/source/NVDAObjects/UIA/ConsoleUIA.py b/source/NVDAObjects/UIA/ConsoleUIA.py index 4a0812bb802..bb12d0629e1 100644 --- a/source/NVDAObjects/UIA/ConsoleUIA.py +++ b/source/NVDAObjects/UIA/ConsoleUIA.py @@ -12,9 +12,9 @@ from ..behaviors import Terminal -class ConsoleUIATextInfo(UIATextInfo): +class consoleUIATextInfo(UIATextInfo): def __init__(self,obj,position,_rangeObj=None): - super(ConsoleUIATextInfo, self).__init__(obj,position,_rangeObj) + super(consoleUIATextInfo, self).__init__(obj,position,_rangeObj) if position==textInfos.POSITION_CARET: if winVersion.build >= 18362: #Windows 10 version 1903 # The UIA implementation in 1903 causes the caret to be off-by-one, so move it one position to the right to compensate. @@ -22,4 +22,12 @@ def __init__(self,obj,position,_rangeObj=None): class consoleUIA(Terminal): - _TextInfo=ConsoleUIATextInfo \ No newline at end of file + _TextInfo=consoleUIATextInfo + def event_textChanged(self): + # fire textChange for liveText + #Todo: this is probably a good place to filter out extraneous events from user input + self.event_textChange() + def _getTextLines(self): + # Filter out extraneous empty lines from UIA + #Todo: do this (also) somewhere else so they aren't in document review either + return self.makeTextInfo(textInfos.POSITION_ALL).text.strip().split("\r\n") \ No newline at end of file From 8aff6d0d2bb7a4bf5e1a6f526cede7496ba39f8e Mon Sep 17 00:00:00 2001 From: Bill Dengler Date: Wed, 22 May 2019 01:17:59 -0400 Subject: [PATCH 05/24] Filter out extraneous characters by disabling live text reporting while a user is typing. This does not regress NVDA functionality, since we already cancel speech when the user types. --- source/NVDAObjects/UIA/ConsoleUIA.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/source/NVDAObjects/UIA/ConsoleUIA.py b/source/NVDAObjects/UIA/ConsoleUIA.py index bb12d0629e1..543054381e9 100644 --- a/source/NVDAObjects/UIA/ConsoleUIA.py +++ b/source/NVDAObjects/UIA/ConsoleUIA.py @@ -4,9 +4,11 @@ #See the file COPYING for more details. #Copyright (C) 2019 Bill Dengler +import time import textInfos import UIAHandler +from scriptHandler import script from winVersion import winVersion from . import UIATextInfo from ..behaviors import Terminal @@ -23,10 +25,25 @@ def __init__(self,obj,position,_rangeObj=None): class consoleUIA(Terminal): _TextInfo=consoleUIATextInfo + _isTyping=False + _lastCharTime=0 + def _reportNewText(self, line): + # Additional typed character filtering beyond that in LiveText + if self._isTyping and time.time()-self._lastCharTime <= 2: + return + super(consoleUIA, self)._reportNewText(line) def event_textChanged(self): # fire textChange for liveText - #Todo: this is probably a good place to filter out extraneous events from user input self.event_textChange() + def event_typedCharacter(self, ch): + if len(''.join(ch.split())) > 0: + self._isTyping=True + self._lastCharTime=time.time() + super(consoleUIA, self).event_typedCharacter(ch) + @script(gestures=["kb:enter","kb:numpadEnter"]) + def script_clear_isTyping(self, gesture): + gesture.send() + self._isTyping=False def _getTextLines(self): # Filter out extraneous empty lines from UIA #Todo: do this (also) somewhere else so they aren't in document review either From 3b7ab8820ee11816f15df6b1f3e9d4fa65565787 Mon Sep 17 00:00:00 2001 From: Bill Dengler Date: Wed, 22 May 2019 01:25:44 -0400 Subject: [PATCH 06/24] Cleanup. --- source/NVDAObjects/UIA/ConsoleUIA.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source/NVDAObjects/UIA/ConsoleUIA.py b/source/NVDAObjects/UIA/ConsoleUIA.py index 543054381e9..9bd74953815 100644 --- a/source/NVDAObjects/UIA/ConsoleUIA.py +++ b/source/NVDAObjects/UIA/ConsoleUIA.py @@ -27,23 +27,28 @@ class consoleUIA(Terminal): _TextInfo=consoleUIATextInfo _isTyping=False _lastCharTime=0 + def _reportNewText(self, line): # Additional typed character filtering beyond that in LiveText if self._isTyping and time.time()-self._lastCharTime <= 2: return super(consoleUIA, self)._reportNewText(line) + def event_textChanged(self): # fire textChange for liveText self.event_textChange() + def event_typedCharacter(self, ch): if len(''.join(ch.split())) > 0: self._isTyping=True self._lastCharTime=time.time() super(consoleUIA, self).event_typedCharacter(ch) + @script(gestures=["kb:enter","kb:numpadEnter"]) def script_clear_isTyping(self, gesture): gesture.send() self._isTyping=False + def _getTextLines(self): # Filter out extraneous empty lines from UIA #Todo: do this (also) somewhere else so they aren't in document review either From ed008b55ce58577078fe71dca64f464be8c30c98 Mon Sep 17 00:00:00 2001 From: Bill Dengler Date: Wed, 22 May 2019 13:21:18 -0400 Subject: [PATCH 07/24] Style, eliminate magic number, halve typing timeout, update label in GUI to inform the user that restarting NVDA is required to switch console implementations. --- source/NVDAObjects/UIA/ConsoleUIA.py | 57 ++++++++++++++++------------ source/gui/settingsDialogs.py | 2 +- 2 files changed, 33 insertions(+), 26 deletions(-) diff --git a/source/NVDAObjects/UIA/ConsoleUIA.py b/source/NVDAObjects/UIA/ConsoleUIA.py index 9bd74953815..dd936940905 100644 --- a/source/NVDAObjects/UIA/ConsoleUIA.py +++ b/source/NVDAObjects/UIA/ConsoleUIA.py @@ -1,8 +1,8 @@ -#NVDAObjects/UIA/ConsoleUIA.py -#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 Bill Dengler +# NVDAObjects/UIA/ConsoleUIA.py +# 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 Bill Dengler import time import textInfos @@ -15,41 +15,48 @@ class consoleUIATextInfo(UIATextInfo): - def __init__(self,obj,position,_rangeObj=None): - super(consoleUIATextInfo, self).__init__(obj,position,_rangeObj) - if position==textInfos.POSITION_CARET: - if winVersion.build >= 18362: #Windows 10 version 1903 - # The UIA implementation in 1903 causes the caret to be off-by-one, so move it one position to the right to compensate. - self._rangeObj.MoveEndpointByUnit(UIAHandler.TextPatternRangeEndpoint_Start,UIAHandler.NVDAUnitsToUIAUnits['character'],1) + def __init__(self, obj, position, _rangeObj=None): + super(consoleUIATextInfo, self).__init__(obj, position, _rangeObj) + if position == textInfos.POSITION_CARET: + if winVersion.build >= 18362: # Windows 10 version 1903 + # The UIA implementation in 1903 causes the caret to be + # off-by-one, so move it one position to the right + # to compensate. + self._rangeObj.MoveEndpointByUnit( + UIAHandler.TextPatternRangeEndpoint_Start, + UIAHandler.NVDAUnitsToUIAUnits['character'], + 1 + ) class consoleUIA(Terminal): - _TextInfo=consoleUIATextInfo + _TextInfo = consoleUIATextInfo _isTyping=False - _lastCharTime=0 - + _lastCharTime = 0 + _TYPING_TIMEOUT = 1 + def _reportNewText(self, line): # Additional typed character filtering beyond that in LiveText - if self._isTyping and time.time()-self._lastCharTime <= 2: + if self._isTyping and time.time()-self._lastCharTime <= self._TYPING_TIMEOUT: return super(consoleUIA, self)._reportNewText(line) - + def event_textChanged(self): # fire textChange for liveText self.event_textChange() - + def event_typedCharacter(self, ch): if len(''.join(ch.split())) > 0: - self._isTyping=True - self._lastCharTime=time.time() + self._isTyping = True + self._lastCharTime = time.time() super(consoleUIA, self).event_typedCharacter(ch) - - @script(gestures=["kb:enter","kb:numpadEnter"]) + + @script(gestures=["kb:enter", "kb:numpadEnter"]) def script_clear_isTyping(self, gesture): gesture.send() - self._isTyping=False - + self._isTyping = False + def _getTextLines(self): # Filter out extraneous empty lines from UIA - #Todo: do this (also) somewhere else so they aren't in document review either - return self.makeTextInfo(textInfos.POSITION_ALL).text.strip().split("\r\n") \ No newline at end of file + # Todo: do this (also) somewhere else so they aren't in document review either + return self.makeTextInfo(textInfos.POSITION_ALL).text.strip().split("\r\n") diff --git a/source/gui/settingsDialogs.py b/source/gui/settingsDialogs.py index c2d20fbaa6b..30021c56047 100644 --- a/source/gui/settingsDialogs.py +++ b/source/gui/settingsDialogs.py @@ -2052,7 +2052,7 @@ def __init__(self, parent): # Translators: This is the label for a checkbox in the # Advanced settings panel. - label = _("Use UI Automation to access the Windows Console (highly experimental)") + label = _("Use UI Automation to access the Windows Console (highly experimental, restart NVDA for changes to take effect)") self.ConsoleUIACheckBox=UIAGroup.addItem(wx.CheckBox(self, label=label)) self.ConsoleUIACheckBox.SetValue(config.conf["UIA"]["consoleUIA"]) self.ConsoleUIACheckBox.defaultValue = self._getDefaultValue(["UIA", "consoleUIA"]) From 19d7bfb07e5413b962feebd7b5aaa93626582d47 Mon Sep 17 00:00:00 2001 From: Bill Dengler Date: Thu, 23 May 2019 20:43:21 -0400 Subject: [PATCH 08/24] Clear isTyping when tab is pressed to announce tab completion. --- source/NVDAObjects/UIA/ConsoleUIA.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/NVDAObjects/UIA/ConsoleUIA.py b/source/NVDAObjects/UIA/ConsoleUIA.py index dd936940905..0d9455a24d1 100644 --- a/source/NVDAObjects/UIA/ConsoleUIA.py +++ b/source/NVDAObjects/UIA/ConsoleUIA.py @@ -51,7 +51,7 @@ def event_typedCharacter(self, ch): self._lastCharTime = time.time() super(consoleUIA, self).event_typedCharacter(ch) - @script(gestures=["kb:enter", "kb:numpadEnter"]) + @script(gestures=["kb:enter", "kb:numpadEnter", "kb:tab"]) def script_clear_isTyping(self, gesture): gesture.send() self._isTyping = False From 9d43eb0eb258c0adbab348a35406f4290d75f35c Mon Sep 17 00:00:00 2001 From: Bill Dengler Date: Thu, 23 May 2019 19:37:18 -0400 Subject: [PATCH 09/24] Re-implement consoleUIA._getTextLines using UIATextPattern.GetVisibleRanges. This may improve performance when large amounts of text are written to the console, but possibly at the cost of less reliable autoread (particularly when the screen is refreshed or scrolled). --- source/NVDAObjects/UIA/ConsoleUIA.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/NVDAObjects/UIA/ConsoleUIA.py b/source/NVDAObjects/UIA/ConsoleUIA.py index 0d9455a24d1..6a36b4b2601 100644 --- a/source/NVDAObjects/UIA/ConsoleUIA.py +++ b/source/NVDAObjects/UIA/ConsoleUIA.py @@ -59,4 +59,6 @@ def script_clear_isTyping(self, gesture): def _getTextLines(self): # Filter out extraneous empty lines from UIA # Todo: do this (also) somewhere else so they aren't in document review either - return self.makeTextInfo(textInfos.POSITION_ALL).text.strip().split("\r\n") + ptr = self.UIATextPattern.GetVisibleRanges() + res = [ptr.GetElement(i).GetText(-1) for i in range(ptr.length)] + return res \ No newline at end of file From 758f60b971f350f5bc8b11f1ecf0d1c95b2a6557 Mon Sep 17 00:00:00 2001 From: Bill Dengler Date: Fri, 24 May 2019 16:27:06 -0400 Subject: [PATCH 10/24] Review actions, style, update user guide. The user guide will need to be updated once auto-detection is introduced (and therefore the NVDA preference is changed). --- source/NVDAObjects/UIA/ConsoleUIA.py | 6 +++--- source/gui/settingsDialogs.py | 2 +- user_docs/en/userGuide.t2t | 3 +++ 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/source/NVDAObjects/UIA/ConsoleUIA.py b/source/NVDAObjects/UIA/ConsoleUIA.py index 6a36b4b2601..2e43c6982a4 100644 --- a/source/NVDAObjects/UIA/ConsoleUIA.py +++ b/source/NVDAObjects/UIA/ConsoleUIA.py @@ -31,13 +31,13 @@ def __init__(self, obj, position, _rangeObj=None): class consoleUIA(Terminal): _TextInfo = consoleUIATextInfo - _isTyping=False + _isTyping = False _lastCharTime = 0 _TYPING_TIMEOUT = 1 def _reportNewText(self, line): # Additional typed character filtering beyond that in LiveText - if self._isTyping and time.time()-self._lastCharTime <= self._TYPING_TIMEOUT: + if self._isTyping and time.time() - self._lastCharTime <= self._TYPING_TIMEOUT: return super(consoleUIA, self)._reportNewText(line) @@ -61,4 +61,4 @@ def _getTextLines(self): # Todo: do this (also) somewhere else so they aren't in document review either ptr = self.UIATextPattern.GetVisibleRanges() res = [ptr.GetElement(i).GetText(-1) for i in range(ptr.length)] - return res \ No newline at end of file + return res diff --git a/source/gui/settingsDialogs.py b/source/gui/settingsDialogs.py index 30021c56047..b90c78c371c 100644 --- a/source/gui/settingsDialogs.py +++ b/source/gui/settingsDialogs.py @@ -2052,7 +2052,7 @@ def __init__(self, parent): # Translators: This is the label for a checkbox in the # Advanced settings panel. - label = _("Use UI Automation to access the Windows Console (highly experimental, restart NVDA for changes to take effect)") + label = _("Use UI Automation to access the Windows Console (restart NVDA for changes to take effect)") self.ConsoleUIACheckBox=UIAGroup.addItem(wx.CheckBox(self, label=label)) self.ConsoleUIACheckBox.SetValue(config.conf["UIA"]["consoleUIA"]) self.ConsoleUIACheckBox.defaultValue = self._getDefaultValue(["UIA", "consoleUIA"]) diff --git a/user_docs/en/userGuide.t2t b/user_docs/en/userGuide.t2t index c42568e56a7..61231897b64 100644 --- a/user_docs/en/userGuide.t2t +++ b/user_docs/en/userGuide.t2t @@ -1670,6 +1670,9 @@ This includes in Microsoft Word itself, and also the Microsoft Outlook message v However, There may be some information which is either not exposed, or exposed incorrectly in some versions of Microsoft Office, which means this UI automation support cannot always be relied upon. We still do not recommend that the majority of users turn this on by default, though we do welcome users of Office 2016/365 to test this feature and provide feedback. +==== Use UI automation to access the Windows Console====[AdvancedSettingsConsoleUIA] +When this option is enabled, NVDA will use a new, work in progress version of its support for Windows Console which takes advantage of [accessibility improvements made by Microsoft https://devblogs.microsoft.com/commandline/whats-new-in-windows-console-in-windows-10-fall-creators-update/]. This feature is highly experimental and is still incomplete, so its use is not yet recommended, especially for users of Windows 10 version 1903 and later. However, once completed, it is anticipated that this new support will become the default, improving NVDA's performance and stability in Windows command consoles. + ==== Automatically set system focus to focusable elements in Browse Mode ====[BrowseModeSettingsAutoFocusFocusableElements] Key: NVDA+8 From ed61c7c746819bdea724f0087a628e9e1d09e2a1 Mon Sep 17 00:00:00 2001 From: Bill Dengler Date: Sat, 25 May 2019 11:35:19 -0400 Subject: [PATCH 11/24] Review actions. --- source/NVDAObjects/UIA/__init__.py | 10 +++++++--- .../UIA/{ConsoleUIA.py => winConsoleUIA.py} | 10 +++++----- source/_UIAHandler.py | 2 +- source/keyboardHandler.py | 6 ++++-- 4 files changed, 17 insertions(+), 11 deletions(-) rename source/NVDAObjects/UIA/{ConsoleUIA.py => winConsoleUIA.py} (90%) diff --git a/source/NVDAObjects/UIA/__init__.py b/source/NVDAObjects/UIA/__init__.py index b48ea632475..58a04077426 100644 --- a/source/NVDAObjects/UIA/__init__.py +++ b/source/NVDAObjects/UIA/__init__.py @@ -859,9 +859,13 @@ def findOverlayClasses(self,clsList): pass # Support Windows Console's UIA interface - if self.windowClassName == "ConsoleWindowClass" and self.UIAElement.cachedAutomationId == "Text Area" and config.conf['UIA']['consoleUIA']: - from .ConsoleUIA import consoleUIA - clsList.append(consoleUIA) + if ( + self.windowClassName == "ConsoleWindowClass" + and self.UIAElement.cachedAutomationId == "Text Area" + and config.conf['UIA']['consoleUIA'] + ): + from .winConsoleUIA import winConsoleUIA + clsList.append(winConsoleUIA) # Add editableText support if UIA supports a text pattern if self.TextInfo==UIATextInfo: clsList.append(EditableTextWithoutAutoSelectDetection) diff --git a/source/NVDAObjects/UIA/ConsoleUIA.py b/source/NVDAObjects/UIA/winConsoleUIA.py similarity index 90% rename from source/NVDAObjects/UIA/ConsoleUIA.py rename to source/NVDAObjects/UIA/winConsoleUIA.py index 2e43c6982a4..bb6e5544180 100644 --- a/source/NVDAObjects/UIA/ConsoleUIA.py +++ b/source/NVDAObjects/UIA/winConsoleUIA.py @@ -1,4 +1,4 @@ -# NVDAObjects/UIA/ConsoleUIA.py +# NVDAObjects/UIA/winConsoleUIA.py # A part of NonVisual Desktop Access (NVDA) # This file is covered by the GNU General Public License. # See the file COPYING for more details. @@ -29,7 +29,7 @@ def __init__(self, obj, position, _rangeObj=None): ) -class consoleUIA(Terminal): +class winConsoleUIA(Terminal): _TextInfo = consoleUIATextInfo _isTyping = False _lastCharTime = 0 @@ -39,17 +39,17 @@ def _reportNewText(self, line): # Additional typed character filtering beyond that in LiveText if self._isTyping and time.time() - self._lastCharTime <= self._TYPING_TIMEOUT: return - super(consoleUIA, self)._reportNewText(line) + super(winConsoleUIA, self)._reportNewText(line) def event_textChanged(self): # fire textChange for liveText self.event_textChange() def event_typedCharacter(self, ch): - if len(''.join(ch.split())) > 0: + if not ch.isspace(): self._isTyping = True self._lastCharTime = time.time() - super(consoleUIA, self).event_typedCharacter(ch) + super(winConsoleUIA, self).event_typedCharacter(ch) @script(gestures=["kb:enter", "kb:numpadEnter", "kb:tab"]) def script_clear_isTyping(self, gesture): diff --git a/source/_UIAHandler.py b/source/_UIAHandler.py index dbd5b9e2e49..0d108ff58fb 100644 --- a/source/_UIAHandler.py +++ b/source/_UIAHandler.py @@ -142,7 +142,7 @@ UIAEventIdsToNVDAEventNames={ UIA_LiveRegionChangedEventId:"liveRegionChange", - UIA_Text_TextChangedEventId:"textChanged", + UIA_Text_TextChangedEventId:"textChange", UIA_SelectionItem_ElementSelectedEventId:"UIA_elementSelected", UIA_MenuOpenedEventId:"gainFocus", UIA_SelectionItem_ElementAddedToSelectionEventId:"stateChange", diff --git a/source/keyboardHandler.py b/source/keyboardHandler.py index 77f68a729b7..92609bf30cb 100644 --- a/source/keyboardHandler.py +++ b/source/keyboardHandler.py @@ -197,6 +197,7 @@ def internal_keyDownEvent(vkCode,scanCode,extended,injected): # #6017: handle typed characters in Win10 RS2 and above where we can't detect typed characters in-process # This code must be in the 'finally' block as code above returns in several places yet we still want to execute this particular code. focus=api.getFocusObject() + from NVDAObjects.UIA.winConsoleUIA import winConsoleUIA if ( # This is only possible in Windows 10 RS2 and above winVersion.winVersion.build>=14986 @@ -205,12 +206,13 @@ def internal_keyDownEvent(vkCode,scanCode,extended,injected): # and not if this gesture is a modifier key and not isNVDAModifierKey(vkCode,extended) and not vkCode in KeyboardInputGesture.NORMAL_MODIFIER_KEYS and ( # Either of - # We couldn't inject in-process, and its not a legacy console window (console windows have their own specific typed character support) + # We couldn't inject in-process, and its not a legacy console window. + # console windows have their own specific typed character support. (not focus.appModule.helperLocalBindingHandle and focus.windowClassName!='ConsoleWindowClass') # or the focus is within a UWP app, where WM_CHAR never gets sent or focus.windowClassName.startswith('Windows.UI.Core') #Or this is a UIA console window, where WM_CHAR messages are doubled - or focus.windowClassName == "ConsoleWindowClass" and config.conf['UIA']['consoleUIA'] + or isinstance(focus, winConsoleUIA) ) ): keyStates=(ctypes.c_byte*256)() From 0d364d778f4c6bddbc0a8a14a704e3d40fe835bf Mon Sep 17 00:00:00 2001 From: Bill Dengler Date: Sat, 25 May 2019 15:01:04 -0400 Subject: [PATCH 12/24] Remove unneeded event_textChanged --- source/NVDAObjects/UIA/winConsoleUIA.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/source/NVDAObjects/UIA/winConsoleUIA.py b/source/NVDAObjects/UIA/winConsoleUIA.py index bb6e5544180..1e22c6b1daa 100644 --- a/source/NVDAObjects/UIA/winConsoleUIA.py +++ b/source/NVDAObjects/UIA/winConsoleUIA.py @@ -41,10 +41,6 @@ def _reportNewText(self, line): return super(winConsoleUIA, self)._reportNewText(line) - def event_textChanged(self): - # fire textChange for liveText - self.event_textChange() - def event_typedCharacter(self, ch): if not ch.isspace(): self._isTyping = True From e94c1d60fafc0da854440f5e31eb8e54f5a3e015 Mon Sep 17 00:00:00 2001 From: Bill Dengler Date: Sat, 25 May 2019 17:49:34 -0400 Subject: [PATCH 13/24] Fix document review on Windows 10 1903. This fix adds a new textInfo instance variable, _expandCollapseBeforeReview, which stops review from expanding and immediately collapsing the textInfo during review. For some reason, this was causing object review to malfunction in this instance. --- source/NVDAObjects/UIA/winConsoleUIA.py | 2 ++ source/globalCommands.py | 35 +++++++++++++++---------- source/textInfos/__init__.py | 4 +++ 3 files changed, 27 insertions(+), 14 deletions(-) diff --git a/source/NVDAObjects/UIA/winConsoleUIA.py b/source/NVDAObjects/UIA/winConsoleUIA.py index 1e22c6b1daa..140b833cc89 100644 --- a/source/NVDAObjects/UIA/winConsoleUIA.py +++ b/source/NVDAObjects/UIA/winConsoleUIA.py @@ -15,6 +15,8 @@ class consoleUIATextInfo(UIATextInfo): + _expandCollapseBeforeReview = False + def __init__(self, obj, position, _rangeObj=None): super(consoleUIATextInfo, self).__init__(obj, position, _rangeObj) if position == textInfos.POSITION_CARET: diff --git a/source/globalCommands.py b/source/globalCommands.py index e5962bebcc9..0270b88af5a 100755 --- a/source/globalCommands.py +++ b/source/globalCommands.py @@ -983,8 +983,9 @@ def script_review_top(self,gesture): def script_review_previousLine(self,gesture): info=api.getReviewPosition().copy() - info.expand(textInfos.UNIT_LINE) - info.collapse() + if info._expandCollapseBeforeReview: + info.expand(textInfos.UNIT_LINE) + info.collapse() res=info.move(textInfos.UNIT_LINE,-1) if res==0: # Translators: a message reported when review cursor is at the top line of the current navigator object. @@ -1014,8 +1015,9 @@ def script_review_currentLine(self,gesture): def script_review_nextLine(self,gesture): info=api.getReviewPosition().copy() - info.expand(textInfos.UNIT_LINE) - info.collapse() + if info._expandCollapseBeforeReview: + info.expand(textInfos.UNIT_LINE) + info.collapse() res=info.move(textInfos.UNIT_LINE,1) if res==0: # Translators: a message reported when review cursor is at the bottom line of the current navigator object. @@ -1041,8 +1043,9 @@ def script_review_bottom(self,gesture): def script_review_previousWord(self,gesture): info=api.getReviewPosition().copy() - info.expand(textInfos.UNIT_WORD) - info.collapse() + if info._expandCollapseBeforeReview: + info.expand(textInfos.UNIT_WORD) + info.collapse() res=info.move(textInfos.UNIT_WORD,-1) if res==0: # Translators: a message reported when review cursor is at the top line of the current navigator object. @@ -1071,8 +1074,9 @@ def script_review_currentWord(self,gesture): def script_review_nextWord(self,gesture): info=api.getReviewPosition().copy() - info.expand(textInfos.UNIT_WORD) - info.collapse() + if info._expandCollapseBeforeReview: + info.expand(textInfos.UNIT_WORD) + info.collapse() res=info.move(textInfos.UNIT_WORD,1) if res==0: # Translators: a message reported when review cursor is at the bottom line of the current navigator object. @@ -1087,8 +1091,9 @@ def script_review_nextWord(self,gesture): def script_review_startOfLine(self,gesture): info=api.getReviewPosition().copy() - info.expand(textInfos.UNIT_LINE) - info.collapse() + if info._expandCollapseBeforeReview: + info.expand(textInfos.UNIT_LINE) + info.collapse() api.setReviewPosition(info) info.expand(textInfos.UNIT_CHARACTER) ui.reviewMessage(_("Left")) @@ -1101,8 +1106,9 @@ def script_review_previousCharacter(self,gesture): lineInfo=api.getReviewPosition().copy() lineInfo.expand(textInfos.UNIT_LINE) charInfo=api.getReviewPosition().copy() - charInfo.expand(textInfos.UNIT_CHARACTER) - charInfo.collapse() + if charInfo._expandCollapseBeforeReview: + charInfo.expand(textInfos.UNIT_CHARACTER) + charInfo.collapse() res=charInfo.move(textInfos.UNIT_CHARACTER,-1) if res==0 or charInfo.compareEndPoints(lineInfo,"startToStart")<0: # Translators: a message reported when review cursor is at the leftmost character of the current navigator object's text. @@ -1158,8 +1164,9 @@ def script_review_nextCharacter(self,gesture): lineInfo=api.getReviewPosition().copy() lineInfo.expand(textInfos.UNIT_LINE) charInfo=api.getReviewPosition().copy() - charInfo.expand(textInfos.UNIT_CHARACTER) - charInfo.collapse() + if charInfo._expandCollapseBeforeReview: + charInfo.expand(textInfos.UNIT_CHARACTER) + charInfo.collapse() res=charInfo.move(textInfos.UNIT_CHARACTER,1) if res==0 or charInfo.compareEndPoints(lineInfo,"endToEnd")>=0: # Translators: a message reported when review cursor is at the rightmost character of the current navigator object's text. diff --git a/source/textInfos/__init__.py b/source/textInfos/__init__.py index 39e75ef046f..4497e183436 100755 --- a/source/textInfos/__init__.py +++ b/source/textInfos/__init__.py @@ -264,6 +264,10 @@ class TextInfo(baseObject.AutoPropertyObject): @type bookmark: L{Bookmark} """ + #: whether this textInfo should be expanded then collapsed around its enclosing unit before review. + #: This can be problematic for some implementations. + _expandCollapseBeforeReview = True + def __init__(self,obj,position): """Constructor. Subclasses must extend this, calling the superclass method first. From 0ff312fb073b37beba634fefb95bceed653b641c Mon Sep 17 00:00:00 2001 From: Bill Dengler Date: Sat, 25 May 2019 19:58:35 -0400 Subject: [PATCH 14/24] Remove 1903 warning from user guide. --- user_docs/en/userGuide.t2t | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_docs/en/userGuide.t2t b/user_docs/en/userGuide.t2t index 61231897b64..32ccb4d5ad4 100644 --- a/user_docs/en/userGuide.t2t +++ b/user_docs/en/userGuide.t2t @@ -1671,7 +1671,7 @@ However, There may be some information which is either not exposed, or exposed i We still do not recommend that the majority of users turn this on by default, though we do welcome users of Office 2016/365 to test this feature and provide feedback. ==== Use UI automation to access the Windows Console====[AdvancedSettingsConsoleUIA] -When this option is enabled, NVDA will use a new, work in progress version of its support for Windows Console which takes advantage of [accessibility improvements made by Microsoft https://devblogs.microsoft.com/commandline/whats-new-in-windows-console-in-windows-10-fall-creators-update/]. This feature is highly experimental and is still incomplete, so its use is not yet recommended, especially for users of Windows 10 version 1903 and later. However, once completed, it is anticipated that this new support will become the default, improving NVDA's performance and stability in Windows command consoles. +When this option is enabled, NVDA will use a new, work in progress version of its support for Windows Console which takes advantage of [accessibility improvements made by Microsoft https://devblogs.microsoft.com/commandline/whats-new-in-windows-console-in-windows-10-fall-creators-update/]. This feature is highly experimental and is still incomplete, so its use is not yet recommended. However, once completed, it is anticipated that this new support will become the default, improving NVDA's performance and stability in Windows command consoles. ==== Automatically set system focus to focusable elements in Browse Mode ====[BrowseModeSettingsAutoFocusFocusableElements] Key: NVDA+8 From 3c437f4958b22efc74b5df27a46f15acfafee860 Mon Sep 17 00:00:00 2001 From: Bill Dengler Date: Mon, 27 May 2019 00:26:54 -0400 Subject: [PATCH 15/24] Check bad UIA window class name at runtime. This allows for UIA console support to be dynamically enabled/disabled. Note: _UIAHandler.badUIAWindowClassNames has been removed. To check if a UIA windowClassName is bad, use the new _UIAHandler.UIAHandler._isBadUIAWindowClassName method. --- source/_UIAHandler.py | 52 ++++++++++++++++++----------------- source/gui/settingsDialogs.py | 2 +- 2 files changed, 28 insertions(+), 26 deletions(-) diff --git a/source/_UIAHandler.py b/source/_UIAHandler.py index 0d108ff58fb..44ccac6b63a 100644 --- a/source/_UIAHandler.py +++ b/source/_UIAHandler.py @@ -44,30 +44,6 @@ 'RAIL_WINDOW', ] -badUIAWindowClassNames=[ - "SysTreeView32", - "WuDuiListView", - "ComboBox", - "msctls_progress32", - "Edit", - "CommonPlacesWrapperWndClass", - "SysMonthCal32", - "SUPERGRID", #Outlook 2010 message list - "RichEdit", - "RichEdit20", - "RICHEDIT50W", - "SysListView32", - "EXCEL7", - "Button", - # #8944: The Foxit UIA implementation is incomplete and should not be used for now. - "FoxitDocWnd", -] - -# #7497: Windows 10 Fall Creators Update has an incomplete UIA implementation for console windows, therefore for now we should ignore it. -# It does not implement caret/selection, and probably has no new text events. -if not config.conf['UIA']['consoleUIA']: - badUIAWindowClassNames.append("ConsoleWindowClass") - # #8405: used to detect UIA dialogs prior to Windows 10 RS5. UIADialogClassNames=[ "#32770", @@ -344,6 +320,32 @@ def IUIAutomationNotificationEventHandler_HandleNotificationEvent(self,sender,No return eventHandler.queueEvent("UIA_notification",obj, notificationKind=NotificationKind, notificationProcessing=NotificationProcessing, displayString=displayString, activityId=activityId) + def _isBadUIAWindowClassName(self, windowClass): + "Given a windowClassName, returns True if this is a known problematic UIA implementation." + badUIAWindowClassNames=[ + "SysTreeView32", + "WuDuiListView", + "ComboBox", + "msctls_progress32", + "Edit", + "CommonPlacesWrapperWndClass", + "SysMonthCal32", + "SUPERGRID", #Outlook 2010 message list + "RichEdit", + "RichEdit20", + "RICHEDIT50W", + "SysListView32", + "EXCEL7", + "Button", + # #8944: The Foxit UIA implementation is incomplete and should not be used for now. + "FoxitDocWnd", + ] + # #7497: Windows 10 Fall Creators Update has an incomplete UIA implementation for console windows, therefore for now we should ignore it. + # It does not implement caret/selection, and probably has no new text events. + if not config.conf['UIA']['consoleUIA']: + badUIAWindowClassNames.append("ConsoleWindowClass") + return windowClass in badUIAWindowClassNames + def _isUIAWindowHelper(self,hwnd): # UIA in NVDA's process freezes in Windows 7 and below processID=winUser.getWindowThreadProcessID(hwnd)[0] @@ -360,7 +362,7 @@ def _isUIAWindowHelper(self,hwnd): if appModule and appModule.isGoodUIAWindow(hwnd): return True # There are certain window classes that just had bad UIA implementations - if windowClass in badUIAWindowClassNames: + if self._isBadUIAWindowClassName(windowClass): return False # allow the appModule for the window to also choose if this window is bad if appModule and appModule.isBadUIAWindow(hwnd): diff --git a/source/gui/settingsDialogs.py b/source/gui/settingsDialogs.py index b90c78c371c..a8f365cb228 100644 --- a/source/gui/settingsDialogs.py +++ b/source/gui/settingsDialogs.py @@ -2052,7 +2052,7 @@ def __init__(self, parent): # Translators: This is the label for a checkbox in the # Advanced settings panel. - label = _("Use UI Automation to access the Windows Console (restart NVDA for changes to take effect)") + label = _("Use UI Automation to access the Windows Console") self.ConsoleUIACheckBox=UIAGroup.addItem(wx.CheckBox(self, label=label)) self.ConsoleUIACheckBox.SetValue(config.conf["UIA"]["consoleUIA"]) self.ConsoleUIACheckBox.defaultValue = self._getDefaultValue(["UIA", "consoleUIA"]) From aae5e96208173c4a9905ac3c154244a6fe4f8ecc Mon Sep 17 00:00:00 2001 From: Bill Dengler Date: Mon, 27 May 2019 00:58:04 -0400 Subject: [PATCH 16/24] Add a new winVersion.isAtLeastWin10 function for checking win10 builds with friendly version numbers, and only register for UIA textChange on Windows 10. --- source/NVDAObjects/UIA/winConsoleUIA.py | 4 ++-- source/_UIAHandler.py | 5 ++++- source/keyboardHandler.py | 2 +- source/winVersion.py | 24 ++++++++++++++++++++++++ 4 files changed, 31 insertions(+), 4 deletions(-) diff --git a/source/NVDAObjects/UIA/winConsoleUIA.py b/source/NVDAObjects/UIA/winConsoleUIA.py index 140b833cc89..9436ff826e9 100644 --- a/source/NVDAObjects/UIA/winConsoleUIA.py +++ b/source/NVDAObjects/UIA/winConsoleUIA.py @@ -9,7 +9,7 @@ import UIAHandler from scriptHandler import script -from winVersion import winVersion +from winVersion import isAtLeastWin10 from . import UIATextInfo from ..behaviors import Terminal @@ -20,7 +20,7 @@ class consoleUIATextInfo(UIATextInfo): def __init__(self, obj, position, _rangeObj=None): super(consoleUIATextInfo, self).__init__(obj, position, _rangeObj) if position == textInfos.POSITION_CARET: - if winVersion.build >= 18362: # Windows 10 version 1903 + if isAtLeastWin10(1903): # The UIA implementation in 1903 causes the caret to be # off-by-one, so move it one position to the right # to compensate. diff --git a/source/_UIAHandler.py b/source/_UIAHandler.py index 44ccac6b63a..a1a9758d47a 100644 --- a/source/_UIAHandler.py +++ b/source/_UIAHandler.py @@ -21,6 +21,7 @@ import NVDAHelper import winKernel import winUser +import winVersion import eventHandler from logHandler import log import UIAUtils @@ -118,7 +119,6 @@ UIAEventIdsToNVDAEventNames={ UIA_LiveRegionChangedEventId:"liveRegionChange", - UIA_Text_TextChangedEventId:"textChange", UIA_SelectionItem_ElementSelectedEventId:"UIA_elementSelected", UIA_MenuOpenedEventId:"gainFocus", UIA_SelectionItem_ElementAddedToSelectionEventId:"stateChange", @@ -132,6 +132,9 @@ UIA_SystemAlertEventId:"UIA_systemAlert", } +if winVersion.isAtLeastWin10(): + UIAEventIdsToNVDAEventNames[UIA_Text_TextChangedEventId] = "textChange" + class UIAHandler(COMObject): _com_interfaces_=[IUIAutomationEventHandler,IUIAutomationFocusChangedEventHandler,IUIAutomationPropertyChangedEventHandler,IUIAutomationNotificationEventHandler] diff --git a/source/keyboardHandler.py b/source/keyboardHandler.py index 92609bf30cb..085b5707f44 100644 --- a/source/keyboardHandler.py +++ b/source/keyboardHandler.py @@ -200,7 +200,7 @@ def internal_keyDownEvent(vkCode,scanCode,extended,injected): from NVDAObjects.UIA.winConsoleUIA import winConsoleUIA if ( # This is only possible in Windows 10 RS2 and above - winVersion.winVersion.build>=14986 + winVersion.isAtLeastWin10(1703) # And we only want to do this if the gesture did not result in an executed action and not gestureExecuted # and not if this gesture is a modifier key diff --git a/source/winVersion.py b/source/winVersion.py index e32e0e6b755..d67d3bc153b 100644 --- a/source/winVersion.py +++ b/source/winVersion.py @@ -26,3 +26,27 @@ def canRunVc2010Builds(): UWP_OCR_DATA_PATH = os.path.expandvars(r"$windir\OCR") def isUwpOcrAvailable(): return os.path.isdir(UWP_OCR_DATA_PATH) + +def isAtLeastWin10(version=1507): + """ + Returns True if NVDA is running on at least the supplied version of Windows 10. If no argument is supplied, returns True for all public Windows 10 releases. + Note: this function will always return False for source copies of NVDA due to a Python bug. + """ + from logHandler import log + win10VersionsToBuilds={ + 1507: 10240, + 1511: 10586, + 1607: 14393, + 1703: 15063, + 1709: 16299, + 1803: 17134, + 1809: 17763, + 1903: 18362 + } + if winVersion.major < 10: + return False + try: + return winVersion.build >= win10VersionsToBuilds[version] + except KeyError: + log.warning("Unknown Windows 10 version {}".format(version)) + return False \ No newline at end of file From d9f7fe66ebbc5636e55f8d95dd8fc5f073e6fa1c Mon Sep 17 00:00:00 2001 From: Bill Dengler Date: Mon, 27 May 2019 01:02:07 -0400 Subject: [PATCH 17/24] Misc review actions. --- source/NVDAObjects/UIA/winConsoleUIA.py | 2 +- source/winConsoleHandler.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/source/NVDAObjects/UIA/winConsoleUIA.py b/source/NVDAObjects/UIA/winConsoleUIA.py index 9436ff826e9..6470911194e 100644 --- a/source/NVDAObjects/UIA/winConsoleUIA.py +++ b/source/NVDAObjects/UIA/winConsoleUIA.py @@ -26,7 +26,7 @@ def __init__(self, obj, position, _rangeObj=None): # to compensate. self._rangeObj.MoveEndpointByUnit( UIAHandler.TextPatternRangeEndpoint_Start, - UIAHandler.NVDAUnitsToUIAUnits['character'], + UIAHandler.NVDAUnitsToUIAUnits[textInfos.UNIT_CHARACTER], 1 ) diff --git a/source/winConsoleHandler.py b/source/winConsoleHandler.py index 96a06d8a990..62d7e74a2d8 100755 --- a/source/winConsoleHandler.py +++ b/source/winConsoleHandler.py @@ -46,6 +46,7 @@ COMMON_LVB_UNDERSCORE=0x8000 + @wincon.PHANDLER_ROUTINE def _consoleCtrlHandler(event): if event in (wincon.CTRL_C_EVENT,wincon.CTRL_BREAK_EVENT): From ed9a5fe06453adcd092270090114134fd92ef7b4 Mon Sep 17 00:00:00 2001 From: Bill Dengler Date: Mon, 27 May 2019 02:51:16 -0400 Subject: [PATCH 18/24] Review actions. --- source/_UIAHandler.py | 41 +++++++++++++++++++++-------------------- source/winVersion.py | 7 ++++--- 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/source/_UIAHandler.py b/source/_UIAHandler.py index a1a9758d47a..a06512167cf 100644 --- a/source/_UIAHandler.py +++ b/source/_UIAHandler.py @@ -45,6 +45,25 @@ 'RAIL_WINDOW', ] +badUIAWindowClassNames=[ +"SysTreeView32", +"WuDuiListView", +"ComboBox", +"msctls_progress32", +"Edit", +"CommonPlacesWrapperWndClass", +"SysMonthCal32", +"SUPERGRID", #Outlook 2010 message list +"RichEdit", +"RichEdit20", +"RICHEDIT50W", +"SysListView32", +"EXCEL7", +"Button", +# #8944: The Foxit UIA implementation is incomplete and should not be used for now. +"FoxitDocWnd", +] + # #8405: used to detect UIA dialogs prior to Windows 10 RS5. UIADialogClassNames=[ "#32770", @@ -325,28 +344,10 @@ def IUIAutomationNotificationEventHandler_HandleNotificationEvent(self,sender,No def _isBadUIAWindowClassName(self, windowClass): "Given a windowClassName, returns True if this is a known problematic UIA implementation." - badUIAWindowClassNames=[ - "SysTreeView32", - "WuDuiListView", - "ComboBox", - "msctls_progress32", - "Edit", - "CommonPlacesWrapperWndClass", - "SysMonthCal32", - "SUPERGRID", #Outlook 2010 message list - "RichEdit", - "RichEdit20", - "RICHEDIT50W", - "SysListView32", - "EXCEL7", - "Button", - # #8944: The Foxit UIA implementation is incomplete and should not be used for now. - "FoxitDocWnd", - ] # #7497: Windows 10 Fall Creators Update has an incomplete UIA implementation for console windows, therefore for now we should ignore it. # It does not implement caret/selection, and probably has no new text events. - if not config.conf['UIA']['consoleUIA']: - badUIAWindowClassNames.append("ConsoleWindowClass") + if windowClass == "ConsoleWindowClass" and not config.conf['UIA']['consoleUIA']: + return True return windowClass in badUIAWindowClassNames def _isUIAWindowHelper(self,hwnd): diff --git a/source/winVersion.py b/source/winVersion.py index d67d3bc153b..75c854c43e4 100644 --- a/source/winVersion.py +++ b/source/winVersion.py @@ -29,8 +29,9 @@ def isUwpOcrAvailable(): def isAtLeastWin10(version=1507): """ - Returns True if NVDA is running on at least the supplied version of Windows 10. If no argument is supplied, returns True for all public Windows 10 releases. + Returns True if NVDA is running on at least the supplied release version of Windows 10. If no argument is supplied, returns True for all public Windows 10 releases. Note: this function will always return False for source copies of NVDA due to a Python bug. + @param version: a release version of Windows 10 (such as 1903). """ from logHandler import log win10VersionsToBuilds={ @@ -48,5 +49,5 @@ def isAtLeastWin10(version=1507): try: return winVersion.build >= win10VersionsToBuilds[version] except KeyError: - log.warning("Unknown Windows 10 version {}".format(version)) - return False \ No newline at end of file + log.error("Unknown Windows 10 version {}".format(version)) + return False From f19bd1f265634917223dae1b909e9f0b55b7fea0 Mon Sep 17 00:00:00 2001 From: Bill Dengler Date: Mon, 27 May 2019 03:22:26 -0400 Subject: [PATCH 19/24] Change config spec --- source/NVDAObjects/UIA/__init__.py | 2 +- source/NVDAObjects/window/__init__.py | 2 +- source/_UIAHandler.py | 2 +- source/config/configSpec.py | 2 +- source/gui/settingsDialogs.py | 14 +++++++++----- 5 files changed, 13 insertions(+), 9 deletions(-) diff --git a/source/NVDAObjects/UIA/__init__.py b/source/NVDAObjects/UIA/__init__.py index 58a04077426..9e24448b21b 100644 --- a/source/NVDAObjects/UIA/__init__.py +++ b/source/NVDAObjects/UIA/__init__.py @@ -862,7 +862,7 @@ def findOverlayClasses(self,clsList): if ( self.windowClassName == "ConsoleWindowClass" and self.UIAElement.cachedAutomationId == "Text Area" - and config.conf['UIA']['consoleUIA'] + and config.conf['UIA']['winConsoleImplementation'] == "UIA" ): from .winConsoleUIA import winConsoleUIA clsList.append(winConsoleUIA) diff --git a/source/NVDAObjects/window/__init__.py b/source/NVDAObjects/window/__init__.py index 98d8ae69cda..8ab59c63451 100644 --- a/source/NVDAObjects/window/__init__.py +++ b/source/NVDAObjects/window/__init__.py @@ -121,7 +121,7 @@ def findOverlayClasses(self,clsList): from .scintilla import Scintilla as newCls elif windowClassName in ("AkelEditW", "AkelEditA"): from .akelEdit import AkelEdit as newCls - elif windowClassName=="ConsoleWindowClass" and not config.conf['UIA']['consoleUIA']: + elif windowClassName=="ConsoleWindowClass" and config.conf['UIA']['winConsoleImplementation'] == "legacy": from .winConsole import WinConsole as newCls elif windowClassName=="EXCEL7": from .excel import Excel7Window as newCls diff --git a/source/_UIAHandler.py b/source/_UIAHandler.py index a06512167cf..abb1b25a70e 100644 --- a/source/_UIAHandler.py +++ b/source/_UIAHandler.py @@ -346,7 +346,7 @@ def _isBadUIAWindowClassName(self, windowClass): "Given a windowClassName, returns True if this is a known problematic UIA implementation." # #7497: Windows 10 Fall Creators Update has an incomplete UIA implementation for console windows, therefore for now we should ignore it. # It does not implement caret/selection, and probably has no new text events. - if windowClass == "ConsoleWindowClass" and not config.conf['UIA']['consoleUIA']: + if windowClass == "ConsoleWindowClass" and config.conf['UIA']['winConsoleImplementation'] == "legacy": return True return windowClass in badUIAWindowClassNames diff --git a/source/config/configSpec.py b/source/config/configSpec.py index ba973765279..baac6e439a8 100644 --- a/source/config/configSpec.py +++ b/source/config/configSpec.py @@ -187,7 +187,7 @@ [UIA] enabled = boolean(default=true) useInMSWordWhenAvailable = boolean(default=false) - consoleUIA = boolean(default=false) + winConsoleImplementation= option("auto", "legacy", "UIA", default="legacy") [update] autoCheck = boolean(default=true) diff --git a/source/gui/settingsDialogs.py b/source/gui/settingsDialogs.py index a8f365cb228..063b69c1164 100644 --- a/source/gui/settingsDialogs.py +++ b/source/gui/settingsDialogs.py @@ -2053,9 +2053,10 @@ def __init__(self, parent): # Translators: This is the label for a checkbox in the # Advanced settings panel. label = _("Use UI Automation to access the Windows Console") + consoleUIADevMap = True if config.conf['UIA']['winConsoleImplementation'] == 'UIA' else False self.ConsoleUIACheckBox=UIAGroup.addItem(wx.CheckBox(self, label=label)) - self.ConsoleUIACheckBox.SetValue(config.conf["UIA"]["consoleUIA"]) - self.ConsoleUIACheckBox.defaultValue = self._getDefaultValue(["UIA", "consoleUIA"]) + self.ConsoleUIACheckBox.SetValue(consoleUIADevMap) + self.ConsoleUIACheckBox.defaultValue = self._getDefaultValue(["UIA", "winConsoleImplementation"]) # Translators: This is the label for a group of advanced options in the # Advanced settings panel @@ -2159,7 +2160,10 @@ def onSave(self): log.debug("Saving advanced config") config.conf["development"]["enableScratchpadDir"]=self.scratchpadCheckBox.IsChecked() config.conf["UIA"]["useInMSWordWhenAvailable"]=self.UIAInMSWordCheckBox.IsChecked() - config.conf["UIA"]["consoleUIA"]=self.ConsoleUIACheckBox.IsChecked() + if self.ConsoleUIACheckBox.IsChecked(): + config.conf['UIA']['winConsoleImplementation'] = "UIA" + else: + config.conf['UIA']['winConsoleImplementation'] = "legacy" config.conf["virtualBuffers"]["autoFocusFocusableElements"] = self.autoFocusFocusableElementsCheckBox.IsChecked() config.conf["editableText"]["caretMoveTimeoutMs"]=self.caretMoveTimeoutSpinControl.GetValue() for index,key in enumerate(self.logCategories): @@ -2233,7 +2237,7 @@ def onSave(self): self.enableControlsCheckBox.IsChecked() or self.advancedControls.haveConfigDefaultsBeenRestored() ): - self.advancedControls.onSave() + self.advancedControls.onSave() def onEnableControlsCheckBox(self, evt): @@ -2929,7 +2933,7 @@ def makeSettings(self, settingsSizer): # generally the advice on the wx documentation is: "In general, it is recommended to skip all non-command events # to allow the default handling to take place. The command events are, however, normally not skipped as usually # a single command such as a button click or menu item selection must only be processed by one handler." - def skipEventAndCall(handler): + def skipEventAndCall(handler): def wrapWithEventSkip(event): if event: event.Skip() From 91c8f829cff5b4be04ce807cb4c838d8d62c9bed Mon Sep 17 00:00:00 2001 From: Bill Dengler Date: Mon, 27 May 2019 08:36:15 -0400 Subject: [PATCH 20/24] Meeting actions. --- source/NVDAObjects/window/__init__.py | 2 +- source/_UIAHandler.py | 2 +- source/gui/settingsDialogs.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/source/NVDAObjects/window/__init__.py b/source/NVDAObjects/window/__init__.py index 8ab59c63451..7cde798fb53 100644 --- a/source/NVDAObjects/window/__init__.py +++ b/source/NVDAObjects/window/__init__.py @@ -121,7 +121,7 @@ def findOverlayClasses(self,clsList): from .scintilla import Scintilla as newCls elif windowClassName in ("AkelEditW", "AkelEditA"): from .akelEdit import AkelEdit as newCls - elif windowClassName=="ConsoleWindowClass" and config.conf['UIA']['winConsoleImplementation'] == "legacy": + elif windowClassName=="ConsoleWindowClass" and config.conf['UIA']['winConsoleImplementation'] != "UIA": from .winConsole import WinConsole as newCls elif windowClassName=="EXCEL7": from .excel import Excel7Window as newCls diff --git a/source/_UIAHandler.py b/source/_UIAHandler.py index abb1b25a70e..c2aebf534e8 100644 --- a/source/_UIAHandler.py +++ b/source/_UIAHandler.py @@ -346,7 +346,7 @@ def _isBadUIAWindowClassName(self, windowClass): "Given a windowClassName, returns True if this is a known problematic UIA implementation." # #7497: Windows 10 Fall Creators Update has an incomplete UIA implementation for console windows, therefore for now we should ignore it. # It does not implement caret/selection, and probably has no new text events. - if windowClass == "ConsoleWindowClass" and config.conf['UIA']['winConsoleImplementation'] == "legacy": + if windowClass == "ConsoleWindowClass" and config.conf['UIA']['winConsoleImplementation'] != "UIA": return True return windowClass in badUIAWindowClassNames diff --git a/source/gui/settingsDialogs.py b/source/gui/settingsDialogs.py index 063b69c1164..36b2286656a 100644 --- a/source/gui/settingsDialogs.py +++ b/source/gui/settingsDialogs.py @@ -2163,7 +2163,7 @@ def onSave(self): if self.ConsoleUIACheckBox.IsChecked(): config.conf['UIA']['winConsoleImplementation'] = "UIA" else: - config.conf['UIA']['winConsoleImplementation'] = "legacy" + config.conf['UIA']['winConsoleImplementation'] = "auto" config.conf["virtualBuffers"]["autoFocusFocusableElements"] = self.autoFocusFocusableElementsCheckBox.IsChecked() config.conf["editableText"]["caretMoveTimeoutMs"]=self.caretMoveTimeoutSpinControl.GetValue() for index,key in enumerate(self.logCategories): From 8a6be9e8cc8a449cee9036ca43846188a3a10edf Mon Sep 17 00:00:00 2001 From: Bill Dengler Date: Mon, 27 May 2019 08:44:15 -0400 Subject: [PATCH 21/24] Make auto the default. --- source/config/configSpec.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/config/configSpec.py b/source/config/configSpec.py index baac6e439a8..12c16356de3 100644 --- a/source/config/configSpec.py +++ b/source/config/configSpec.py @@ -187,7 +187,7 @@ [UIA] enabled = boolean(default=true) useInMSWordWhenAvailable = boolean(default=false) - winConsoleImplementation= option("auto", "legacy", "UIA", default="legacy") + winConsoleImplementation= option("auto", "legacy", "UIA", default="auto") [update] autoCheck = boolean(default=true) From 9add4fd3d907959c50d4316eaa99d43a505f6fa3 Mon Sep 17 00:00:00 2001 From: Bill Dengler Date: Mon, 27 May 2019 15:08:54 -0400 Subject: [PATCH 22/24] Use->force --- source/gui/settingsDialogs.py | 2 +- user_docs/en/userGuide.t2t | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/source/gui/settingsDialogs.py b/source/gui/settingsDialogs.py index 36b2286656a..caef54d3c59 100644 --- a/source/gui/settingsDialogs.py +++ b/source/gui/settingsDialogs.py @@ -2052,7 +2052,7 @@ def __init__(self, parent): # Translators: This is the label for a checkbox in the # Advanced settings panel. - label = _("Use UI Automation to access the Windows Console") + label = _("Force UI Automation in the Windows Console") consoleUIADevMap = True if config.conf['UIA']['winConsoleImplementation'] == 'UIA' else False self.ConsoleUIACheckBox=UIAGroup.addItem(wx.CheckBox(self, label=label)) self.ConsoleUIACheckBox.SetValue(consoleUIADevMap) diff --git a/user_docs/en/userGuide.t2t b/user_docs/en/userGuide.t2t index 32ccb4d5ad4..4fbbe0c0c5f 100644 --- a/user_docs/en/userGuide.t2t +++ b/user_docs/en/userGuide.t2t @@ -1670,7 +1670,7 @@ This includes in Microsoft Word itself, and also the Microsoft Outlook message v However, There may be some information which is either not exposed, or exposed incorrectly in some versions of Microsoft Office, which means this UI automation support cannot always be relied upon. We still do not recommend that the majority of users turn this on by default, though we do welcome users of Office 2016/365 to test this feature and provide feedback. -==== Use UI automation to access the Windows Console====[AdvancedSettingsConsoleUIA] +==== Force UI Automation in the Windows Console====[AdvancedSettingsConsoleUIA] When this option is enabled, NVDA will use a new, work in progress version of its support for Windows Console which takes advantage of [accessibility improvements made by Microsoft https://devblogs.microsoft.com/commandline/whats-new-in-windows-console-in-windows-10-fall-creators-update/]. This feature is highly experimental and is still incomplete, so its use is not yet recommended. However, once completed, it is anticipated that this new support will become the default, improving NVDA's performance and stability in Windows command consoles. ==== Automatically set system focus to focusable elements in Browse Mode ====[BrowseModeSettingsAutoFocusFocusableElements] From 0af9303d3202688ebcfd175f531a1cf1855dfc5a Mon Sep 17 00:00:00 2001 From: Michael Curran Date: Tue, 28 May 2019 07:24:06 +1000 Subject: [PATCH 23/24] Updated what's new. --- user_docs/en/changes.t2t | 2 ++ 1 file changed, 2 insertions(+) diff --git a/user_docs/en/changes.t2t b/user_docs/en/changes.t2t index 944dea371d7..5d08390813d 100644 --- a/user_docs/en/changes.t2t +++ b/user_docs/en/changes.t2t @@ -26,6 +26,7 @@ What's New in NVDA - Freedom Scientific braille displays are now supported by braille display auto detection. (#7727) - The name of the current virtual desktop on windows 10 May 2019update is now reported when switching virtual desktops. (#5641) - Added a command to show the replacement for the symbol under the review cursor. (#9286) +- Added an experimental option to the Advanced Settings panel that allows you to try out a new, work-in-progress rewrite of NVDA's Windows Console support using the Microsoft UI Automation API. (#9614) == Changes == @@ -65,6 +66,7 @@ What's New in NVDA - Updated comtypes package to 1.1.7. (#9440, #8522) - When using the report module info command, the order of information has changed to present the module first. (#7338) - Added an example to demonstrate using nvdaControllerClient.dll from C#. (#9600) +- Added a new isAtLeastWin10 function to the winVersion module which returns whether or not this copy of NVDA is running on at least the supplied release version of Windows 10 (such as 1809 or 1903) of Windows 10. (#9614) = 2019.1.1 = From 274f521cf794d488fbaa765315887fbc810f39a2 Mon Sep 17 00:00:00 2001 From: Michael Curran Date: Tue, 28 May 2019 07:28:28 +1000 Subject: [PATCH 24/24] Settings dialog: Ensure that the UIA in Windows Consoles option can be restored to default using the Advance Panel's restore to defaults button. --- source/gui/settingsDialogs.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/gui/settingsDialogs.py b/source/gui/settingsDialogs.py index caef54d3c59..768ea056e60 100644 --- a/source/gui/settingsDialogs.py +++ b/source/gui/settingsDialogs.py @@ -2142,6 +2142,7 @@ def haveConfigDefaultsBeenRestored(self): self._defaultsRestored and self.scratchpadCheckBox.IsChecked() == self.scratchpadCheckBox.defaultValue and self.UIAInMSWordCheckBox.IsChecked() == self.UIAInMSWordCheckBox.defaultValue and + self.ConsoleUIACheckBox.IsChecked() == (self.ConsoleUIACheckBox.defaultValue=='UIA') and self.autoFocusFocusableElementsCheckBox.IsChecked() == self.autoFocusFocusableElementsCheckBox.defaultValue and self.caretMoveTimeoutSpinControl.GetValue() == self.caretMoveTimeoutSpinControl.defaultValue and set(self.logCategoriesList.CheckedItems) == set(self.logCategoriesList.defaultCheckedItems) and @@ -2151,6 +2152,7 @@ def haveConfigDefaultsBeenRestored(self): def restoreToDefaults(self): self.scratchpadCheckBox.SetValue(self.scratchpadCheckBox.defaultValue) self.UIAInMSWordCheckBox.SetValue(self.UIAInMSWordCheckBox.defaultValue) + self.ConsoleUIACheckBox.SetValue(self.ConsoleUIACheckBox.defaultValue=='UIA') self.autoFocusFocusableElementsCheckBox.SetValue(self.autoFocusFocusableElementsCheckBox.defaultValue) self.caretMoveTimeoutSpinControl.SetValue(self.caretMoveTimeoutSpinControl.defaultValue) self.logCategoriesList.CheckedItems = self.logCategoriesList.defaultCheckedItems