C#全局键盘监听(Hook)的使用(转载)
转载 https://www.cnblogs.com/zhaoyuncai/p/7684958.html
稍微有些改动 这里只添加 按键按下
一.为什么需要全局键盘监听?
在某些情况下应用程序需要实现快捷键执行特定功能,例如大家熟知的QQ截图功能Ctrl+Alt+A快捷键,只要QQ程序在运行(无论是拥有焦点还是处于后台运行状态),都可以按下快捷键使用此功能…
这个时候在程序中添加键盘监听肯定不能满足需求了,当用户焦点不在App上时(如最小化,或者用户在处理其它事物等等)键盘监听就失效了
二.怎样才能实现全局键盘监听?
这里需要用到Windows API,源码如下:(可以作为一个工具类[KeyboardHook.cs]收藏起来)
1 using System; 2 using System.Text; 3 using System.Runtime.InteropServices; 4 using System.Reflection; 5 using System.Windows.Forms; 6 7 namespace BAMdp.MouseKeyboardLibrary 8 { 9 public abstract class GlobalHook 10 { 11 #region Windows API Code 12 13 [StructLayout(LayoutKind.Sequential)] 14 protected class POINT 15 { 16 public int x; 17 public int y; 18 } 19 20 [StructLayout(LayoutKind.Sequential)] 21 protected class MouseHookStruct 22 { 23 public POINT pt; 24 public int hwnd; 25 public int wHitTestCode; 26 public int dwExtraInfo; 27 } 28 29 [StructLayout(LayoutKind.Sequential)] 30 protected class MouseLLHookStruct 31 { 32 public POINT pt; 33 public int mouseData; 34 public int flags; 35 public int time; 36 public int dwExtraInfo; 37 } 38 39 [StructLayout(LayoutKind.Sequential)] 40 protected class KeyboardHookStruct 41 { 42 public int vkCode; 43 public int scanCode; 44 public int flags; 45 public int time; 46 public int dwExtraInfo; 47 } 48 49 [DllImport("user32.dll", CharSet = CharSet.Auto, 50 CallingConvention = CallingConvention.StdCall, SetLastError = true)] 51 protected static extern int SetWindowsHookEx( 52 int idHook, 53 HookProc lpfn, 54 IntPtr hMod, 55 int dwThreadId); 56 57 [DllImport("user32.dll", CharSet = CharSet.Auto, 58 CallingConvention = CallingConvention.StdCall, SetLastError = true)] 59 protected static extern int UnhookWindowsHookEx(int idHook); 60 61 62 [DllImport("user32.dll", CharSet = CharSet.Auto, 63 CallingConvention = CallingConvention.StdCall)] 64 protected static extern int CallNextHookEx( 65 int idHook, 66 int nCode, 67 int wParam, 68 IntPtr lParam); 69 70 [DllImport("user32")] 71 protected static extern int ToAscii( 72 int uVirtKey, 73 int uScanCode, 74 byte[] lpbKeyState, 75 byte[] lpwTransKey, 76 int fuState); 77 78 [DllImport("user32")] 79 protected static extern int GetKeyboardState(byte[] pbKeyState); 80 81 [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] 82 protected static extern short GetKeyState(int vKey); 83 84 [DllImport("kernel32.dll")] 85 private static extern IntPtr GetModuleHandle(string name); 86 87 protected delegate int HookProc(int nCode, int wParam, IntPtr lParam); 88 89 protected const int WH_MOUSE_LL = 14; 90 protected const int WH_KEYBOARD_LL = 13; 91 92 protected const int WH_MOUSE = 7; 93 protected const int WH_KEYBOARD = 2; 94 protected const int WM_MOUSEMOVE = 0x200; 95 protected const int WM_LBUTTONDOWN = 0x201; 96 protected const int WM_RBUTTONDOWN = 0x204; 97 protected const int WM_MBUTTONDOWN = 0x207; 98 protected const int WM_LBUTTONUP = 0x202; 99 protected const int WM_RBUTTONUP = 0x205; 100 protected const int WM_MBUTTONUP = 0x208; 101 protected const int WM_LBUTTONDBLCLK = 0x203; 102 protected const int WM_RBUTTONDBLCLK = 0x206; 103 protected const int WM_MBUTTONDBLCLK = 0x209; 104 protected const int WM_MOUSEWHEEL = 0x020A; 105 protected const int WM_KEYDOWN = 0x100; 106 protected const int WM_KEYUP = 0x101; 107 protected const int WM_SYSKEYDOWN = 0x104; 108 protected const int WM_SYSKEYUP = 0x105; 109 110 protected const byte VK_SHIFT = 0x10; 111 protected const byte VK_CAPITAL = 0x14; 112 protected const byte VK_NUMLOCK = 0x90; 113 114 protected const byte VK_LSHIFT = 0xA0; 115 protected const byte VK_RSHIFT = 0xA1; 116 protected const byte VK_LCONTROL = 0xA2; 117 protected const byte VK_RCONTROL = 0x3; 118 protected const byte VK_LALT = 0xA4; 119 protected const byte VK_RALT = 0xA5; 120 121 protected const byte LLKHF_ALTDOWN = 0x20; 122 123 #endregion 124 125 #region Private Variables 126 127 protected int _hookType; 128 protected int _handleToHook; 129 protected bool _isStarted; 130 protected HookProc _hookCallback; 131 132 #endregion 133 134 #region Properties 135 136 public bool IsStarted 137 { 138 get 139 { 140 return _isStarted; 141 } 142 } 143 144 #endregion 145 146 #region Constructor 147 148 public GlobalHook() 149 { 150 151 Application.ApplicationExit += new EventHandler(Application_ApplicationExit); 152 153 } 154 155 #endregion 156 157 #region Methods 158 159 public void Start() 160 { 161 162 if (!_isStarted && 163 _hookType != 0) 164 { 165 166 // Make sure we keep a reference to this delegate! 167 // If not, GC randomly collects it, and a NullReference exception is thrown 168 _hookCallback = new HookProc(HookCallbackProcedure); 169 170 _handleToHook = SetWindowsHookEx( 171 _hookType, 172 _hookCallback, 173 GetModuleHandle(System.Diagnostics.Process.GetCurrentProcess().MainModule.ModuleName), 174 0); 175 //GetModuleHandle(System.Diagnostics.Process.GetCurrentProcess().MainModule.ModuleName 176 //GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName) 177 // Were we able to sucessfully start hook? 178 if (_handleToHook != 0) 179 { 180 _isStarted = true; 181 } 182 183 } 184 185 } 186 187 public void Stop() 188 { 189 190 if (_isStarted) 191 { 192 193 UnhookWindowsHookEx(_handleToHook); 194 195 _isStarted = false; 196 197 } 198 199 } 200 201 protected virtual int HookCallbackProcedure(int nCode, Int32 wParam, IntPtr lParam) 202 { 203 204 // This method must be overriden by each extending hook 205 return 0; 206 207 } 208 209 protected void Application_ApplicationExit(object sender, EventArgs e) 210 { 211 212 if (_isStarted) 213 { 214 Stop(); 215 } 216 217 } 218 219 #endregion 220 } 221 }
1 using System; 2 using System.Text; 3 using System.Windows.Forms; 4 using System.Runtime.InteropServices; 5 6 namespace BAMdp.MouseKeyboardLibrary 7 { 8 public class KeyboardHook : GlobalHook 9 { 10 #region Events 11 12 public event KeyEventHandler KeyDown; 13 public event KeyEventHandler KeyUp; 14 public event KeyPressEventHandler KeyPress; 15 16 #endregion 17 18 #region Constructor 19 20 public KeyboardHook() 21 { 22 23 _hookType = WH_KEYBOARD_LL; 24 25 } 26 27 #endregion 28 29 #region Methods 30 31 protected override int HookCallbackProcedure(int nCode, int wParam, IntPtr lParam) 32 { 33 34 bool handled = false; 35 36 if (nCode > -1 && (KeyDown != null || KeyUp != null || KeyPress != null)) 37 { 38 39 KeyboardHookStruct keyboardHookStruct = 40 (KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct)); 41 42 // Is Control being held down? 43 bool control = ((GetKeyState(VK_LCONTROL) & 0x80) != 0) || 44 ((GetKeyState(VK_RCONTROL) & 0x80) != 0); 45 46 // Is Shift being held down? 47 bool shift = ((GetKeyState(VK_LSHIFT) & 0x80) != 0) || 48 ((GetKeyState(VK_RSHIFT) & 0x80) != 0); 49 50 // Is Alt being held down? 51 bool alt = ((GetKeyState(VK_LALT) & 0x80) != 0) || 52 ((GetKeyState(VK_RALT) & 0x80) != 0); 53 54 // Is CapsLock on? 55 bool capslock = (GetKeyState(VK_CAPITAL) != 0); 56 57 // Create event using keycode and control/shift/alt values found above 58 KeyEventArgs e = new KeyEventArgs( 59 (Keys)( 60 keyboardHookStruct.vkCode | 61 (control ? (int)Keys.Control : 0) | 62 (shift ? (int)Keys.Shift : 0) | 63 (alt ? (int)Keys.Alt : 0) 64 )); 65 66 // Handle KeyDown and KeyUp events 67 switch (wParam) 68 { 69 70 case WM_KEYDOWN: 71 case WM_SYSKEYDOWN: 72 if (KeyDown != null) 73 { 74 KeyDown(this, e); 75 handled = handled || e.Handled; 76 } 77 break; 78 case WM_KEYUP: 79 case WM_SYSKEYUP: 80 if (KeyUp != null) 81 { 82 KeyUp(this, e); 83 handled = handled || e.Handled; 84 } 85 break; 86 87 } 88 89 // Handle KeyPress event 90 if (wParam == WM_KEYDOWN && 91 !handled && 92 !e.SuppressKeyPress && 93 KeyPress != null) 94 { 95 96 byte[] keyState = new byte[256]; 97 byte[] inBuffer = new byte[2]; 98 GetKeyboardState(keyState); 99 100 if (ToAscii(keyboardHookStruct.vkCode, 101 keyboardHookStruct.scanCode, 102 keyState, 103 inBuffer, 104 keyboardHookStruct.flags) == 1) 105 { 106 107 char key = (char)inBuffer[0]; 108 if ((capslock ^ shift) && Char.IsLetter(key)) 109 key = Char.ToUpper(key); 110 KeyPressEventArgs e2 = new KeyPressEventArgs(key); 111 KeyPress(this, e2); 112 handled = handled || e.Handled; 113 114 } 115 116 } 117 118 } 119 120 if (handled) 121 { 122 return 1; 123 } 124 else 125 { 126 return CallNextHookEx(_handleToHook, nCode, wParam, lParam); 127 } 128 129 } 130 131 #endregion 132 } 133 }
using System; using System.Text; using System.Runtime.InteropServices; using System.Windows.Forms; namespace BAMdp.MouseKeyboardLibrary { /// <summary> /// Standard Keyboard Shortcuts used by most applications /// </summary> public enum StandardShortcut { Copy, Cut, Paste, SelectAll, Save, Open, New, Close, Print } /// <summary> /// Simulate keyboard key presses /// </summary> public static class KeyboardSimulator { #region Windows API Code const int KEYEVENTF_EXTENDEDKEY = 0x1; const int KEYEVENTF_KEYUP = 0x2; [DllImport("user32.dll")] static extern void keybd_event(byte key, byte scan, int flags, int extraInfo); #endregion #region Methods public static void KeyDown(Keys key) { keybd_event(ParseKey(key), 0, 0, 0); } public static void KeyUp(Keys key) { keybd_event(ParseKey(key), 0, KEYEVENTF_KEYUP, 0); } public static void KeyPress(Keys key) { KeyDown(key); KeyUp(key); } public static void SimulateStandardShortcut(StandardShortcut shortcut) { switch (shortcut) { case StandardShortcut.Copy: KeyDown(Keys.Control); KeyPress(Keys.C); KeyUp(Keys.Control); break; case StandardShortcut.Cut: KeyDown(Keys.Control); KeyPress(Keys.X); KeyUp(Keys.Control); break; case StandardShortcut.Paste: KeyDown(Keys.Control); KeyPress(Keys.V); KeyUp(Keys.Control); break; case StandardShortcut.SelectAll: KeyDown(Keys.Control); KeyPress(Keys.A); KeyUp(Keys.Control); break; case StandardShortcut.Save: KeyDown(Keys.Control); KeyPress(Keys.S); KeyUp(Keys.Control); break; case StandardShortcut.Open: KeyDown(Keys.Control); KeyPress(Keys.O); KeyUp(Keys.Control); break; case StandardShortcut.New: KeyDown(Keys.Control); KeyPress(Keys.N); KeyUp(Keys.Control); break; case StandardShortcut.Close: KeyDown(Keys.Alt); KeyPress(Keys.F4); KeyUp(Keys.Alt); break; case StandardShortcut.Print: KeyDown(Keys.Control); KeyPress(Keys.P); KeyUp(Keys.Control); break; } } static byte ParseKey(Keys key) { // Alt, Shift, and Control need to be changed for API function to work with them switch (key) { case Keys.Alt: return (byte)18; case Keys.Control: return (byte)17; case Keys.Shift: return (byte)16; default: return (byte)key; } } #endregion } }
1 private void Form_Load(object sender, EventArgs e) 2 { 3 keyboardHook = new KeyboardHook(); 4 keyboardHook.KeyDown += new KeyEventHandler(keyboardHook_KeyDown); 5 keyboardHook.KeyUp += new KeyEventHandler(keyboardHook_KeyUp); 6 keyboardHook.Start(); 7 }
1 private void keyboardHook_KeyUp(object sender, KeyEventArgs e) 2 { 3 if (e.KeyCode == Keys.Space && SpacePrease) 4 { 5 SpacePrease = false; 6 m_emergency.ReleaseSpeaker(); 7 } 8 } 9 10 private void keyboardHook_KeyDown(object sender, KeyEventArgs e) 11 { 12 if (e.KeyCode == Keys.Space && !SpacePrease) 13 { 14 SpacePrease = true; 15 m_emergency.ApplySpeaker(); 16 } 17 }