I'm trying to find a way to intercept and block the caps lock toggle event globally with WinAPI.
I have tried using SetWindowsHookEx
with WH_KEYBOARD_LL
and checking for WPARAM==WM_KEYDOWN || WPARAM==WM_SYSKEYDOWN
messages, and LPARAM.vkCode==VK_CAPITAL || LPARAM.scanCode==0x3A
, but this results in me intercepting/blocking caps lock when it's held down/pressed, not only when it's actually toggled.
The reason it's important to me that it only intercepts the toggled event is because certain software (like screen readers) can use a single press or holding of caps lock as a modifier, which is not something I wish to disrupt.
I'm currently using GetKeyState(VK_CAPITAL)&1
to check for caps lock getting toggled and forcing it back off by sending caps lock with SendInput
, but I would rather intercept/block it if any possible.
I have tried Raw Input as well, and it generates a pair of RI_KEY_BREAK And RI_KEY_MAKE messages when caps lock gets toggled, but (unless I'm mistaken), there is no way to block keys based on WM_INPUT messages, and trying to synchronize a hook and Raw Input seems to be difficult because the hook always gets them first.
Is there any way to hook into whatever GetKeyState(VK_CAPITAL)&1
does or intercept/block a toggle message before other things can receive it?
CodePudding user response:
Use GetAsyncKeyState to detect when/if the caps key is hit, and its current state. Then call keybd_event to programmatically set the caps key back to the state that you want it to be.
The following code snippet (along with other setup code) is included in this link, and will toggle CAPS lock on or off when executed:
RUN keybd_event ({&VK_CAPITAL}, 0, {&KEYEVENTF_KEYUP}, 0, OUTPUT intResult).
RUN keybd_event ({&VK_CAPITAL}, 0, {&KEYEVENTF_EXTENDEDKEY}, 0, OUTPUT intResult).
RUN keybd_event ({&VK_SHIFT}, 0, {&KEYEVENTF_KEYUP}, 0, OUTPUT intResult).
RUN keybd_event ({&VK_SHIFT}, 0, {&KEYEVENTF_EXTENDEDKEY}, 0, OUTPUT intResult).
The recommended way to deploy this implementation (GetAsyncKeyState
/ keybd_event
combination) within your application is to encapsulate it into a worker thread set in a forever loop with sleep()
set to allow sampling of the state approximately every 100ms.
(Note, I believe GetAsyncKeyState()
over GetKeyState()
is an improvement for what you want to do here as GetKeyState()
gets the key status returned from the thread's message queue. The status does not reflect the
interrupt-level state associated with the hardware. GetAsyncKeyState()
specifies whether the key was pressed since the last call to
GetAsyncKeyState()
, and whether the key is currently up or down.)
CodePudding user response:
You could set a low-level hook with SetWindowsHookEx. Refer to the thread: Best way to intercept pressing of Caps Lock