Compact Framework: Global Hotkeys
A long time ago, in a galaxy far far away… well… back when I worked in VB.NET up in Dallas… I wrote a little hot key class for compact framework apps and posted a little bit on how to use it. Of course that was all done in VB.NET and I haven’t used that since the end of 2005. Fast forward 5 years and I find myself using the Compact Framework a lot and needing hotkeys again. So, here is the same code translated into C# (with the help of PInvoke.NET):
1: using System;
2: using System.Windows.Forms;
3: using Microsoft.WindowsCE.Forms;
4: using System.Runtime.InteropServices;
5:
6: namespace CFHotKeys
7: {
8: public class HotKeys
9: {
10: #region dll imports
11:
12: [DllImport("coredll.dll")]
13: private static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vlc);
14:
15: [DllImport("coredll.dll")]
16: private static extern bool UnregisterHotKey(IntPtr hWnd, int id);
17:
18: #endregion
19:
20: public enum KeyModifiers
21: {
22: None = 0,
23: Alt = 1,
24: Control = 2,
25: Shift = 4,
26: Windows = 8,
27: Modkeyup = 0x1000
28: }
29:
30: public delegate void KeyPressedEventHandler(Keys key);
31:
32: public event KeyPressedEventHandler KeyPressed;
33: private readonly HotKeyMessageWindow wnd;
34:
35: public HotKeys()
36: {
37: wnd = new HotKeyMessageWindow(this);
38: }
39:
40: public void Register(Keys Key)
41: {
42: RegisterHotKey(wnd.Hwnd, (int)Key, 0, (int)Key);
43: }
44:
45: public void Register(Keys Key, KeyModifiers Modifier)
46: {
47: RegisterHotKey(wnd.Hwnd, (int)Key, (int)Modifier, (int)Key);
48: }
49:
50: public void UnRegister(Keys Key)
51: {
52: UnregisterHotKey(wnd.Hwnd, (int)Key);
53: }
54:
55: public void OnKeyPressed(Keys key)
56: {
57: //forward the keypress event to the outside world.
58:
59: if (KeyPressed != null)
60: {
61: KeyPressed(key);
62: }
63: }
64:
65: private class HotKeyMessageWindow : MessageWindow
66: {
67: private const int WM_HOTKEY = 0x312;
68: private readonly HotKeys parent;
69:
70: public HotKeyMessageWindow(HotKeys h)
71: {
72: parent = h;
73: }
74:
75: protected override void WndProc(ref Message msg)
76: {
77: switch (msg.Msg)
78: {
79: case WM_HOTKEY:
80: {
81: int keyNum = msg.WParam.ToInt32();
82: Keys key = (Keys) keyNum;
83: parent.OnKeyPressed(key);
84: break;
85: }
86: default:
87: {
88: base.WndProc(ref msg);
89: break;
90: }
91: }
92: }
93: }
94: }
95: }
</div> </div>
You’ll need to add a reference to Microsoft.WindowCE.Forms in your compact framework app.
The hot key interop call technically requires a windows form to receive the hotkey press using a windows message pump handler. This isn’t available in the standard System.Windows.Forms, but it is available in the MessageWindow class in the Microsoft.WindowsCE.Forms assembly. This code instantiates a class that inherits from MessageWindow so that we can handle the hot key press from anywhere in our application, not just from a specific form.
As an example of this being a global hotkey, create a Compact Framework app with a single form in it, and change your Program.cs to look like this:
1: static class Program
2: {
3:
4: private static HotKeys hotKeys;
5:
6: [MTAThread]
7: static void Main()
8: {
9: hotKeys = new HotKeys();
10: hotKeys.Register(Keys.A);
11: hotKeys.KeyPressed += hotKeys_KeyPressed;
12:
13: Application.Run(new Form1());
14: }
15:
16: private static void hotKeys_KeyPressed(Keys key)
17: {
18: switch (key)
19: {
20: case Keys.A:
21: {
22: MessageBox.Show("You pressed A!");
23: break;
24: }
25: default: break;
26: }
27: }
28:
29: }
</div> </div>
Anytime you press the “a” or “A” key in the application, you’ll get a message box that pops up. The API for the HotKeys class could be made quite a bit more elegant, IMO. I don’t really like using switch statements like I showed in the program.cs… I would rather register a hotkey with a delegate that gets fired, like this:
1: private void RegisterHotKeys()
2: {
3: hotKeys.Register(Keys.A, HandleAPress);
4: }
5:
6: private void HandleAPress()
7: {
8: MessageBox.Show("You Presed A!");
9: }
</div> </div>
I don’t want to spoil all the fun of playing with this little snippet of code, though. So I’ll let you, the reader, explore the possibilities of implementing this API. 🙂