Repository: nvaccess/nvda

Issue:
Keyboard handler/ToUnicodeEx: typed characters from Braille displays not reported
<!--
Please thoroughly read NVDA's wiki article on how to fill in this template, including how to provide the required files.
Issues may be closed if the required information is not present.
https://github.com/nvaccess/nvda/wiki/Github-issue-template-explanation-and-examples
-->

### Steps to reproduce:
1. Open a Windows Console, or some other application which uses `toUnicodeEx` to determine typed characters.
2. With "speak typed characters" enabled, enter text using a connected Braille keyboard.

### Actual behavior:
No characters are reported.

### Expected behavior:
Typed characters are reported.

### System configuration
#### NVDA installed/portable/running from source:
Installed.

#### NVDA version:
Latest `master` branch.

#### Windows version:
Windows 10 1903.

#### Name and version of other software in use when reproducing the issue:
Windows Console, PuTTY

#### Other information about your system:

### Other questions
#### Does the issue still occur after restarting your PC?
Yes.

#### Have you tried any other versions of NVDA? If so, please report their behaviors.
No.


Discussion:
Cc @leonardder @michaelDCurran 

Resolving patch:
diff --git a/source/brailleInput.py b/source/brailleInput.py
--- 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,13 @@ def sendChars(self, chars: str):
 				input.ii.ki.dwFlags = winUser.KEYEVENTF_UNICODE|direction
 				inputs.append(input)
 		winUser.SendInput(inputs)
+		focusObj = api.getFocusObject()
+		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)
 
 	def handleGainFocus(self, obj):
 		""" Clear all state when the focus changes.
diff --git a/source/keyboardHandler.py b/source/keyboardHandler.py
--- 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):


Test patch: