WPF 利用键盘钩子来捕获键盘,做一些不为人知的事情...完整实例
键盘钩子是一种可以监控键盘操作的指令。
看到这句话是不是觉得其实键盘钩子可以做很多事情.
场景
当你的程序需要一个全局的快捷键时,可以考虑使用键盘钩子,如大家常用qq的截图快捷键,那么在WPF里怎么去实现呢?
当然不是直接在Window窗体里面去注册KeyDown、KeyUp,这样只有在程序是焦点的情况下才能触发,
我们这里要做的更为强大,即在非焦点下去获取到键盘的事件(要偷偷记录女朋友键盘记录的滚粗,当然我是在开玩笑,程序猿哪里有女朋友,我们只有男朋友(⊙0⊙))
实现
首先我们需要用到这么几个WinAPI
//安装钩子的函数 [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);
大致的逻辑为:
安装键盘钩子,然后通过委托来处理获取到的键盘消息
整理为两个类(winapi[Win32Api.cs]类和键盘钩子[KeyboardHook.cs]类)如下
public class Win32Api { 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;[StructLayout(LayoutKind.Sequential)] //声明键盘钩子的封送结构类型public class KeyboardHookStruct{public int vkCode; //表示一个在1到254间的虚似键盘码 public int scanCode; //表示硬件扫描码 public int flags;public int time;public int dwExtraInfo;}public delegate int HookProc(int nCode, Int32 wParam, IntPtr lParam);//安装钩子的函数 [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);[DllImport("kernel32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]public static extern IntPtr GetModuleHandle(string lpModuleName); }
public class KeyboardHook{int hHook;Win32Api.HookProc KeyboardHookDelegate;/// <summary>/// 安装键盘钩子/// </summary>public void SetHook(){KeyboardHookDelegate = new Win32Api.HookProc(KeyboardHookProc);ProcessModule cModule = Process.GetCurrentProcess().MainModule;var mh = Win32Api.GetModuleHandle(cModule.ModuleName);hHook = Win32Api.SetWindowsHookEx(Win32Api.WH_KEYBOARD_LL, KeyboardHookDelegate, mh, 0);}/// <summary>/// 卸载键盘钩子/// </summary>public void UnHook(){Win32Api.UnhookWindowsHookEx(hHook);}/// <summary>/// 获取键盘消息/// </summary>/// <param name="nCode"></param>/// <param name="wParam"></param>/// <param name="lParam"></param>/// <returns></returns>private int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam){// 如果该消息被丢弃(nCode<0if (nCode >= 0){Win32Api.KeyboardHookStruct KeyDataFromHook = (Win32Api.KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(Win32Api.KeyboardHookStruct));int keyData = KeyDataFromHook.vkCode;//WM_KEYDOWN和WM_SYSKEYDOWN消息,将会引发OnKeyDownEvent事件if (OnKeyDownEvent != null && (wParam == Win32Api.WM_KEYDOWN || wParam == Win32Api.WM_SYSKEYDOWN)){// 此处触发键盘按下事件// keyData为按下键盘的值,对应 虚拟码 }//WM_KEYUP和WM_SYSKEYUP消息,将引发OnKeyUpEvent事件 if (OnKeyUpEvent != null && (wParam == Win32Api.WM_KEYUP || wParam == Win32Api.WM_SYSKEYUP)){// 此处触发键盘抬起事件 }}return Win32Api.CallNextHookEx(hHook, nCode, wParam, lParam);} }
当时拿在虚拟码的时候其实我是拒绝的,因为在接下来我竟然不知道要对这些虚拟码做什么处理,难道要一个一个转换才能在WPF里进一步的去判断按下的是什么键?
最后经博客园<Launcher>告知,在System.Windows.Input命名空间下其实已经封装了转换的方法
namespace System.Windows.Input {// 摘要: // 提供在 Win32 虚拟键和 WPFSystem.Windows.Input.Key 枚举之间进行转换的静态方法。public static class KeyInterop{// 摘要: // 将 Win32 虚拟键转换为 WPFSystem.Windows.Input.Key。//// 参数: // virtualKey:// 要转换的虚拟键。//// 返回结果: // WPF 键。public static Key KeyFromVirtualKey(int virtualKey);//// 摘要: // 将 WPFSystem.Windows.Input.Key 转换为 Win32 虚拟键。//// 参数: // key:// 要转换的 WPF。//// 返回结果: // Win32 虚拟键。public static int VirtualKeyFromKey(Key key);} }
结果
于是我们开开心心的拿到了基友的键盘操作记录
KeyInterop.KeyFromVirtualKey(KeyData)
nono,我只是拿来做了一个钢琴键盘
代码已贴,恕不给基友另行提供Demo
WPF 利用键盘钩子来捕获键盘,做一些不为人知的事情...完整实例相关推荐
- python 键盘钩子_WPF 利用键盘钩子来捕获键盘,做一些不为人知的事情...完整实例...
原文:WPF 利用键盘钩子来捕获键盘,做一些不为人知的事情...完整实例 键盘钩子是一种可以监控键盘操作的指令. 看到这句话是不是觉得其实键盘钩子可以做很多事情. 场景 当你的程序需要一个全局的快捷键 ...
- java键盘钩子_java – JNA键盘钩在Windows
我已经在 Windows中安装了一个JNA代码来安装键盘钩子(使用JNA示例).代码编译和一切,我得到挂钩安装(我成功处理挂钩),我也可以卸载挂钩成功.但是,当我按键盘上的任何键时,回调永远不会被调用 ...
- 利用底层键盘钩子拦载任意按键(回调版)
前段时间我曾经写过一篇<利用底层键盘钩子屏蔽任意按键>,并放到了我的blog上.这篇文章的题目中把"屏蔽"改成了"拦截",显然要比以前的版本强一些了 ...
- C# 键盘钩子捕获扫码枪
由于扫码枪的输出方式与键盘输出是一样的,由此可以使用键盘钩子来捕获扫码枪数据 文章目录 引用 HookApi 常数和结构 安装与卸载 释放不需要的数据 捕获 引用 using System; usin ...
- 利用底层键盘钩子屏蔽任意按键
很多人都知道,如果想在系统范围内屏蔽键盘上的任意按键需要使用全局键盘钩子,然而像win键这样"倔强"的按键又不是普通的键盘钩子就能搞定的.这里我提供一种利用底层键盘钩子屏蔽任意按键 ...
- 钩子原理及实例:实现键盘钩子截获密码
钩子原理及实例:利用鼠标键盘钩子截获密码 钩子原理 钩子能截获系统并得理发送给其它应用程序的消息,能完成一般程序无法完成的功能.Windows系统是建立在事件驱动的机制上的,也就是整个系统都是通过消息 ...
- [C++]键盘钩子程序
实现适时监视键盘,并将按键信息保存在TXT文件中的程序 Windows系统是建立在事件驱动的机制上的,说穿了就是整个系统都是通过消息的传递来实现的.而钩子是Windows系统中非常重要的系统接口,用它 ...
- 一个简单的键盘钩子程序(ZZZ)
一个简单的键盘钩子程序 从哪儿抄来的忘了,不过写的很简单明了 实现适时监视键盘,并将按键信息保存在TXT文件中的程序 Windows系统是建立在事件驱动的机制上的,说穿了就是整个系统都 ...
- 要如何禁止键盘钩子?
要如何禁止键盘钩子? Delphi / Windows SDK/API http://www.delphi2007.net/DelphiAPI/html/delphi_2006112612072216 ...
最新文章
- 实战经验:MySQL 构建高并发网站性能优化
- Ctex软件介绍安装破解(是WinEdt_v6.0破解)
- 【开发环境】Ubuntu 中使用 VSCode 开发 C/C++ ⑤ ( tasks.json 中的 args 数组配置分析 | 编译并执行 C++ 程序 )
- 第四百三十六天 how can I 坚持
- 记一次悲惨的 Excel 导出事件
- 蓝桥杯-5-1最小公倍数(java)
- Yii的scenarios
- 打包指令_Linux系统常用指令总结
- 大项目之网上书城(十二)——完成啦
- ubantu中rpm转换成deb(软件包格式)
- dump文件 修复iat_内存溢出如何Dump文件
- 渗透测试攻击(一)Arp中间人攻击 伪装网关 截获 上网信息用户名密码
- 八皇后时间复杂度_九章算法 | N皇后问题
- 阿里云高级技术专家王晨:云原生数据库PolarDB技术解密
- 2021 软考 软件设计师考试教程(详细版)
- EPLAN学习教程目录
- 富士施乐Fuji Xerox DocuPrint M225 dw 驱动
- 浅谈机器学习中的非线性
- Jmeter性能测试简单示例
- 本机可以访问8080端口,外网不能访问的解决方案
热门文章
- Linux系统性能相关知识学习
- windows中的计划任务(タスクスケジュール)不登陆也可以执行 设定方式
- 如何提高员工的能动性,体现员工的自我价值
- VBA代码执行过程中,显示程序的运行状态
- 用python建立socket,用python建立socket服务器
- RestTemplate的异常 Not enough variables available to expand
- mount: block device /dev/cdrom is write-protected, mounting read-only 解决方法
- 将DEX反编译成Java源代码
- 什么是std :: move(),什么时候应该使用?
- 为什么null为对象,并且null和undefined有什么区别?