键盘钩子是一种可以监控键盘操作的指令。

看到这句话是不是觉得其实键盘钩子可以做很多事情.

场景

当你的程序需要一个全局的快捷键时,可以考虑使用键盘钩子,如大家常用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 利用键盘钩子来捕获键盘,做一些不为人知的事情...完整实例的更多相关文章

  1. C# 获取键盘钩子,屏蔽键盘按键

    static int hHook = 0; public delegate int HookProc(int nCode, int wParam, IntPtr lParam); //LowLevel ...

  2. 基于C#实现的HOOK键盘钩子实例代码

    本文所述为基于C#实现的HOOK实例,该实例可用来屏蔽系统热键.程序主要实现了安装钩子.传递钩子.卸载钩子等功能.在传递钩子中:<param name="pHookHandle&quo ...

  3. C# 键盘钩子

    p{ text-align:center; } blockquote > p > span{ text-align:center; font-size: 18px; color: #ff0 ...

  4. 低级键盘钩子,在WIN7以上版本的问题

    最近在项目用到低级键盘钩子.发现一个很奇怪的事情,在开发环境和测试环境下都正常运行的键盘钩子, 到了现场环境,总是偶发性出现 键盘钩子不能用了,而且退出时产生1404 错误. 后经过阅读MSDN 的R ...

  5. WPF 捕获键盘输入事件

    最近修改的一个需求要求捕获键盘输入的 Text,包括各种标点符号. 最开始想到的是 PreviewKeyDown 或者 PreviewKeyUp 这样的键盘事件. 但是这两个事件的对象 KeyEven ...

  6. 在WPF中快速实现键盘钩子

    大部分的时候,当我们需要键盘事件的时候,可以通过在主窗口注册KeyBinding来实现,不过,有的时候我们需要的是全局键盘事件,想在任何一个地方都能使用,最开始的时候我是通过键盘钩子来实现的, 不过键 ...

  7. js简单的设置快捷键,hotkeys捕获键盘键和组合键的输入

    设置快捷键 这是一个强健的 Javascript 库用于捕获键盘输入和输入的组合键,它没有依赖,压缩只有只有(~3kb). hotkeys on Githubhotkeys预览 创建 您将需要在您的系 ...

  8. Hotkeys.js 2.0.2 发布,捕获键盘输入和输入的组合键快捷键,它没有依赖

    这是一个强健的 Javascript 库用于捕获键盘输入和输入的组合键,它没有依赖,压缩只有只有(~3kb),gzip:1.9k. 更新内容: 添加测试用例: 添加更多特殊键支持: 修复bug. __ ...

  9. Hotkeys.js 2.0.2 发布,JS 网页快捷键设置,捕获键盘输入和输入的组合键快捷键,它没有依赖

    这是一个强健的 Javascript 库用于捕获键盘输入和输入的组合键,它没有依赖,压缩只有只有(~3kb),gzip:1.9k. 更新内容: 添加测试用例: 添加更多特殊键支持: 修复bug. __ ...

随机推荐

  1. Uva 11806 拉拉队

    题目链接:https://uva.onlinejudge.org/external/118/11806.pdf 题意: n行m列的矩阵上放k个棋子,其中要求第一行,最后一行,第一列,最后一列必须要有. ...

  2. Python2.x 和 3.x 的区别

    Python有两个版本,2.x 和 3.x ,两个版本不兼容,3.x 不不考虑对2.x代码的向后兼容. 在3.x中,一些语法,内建函数和对象的行为都有所调整. 大部分的python库都支持 pytho ...

  3. 统一项目中编码风格(Eclipse Java code format、codetemplate)

    在公司内的日常开发过程中,除了需要遵守统一的编码规范之外,还需要对编写的代码做统一的格式化,Eclipse提供了格式化编码的工具,快捷键是:Ctrl+Shift+F. 为了统一项目组的代码风格,建议使 ...

  4. Vue nodejs商城项目-项目概述

    项目概况 用vue2.0 +node.js +MongonDB 做了一个商城系统 技术选型 Vue2.0+node.js+express+MongoDB+axios+vuex 构建工具 Webpack ...

  5. ES6介绍

    1.ES6简介 ECMAScript 6.0,是 JavaScript 语言下一代标准,发布于 2015 年 6 月.它的目标是使得 JavaScript 语言可以用来编写复杂的大型应用程序,成为企业 ...

  6. Data Warehouse 业务系统不入仓表

    根据数据仓库的实施经验,凡符合如下特征的表,建议不入仓. ① 备份数据表 此类表是对现有表中某个时点数据的一份拷贝,根据需要进行数据恢复使用.因此,只需取当前表中的数据即可. ② 冗余数据表 同一类数 ...

  7. XML DTD约束 对xml文件的crud的查询Read Retrieve操作 xml递归遍历

    本地的dtd文档 xml中引入dtd文档 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE 书 ...

  8. spring-传统AOP

    Spring传统AOP AOP的增强类型 AOP联盟定义了Advice(org.aopalliance.aop.Interface.Advice) 五类(目标类方法的连接点): 1.  前置通知(or ...

  9. Centos7-Mysql-5.6.41一主两从的搭建

    01.准备工作 首先的前提条件你必须安装了mysql,而且知道你安装mysql配置文件的位置,接下来的事情就好办了. 我的搭建环境: 服务器1: 10.233.17.20 mysql-master(主 ...

  10. 死锁-Java代码示例

    class MyThread implements Runnable{ private Object o1 = new Object(); private Object o2 = new Object ...