【发布时间】:2014-04-09 23:37:17
【问题描述】:
我正在尝试编写一个简单的全局键盘挂钩程序来重定向一些键。例如,当程序执行时,我按下键盘上的'a',程序可以禁用它并模拟'b'点击。我不需要图形用户界面,只需一个控制台就足够了(保持运行)
我的计划是使用全局钩子捕捉按键输入,然后使用keybd_event模拟键盘。但是我有一些问题。
第一个问题是程序可以正确地阻止'A',但是如果我在键盘上按一次'A',回调函数中的printf会执行两次,以及keybd_event。因此,如果我打开一个 txt 文件,我单击“A”一次,有两个“B”输入。这是为什么呢?
第二个问题是为什么使用WH_KEYBOARD_LL的钩子可以在没有dll的情况下在其他进程上工作?在我写这个例子之前,我认为我们必须使用一个 dll 来制作一个全局钩子......
#include "stdafx.h"
#include <Windows.h>
#define _WIN32_WINNT 0x050
LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
BOOL fEatKeystroke = FALSE;
if (nCode == HC_ACTION)
{
switch (wParam)
{
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
case WM_KEYUP:
case WM_SYSKEYUP:
PKBDLLHOOKSTRUCT p = (PKBDLLHOOKSTRUCT)lParam;
if (fEatKeystroke = (p->vkCode == 0x41)) { //redirect a to b
printf("Hello a\n");
keybd_event('B', 0, 0, 0);
keybd_event('B', 0, KEYEVENTF_KEYUP, 0);
break;
}
break;
}
}
return(fEatKeystroke ? 1 : CallNextHookEx(NULL, nCode, wParam, lParam));
}
int main()
{
// Install the low-level keyboard & mouse hooks
HHOOK hhkLowLevelKybd = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, 0, 0);
// Keep this app running until we're told to stop
MSG msg;
while (!GetMessage(&msg, NULL, NULL, NULL)) { //this while loop keeps the hook
TranslateMessage(&msg);
DispatchMessage(&msg);
}
UnhookWindowsHookEx(hhkLowLevelKybd);
return(0);
}
非常感谢!
【问题讨论】:
-
全局挂钩不会阻止输入,它们只是让您预览它。
-
@CodyGray 根据msdn.microsoft.com/en-us/library/windows/desktop/… - “...可能返回一个非零值以防止系统将消息传递给钩子链的其余部分或目标窗口过程”。对我来说,阻止系统将消息传递给目标窗口过程看起来就像阻塞一样。
-
对于那些试图让它工作但收到 ERROR_HOOK_NEEDS_HMOD (1428) 的人:根据SetWindowsHookEx doc,“如果 hMod 参数为 NULL 并且 dwThreadId 参数为零,则可能会发生错误” .因此,您必须指定
hMod,但在这种情况下,您可以使用任何合法值,因为无论如何都不会为低级挂钩注入 DLL。例如,您可以使用GetModuleHandle("kernel32.dll")。
标签: c++ hook keyboard-events keyboard-hook