HOWTO · C++

Tastendruck in Windows mit C++ erkennen

Vergleichen Sie Windows-C++-APIs zum Prüfen des Tastenzustands und zum Behandeln von Tastaturereignissen auf niedriger Ebene.

Auf dieser Seite

Um Tastatureingaben in einer Windows-Anwendung mit C++ zu erkennen, können Sie je nach Bedarf GetKeyState bei der Verarbeitung von Nachrichten, GetAsyncKeyState zum Abfragen des aktuellen Tastenzustands oder einen WH_KEYBOARD_LL-Hook für Ereignisse auf niedriger Ebene verwenden. Die Ansätze eignen sich für unterschiedliche Aufgaben: Texteingaben und Tastenkombinationen werden üblicherweise über die Fensternachrichten verarbeitet, während sich Abfragen und Hooks für speziellere Überwachungsfälle eignen.

Tastatureingaben in Windows-Anwendungen

Tastatureingaben können Text, eine Tastenkombination der Anwendung wie Ctrl+O oder einen Systembefehl wie Alt+Tab darstellen. Eine API für den Tastenzustand gibt Auskunft über eine Taste, wandelt Tastatureingaben aber nicht in Text um. Für Texteingaben sollten Sie die übliche Verarbeitung von Zeichenmeldungen des Fensters verwenden, die Tastaturlayout und Modifikatortasten berücksichtigt.

Virtuelle Tastencodes

Ein Scan-Code bezeichnet die von der Tastatur gemeldete physische Tastenposition. Windows ordnet Tastatureingaben einen virtuellen Tastencode zu, den APIs verwenden, um die Bedeutung einer Taste zu bestimmen. Für Buchstaben und Ziffern entsprechen die virtuellen Tastencodes den Zeichenwerten: A bis Z werden 0x41 bis 0x5A zugeordnet, 0 bis 9 den Werten 0x30 bis 0x39. Für andere Tasten gibt es benannte Konstanten in WinUser.h.

Konstante für virtuelle Tasten Taste
VK_SPACE Leertaste
VK_SHIFT Umschalttaste
VK_ESCAPE Escape
VK_LEFT Pfeil nach links
VK_F1 F1

Die vollständige Liste finden Sie in Microsofts Referenz zu virtuellen Tastencodes.

Mit GetKeyState den Zustand der Nachrichtenwarteschlange prüfen

GetKeyState meldet den Tastenzustand, der der Nachrichtenwarteschlange des aufrufenden Threads zugeordnet ist. Die Funktion eignet sich während der Verarbeitung einer Nachricht, wenn der Zustand zur betreffenden Eingabeverarbeitung gehören soll. Sie liefert jedoch keine allgemeine Momentaufnahme der physischen Tastatur zu einem beliebigen Zeitpunkt. Das höchstwertige Bit zeigt an, ob eine Taste gedrückt ist. Prüfen Sie beispielsweise in einer Fensterprozedur mit if (message == WM_KEYDOWN && (GetKeyState(VK_SHIFT) & 0x8000)) { /* handle Shift+key */ }, ob die Umschalttaste gedrückt ist, während eine Taste-abwärts-Nachricht verarbeitet wird. Führen Sie diese Prüfung im Nachrichtenhandler aus, statt in einer Schleife dauerhaft abzufragen.

Das ist etwa bei einer Aktion mit der Leertaste in einem Spiel wichtig: Eine Anwendung, die bereits Fensternachrichten verarbeitet, kann diese Nachrichten auch für die Eingabe verwenden. Welche Eingabeverarbeitung für ein Spiel am besten passt, hängt von dessen Eingabesystem und Aktualisierungsschleife ab; eine Abfrage in einer Schleife ist nicht automatisch erforderlich.

Mit GetAsyncKeyState eine Taste abfragen

