windows-hotkeys icon indicating copy to clipboard operation
windows-hotkeys copied to clipboard

`SetWindowHookEx` for Win key support

Open LGUG2Z opened this issue 1 year ago • 2 comments

Hi again! I use this crate as a dependency of whkd and one of the most common requests I get from users is to be able to rebind Win key combinations which are reserved by the system.

Currently this is what happens when trying to set a Win key binding which is already reserved by the system:

image

AutoHotKey gets around these restrictions by using SetWindowHookEx for bindings with Win keys automatically as explained briefly here: https://www.autohotkey.com/board/topic/121557-how-does-ahk-register-hotkeys/?p=688533

I did some sleuthing and it seems there is some prior art in using SetWindowHookEx instead of RegisterHotKey in the nog Rust codebase: https://github.com/TimUntersberger/nog/pull/283.

Is there any interest in adding this sort of functionality to this crate?

LGUG2Z avatar May 01 '24 17:05 LGUG2Z

Hi! I am aware of this limitation with RegisterHotKey and therefore windows-hotkeys. The SetWindowHookEx approach seems interesting but from what I've gathered by skimming through the docs and a few other sites, this would be quite a bit of code and might create somewhat redundant systems if the RegisterHotKey approach is not replaced.

If my understanding is correct, it would work somewhat like this:

  • Register a hook for WH_KEYBOARD_LL in order to catch all low level keyboard events before they get handled by windows shortcuts
  • Then (not actually then after registration, but rather constantly after program start) handle the incoming keyboard events from the event queue
  • Parse the events and track the key states in software
  • Check those key states against the list of registered hotkeys
  • Execute the configured actions if a match is detected (and somehow prevent the event from being further processed by windows)

This all sounds pretty cool and actually kinda doable. The main problem I see with this is, that we need the whole code with all the active hooks, event parsing, key state tracking and shortcut detection, even if it is only used for those special windows key shortcuts. That means we have two completely different systems that both register and detect hotkeys in completely different ways. One of them actually with more features. Also I assume the SetWindowHookEx requires admin privileges, so we can't even just fully replace the RegisterHotKey system. One other point might be that the SetWindowHookEx approach likely increases the CPU usage a bit since we do more stuff in the application instead of letting windows take care of it. Although I believe the hooked keyboard events with the event queue is probably still pretty efficient and not a problem here.

Anyway, this is mainly me writing down my first thoughts about this. I'm not fully for or against this kind of functionality right now, I'll have to think about it a bit more. It might be an option to extend the crate to provide different selectable hotkey backends (RegisterHotKey / SetWindowHookEx).

I'd also enjoy your thoughts on the points I rambled on about if you have any.

dnlmlr avatar May 01 '24 23:05 dnlmlr

Also I assume the SetWindowHookEx requires admin privileges, so we can't even just fully replace the RegisterHotKey system.

I don't think this is the case based on my testing with AHK and Win key binds which use the hook method; I haven't had to run as admin to get the functionality working.

One other point might be that the SetWindowHookEx approach likely increases the CPU usage a bit since we do more stuff in the application instead of letting windows take care of it.

This is definitely worth benchmarking and taking into consideration; I saw a similar increase in CPU usage when I implemented a custom focus-follows-mouse feature vs. the built-in (but overly sensitive) Xmouse controls.

The main problem I see with this is, that we need the whole code with all the active hooks, event parsing, key state tracking and shortcut detection, even if it is only used for those special windows key shortcuts.

That means we have two completely different systems that both register and detect hotkeys in completely different ways.

It might be an option to extend the crate to provide different selectable hotkey backends

Maybe this could be treated as two different implementations with RegisterHotKey enabled in default-features and and the low level hook requiring no-default-features and an explicit opt-in?

Fully appreciate that this is a huge chunk of potential work not to mention the ongoing work of maintaining two separate implementations.

LGUG2Z avatar May 15 '24 20:05 LGUG2Z