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 = ; [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, ); } /// <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<0
if (nCode >= )
{ 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 利用键盘钩子来捕获键盘,做一些不为人知的事情...完整实例的更多相关文章
- C# 获取键盘钩子,屏蔽键盘按键
static int hHook = 0; public delegate int HookProc(int nCode, int wParam, IntPtr lParam); //LowLevel ...
- 基于C#实现的HOOK键盘钩子实例代码
本文所述为基于C#实现的HOOK实例,该实例可用来屏蔽系统热键.程序主要实现了安装钩子.传递钩子.卸载钩子等功能.在传递钩子中:<param name="pHookHandle&quo ...
- C# 键盘钩子
p{ text-align:center; } blockquote > p > span{ text-align:center; font-size: 18px; color: #ff0 ...
- 低级键盘钩子,在WIN7以上版本的问题
最近在项目用到低级键盘钩子.发现一个很奇怪的事情,在开发环境和测试环境下都正常运行的键盘钩子, 到了现场环境,总是偶发性出现 键盘钩子不能用了,而且退出时产生1404 错误. 后经过阅读MSDN 的R ...
- WPF 捕获键盘输入事件
最近修改的一个需求要求捕获键盘输入的 Text,包括各种标点符号. 最开始想到的是 PreviewKeyDown 或者 PreviewKeyUp 这样的键盘事件. 但是这两个事件的对象 KeyEven ...
- 在WPF中快速实现键盘钩子
大部分的时候,当我们需要键盘事件的时候,可以通过在主窗口注册KeyBinding来实现,不过,有的时候我们需要的是全局键盘事件,想在任何一个地方都能使用,最开始的时候我是通过键盘钩子来实现的, 不过键 ...
- js简单的设置快捷键,hotkeys捕获键盘键和组合键的输入
设置快捷键 这是一个强健的 Javascript 库用于捕获键盘输入和输入的组合键,它没有依赖,压缩只有只有(~3kb). hotkeys on Githubhotkeys预览 创建 您将需要在您的系 ...
- Hotkeys.js 2.0.2 发布,捕获键盘输入和输入的组合键快捷键,它没有依赖
这是一个强健的 Javascript 库用于捕获键盘输入和输入的组合键,它没有依赖,压缩只有只有(~3kb),gzip:1.9k. 更新内容: 添加测试用例: 添加更多特殊键支持: 修复bug. __ ...
- Hotkeys.js 2.0.2 发布,JS 网页快捷键设置,捕获键盘输入和输入的组合键快捷键,它没有依赖
这是一个强健的 Javascript 库用于捕获键盘输入和输入的组合键,它没有依赖,压缩只有只有(~3kb),gzip:1.9k. 更新内容: 添加测试用例: 添加更多特殊键支持: 修复bug. __ ...
随机推荐
- 153. Find Minimum in Rotated Sorted Array(leetcode, binary search)
https://leetcode.com/problems/find-minimum-in-rotated-sorted-array/description/ leetcode 的题目,binary ...
- sublime打开txt文件乱码的问题
我们使用Sublime打开TXT文件的时候,会经常因为编码的问题造成乱码. 这是因为TXT记事本的默认保存编码格式是GBK,而Sublime text不支持GB2312和GBK编码. 我们可以通过安装 ...
- php图像处理插件imagick安装(仅适用于86位,php5.4非安全环境-16px)
phpImageMagick-6.7.7-5-Q16-windows-dll(加测试代码,经测试,仅适用于86位,php5.4安全环境-16px) 下载地址:http://pan.baidu.com/ ...
- C++之string基本字符系列容器
string基本字符系列容器 C语言只提供了一个插入类型用来处理字符, 而对于字符串, 只能通过字符串数组来处理, 显得十分不便. C++STL提供了string基本字符系列容器来处理字符串, 可以把 ...
- vim常用操作整理
一.删除操作 :%s/r//g 删除DOS方式的回车^M :%s= *$== 删除行尾空白 :%s/^(.*)n1/1$/ 删除重复行 :%s/^.pdf/new.pdf/ 只是删除第一个pdf :% ...
- IBM区块链总经理谈区块链
IBM区块链总经理谈区块链:3.4年前IBM的区块链人员就达到了1500人 Captain Hiro 2018-03-20 16:22 发布在 区块链 3 18349 CCN的记者Eric Eiss ...
- 线程池,多线程,线程异步,同步和死锁,Lock接口
线程池 线程池,其实就是一个容纳多个线程的容器,其中的线程可以反复使用,省去了频繁创建线程对象的操作,无需反复创建线程而消耗过多资源. 除了创建和销毁线程的开销之外,活动的线程也需要消耗系统资源.线程 ...
- 第48章 MDK的编译过程及文件类型全解—零死角玩转STM32-F429系列
第48章 MDK的编译过程及文件类型全解 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.co ...
- OpenFire通过User Service管理用户
安装OpenFire服务器略去 1.安装User Service插件: 在管理控制平台找到选项卡“插件”,里边有我们需要安装的一个User Service插件,如果安装过了会显示已经安装的哪些插件,没 ...
- CNN训练中的技巧
转自: http://weibo.com/p/1001603816330729006673 说明:这个翻译应该是来自原文:http://yyue.blogspot.hk/2015/01/a-brief ...