Esempio n. 1
0
 def _get_isCollapsed(self):
     """Works around a UIA bug on Windows 10 1903 and later."""
     if not isWin10(1903):
         return super(consoleUIATextInfo, self)._get_isCollapsed()
     # Even when a console textRange's start and end have been moved to the
     # same position, the console incorrectly reports the end as being
     # past the start.
     # Therefore to decide if the textRange is collapsed,
     # Check if it has no text.
     return not bool(self._rangeObj.getText(1))
Esempio n. 2
0
 def __init__(self, obj, position, _rangeObj=None):
     super(consoleUIATextInfo, self).__init__(obj, position, _rangeObj)
     if position == textInfos.POSITION_CARET and isWin10(1903,
                                                         atLeast=False):
         # 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[textInfos.UNIT_CHARACTER], 1)
Esempio n. 3
0
 def collapse(self, end=False):
     """Works around a UIA bug on Windows 10 1903 and later."""
     if not isWin10(1903):
         return super(consoleUIATextInfo, self).collapse(end=end)
     # When collapsing, consoles seem to incorrectly push the start of the
     # textRange back one character.
     # Correct this by bringing the start back up to where the end is.
     oldInfo = self.copy()
     super(consoleUIATextInfo, self).collapse()
     if not end:
         self._rangeObj.MoveEndpointByRange(
             UIAHandler.TextPatternRangeEndpoint_Start, oldInfo._rangeObj,
             UIAHandler.TextPatternRangeEndpoint_Start)
 def chooseNVDAObjectOverlayClasses(self, obj, clsList):
     if obj.windowClassName == self.TERMINAL_WINDOW_CLASS and isinstance(
             obj, IAccessible
     ) and obj.IAccessibleRole == oleacc.ROLE_SYSTEM_CLIENT:
         try:
             clsList.remove(DisplayModelEditableText)
         except ValueError:
             pass
         if isWin10(1607):
             clsList[0:0] = (KeyboardHandlerBasedTypedCharSupport,
                             DisplayModelLiveText)
         else:
             clsList[0:0] = (Terminal, DisplayModelLiveText)
Esempio n. 5
0
def onInstall():
    import gui
    import wx
    import winVersion
    requiredVer = "Windows 10 Version 1909"
    if not winVersion.isWin10(version=1909) and gui.messageBox(
            # Translators: Dialog text shown when attempting to install the add-on on an unsupported version of Windows (minSupportedVersion is the minimum version required for this add-on).
            _("You are using an older version of Windows. This add-on requires {minSupportedVersion} or later. Are you sure you wish to install this add-on anyway?"
              ).format(minSupportedVersion=requiredVer),
            # Translators: title of the dialog shown when attempting to install the add-on on an old version of Windows.
            _("Old Windows version"),
            wx.YES | wx.NO | wx.CANCEL | wx.CENTER
            | wx.ICON_QUESTION) == wx.NO:
        raise RuntimeError("Old Windows version detected")
def shouldUseToUnicodeEx(focus=None):
    "Returns whether to use ToUnicodeEx to determine typed characters."
    if not focus:
        focus = api.getFocusObject()
    from NVDAObjects.behaviors import KeyboardHandlerBasedTypedCharSupport
    return (
        # This is only possible in Windows 10 1607 and above
        winVersion.isWin10(1607) and (  # Either of
            # We couldn't inject in-process, and its not a legacy console window without keyboard support.
            # 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 console with keyboard support, where WM_CHAR messages are doubled
            or isinstance(focus, KeyboardHandlerBasedTypedCharSupport)))
Esempio n. 7
0
def shouldUseUIAConsole(setting=None):
    """Determines whether to use UIA in the Windows Console.
@param setting: the config value to base this check on (if not provided,
it is retrieved from config).
	"""
    if not setting:
        setting = config.conf['UIA']['winConsoleImplementation']
    if setting == "legacy":
        return False
    elif setting == "UIA":
        return True
    # #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.
    return isWin10(1803)
