using System; using System.Collections.Generic; using System.Runtime.InteropServices; using System.Text; namespace Veldrid.Common { class KeyboardHook { #region 常数和结构 #region wParam对应的按钮事件 public const int WM_KEYDOWN = 0x100; // 键盘被按下 public const int WM_KEYUP = 0x101; // 键盘被松开 public const int WM_SYSKEYDOWN = 0x104; // 键盘被按下,这个是系统键被按下,例如Alt、Ctrl等键 public const int WM_SYSKEYUP = 0x105; // 键盘被松开,这个是系统键被松开,例如Alt、Ctrl等键 #endregion public const int WH_KEYBOARD_LL = 13; [StructLayout(LayoutKind.Sequential)] //声明键盘钩子的封送结构类型 public class KeyboardHookStruct { public int vkCode; //表示一个在1到254间的虚似键盘码 public int scanCode; //表示硬件扫描码 public int flags; public int time; public int dwExtraInfo; } #endregion #region 成员变量、委托、事件 private static int hHook; private static HookProc KeyboardHookDelegate; // 键盘回调委托 public delegate void KeyboardHandler(Int32 wParam, KeyboardHookStruct keyboardHookStruct); // 键盘回调事件 private static event KeyboardHandler Handlers; // 锁 private readonly object lockObject = new object(); // 当前状态,是否已经启动 private volatile bool isStart = false; #endregion #region Win32的Api [System.Runtime.InteropServices.DllImportAttribute("user32.dll", EntryPoint = "GetWindowThreadProcessId")] private static extern int GetWindowThreadProcessId(System.IntPtr hWnd, IntPtr intPtr); private delegate int HookProc(int nCode, Int32 wParam, IntPtr lParam); //安装钩子的函数 [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention =CallingConvention.StdCall)] private static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId); //卸下钩子的函数 [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention =CallingConvention.StdCall)] private static extern bool UnhookWindowsHookEx(int idHook); //下一个钩挂的函数 [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] private static extern int CallNextHookEx(int idHook, int nCode, Int32 wParam,IntPtr lParam); [DllImport("kernel32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] private static extern IntPtr GetModuleHandle(string lpModuleName); #endregion #region 单例模式 private static volatile KeyboardHook MyKeyboard; private readonly static object createLock = new object(); private KeyboardHook() { } public static KeyboardHook GetKeyboardHook() { if (MyKeyboard == null) { lock (createLock) { if (MyKeyboard == null) { MyKeyboard = new KeyboardHook(); } } } return MyKeyboard; } #endregion /// /// 安装钩子 /// public void Start(IntPtr hwnd) { if (isStart) { return; } lock (lockObject) { if (isStart) { return; } if (Handlers == null) { throw new Exception("Please set handler first!Then run Start"); } KeyboardHookDelegate = new HookProc(KeyboardHookProc); var handle = GetWindowThreadProcessId(hwnd, IntPtr.Zero); hHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardHookDelegate, IntPtr.Zero, handle); isStart = true; } } /// /// 卸载钩子 /// public void Stop() { if (!isStart) { return; } lock (lockObject) { if (!isStart) { return; } UnhookWindowsHookEx(hHook); // 清除所有事件 Handlers = null; isStart = false; } } /// /// 键盘的系统回调函数 /// /// /// /// /// private static int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam) { //如果该消息被丢弃(nCode<0)或者没有事件绑定处理程序则不会触发事件 if ((nCode >= 0) && Handlers != null) { KeyboardHookStruct KeyDataFromHook =(KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct)); Handlers(wParam, KeyDataFromHook); } return CallNextHookEx(hHook, nCode, wParam, lParam); } /// /// 添加按键的回调函数 /// /// public void AddKeyboardHandler(KeyboardHandler handler) { Handlers += handler; } /// /// 删除指定按键的回调函数 /// /// public void RemoveKeyboardHandler(KeyboardHandler handler) { if (Handlers != null) { Handlers -= handler; } } } class MouseHook { #region 常量 public const int WM_MOUSEMOVE = 0x200; // 鼠标移动 public const int WM_LBUTTONDOWN = 0x201;// 鼠标左键按下 public const int WM_RBUTTONDOWN = 0x204;// 鼠标右键按下 public const int WM_MBUTTONDOWN = 0x207;// 鼠标中键按下 public const int WM_LBUTTONUP = 0x202;// 鼠标左键抬起 public const int WM_RBUTTONUP = 0x205;// 鼠标右键抬起 public const int WM_MBUTTONUP = 0x208;// 鼠标中键抬起 public const int WM_LBUTTONDBLCLK = 0x203;// 鼠标左键双击 public const int WM_RBUTTONDBLCLK = 0x206;// 鼠标右键双击 public const int WM_MBUTTONDBLCLK = 0x209;// 鼠标中键双击 public const int WH_MOUSE_LL = 14; //可以截获整个系统所有模块的鼠标事件。 #endregion #region 成员变量、回调函数、事件 /// /// 钩子回调函数 /// /// 如果代码小于零,则挂钩过程必须将消息传递给CallNextHookEx函数,而无需进一步处理,并且应返回CallNextHookEx返回的值。此参数可以是下列值之一。(来自官网手册) /// 记录了按下的按钮 /// /// public delegate int HookProc(int nCode, Int32 wParam, IntPtr lParam); /// /// 全局的鼠标事件 /// /// 代表发生的鼠标的事件 /// 钩子的结构体,存储着鼠标的位置及其他信息 public delegate void MyMouseEventHandler(Int32 wParam, MouseHookStruct mouseMsg); private event MyMouseEventHandler OnMouseActivity; // 声明鼠标钩子事件类型 private HookProc _mouseHookProcedure; private static int _hMouseHook = 0; // 鼠标钩子句柄 // 锁 private readonly object lockObject = new object(); // 当前状态,是否已经启动 private bool isStart = false; #endregion #region Win32的API /// /// 钩子结构体 /// [StructLayout(LayoutKind.Sequential)] public class MouseHookStruct { public POINT pt; // 鼠标位置 public int hWnd; public int wHitTestCode; public int dwExtraInfo; } //声明一个Point的封送类型 [StructLayout(LayoutKind.Sequential)] public class POINT { public int x; public int y; } // 装置钩子的函数 [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] private static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId); // 卸下钩子的函数 [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] private static extern bool UnhookWindowsHookEx(int idHook); [System.Runtime.InteropServices.DllImportAttribute("user32.dll", EntryPoint = "GetWindowThreadProcessId")] private static extern int GetWindowThreadProcessId(System.IntPtr hWnd, IntPtr intPtr); // 下一个钩挂的函数 [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] private static extern int CallNextHookEx(int idHook, int nCode, Int32 wParam, IntPtr lParam); #endregion #region 构造(单例模式)与析构函数 private static volatile MouseHook MyMouseHook; private readonly static object createLock = new object(); private MouseHook() { } public static MouseHook GetMouseHook() { if (MyMouseHook == null) { lock (createLock) { if (MyMouseHook == null) { MyMouseHook = new MouseHook(); } } } return MyMouseHook; } /// /// 析构函数 /// ~MouseHook() { Stop(); } #endregion /// /// 启动全局钩子 /// public void Start(IntPtr intPtr) { if (isStart) { return; } lock (lockObject) { if (isStart) { return; } if (OnMouseActivity == null) { throw new Exception("Please set handler first!Then run Start"); } // 安装鼠标钩子 if (_hMouseHook == 0) { var handle = GetWindowThreadProcessId(intPtr, IntPtr.Zero); // 生成一个HookProc的实例. _mouseHookProcedure = new HookProc(MouseHookProc); _hMouseHook = SetWindowsHookEx(WH_MOUSE_LL, _mouseHookProcedure, IntPtr.Zero, handle); //假设装置失败停止钩子 if (_hMouseHook == 0) { Stop(); throw new Exception("SetWindowsHookEx failed."); } } isStart = true; } } /// /// 停止全局钩子 /// public void Stop() { if (!isStart) { return; } lock (lockObject) { if (!isStart) { return; } bool retMouse = true; if (_hMouseHook != 0) { retMouse = UnhookWindowsHookEx(_hMouseHook); _hMouseHook = 0; } // 假设卸下钩子失败 if (!(retMouse)) throw new Exception("UnhookWindowsHookEx failed."); // 删除所有事件 OnMouseActivity = null; // 标志位改变 isStart = false; } } /// /// 鼠标钩子回调函数 /// private int MouseHookProc(int nCode, Int32 wParam, IntPtr lParam) { // 假设正常执行而且用户要监听鼠标的消息 if ((nCode >= 0) && (OnMouseActivity != null)) { MouseHookStruct MyMouseHookStruct = (MouseHookStruct)Marshal.PtrToStructure(lParam, typeof(MouseHookStruct)); OnMouseActivity(wParam, MyMouseHookStruct); } // 启动下一次钩子 return CallNextHookEx(_hMouseHook, nCode, wParam, lParam); } /// /// 注册全局鼠标事件 /// /// public void AddMouseHandler(MyMouseEventHandler handler) { OnMouseActivity += handler; } /// /// 注销全局鼠标事件 /// /// public void RemoveMouseHandler(MyMouseEventHandler handler) { if (OnMouseActivity != null) { OnMouseActivity -= handler; } } } }