鼠标键盘钩子-组合键监测
假设目标窗口的句柄已取得(hwnd),然后要用PostMessage向该窗口发送按键消息,对于普通字符键,直接用WM_CHAR消息最简单,如下:
PostMessage hwnd, WM_CHAR, Asc("A"), 0 ' 发送一个 A 字符
对于非普通字符按键,如功能键、方向键等,要用 WM_KEYDOWN、WM_KEYUP 消息,如下:
PostMessage hWndMsg, WM_KEYDOWN, VK_ESCAPE, &H00010001 ' 模拟按下 Esc 键
PostMessage hWndMsg, WM_KEYUP, VK_ESCAPE, &HC0010001 ' 模拟抬起 Esc 键
以上最后一个参数(lParam)低16位(0001)表示按键一次,高8位00表示按下,C0表示抬起,次高8位(01)表示该键的扫描码,可用 API MapVirtualKey(VirtualKey, 0)取得(注意:扫描码在各系统可能会不同,在此以具体数值示例,实际应用MapVirtualKey取得)。
下面要讲Shift/Control/Alt修饰键与其它按键的组合怎样发送,对于Shift和Control用以下方式(用到 API keybd_event):
keybd_event VK_SHIFT, &H2A, 0, 0 ' 模拟按下SHIFT键,&H2A是VK_SHIFT的扫描码
PostMessage hWndMsg, WM_KEYDOWN, VK_A, &H001E0001 ' 模拟按下 A 键,SHIFT+A产生一个大写A字符
PostMessage hWndMsg, WM_KEYUP, VK_A, &HC01E0001 ' 模拟抬起 A 键
keybd_event VK_SHIFT, &H2A, KEYEVENTF_KEYUP, 0 ' 模拟抬起 SHIFT 键
以上VK_SHIFT(扫描码2A)换成VK_CONTROL(扫描码1D)就可以实现Ctrl组合键,VK_A(扫描码1E)也可以换成任意功能键,如VK_F4(扫描码3E)。
对于Alt修饰键比较特别,它属于系统按键,要用 WM_SYSKEYDOWN/WM_SYSKEYUP 消息,如下:
PostMessage hWndMsg, WM_SYSKEYDOWN, VK_F4, &H003E0001 Or &H20000000 ' 模拟按下 Alt+F4
PostMessage hWndMsg, WM_SYSKEYUP, VK_F4, &HC03E0001 Or &H20000000 ' 模拟抬起 Alt+F4
' &H20000000 为 context code 位,置 1 表示 Alt 键被按下
'’捕捉快捷键,控制HOOK开关,alt+/ 助手当前行到最后
If wParam = 191 And (lParam And &H20000000) <> 0 Then
'If (lParam And &HC000000) = 0 Then '是否进行ALT+F4操作
' MyHBHook = 1 '钩子吃掉这个消息
'End If
MyKeyboardProc = 0
annotation注释()
MyKeyboardProc = 1
End If
lParam这个参数我已经知道了是个32位的 3个组合参数
&h 00 00 00 00
高8位 00=按下 C0=弹起
中8位 扫描码
低16位 按键次数和扩展功能
你说的魔法数,意思是不是编程人员因为非常熟悉代码, 随便用了个“富含特定技巧”的数字?
HOOK过程中,wparam是键码,lparam是一些组合信息,其中包含ALT键的状态.
If wParam = 115 这里的115其实是VK_F4,声明个常量会让你的程序可读性大大增加.
而lparam的第29位就是ALT键是否按下,按下为1,否则为零.
‘‘’屏蔽Ctrl+Esc
if kbh.vkCode = Keys.Escape and Control.ModifierKeys = Keys.Control
判断按下CTRL键
If wParam = 76 And (lParam And &H80000000) = 0 And GetKeyState(17) < 0 Then ' ctrl+L
判断按下shift键 只能成功一个,所以先判断功能键,再判断里面的普通按键
keybd_event(16, 0, 0, 0) '按下shift
' keybd_event(16, 2, 0, 0) '抬起shift
Public Declare Sub keybd_event Lib "user32" Alias "keybd_event" (ByVal bVk As Integer, ByVal bScan As Integer, ByVal dwFlags As Integer, ByVal dwExtraInfo As Integer)
Public Declare Function PostMessage Lib "user32" Alias "PostMessageA" (ByVal hwnd As Integer, ByVal wMsg As Integer, ByVal wParam As Integer, lParam As Integer) As Integer
PostMessage(ActiveHandle, WM_KEYDOWN, 16, MakeKeyLparam(16, WM_KEYUP)) '抬起shift
Public Function MakeKeyLparam(ByVal VirtualKey As Integer, ByVal flag As Integer) As Integer
Dim s As String
Dim Firstbyte As String 'lparam参数的24-31位
If flag = WM_KEYDOWN Then '如果是按下键
Firstbyte = "00"
Else
Firstbyte = "C0" '如果是释放键
End If
Dim Scancode As Long
'获得键的扫描码
Scancode = MapVirtualKey(VirtualKey, 0)
Dim Secondbyte As String 'lparam参数的16-23位,即虚拟键扫描码
Secondbyte = Right("00" & Hex(Scancode), 2)
s = Firstbyte & Secondbyte & "0001" '0001为lparam参数的0-15位,即发送次数和其它扩展信息
MakeKeyLparam = Val("&H" & s)
End Function
发送按键函数两个混合用
If (lParam And &H2A) = 0 And GetKeyState(16) < 0 Then ‘判断按下shift键
Sleep(100)
PostMessage(ActiveHandle, WM_KEYUP, 16, MakeKeyLparam(16, WM_KEYUP)) '抬起shift