Search
Module:
Directory

   Desktop Functions:

   Smart Device Functions:


Show Recent Changes
Subscribe (RSS)
Misc. Pages
Comments
FAQ
Helpful Tools
Playground
Suggested Reading
Website TODO List
Download Visual Studio Add-In

RegisterHotKey (user32)
 
.
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 RegisterHotKeyaspx 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!

HotKeyRegister Class:

    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

Please edit this page!

Do you have...

  • helpful tips or sample code to share for using this API in managed code?
  • corrections to the existing content?
  • variations of the signature you want to share?
  • additional languages you want to include?

Select "Edit This Page" on the right hand toolbar and edit it! Or add new pages containing supporting types needed for this API (structures, delegates, and more).

 
Access PInvoke.net directly from VS:
Terms of Use
Find References
Show Printable Version
Revisions