Esempio n. 8
0
 def event_nameChange(self, obj, nextHandler):
     # NVDA Core issue 5641: try catching virtual desktop switch event, which will result in name change for the desktop object.
     # To be taken care of by NVDA Core, and for older releases, let the add-on handle it for a time.
     # This may degrade performance and/or cause NVDA to become verbose in situations other than virtual desktop switch, so exercise discretion.
     if obj.windowClassName == "#32769":
         if globalVars.appArgs.debugLogging:
             import tones
             tones.beep(512, 50)
             log.debug(
                 f"W10: possible desktop name change from {obj}, app module: {obj.appModule}"
             )
         # CSRSS: Client/Server Runtime Subsystem (Windows subsystem process/desktop object)
         if obj.appModule.appName == "csrss":
             import wx
             # Even with desktop name change handler added, older Windows 10 releases won't support this properly.
             if (not hasattr(eventHandler,
                             "handlePossibleDesktopNameChange") or
                 (hasattr(eventHandler, "handlePossibleDesktopNameChange")
                  and not winVersion.isWin10(version=1909))):
                 wx.CallLater(500, ui.message, obj.name)
     self.uiaDebugLogging(obj, "nameChange")
     nextHandler()
Esempio n. 9
0
UIAEventIdsToNVDAEventNames={
	UIA_LiveRegionChangedEventId:"liveRegionChange",
	UIA_SelectionItem_ElementSelectedEventId:"UIA_elementSelected",
	UIA_MenuOpenedEventId:"gainFocus",
	UIA_SelectionItem_ElementAddedToSelectionEventId:"stateChange",
	UIA_SelectionItem_ElementRemovedFromSelectionEventId:"stateChange",
	#UIA_MenuModeEndEventId:"menuModeEnd",
	UIA_ToolTipOpenedEventId:"UIA_toolTipOpened",
	#UIA_AsyncContentLoadedEventId:"documentLoadComplete",
	#UIA_ToolTipClosedEventId:"hide",
	UIA_Window_WindowOpenedEventId:"UIA_window_windowOpen",
	UIA_SystemAlertEventId:"UIA_systemAlert",
}

autoSelectDetectionAvailable = False
if winVersion.isWin10():
	UIAEventIdsToNVDAEventNames.update({
		UIA.UIA_Text_TextChangedEventId: "textChange",
		UIA.UIA_Text_TextSelectionChangedEventId: "caret", })
	autoSelectDetectionAvailable = True

ignoreWinEventsMap = {
	UIA_AutomationPropertyChangedEventId: list(UIAPropertyIdsToNVDAEventNames.keys()),
}
for id in UIAEventIdsToNVDAEventNames.keys():
	ignoreWinEventsMap[id] = [0]

class UIAHandler(COMObject):
	_com_interfaces_=[IUIAutomationEventHandler,IUIAutomationFocusChangedEventHandler,IUIAutomationPropertyChangedEventHandler,IUIAutomationNotificationEventHandler]

	def __init__(self):
Esempio n. 10
0
 def check(cls):
     # Only present this as an available synth if this is Windows 10.
     return winVersion.isWin10()
Esempio n. 11
0
 def isGoodUIAWindow(self, hwnd):
     # #9204: shell raises window open event for emoji panel in build 18305 and later.
     if winVersion.isWin10(version=1903) and winUser.getClassName(
             hwnd) == "ApplicationFrameWindow":
         return True
     return False
Esempio n. 12
0
from NVDAObjects.UIA import UIA, SearchField, Dialog
from NVDAObjects.behaviors import EditableTextWithSuggestions
import api
import config
import queueHandler
import eventHandler
import globalVars
import UIAHandler
from logHandler import log
import winVersion
import addonHandler
addonHandler.initTranslation()

