简体   繁体   English

数字键事件导致GetKeyboardState中的键卡住

[英]Numpad key events result in stuck keys from GetKeyboardState

I've got a C++ (MFC) app that needs to check the keystate on a timer. 我有一个C ++(MFC)应用程序,需要检查计时器上的键状态。 If the user is holding down a key, we delay processing of some code. 如果用户按住某个键,我们将延迟某些代码的处理。

Here's the check for the keydown : 这是keydown检查:

if (!GetKeyboardState(keyState)) 
{
    s_executeDeferredResult = e_executeDeferredButtonCheckFailed;
    return;
}   
s_executeDeferredStuckKeys.clear();
for (int index=0; index<arrsize(keyState); ++index)
{
    if (keyState[index] & 0x80)
    {
        s_executeDeferredStuckKeys.insert(index);
    }
}
if (!s_executeDeferredStuckKeys.empty())
{
    s_executeDeferredResult = e_executeDeferredButtonsActive;
    return;
}

But, there are some key combos that get stuck: 但是,有一些关键的组合卡住了:

  1. Turn on NUMLOCK 开启NUMLOCK
  2. Press SHIFT SHIFT
  3. Press NumPad8 NumPad8
  4. Release SHIFT 释放SHIFT
  5. Release NumPad8 发行NumPad8
    (this is one example, there are others, including a doozy with CTRL - ALT - DEL ) (这是一个示例,还有其他示例,包括带有CTRL - ALT - DEL的doozy)

GetKeyboardState will now report that VK_UP is pressed. 现在, GetKeyboardState将报告已按下VK_UP

The events that happen are (corresponding to the actions above). 发生的事件是(对应于上述操作)。

  1. <None>
  2. WM_KEYDOWN , VK_SHIFT WM_KEYDOWNVK_SHIFT
  3. WM_KEYUP , VK_SHIFT WM_KEYUPVK_SHIFT
    WM_KEYDOWN , VK_UP WM_KEYDOWNVK_UP
    WM_KEYDOWN , VK_SHIFT WM_KEYDOWNVK_SHIFT
  4. WM_KEYUP , VK_SHIFT WM_KEYUPVK_SHIFT
  5. WM_KEYUP , VK_NUMPAD8 WM_KEYUPVK_NUMPAD8

So, Windows doesn't recognize that the Up key came up, and now GetKeyboardState is broken. 因此,Windows无法识别出Up键,现在GetKeyboardState已损坏。

Is there any good way to check the real state of the key? 有什么好的方法可以检查密钥的真实状态? GetAsyncKeyState and GetKeyState both report that the key is down as well. GetAsyncKeyStateGetKeyState都报告密钥也已按下。

Solved it. 解决了。

I hooked into the keyboard events in InitInstance and am tracking the ups and downs by scan code (a map with the scan code as key and the virtual keys as the value). 我迷上了InitInstance中的键盘事件,并通过扫描代码(以扫描代码为键,虚拟键为值的映射)跟踪起伏。

m_keyboardHook = SetWindowsHookEx(WH_KEYBOARD, &KeyboardHook, NULL, GetCurrentThreadId());

static LRESULT CALLBACK KeyboardHook(
    __in int nCode,
    __in WPARAM wParam,
    __in LPARAM lParam
    )
{
    // According to the docs, we're not allowed to do any "further processing" if nCode is < 0.
    // According to the docs, we should process messages if we get code HC_ACTION. 
    // http://msdn.microsoft.com/en-us/library/windows/desktop/ms644984(v=vs.85).aspx
    // It doesn't specify what to do if another code comes in, so we will just ignore any other codes.
    if (nCode == HC_ACTION)
    {
        uint8 scanCode = (uint8)((lParam & 0x00FF0000) >> 16);
        uint8 virtKey = (uint8)wParam;
        if (lParam & 0x80000000) // key up
            KeyState::SetKeyUp(scanCode);
        else
            KeyState::SetKeyDown(scanCode, virtKey);
    }

    // We must call the next hook in the chain, according to http://msdn.microsoft.com/en-us/library/windows/desktop/ms644975%28v=vs.85%29.aspx
    // First param is ignored, according to http://msdn.microsoft.com/en-us/library/windows/desktop/ms644974%28v=vs.85%29.aspx )
    return CallNextHookEx(0, nCode, wParam, lParam);
}

So, my defer checking becomes: 因此,我的延迟检查变为:

// Similarly, don't process deferred events if there are keys or mouse buttons which are currently down.
s_executeDeferredStuckKeys.clear();
if (KeyState::AnyKeysDown(s_excludeKeys, arrsize(s_excludeKeys)))
{
    s_executeDeferredResult = e_executeDeferredButtonsActive;
    KeyState::GetDownKeys(s_executeDeferredStuckKeys);
    return;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM