键盘钩子在64位系统中运行
using Newtonsoft.Json; using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Linq; using System.Runtime.InteropServices; using System.Windows.Forms; namespace Hook { public class Hook : IDisposable { public delegate int HookProc(WH_CODE nCode, Int32 wParam, IntPtr lParam); #region 常数和结构 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; #endregion public enum WH_CODE : int { WH_JOURNALRECORD = 0, WH_JOURNALPLAYBACK = 1, /// <summary> /// 进程钩子 /// {系统级或线程级; 截获键盘消息} /// </summary> WH_KEYBOARD = 2, /// <summary> /// 底层键盘钩子 全局钩子就是用这个 /// </summary> WH_KEYBOARD_LL = 13, } public enum HC_CODE : int { HC_ACTION = 0, HC_GETNEXT = 1, HC_SKIP = 2, HC_NOREMOVE = 3, HC_NOREM = 3, HC_SYSMODALON = 4, HC_SYSMODALOFF = 5 } [StructLayout(LayoutKind.Sequential)] public class KeyboardHookStruct { public int vkCode; //定一个虚拟键码。该代码必须有一个价值的范围1至254 public int scanCode; // 指定的硬件扫描码的关键 public int flags; // 键标志 public int time; // 指定的时间戳记的这个讯息 public int dwExtraInfo; // 指定额外信息相关的信息 } /// <summary> /// 安装钩子 /// </summary> [DllImport("user32.dll", SetLastError = true, CallingConvention = CallingConvention.StdCall)] public static extern IntPtr SetWindowsHookEx(WH_CODE idHook, HookProc lpfn, IntPtr pInstance, uint threadId); /// <summary> /// 卸载钩子 /// </summary> [DllImport("user32.dll", CallingConvention = CallingConvention.StdCall)] public static extern bool UnhookWindowsHookEx(IntPtr pHookHandle); /// <summary> /// 传递钩子 /// </summary> [DllImport("user32.dll", CallingConvention = CallingConvention.StdCall)] public static extern int CallNextHookEx(IntPtr pHookHandle, WH_CODE nCodem, Int32 wParam, IntPtr lParam); /// <summary> /// 获取全部按键状态 /// </summary> /// <param name="pbKeyState"></param> /// <returns>非0表示成功</returns> [DllImport("user32.dll")] public static extern int GetKeyboardState(byte[] pbKeyState); /// <summary> /// 获取程序集模块的句柄 /// </summary> /// <param name="lpModuleName"></param> /// <returns></returns> [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] public static extern IntPtr GetModuleHandle(string lpModuleName); /// <summary> /// 获取当前进程中的当前线程ID /// </summary> /// <returns></returns> [DllImport("kernel32.dll", CharSet = CharSet.Auto)] public static extern uint GetCurrentThreadId(); #region 私有变量 private byte[] mKeyState = new byte[256]; private Keys mKeyData = Keys.None; //专门用于判断按键的状态 /// <summary> /// 键盘钩子句柄 /// </summary> private IntPtr mKetboardHook = IntPtr.Zero; /// <summary> /// 键盘钩子委托实例 /// </summary> private HookProc mKeyboardHookProcedure; #endregion /// <summary> /// 构造函数 /// </summary> public Hook() { GetKeyboardState(this.mKeyState); } ~Hook() { Dispose(); } bool KeyDown = true; public bool Ekey = false; public bool Rkey = false; /// <summary> /// 键盘钩子处理函数 /// </summary> private int KeyboardHookProcNew(WH_CODE nCode, Int32 wParam, IntPtr lParam) { /*全局钩子应该这样设定 KeyboardHookStruct MyKeyboardHookStruct = (KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct)); */ // 定义为线程钩子时,wParam的值是击打的按键,与Keys里的对应按键相同 if ((int)nCode == (int)HC_CODE.HC_NOREMOVE) { if (FormStatus) { mKeyData = (Keys)wParam; KeyEventArgs keyEvent = new KeyEventArgs(mKeyData); if (KeyDown && lParam.ToInt64() > 0) { //这里简单的通过lParam的值的正负情况与按键的状态相关联 if (mKeyData == Keys.Space && lParam.ToInt64() > 0) { this.OnSpaceKeyDown(); } } } } return CallNextHookEx(this.mKetboardHook, nCode, wParam, lParam); } #region 事件的声明 // public event KeyEventHandler KeyDownEvent; private static readonly object _eventKeyDown = new object(); private EventHandlerList _events; protected EventHandlerList Events => _events ??= new EventHandlerList(); [Category("Property Changed")] public event KeyEventHandler KeyDownEvent { add { this.Events.AddHandler(_eventKeyDown, value); } remove { this.Events.RemoveHandler(_eventKeyDown, value); } } #endregion /// <summary> /// 键盘钩子处理函数 /// </summary> private int KeyboardHookProc(WH_CODE nCode, Int32 wParam, IntPtr lParam) { /*全局钩子应该这样设定 KeyboardHookStruct MyKeyboardHookStruct = (KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct)); */ // 定义为线程钩子时,wParam的值是击打的按键,与Keys里的对应按键相同 if ((int)nCode == (int)HC_CODE.HC_NOREMOVE) { if (FormStatus) { // Debug.WriteLine($"{nCode} {(Keys)wParam} {lParam} "); mKeyData = (Keys)wParam; if (lParam.ToInt64() > int.MaxValue) { Debug.WriteLine($"松开了{mKeyData}键"); } if (lParam.ToInt64() > 0 && lParam.ToInt64() < int.MaxValue) { KeyEventArgs e = new(mKeyData);//获取KeyEventArgs事件的相关信息 if (Events[_eventKeyDown] is KeyEventHandler handler) handler.Invoke(this, e); } } } return CallNextHookEx(this.mKetboardHook, nCode, wParam, lParam); } /// <summary> /// 安装钩子 /// </summary> /// <returns></returns> public bool InstallHook(bool status) { //线程钩子时一定要通过这个取得的值才是操作系统下真实的线程 uint result = GetCurrentThreadId(); if (this.mKetboardHook == IntPtr.Zero) { if (status) { this.mKeyboardHookProcedure = new HookProc(this.KeyboardHookProc); } else { this.mKeyboardHookProcedure = new HookProc(this.KeyboardHookProcNew); } //注册线程钩子时第三个参数是空 this.mKetboardHook = SetWindowsHookEx(WH_CODE.WH_KEYBOARD, this.mKeyboardHookProcedure, IntPtr.Zero, result); /* 如果是全局钩子应该这样使用 this.mKetboardHook = SetWindowsHookEx(WH_CODE.WH_KEYBOARD_LL, mKeyboardHookProcedure,GetModuleHandle(System.Diagnostics.Process.GetCurrentProcess().MainModule.ModuleName), 0); */ if (this.mKetboardHook == IntPtr.Zero) { return false; } } return true; } /// <summary> /// 卸载钩子 /// </summary> /// <returns>true表示成功 </returns> public bool UnInstallHook() { bool result = true; if (this.mKetboardHook != IntPtr.Zero) { result = UnhookWindowsHookEx(this.mKetboardHook) && result; this.mKetboardHook = IntPtr.Zero; } return result; } public void Dispose() { UnInstallHook(); GC.SuppressFinalize(this); } } }
本文来自博客园,作者:willamyao,转载请注明原文链接:https://www.cnblogs.com/robertyao/p/17945643
代码改变世界