User32.dll exposes a RegisterHotKey function, to register, well, hotkeys:

[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool RegisterHotKey(IntPtr hWnd, IntPtr id, uint fsModifiers, uint vk);

Using this API, we can register hotkeys like Ctrl+R or whatever modifier+key combination we want to use, and then we can handle WM_HOTKEY messages to run the associated application command, and then we can use UnregisterHotKey to un-hook the key combination.

In Visual Studio, we have "composite", 2-step "chords" hotkeys:

  • Ctrl+R, Ctrl+R triggers refactor / rename
  • Ctrl+R, Ctrl+M triggers refactor / extract method

I'm trying to think of a good way of doing exactly this, and I thought of several approaches:

  1. Register Ctrl+R as a hotkey, then use a low-level key hook to capture (and swallow) the next keypress.
  2. Register Ctrl+R as a hotkey, and then handle WM_HOTKEY messages by registering all possible 2nd keys for that hotkey; unregister them upon the next keypress. This has the advantage of processing everything as WM_HOTKEY messages.
  3. Don't register any hotkeys. Use a low-level key hook to capture everything, and basically implement the hotkey-messaging logic manually.

What's the better approach, and why? Could I run into stability issues if I go with #2 and start continuously hooking and un-hooking stuff? Is there another way I haven't thought of? How are Visual Studio and ReSharper doing it?

  • You should consider Visual Studio's Ctrl+A (Select All), Ctrl+R, A (Run all Tests) and Ctrl+R, Ctrl+A (Debug all tests). In your 2nd approach, you'd need to determine how to handle the Ctrl+A depending on whether it was the first or second leg of a chord. – ThunderFrame Mar 29 '16 at 2:19

It seems that Visual Studio allows F12 as a shortcut key, while RegisterHotKey won't allow F12, so Visual Studio does not appear to be using RegisterHotKey.

This approach uses GetAsyncKeyState so it's avoiding RegisterHotKey without going too low-level, and it uses delegates to handle the hotkeys. It doesn't implement 2-step chords, but looking at the way it captures the modifiers, it looks like it could be expanded to handle chords.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.