Verwenden Sie GetAsyncKeyState, wenn eine Schleife den aktuellen Zustand einer Taste ermitteln soll, ohne sich auf den Zustand der Nachrichtenwarteschlange des aufrufenden Threads zu stützen. Das höchstwertige Bit ist gesetzt, solange die Taste gedrückt ist. Verlassen Sie sich für eine zuverlässige Erkennung nicht auf das niederwertige Bit für „seit dem letzten Aufruf gedrückt“, da eine andere Anwendung diesen Zustand auslesen kann. Begrenzen Sie die Abfragehäufigkeit und vergleichen Sie aufeinanderfolgende Zustände, damit ein Übergang zum gedrückten Zustand nur einmal gemeldet wird.

Das folgende portable Beispiel veranschaulicht die Übergangslogik anhand einer kurzen Folge von Tastenzuständen. In einer Windows-Abfrageschleife lesen Sie jeden Zustand mit GetAsyncKeyState(VK_SPACE) aus und prüfen das höchstwertige Bit. Begrenzen Sie die Schleifenfrequenz und verwenden Sie eine separate Abfrage für Escape, um die Schleife zu beenden.

#include <array>
#include <iostream>

int main() {
    bool spaceWasDown = false;
    const std::array<bool, 4> spaceStates{false, true, true, false};

    for (bool spaceIsDown : spaceStates) {
        if (spaceIsDown && !spaceWasDown) {
            std::cout << "Space pressed\n";
        }
        spaceWasDown = spaceIsDown;
    }
    return 0;
}
Space pressed

Mit SetWindowsHookEx Tastaturereignisse auf niedriger Ebene erfassen

Ein WH_KEYBOARD_LL-Hook empfängt Ereignisse auf niedriger Tastaturebene auf dem Desktop, auf dem er installiert wurde. Der Rückruf wird im Kontext des installierenden Prozesses ausgeführt; deshalb muss der betreffende Thread eine Nachrichtenschleife betreiben. Hooks wirken sich auf die systemweite Eingabeverarbeitung aus und sollten Fällen vorbehalten bleiben, in denen eine Überwachung auf Ereignisebene nötig ist. Halten Sie den Rückruf kurz und leiten Sie nicht behandelte Ereignisse mit CallNextHookEx an den nächsten Hook weiter.

Installieren Sie den Rückruf unter Windows mit SetWindowsHookExW(WH_KEYBOARD_LL, ...) und prüfen Sie vor Beginn der Nachrichtenschleife, ob das zurückgegebene Hook-Handle ungleich null ist. Prüfen Sie im Rückruf KBDLLHOOKSTRUCT::vkCode auf die gewünschte Taste, wenn code >= 0 gilt und die Nachricht WM_KEYDOWN oder WM_SYSKEYDOWN ist. Rufen Sie für Ereignisse, die die Anwendung nicht absichtlich unterdrückt, CallNextHookEx auf. Lassen Sie den installierenden Thread eine GetMessageW-Schleife ausführen und rufen Sie danach UnhookWindowsHookEx auf. Führen Sie diese Bereinigung sowohl nach einem regulären Ende der Nachrichtenschleife als auch nach einem Fehler von GetMessageW aus. Diese Übersicht zu Windows-APIs ist plattformspezifisch und kein portables, ausführbares Beispiel. Ein Rückruf für einen Low-Level-Hook muss zügig zurückkehren; Windows kann einen Hook entfernen, wenn er sein Zeitlimit überschreitet. Geben Sie das Ergebnis des nächsten Hooks zurück, sofern die Anwendung ein Ereignis nicht absichtlich unterdrücken soll.

Die passende Methode zur Tastenerkennung wählen

Verwenden Sie GetKeyState, wenn Sie eine Fensternachricht verarbeiten und den zugehörigen Zustand der Nachrichtenwarteschlange auswerten. GetAsyncKeyState eignet sich für eine begrenzte Abfrage, ob eine Taste gerade gedrückt ist. Wählen Sie SetWindowsHookEx mit WH_KEYBOARD_LL nur dann, wenn eine Überwachung auf niedriger Ereignisebene erforderlich ist und das Programm Rückruf und Nachrichtenschleife korrekt verwalten kann. Bei einer Aktion mit der Leertaste in einem Spiel sollten Sie mit dem vorhandenen Eingabesystem des Spiels beginnen und die API verwenden, die zu dessen Ereignis- oder Aktualisierungsmodell passt.