using System; using System.Diagnostics; using System.Runtime.InteropServices; using HandyControl.Data; using HandyControl.Tools.Interop; namespace HandyControl.Tools { public class KeyboardHook { public static event EventHandler KeyDown; public static event EventHandler KeyUp; private static IntPtr HookId = IntPtr.Zero; private static readonly UnsafeNativeMethods.HookProc Proc = HookCallback; private static int VirtualKey; private static readonly IntPtr KeyDownIntPtr = (IntPtr)NativeMethods.WM_KEYDOWN; private static readonly IntPtr KeyUpIntPtr = (IntPtr)NativeMethods.WM_KEYUP; private static readonly IntPtr SyskeyDownIntPtr = (IntPtr)NativeMethods.WM_SYSKEYDOWN; private static readonly IntPtr SyskeyUpIntPtr = (IntPtr)NativeMethods.WM_SYSKEYUP; public static void Start() { if (HookId != IntPtr.Zero) { Stop(); } HookId = SetHook(Proc); } public static void Stop() => UnsafeNativeMethods.UnhookWindowsHookEx(HookId); private static IntPtr SetHook(UnsafeNativeMethods.HookProc proc) { using (var curProcess = Process.GetCurrentProcess()) using (var curModule = curProcess.MainModule) { if (curModule != null) { return UnsafeNativeMethods.SetWindowsHookEx((int)UnsafeNativeMethods.HookType.WH_KEYBOARD_LL, proc, UnsafeNativeMethods.GetModuleHandle(curModule.ModuleName), 0); } return IntPtr.Zero; } } private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam) { if (nCode >= 0) { if (wParam == KeyDownIntPtr) { var virtualKey = Marshal.ReadInt32(lParam); if (VirtualKey != virtualKey) { VirtualKey = virtualKey; KeyDown?.Invoke(null, new KeyboardHookEventArgs(virtualKey, false)); } } else if (wParam == SyskeyDownIntPtr) { var virtualKey = Marshal.ReadInt32(lParam); if (VirtualKey != virtualKey) { VirtualKey = virtualKey; KeyDown?.Invoke(null, new KeyboardHookEventArgs(virtualKey, true)); } } else if (wParam == KeyUpIntPtr) { var virtualKey = Marshal.ReadInt32(lParam); VirtualKey = -1; KeyUp?.Invoke(null, new KeyboardHookEventArgs(virtualKey, false)); } else if (wParam == SyskeyUpIntPtr) { var virtualKey = Marshal.ReadInt32(lParam); VirtualKey = -1; KeyUp?.Invoke(null, new KeyboardHookEventArgs(virtualKey, true)); } } return UnsafeNativeMethods.CallNextHookEx(HookId, nCode, wParam, lParam); } } }