registerhotkey (user32)
Last changed: -86.11.174.174

.
Summary
Defines a system-wide hot key.

C# Signature:

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool RegisterHotKey(IntPtr hWnd, int id, KeyModifiers fsModifiers, Keys vk);

VB Signature:

Declare Function RegisterHotKey Lib "user32.dll" (TODO) As TODO

User-Defined Types:

None.

Alternative Managed API:

Do you know one? Please contribute it!

Notes:

None.

Tips & Tricks:

Please add some!

KeyModifiers Enum:

    [Flags]
    public enum KeyModifiers
    {
    None = 0,
    Alt = 1,
    Control = 2,
    Shift = 4,
    // Either WINDOWS key was held down. These keys are labeled with the Windows logo.
    // Keyboard shortcuts that involve the WINDOWS key are reserved for use by the
    // operating system.
    Windows = 8
    }

HotKeyRegister Class (Source: https://code.msdn.microsoft.com/CSRegisterHotkey-e3f5061e ):

    public class HotKeyRegister : IMessageFilter, IDisposable
    {
    /// <summary>
    /// Define a system-wide hot key.
    /// </summary>
    /// <param name="hWnd">
    /// A handle to the window that will receive WM_HOTKEY messages generated by the
    /// hot key. If this parameter is NULL, WM_HOTKEY messages are posted to the
    /// message queue of the calling thread and must be processed in the message loop.
    /// </param>
    /// <param name="id">
    /// The identifier of the hot key. If the hWnd parameter is NULL, then the hot
    /// key is associated with the current thread rather than with a particular
    /// window.
    /// </param>
    /// <param name="fsModifiers">
    /// The keys that must be pressed in combination with the key specified by the
    /// uVirtKey parameter in order to generate the WM_HOTKEY message. The fsModifiers
    /// parameter can be a combination of the following values.
    /// MOD_ALT     0x0001
    /// MOD_CONTROL 0x0002
    /// MOD_SHIFT   0x0004
    /// MOD_WIN     0x0008
    /// </param>
    /// <param name="vk">The virtual-key code of the hot key.</param>
    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern bool RegisterHotKey(IntPtr hWnd, int id,
        KeyModifiers fsModifiers, Keys vk);

    /// <summary>
    /// Frees a hot key previously registered by the calling thread.
    /// </summary>
    /// <param name="hWnd">
    /// A handle to the window associated with the hot key to be freed. This parameter
    /// should be NULL if the hot key is not associated with a window.
    /// </param>
    /// <param name="id">
    /// The identifier of the hot key to be freed.
    /// </param>
    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern bool UnregisterHotKey(IntPtr hWnd, int id);

    /// <summary>
    /// Get the modifiers and key from the KeyData property of KeyEventArgs.
    /// </summary>
    /// <param name="keydata">
    /// The KeyData property of KeyEventArgs. The KeyData is a key in combination
    /// with modifiers.
    /// </param>
    /// <param name="key">The pressed key.</param>
    public static KeyModifiers GetModifiers(Keys keydata, out Keys key)
    {
        key = keydata;
        KeyModifiers modifers = KeyModifiers.None;

        // Check whether the keydata contains the CTRL modifier key.
        // The value of Keys.Control is 131072.
        if ((keydata & Keys.Control) == Keys.Control)
        {
        modifers |= KeyModifiers.Control;

        key = keydata ^ Keys.Control;
        }

        // Check whether the keydata contains the SHIFT modifier key.
        // The value of Keys.Control is 65536.
        if ((keydata & Keys.Shift) == Keys.Shift)
        {
        modifers |= KeyModifiers.Shift;
        key = key ^ Keys.Shift;
        }

        // Check whether the keydata contains the ALT modifier key.
        // The value of Keys.Control is 262144.
        if ((keydata & Keys.Alt) == Keys.Alt)
        {
        modifers |= KeyModifiers.Alt;
        key = key ^ Keys.Alt;
        }

        // Check whether a key other than SHIFT, CTRL or ALT (Menu) is pressed.
        if (key == Keys.ShiftKey || key == Keys.ControlKey || key == Keys.Menu)
        {
        key = Keys.None;
        }

        return modifers;
    }

    /// <summary>
    /// Specify whether this object is disposed.
    /// </summary>
    bool disposed = false;

    /// <summary>
    /// This constant could be found in WinUser.h if you installed Windows SDK.
    /// Each windows message has an identifier, 0x0312 means that the mesage is
    /// a WM_HOTKEY message.
    /// </summary>
    const int WM_HOTKEY = 0x0312;

    /// <summary>
    /// A handle to the window that will receive WM_HOTKEY messages generated by the
    /// hot key.
    /// </summary>
    public IntPtr Handle { get; private set; }

    /// <summary>
    /// A normal application can use any value between 0x0000 and 0xBFFF as the ID
    /// but if you are writing a DLL, then you must use GlobalAddAtom to get a
    /// unique identifier for your hot key.
    /// </summary>
    public int ID { get; private set; }

    public KeyModifiers Modifiers { get; private set; }

    public Keys Key { get; private set; }

    /// <summary>
    /// Raise an event when the hotkey is pressed.
    /// </summary>
    public event EventHandler HotKeyPressed;


    public HotKeyRegister(IntPtr handle, int id, KeyModifiers modifiers, Keys key)
    {
        if (key == Keys.None || modifiers == KeyModifiers.None)
        {
        throw new ArgumentException("The key or modifiers could not be None.");
        }

        this.Handle = handle;
        this.ID = id;
        this.Modifiers = modifiers;
        this.Key = key;

        RegisterHotKey();

        // Adds a message filter to monitor Windows messages as they are routed to
        // their destinations.
        Application.AddMessageFilter(this);
    }


    /// <summary>
    /// Register the hotkey.
    /// </summary>
    private void RegisterHotKey()
    {
        bool isKeyRegisterd = RegisterHotKey(Handle, ID, Modifiers, Key);

        // If the operation failed, try to unregister the hotkey if the thread
        // has registered it before.
        if (!isKeyRegisterd)
        {
        // IntPtr.Zero means the hotkey registered by the thread.
        UnregisterHotKey(IntPtr.Zero, ID);

        // Try to register the hotkey again.
        isKeyRegisterd = RegisterHotKey(Handle, ID, Modifiers, Key);

        // If the operation still failed, it means that the hotkey was already
        // used in another thread or process.
        if (!isKeyRegisterd)
        {
            throw new ApplicationException("The hotkey is in use");
        }
        }
    }

    /// <summary>
    /// Filters out a message before it is dispatched.
    /// </summary>
    [PermissionSetAttribute(SecurityAction.LinkDemand, Name = "FullTrust")]
    public bool PreFilterMessage(ref Message m)
    {
        // The property WParam of Message is typically used to store small pieces
        // of information. In this scenario, it stores the ID.
        if (m.Msg == WM_HOTKEY
        && m.HWnd == this.Handle
        && m.WParam == (IntPtr)this.ID
        && HotKeyPressed != null)
        {
        // Raise the HotKeyPressed event if it is an WM_HOTKEY message.
        HotKeyPressed(this, EventArgs.Empty);

        // True to filter the message and stop it from being dispatched.
        return true;
        }

        // Return false to allow the message to continue to the next filter or
        // control.
        return false;
    }


    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    /// <summary>
    /// Unregister the hotkey.
    /// </summary>
    protected virtual void Dispose(bool disposing)
    {
        // Protect from being called multiple times.
        if (disposed)
        {
        return;
        }

        if (disposing)
        {

        // Removes a message filter from the message pump of the application.
        Application.RemoveMessageFilter(this);

        UnregisterHotKey(Handle, ID);
        }

        disposed = true;
    }
    }

Sample Code:

Here is a helper class for easily adding a hotkey to WPF Windows.

Usage:

    /// <summary>
    /// Id's to disambiguate multiple hotkey registrations
    /// </summary>
    uint hotKey1, hotKey2;

    // --------------------------------------------------------------------------
    /// <summary>
    /// Once we have a window handle, register for hot keys
    /// </summary>
    // --------------------------------------------------------------------------
    protected override void OnSourceInitialized(EventArgs e)
    {
        base.OnSourceInitialized(e);
        _hotKeys = new HotKeyHelper(this, HandleHotKey);
        hotKey1 = _hotKeys.ListenForHotKey(System.Windows.Forms.Keys.F8, HotKeyModifiers.Control);
        hotKey2 = _hotKeys.ListenForHotKey(System.Windows.Forms.Keys.F9, HotKeyModifiers.WindowsKey | HotKeyModifiers.Shift);
    }

    // --------------------------------------------------------------------------
    /// <summary>
    /// Hotkey handler.  The keyId is the return value from ListenForHotKey()
    /// </summary>
    // --------------------------------------------------------------------------
    void HandleHotKey(int keyId)
    {
        if (keyId == hotKey1)
        {
        // first hotkey was pressed
        }
        else if (keyId == hotKey2)
        {
        // second hotkey was pressed
        }
    }

Helper class:

    /// <summary>
    /// Simpler way to expose key modifiers
    /// </summary>
    [Flags]
    public enum HotKeyModifiers
    {
    Alt = 1,        // MOD_ALT
    Control = 2,    // MOD_CONTROL
    Shift = 4,      // MOD_SHIFT
    WindowsKey = 8,     // MOD_WIN
    }

    // --------------------------------------------------------------------------
    /// <summary>
    /// A nice generic class to register multiple hotkeys for your app
    /// </summary>
    // --------------------------------------------------------------------------
    public class HotKeyHelper : IDisposable
    {
    // Required interop declarations for working with hotkeys
    [DllImport("user32", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool RegisterHotKey(IntPtr hwnd, int id, uint fsModifiers, uint vk);
    [DllImport("user32", SetLastError = true)]
    public static extern int UnregisterHotKey(IntPtr hwnd, int id);
    [DllImport("kernel32", SetLastError = true)]
    public static extern short GlobalAddAtom(string lpString);
    [DllImport("kernel32", SetLastError = true)]
    public static extern short GlobalDeleteAtom(short nAtom);

    public const int WM_HOTKEY = 0x312;

    /// <summary>
    /// The unique ID to receive hotkey messages
    /// </summary>
    public short HotkeyID { get; private set; }

    /// <summary>
    /// Handle to the window listening to hotkeys
    /// </summary>
    private IntPtr _windowHandle;

    /// <summary>
    /// Callback for hot keys
    /// </summary>
    Action<int> _onHotKeyPressed;

    // --------------------------------------------------------------------------
    /// <summary>
    /// ctor
    /// </summary>
    // --------------------------------------------------------------------------

    public HotKeyHelper(Window handlerWindow, Action<int> hotKeyHandler)
    {
        _onHotKeyPressed = hotKeyHandler;

        // Create a unique Id for this class in this instance
        string atomName = Thread.CurrentThread.ManagedThreadId.ToString("X8") + this.GetType().FullName;
        HotkeyID = GlobalAddAtom(atomName);

        // Set up the hook to listen for hot keys
        _windowHandle = new WindowInteropHelper(handlerWindow).Handle;
        if(_windowHandle == null)
        {
        throw new ApplicationException("Cannot find window handle.  Try calling this on or after OnSourceInitialized()");
        }
        var source = HwndSource.FromHwnd(_windowHandle);
        source.AddHook(HwndHook);
    }

    // --------------------------------------------------------------------------
    /// <summary>
    /// Intermediate processing of hotkeys
    /// </summary>
    // --------------------------------------------------------------------------
    private IntPtr HwndHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
    {
        if (msg == WM_HOTKEY && wParam.ToInt32() == HotkeyID)
        {
        _onHotKeyPressed?.Invoke(lParam.ToInt32());
        handled = true;
        }
        return IntPtr.Zero;
    }

    // --------------------------------------------------------------------------
    /// <summary>
    /// Tell what key you want to listen for.  Returns an id representing
    /// this particular key combination.  Use this in your handler to
    /// disambiguate what key was pressed.
    /// </summary>
    // --------------------------------------------------------------------------
    public uint ListenForHotKey(Keys key, HotKeyModifiers modifiers)
    {
        RegisterHotKey(_windowHandle, HotkeyID, (uint)modifiers, (uint)key);
        return (uint)modifiers | (((uint)key) << 16);
    }

    // --------------------------------------------------------------------------
    /// <summary>
    /// Stop listening for hotkeys
    /// </summary>
    // --------------------------------------------------------------------------
    private void StopListening()
    {
        if (this.HotkeyID != 0)
        {
        UnregisterHotKey(_windowHandle, HotkeyID);
        // clean up the atom list
        GlobalDeleteAtom(HotkeyID);
        HotkeyID = 0;
        }
    }

    // --------------------------------------------------------------------------
    /// <summary>
    /// Dispose
    /// </summary>
    // --------------------------------------------------------------------------
    public void Dispose()
    {
        StopListening();
    }
    }

Documentation