1
26 using System;
27 using System.Diagnostics;
28 using System.Windows.Forms;
29 using System.Runtime.InteropServices;
30 using System.Text;
31
32 public class KeyboardHook : IDisposable
36 {
37 public enum Parameters
41 {
42 None,
43 AllowAltTab,
44 AllowWindowsKey,
45 AllowAltTabAndWindows,
46 PassAllKeysToNextApp
47 }
48
49
50 private bool PassAllKeysToNextApp = false;
51 private bool AllowAltTab = false;
52 private bool AllowWindowsKey = false;
53
54
55 private const int WH_KEYBOARD_LL = 13;
56 private const int WM_KEYUP = 0x0101;
57 private const int WM_SYSKEYUP = 0x0105;
58
59
60 private const int VK_SHIFT = 0x10;
61 private const int VK_CONTROL = 0x11;
62 private const int VK_MENU = 0x12;
63 private const int VK_CAPITAL = 0x14;
64
65
66 private HookHandlerDelegate proc;
67 private IntPtr hookID = IntPtr.Zero;
68 internal delegate IntPtr HookHandlerDelegate(
69 int nCode, IntPtr wParam, ref KBDLLHOOKSTRUCT lParam);
70
71 public event KeyboardHookEventHandler KeyIntercepted;
76
77
78 internal struct KBDLLHOOKSTRUCT
79 {
80 public int vkCode;
81 int scanCode;
82 public int flags;
83 int time;
84 int dwExtraInfo;
85 }
86
87 #region Constructors
88 public KeyboardHook()
93 {
94 proc = new HookHandlerDelegate(HookCallback);
95 using (Process curProcess = Process.GetCurrentProcess())
96 using (ProcessModule curModule = curProcess.MainModule)
97 {
98 hookID = NativeMethods.SetWindowsHookEx(WH_KEYBOARD_LL, proc,
99 NativeMethods.GetModuleHandle(curModule.ModuleName), 0);
100 }
101 }
102
103 public KeyboardHook(string param)
109 : this()
110 {
111 if (!String.IsNullOrEmpty(param) && Enum.IsDefined(typeof(Parameters), param))
112 {
113 SetParameters((Parameters)Enum.Parse(typeof(Parameters), param));
114 }
115 }
116
117 public KeyboardHook(Parameters param)
122 : this()
123 {
124 SetParameters(param);
125 }
126
127 private void SetParameters(Parameters param)
128 {
129 switch (param)
130 {
131 case Parameters.None:
132 break;
133 case Parameters.AllowAltTab:
134 AllowAltTab = true;
135 break;
136 case Parameters.AllowWindowsKey:
137 AllowWindowsKey = true;
138 break;
139 case Parameters.AllowAltTabAndWindows:
140 AllowAltTab = true;
141 AllowWindowsKey = true;
142 break;
143 case Parameters.PassAllKeysToNextApp:
144 PassAllKeysToNextApp = true;
145 break;
146 }
147 }
148 #endregion
149
150 #region Check Modifier keys
151 private void CheckModifiers()
158 {
159 StringBuilder sb = new StringBuilder();
160
161 if ((NativeMethods.GetKeyState(VK_CAPITAL) & 0x0001) != 0)
162 {
163
164 sb.AppendLine("Capslock is enabled.");
165 }
166
167 if ((NativeMethods.GetKeyState(VK_SHIFT) & 0x8000) != 0)
168 {
169
170 sb.AppendLine("Shift is pressed.");
171 }
172 if ((NativeMethods.GetKeyState(VK_CONTROL) & 0x8000) != 0)
173 {
174
175 sb.AppendLine("Control is pressed.");
176 }
177 if ((NativeMethods.GetKeyState(VK_MENU) & 0x8000) != 0)
178 {
179
180 sb.AppendLine("Alt is pressed.");
181 }
182 Console.WriteLine(sb.ToString());
183 }
184 #endregion Check Modifier keys
185
186 #region Hook Callback Method
187 private IntPtr HookCallback(
191 int nCode, IntPtr wParam, ref KBDLLHOOKSTRUCT lParam)
192 {
193 bool AllowKey = PassAllKeysToNextApp;
194
195
196 if (nCode >= 0 &&
197 (wParam == (IntPtr)WM_KEYUP || wParam == (IntPtr)WM_SYSKEYUP))
198 {
199
200
201
202
203
204
205 if (!(lParam.vkCode >= 160 && lParam.vkCode <= 164))
206 {
207 CheckModifiers();
208 }
209
210
211
212
213
214 if (AllowWindowsKey)
215 {
216 switch (lParam.flags)
217 {
218
219 case 0:
220 if (lParam.vkCode == 27)
221 AllowKey = true;
222 break;
223
224
225 case 1:
226 if ((lParam.vkCode == 91) || (lParam.vkCode == 92))
227 AllowKey = true;
228 break;
229 }
230 }
231
232 if (AllowAltTab)
233 {
234 if ((lParam.flags == 32) && (lParam.vkCode == 9))
235 AllowKey = true;
236 }
237
238 OnKeyIntercepted(new KeyboardHookEventArgs(lParam.vkCode, AllowKey));
239
240
241 if (AllowKey == false)
242 return (System.IntPtr)1;
243 }
244
245 return NativeMethods.CallNextHookEx(hookID, nCode, wParam, ref lParam);
246
247 }
248 #endregion
249
250 #region Event Handling
251 public void OnKeyIntercepted(KeyboardHookEventArgs e)
256 {
257 if (KeyIntercepted != null)
258 KeyIntercepted(e);
259 }
260
261 public delegate void KeyboardHookEventHandler(KeyboardHookEventArgs e);
266
267 public class KeyboardHookEventArgs : System.EventArgs
271 {
272
273 private string keyName;
274 private int keyCode;
275 private bool passThrough;
276
277 public string KeyName
281 {
282 get { return keyName; }
283 }
284
285 public int KeyCode
289 {
290 get { return keyCode; }
291 }
292
293 public bool PassThrough
298 {
299 get { return passThrough; }
300 }
301
302 public KeyboardHookEventArgs(int evtKeyCode, bool evtPassThrough)
303 {
304 keyName = ((Keys)evtKeyCode).ToString();
305 keyCode = evtKeyCode;
306 passThrough = evtPassThrough;
307 }
308
309 }
310
311 #endregion
312
313 #region IDisposable Members
314 public void Dispose()
318 {
319 NativeMethods.UnhookWindowsHookEx(hookID);
320 }
321 #endregion
322
323 #region Native methods
324
325 [ComVisibleAttribute(false),
326 System.Security.SuppressUnmanagedCodeSecurity()]
327 internal class NativeMethods
328 {
329 [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
330 public static extern IntPtr GetModuleHandle(string lpModuleName);
331
332 [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
333 public static extern IntPtr SetWindowsHookEx(int idHook,
334 HookHandlerDelegate lpfn, IntPtr hMod, uint dwThreadId);
335
336 [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
337 [return: MarshalAs(UnmanagedType.Bool)]
338 public static extern bool UnhookWindowsHookEx(IntPtr hhk);
339
340 [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
341 public static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
342 IntPtr wParam, ref KBDLLHOOKSTRUCT lParam);
343
344 [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)]
345 public static extern short GetKeyState(int keyCode);
346
347 }
348
349
350 #endregion
351 }