覆盖应用程序的低级别键盘挂钩问题
Low level keyboard hook issue with an overlay application
这里的第一篇文章,多年来我一直在研究这个问题的正确解决方案。
我有自己的 UI 引擎,有自己的键盘处理,并且正在使用它来显示游戏覆盖。游戏覆盖本身对键盘和窗口事件都是透明的,以便对游戏的干扰最小,但为了使覆盖本身具有交互性,我需要求助于键盘和鼠标钩子来阻止某些事件到达游戏。对于鼠标输入,这是非常微不足道的,并且效果很好。这是我遇到问题的低级键盘钩子。
在这一点上,我有一些在大多数情况下可用的东西。我设法解决了几个涉及死键和错误输入的问题,但从未设法创建一个可以主动阻止游戏键盘输入的钩子 - 总是会出错。
例如,当用户尝试在覆盖层的文本框中编写一些文本并且不希望游戏处理相同的击键时,主动阻止键盘输入将最有用。
我目前的问题是,如果我通过在挂钩过程中返回非零值来阻止键盘输入,则覆盖层的 UI 引擎将停止感知Ctrl键的状态,从而导致无法复制/粘贴到覆盖层的文本框中。有趣的是,在Alt-Tab'ing之前,一切正常,但在那之后,按Ctrl键钩抓取从VK_CONTROL
转到VK_LCONTROL
.更有趣的是,GetKeyState(VK_CONTROL)
、GetAsyncKeyState(VK_CONTROL)
和 UI 端的GetAsyncKeyState(VK_LCONTROL)
都没有将Ctrl键注册为按下。
由于多年的实验和解决方法,下面的键盘挂钩的代码有点混乱。我会尽我所能评论它。
LRESULT __stdcall KeyboardHook( int code, WPARAM wParam, LPARAM lParam )
{
// this is an early exit if the game tells me that it actively has focus
if ( disableHooks || mumbleLink.textBoxHasFocus )
return CallNextHookEx( 0, code, wParam, lParam );
// the following two early exits are remnants from earlier experimentation
if ( code < 0 )
return CallNextHookEx( 0, code, wParam, lParam );
if ( wParam != WM_KEYDOWN && wParam != WM_KEYUP && wParam != WM_CHAR && wParam != WM_DEADCHAR && wParam != WM_UNICHAR )
return CallNextHookEx( 0, code, wParam, lParam );
// this checks if either the game or the overlay are in focus and otherwise ignores keyboard input
auto wnd = GetForegroundWindow();
if ( code != HC_ACTION || !lParam || ( wnd != gw2Window && App && wnd != (HWND)App->GetHandle() ) )
return CallNextHookEx( 0, code, wParam, lParam );
// this ignores the overlay itself if it's in focus for some odd reason
if ( App && wnd == (HWND)App->GetHandle() )
return CallNextHookEx( 0, code, wParam, lParam );
KBDLLHOOKSTRUCT *kbdat = (KBDLLHOOKSTRUCT*)lParam;
UINT mapped = MapVirtualKey( kbdat->vkCode, MAPVK_VK_TO_CHAR );
// this bool tests if the overlay has a textbox in focus and the keyboard input should be blocked from propagating further
bool inFocus = App->GetFocusItem() && App->GetFocusItem()->InstanceOf( "textbox" );
// forcefully inject a WM_CHAR message to the overlay's UI engine - never figured out how to trigger a message that would be translated into a WM_CHAR properly
if ( !( mapped & ( 1 << 31 ) ) && !inFocus && wParam == WM_KEYDOWN )
App->InjectMessage( WM_CHAR, mapped, 0 );
if ( inFocus )
{
PostMessage( (HWND)App->GetHandle(), wParam, kbdat->vkCode, 1 | ( kbdat->scanCode << 16 ) + ( kbdat->flags << 24 ) );
/////////////////////////////////////////////////
return 1; // this is where the key input should be blocked, but it causes the mentioned issues with the ctrl key (and probably others too)
/////////////////////////////////////////////////
}
return CallNextHookEx( 0, code, wParam, lParam );
}
UI 引擎本身通过GetKeyState()
检查Ctrl、Shift和 Alt 状态,因为通过WM_SYSKEYDOWN
消息跟踪这些状态会导致Alt-Tab卡住Alt键,因为窗口永远不会收到WM_SYSKEYUP
消息。必要时,在几个不同的WM_...
消息上调用检查Ctrl/Shift/Alt键状态的函数。但是,一旦VK_LCONTROL
消息开始被键盘挂钩而不是VK_CONTROL
消息拦截,此函数始终将所有键报告为未按下。
您可以尝试不同的方法。如果在此期间您的叠加层是活动窗口,则可以在没有挂钩的情况下处理键盘和鼠标事件,如果要将事件转发到游戏,只需为游戏窗口合成事件即可。
- 警告处理为错误这里有什么问题
- 最小硬币更换问题(自上而下方法)
- 为"adjacent"变量赋值时出现问题
- 我的神经网络不起作用 [XOR 问题]
- 在Ubuntu 16.04上安装Cilk时出现问题
- C++我的数学有什么问题,为什么我的代码不能正确循环
- 物理键盘上的触发器按键
- 编译包含字符串的代码时遇到问题
- Project Euler问题4的错误解决方案
- 问题:什么是QAbstractItemView::NoEditTriggers的反面
- 在编译C++代码(具有dlib和opencv)到WASM时面临问题
- 在进程中对同一管道进行读取和写入时C++管道出现问题
- 静态数据成员的问题-修复链接错误会导致编译器错误
- 覆盖应用程序的低级别键盘挂钩问题
- 键盘有一些问题
- 显示和隐藏Windows 10屏幕键盘(osk.exe)时遇到问题
- 奇怪的SDL键盘问题
- 多个玩家的键盘输入问题
- Linux 键盘扫描码问题:例如,向上箭头给出 ^[[A.
- 使用SetWindowsHookEx钩子键盘消息的问题