2013-08-28 82 views
4

我有一個C++(MFC)應用程序,需要檢查定時器上的keystate。如果用戶按住一個鍵,我們會延遲處理一些代碼。數字鍵盤按鍵事件導致從GetKeyboardState卡住的鍵

這裏是爲​​檢查:

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; 
} 

但是,也有卡住的一些關鍵連擊:

  1. 打開NUMLOCK
  2. SHIFT
  3. NumPad8
  4. 發佈SHIFT
  5. 發佈NUMPAD8
    (這是一個例子,還有其他的,包括CTRL了一個謊言 - ALT - DEL

GetKeyboardState現在將報告VK_UP被按下。

發生的事件是(對應於上述操作)。

  1. <None>
  2. WM_KEYDOWNVK_SHIFT
  3. WM_KEYUPVK_SHIFT
    WM_KEYDOWNVK_UP
    WM_KEYDOWNVK_SHIFT
  4. WM_KEYUPVK_SHIFT
  5. WM_KEYUPVK_NUMPAD8

因此,Windows不承認,向上鍵上來,現在GetKeyboardState被打破。

有沒有什麼好的方法來檢查密鑰的真實狀態? GetAsyncKeyStateGetKeyState都報告說關鍵也是關閉的。

+0

您是否嘗試過與其他鍵盤? –

+0

是的,它發生在我們嘗試過的所有鍵盤上。 – StilesCrisis

+0

由於這是一個MFC應用程序,請務必檢查您的'PreTranslateMessage'實現。這就是各種各樣的壞事隨着時間積累的地方。還要注意['GetKeyboardState'](http://msdn.microsoft.com/en-us/library/windows/desktop/ms646299.aspx)文檔中的註釋:*「狀態隨線程移除鍵盤消息它的消息隊列。「換句話說:如果你的應用程序做了一些可怕的事情,那麼'GetKeyboardState'可能會變得混亂。 – IInspectable

回答

2

解決了它。

我連接到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); 
} 

所以,我的延遲檢查變爲:

// 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; 
}