如何在C#中使用全局鼠标、键盘Hook
今天,有个同事问我,怎样在C#中使用全局钩子?以前写的全局钩子都是用unmanaged C或C++写个DLL来实现,可大家都知道,C#是基于.Net Framework的,是managed,怎么实现全局钩子呢?于是开始到网上搜索,好不容易找到一篇,318804 - HOW TO: Set a Windows Hook in Visual C# .NET,里面详细的说明了如何使用鼠标钩子捕获鼠标的移动等,可是,它只能在Application里起作用,出了Application就没用了,就是说它还是没有实现全局钩子,而且文章结尾处说:“Global Hooks are not supported in the .NET Framework...”,这可怎么办呢?
别担心,办法总是有的,经过一番摸索以后,发现WH_KEYBORAD_LL和WH_MOUSE_LL这两个low-level的hook可以被安装成全局的,这就好办了,我们不妨用这两个low-level的hook替换掉WH_KEYBORAD和WH_MOUSE,于是开始测试。结果成功了,在C#里实现了全局钩子。
我们来看一下主要代码段。
首先倒入所需要的windows函数,主要有三个,SetWindowsHookEX用来安装钩子,UnhookWindowsHookEX用来卸载钩子以及CallNextHookEX用来将hook信息传递到链表中下一个hook处理过程。
- [DllImport("user32.dll", CharSet = CharSet.Auto,
- CallingConvention = CallingConvention.StdCall, SetLastError = true)]
- private static extern int SetWindowsHookEx(
- int idHook,
- HookProc lpfn,
- IntPtr hMod,
- int dwThreadId);
- [DllImport("user32.dll", CharSet = CharSet.Auto,
- CallingConvention = CallingConvention.StdCall, SetLastError = true)]
- private static extern int UnhookWindowsHookEx(int idHook);
- [DllImport("user32.dll", CharSet = CharSet.Auto,
- CallingConvention = CallingConvention.StdCall)]
- private static extern int CallNextHookEx(
- int idHook,
- int nCode,
- int wParam,
- IntPtr lParam);
- 下面是有关这两个low-level hook在Winuser.h中的定义:
- /// <summary>
- /// Windows NT/2000/XP: Installs a hook procedure that monitors low-level mouse input events.
- /// </summary>
- private const int WH_MOUSE_LL = 14;
- /// <summary>
- /// Windows NT/2000/XP: Installs a hook procedure that monitors low-level keyboard input events.
- /// </summary>
- private const int WH_KEYBOARD_LL = 13;
- 在安装全局钩子的时候,我们就要做替换了,将WH_MOUSE和WH_KEYBORAD分别换成WH_MOUSE_LL和WH_KEYBORAD_LL:
- //install hook
- hMouseHook = SetWindowsHookEx(
- WH_MOUSE_LL, //原来是WH_MOUSE
- MouseHookProcedure,
- Marshal.GetHINSTANCE(
- Assembly.GetExecutingAssembly().GetModules()[0]),
- 0);
- //install hook
- hKeyboardHook = SetWindowsHookEx(
- WH_KEYBOARD_LL, //原来是WH_KEYBORAD
- KeyboardHookProcedure,
- Marshal.GetHINSTANCE(
- Assembly.GetExecutingAssembly().GetModules()[0]),
- 0);
- 这样替换了之后,我们就可以实现全局钩子了,而且,不需要写DLL。看一下程序运行情况:
- 下面是关于鼠标和键盘的两个Callback函数:
- private int MouseHookProc(int nCode, int wParam, IntPtr lParam)
- {
- // if ok and someone listens to our events
- if ((nCode >= 0) && (OnMouseActivity != null))
- {
- //Marshall the data from callback.
- MouseLLHookStruct mouseHookStruct = (MouseLLHookStruct)Marshal.PtrToStructure(lParam, typeof(MouseLLHookStruct));
- //detect button clicked
- MouseButtons button = MouseButtons.None;
- short mouseDelta = 0;
- switch (wParam)
- {
- case WM_LBUTTONDOWN:
- //case WM_LBUTTONUP:
- //case WM_LBUTTONDBLCLK:
- button = MouseButtons.Left;
- break;
- case WM_RBUTTONDOWN:
- //case WM_RBUTTONUP:
- //case WM_RBUTTONDBLCLK:
- button = MouseButtons.Right;
- break;
- case WM_MOUSEWHEEL:
- //If the message is WM_MOUSEWHEEL, the high-order word of mouseData member is the wheel delta.
- //One wheel click is defined as WHEEL_DELTA, which is 120.
- //(value >> 16) & 0xffff; retrieves the high-order word from the given 32-bit value
- mouseDelta = (short)((mouseHookStruct.mouseData >> 16) & 0xffff);
- //TODO: X BUTTONS (I havent them so was unable to test)
- //If the message is WM_XBUTTONDOWN, WM_XBUTTONUP, WM_XBUTTONDBLCLK, WM_NCXBUTTONDOWN, WM_NCXBUTTONUP,
- //or WM_NCXBUTTONDBLCLK, the high-order word specifies which X button was pressed or released,
- //and the low-order word is reserved. This value can be one or more of the following values.
- //Otherwise, mouseData is not used.
- break;
- }
- //double clicks
- int clickCount = 0;
- if (button != MouseButtons.None)
- if (wParam == WM_LBUTTONDBLCLK || wParam == WM_RBUTTONDBLCLK) clickCount = 2;
- else clickCount = 1;
- //generate event
- MouseEventArgs e = new MouseEventArgs(
- button,
- clickCount,
- mouseHookStruct.pt.x,
- mouseHookStruct.pt.y,
- mouseDelta);
- //raise it
- OnMouseActivity(this, e);
- }
- //call next hook
- return CallNextHookEx(hMouseHook, nCode, wParam, lParam);
- }
- private int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam)
- {
- //indicates if any of underlaing events set e.Handled flag
- bool handled = false;
- //it was ok and someone listens to events
- if ((nCode >= 0) && (KeyDown != null || KeyUp != null || KeyPress != null))
- {
- //read structure KeyboardHookStruct at lParam
- KeyboardHookStruct MyKeyboardHookStruct = (KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct));
- //raise KeyDown
- if (KeyDown != null && (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN))
- {
- Keys keyData = (Keys)MyKeyboardHookStruct.vkCode;
- KeyEventArgs e = new KeyEventArgs(keyData);
- KeyDown(this, e);
- handled = handled || e.Handled;
- }
- // raise KeyPress
- if (KeyPress != null && wParam == WM_KEYDOWN)
- {
- bool isDownShift = ((GetKeyState(VK_SHIFT) & 0x80) == 0x80 ? true : false);
- bool isDownCapslock = (GetKeyState(VK_CAPITAL) != 0 ? true : false);
- byte[] keyState = new byte[256];
- GetKeyboardState(keyState);
- byte[] inBuffer = new byte[2];
- if (ToAscii(MyKeyboardHookStruct.vkCode,
- MyKeyboardHookStruct.scanCode,
- keyState,
- inBuffer,
- MyKeyboardHookStruct.flags) == 1)
- {
- char key = (char)inBuffer[0];
- if ((isDownCapslock ^ isDownShift) && Char.IsLetter(key)) key = Char.ToUpper(key);
- KeyPressEventArgs e = new KeyPressEventArgs(key);
- KeyPress(this, e);
- handled = handled || e.Handled;
- }
- }
- // raise KeyUp
- if (KeyUp != null && (wParam == WM_KEYUP || wParam == WM_SYSKEYUP))
- {
- Keys keyData = (Keys)MyKeyboardHookStruct.vkCode;
- KeyEventArgs e = new KeyEventArgs(keyData);
- KeyUp(this, e);
- handled = handled || e.Handled;
- }
- }
- //if event handled in application do not handoff to other listeners
- if (handled)
- return 1;
- else
- return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam);
- }
如何在C#中使用全局鼠标、键盘Hook的更多相关文章
- C#全局鼠标键盘Hook
原文出自:http://www.cnblogs.com/iEgrhn/archive/2008/02/17/1071392.html using System; using System.Collec ...
- 如何在ArcMap中监听键盘鼠标事件(转)
如何在ArcMap中监听键盘鼠标事件(转) Link: http://www.cnblogs.com/dyllove98/p/3155551.html 昨天有个朋友想要实现一个功能,就是在ArcMap ...
- 在C#中使用全局鼠标、键盘Hook
今天,有个同事问我,怎样在C#中使用全局钩子?以前写的全局钩子都是用unmanaged C或C++写个DLL来实现,可大家都知道,C#是基于.Net Framework的,是managed,怎么实现全 ...
- 全局鼠标钩子:WH_MOUSE_LL, 在【 win 10 上网本】上因为太卡,运行中丢失全局鼠标钩子
一台几年前买的上网本,让我安装了一个 win 10,然后用来测试程序的时候, 发现 使用 SetWindowsHookEx(WH_MOUSE_LL, mouseHook, GetModuleHandl ...
- 将CodedUI Test 放到控制台程序中,模拟鼠标键盘操作
CodedUI Test是微软的自动化测试工具,在VS中非常好用.可以用来模拟鼠标点击,键盘输入.但执行的时候必须要用mstest调用,无法传入参数(当然可以写入config文件中,但每次修改十分麻烦 ...
- 如何在 pyqt 中实现全局事件总线
前言 在 Qt 中可以使用信号和槽机制很方便地实现部件之间的通信,考虑下面这样的场景: 我想要点击任意一个专辑卡并通知主界面跳转到专辑界面,那么一种实现方式如上图所示:点击任意一个蓝色方框所示的专辑卡 ...
- 如何在ArcMap中监听键盘鼠标事件
昨天有个朋友想要实现一个功能,就是在ArcMap中编辑数据的时候,能够通过快捷键自动设置预定义的属性,比如,选中若干要素,按A键,就自动填充属性,按B键,则又自动填充另外的属性字段. 单就这个功能而言 ...
- [No0000AC]全局鼠标键盘模拟器
之前网上下载的一位前辈写的工具,名叫:Dragon键盘鼠标模拟器,网址http://www.esc0.com/. 本软件能够录制键盘鼠标操作,并能按要求回放,对于重复的键盘鼠标操作,可以代替人去做,操 ...
- 如何在Vue中建立全局引用或者全局命令
1 一般在vue中,有很多vue组件,这些组件每个都是一个文件.都可能需要引用到相同模块(或者插件).我们不想每个文件都import 一次模块. 如果是基于vue.js编写的插件我们可以用 Vue.u ...
随机推荐
- Python超级程序员使用的开发工具
我以个人的身份采访了几个顶尖的Python程序员,问了他们以下5个简单的问题: 当前你的主要开发任务是什么? 你在项目中使用的电脑是怎样的? 你使用什么IDE开发? 你将来的计划是什么? 有什么给Py ...
- Chapter6:函数
执行函数的第一步是(隐式地)定义并初始化它的形参.所以,函数最外层作用域中的局部变量也不能使用与函数形参一样的名字. 局部静态变量:在程序的执行路径第一次经过对象定义语句时初始化,并且直到程序终止才被 ...
- Visual Basic相关图书推荐
Visual Basic从入门到精通(第2版) 作 者 国家863中部软件孵化器 编 出 版 社 人民邮电出版社 出版时间 2015-03-01 版 次 2 页 数 61 ...
- 初识---Qt解析XML文件(QDomDocument)
关于XML及其使用场景不在此多做介绍,今天主要介绍Qt中对于XML的解析.QtXml模块提供了一个读写XML文件的流,解析方法包含DOM和SAX,两者的区别是什么呢? DOM(Document Ob ...
- 使用nodejs中httpProxy代理时候出现404异常
在公司中使用nodejs构建代理服务器实现前后台分离,代码不能拿出来,然后出现httpProxy代理资源的时候老是出现404.明明被代理的接口是存在的.代码大概如下: var http = requi ...
- Web 检测代码 web analysis 开源 open source
1. Grape Web Statistics Grape Web Statistics is a fairly simple piece of analytics software. Grape i ...
- 关闭HTML5只能提示(form上新增novalidate)
<form novalidate> <input type="text" required /> <input type="su ...
- 一排下去再上来的div
<!DOCTYPE HTML> <html> <head> <meta http-equiv="Content-Type" content ...
- 第二百零二天 how can I 坚持
最近增肥好明显,胃口好没办法,只要肚子起不来就行了.加油. 其实挺幸福,想吃啥吃啥. 鱼会不会被冻死,买了加热棒不想用,该咋办呢. 股市又跌没了一千多,还是不够睿智,不够淡定. 人活这一辈子,到底最想 ...
- 转】Mahout分步式程序开发 基于物品的协同过滤ItemCF
原博文出自于: http://blog.fens.me/hadoop-mahout-mapreduce-itemcf/ 感谢! Posted: Oct 14, 2013 Tags: Hadoopite ...