带有WH_keyboard_LL和keybd_event(windows)的全局键盘挂钩
Global keyboard hook with WH_KEYBOARD_LL and keybd_event (windows)
我正在尝试编写一个简单的全局键盘挂钩程序来重定向一些键。例如,当程序执行时,我按下键盘上的"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 an");
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);
}
非常感谢!
由于WM_KEYDOWN
和WM_KEYUP
,回调函数执行了两次。当你按下键盘上的一个键时,windows会用WM_KEYDOWN
消息调用回调函数;当你松开键时,windows会用WM_KEYUP
消息调用回调功能。这就是回调函数执行两次的原因。
您应该将switch语句更改为:
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 an");
if ( (wParam == WM_KEYDOWN) || (wParam == WM_SYSKEYDOWN) ) // Keydown
{
keybd_event('B', 0, 0, 0);
}
else if ( (wParam == WM_KEYUP) || (wParam == WM_SYSKEYUP) ) // Keyup
{
keybd_event('B', 0, KEYEVENTF_KEYUP, 0);
}
break;
}
break;
}
关于你的第二个问题,我想你已经从@Ivan Danilov那里得到了答案。
第一个很容易。你可以得到一个键向下,另一个键向上。:)
至于为什么它可以在没有DLL的情况下工作,那是因为它是一个全局钩子。与线程特定的不同,它是在您自己的进程中执行的,而不是在发生键盘事件的进程中。这是通过向安装了钩子的线程发送消息来完成的——这正是您需要在这里进行消息循环的原因。如果没有它,你的钩子就无法运行,因为没有人可以监听传入的消息。
特定于线程的挂钩需要DLL,因为它们是在另一个进程的上下文中调用的。为了实现这一点,应该将DLL注入到该进程中。这里的情况并非如此。
- 我已经运行了你的代码,但什么都没发生?我怎么了
- 基于msdn,WH_KEYBOARD_LL消息是"仅全局",这意味着更多。
每当一个新的键盘输入事件即将发布到线程输入队列中时,系统就会调用此函数。此消息是特殊情况。您还需要一个DLL来为其他消息制作一个真正的全局挂钩。
- 为什么在全局范围内使用"extern int a"似乎不行?
- 在全局变量中保存类的实例以重新创建类(创建"backup")
- 在VS代码中交叉编译Windows与Linux上的MinGW的SDL程序
- 在Linux for Windows上编译C++代码时出错
- 在Windows上用C++裁剪HBITMAP
- C++ Windows 驱动程序MSB3030无法复制该文件,因为它找不到
- 当vector是tje全局变量时,c++中vector的内存管理
- std::threads可以从Windows DLL中的全局变量创建/销毁吗?
- 如何在使用 windows.h 时避免使用全局变量 C++.
- 在Windows中检测全局双击
- 在Windows中全局存储C++头文件
- VS2013上Windows上的全局包含路径
- 是否可以将 pnames.icu 的内容存储在 Windows C++全局变量中
- 在没有运行应用程序的情况下添加Windows全局热键
- 64位Windows上的全局Keyhook
- Windows API 全局钩子的无限范围
- #include < windows.h> 在全局命名空间中定义了许多符号,例如 Polygon
- 带有WH_keyboard_LL和keybd_event(windows)的全局键盘挂钩
- 在 Windows Mobile 6.1/6.5 上使用全局热键切换应用程序
- 我可以为那些知道互斥锁密码的进程全局创建一个Windows互斥锁吗?