覆盖应用程序的低级键盘钩子问题

问题描述 投票:4回答:1

第一次在这里发帖,我一直在纠结这个问题的正确解决方法。

我有一个自己的UI引擎,它有自己的键盘处理功能,并且正在用它来显示一个游戏覆盖层。游戏叠加本身对键盘和窗口事件都是透明的,为了尽量减少对游戏的干扰,但为了让叠加本身具有交互性,我需要借助键盘和鼠标钩子来阻止一些事件到达游戏。对于鼠标输入来说,这是很琐碎的,而且效果完美。我遇到问题的是低级别的键盘钩子。

在这一点上,我有一些在大多数情况下可以使用的东西。我设法解决了几个涉及死键和不良输入的问题,但从来没有设法创建一个可以主动阻止键盘输入到游戏中的钩子--有些东西总是出错。

例如,当用户试图在覆盖层上的文本框中写一些文本,并且不希望游戏处理相同的按键时,主动阻止键盘输入将是最有用的。

我目前的问题是,如果我在钩子过程中通过返回一个非零值来阻止键盘输入,那么覆盖层的UI引擎就会停止感知 Ctrl 键的状态,导致无法复制粘贴到覆盖层的文本框中。有趣的是,在 Alt-Tab锭,一切都很好,但在这之后, Ctrl 钩子抓取从 VK_CONTROLVK_LCONTROL. 更有趣的是,无论是 GetKeyState(VK_CONTROL) 也不 GetAsyncKeyState(VK_CONTROL) 也不 GetAsyncKeyState(VK_LCONTROL) 在UI端注册 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引擎本身会检查 Ctrl, 换挡祭祀 国家通过 GetKeyState() 因为通过跟踪这些 WM_SYSKEYDOWN 比如说,这些信息会导致 Alt-Tab 具有 祭祀 键卡住了,因为窗口永远不会收到 WM_SYSKEYUP 消息。的状态的函数。Ctrl换挡祭祀 键被调用在几个不同的 WM_... 必要的时候,会有消息。然而,一旦 VK_LCONTROL 信息开始被键盘钩子拦截,而不是被键盘钩子拦截。VK_CONTROL 的,这个功能总是报告所有的键都没有按下。

c++ winapi keyboard keyboard-hook
1个回答
0
投票

你可以试试不同的方法。如果你的叠加是这期间的活动窗口,那么你可以不用钩子处理键盘和鼠标事件,如果你想把一个事件转发给游戏,你可以直接为游戏窗口合成事件。

© www.soinside.com 2019 - 2024. All rights reserved.