From db6474150b13d1a2560ddd341eb7a124af591ecb Mon Sep 17 00:00:00 2001 From: Bill Dengler Date: Tue, 3 Dec 2019 00:28:10 -0500 Subject: [PATCH 1/2] Patch around #10569 for KeyboardHandlerBasedTypedCharSupport. --- source/brailleInput.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/source/brailleInput.py b/source/brailleInput.py index 2896b04c94c..8444723d948 100644 --- a/source/brailleInput.py +++ b/source/brailleInput.py @@ -22,6 +22,7 @@ from baseObject import AutoPropertyObject import keyLabels + """Framework for handling braille input from the user. All braille input is represented by a {BrailleInputGesture}. Normally, all that is required is to create and execute a L{BrailleInputGesture}, @@ -399,6 +400,14 @@ def sendChars(self, chars: str): input.ii.ki.dwFlags = winUser.KEYEVENTF_UNICODE|direction inputs.append(input) winUser.SendInput(inputs) + from NVDAObjects.behaviors import KeyboardHandlerBasedTypedCharSupport + focusObj = api.getFocusObject() + if isinstance(focusObj, KeyboardHandlerBasedTypedCharSupport): + # #10569: KeyboardHandlerBasedTypedCharSupport uses ToUnicodeEx, + # which can't read emulated keyboard events. + # Send TypedCharacter events manually. + for ch in chars: + focusObj.event_typedCharacter(ch=ch) def handleGainFocus(self, obj): """ Clear all state when the focus changes. From b6e2b8b9fd3a017a0111bd3a268ac2033a81f1e0 Mon Sep 17 00:00:00 2001 From: Bill Dengler Date: Tue, 3 Dec 2019 13:03:35 -0500 Subject: [PATCH 2/2] Generalize solution. --- source/brailleInput.py | 7 +++---- source/keyboardHandler.py | 34 ++++++++++++++++++++++------------ 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/source/brailleInput.py b/source/brailleInput.py index 8444723d948..e85a0cb1d8c 100644 --- a/source/brailleInput.py +++ b/source/brailleInput.py @@ -400,11 +400,10 @@ def sendChars(self, chars: str): input.ii.ki.dwFlags = winUser.KEYEVENTF_UNICODE|direction inputs.append(input) winUser.SendInput(inputs) - from NVDAObjects.behaviors import KeyboardHandlerBasedTypedCharSupport focusObj = api.getFocusObject() - if isinstance(focusObj, KeyboardHandlerBasedTypedCharSupport): - # #10569: KeyboardHandlerBasedTypedCharSupport uses ToUnicodeEx, - # which can't read emulated keyboard events. + if keyboardHandler.shouldUseToUnicodeEx(focusObj): + # #10569: When we use ToUnicodeEx to detect typed characters, + # emulated keypresses aren't detected. # Send TypedCharacter events manually. for ch in chars: focusObj.event_typedCharacter(ch=ch) diff --git a/source/keyboardHandler.py b/source/keyboardHandler.py index 05190ad3aa9..6cfebb8b3d5 100644 --- a/source/keyboardHandler.py +++ b/source/keyboardHandler.py @@ -99,6 +99,27 @@ def getNVDAModifierKeys(): keys.append(vkCodes.byName["capslock"]) return keys + +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) + ) + ) + + def internal_keyDownEvent(vkCode,scanCode,extended,injected): """Event called by winInputHook when it receives a keyDown. """ @@ -197,23 +218,12 @@ 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.behaviors import KeyboardHandlerBasedTypedCharSupport if ( - # This is only possible in Windows 10 1607 and above - winVersion.isWin10(1607) + shouldUseToUnicodeEx(focus) # 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):