# #52: forget everything if the current release is not a supported version of Windows 10.
# NVDA 2019.2 includes a handy Windows 10 version check function.
W10AddonSupported = winVersion.isWin10(version=1909)

# Extra UIA constants
UIA_Drag_DragStartEventId = 20026
UIA_Drag_DragCancelEventId = 20027
UIA_Drag_DragCompleteEventId = 20028
UIA_DropTarget_DragEnterEventId = 20029
UIA_DropTarget_DragLeaveEventId = 20030
UIA_DropTarget_DroppedEventId = 20031
UIA_Text_TextChangedEventId = 20015

# For convenience.
W10Events = {
    UIA_Drag_DragStartEventId: "UIA_dragStart",
    UIA_Drag_DragCancelEventId: "UIA_dragCancel",
    UIA_Drag_DragCompleteEventId: "UIA_dragComplete",
Esempio n. 13
0
def internal_keyDownEvent(vkCode, scanCode, extended, injected):
    """Event called by winInputHook when it receives a keyDown.
	"""
    gestureExecuted = False
    try:
        global lastNVDAModifier, lastNVDAModifierReleaseTime, bypassNVDAModifier, passKeyThroughCount, lastPassThroughKeyDown, currentModifiers, keyCounter, stickyNVDAModifier, stickyNVDAModifierLocked
        # Injected keys should be ignored in some cases.
        if injected and (ignoreInjected
                         or not config.conf['keyboard']['handleInjectedKeys']):
            return True

        keyCode = (vkCode, extended)

        if passKeyThroughCount >= 0:
            # We're passing keys through.
            if lastPassThroughKeyDown != keyCode:
                # Increment the pass key through count.
                # We only do this if this isn't a repeat of the previous key down, as we don't receive key ups for repeated key downs.
                passKeyThroughCount += 1
                lastPassThroughKeyDown = keyCode
            return True

        keyCounter += 1
        stickyKeysFlags = winUser.getSystemStickyKeys().dwFlags
        if stickyNVDAModifier and not stickyKeysFlags & winUser.SKF_STICKYKEYSON:
            # Sticky keys has been disabled,
            # so clear the sticky NVDA modifier.
            currentModifiers.discard(stickyNVDAModifier)
            stickyNVDAModifier = None
            stickyNVDAModifierLocked = False
        gesture = KeyboardInputGesture(currentModifiers, vkCode, scanCode,
                                       extended)
        if not (stickyKeysFlags & winUser.SKF_STICKYKEYSON) and (
                bypassNVDAModifier or
            (keyCode == lastNVDAModifier and lastNVDAModifierReleaseTime
             and time.time() - lastNVDAModifierReleaseTime < 0.5)):
            # The user wants the key to serve its normal function instead of acting as an NVDA modifier key.
            # There may be key repeats, so ensure we do this until they stop.
            bypassNVDAModifier = True
            gesture.isNVDAModifierKey = False
        lastNVDAModifierReleaseTime = None
        if gesture.isNVDAModifierKey:
            lastNVDAModifier = keyCode
            if stickyKeysFlags & winUser.SKF_STICKYKEYSON:
                if keyCode == stickyNVDAModifier:
                    if stickyKeysFlags & winUser.SKF_TRISTATE and not stickyNVDAModifierLocked:
                        # The NVDA modifier is being locked.
                        stickyNVDAModifierLocked = True
                        if stickyKeysFlags & winUser.SKF_AUDIBLEFEEDBACK:
                            tones.beep(1984, 60)
                        return False
                    else:
                        # The NVDA modifier is being unlatched/unlocked.
                        stickyNVDAModifier = None
                        stickyNVDAModifierLocked = False
                        if stickyKeysFlags & winUser.SKF_AUDIBLEFEEDBACK:
                            tones.beep(496, 60)
                        return False
                else:
                    # The NVDA modifier is being latched.
                    if stickyNVDAModifier:
                        # Clear the previous sticky NVDA modifier.
                        currentModifiers.discard(stickyNVDAModifier)
                        stickyNVDAModifierLocked = False
                    stickyNVDAModifier = keyCode
                    if stickyKeysFlags & winUser.SKF_AUDIBLEFEEDBACK:
                        tones.beep(1984, 60)
        else:
            # Another key was pressed after the last NVDA modifier key, so it should not be passed through on the next press.
            lastNVDAModifier = None
        if gesture.isModifier:
            if gesture.speechEffectWhenExecuted in (
                    gesture.SPEECHEFFECT_PAUSE, gesture.SPEECHEFFECT_RESUME
            ) and keyCode in currentModifiers:
                # Ignore key repeats for the pause speech key to avoid speech stuttering as it continually pauses and resumes.
                return True
            currentModifiers.add(keyCode)
        elif stickyNVDAModifier and not stickyNVDAModifierLocked:
            # A non-modifier was pressed, so unlatch the NVDA modifier.
            currentModifiers.discard(stickyNVDAModifier)
            stickyNVDAModifier = None

        try:
            inputCore.manager.executeGesture(gesture)
            gestureExecuted = True
            trappedKeys.add(keyCode)
            if canModifiersPerformAction(gesture.generalizedModifiers):
                # #3472: These modifiers can perform an action if pressed alone
                # and we've just consumed the main key.
                # Send special reserved vkcode (0xff) to at least notify the app's key state that something happendd.
                # This allows alt and windows to be bound to scripts and
                # stops control+shift from switching keyboard layouts in cursorManager selection scripts.
                KeyboardInputGesture((), 0xff, 0, False).send()
            return False
        except inputCore.NoInputGestureAction:
            if gesture.isNVDAModifierKey:
                # Never pass the NVDA modifier key to the OS.
                trappedKeys.add(keyCode)
                return False
    except:
        log.error("internal_keyDownEvent", exc_info=True)
    finally:
        # #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.behaviors import KeyboardHandlerBasedTypedCharSupport
        if (
                # This is only possible in Windows 10 1607 and above
                winVersion.isWin10(1607)
                # 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
                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 without keyboard support.
                # 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 console with keyboard support, where WM_CHAR messages are doubled
                or isinstance(focus, KeyboardHandlerBasedTypedCharSupport))):
            keyStates = (ctypes.c_byte * 256)()
            for k in range(256):
                keyStates[k] = ctypes.windll.user32.GetKeyState(k)
            charBuf = ctypes.create_unicode_buffer(5)
            hkl = ctypes.windll.user32.GetKeyboardLayout(focus.windowThreadID)
            # In previous Windows builds, calling ToUnicodeEx would destroy keyboard buffer state and therefore cause the app to not produce the right WM_CHAR message.
            # However, ToUnicodeEx now can take a new flag of 0x4, which stops it from destroying keyboard state, thus allowing us to safely call it here.
            res = ctypes.windll.user32.ToUnicodeEx(vkCode, scanCode,
                                                   keyStates, charBuf,
                                                   len(charBuf), 0x4, hkl)
            if res > 0:
                for ch in charBuf[:res]:
                    eventHandler.queueEvent("typedCharacter", focus, ch=ch)
    return True
Esempio n. 14
0
def findExtraOverlayClasses(obj, clsList):
    if isWin10(1607) and config.conf['terminals']['keyboardSupportInLegacy']:
        from NVDAObjects.behaviors import KeyboardHandlerBasedTypedCharSupport
        clsList.append(KeyboardHandlerBasedTypedCharSupport)
    clsList.append(WinConsole)
Esempio n. 15
0
def findExtraOverlayClasses(obj, clsList):
    if isWin10(1607) and config.conf['terminals']['keyboardSupportInLegacy']:
        clsList.append(EnhancedLegacyWinConsole)
    else:
        clsList.append(LegacyWinConsole)