Hot Keys

I will be describing two types of hot keys here: application hotkeys and system-wide hotkeys.
Application hotkeys will be processed when your application is the active application, the key press anywhere else in the system will not alert your application. On the other hand a system-wide hotkey will alert your application whenever the key combination is pressed, no matter where the user is.

Application Hot Keys

Application hotkeys are provided by overriding WndProc and obtaining the Key Down events. Every window has an associated window procedure, which all messages are sent to. So, when a user presses down a key, a message is sent to the window to process that key. We will intercept all of the key down messages, check if they are the key we are looking for, and react if so.

Here is the override method for WndProc:

protected override void WndProc(ref Message m)
        {
            base.WndProc(ref m);
        }

As part of the message we can retrieve the virtual key code and some other information such as the context code, repeat count, extended-key flag, etc. The virtual key code is in the wParam, and the extra information in the lParam.

You can find out more about lParm and the WM_KEYDOWN message at http://msdn.microsoft.com/en-us/library/ms646280(VS.85).aspx

So, to retrieve what key was pressed, we cast it to a Keys object. Then using a simple switch statement we can respond to this key press.

(You can check WinUser.h for the uint values for other messages you are able to intercept)

const uint WM_KEYDOWN = 0x0100;
 
protected override void WndProc(ref Message m)
        {
            if (m.Msg == WM_KEYDOWN)
            {
                Keys key = (Keys) m.WParam;
 
                switch(key)
                {
                    case Keys.Delete:
                        MessageBox.Show("You pressed the delete key!");
                        break;
                }
            }
            base.WndProc(ref m);
        }

This code will be able to pick up all key presses bar the system key presses (a key that is pressed along with the ALT key).

System-Wide Hot Keys

To set system wide hot keys we need to make use of interop to call some native Windows API. So, we need to include the System.Runtime.InteropServices namespace in our class.

The three API functions we will be using are:

[DllImport("user32", SetLastError = true)]
private static extern int RegisterHotKey(IntPtr hwnd, uint id, int fsModifiers, int vk);
 
[DllImport("user32", SetLastError = true)]
private static extern int UnregisterHotKey(IntPtr hwnd, uint id);
 
[DllImport("kernel32.dll", SetLastError=true, CharSet=CharSet.Auto)]
static extern ushort GlobalAddAtom(string lpString);

The first two functions are self-explanatory, as for the third, it will add a specified string to the global atom table and return a unique value (the atom) for that string. We want our hot key to have a unique ID so we will use this method.

We also have a few constant key codes, the wndproc message code we will be looking out for and a variable to hold our id:

const uint MOD_ALT = 0x0001;
const uint MOD_CONTROL = 0x0002;
const uint MOD_SHIFT = 0x0004;
const uint MOD_WIN = 0x0008;
 
const uint WM_HOTKEY = 0x0312;
 
ushort id;

The parameters of the RegisterHotKey call are:

hwnd: The handle of a window that will receive the messages generated by the hot key.
id: The hot key’s identifier.
fsmodifiers: The keys that must be pressed in combination with the key in the vk parameter to fire the hot key message.
vk: The virtual-key code of the hot key.

Our parameters will be as follows. We want our main application window to handle the event messages, so the first parameter will be the handle of our application. The ID will be returned by the GlobalAddAtom function. For FSModifiers, we will use the Windows Key. The virtual key code will be that from the ‘K’ key.

To register our hotkey:

id = GlobalAddAtom("Luke's Brilliant Appplication");
RegisterHotKey(this.Handle, id, MOD_WIN, (int)Keys.K);

Then we need to unregister it when are finished:

UnregisterHotKey(this.Handle, id);

The first parameter of the unregister hot key function specifies the window handle and the second, the id of the hot key.

After registering the hot key we will receive the hot key message when it is used, we need to keep an eye out and react to that message. To do this, we override WndProc and check the message coming in. If it is that our hot key has been pressed, then we respond accordingly.

protected override void WndProc(ref Message m)
        {
            if (m.Msg == WM_HOTKEY)
            {
                MessageBox.Show("You pressed the Windows Key and the K Key!");
            }
 
            base.WndProc(ref m);
        }

You can find out more about the following functions:

RegisterHotKey: http://msdn.microsoft.com/en-us/library/ms646309(VS.85).aspx
UnregisterHotKey: http://msdn.microsoft.com/en-us/library/ms646327(VS.85).aspx
GlobalAddAtom: http://msdn.microsoft.com/en-us/library/ms649060(v=VS.85).aspx