By Hook or by Crook

Tags: .NET, CodeSnippets

While trying to implement custom shortcut keys in Outlook, I came across an old column by Dino Esposito on implementing custom Windows hooks in .NET. At first I wanted to use it as reference and inspiration only, and only when I finished did I notice I simply rewrote, from scratch, most of the code he offers in his article. The main difference is that he supplies a base, generic WindowsHook class and a derived CBTHook class to handle window opening/closing/etc events, while I implemented my generic parent class and a derived KeyboardHook class for keyboard events. This is implemented as thread-local hooks on the currently running process, rather than expensive global system hooks.

The basic premise is simple - keep all the Win32 P/Invoke code well hid inside the private implementation, and have the WindowsHook class simply raise an event when the hook function is invoked, passing the hook function paraemeters as event args to the HookInvoked event.

However, since the hook parameters are different for each kind of hook, the KeyboardHook class also raises a different event, KeyPressed, that parses the hook parameters and gives more intelligble and specific meaning to the parameters - which key was pressed, as well as the state of the Control, Alt and Shift keys.

Additionally, the KeyboardHook class allows setting filters, so that the event will only be raised for specific keystrokes. This allows us to get only the keystrokes we want (say, our chosen keyboard shortcut keys).

Code such as this sample will raise the KeyPressed event whenever the user presses Ctrl-Shift-F, or Alt-F6:

KeyboardHook hook;
private void Form1_Load(object sender, System.EventArgs e)
{
  hook = new KeyboardHook();
  hook.AddFilter(Keys.F, true, false, true);
  hook.AddFilter(Keys.F6, false, true, false);
  hook.KeyPressed +=new KeyboardHookEventHandler(hook_KeyPressed);
  hook.Install();
}

KeyboardHook hook;
private void Form1_Load(object sender, System.EventArgs e)
{
  hook = new KeyboardHook();
  hook.AddFilter(Keys.F, true, false, true);
  hook.AddFilter(Keys.F6, false, true, false);
  hook.KeyPressed +=new KeyboardHookEventHandler(hook_KeyPressed);
  hook.Install();
}

private void hook_KeyPressed(object sender, KeyboardHookEventArgs e)
{
  this.label1.Text = "Found " + e.KeyStroke.ToString();
}

void hook_KeyPressed(object sender, KeyboardHookEventArgs e)
{
  this.label1.Text = "Found " + e.KeyStroke.ToString();
}

Full code for this class can be found in the attached ZIP file.

And thanks, again, to Dino Esposito for the inspiration, not to mention blatant plagiarism. :)

3 Comments

Comments have been disabled for this content.