原文: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 利用键盘钩子来捕获键盘,做一些不为人知的事情...完整实例相关推荐

  1. python 键盘钩子_WPF 利用键盘钩子来捕获键盘,做一些不为人知的事情...完整实例...

    原文:WPF 利用键盘钩子来捕获键盘,做一些不为人知的事情...完整实例 键盘钩子是一种可以监控键盘操作的指令. 看到这句话是不是觉得其实键盘钩子可以做很多事情. 场景 当你的程序需要一个全局的快捷键 ...

  2. java键盘钩子_java – JNA键盘钩在Windows

    我已经在 Windows中安装了一个JNA代码来安装键盘钩子(使用JNA示例).代码编译和一切,我得到挂钩安装(我成功处理挂钩),我也可以卸载挂钩成功.但是,当我按键盘上的任何键时,回调永远不会被调用 ...

  3. 利用底层键盘钩子拦载任意按键(回调版)

    前段时间我曾经写过一篇<利用底层键盘钩子屏蔽任意按键>,并放到了我的blog上.这篇文章的题目中把"屏蔽"改成了"拦截",显然要比以前的版本强一些了 ...

  4. C# 键盘钩子捕获扫码枪

    由于扫码枪的输出方式与键盘输出是一样的,由此可以使用键盘钩子来捕获扫码枪数据 文章目录 引用 HookApi 常数和结构 安装与卸载 释放不需要的数据 捕获 引用 using System; usin ...

  5. 利用底层键盘钩子屏蔽任意按键

    很多人都知道,如果想在系统范围内屏蔽键盘上的任意按键需要使用全局键盘钩子,然而像win键这样"倔强"的按键又不是普通的键盘钩子就能搞定的.这里我提供一种利用底层键盘钩子屏蔽任意按键 ...

  6. 钩子原理及实例:实现键盘钩子截获密码

    钩子原理及实例:利用鼠标键盘钩子截获密码 钩子原理 钩子能截获系统并得理发送给其它应用程序的消息,能完成一般程序无法完成的功能.Windows系统是建立在事件驱动的机制上的,也就是整个系统都是通过消息 ...

  7. [C++]键盘钩子程序

    实现适时监视键盘,并将按键信息保存在TXT文件中的程序 Windows系统是建立在事件驱动的机制上的,说穿了就是整个系统都是通过消息的传递来实现的.而钩子是Windows系统中非常重要的系统接口,用它 ...

  8. 一个简单的键盘钩子程序(ZZZ)

    一个简单的键盘钩子程序 从哪儿抄来的忘了,不过写的很简单明了 实现适时监视键盘,并将按键信息保存在TXT文件中的程序         Windows系统是建立在事件驱动的机制上的,说穿了就是整个系统都 ...

  9. 要如何禁止键盘钩子?

    要如何禁止键盘钩子? Delphi / Windows SDK/API http://www.delphi2007.net/DelphiAPI/html/delphi_2006112612072216 ...

最新文章

  1. 实战经验:MySQL 构建高并发网站性能优化
  2. Ctex软件介绍安装破解(是WinEdt_v6.0破解)
  3. 【开发环境】Ubuntu 中使用 VSCode 开发 C/C++ ⑤ ( tasks.json 中的 args 数组配置分析 | 编译并执行 C++ 程序 )
  4. 第四百三十六天 how can I 坚持
  5. 记一次悲惨的 Excel 导出事件
  6. 蓝桥杯-5-1最小公倍数(java)
  7. Yii的scenarios
  8. 打包指令_Linux系统常用指令总结
  9. 大项目之网上书城(十二)——完成啦
  10. ubantu中rpm转换成deb(软件包格式)
  11. dump文件 修复iat_内存溢出如何Dump文件
  12. 渗透测试攻击(一)Arp中间人攻击 伪装网关 截获 上网信息用户名密码
  13. 八皇后时间复杂度_九章算法 | N皇后问题
  14. 阿里云高级技术专家王晨:云原生数据库PolarDB技术解密
  15. 2021 软考 软件设计师考试教程(详细版)
  16. EPLAN学习教程目录
  17. 富士施乐Fuji Xerox DocuPrint M225 dw 驱动
  18. 浅谈机器学习中的非线性
  19. Jmeter性能测试简单示例
  20. 本机可以访问8080端口,外网不能访问的解决方案

热门文章

  1. Linux系统性能相关知识学习
  2. windows中的计划任务(タスクスケジュール)不登陆也可以执行 设定方式
  3. 如何提高员工的能动性,体现员工的自我价值
  4. VBA代码执行过程中,显示程序的运行状态
  5. 用python建立socket,用python建立socket服务器
  6. RestTemplate的异常 Not enough variables available to expand
  7. mount: block device /dev/cdrom is write-protected, mounting read-only 解决方法
  8. 将DEX反编译成Java源代码
  9. 什么是std :: move(),什么时候应该使用?
  10. 为什么null为对象,并且null和undefined有什么区别?