I'm trying to write an application that responds whenever the Shift key is pressed, no matter what application currently has focus.
I tried this with SetWindowsHookEx()
and with GetKeyboardState()
, but both of these only work when the application's window has focus. I need it to work globally.
How do I do this?
None of the provided answers helped me solve my problem, but I found the answer myself. Here it is.
Using SetWindowsHookEx()
with WH_KEYBOARD_LL
was the correct approach. However, the other parameters to SetWindowsHookEx()
are unintuitive:
dwThreadId
, needs to be 0.hMod
, needs to point to some DLL. I used
User32
, which is a DLL that is always loaded anyway and is used by all
processes with a GUI. I got this idea from a CodeProject post about this.Thus, the code looks a bit like this:
instance = LoadLibrary("User32");
hhook = SetWindowsHookEx(WH_KEYBOARD_LL, hookFunction, instance, 0);
The documentation is unclear about the second-last parameter. It says:
The hMod parameter must be set to NULL [...] if the hook procedure is within the code associated with the current process.
It doesn't state that this only applies to some types of hooks, but not to WH_KEYBOARD_LL
and WH_MOUSE_LL
.
You'll have to use SetWindowsHookEx(). There are only two types of hooks that you can implement in a managed language, WH_KEYBOARD_LL and WH_MOUSE_LL. All other hooks require a DLL that can be injected into another process. Managed DLLs cannot be injected, the CLR cannot be initialized.
This blog post has a functional example.
If you use the technique in the post referenced by nobugz, you will need to make sure the delegate doesn't get garbage-collected, e.g. by using GC.KeepAlive(_proc) when setting the hook, otherwise after an indeterminate period the hook will stop working when the delagate gets GCed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With