using System.Diagnostics; using System.Runtime.InteropServices; using System.Windows.Input; namespace ProximaAnalizer.Helpers; internal class KeyboardHook { public delegate void KeyDownEvent(Key key); public delegate void KeyUpEvent(Key key); private int _hKeyboardHook; private Win32Helper.HookProc? _keyboardHookDelegate; private KeyDownEvent? _onKeyDown; private KeyUpEvent? _onKeyUp; public void SetHook() { _keyboardHookDelegate = KeyboardHookProc; var cModule = Process.GetCurrentProcess().MainModule; if (null == cModule) return; var moduleHandle = Win32Helper.GetModuleHandle(cModule.ModuleName); _hKeyboardHook = Win32Helper.SetWindowsHookEx(Win32Helper.WH_KEYBOARD_LL, _keyboardHookDelegate, moduleHandle, 0); } public void SetOnKeyDownEvent(KeyDownEvent callback) { _onKeyDown = callback; } public void SetOnKeyUpEvent(KeyUpEvent callback) { _onKeyUp = callback; } public void UnHook() { var retKeyboard = true; if (_hKeyboardHook != 0) { retKeyboard = Win32Helper.UnhookWindowsHookEx(_hKeyboardHook); _hKeyboardHook = 0; } //如果卸下钩子失败 if (!retKeyboard) throw new Exception("卸下钩子失败!"); } /// /// 获取键盘消息 /// /// /// /// /// private int KeyboardHookProc(int nCode, int wParam, IntPtr lParam) { // 如果该消息被丢弃 nCode<0 if (nCode < 0) return Win32Helper.CallNextHookEx(_hKeyboardHook, nCode, wParam, lParam); if (Marshal.PtrToStructure(lParam, typeof(Win32Helper.KeyboardHookStruct)) is not Win32Helper.KeyboardHookStruct keyboardHookStruct) return Win32Helper.CallNextHookEx(_hKeyboardHook, nCode, wParam, lParam); var key = KeyInterop.KeyFromVirtualKey(keyboardHookStruct.vkCode); switch (wParam) { case Win32Helper.WM_KEYDOWN: case Win32Helper.WM_SYSKEYDOWN: _onKeyDown?.Invoke(key); break; case Win32Helper.WM_KEYUP: case Win32Helper.WM_SYSKEYUP: _onKeyUp?.Invoke(key); break; } return Win32Helper.CallNextHookEx(_hKeyboardHook, nCode, wParam, lParam); } } internal class Win32Helper { public delegate int HookProc(int nCode, int wParam, IntPtr lParam); public const int WM_KEYDOWN = 0x100; public const int WM_KEYUP = 0x101; public const int WM_SYSKEYDOWN = 0x104; public const int WM_SYSKEYUP = 0x105; public const int WH_KEYBOARD_LL = 13; //安装钩子的函数 [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] public static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId); //卸下钩子的函数 [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] public static extern bool UnhookWindowsHookEx(int idHook); //下一个钩挂的函数 [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] public static extern int CallNextHookEx(int idHook, int nCode, int wParam, IntPtr lParam); [DllImport("kernel32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] public static extern IntPtr GetModuleHandle(string lpModuleName); [DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto)] public static extern bool SetForegroundWindow(IntPtr hWnd); [DllImport("winmm.dll", EntryPoint = "mciSendString", CharSet = CharSet.Auto)] public static extern int MciSendString(string lpstrCommand, string lpstrReturnString, int uReturnLength, int hwndCallback); [StructLayout(LayoutKind.Sequential)] //声明键盘钩子的封送结构类型 public class KeyboardHookStruct { public int vkCode; //表示一个在1到254间的虚似键盘码 public int scanCode; //表示硬件扫描码 public int flags; public int time; public int dwExtraInfo; } }