Extending the .NET Windows Forms to respond to System Wide HotKeys

HotKeyForm Demonstration

One of the Windows API features which isn't included in the .NET Framework is setting up and receiving notifications from system-wide HotKeys. This article presents an extended version of System.Windows.Forms.Form which adds HotKey functionality.

HotKeys in Win32

Win32 allows you to set up combinations of key-presses which can be associated with an application on a system-wide scope, called Hotkeys. When a user presses a registered HotKey it doesn't matter which application is active when they pressed it, the hot-key message will get routed to your application.

There are two types of HotKeys:

  • Application activation HotKeys
    These are the simplest type. When the HotKey is selected your application is activated. They are very simple to set up but they only activate your application - you can't determine if this was due to the HotKey being pressed nor take any other action.
  • Registered HotKeys
    This type of HotKey sends a WM_HOTKEY message to your application when the HotKey is pressed. so you can choose how to respond to the key. Setting up this type is slightly more complex and you need to be able to respond to the WM_HOTKEY message through the application's form WndProc to work with the HotKey message.

This article describes how to create and respond to the second type, Registered HotKeys.

Registering a HotKey

Registering a system-wide HotKey is achieved in two steps:

  1. Creating a globally unique identifier for the HotKey. You do this using the Win32 Global Atom database.
  2. Registering the HotKey itself.

1. The Win32 Atom Databases

Win32 Atom databases store a list of unique strings which are internally identified by a 16 bit integer ID. The Global Atom database creates string lists which are accessible to all processes. In addition to this each process on the system can have its own Local Atom database. These functions could be quite useful for other purposes - if you need to store a list of unique strings and IDs in an application, you could take advantage of the Atom database to do it. However, as there is only one atom database per process you would have to be careful! Note that an applications process includes both the executable and any OCXs or DLLs being used in that executable.

The Global Atom database functions in Win32 are GlobalAddAtom, GlobalDeleteAtom, GlobalFindAtom and GlobalGetAtomName. The first step of registering a HotKey is to create a string that is unlikely to be in use by any other application on the system and then get an ID for it by calling GlobalAddAtom for that string. In the download string is created by specifying a local key string to which the current GetTickCount value is appended.

2. Registering the HotKey

Registering the key itself is acheived using Win32's unusually sensibly named RegisterHotKey function. This takes the window handle you want to send the messages to, the globally unique identifier you created using the Global Atom database, a bit flag containing the Shift, Ctrl, Alt or Windows Key keys which have to be pressed for the HotKey and the Virtual Key Code of the key you want to register. Note that in .NET the System.Windows.Forms.Keys enumeration corresponds directly to the Win32 Virtual Key Code constants. These are the key values that are passed to you in the KeyUp and KeyDown events.

Responding to HotKeys

Once you've set up a HotKey, you can respond to it by responding to the WM_HOTKEY message sent to the window by overriding a form's WndProc. The message's wParam of the WM_HOTKEY message contains the globally unique identifier you assigned to the HotKey, and the lParam contains the virtual key code in the HiWord and the key modifiers in the LoWord.

Putting it all Together

To make this easy to use, the download contains an extended version of System.Windows.Forms.Form which includes all of the functionality you need to set up and respond to hotkeys. This is stored within the HotKeyFormLib class in the namespace vbAccelerator.Components.HotKey. The implementation consists of the following classes:

  • HotKeyForm
    An extended version of System.Windows.Forms.Form which includes HotKey functionality
  • HotKeyCollection
    A collection (extended from the generic ArrayList implementation provided in CollectionBase) which enables you to add, remove and enumerate HotKeys associated with the form.
  • HotKey
    A class for configuring HotKeys.
  • HotKeyPressedEventArgs
    An EventArgs type containing the HotKey which has been pressed.
  • HotKeyAddException
    An extended System.Exception which is thrown if adding a HotKey fails.

To use the library, simply add the relevant version of HotKeyFormLib to your project. Then modify the form you want to respond to HotKeys to be a HotKeyForm rather than a System.Windows.Forms.Form. Now you can start adding hotkeys and responding to events.

To add a HotKey, create a new instance of the HotKey class and set the Name, KeyCode and Modifier properties. There is a constructor which enables you to do this all at one time. Then add the HotKey to the hot key collection using the HotKeys property.

Once you've added the HotKey, you will want to respond to any events. The event raised by the is called HotKeyPressed and also has a corresponding delegate called HotKeyPressedEventHandler. The event parameter to this method contains the HotKey which has been pressed.

Try The Sample

The samples provided register Ctrl+Shift+Up as a HotKey and respond to presses by bringing the application to the foreground, regardless of whether it is hidden or minimised when the hot key is pressed. Another application which uses this code is the "ZoomIn" utility, which uses it to allow you to take dynamic snapshots of screen areas regardless of whether you are clicking on a button in the application you're Zooming in on.