Skip to content

No longer freeze or restart when holding down control+shift+downArrow in MS Word#11477

Closed
michaelDCurran wants to merge 8 commits into
masterfrom
i9463-2
Closed

No longer freeze or restart when holding down control+shift+downArrow in MS Word#11477
michaelDCurran wants to merge 8 commits into
masterfrom
i9463-2

Conversation

@michaelDCurran

Copy link
Copy Markdown
Member

Link to issue number:

Fixes #9463

Summary of the issue:

background

As NVDA detects key presses in its key hook, it may block a certain key from continuing through to the Operating System if that key press is bound to a particular NvDA script. The script may or may not then choose to send the key onto the Operating system later, depending on the action it is taking.
However, certain key combinations such as control+shift, may cause an action in Windows such as changing the input language, if a main key is not also included with that key combination. E.g. control+shift by itself changes input languages, but control+shift+downArrow does not. But, if NVDA blocks control+shift+downArrow, and does not send any key, then the input language is still changed. To get around this, in its key hook, NVDA sends a special VK_NONE (0xff) when modifiers like control+shift are pressed, (whether or not NVDA scripts later send a key) to ensure that the Operating System does not change input languages.

Actual problem

To send the VK_NONE key press in its key hook, currently NVDA uses KeyboardInputGesture.send, which among other things, enters a lock and sets a global variable which flags that NVDA should ignore any injected keys at the moment (I.e. this one).
The assumption was that during the call to KeyboardInputGesture.send (or keybd_event more specifically) only the key press NVDA sent would be executed in NVDA's key hook. And because the OS would have marked i as injected, and because ignoreInjected was true, then we would exit from the reentered key hook early.
But, on some Operating systems (E.g. users in #9463 ) other key presses currently pending, may also execute in the key hook inside keybd_event. In this case though, they are not injected, and therefore the entire key hook runs, and as these key presses are most likely repeats of modifier keys that require us to send the VK_NONE, then we do this, but cause a deadkock in the winInputHook thread as our ignoreInjected lock is not reentrant. Further to this, NVDA's main thread may then actually itself call KeyboardInputGesture.send in a script (perhaps for control+shift+downArrow) which also tries to take the lock, and waits for ever as well.

See the following Python stacks:

Python stack for thread 10376 (winInputHook):
  File "threading.pyc", line 890, in _bootstrap
  File "threading.pyc", line 926, in _bootstrap_inner
  File "threading.pyc", line 870, in run
  File "winInputHook.pyc", line 79, in hookThreadFunc
  File "winInputHook.pyc", line 54, in keyboardHook
  File "keyboardHandler.pyc", line 208, in internal_keyDownEvent
  File "keyboardHandler.pyc", line 528, in send
  File "winUser.pyc", line 494, in keybd_event
  File "winInputHook.pyc", line 56, in keyboardHook
  File "winInputHook.pyc", line 54, in keyboardHook
  File "keyboardHandler.pyc", line 208, in internal_keyDownEvent
  File "keyboardHandler.pyc", line 521, in send
  File "contextlib.pyc", line 112, in __enter__
  File "keyboardHandler.pyc", line 70, in ignoreInjection 

and

Python stack for thread 11700 (MainThread):
  File "nvda.pyw", line 215, in <module>
  File "core.pyc", line 545, in main
  File "wx\core.pyc", line 2134, in MainLoop
  File "gui\__init__.pyc", line 1049, in Notify
  File "core.pyc", line 515, in run
  File "queueHandler.pyc", line 88, in pumpAll
  File "queueHandler.pyc", line 55, in flushQueue
  File "scriptHandler.pyc", line 166, in _queueScriptCallback
  File "scriptHandler.pyc", line 208, in executeScript
  File "editableText.pyc", line 385, in script_caret_changeSelection
  File "keyboardHandler.pyc", line 521, in send
  File "contextlib.pyc", line 112, in __enter__
  File "keyboardHandler.pyc", line 70, in ignoreInjection

We could fix it in one of two ways:

  1. Make the lock reentrant, and ensure that the ignoreInjected variable was only set to true and back to false, if it was not already true. this would stop the deadlock in the winInputHook thread.
  2. In the key hook, No longer use KeyboardInputGesture.send, instead just call keybd_event directly for the keyDown and keyUps required.

Description of how this pull request fixes the issue:

Implement option 2: replace KeyboardInputGesture.send with keybd_event calls in the key hook, and exit the key hook early for VK_NONE.

Testing performed:

Ran the steps in #9463 locally, confirming the freeze / exit cannot be reproduced. Also provided a try build on that issue and had multiple users confirm the freeze / exit is gone for them.

Known issues with pull request:

None.

Change log entry:

Bug fixes:

…d reentrantly. E.g. The keyhook calls keybd_event or sendInput which internally calls the keyHook.

The lock is now a RLock (reentrant lock) and the global variable is only toggled on and then off if it was not already on.
…s (VK 0xff) to ensure that certain modifier keys don't change keyboard layouts, use keybd_event directly rather than our KeyboardInputGesture.send.

This stops a deadlock in the winInputHook thread (#9463)
@michaelDCurran

Copy link
Copy Markdown
Member Author

Replaced by #11478

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.

NVDA exits automatically in MS Word when working with this document

2 participants