Reputation: 167
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.
Upvotes: 1
Views: 440
Reputation: 23236
A key-mapping approach
The method described below meets the primary need, i.e. to disable the the Caps Lock key from toggling the keyboard into CAPS mode. However, it does not maintain the ability of key to be used as a modifier once it has been re-mapped. (One of the criteria you list.)
The uncap project worked (almost out-of-the-box) for me to disable the Caps Lock key. Before trying it, I recommend going through the README.md to get the details. In short, it uses a key map approach that allows keys to be mapped to different locations. I found it essentially does what it claims in terms of disabling Caps Lock, and it is capable of doing much more. This could be good or bad. Having the source code available allows you to create a pared down version that simply disables the Caps Key, or do other modifications as needed.
While exploring it, I found a couple of issues that I describe below under problems.
Note that the default behavior is to map Caps Lock key to VK_ESCAPE
upon startup. I commented out the following line in the parseArguments(...)
function to disable that feature so I could experiment with other mappings...
/*my.keymap[VK_CAPITAL] = VK_ESCAPE;*/
I used uncap.c
as the only source file and the following on a Windows 10 machine:
gcc.exe -Wall -g -std=c89 -I"C:\Program Files (x86)\CodeBlocks\MinGW\mingw32\lib" -c C:\play_cb\uncap\uncap.c -o obj\Debug\uncap.o
Problems
It builds with a few warnings related to wrong number of arguments, or format specifiers in sprintf
, but once addressing those issues, the code worked as described in this section of documentation.
Although the feature list claims "Disable key mappings easily by stopping Uncap.". did not work. Once the PC was re-booted, normal key mappings are restored.
If the keyboard is set to CAPS ON when uncap
is executed, it remains in CAPS mode and the Caps Lock key is not able to undo it :)
I found this link useful when experimenting with mappings: Virtual key codes
Upvotes: 1
Reputation: 23236
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 the content here RAWKEYBOARD into areas such as Keyboard and Mouse HID drivers.
Upvotes: 1
Reputation: 4040
You could set a low-level hook with SetWindowsHookEx. Refer to the thread: Best way to intercept pressing of Caps Lock
Upvotes: -2