3535import NVDAState
3636from contextlib import contextmanager
3737import threading
38+ import winKernel
3839
3940if typing .TYPE_CHECKING :
4041 from NVDAObjects import NVDAObject # noqa: F401
4142 from watchdog import WatchdogObserver
4243
4344_watchdogObserver : typing .Optional ["WatchdogObserver" ] = None
4445ignoreInjected = False
46+ _lastInjectedKeyUp : typing .Tuple [int , int ] = None
47+ _injectionDoneEvent : int = None
4548
4649# Fake vk codes.
4750# These constants should be assigned to the name that NVDA will use for the key.
@@ -285,11 +288,15 @@ def internal_keyUpEvent(vkCode,scanCode,extended,injected):
285288 """
286289 try :
287290 global lastNVDAModifier , lastNVDAModifierReleaseTime , bypassNVDAModifier , passKeyThroughCount , lastPassThroughKeyDown , currentModifiers
288- # Injected keys should be ignored in some cases.
289- if injected and (ignoreInjected or not config .conf ['keyboard' ]['handleInjectedKeys' ]):
290- return True
291-
292291 keyCode = (vkCode , extended )
292+ # Injected keys should be ignored in some cases.
293+ if injected :
294+ if not config .conf ['keyboard' ]['handleInjectedKeys' ]:
295+ return True
296+ if ignoreInjected :
297+ if keyCode == _lastInjectedKeyUp :
298+ winKernel .kernel32 .SetEvent (_injectionDoneEvent )
299+ return True
293300
294301 if passKeyThroughCount >= 1 :
295302 if lastPassThroughKeyDown == keyCode :
@@ -567,7 +574,11 @@ def executeScript(self, script):
567574 # Now actually execute the script.
568575 super ().executeScript (script )
569576
577+ #: The maximum amount of time (in ms) to wait for keys injected by NVDA to be
578+ #: received by NVDA.
579+ _INJECTION_WAIT_TIMEOUT : int = 10
570580 def send (self ):
581+ global _lastInjectedKeyUp , _injectionDoneEvent
571582 keys = []
572583 for vk , ext in self .generalizedModifiers :
573584 if vk == VK_WIN :
@@ -582,6 +593,11 @@ def send(self):
582593 keys .append ((self .vkCode , self .scanCode , self .isExtended ))
583594
584595 with ignoreInjection ():
596+ handleInjectedKeys = config .conf ['keyboard' ]['handleInjectedKeys' ]
597+ if handleInjectedKeys :
598+ _lastInjectedKeyUp = (keys [0 ][0 ], keys [0 ][2 ])
599+ if not _injectionDoneEvent :
600+ _injectionDoneEvent = winKernel .createEvent ()
585601 if winUser .getKeyState (self .vkCode ) & 32768 :
586602 # This key is already down, so send a key up for it first.
587603 winUser .keybd_event (self .vkCode , self .scanCode , self .isExtended + 2 , 0 )
@@ -592,6 +608,11 @@ def send(self):
592608 # Send key up events for the keys in reverse order.
593609 for vk , scan , ext in reversed (keys ):
594610 winUser .keybd_event (vk , scan , ext + 2 , 0 )
611+ if handleInjectedKeys :
612+ # Wait for the keys to be received by NVDA. We don't do this if
613+ # handleInjectedKeys is disabled because we just ignore all injected keys
614+ # in that case.
615+ winKernel .waitForSingleObject (_injectionDoneEvent , self ._INJECTION_WAIT_TIMEOUT )
595616
596617 @classmethod
597618 def fromName (cls , name ):
0 commit comments