Easy Way Global Keyboard Hooking In .NET Application

I was looking for a way to use global keyboard hooking in my personal .net application and I came to know that there is no easy way of doing it. So I designed this particular class, which is really easy to use for simple purposes without requiring you to understand any thing. But it is always good to study, you can download these from below & modify as per your requirements & any suggestions are welcomed as well.

SIMPLE USAGE OF CLASS

   1: static class Program
   2:     {
   3:         /// <summary>
   4:         /// The main entry point for the application.
   5:         /// </summary>
   6:         [STAThread]
   7:         static void Main()
   8:         {
   9:             Application.EnableVisualStyles();
  10:             Application.SetCompatibleTextRenderingDefault(false);
  11:  
  12:             KeyboardHook.SetHook(   () => MessageBox.Show("Hello From Hook "),
  13:                                     KeyboardHook.BeginKeys.Control_Shift,KeyboardHook.EndKey.A );
  14:  
  15:             Application.Run(new Form1());
  16:             KeyboardHook.UnhookWindowsHook();
  17:         }
  18:     }

You just need to add methods calls to SetHook and UnhookWindowsHook as shown above in code sample. The first parameter of SetHook method takes a function which takes no parameters & returns no value. The second and third parameter together forms a valid keyboard shortcut. So the function passed in first parameter will be called every time when the user presses Ctrl+Shift+A irrespective of application is currently active or not since it is using global hooking. Remember its very important to call the method UnhookWindowsHook when done, so that there are no leaks because the KeyboardHook class is just a wrapper and it uses P/Invoke calls to do all dirty work.

DESIGN OF KEYBOARDHOOK CLASS

   1: using System;
   2: using System.Diagnostics;
   3: using System.Runtime.InteropServices;
   4: using System.Windows.Forms;
   5:  
   6: public static class KeyboardHook
   7: {
   8:     #region ExternMethods
   9:  
  10:     [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
  11:     private static extern IntPtr SetWindowsHookEx(int idHook,
  12:         LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
  13:  
  14:     [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
  15:     [return: MarshalAs(UnmanagedType.Bool)]
  16:     private static extern bool UnhookWindowsHookEx(IntPtr hhk);
  17:  
  18:     [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
  19:     private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
  20:         IntPtr wParam, IntPtr lParam);
  21:  
  22:     [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
  23:     private static extern IntPtr GetModuleHandle(string lpModuleName);
  24:  
  25:     #endregion
  26:  
  27:     public enum BeginKeys
  28:     {
  29:         Alt_Control = Keys.Alt | Keys.Control,
  30:         Alt_Shift = Keys.Alt | Keys.Shift,
  31:         Control_Shift = Keys.Control | Keys.Shift,
  32:         Alt_Control_Shift = Keys.Alt | Keys.Control | Keys.Shift,
  33:     } ;
  34:  
  35:     public enum EndKey
  36:     {
  37:         A = Keys.A, B = Keys.B, C = Keys.C, D = Keys.D, E = Keys.E, F = Keys.F, G = Keys.G, H = Keys.H,
  38:         I = Keys.I, J = Keys.J, K = Keys.K, L = Keys.L, M = Keys.M, N = Keys.N, O = Keys.O, P = Keys.P,
  39:         Q = Keys.Q, R = Keys.R, S = Keys.S, T = Keys.T, U = Keys.U, V = Keys.V, W = Keys.W, X = Keys.X,
  40:         Y = Keys.Y, Z = Keys.Z
  41:     } ;
  42:  
  43:     public static void SetHook(Action act,BeginKeys b, EndKey e)
  44:     {
  45:         _beginKeys = b;
  46:         _endKey = e;
  47:         _action = act;
  48:  
  49:         _hookID = SetHook(_proc);
  50:     }
  51:  
  52:     public static void UnhookWindowsHook()
  53:     {
  54:         UnhookWindowsHookEx(_hookID);
  55:     }
  56:  
  57:     private delegate IntPtr LowLevelKeyboardProc(
  58:                     int nCode, IntPtr wParam, IntPtr lParam);
  59:  
  60:     private const int WH_KEYBOARD_LL = 13;
  61:     private const int WM_KEYDOWN = 0x0100;
  62:     private const int WM_SYSKEYDOWN = 0x0104;
  63:     private static LowLevelKeyboardProc _proc = HookCallback;
  64:     private static IntPtr _hookID = IntPtr.Zero;
  65:     private static BeginKeys _beginKeys;
  66:     private static EndKey _endKey;
  67:     private static Action _action;
  68:  
  69:     private static IntPtr SetHook(LowLevelKeyboardProc proc)
  70:     {
  71:         using (Process curProcess = Process.GetCurrentProcess())
  72:         using (ProcessModule curModule = curProcess.MainModule)
  73:         {
  74:             return SetWindowsHookEx(WH_KEYBOARD_LL, proc,
  75:                                          GetModuleHandle(curModule.ModuleName), 0);
  76:         }
  77:     }
  78:  
  79:     private static IntPtr HookCallback(
  80:                         int nCode, IntPtr wParam, IntPtr lParam)
  81:     {
  82:         if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN || wParam == (IntPtr)WM_SYSKEYDOWN)
  83:         {
  84:             int vkCode = Marshal.ReadInt32(lParam);
  85:             if ((Keys)(_endKey) == (Keys)vkCode && (Keys)_beginKeys == Control.ModifierKeys)
  86:             {
  87:                 _action();
  88:             }
  89:         }
  90:         return CallNextHookEx(_hookID, nCode, wParam, lParam);
  91:     }
  92: }

Attachments : Hook.cs File, Sample Keyboard Hook Project [ VS 2008 ]

In next post i will show you how i used this class to hide my personal .NET application using a keyboard shortcut and then displaying it back from same keyboard shortcut.

Cheers

kick it on DotNetKicks.com

About these ads
This entry was posted in Uncategorized. Bookmark the permalink.

10 Responses to Easy Way Global Keyboard Hooking In .NET Application

  1. Danny says:

    Thank you – that is a genuinely useful class. Shame it can only be done using unmanaged DLL calls, it is the kind of thing you would thing the framework would include. Perhaps in the next .net iteration we will see it.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s