关于用HOOK拦截键盘的一些问题
先看回调函数KeyboardProc的参数描述:
Syntax
LRESULT CALLBACK KeyboardProc(
int code,
WPARAM wParam,
LPARAM lParam
);
Parameters
code
[in] Specifies a code the hook procedure uses to determine how to process the message. If code is less than zero, the hook procedure must pass the message to the CallNextHookEx function without further processing and should return the value returned by CallNextHookEx. This parameter can be one of the following values.
HC_ACTION
The wParam and lParam parameters contain information about a keystroke message.
HC_NOREMOVE
The wParam and lParam parameters contain information about a keystroke message, and the keystroke message has not been removed from the message queue. (An application called the PeekMessage function, specifying the PM_NOREMOVE flag.)
wParam
[in] Specifies the virtual-key code of the key that generated the keystroke message.
lParam
[in] Specifies the repeat count, scan code, extended-key flag, context code, previous key-state flag, and transition-state flag. For more information about the lParam parameter, see Keystroke Message Flags. This parameter can be one or more of the following values.
0-15
Specifies the repeat count. The value is the number of times the keystroke is repeated as a result of the user's holding down the key.
16-23
Specifies the scan code. The value depends on the OEM.
24
Specifies whether the key is an extended key, such as a function key or a key on the numeric keypad. The value is 1 if the key is an extended key; otherwise, it is 0.
25-28
Reserved.
29
Specifies the context code. The value is 1 if the ALT key is down; otherwise, it is 0.
30
Specifies the previous key state. The value is 1 if the key is down before the message is sent; it is 0 if the key is up.
31
Specifies the transition state. The value is 0 if the key is being pressed and 1 if it is being released.
第一个参数原文说了“This parameter can be one of the following values.”(这个参数可以是以下取值中的一个),总共只列出了两个值HC_ACTION和HC_NOREMOVE,所以这里我们采用了HC_ACTION值,代码写成“If code = HC_ACTION Then”,这个想必对你来说理解起来难度不大。
第二个参数原文说wParam表示的是一个“virtual-key code”,这里我们称为虚拟键盘码,virtual-key code是不区分大小写的,如果要判断输入的大小写状态,可以用API函数GetKeyState或GetAsyncKeyState,也可以用GetKeyboardState函数把256个virtual-key code状态全部扫描一遍,这些函数怎么判断这里不再阐述,查阅MSDN就能得到答案。那么键盘上“A”的virtual-key code是多少,如果你安装过VC++的话,可以在“winuser.h”中第371行看到这样定义的“VK_A thru VK_Z are the same as ASCII 'A' thru 'Z' (0x41 - 0x5A)”(虚拟键盘码A到Z与它们的ASCII码相同)。这里我用的ASCII码采用的16进制,所以我写成“If wParam = &H41 Then”,这里写16进制还是10进制并没什么影响,如果你习惯使用10进制表示的ASCII码就用10进制表示,我之所以喜欢用16进制表示字符,是由于系统自带的“字符映射表”工具中都是用16进制表示的,通过查表后不需作进制转换直接用16进制描述字符更方便点。
第三个参数可能就是你问题最大的地方,它关系到判断按键的状态,所以我把第三个参数翻译一遍:
lParam
[输入]表示了重复次数,扫描码,扩展键标志,上下文码,按键之前的状态标志,和按键状态跃变标志,要获得更多关于lParam参数的信息,查阅“Keystroke Message Flags”(http://msdn.microsoft.com/library/en-us/winui/winui/windowsuserinterface/userinput/keyboardinput/aboutkeyboardinput.asp)。这个参数由以下一个或多个值组成:
0-15
表示重复次数。其值是用户保持按下键状态导致的重复击键次数。
16-23
表示扫描码。该值与OEM厂商有关。(什么是扫描码稍候可以简介一下)
24
表示键是否是一个扩展键,例如一个功能键或数字键盘区的键。如果这个键是一个扩展键,其值为1,否则值为0。
25-28
保留,未使用。
29
表示上下文码。如果ALT键是按下状态,其值为1,否则值为0。
30
表示按键之前的状态标志。如果在这个消息发送之前,键是被按下状态,其值为1;如果在这个消息发送之前,键是抬起状态,其值为0。
31
表示按键状态跃变标志。如果键跃变到按下状态,其值为0;如果键跃变到释放状态,其值为1。
这个参数描述的0-31可以用后面的图来表示其意义:

从这个参数的解释来看,要判断键是按下还是抬起状态,甚至持续按下状态,可以用30和31位来表示,因此,我们只关心30、31位的值,为了不使其他位的值干扰我们判断的结果,我们先把其他位的值都变成0。于是我们代码中写成“lParam And &HC0000000”这里&HC0000000是16进制,展开成2进制就是(1100 0000 0000 0000 0000 0000 0000 0000),意义就是通过与运算只保留30、31位的原值。与运算完成后,仅剩30、31位有意义了,这时再来判断键的状态。
如果要判断按下键,那么在按键之前键肯定是处于抬起状态的,所以30位应该是0;当键被按下后,其状态从释放状态跃变到按下状态,所以31位应该是0;剩下的0-29位也是0,所以“(lParam And &HC0000000) = &H0”就是按下键的标志。
如果要判断抬起键,那么在按键之前键肯定是处于按下状态的,所以30位应该是1;当键被按下后,其状态从按下状态跃变到释放状态,所以31位应该是1;剩下的0-29位也是0,所以“(lParam And &HC0000000) = &HC0000000”就是抬起键的标志,上面已经说了&HC0000000的2进制是(1100 0000 0000 0000 0000 0000 0000 0000)。
如果要判断持续按下键,那么在这个按键消息到达之前键肯定是处于按下状态的,所以30位应该是1;当这个按键消息到达后,其状态仍然是按下状态,没有跃变到释放状态,所以31位应该是0;剩下的0-29位也是0,所以“(lParam And &HC0000000) = &H40000000”就是持续按下键的标志,&H40000000的2进制是(0100 0000 0000 0000 0000 0000 0000 0000)。
说道这里,判断的方法你应该弄明白了吧。
前面还提到一个概念叫“scan code”,扫描码,这里可以简单介绍一下扫描码的概念,感兴趣的可以继续往下看。先看看MSDN对“scan code”的说明,然后再翻译一下大家应该就明白了,原文如下:
Scan Code
The scan code is the value that the keyboard hardware generates when the user presses a key. It is a device-dependent value that identifies the key pressed, as opposed to the character represented by the key. An application typically ignores scan codes. Instead, it uses the device-independent virtual-key codes to interpret keystroke messages.
扫描码
扫描码的值是当用户按下键时由键盘硬件生成的。这个值是与硬件设备相关的,标志着键按下、抬起时所表示的键对应的字符。应用程序通常忽略扫描码,而使用与硬件设备无关的虚拟键盘码代替,虚拟键盘码用来表示击键消息。
关于用HOOK拦截键盘的一些问题的更多相关文章
- 简单全局HOOK拦截大部分键盘消息
前言:学习HOOK中,万一老师讲解HOOK入门教程:http://www.cnblogs.com/del/category/124150.html http://www.cnblogs.com/del ...
- 初探hook的键盘获取
初探hook的键盘获取 import pyHook import pythoncom class e(): keyIsPressed = False #键盘是否按下 按住.. def onKeyDow ...
- hook 鼠标键盘消息实例分析
1.木马控制及通信方法包含:双管道,port重用.反弹技术.Hook技术,今天重点引用介绍一下hook的使用方法,hook信息后能够将结果发送到hacker邮箱等.实现攻击的目的. 转自:http:/ ...
- windows hook + pyhook3 + python win32api hook + C 键盘hook
安装pyhook3见:https://www.cnblogs.com/lqerio/p/12096710.html 使用见:https://www.cnblogs.com/lqerio/p/12106 ...
- [Windows Hook] 屏蔽键盘按键
//该例程为在系统级屏蔽一些系统键.如WIN.TAB.CAP.POWER.SLEEP.HOME等! //屏蔽组合键下面例程不适用!(比如CTRL+ESC需要在钩子函数中用(p.vkCode = VK_ ...
- HOOK 底层键盘消息---WH_KEYBOARD_LL
代码:屏蔽三个全局快捷键 代码的作用是屏蔽掉凝视中的三个快捷键. LRESULT CALLBACK LowLevelKeyboardProc (INT nCode, WPARAM wParam, LP ...
- hook鼠标键盘记录和回放
unit Unit1; // download by http://www.codefans.net interface uses Windows, Messages, SysUtils, Class ...
- hook键盘驱动中的分发函数实现键盘输入数据的拦截
我自己在看<寒江独钓>这本书的时候,书中除了给出了利用过滤的方式来拦截键盘数据之外,也提到了另外一种方法,就是hook键盘分发函数,将它替换成我们自己的,然后再自己的分发函数中获取这个数据 ...
- Java语言的Hook实现
引言:最近在玩完美时空的诛仙Online(不知道这里有没人有共同爱好的),这个游戏每晚七点会出现一个任务"新科试炼".这个任务简单地说就是做选择题,范围小到柴米油盐,大到世界大千, ...
随机推荐
- pytorch中的math operation: torch.bmm()
torch.bmm(batch1, batch2, out=None) → Tensor Performs a batch matrix-matrix product of matrices stor ...
- 在ubuntu上安装npm
sudo apt install npm 执行上面的安装命令,会报错: Reading package lists... Done Building dependency tree Reading s ...
- 【JavaScript 6—基础知识点】:正则表达式(应用)
导读:其实,我不像大家一样,从一开始就重视着正则表达式,我甚至都觉得好浪费时间浪费精力,都没用的.因为,如果我要判断是不是为数字,我可以使用Numberic()方法,如果要去空格的话,使用trim() ...
- BZOJ 2820 YY的GCD ——莫比乌斯反演
我们可以枚举每一个质数,那么答案就是 $\sum_{p}\sum_{d<=n}\mu(d)*\lfloor n / pd \rfloor *\lfloor m / pd \rfloor$ 直接做 ...
- 2013 Dhaka 区域赛
A.uva 12709 Falling ANTS 首先按照H排序,然后按照L*H*W排序 #include<iostream> #include<cstdio> #includ ...
- 刷题总结——spoj1812(后缀自动机+DP)
题目: A string is finite sequence of characters over a non-empty finite set Σ. In this problem, Σ is t ...
- Codeforces Round #512 (Div. 2, based on Technocup 2019 Elimination Round 1) E. Vasya and Good Sequences
题目链接 官网题解写的好清楚,和昨晚Aguin说的一模一样…… 这题只和每个数1的个数有关,设每个数1的个数的数组为$b$,就是首先一段如果是好的,要满足两个条件: 1.这一段$b$数组和为偶数,因为 ...
- Callable和Runnable和FutureTask
http://www.cnblogs.com/dolphin0520/p/3949310.html 一.Callable与Runnable 二.Future 三.FutureTask 四.使用示例 一 ...
- Spring 详解(三)------- SpringMVC拦截器使用
目录 不拦截静态资源 使用拦截器 拦截器使用测试 SimpleMappingExceptionResolver 拦截异常 不拦截静态资源 如果配置拦截类似于*.do格式的拦截规则,则对静态资源的访问是 ...
- Oracle 12c agent install for linux
安装Agent代理 在EM11g时,agent安装是通过在被监制主机端下载agent代理并安装,在EM12c版本号上,能够在EM12c服务端.通过"推送"的方式把agent代理在远 ...