当前位置: 首页 > news >正文

C# 使用Windows API实现键盘钩子的类

源码

/// KEYBOARD.CS
/// 本文件包含以下内容:
///  - KeyboardHook: 使用Windows API实现低级键盘钩子的类
///  - KeyboardHookEventHandler: 处理KeyboardHook类触发的KeyIntercepted事件的委托
///  - KeyboardHookEventArgs: 包含KeyIntercepted事件返回信息的EventArgs类
///    using System;
using System.Diagnostics;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Text;/// <summary>
/// 低级键盘拦截类,用于捕获和屏蔽系统按键
/// </summary>
public class KeyboardHook : IDisposable
{/// <summary>/// KeyboardHook构造函数接受的参数枚举/// </summary>public enum Parameters{None,AllowAltTab,AllowWindowsKey,AllowAltTabAndWindows,PassAllKeysToNextApp}// 内部参数private bool PassAllKeysToNextApp = false;private bool AllowAltTab = false;private bool AllowWindowsKey = false;// 键盘API常量private const int WH_KEYBOARD_LL = 13;private const int WM_KEYUP = 0x0101;private const int WM_SYSKEYUP = 0x0105;// 修饰键常量private const int VK_SHIFT = 0x10;private const int VK_CONTROL = 0x11;private const int VK_MENU = 0x12;private const int VK_CAPITAL = 0x14;// SetWindowsHookEx调用使用的变量private HookHandlerDelegate proc;private IntPtr hookID = IntPtr.Zero;internal delegate IntPtr HookHandlerDelegate(int nCode, IntPtr wParam, ref KBDLLHOOKSTRUCT lParam);/// <summary>/// 当低级钩子拦截到击键时触发的事件/// </summary>public event KeyboardHookEventHandler KeyIntercepted;// 按键时钩子返回的结构体internal struct KBDLLHOOKSTRUCT{public int vkCode;int scanCode;public int flags;int time;int dwExtraInfo;}#region 构造函数/// <summary>/// 设置键盘钩子以捕获所有按键,并不传递给其他应用/// </summary>public KeyboardHook(){proc = new HookHandlerDelegate(HookCallback);using (Process curProcess = Process.GetCurrentProcess())using (ProcessModule curModule = curProcess.MainModule){hookID = NativeMethods.SetWindowsHookEx(WH_KEYBOARD_LL, proc,NativeMethods.GetModuleHandle(curModule.ModuleName), 0);}}/// <summary>/// 使用自定义参数设置键盘钩子/// </summary>/// <param name="param">Parameters枚举中的有效名称,否则将使用默认参数Parameter.None</param>public KeyboardHook(string param): this(){if (!String.IsNullOrEmpty(param) && Enum.IsDefined(typeof(Parameters), param)){SetParameters((Parameters)Enum.Parse(typeof(Parameters), param));}}/// <summary>/// 使用自定义参数设置键盘钩子/// </summary>/// <param name="param">Parameters枚举值</param>public KeyboardHook(Parameters param): this(){SetParameters(param);}private void SetParameters(Parameters param){switch (param){case Parameters.None:break;case Parameters.AllowAltTab:AllowAltTab = true;break;case Parameters.AllowWindowsKey:AllowWindowsKey = true;break;case Parameters.AllowAltTabAndWindows:AllowAltTab = true;AllowWindowsKey = true;break;case Parameters.PassAllKeysToNextApp:PassAllKeysToNextApp = true;break;}}#endregion#region 检查修饰键/// <summary>/// 检查Alt、Shift、Control或CapsLock是否与其他键同时启用/// 根据需要对相关部分和返回类型进行修改/// </summary>private void CheckModifiers(){StringBuilder sb = new StringBuilder();if ((NativeMethods.GetKeyState(VK_CAPITAL) & 0x0001) != 0){// 大写锁定开启sb.AppendLine("大写锁定已启用");}if ((NativeMethods.GetKeyState(VK_SHIFT) & 0x8000) != 0){// Shift键按下sb.AppendLine("Shift键按下");}if ((NativeMethods.GetKeyState(VK_CONTROL) & 0x8000) != 0){// Control键按下sb.AppendLine("Control键按下");}if ((NativeMethods.GetKeyState(VK_MENU) & 0x8000) != 0){// Alt键按下sb.AppendLine("Alt键按下");}Console.WriteLine(sb.ToString());}#endregion#region 钩子回调方法/// <summary>/// 处理钩子捕获的按键事件/// </summary>private IntPtr HookCallback(int nCode, IntPtr wParam, ref KBDLLHOOKSTRUCT lParam){bool AllowKey = PassAllKeysToNextApp;// 仅过滤KeyUp事件if (nCode >= 0){if (wParam == (IntPtr)WM_KEYUP || wParam == (IntPtr)WM_SYSKEYUP){// 检查修饰键,但仅当当前处理的键不是修饰键时// (换句话说,只有当Ctrl、Shift、CapsLock或Alt与其他键同时按下时才会运行CheckModifiers)if (!(lParam.vkCode >= 160 && lParam.vkCode <= 164)){CheckModifiers();}// 检查允许传递给Windows的按键组合//// Ctrl+Esc或Windows键if (AllowWindowsKey){switch (lParam.flags){// Ctrl+Esccase 0:if (lParam.vkCode == 27)AllowKey = true;break;// Windows键case 1:if ((lParam.vkCode == 91) || (lParam.vkCode == 92))AllowKey = true;break;}}// Alt+Tabif (AllowAltTab){if ((lParam.flags == 32) && (lParam.vkCode == 9))AllowKey = true;}OnKeyIntercepted(new KeyboardHookEventArgs(lParam.vkCode, AllowKey));}// 如果此键被屏蔽,返回虚拟值if (AllowKey == false)return (System.IntPtr)1;}// 将按键传递给下一个应用return NativeMethods.CallNextHookEx(hookID, nCode, wParam, ref lParam);}#endregion#region 事件处理/// <summary>/// 触发KeyIntercepted事件/// </summary>/// <param name="e">KeyboardHookEventArgs实例</param>public void OnKeyIntercepted(KeyboardHookEventArgs e){if (KeyIntercepted != null)KeyIntercepted(e);}/// <summary>/// KeyboardHook事件处理的委托/// </summary>/// <param name="e">InterceptKeysEventArgs实例</param>public delegate void KeyboardHookEventHandler(KeyboardHookEventArgs e);/// <summary>/// KeyboardHook类KeyIntercepted事件的事件参数/// </summary>public class KeyboardHookEventArgs : System.EventArgs{private string keyName;private int keyCode;private bool passThrough;/// <summary>/// 按下的键名/// </summary>public string KeyName{get { return keyName; }}/// <summary>/// 按下的键的虚拟键码/// </summary>public int KeyCode{get { return keyCode; }}/// <summary>/// 如果此按键组合被传递给其他应用则为true,被捕获则为false/// </summary>public bool PassThrough{get { return passThrough; }}public KeyboardHookEventArgs(int evtKeyCode, bool evtPassThrough){keyName = ((Keys)evtKeyCode).ToString();keyCode = evtKeyCode;passThrough = evtPassThrough;}}#endregion#region IDisposable接口实现/// <summary>/// 释放键盘钩子/// </summary>public void Dispose(){NativeMethods.UnhookWindowsHookEx(hookID);}#endregion#region 原生方法[ComVisibleAttribute(false),System.Security.SuppressUnmanagedCodeSecurity()]internal class NativeMethods{[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]public static extern IntPtr GetModuleHandle(string lpModuleName);[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]public static extern IntPtr SetWindowsHookEx(int idHook,HookHandlerDelegate lpfn, IntPtr hMod, uint dwThreadId);[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)][return: MarshalAs(UnmanagedType.Bool)]public static extern bool UnhookWindowsHookEx(IntPtr hhk);[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]public static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,IntPtr wParam, ref KBDLLHOOKSTRUCT lParam);[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)]public static extern short GetKeyState(int keyCode);}#endregion
}

