HotKey – Global shortcuts

 
 
  • Gérald Barré

Hotkeys allow you to associate a key combination with an action. For example, Alt+F4 closes the current application. This action is not set in each application but is set in Windows. I needed to do the same thing in my WindowManager application. Indeed, the application runs in the background and has to react to certain key combinations to move the current window.

As you can imagine this function is quite tricky and therefore requires a minimum of interop. Here are the 2 functions used:

C#
[DllImport("user32.dll", SetLastError = true)]
public static extern bool RegisterHotKey(IntPtr hWnd, int id, ModifierKeys modifiers, Keys keys);

[DllImport("user32.dll", SetLastError = true)]
public static extern bool UnregisterHotKey(IntPtr hWnd, int id);

[Flags]
public enum Modifiers
{
    None = 0x0000,
    Alt = 0x0001,
    Ctrl = 0x0002,
    Shift = 0x0004,
    Win = 0x0008
}
  • hWnd corresponds to the handle of the window:
    • WinForm : myWindow.Handle
    • WPF : new WindowInteropHelper(myWindow).Handle
  • id is a number that will allows you to know which hotkey is triggered
  • ModifierKeys matches keys Control, Alt, Shift and Windows.
  • Keys matches all other keys. In WPF you must add a reference to System.Window.Forms, or recreate the enumeration.

You can declare a shortcut using RegisterHotKey:

C#
RegisterHotKey(Handle, id: 1, ModifierKeys.Control, Keys.A);
RegisterHotKey(Handle, id: 2, ModifierKeys.Control | ModifierKeys.Alt, Keys.B);

Now that the hotkeys are declared, it must be associated with a method. To do this, you must interact with the Windows message loop:

C#
ComponentDispatcher.ThreadPreprocessMessage += ThreadPreprocessMessageMethod;
C#
private void ThreadPreprocessMessageMethod(ref MSG msg, ref bool handled)
{
    const int WmHotKey = 786;
    if (handled || msg.message != WmHotKey)
        return;

    var id = (int)msg.wParam;
    if (id == 1) // Ctrl + A
    {
        // TODO
        handled = true;
    }
    else if (id == 2) // Ctrl + Alt + B
    {
        // TODO
        handled = true;
    }
}

The only thing left to do is to unregister the shortcut when closing the application:

C#
UnregisterHotKey(Handle, id: 1);

All the code is available in the application WindowManager.

Do you have a question or a suggestion about this post? Contact me!

Follow me:
Enjoy this blog?Buy Me A Coffee💖 Sponsor on GitHub