From 6a3f7e360399357cdbee483edfc121ae834299bd Mon Sep 17 00:00:00 2001 From: Bill Dengler Date: Mon, 27 May 2019 21:16:02 -0400 Subject: [PATCH 1/4] Move legacy console code to IAccessible and only enable UIA when available. --- source/NVDAObjects/IAccessible/__init__.py | 3 +++ .../winConsoleLegacy.py} | 22 +++++++++---------- source/NVDAObjects/window/__init__.py | 4 +--- source/core.py | 8 +++---- source/gui/settingsDialogs.py | 2 +- ...eHandler.py => winConsoleHandlerLegacy.py} | 8 +++---- source/{wincon.py => winconLegacy.py} | 0 user_docs/en/userGuide.t2t | 2 +- 8 files changed, 25 insertions(+), 24 deletions(-) rename source/NVDAObjects/{window/winConsole.py => IAccessible/winConsoleLegacy.py} (74%) rename source/{winConsoleHandler.py => winConsoleHandlerLegacy.py} (95%) rename source/{wincon.py => winconLegacy.py} (100%) diff --git a/source/NVDAObjects/IAccessible/__init__.py b/source/NVDAObjects/IAccessible/__init__.py index 1242e1f9b17..d1f674e0557 100644 --- a/source/NVDAObjects/IAccessible/__init__.py +++ b/source/NVDAObjects/IAccessible/__init__.py @@ -528,6 +528,9 @@ def findOverlayClasses(self,clsList): elif windowClassName.startswith("Chrome_"): from . import chromium chromium.findExtraOverlayClasses(self, clsList) + elif windowClassName == "ConsoleWindowClass": + from .winConsoleLegacy import winConsoleLegacy + clsList.append(winConsoleLegacy) #Support for Windowless richEdit diff --git a/source/NVDAObjects/window/winConsole.py b/source/NVDAObjects/IAccessible/winConsoleLegacy.py similarity index 74% rename from source/NVDAObjects/window/winConsole.py rename to source/NVDAObjects/IAccessible/winConsoleLegacy.py index 65df9117c1e..4365a162a56 100644 --- a/source/NVDAObjects/window/winConsole.py +++ b/source/NVDAObjects/IAccessible/winConsoleLegacy.py @@ -1,23 +1,23 @@ -#NVDAObjects/WinConsole.py +#NVDAObjects/IAccessible/winConsoleLegacy.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) 2007-2012 NV Access Limited +#Copyright (C) 2007-2019 NV Access Limited, Bill Dengler -import winConsoleHandler -from . import Window +import winConsoleHandlerLegacy as winConsoleHandler +from . import IAccessible from ..behaviors import Terminal, EditableTextWithoutAutoSelectDetection import api import core -class WinConsole(Terminal, EditableTextWithoutAutoSelectDetection, Window): +class winConsoleLegacy(Terminal, EditableTextWithoutAutoSelectDetection, IAccessible): STABILIZE_DELAY = 0.03 def _get_TextInfo(self): consoleObject=winConsoleHandler.consoleObject if consoleObject and self.windowHandle == consoleObject.windowHandle: - return winConsoleHandler.WinConsoleTextInfo - return super(WinConsole,self).TextInfo + return winConsoleHandler.legacyConsoleTextInfo + return super(winConsoleLegacy,self).TextInfo def event_becomeNavigatorObject(self, isFocus=False): if winConsoleHandler.consoleObject is not self: @@ -28,17 +28,17 @@ def event_becomeNavigatorObject(self, isFocus=False): # The user is returning to the focus object with object navigation. # The focused console should always be monitored if possible. self.startMonitoring() - super(WinConsole,self).event_becomeNavigatorObject(isFocus=isFocus) + super(winConsoleLegacy,self).event_becomeNavigatorObject(isFocus=isFocus) def event_gainFocus(self): if winConsoleHandler.consoleObject is not self: if winConsoleHandler.consoleObject: winConsoleHandler.disconnectConsole() winConsoleHandler.connectConsole(self) - super(WinConsole, self).event_gainFocus() + super(winConsoleLegacy, self).event_gainFocus() def event_loseFocus(self): - super(WinConsole, self).event_loseFocus() + super(winConsoleLegacy, self).event_loseFocus() if winConsoleHandler.consoleObject is self: winConsoleHandler.disconnectConsole() @@ -49,7 +49,7 @@ def _getTextLines(self): return winConsoleHandler.getConsoleVisibleLines() def script_caret_backspaceCharacter(self, gesture): - super(WinConsole, self).script_caret_backspaceCharacter(gesture) + super(winConsoleLegacy, self).script_caret_backspaceCharacter(gesture) # #2586: We use console update events for typed characters, # so the typedCharacter event is never fired for the backspace key. # Call it here so that speak typed words works as expected. diff --git a/source/NVDAObjects/window/__init__.py b/source/NVDAObjects/window/__init__.py index 78858edcf8e..6f7ee3c6db9 100644 --- a/source/NVDAObjects/window/__init__.py +++ b/source/NVDAObjects/window/__init__.py @@ -1,6 +1,6 @@ #NVDAObjects/window.py #A part of NonVisual Desktop Access (NVDA) -#Copyright (C) 2006-2019 NV Access Limited, Babbage B.V. +#Copyright (C) 2006-2019 NV Access Limited, Babbage B.V., Bill Dengler #This file is covered by the GNU General Public License. #See the file COPYING for more details. @@ -124,8 +124,6 @@ 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'] != "UIA": - from .winConsole import WinConsole as newCls elif windowClassName=="EXCEL7": from .excel import Excel7Window as newCls if newCls: diff --git a/source/core.py b/source/core.py index 228df2e8f5f..c2832cd8710 100644 --- a/source/core.py +++ b/source/core.py @@ -416,9 +416,9 @@ def handlePowerStatusChange(self): log.warning("Java Access Bridge not available") except: log.error("Error initializing Java Access Bridge support", exc_info=True) - import winConsoleHandler - log.debug("Initializing winConsole support") - winConsoleHandler.initialize() + import winConsoleHandlerLegacy + log.debug("Initializing legacy winConsole support") + winConsoleHandlerLegacy.initialize() import UIAHandler log.debug("Initializing UIA support") try: @@ -542,7 +542,7 @@ def run(self): _terminate(treeInterceptorHandler) _terminate(IAccessibleHandler, name="IAccessible support") _terminate(UIAHandler, name="UIA support") - _terminate(winConsoleHandler, name="winConsole support") + _terminate(winConsoleHandlerLegacy, name="Legacy winConsole support") _terminate(JABHandler, name="Java Access Bridge support") _terminate(appModuleHandler, name="app module handler") _terminate(NVDAHelper) diff --git a/source/gui/settingsDialogs.py b/source/gui/settingsDialogs.py index 768ea056e60..42d4ad2ce5c 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 = _("Force UI Automation in the Windows Console") + label = _("Use UI Automation to access the Windows Console when available") 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/source/winConsoleHandler.py b/source/winConsoleHandlerLegacy.py similarity index 95% rename from source/winConsoleHandler.py rename to source/winConsoleHandlerLegacy.py index 62d7e74a2d8..91c4eca40dd 100755 --- a/source/winConsoleHandler.py +++ b/source/winConsoleHandlerLegacy.py @@ -1,13 +1,13 @@ -#winConsoleHandler.py +#winConsoleHandlerLegacy.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) 2009-2018 NV Access Limited, Babbage B.V. +#Copyright (C) 2009-2019 NV Access Limited, Babbage B.V., Bill Dengler import gui import winUser import winKernel -import wincon +import winconLegacy as wincon from colors import RGB import eventHandler from logHandler import log @@ -150,7 +150,7 @@ def terminate(): if consoleObject: disconnectConsole() -class WinConsoleTextInfo(textInfos.offsets.OffsetsTextInfo): +class legacyConsoleTextInfo(textInfos.offsets.OffsetsTextInfo): _cache_consoleScreenBufferInfo=True def _get_consoleScreenBufferInfo(self): diff --git a/source/wincon.py b/source/winconLegacy.py similarity index 100% rename from source/wincon.py rename to source/winconLegacy.py diff --git a/user_docs/en/userGuide.t2t b/user_docs/en/userGuide.t2t index c49736ed6dd..1deac4c5e4f 100644 --- a/user_docs/en/userGuide.t2t +++ b/user_docs/en/userGuide.t2t @@ -1671,7 +1671,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. -==== Force UI Automation in the Windows Console====[AdvancedSettingsConsoleUIA] +==== Use UI Automation to access the Windows Console when available ====[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 0cf311e9301f04202e6f1ef67ddbf9a499f1cc8c Mon Sep 17 00:00:00 2001 From: Bill Dengler Date: Fri, 31 May 2019 10:14:30 -0400 Subject: [PATCH 2/4] Add winConsole compatibility module. --- source/NVDAObjects/window/winConsole.py | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 source/NVDAObjects/window/winConsole.py diff --git a/source/NVDAObjects/window/winConsole.py b/source/NVDAObjects/window/winConsole.py new file mode 100644 index 00000000000..b4b696084cd --- /dev/null +++ b/source/NVDAObjects/window/winConsole.py @@ -0,0 +1,11 @@ +# NVDAObjects/window/winConsole.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 warnings +from ..IAccessible.winConsoleLegacy import winConsoleLegacy as WinConsole + +warnings.warn("NVDAObjects.window.winConsole is deprecated. Use NVDAObjects.IAccessible.winConsoleLegacy or NVDAObjects.UIA.winConsoleUIA instead", + DeprecationWarning, stacklevel=3) \ No newline at end of file From c47f1657e3922da8662aa71248964c0cde494f27 Mon Sep 17 00:00:00 2001 From: Bill Dengler Date: Mon, 3 Jun 2019 12:15:17 -0400 Subject: [PATCH 3/4] Address review actions. --- source/NVDAObjects/IAccessible/__init__.py | 16 ++++++---------- .../NVDAObjects/IAccessible/winConsoleLegacy.py | 14 +++++++------- source/NVDAObjects/window/winConsole.py | 6 +++--- source/winConsoleHandler.py | 11 +++++++++++ source/wincon.py | 11 +++++++++++ 5 files changed, 38 insertions(+), 20 deletions(-) create mode 100644 source/winConsoleHandler.py create mode 100644 source/wincon.py diff --git a/source/NVDAObjects/IAccessible/__init__.py b/source/NVDAObjects/IAccessible/__init__.py index d1f674e0557..96297f5d3e0 100644 --- a/source/NVDAObjects/IAccessible/__init__.py +++ b/source/NVDAObjects/IAccessible/__init__.py @@ -10,7 +10,6 @@ import os import re import itertools -import importlib from comInterfaces.tom import ITextDocument import tones import languageHandler @@ -439,8 +438,7 @@ def findOverlayClasses(self,clsList): if classString and classString.find('.')>0: modString,classString=os.path.splitext(classString) classString=classString[1:] - # #8712: Python 3 wants a dot (.) when loading a module from the same folder via relative imports, and this is done via package argument. - mod=importlib.import_module("NVDAObjects.IAccessible.%s"%modString, package="NVDAObjects.IAccessible") + mod=__import__(modString,globals(),locals(),[]) newCls=getattr(mod,classString) elif classString: newCls=globals()[classString] @@ -451,21 +449,21 @@ def findOverlayClasses(self,clsList): if windowClassName=="Frame Notification Bar" and role==oleacc.ROLE_SYSTEM_CLIENT: clsList.append(IEFrameNotificationBar) elif self.event_objectID==winUser.OBJID_CLIENT and self.event_childID==0 and windowClassName=="_WwG": - from .winword import WordDocument + from winword import WordDocument clsList.append(WordDocument) elif self.event_objectID==winUser.OBJID_CLIENT and self.event_childID==0 and windowClassName in ("_WwN","_WwO"): if self.windowControlID==18: - from .winword import SpellCheckErrorField + from winword import SpellCheckErrorField clsList.append(SpellCheckErrorField) else: - from .winword import WordDocument_WwN + from winword import WordDocument_WwN clsList.append(WordDocument_WwN) elif windowClassName=="DirectUIHWND" and role==oleacc.ROLE_SYSTEM_TOOLBAR: parentWindow=winUser.getAncestor(self.windowHandle,winUser.GA_PARENT) if parentWindow and winUser.getClassName(parentWindow)=="Frame Notification Bar": clsList.append(IENotificationBar) if windowClassName.lower().startswith('mscandui'): - from . import mscandui + import mscandui mscandui.findExtraOverlayClasses(self,clsList) elif windowClassName=="GeckoPluginWindow" and self.event_objectID==0 and self.IAccessibleChildID==0: from mozilla import GeckoPluginWindowRoot @@ -528,9 +526,6 @@ def findOverlayClasses(self,clsList): elif windowClassName.startswith("Chrome_"): from . import chromium chromium.findExtraOverlayClasses(self, clsList) - elif windowClassName == "ConsoleWindowClass": - from .winConsoleLegacy import winConsoleLegacy - clsList.append(winConsoleLegacy) #Support for Windowless richEdit @@ -2012,4 +2007,5 @@ def event_alert(self): ("NUIDialog",oleacc.ROLE_SYSTEM_CLIENT):"NUIDialogClient", ("_WwB",oleacc.ROLE_SYSTEM_CLIENT):"winword.ProtectedDocumentPane", ("MsoCommandBar",oleacc.ROLE_SYSTEM_LISTITEM):"msOffice.CommandBarListItem", + ("ConsoleWindowClass",oleacc.ROLE_SYSTEM_CLIENT):"winConsoleLegacy.WinConsoleLegacy", } diff --git a/source/NVDAObjects/IAccessible/winConsoleLegacy.py b/source/NVDAObjects/IAccessible/winConsoleLegacy.py index 4365a162a56..e2b471d1dbd 100644 --- a/source/NVDAObjects/IAccessible/winConsoleLegacy.py +++ b/source/NVDAObjects/IAccessible/winConsoleLegacy.py @@ -1,4 +1,4 @@ -#NVDAObjects/IAccessible/winConsoleLegacy.py +#NVDAObjects/IAccessible/WinConsoleLegacy.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. @@ -10,14 +10,14 @@ import api import core -class winConsoleLegacy(Terminal, EditableTextWithoutAutoSelectDetection, IAccessible): +class WinConsoleLegacy(Terminal, EditableTextWithoutAutoSelectDetection, IAccessible): STABILIZE_DELAY = 0.03 def _get_TextInfo(self): consoleObject=winConsoleHandler.consoleObject if consoleObject and self.windowHandle == consoleObject.windowHandle: return winConsoleHandler.legacyConsoleTextInfo - return super(winConsoleLegacy,self).TextInfo + return super(WinConsoleLegacy,self).TextInfo def event_becomeNavigatorObject(self, isFocus=False): if winConsoleHandler.consoleObject is not self: @@ -28,17 +28,17 @@ def event_becomeNavigatorObject(self, isFocus=False): # The user is returning to the focus object with object navigation. # The focused console should always be monitored if possible. self.startMonitoring() - super(winConsoleLegacy,self).event_becomeNavigatorObject(isFocus=isFocus) + super(WinConsoleLegacy,self).event_becomeNavigatorObject(isFocus=isFocus) def event_gainFocus(self): if winConsoleHandler.consoleObject is not self: if winConsoleHandler.consoleObject: winConsoleHandler.disconnectConsole() winConsoleHandler.connectConsole(self) - super(winConsoleLegacy, self).event_gainFocus() + super(WinConsoleLegacy, self).event_gainFocus() def event_loseFocus(self): - super(winConsoleLegacy, self).event_loseFocus() + super(WinConsoleLegacy, self).event_loseFocus() if winConsoleHandler.consoleObject is self: winConsoleHandler.disconnectConsole() @@ -49,7 +49,7 @@ def _getTextLines(self): return winConsoleHandler.getConsoleVisibleLines() def script_caret_backspaceCharacter(self, gesture): - super(winConsoleLegacy, self).script_caret_backspaceCharacter(gesture) + super(WinConsoleLegacy, self).script_caret_backspaceCharacter(gesture) # #2586: We use console update events for typed characters, # so the typedCharacter event is never fired for the backspace key. # Call it here so that speak typed words works as expected. diff --git a/source/NVDAObjects/window/winConsole.py b/source/NVDAObjects/window/winConsole.py index b4b696084cd..00ea7cdf3a5 100644 --- a/source/NVDAObjects/window/winConsole.py +++ b/source/NVDAObjects/window/winConsole.py @@ -5,7 +5,7 @@ # Copyright (C) 2019 Bill Dengler import warnings -from ..IAccessible.winConsoleLegacy import winConsoleLegacy as WinConsole +from ..IAccessible.winConsoleLegacy import WinConsoleLegacy as WinConsole -warnings.warn("NVDAObjects.window.winConsole is deprecated. Use NVDAObjects.IAccessible.winConsoleLegacy or NVDAObjects.UIA.winConsoleUIA instead", - DeprecationWarning, stacklevel=3) \ No newline at end of file +warnings.warn("NVDAObjects.window.winConsole is deprecated. Use NVDAObjects.IAccessible.WinConsoleLegacy or NVDAObjects.UIA.winConsoleUIA instead", + DeprecationWarning, stacklevel=3) diff --git a/source/winConsoleHandler.py b/source/winConsoleHandler.py new file mode 100644 index 00000000000..32fbad801dc --- /dev/null +++ b/source/winConsoleHandler.py @@ -0,0 +1,11 @@ +# NVDAObjects/winConsoleHandler.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 warnings +from winConsoleHandlerLegacy import * + +warnings.warn("winConsoleHandler is deprecated. Use winConsoleHandlerLegacy instead, and consider switching to the UIA console implementation.", + DeprecationWarning, stacklevel=3) diff --git a/source/wincon.py b/source/wincon.py new file mode 100644 index 00000000000..7dc32919535 --- /dev/null +++ b/source/wincon.py @@ -0,0 +1,11 @@ +# NVDAObjects/wincon.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 warnings +from winconLegacy import * + +warnings.warn("wincon is deprecated. Use winconLegacy instead, and consider switching to the UIA console implementation.", + DeprecationWarning, stacklevel=3) From 617f176fda59424a1939feda93c0c2bff5a1ae92 Mon Sep 17 00:00:00 2001 From: Bill Dengler Date: Wed, 5 Jun 2019 02:39:32 -0400 Subject: [PATCH 4/4] Revert legacy console rename. --- source/NVDAObjects/IAccessible/__init__.py | 2 +- source/NVDAObjects/IAccessible/winConsole.py | 12 + .../IAccessible/winConsoleLegacy.py | 71 ----- source/NVDAObjects/window/winConsole.py | 87 ++++- source/core.py | 6 +- source/winConsoleHandler.py | 298 +++++++++++++++++- source/winConsoleHandlerLegacy.py | 282 ----------------- source/wincon.py | 107 ++++++- source/winconLegacy.py | 91 ------ 9 files changed, 475 insertions(+), 481 deletions(-) create mode 100644 source/NVDAObjects/IAccessible/winConsole.py delete mode 100644 source/NVDAObjects/IAccessible/winConsoleLegacy.py mode change 100644 => 100755 source/winConsoleHandler.py delete mode 100755 source/winConsoleHandlerLegacy.py mode change 100644 => 100755 source/wincon.py delete mode 100755 source/winconLegacy.py diff --git a/source/NVDAObjects/IAccessible/__init__.py b/source/NVDAObjects/IAccessible/__init__.py index 96297f5d3e0..401df9a942c 100644 --- a/source/NVDAObjects/IAccessible/__init__.py +++ b/source/NVDAObjects/IAccessible/__init__.py @@ -2007,5 +2007,5 @@ def event_alert(self): ("NUIDialog",oleacc.ROLE_SYSTEM_CLIENT):"NUIDialogClient", ("_WwB",oleacc.ROLE_SYSTEM_CLIENT):"winword.ProtectedDocumentPane", ("MsoCommandBar",oleacc.ROLE_SYSTEM_LISTITEM):"msOffice.CommandBarListItem", - ("ConsoleWindowClass",oleacc.ROLE_SYSTEM_CLIENT):"winConsoleLegacy.WinConsoleLegacy", + ("ConsoleWindowClass",oleacc.ROLE_SYSTEM_CLIENT):"winConsole.WinConsole", } diff --git a/source/NVDAObjects/IAccessible/winConsole.py b/source/NVDAObjects/IAccessible/winConsole.py new file mode 100644 index 00000000000..59b33186edd --- /dev/null +++ b/source/NVDAObjects/IAccessible/winConsole.py @@ -0,0 +1,12 @@ +#NVDAObjects/IAccessible/WinConsole.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) 2007-2019 NV Access Limited, Bill Dengler + +from . import IAccessible +from ..window.winConsole import WinConsole + +class WinConsole(WinConsole, IAccessible): + "The legacy console implementation for situations where UIA isn't supported." + pass \ No newline at end of file diff --git a/source/NVDAObjects/IAccessible/winConsoleLegacy.py b/source/NVDAObjects/IAccessible/winConsoleLegacy.py deleted file mode 100644 index e2b471d1dbd..00000000000 --- a/source/NVDAObjects/IAccessible/winConsoleLegacy.py +++ /dev/null @@ -1,71 +0,0 @@ -#NVDAObjects/IAccessible/WinConsoleLegacy.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) 2007-2019 NV Access Limited, Bill Dengler - -import winConsoleHandlerLegacy as winConsoleHandler -from . import IAccessible -from ..behaviors import Terminal, EditableTextWithoutAutoSelectDetection -import api -import core - -class WinConsoleLegacy(Terminal, EditableTextWithoutAutoSelectDetection, IAccessible): - STABILIZE_DELAY = 0.03 - - def _get_TextInfo(self): - consoleObject=winConsoleHandler.consoleObject - if consoleObject and self.windowHandle == consoleObject.windowHandle: - return winConsoleHandler.legacyConsoleTextInfo - return super(WinConsoleLegacy,self).TextInfo - - def event_becomeNavigatorObject(self, isFocus=False): - if winConsoleHandler.consoleObject is not self: - if winConsoleHandler.consoleObject: - winConsoleHandler.disconnectConsole() - winConsoleHandler.connectConsole(self) - if self == api.getFocusObject(): - # The user is returning to the focus object with object navigation. - # The focused console should always be monitored if possible. - self.startMonitoring() - super(WinConsoleLegacy,self).event_becomeNavigatorObject(isFocus=isFocus) - - def event_gainFocus(self): - if winConsoleHandler.consoleObject is not self: - if winConsoleHandler.consoleObject: - winConsoleHandler.disconnectConsole() - winConsoleHandler.connectConsole(self) - super(WinConsoleLegacy, self).event_gainFocus() - - def event_loseFocus(self): - super(WinConsoleLegacy, self).event_loseFocus() - if winConsoleHandler.consoleObject is self: - winConsoleHandler.disconnectConsole() - - def event_nameChange(self): - pass - - def _getTextLines(self): - return winConsoleHandler.getConsoleVisibleLines() - - def script_caret_backspaceCharacter(self, gesture): - super(WinConsoleLegacy, self).script_caret_backspaceCharacter(gesture) - # #2586: We use console update events for typed characters, - # so the typedCharacter event is never fired for the backspace key. - # Call it here so that speak typed words works as expected. - self.event_typedCharacter(u"\b") - - def script_close(self,gesture): - # #5343: New consoles in Windows 10 close with alt+f4 and take any processes attached with it (including NVDA). - # Therefore detach from the console temporarily while sending the gesture. - winConsoleHandler.disconnectConsole() - gesture.send() - def reconnect(): - if api.getFocusObject()==self: - winConsoleHandler.connectConsole(self) - self.startMonitoring() - core.callLater(200,reconnect) - - __gestures={ - "kb:alt+f4":"close", - } diff --git a/source/NVDAObjects/window/winConsole.py b/source/NVDAObjects/window/winConsole.py index 00ea7cdf3a5..ec3923e5fcf 100644 --- a/source/NVDAObjects/window/winConsole.py +++ b/source/NVDAObjects/window/winConsole.py @@ -1,11 +1,76 @@ -# NVDAObjects/window/winConsole.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 warnings -from ..IAccessible.winConsoleLegacy import WinConsoleLegacy as WinConsole - -warnings.warn("NVDAObjects.window.winConsole is deprecated. Use NVDAObjects.IAccessible.WinConsoleLegacy or NVDAObjects.UIA.winConsoleUIA instead", - DeprecationWarning, stacklevel=3) +#NVDAObjects/WinConsole.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) 2007-2012 NV Access Limited + +import winConsoleHandler +from . import Window +from ..behaviors import Terminal, EditableTextWithoutAutoSelectDetection +import api +import core + +class WinConsole(Terminal, EditableTextWithoutAutoSelectDetection, Window): + """ + NVDA's legacy Windows Console support. + This is used in situations where UIA isn't available. + Please consider using NVDAObjects.UIA.winConsoleUIA instead. + """ + STABILIZE_DELAY = 0.03 + + def _get_TextInfo(self): + consoleObject=winConsoleHandler.consoleObject + if consoleObject and self.windowHandle == consoleObject.windowHandle: + return winConsoleHandler.WinConsoleTextInfo + return super(WinConsole,self).TextInfo + + def event_becomeNavigatorObject(self, isFocus=False): + if winConsoleHandler.consoleObject is not self: + if winConsoleHandler.consoleObject: + winConsoleHandler.disconnectConsole() + winConsoleHandler.connectConsole(self) + if self == api.getFocusObject(): + # The user is returning to the focus object with object navigation. + # The focused console should always be monitored if possible. + self.startMonitoring() + super(WinConsole,self).event_becomeNavigatorObject(isFocus=isFocus) + + def event_gainFocus(self): + if winConsoleHandler.consoleObject is not self: + if winConsoleHandler.consoleObject: + winConsoleHandler.disconnectConsole() + winConsoleHandler.connectConsole(self) + super(WinConsole, self).event_gainFocus() + + def event_loseFocus(self): + super(WinConsole, self).event_loseFocus() + if winConsoleHandler.consoleObject is self: + winConsoleHandler.disconnectConsole() + + def event_nameChange(self): + pass + + def _getTextLines(self): + return winConsoleHandler.getConsoleVisibleLines() + + def script_caret_backspaceCharacter(self, gesture): + super(WinConsole, self).script_caret_backspaceCharacter(gesture) + # #2586: We use console update events for typed characters, + # so the typedCharacter event is never fired for the backspace key. + # Call it here so that speak typed words works as expected. + self.event_typedCharacter(u"\b") + + def script_close(self,gesture): + # #5343: New consoles in Windows 10 close with alt+f4 and take any processes attached with it (including NVDA). + # Therefore detach from the console temporarily while sending the gesture. + winConsoleHandler.disconnectConsole() + gesture.send() + def reconnect(): + if api.getFocusObject()==self: + winConsoleHandler.connectConsole(self) + self.startMonitoring() + core.callLater(200,reconnect) + + __gestures={ + "kb:alt+f4":"close", + } diff --git a/source/core.py b/source/core.py index c2832cd8710..93dcb7ce22d 100644 --- a/source/core.py +++ b/source/core.py @@ -416,9 +416,9 @@ def handlePowerStatusChange(self): log.warning("Java Access Bridge not available") except: log.error("Error initializing Java Access Bridge support", exc_info=True) - import winConsoleHandlerLegacy + import winConsoleHandler log.debug("Initializing legacy winConsole support") - winConsoleHandlerLegacy.initialize() + winConsoleHandler.initialize() import UIAHandler log.debug("Initializing UIA support") try: @@ -542,7 +542,7 @@ def run(self): _terminate(treeInterceptorHandler) _terminate(IAccessibleHandler, name="IAccessible support") _terminate(UIAHandler, name="UIA support") - _terminate(winConsoleHandlerLegacy, name="Legacy winConsole support") + _terminate(winConsoleHandler, name="Legacy winConsole support") _terminate(JABHandler, name="Java Access Bridge support") _terminate(appModuleHandler, name="app module handler") _terminate(NVDAHelper) diff --git a/source/winConsoleHandler.py b/source/winConsoleHandler.py old mode 100644 new mode 100755 index 32fbad801dc..2a583b64199 --- a/source/winConsoleHandler.py +++ b/source/winConsoleHandler.py @@ -1,11 +1,287 @@ -# NVDAObjects/winConsoleHandler.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 warnings -from winConsoleHandlerLegacy import * - -warnings.warn("winConsoleHandler is deprecated. Use winConsoleHandlerLegacy instead, and consider switching to the UIA console implementation.", - DeprecationWarning, stacklevel=3) +#winConsoleHandler.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) 2009-2018 NV Access Limited, Babbage B.V. + +import gui +import winUser +import winKernel +import wincon +from colors import RGB +import eventHandler +from logHandler import log +import speech +import textInfos +import api +import config + +""" +Handler for NVDA's legacy Windows Console support, +used in situations where UIA isn't available. +""" + +#: How often to check whether the console is dead (in ms). +CHECK_DEAD_INTERVAL = 100 + +consoleObject=None #:The console window that is currently in the foreground. +consoleWinEventHookHandles=[] #:a list of currently registered console win events. +consoleOutputHandle=None +checkDeadTimer=None + +CONSOLE_COLORS_TO_RGB=( #http://en.wikipedia.org/wiki/Color_Graphics_Adapter + RGB(0x00,0x00,0x00), #black + RGB(0x00,0x00,0xAA), #blue + RGB(0x00,0xAA,0x00), #green + RGB(0x00,0xAA,0xAA), #cyan + RGB(0xAA,0x00,0x00), #red + RGB(0xAA,0x00,0xAA), #magenta + RGB(0xAA,0x55, 0x00), #brown + RGB(0xAA,0xAA,0xAA), #white + RGB(0x55,0x55,0x55), #gray + RGB(0x55,0x55,0xFF), #light blue + RGB(0x55,0xFF,0x55), #light green + RGB(0x55,0xFF,0xFF), #light cyan + RGB(0xFF,0x55,0x55), #light red + RGB(0xFF,0x55,0xFF), #light magenta + RGB(0xFF,0xFF,0x55), #yellow + RGB(0xFF,0xFF,0xFF), #white (high intensity) +) + +COMMON_LVB_UNDERSCORE=0x8000 + + + +@wincon.PHANDLER_ROUTINE +def _consoleCtrlHandler(event): + if event in (wincon.CTRL_C_EVENT,wincon.CTRL_BREAK_EVENT): + return True + return False + +def connectConsole(obj): + global consoleObject, consoleOutputHandle, checkDeadTimer + #Get the process ID of the console this NVDAObject is fore + processID,threadID=winUser.getWindowThreadProcessID(obj.windowHandle) + #Attach NVDA to this console so we can access its text etc + try: + wincon.AttachConsole(processID) + except WindowsError as e: + log.debugWarning("Could not attach console: %r"%e) + return False + wincon.SetConsoleCtrlHandler(_consoleCtrlHandler,True) + consoleOutputHandle=winKernel.CreateFile(u"CONOUT$",winKernel.GENERIC_READ|winKernel.GENERIC_WRITE,winKernel.FILE_SHARE_READ|winKernel.FILE_SHARE_WRITE,None,winKernel.OPEN_EXISTING,0,None) + #Register this callback with all the win events we need, storing the given handles for removal later + for eventID in (winUser.EVENT_CONSOLE_CARET,winUser.EVENT_CONSOLE_UPDATE_REGION,winUser.EVENT_CONSOLE_UPDATE_SIMPLE,winUser.EVENT_CONSOLE_UPDATE_SCROLL,winUser.EVENT_CONSOLE_LAYOUT): + handle=winUser.setWinEventHook(eventID,eventID,0,consoleWinEventHook,0,0,0) + if not handle: + raise OSError("could not register eventID %s"%eventID) + consoleWinEventHookHandles.append(handle) + consoleObject=obj + checkDeadTimer=gui.NonReEntrantTimer(_checkDead) + checkDeadTimer.Start(CHECK_DEAD_INTERVAL) + return True + +def disconnectConsole(): + global consoleObject, consoleOutputHandle, consoleWinEventHookHandles, checkDeadTimer + if not consoleObject: + log.debugWarning("console was not connected") + return False + checkDeadTimer.Stop() + checkDeadTimer=None + #Unregister any win events we are using + for handle in consoleWinEventHookHandles: + winUser.unhookWinEvent(handle) + consoleEventHookHandles=[] + consoleObject.stopMonitoring() + winKernel.closeHandle(consoleOutputHandle) + consoleOutputHandle=None + consoleObject=None + try: + wincon.SetConsoleCtrlHandler(_consoleCtrlHandler,False) + except WindowsError: + pass + #Try freeing NVDA from this console + try: + wincon.FreeConsole() + except WindowsError: + pass + return True + +def isConsoleDead(): + # Every console should have at least one process associated with it. + # This console should have two if NVDA is also connected. + # If there is only one, it must be NVDA alone, so it is dead. + processList=wincon.GetConsoleProcessList(2) + return len(processList) < 2 + +def _checkDead(): + try: + if isConsoleDead(): + # We must disconnect NVDA from this console so it can close. + disconnectConsole() + except: + log.exception() + +def getConsoleVisibleLines(): + consoleScreenBufferInfo=wincon.GetConsoleScreenBufferInfo(consoleOutputHandle) + topLine=consoleScreenBufferInfo.srWindow.Top + lineCount=(consoleScreenBufferInfo.srWindow.Bottom-topLine)+1 + lineLength=consoleScreenBufferInfo.dwSize.x + text=wincon.ReadConsoleOutputCharacter(consoleOutputHandle,lineCount*lineLength,0,topLine) + newLines=[text[x:x+lineLength] for x in xrange(0,len(text),lineLength)] + return newLines + +@winUser.WINEVENTPROC +def consoleWinEventHook(handle,eventID,window,objectID,childID,threadID,timestamp): + #We don't want to do anything with the event if the event is not for the window this console is in + if window!=consoleObject.windowHandle: + return + if eventID==winUser.EVENT_CONSOLE_CARET and not eventHandler.isPendingEvents("caret",consoleObject): + eventHandler.queueEvent("caret",consoleObject) + # It is safe to call this event from this callback. + # This avoids an extra core cycle. + consoleObject.event_textChange() + if eventID==winUser.EVENT_CONSOLE_UPDATE_SIMPLE: + x=winUser.GET_X_LPARAM(objectID) + y=winUser.GET_Y_LPARAM(objectID) + consoleScreenBufferInfo=wincon.GetConsoleScreenBufferInfo(consoleOutputHandle) + if x0: #offsets span multiple lines + rect.Left=0 + rect.Right=self.consoleScreenBufferInfo.dwSize.x-1 + length=self.consoleScreenBufferInfo.dwSize.x*(bottom-top+1) + else: + length=self._endOffset-self._startOffset + buf=wincon.ReadConsoleOutput(consoleOutputHandle, length, rect) + if bottom-top>0: + buf=buf[left:len(buf)-(self.consoleScreenBufferInfo.dwSize.x-right)+1] + lastAttr=None + lastText=[] + boundEnd=self._startOffset + for i,c in enumerate(buf): + if self._startOffset+i==boundEnd: + field,(boundStart,boundEnd)=self._getFormatFieldAndOffsets(boundEnd,formatConfig) + if lastText: + commands.append("".join(lastText)) + lastText=[] + commands.append(textInfos.FieldCommand("formatChange",field)) + if not c.Attributes==lastAttr: + formatField=textInfos.FormatField() + if formatConfig['reportColor']: + formatField["color"]=CONSOLE_COLORS_TO_RGB[c.Attributes&0x0f] + formatField["background-color"]=CONSOLE_COLORS_TO_RGB[(c.Attributes>>4)&0x0f] + if formatConfig['reportFontAttributes'] and c.Attributes&COMMON_LVB_UNDERSCORE: + formatField['underline']=True + if formatField: + if lastText: + commands.append("".join(lastText)) + lastText=[] + command=textInfos.FieldCommand("formatChange", formatField) + commands.append(command) + lastAttr=c.Attributes + lastText.append(c.Char) + commands.append("".join(lastText)) + return commands + + def _getTextRange(self,start,end): + startX,startY=self._consoleCoordFromOffset(start) + return wincon.ReadConsoleOutputCharacter(consoleOutputHandle,end-start,startX,startY) + + def _getLineOffsets(self,offset): + consoleScreenBufferInfo=self.consoleScreenBufferInfo + x,y=self._consoleCoordFromOffset(offset) + x=0 + start=self._offsetFromConsoleCoord(x,y) + end=start+consoleScreenBufferInfo.dwSize.x + return start,end + + def _getLineNumFromOffset(self,offset): + consoleScreenBufferInfo=self.consoleScreenBufferInfo + x,y=self._consoleCoordFromOffset(offset) + return y-consoleScreenBufferInfo.srWindow.Top + + def _getStoryLength(self): + consoleScreenBufferInfo=self.consoleScreenBufferInfo + return consoleScreenBufferInfo.dwSize.x*((consoleScreenBufferInfo.srWindow.Bottom+1)-consoleScreenBufferInfo.srWindow.Top) + + def _get_clipboardText(self): + return "\r\n".join(block.rstrip() for block in self.getTextInChunks(textInfos.UNIT_LINE)) diff --git a/source/winConsoleHandlerLegacy.py b/source/winConsoleHandlerLegacy.py deleted file mode 100755 index 91c4eca40dd..00000000000 --- a/source/winConsoleHandlerLegacy.py +++ /dev/null @@ -1,282 +0,0 @@ -#winConsoleHandlerLegacy.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) 2009-2019 NV Access Limited, Babbage B.V., Bill Dengler - -import gui -import winUser -import winKernel -import winconLegacy as wincon -from colors import RGB -import eventHandler -from logHandler import log -import speech -import textInfos -import api -import config - -#: How often to check whether the console is dead (in ms). -CHECK_DEAD_INTERVAL = 100 - -consoleObject=None #:The console window that is currently in the foreground. -consoleWinEventHookHandles=[] #:a list of currently registered console win events. -consoleOutputHandle=None -checkDeadTimer=None - -CONSOLE_COLORS_TO_RGB=( #http://en.wikipedia.org/wiki/Color_Graphics_Adapter - RGB(0x00,0x00,0x00), #black - RGB(0x00,0x00,0xAA), #blue - RGB(0x00,0xAA,0x00), #green - RGB(0x00,0xAA,0xAA), #cyan - RGB(0xAA,0x00,0x00), #red - RGB(0xAA,0x00,0xAA), #magenta - RGB(0xAA,0x55, 0x00), #brown - RGB(0xAA,0xAA,0xAA), #white - RGB(0x55,0x55,0x55), #gray - RGB(0x55,0x55,0xFF), #light blue - RGB(0x55,0xFF,0x55), #light green - RGB(0x55,0xFF,0xFF), #light cyan - RGB(0xFF,0x55,0x55), #light red - RGB(0xFF,0x55,0xFF), #light magenta - RGB(0xFF,0xFF,0x55), #yellow - RGB(0xFF,0xFF,0xFF), #white (high intensity) -) - -COMMON_LVB_UNDERSCORE=0x8000 - - - -@wincon.PHANDLER_ROUTINE -def _consoleCtrlHandler(event): - if event in (wincon.CTRL_C_EVENT,wincon.CTRL_BREAK_EVENT): - return True - return False - -def connectConsole(obj): - global consoleObject, consoleOutputHandle, checkDeadTimer - #Get the process ID of the console this NVDAObject is fore - processID,threadID=winUser.getWindowThreadProcessID(obj.windowHandle) - #Attach NVDA to this console so we can access its text etc - try: - wincon.AttachConsole(processID) - except WindowsError as e: - log.debugWarning("Could not attach console: %r"%e) - return False - wincon.SetConsoleCtrlHandler(_consoleCtrlHandler,True) - consoleOutputHandle=winKernel.CreateFile(u"CONOUT$",winKernel.GENERIC_READ|winKernel.GENERIC_WRITE,winKernel.FILE_SHARE_READ|winKernel.FILE_SHARE_WRITE,None,winKernel.OPEN_EXISTING,0,None) - #Register this callback with all the win events we need, storing the given handles for removal later - for eventID in (winUser.EVENT_CONSOLE_CARET,winUser.EVENT_CONSOLE_UPDATE_REGION,winUser.EVENT_CONSOLE_UPDATE_SIMPLE,winUser.EVENT_CONSOLE_UPDATE_SCROLL,winUser.EVENT_CONSOLE_LAYOUT): - handle=winUser.setWinEventHook(eventID,eventID,0,consoleWinEventHook,0,0,0) - if not handle: - raise OSError("could not register eventID %s"%eventID) - consoleWinEventHookHandles.append(handle) - consoleObject=obj - checkDeadTimer=gui.NonReEntrantTimer(_checkDead) - checkDeadTimer.Start(CHECK_DEAD_INTERVAL) - return True - -def disconnectConsole(): - global consoleObject, consoleOutputHandle, consoleWinEventHookHandles, checkDeadTimer - if not consoleObject: - log.debugWarning("console was not connected") - return False - checkDeadTimer.Stop() - checkDeadTimer=None - #Unregister any win events we are using - for handle in consoleWinEventHookHandles: - winUser.unhookWinEvent(handle) - consoleEventHookHandles=[] - consoleObject.stopMonitoring() - winKernel.closeHandle(consoleOutputHandle) - consoleOutputHandle=None - consoleObject=None - try: - wincon.SetConsoleCtrlHandler(_consoleCtrlHandler,False) - except WindowsError: - pass - #Try freeing NVDA from this console - try: - wincon.FreeConsole() - except WindowsError: - pass - return True - -def isConsoleDead(): - # Every console should have at least one process associated with it. - # This console should have two if NVDA is also connected. - # If there is only one, it must be NVDA alone, so it is dead. - processList=wincon.GetConsoleProcessList(2) - return len(processList) < 2 - -def _checkDead(): - try: - if isConsoleDead(): - # We must disconnect NVDA from this console so it can close. - disconnectConsole() - except: - log.exception() - -def getConsoleVisibleLines(): - consoleScreenBufferInfo=wincon.GetConsoleScreenBufferInfo(consoleOutputHandle) - topLine=consoleScreenBufferInfo.srWindow.Top - lineCount=(consoleScreenBufferInfo.srWindow.Bottom-topLine)+1 - lineLength=consoleScreenBufferInfo.dwSize.x - text=wincon.ReadConsoleOutputCharacter(consoleOutputHandle,lineCount*lineLength,0,topLine) - newLines=[text[x:x+lineLength] for x in xrange(0,len(text),lineLength)] - return newLines - -@winUser.WINEVENTPROC -def consoleWinEventHook(handle,eventID,window,objectID,childID,threadID,timestamp): - #We don't want to do anything with the event if the event is not for the window this console is in - if window!=consoleObject.windowHandle: - return - if eventID==winUser.EVENT_CONSOLE_CARET and not eventHandler.isPendingEvents("caret",consoleObject): - eventHandler.queueEvent("caret",consoleObject) - # It is safe to call this event from this callback. - # This avoids an extra core cycle. - consoleObject.event_textChange() - if eventID==winUser.EVENT_CONSOLE_UPDATE_SIMPLE: - x=winUser.GET_X_LPARAM(objectID) - y=winUser.GET_Y_LPARAM(objectID) - consoleScreenBufferInfo=wincon.GetConsoleScreenBufferInfo(consoleOutputHandle) - if x0: #offsets span multiple lines - rect.Left=0 - rect.Right=self.consoleScreenBufferInfo.dwSize.x-1 - length=self.consoleScreenBufferInfo.dwSize.x*(bottom-top+1) - else: - length=self._endOffset-self._startOffset - buf=wincon.ReadConsoleOutput(consoleOutputHandle, length, rect) - if bottom-top>0: - buf=buf[left:len(buf)-(self.consoleScreenBufferInfo.dwSize.x-right)+1] - lastAttr=None - lastText=[] - boundEnd=self._startOffset - for i,c in enumerate(buf): - if self._startOffset+i==boundEnd: - field,(boundStart,boundEnd)=self._getFormatFieldAndOffsets(boundEnd,formatConfig) - if lastText: - commands.append("".join(lastText)) - lastText=[] - commands.append(textInfos.FieldCommand("formatChange",field)) - if not c.Attributes==lastAttr: - formatField=textInfos.FormatField() - if formatConfig['reportColor']: - formatField["color"]=CONSOLE_COLORS_TO_RGB[c.Attributes&0x0f] - formatField["background-color"]=CONSOLE_COLORS_TO_RGB[(c.Attributes>>4)&0x0f] - if formatConfig['reportFontAttributes'] and c.Attributes&COMMON_LVB_UNDERSCORE: - formatField['underline']=True - if formatField: - if lastText: - commands.append("".join(lastText)) - lastText=[] - command=textInfos.FieldCommand("formatChange", formatField) - commands.append(command) - lastAttr=c.Attributes - lastText.append(c.Char) - commands.append("".join(lastText)) - return commands - - def _getTextRange(self,start,end): - startX,startY=self._consoleCoordFromOffset(start) - return wincon.ReadConsoleOutputCharacter(consoleOutputHandle,end-start,startX,startY) - - def _getLineOffsets(self,offset): - consoleScreenBufferInfo=self.consoleScreenBufferInfo - x,y=self._consoleCoordFromOffset(offset) - x=0 - start=self._offsetFromConsoleCoord(x,y) - end=start+consoleScreenBufferInfo.dwSize.x - return start,end - - def _getLineNumFromOffset(self,offset): - consoleScreenBufferInfo=self.consoleScreenBufferInfo - x,y=self._consoleCoordFromOffset(offset) - return y-consoleScreenBufferInfo.srWindow.Top - - def _getStoryLength(self): - consoleScreenBufferInfo=self.consoleScreenBufferInfo - return consoleScreenBufferInfo.dwSize.x*((consoleScreenBufferInfo.srWindow.Bottom+1)-consoleScreenBufferInfo.srWindow.Top) - - def _get_clipboardText(self): - return "\r\n".join(block.rstrip() for block in self.getTextInChunks(textInfos.UNIT_LINE)) diff --git a/source/wincon.py b/source/wincon.py old mode 100644 new mode 100755 index 7dc32919535..cdd6d8904ff --- a/source/wincon.py +++ b/source/wincon.py @@ -1,11 +1,96 @@ -# NVDAObjects/wincon.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 warnings -from winconLegacy import * - -warnings.warn("wincon is deprecated. Use winconLegacy instead, and consider switching to the UIA console implementation.", - DeprecationWarning, stacklevel=3) +from ctypes import * +from ctypes.wintypes import * + +""" +Lower level utility functions and constants for NVDA's +legacy Windows console support, for situations where UIA isn't available. +""" + +CONSOLE_REAL_OUTPUT_HANDLE=-2 + +class COORD(Structure): + _fields_=[ + ('x',c_short), + ('y',c_short), + ] + +class CONSOLE_SCREEN_BUFFER_INFO(Structure): + _fields_=[ + ('dwSize',COORD), + ('dwCursorPosition',COORD), + ('wAttributes',WORD), + ('srWindow',SMALL_RECT), + ('dwMaximumWindowSize',COORD), + ] + +class CONSOLE_SELECTION_INFO(Structure): + _fields_=[ + ('dwFlags',DWORD), + ('dwSelectionAnchor',COORD), + ('srSelection',SMALL_RECT), + ] + +class CHAR_INFO(Structure): + _fields_ = [ + ('Char', c_wchar), #union of char and wchar_t isn't needed since we deal only with unicode + ('Attributes', WORD) + ] + +PHANDLER_ROUTINE=WINFUNCTYPE(BOOL,DWORD) + +CTRL_C_EVENT=0 +CTRL_BREAK_EVENT=1 +CTRL_CLOSE_EVENT=2 + +CONSOLE_NO_SELECTION=0X0 +CONSOLE_SELECTION_IN_PROGRESS=0X1 +CONSOLE_SELECTION_NOT_EMPTY=0x2 +CONSOLE_MOUSE_SELECTION=0X4 +CONSOLE_MOUSE_DOWN=0x8 + +def GetConsoleSelectionInfo(): + info=CONSOLE_SELECTION_INFO() + if windll.kernel32.GetConsoleSelectionInfo(byref(info))==0: + raise WinError() + return info + +def ReadConsoleOutputCharacter(handle,length,x,y): + buf=create_unicode_buffer(length) + numCharsRead=c_int() + if windll.kernel32.ReadConsoleOutputCharacterW(handle,buf,length,COORD(x,y),byref(numCharsRead))==0: + raise WinError() + return buf.value + +def ReadConsoleOutput(handle, length, rect): + BufType=CHAR_INFO*length + buf=BufType() + #rect=SMALL_RECT(x, y, x+length-1, y) + if windll.kernel32.ReadConsoleOutputW(handle, buf, COORD(rect.Right-rect.Left+1, rect.Bottom-rect.Top+1), COORD(0,0), byref(rect))==0: + raise WinError() + return buf + +def GetConsoleScreenBufferInfo(handle): + info=CONSOLE_SCREEN_BUFFER_INFO() + if windll.kernel32.GetConsoleScreenBufferInfo(handle,byref(info))==0: + raise WinError() + return info + +def FreeConsole(): + if windll.kernel32.FreeConsole()==0: + raise WinError() + +def AttachConsole(processID): + if windll.kernel32.AttachConsole(processID)==0: + raise WinError() + +def GetConsoleWindow(): + return windll.kernel32.GetConsoleWindow() + +def GetConsoleProcessList(maxProcessCount): + processList=(c_int*maxProcessCount)() + num=windll.kernel32.GetConsoleProcessList(processList,maxProcessCount) + return processList[0:num] + +def SetConsoleCtrlHandler(handler,add): + if windll.kernel32.SetConsoleCtrlHandler(handler,add)==0: + raise WinError() diff --git a/source/winconLegacy.py b/source/winconLegacy.py deleted file mode 100755 index 3eaa94a0238..00000000000 --- a/source/winconLegacy.py +++ /dev/null @@ -1,91 +0,0 @@ -from ctypes import * -from ctypes.wintypes import * - -CONSOLE_REAL_OUTPUT_HANDLE=-2 - -class COORD(Structure): - _fields_=[ - ('x',c_short), - ('y',c_short), - ] - -class CONSOLE_SCREEN_BUFFER_INFO(Structure): - _fields_=[ - ('dwSize',COORD), - ('dwCursorPosition',COORD), - ('wAttributes',WORD), - ('srWindow',SMALL_RECT), - ('dwMaximumWindowSize',COORD), - ] - -class CONSOLE_SELECTION_INFO(Structure): - _fields_=[ - ('dwFlags',DWORD), - ('dwSelectionAnchor',COORD), - ('srSelection',SMALL_RECT), - ] - -class CHAR_INFO(Structure): - _fields_ = [ - ('Char', c_wchar), #union of char and wchar_t isn't needed since we deal only with unicode - ('Attributes', WORD) - ] - -PHANDLER_ROUTINE=WINFUNCTYPE(BOOL,DWORD) - -CTRL_C_EVENT=0 -CTRL_BREAK_EVENT=1 -CTRL_CLOSE_EVENT=2 - -CONSOLE_NO_SELECTION=0X0 -CONSOLE_SELECTION_IN_PROGRESS=0X1 -CONSOLE_SELECTION_NOT_EMPTY=0x2 -CONSOLE_MOUSE_SELECTION=0X4 -CONSOLE_MOUSE_DOWN=0x8 - -def GetConsoleSelectionInfo(): - info=CONSOLE_SELECTION_INFO() - if windll.kernel32.GetConsoleSelectionInfo(byref(info))==0: - raise WinError() - return info - -def ReadConsoleOutputCharacter(handle,length,x,y): - buf=create_unicode_buffer(length) - numCharsRead=c_int() - if windll.kernel32.ReadConsoleOutputCharacterW(handle,buf,length,COORD(x,y),byref(numCharsRead))==0: - raise WinError() - return buf.value - -def ReadConsoleOutput(handle, length, rect): - BufType=CHAR_INFO*length - buf=BufType() - #rect=SMALL_RECT(x, y, x+length-1, y) - if windll.kernel32.ReadConsoleOutputW(handle, buf, COORD(rect.Right-rect.Left+1, rect.Bottom-rect.Top+1), COORD(0,0), byref(rect))==0: - raise WinError() - return buf - -def GetConsoleScreenBufferInfo(handle): - info=CONSOLE_SCREEN_BUFFER_INFO() - if windll.kernel32.GetConsoleScreenBufferInfo(handle,byref(info))==0: - raise WinError() - return info - -def FreeConsole(): - if windll.kernel32.FreeConsole()==0: - raise WinError() - -def AttachConsole(processID): - if windll.kernel32.AttachConsole(processID)==0: - raise WinError() - -def GetConsoleWindow(): - return windll.kernel32.GetConsoleWindow() - -def GetConsoleProcessList(maxProcessCount): - processList=(c_int*maxProcessCount)() - num=windll.kernel32.GetConsoleProcessList(processList,maxProcessCount) - return processList[0:num] - -def SetConsoleCtrlHandler(handler,add): - if windll.kernel32.SetConsoleCtrlHandler(handler,add)==0: - raise WinError()