Registering System-Wide Hot Keys
Some Windows applications execute in the background and are activated only as required. To enhance such a program's usability it is useful to register a system-wide hot key. This allows the software to activate when a specific key combination is pressed.
RegisterHotKey API Function
It is a common requirement, when developing Windows Forms software, that an entire program or some element of it will execute in the background. Often, the user will need to interact with the application only occasionally. At this time they will click a system tray icon or press a special key combination to show the user interface. Two good examples of this are Microsoft Outlook, which may be minimised to the system tray, and Launchy, which has no user interface until summoned.
The .NET framework does not provide a simple manner in which to detect keypresses for a Windows Forms application that is not currently active. However, using Platform Invocation Services (P/Invoke), we can call a Windows API function that registers a system-wide hot key and links it to a form. Once registered, if the user presses the specified key, or combination of keys, a message will automatically be sent to the appropriate form. This message will be received even if the form is inactive.
Hot Key Sample
In this article we will create a simple Windows Forms program that includes registering a hot key. When the key is pressed, the program's form will be activated. To begin, create a new Windows Forms application. The project should include a single form by default. All of the code for the sample will be contained within this form.
Declaring the API Functions
As the code in this sample uses P/Invoke, we will be using attributes from the System.Runtime.InteropServices namespace. To keep the code as simple to read as possible, add the following using directive to the top of the form's code file.
There are two API functions that should be used when registering system-wide hot keys. The first is used to set up the hot key and is named "RegisterHotKey". The second function is used to remove the registration when it is no longer required. This is named "UnregisterHotKey".
To declare the two functions, add the following code within the form class' code block.
private static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vlc);
private static extern bool UnregisterHotKey(IntPtr hWnd, int id);
The RegisterHotKey uses the following four parameters:
- hWnd. The hWnd parameter is used to specify a handle to the window that should receive messages when the hot key is pressed. In the sample we will provide the handle of the form using its in-built Handle property.
- id. Each hot key is registered with an identification number using this parameter. This value is unique for the specified window handle. If the id is already in use, the previous registration is replaced with a new version.
- fsModifiers. Hot keys are almost always registered as a combination of keys so that they are less likely to interfere with the operation of other software. The fsModifiers parameter is used to specify one or more keys that must be pressed at the same time as the hot key. The modifiers can be Ctrl, Alt, Shift, the Windows key or any combination of these four keys.
- vlc. The final parameter is used to provide the virtual key code for the hot key itself.
The function returns a Boolean value. If the process is successful, the value will be true. If it fails, the return value will be false. A failure usually indicates that the hot key combination is already in use or is reserved by the operating system.
The UnregisterHotKey uses the first two of the above parameters only. It does not need to be provided with the hot key or the modifiers, as the combination of handle and unique ID provides enough information to remove the registration.
Hot Key API Constants
When calling the RegisterHotKey function, the fsModifiers parameter is used to specify which keys must be used in conjunction with the hot key to trigger a message. In the rare instance that the hot key is to be used in isolation, you should pass zero to this parameter. In all other cases, you should pass a value that represents the combination of the four possible modifier keys that you wish to register.
To improve the readability and maintainability of the code, we will declare four constants within the form's class to represent the four modifier keys. To use more than one of the modifier keys, the appropriate constants can be combined using the bitwise OR operator.
To declare the four constants, add the code below to the form's class. This includes a fifth constant named "WM_HOTKEY". This constant holds a value that represents the type of message that is sent when a hot key is pressed. We will use this value when processing incoming messages to filter out other message types.
const int MOD_ALT = 0x1;
const int MOD_CONTROL = 0x2;
const int MOD_SHIFT = 0x4;
const int MOD_WIN = 0x8;
const int WM_HOTKEY = 0x312;
Registering the Hot Key
Now that we have added the Windows API functions and associated constants, we can register a hot key during the Load event of our form. We will register the keyboard combination of the Windows key and Q, so that whenever these two keys are pressed simultaneously a message will be sent to the form. We will add the code to react to the message later in the article.
To register the hot key, use the form designer to add the Load event to the form and then modify the event's code as shown below:
private void Form1_Load(object sender, EventArgs e)
MessageBox.Show(RegisterHotKey((IntPtr)Handle, 1, MOD_WIN, (int)Keys.Q).ToString());
You can see that the first parameter uses the handle of the form, cast as IntPtr, to specify the window that will receive the message. The unique ID for the registered key is 1. The last two parameters specify that the Windows key will be the modifier and that Q is the hot key. If this key combination is already in use on your system, or if you do not have a Windows key, modify these parameters to select different options. Note also that the return value of the function is being converted to a string and displayed in a message box. This will allow you to see whether the registration is successful or not. In production code you should obtain the return value and react appropriately to a registration failure.
14 June 2009