4 votes

Les événements de touche du pavé numérique entraînent des touches bloquées de GetKeyboardState

J'ai une application C++ (MFC) qui a besoin de vérifier l'état des touches sur un minuteur. Si l'utilisateur maintient une touche enfoncée, nous retardons le traitement de certains codes.

Voici la vérification pour la touche enfoncée:

if (!GetKeyboardState(keyState)) 
{
    s_executeDeferredResult = e_executeDeferredButtonCheckFailed;
    return;
}   
s_executeDeferredStuckKeys.clear();
for (int index=0; index

``

Mais, il y a des combinaisons de touches qui restent bloquées:

  1. Allumez NUMLOCK
  2. Appuyez sur SHIFT
  3. Appuyez sur NumPad8
  4. Relâchez SHIFT
  5. Relâchez NumPad8
    (c'est un exemple, il y en a d'autres, y compris une difficile avec CTRL-ALT-DEL)

GetKeyboardState va maintenant signaler que VK_UP est pressé.

Les événements qui se produisent sont (correspondant aux actions ci-dessus).

  1. WM_KEYDOWN, VK_SHIFT
  2. WM_KEYUP, VK_SHIFT
    WM_KEYDOWN, VK_UP
    WM_KEYDOWN, VK_SHIFT
  3. WM_KEYUP, VK_SHIFT
  4. WM_KEYUP, VK_NUMPAD8

Donc, Windows ne reconnaît pas que la touche Haut est relevée, et maintenant GetKeyboardState est cassé.

Y a-t-il un bon moyen de vérifier l'état réel de la touche? GetAsyncKeyState et GetKeyState rapportent également que la touche est enfoncée.

``

2voto

Craig Steele Points 61

Résolu.

J'ai accroché les événements du clavier dans InitInstance et je trace les événements de montée et de descente par code de balayage (une carte avec le code de balayage comme clé et les touches virtuelles comme valeur).

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

static LRESULT CALLBACK KeyboardHook(
    __in int nCode,
    __in WPARAM wParam,
    __in LPARAM lParam
    )
{
    // Selon la documentation, nous ne sommes pas autorisés à effectuer "un traitement supplémentaire" si nCode est < 0.
    // Selon la documentation, nous devrions traiter les messages si nous obtenons le code HC_ACTION.
    // http://msdn.microsoft.com/en-us/library/windows/desktop/ms644984(v=vs.85).aspx
    // Il ne spécifie pas ce qu'il faut faire si un autre code arrive, nous allons donc simplement ignorer tout autre code.
    if (nCode == HC_ACTION)
    {
        uint8 scanCode = (uint8)((lParam & 0x00FF0000) >> 16);
        uint8 virtKey = (uint8)wParam;
        if (lParam & 0x80000000) // touche relâchée
            KeyState::SetKeyUp(scanCode);
        else
            KeyState::SetKeyDown(scanCode, virtKey);
    }

    // Nous devons appeler le prochain crochet dans la chaîne, selon http://msdn.microsoft.com/en-us/library/windows/desktop/ms644975%28v=vs.85%29.aspx
    // Le premier paramètre est ignoré, selon http://msdn.microsoft.com/en-us/library/windows/desktop/ms644974%28v=vs.85%29.aspx )
    return CallNextHookEx(0, nCode, wParam, lParam);
}

Ainsi, mon report de différé devient :

// De même, ne pas traiter les événements différés s'il y a des touches ou des boutons de souris actuellement enfoncés.
s_executeDeferredStuckKeys.clear();
if (KeyState::AnyKeysDown(s_excludeKeys, arrsize(s_excludeKeys)))
{
    s_executeDeferredResult = e_executeDeferredButtonsActive;
    KeyState::GetDownKeys(s_executeDeferredStuckKeys);
    return;
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X