键盘钩子类使用指南

类初始化

键盘钩子功能由KeyboardHook类实现(位于keyboard.cs)。该类继承IDisposable接口,推荐在应用主程序中通过using语句初始化:

    static class Program{public static KeyboardHook kh;/// <summary>/// 应用程序的主入口点。/// </summary>[STAThread]static void Main(){using (kh = new KeyboardHook()){Application.EnableVisualStyles();Application.SetCompatibleTextRenderingDefault(false);Application.Run(new Form1());}}}

注意:主窗体需能访问此实例,建议将其存储在公共成员变量中(建议放在Program.cs)

构造函数选项

类提供三种构造方式:

构造函数说明
KeyboardHook()拦截所有按键,不传递给系统和其他应用
KeyboardHook(string param)通过字符串参数指定行为(需匹配Parameters枚举值)
KeyboardHook(KeyboardHook.Parameters)通过枚举精确控制行为

参数枚举说明

public enum Parameters
{None,                   // 拦截所有按键AllowAltTab,            // 允许Alt+Tab切换AllowWindowsKey,        // 允许Win键和Ctrl+EscAllowAltTabAndWindows,  // 同时允许上述两种组合键PassAllKeysToNextApp    // 完全禁用拦截(仅监控)
}
事件处理

当按键被拦截时,会触发KeyIntercepted事件,包含以下信息:

  • KeyName:按键名称(通过System.Windows.Forms.Keys转换)

  • KeyCode:原始键值代码

  • PassThrough:是否允许该按键传递到其他应用

事件注册示例

kh.KeyIntercepted += new KeyboardHook.KeyboardHookEventHandler(kh_KeyIntercepted);

事件处理示例

void kh_KeyIntercepted(KeyboardHookEventArgs e)
{// 执行自定义操作(显示按键名称)MessageBox.Show(e.KeyName);
}

相关文章:

  • 【KWDB 创作者计划】_嵌入式硬件篇---数字电子器件
  • Android Cordova 开发 - Cordova 解读初始化项目(index.html meta、Cordova.js、config.xml)
  • AndroidAutomotive模块介绍(四)VehicleHal介绍
  • Pytorch图像数据转为Tensor张量
  • 大厂面试:MySQL篇
  • create_function()漏洞利用
  • centos stream 10 修改 metric
  • LSTM-GAN生成数据技术
  • 4. 继承基类实现浏览器_Chrome
  • 6.1.多级缓存架构
  • 【Axure高保真原型】动态折线图
  • MongoDB Ubuntu 安装
  • 智能文档解析系统架构师角色定义
  • 智驭未来:NVIDIA自动驾驶安全白皮书与实验室创新实践深度解析
  • Axure按钮设计分享:打造高效交互体验的六大按钮类型
  • Anomize: Better Open Vocabulary Video Anomaly Detection
  • 3.第三章:数据治理的战略价值
  • 初识Redis · 持久化
  • 配置 Nginx 的 HTTPS
  • 分布式理论和事务
  • 联手华为猛攻主流市场,上汽集团总裁:上汽不做生态孤岛
  • 央行副行长陆磊:国际化程度有效提升是上海国际金融中心建设的一个主要方向
  • 内蒙古已评出280名“担当作为好干部”,186人提拔或晋升
  • 助力中国足球未来,香港赛马会鼎力支持U15国少选拔队赴英训练
  • 民建吉林省委提案:当前生育政策集中鼓励多孩生育,应该转变思路
  • 这家企业首次签约参展进博会,为何他说“中资企业没有停止出海的步伐”