Home > Enterprise >  How can I intercept and block the caps lock toggle event globally, leaving other events intact?
How can I intercept and block the caps lock toggle event globally, leaving other events intact?

Time:01-10

I need to check the toggled state of caps lock and block it. I have tried using a low-level keyboard hook 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 when it's actually toggled. It's important that I intercept the toggled event exclusively because I don't wish to rely on a single press of caps lock toggling its state, and I don't want to disrupt other events in case of caps lock being used as a modifier. I'm currently using GetKeyState(VK_CAPITAL)&1 to check for caps lock state in my window callback, and forcing it back off 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. Using GetKeyState or GetAsyncKeyState from a hook also seems not to work, as they seem to get the event after the hook.

CodePudding user response:

Use GetAsyncKeyState to detect when/if the caps key is hit, and its current state (up or down). Then call keybd_event (or SendInput) 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.) With a reasonable and appropriate sample cycle using GetAsyncKeyState().

The concept above is comprised of functions that run in user-mode, therefore almost certainly limited to implementations of reaction algorithms (detect toggle, then execute another toggle.) as opposed to a true prevention algorithm. (ie, one that either re-maps a key to a no-op at run-time, or trap the request at a low level.)
Most true prevention algorithms would likely make use of Kernel mode driver calls, which are accessible and implementable via the WinAPI and for which concepts are introduce (among other places) by burrowing down through RAWKEYBOARD and into areas such as Keyboard and Mouse HID drivers.

CodePudding user response:

You could set a low-level hook with SetWindowsHookEx. Refer to the thread: Best way to intercept pressing of Caps Lock

  • Related