Skip to content

Speak typed characters in windows consoles in the correct language - #10551

Closed
michaelDCurran wants to merge 2 commits into
masterfrom
i10113
Closed

michaelDCurran wants to merge 2 commits into
masterfrom
i10113

Conversation

@michaelDCurran

Copy link
Copy Markdown
Member

Link to issue number:

Fixes #10113

Summary of the issue:

With the work to support Windows consoles via UIA, NVDA moved to speaking typed characters in consoles by detecting keyboard input and then using ToUnicodeEx to convert the keyboard input into a character for speaking. We had already been taking this approach for Microsoft Edge and other places in Windows 10 where we could not inject in-process.
ToUnicodeEx requires a keyboard layout to use the correct language. Therefore, we would call GetKeyboardLayout, giving it the thread ID of the focused window.
However, it seems that Windows console windows report the wrong thread ID, and therefore, GetKeyboardLayout fails, returning 0 instead of a valid keyboard layout.
Passing this 0 to ToUnicodeEx, it would generate characters in the user's system language (I think). At least, on my system it was always english US no matter what input language I was currently using.

Description of how this pull request fixes the issue:

We now try multiple things to get a valid keyboard layout:

  • Firstly we try getting it from the focus as usual.
  • If that fails, we instead use the keyboard layout detected from the last input language change for the foreground window. This keyboard layout is now cached on the foreground object when detected by nvdaControlerInternal_inputLangChange in NVDAHelper.py.
  • Finally, if there is no cached keyboard layout, we fallback to calling GetKeyboardLayout for NVDA's main thread.

Testing performed:

  • Installed the Arabic keyboard layout.
  • Opened a Windows console and ensured NVDA was using UIA.
  • With speak typed characters on, first typed some characters, confirming they were being announced in english. backspacing them also confirming they were english characters written to the console.
  • Switched keyboard layouts to Arabic.
  • Again typed some characters, confirming that NVDA was speaking them as Arabic. Backspacing them, confirmed that actual arabic characters were written to the console.

Known issues with pull request:

None.

Change log entry:

None

…characters in Windows consoles.

As before, first try getting the keyboard layout of the focus (input) thread.
If that fails, get the last keyboard layout change detected by NVDA on the foreground object,
Finally, fallback to the keyboard layout of NVDA's main thread.
Comment thread source/NVDAHelper.py
# Cache the new keyboard layout on the foreground object,
# Which may be used by keyboardHandler
# when speaking typed characters in situations where it cannot be fetched directly from the focus.
fg._lastDetectedKeyboardLayoutChange = hkl

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd suggest storing this in globalVars instead.

Comment thread source/keyboardHandler.py
hkl = getattr(api.getForegroundObject(), '_lastDetectedKeyboardLayoutChange', 0)
if not hkl:
log.debug("No layout cached, falling back to layout of NVDA main thread")
# As a last resort, use the keyboard layout of NVDA's main thread.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How likely would it be that the keyboard layout for the NVDA main thread differs from the keyboard layout of the currently focused app?

@michaelDCurran

michaelDCurran commented Nov 27, 2019 via email

Copy link
Copy Markdown
Member Author

@LeonarddeR

Copy link
Copy Markdown
Collaborator

Thanks for the explanation. Because it's problematic, that's why I suggested globalVars. We only have to cache just one layout anyway. My personal belief is that caching things on objects should be avoided.

@michaelDCurran

Copy link
Copy Markdown
Member Author

But if we cache on globalVars, then we can only track one layout. And if the user has configured for per-app input language changes, this will cause us to sometimes use the wrong layout again.

I think the better approach here is going to be finding a way to get the real input thread of conhost and passing that to GetKeyboardLayout like we do for Edge and such.

@codeofdusk

Copy link
Copy Markdown
Contributor

This may also fix the dead key bug mentioned in #9915.

@michaelDCurran

Copy link
Copy Markdown
Member Author

Replaced by pr #10554

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

UIA console: when typing in the console, characters are wrongly pronounced regardless of the keyboard layout

3 participants