博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
WPF 利用键盘钩子来捕获键盘,做一些不为人知的事情...完整实例
阅读量:7235 次
发布时间:2019-06-29

本文共 5040 字,大约阅读时间需要 16 分钟。

原文:

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

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

 

场景

当你的程序需要一个全局的快捷键时,可以考虑使用键盘钩子,如大家常用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;///         /// 安装键盘钩子        ///         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);        }        ///         /// 卸载键盘钩子        ///         public void UnHook()        {            Win32Api.UnhookWindowsHookEx(hHook);        }                ///         /// 获取键盘消息        ///         ///         ///         ///         /// 
private int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam) { // 如果该消息被丢弃(nCode<0 if (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

转载地址:http://vqgfm.baihongyu.com/

你可能感兴趣的文章
通过VS2010的内存分析工具来分析程序性能问题
查看>>
mini-cygwin
查看>>
如何能低成本地快速获取大量目标用户,而不是与竞争对手持久战?
查看>>
三分钟教你同步 Visual Studio Code 设置
查看>>
程序员,你是选择25k的996还是18k的8小时工作日?
查看>>
Socket编程入门(基于Java实现)
查看>>
RX第一章
查看>>
DOM0级和DOM2级事件
查看>>
iOS Client 与WebSocket 通信(二)(转)
查看>>
网易考拉海购Java后台开发实习-面经(已拿offer)
查看>>
React-Router看这里
查看>>
打造一个通用的 RecyclerView Adapter
查看>>
基于redis的秒杀
查看>>
js如何实现上拉加载更多...
查看>>
.Net Core Logger 实现log写入本地文件系统
查看>>
Java Servlet关键点详解
查看>>
深入分析luait反编译之luajit-decomp
查看>>
从头编写 asp.net core 2.0 web api 基础框架 (5) EF CRUD
查看>>
【我们一起写框架】MVVM的WPF框架(五)—完结篇
查看>>
学习ASP.NET Core Razor 编程系列十一——把新字段更新到数据库
查看>>