C++键盘挂钩
C++ KeyBoard hook
主题:将某些键替换为另一个键值。
例如,如果我按 P,它应该是 F24。
当我尝试从.ini文件钩子加载键值时,它不再是全局的。仅当 winapi 形成焦点时,它才有效。
我的 DLL 代码:
extern "C" __declspec(dllexport) LRESULT CALLBACK KeyboardHook(int, WPARAM, LPARAM);
extern "C" __declspec(dllexport) void loadSettings(LPSTR);
bool shouldUpdateKey = false;
int ArcherKey;
LRESULT CALLBACK KeyboardHook(int code, WPARAM wParam, LPARAM lParam)
{
if ((lParam >> 20))
{
if (wParam == ArcherKey)
{
shouldUpdateKey = shouldUpdateKey ? false : true;
if (shouldUpdateKey)
{
MessageBox(NULL, L"ArcherKey", L"", MB_OK);
keybd_event(0x87, 45, 1, 0); //press F24
return 1;
}
}
}
return CallNextHookEx(NULL, code, wParam, lParam);
}
LPSTR GetValueFromINI(LPSTR FileName, LPSTR Section, LPSTR Key)
{
char *key;
key = (char *)malloc(256);
GetPrivateProfileStringA(Section, Key, NULL, key, 256, FileName);
return key;
free(key);
}
void loadSettings(LPSTR FileName)
{
ArcherKey = atoi(GetValueFromINI(FileName, "HotKey", "Archer key"));
}
我使用 shouldUpdateKey 来避免 x2 回调(当按键按下和向上按下时(调用。我也尝试添加这个语句,如果(lParam>>31( ^ 1,但这个语句总是错误的。
.exe代码:
LRESULT(*pKeybHook)(int, WPARAM, LPARAM);
HHOOK hhookMsg;
void(*loadSettings)(LPSTR);
int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPTSTR lpCmdLine,
_In_ int nCmdShow)
{
/* default code */
HMODULE dll = LoadLibrary(_T("MainHookDLL.dll"));
if (dll)
{
pKeybHook = (LRESULT(*)(int, WPARAM, LPARAM)) GetProcAddress(dll, "_KeyboardHook@12");
loadSettings = (void(*)(LPSTR)) GetProcAddress(dll, "loadSettings");
loadSettings("C:\Settings.ini");
hhookMsg = SetWindowsHookEx(WH_KEYBOARD, (HOOKPROC)(pKeybHook), dll, 0);
}
/* defult code */
UnhookWindowsHookEx(hhookMsg); // unhook
FreeLibrary(dll);
return (int) msg.wParam;
}
设置.ini结构:
[HotKey]
Archer key=80
所以我的问题:如果尝试从文件加载设置,钩子仅在活动的 winapi 窗口中工作。它显示MessageBox\etc,但仅以活动的winapi形式显示。如果将 wParam == ArcherKey 替换为 wParam == 80,则它可以在所有应用程序中全局工作。我调试我的应用程序,从文件加载后.ini我的 ArcherKey = 80。所以我真的无法理解我实际上犯了什么错误。
我所知,如果钩子是全局的,则包含 HOOKPROC 的 DLL 将加载到所有其他进程中。这意味着内存中有多个 DLL 实例。由于您从应用程序中调用 loadSettings(..(,因此仅针对该进程初始化 ArcherKey 的值。这会导致您正在观察的行为。
要更改此设置,您应该将 DllMain(..( 函数修改为如下所示的内容:
BOOL WINAPI DllMain(HINSTANCE hinstDLL, // handle to DLL module
DWORD fdwReason, // reason for calling function
LPVOID lpReserved ) // reserved
{
switch( fdwReason )
{
case DLL_PROCESS_ATTACH:
loadSettings("C:\Settings.ini");
break;
case DLL_THREAD_ATTACH:
// Do thread-specific initialization.
break;
case DLL_THREAD_DETACH:
// Do thread-specific cleanup.
break;
case DLL_PROCESS_DETACH:
// Perform any necessary cleanup.
break;
}
return TRUE;
}
这将初始化正在安装挂钩的所有进程的 ArcherKey 值,因为 Windows 在加载 DLL 时调用 DllMain。出于测试目的,您可以添加消息蜂鸣声(0(;在调用 loadSettings(..( 之前验证代码部分是否已执行。
快速浏览一下 SetWindowsHookEx(..( 的文档让我的担忧成真:如果你正在编译一个 32 位 DLL,你将无法挂接 64 位进程,反之亦然。为此,您必须使用不同名称的 HOOKPROC 实现 64 位版本的 dll。
钩子被"注入"到其他进程中,这意味着你的整个DLL将被加载到所有相关进程中,就好像进程本身(例如记事本.exe(调用了LoadLibrary((。因此,在该上下文中(在其他过程中,例如记事本.exe(,您的设置将不会加载,因此不会初始化 ArcherKey,因此不会显示消息框。
因此,您必须让 DLL 执行初始化,而不是单独的.exe。您可以通过 DLL_PROCESS_ATTACH 上的 DllMain 初始化 ArcherKey(加载您的设置((尽管关于此时哪些 API 是安全的有警告 - 大多数会导致加载其他 DLL 的任何调用都是禁忌(,或者您可以大致添加代码:
static DWORD initialized = 0;
static int ArcherKey;
LRESULT CALLBACK KeyboardHook(int code, WPARAM wParam, LPARAM lParam)
{
if (!initialized)
{
loadSettings();
}
...
}
尽管根本不建议使用此代码,因为长时间运行的钩子至少是相当糟糕的形式,并且可能会导致问题(例如,使该过程停止(。或者,您可以将数据放置在已知的共享位置。编辑:在类似问题的接受答案中,有一些关于共享值的方法的好建议。
LPSTR GetValueFromINI(LPSTR FileName, LPSTR Section, LPSTR Key)
{
char *key;
key = (char *)malloc(256);
GetPrivateProfileStringA(Section, Key, NULL, key, 256, FileName);
return key;
free(key); // <- will never happen
}
ArcherKey = atoi(GetValueFromINI(...)); // <- does not clean up
内存泄漏
- 物理键盘上的触发器按键
- 如何使用C/C++在MacOSX中获得键盘布局
- 视窗键盘输入 c++
- 将鼠标和键盘输入发送到 unity3d 游戏 (Rust)
- C ++异步键盘输入(标准方式)
- 键盘不起作用 - Arduino Uno - 与变量有关的多个错误
- 如何在 WindowProc 处理程序中区分箭头键和数字键盘?
- 覆盖应用程序的低级别键盘挂钩问题
- C++键盘挂钩 CTRL 键卡住
- 在 OpenGL 中使用键盘移动 3D 形状,C++
- SFML 键盘条件或
- 找不到键盘,即使我包括键盘。
- 在C++中隐藏键盘记录器的控制台窗口
- 盖奇不读取键盘输入
- 使用Boost async_read和POSIX::stream_descriptor从键盘读取
- 在 Linux 上C++:在作为 systemd 服务运行时侦听键盘输入
- 是否可以将键盘输入绑定到 Win32 中的单个应用程序?
- SDL2 无法捕获控制台键盘事件?
- 使用 Windows API c++ 的键盘输入
- GTKMM:如何将键盘事件附加到绘图区域?