失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > C# 键盘钩子和鼠标钩子的使用详解

C# 键盘钩子和鼠标钩子的使用详解

时间:2023-02-27 05:03:22

相关推荐

C# 键盘钩子和鼠标钩子的使用详解

1 简介

C# 使用钩子的方式和C++基本上是一样的,因为直接使用了静态链接库user32.dll我把鼠标钩子和键盘钩子封装成了两个工具类,有兴趣的朋友可以参考一下。项目的链接使用的时候需要给定委托,委托的返回参数你可以参考DLL包下的两个类中的常量。注意,给定的委托函数内部不要写复杂的程序,委托的函数内部修改某个变量,然后外部开辟一个循环任务进行读取。如果委托函数内部的逻辑过于复杂,则读取数据的时候可能会有问题。

2 全局鼠标钩子

2.1 工具类

调用win10内置的DLL"user32.dll"设置全局鼠标回调事件

using System;using System.Collections.Generic;using System.Linq;using System.Runtime.InteropServices;using System.Text;using System.Windows.Input;namespace RecordKeyBoardAndMouse.Service{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 成员变量、回调函数、事件/// <summary>/// 钩子回调函数/// </summary>/// <param name="nCode">如果代码小于零,则挂钩过程必须将消息传递给CallNextHookEx函数,而无需进一步处理,并且应返回CallNextHookEx返回的值。此参数可以是下列值之一。(来自官网手册)</param>/// <param name="wParam">记录了按下的按钮</param>/// <param name="lParam"></param>/// <returns></returns>public delegate int HookProc(int nCode, Int32 wParam, IntPtr lParam);/// <summary>/// 全局的鼠标事件/// </summary>/// <param name="wParam"> 代表发生的鼠标的事件 </param>/// <param name="mouseMsg">钩子的结构体,存储着鼠标的位置及其他信息</param>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/// <summary>/// 钩子结构体/// </summary>[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)]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, 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;}/// <summary>/// 析构函数/// </summary>~MouseHook(){Stop();}#endregion/// <summary>/// 启动全局钩子/// </summary>public void Start(){if (isStart){return;}lock (lockObject){if (isStart){return;}if (OnMouseActivity == null){throw new Exception("Please set handler first!Then run Start");}// 安装鼠标钩子if (_hMouseHook == 0){// 生成一个HookProc的实例._mouseHookProcedure = new HookProc(MouseHookProc);_hMouseHook = SetWindowsHookEx(WH_MOUSE_LL, _mouseHookProcedure, Marshal.GetHINSTANCE(System.Reflection.Assembly.GetExecutingAssembly().GetModules()[0]), 0);//假设装置失败停止钩子if (_hMouseHook == 0){Stop();throw new Exception("SetWindowsHookEx failed.");}}isStart = true;}}/// <summary>/// 停止全局钩子/// </summary>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;}}/// <summary>/// 鼠标钩子回调函数/// </summary>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);}/// <summary>/// 注册全局鼠标事件/// </summary>/// <param name="handler"></param>public void AddMouseHandler(MyMouseEventHandler handler){OnMouseActivity += handler;}/// <summary>/// 注销全局鼠标事件/// </summary>/// <param name="handler"></param>public void RemoveMouseHandler(MyMouseEventHandler handler){if (OnMouseActivity != null){OnMouseActivity -= handler;}}}}

2.2 使用

钩子函数为public delegate void MyMouseEventHandler(Int32 wParam,MouseHookStruct mouseMsg); wParam 代表发生的鼠标的事件,详情参考钩子类中的常量mouseMsg存储鼠标信息,其中的pt记录着鼠标的位置。

// 开启钩子,并注册对应的事件public void Start(MyMouseEventHandler handler){mouseHook.AddMouseHandler(handler);mouseHook.Start();}// 停止钩子public void Stop(){mouseHook.Stop();}

鼠标事件

private void Handler(Int32 wParam,MouseHookStruct mouseMsg){switch (wParam){case WM_MOUSEMOVE:// 鼠标移动x = mouseMsg.pt.x;y = mouseMsg.pt.y;break;case WM_LBUTTONDOWN:// 鼠标左键break;case WM_LBUTTONUP:break;case WM_LBUTTONDBLCLK:break;case WM_RBUTTONDOWN:break;case WM_RBUTTONUP:break;case WM_RBUTTONDBLCLK:break;}}

3 全局键盘钩子

3.1 钩子类

using System;using System.Collections.Generic;using System.Diagnostics;using System.Linq;using System.Reflection;using System.Runtime.InteropServices;using System.Text;using System.Windows.Input;namespace RecordKeyBoardAndMouse.DLL{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等键#endregionpublic 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的Apiprivate 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/// <summary>/// 安装钩子/// </summary>public void Start(){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);Process cProcess = Process.GetCurrentProcess();ProcessModule cModule = cProcess.MainModule;var mh = GetModuleHandle(cModule.ModuleName);hHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardHookDelegate, mh, 0);isStart = true;}}/// <summary>/// 卸载钩子/// </summary>public void Stop(){if (!isStart){return;}lock (lockObject){if (!isStart){return;}UnhookWindowsHookEx(hHook);// 清除所有事件Handlers = null;isStart = false;}}/// <summary>/// 键盘的系统回调函数/// </summary>/// <param name="nCode"></param>/// <param name="wParam"></param>/// <param name="lParam"></param>/// <returns></returns>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);}/// <summary>/// 添加按键的回调函数/// </summary>/// <param name="handler"></param>public void AddKeyboardHandler(KeyboardHandler handler){Handlers += handler;}/// <summary>/// 删除指定按键的回调函数/// </summary>/// <param name="handler"></param>public void RemoveKeyboardHandler(KeyboardHandler handler){if (Handlers != null){Handlers -= handler;}}}}

3.2 使用

在启动钩子之前,必须给定回调函数

public void StartKeyboardHook(KeyboardHandler handler){MyKeyboardHook.AddKeyboardHandler(handler);MyKeyboardHook.Start();}public void StopKeyboardHook(){MyKeyboardHook.Stop();}

回调函数 recordService为上面那两个函数的类使用lambda表达式传入回调函数,不要在内部有复杂的处理 wParam为按键的状态,详情参考钩子类的常数部分keyboardHookStruct 存储被按下的按键的相关信息。详情参考虚拟按键

recordService.StartKeyboardHook((wParam, keyboardHookStruct) =>{keyStatus = wParam;keyValue = keyboardHookStruct.vkCode;});

如果觉得《C# 键盘钩子和鼠标钩子的使用详解》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。