GetKeyboardState() Taste gedrückt, aber wird nicht erkannt



  • Hallo,

    laut Dokumentation setzt die Funktion GetKeyboardState() bei allen BYTES das MSB, bei denen der entsprechende VKCode als gedrückt registriert wurde (Als Keyboard Message). Folgendes Beispiel:

    #include <iostream>
    #include <Windows.h>
    
    void print_key(PKBDLLHOOKSTRUCT kb)
    {
    	std::cout << "Key pressed" << std::endl;
    
    	BYTE keystate[256]{};
    	if (!GetKeyboardState(keystate))
    		std::cerr << "GetKeyboardState failed\n";
    
    	if (keystate[VK_RETURN] & 0x80)  // highest order bit set
    		std::cout << "You pressed RETURN!" << std::endl;
    }
    
    LRESULT CALLBACK keyproc(int code, WPARAM wParam, LPARAM lParam)
    {	
    	if (code == HC_ACTION && wParam == WM_KEYDOWN)
    		print_key(PKBDLLHOOKSTRUCT(lParam));
    	return CallNextHookEx(nullptr, code, wParam, lParam);
    }
    
    int main()
    {
    	if (HHOOK hook = SetWindowsHookEx(WH_KEYBOARD_LL, keyproc, nullptr, 0))
        {
    	    for (MSG msg; GetMessage(&msg, nullptr, 0, 0); )
    	    {
    		    TranslateMessage(&msg);
    		    DispatchMessage(&msg);
    	    }
    	    UnhookWindowsHookEx(hook);
        }
    }
    

    OK. Ich habe zwar eine Message-Loop, aber vielleicht mache ich trotzdem etwas falsch, habe mal wieder etwas in der Dokumentation übersehen. Wieso sagt mir das nächste Beispiel trotzdem nicht, dass ich Eingabe gedrückt habe, obwohl die Taste doch offensichtlich zum Zeitpunkt des callbacks gedrückt ist (muss sie ja, sonst gäbe es keinen callback!).

    if (GetAsyncKeyState(VK_RETURN) < 0)
    		std::cout << "You pressed RETURN!" << std::endl;
    

    Das bringt gerade etwas meine Weltansichten durcheinander, und falls mir jemand auch nur den kleinsten Hinweis geben könnte, welche meiner Annahmen hier falsch sind, ich wäre sehr dankbar!

    Ich freue mich auf Eure zahlreichen Antworten!

    LG
    HarteWare

    P.S.: Ich habe schon eine "Lösung" gefunden (Natürlich sollte man keine globale Variable verwenden, sondern das Ganze in eine Klasse kapseln). Das ist für mich trotzdem nicht zufriedenstellend. Ich möchte verstehen, weshalb die obigen Programme sich nicht so verhalten, wie ich es mir vorstelle.

    static BYTE global_keystate[256]{};
    
    void press_key(int vkCode)
    {    // falsch für toggle-keys, aber hier gehts ums Prinzip
    	if (vkCode > 0 && vkCode < 256)
    		global_keystate[vkCode] |= 0x80;
    }
    
    void release_key(int vkCode)
    {
    	if (vkCode > 0 && vkCode < 256)
    		global_keystate[vkCode] = 0;
    }
    

    Die Funktionen werden entsprechend bei WM_KEYDOWN/KEYUP aufgerufen.



  • MSDN schrieb:

    An application can call this function to retrieve the current status of all the virtual keys.

    In dem Moment in dem deine Callback Funktion aufgerufen wird ist die Taste schon nicht mehr gedrückt. Deswegen gibt es auch noch so Funktionen wie GetAsyncKexState.
    Beide Funktionen sind für dein Problem aber irrelevant.
    Schau mal hier nach:
    https://msdn.microsoft.com/en-us/library/windows/desktop/ms644967(v=vs.85).aspx



  • floorball schrieb:

    MSDN schrieb:

    An application can call this function to retrieve the current status of all the virtual keys.

    In dem Moment in dem deine Callback Funktion aufgerufen wird ist die Taste schon nicht mehr gedrückt. Deswegen gibt es auch noch so Funktionen wie GetAsyncKexState.

    Ich widerspreche: Ich drücke die Taste und lass' sie nicht mehr los. Währenddessen erscheint in meiner Konsole der Text "Key pressed". Damit diese Ausgabe stattfinden kann, muss die Callback-Funktion aufgerufen worden sein. Ergo ist die Taste zum Zeitpunkt des Callback-Funktionaufrufs gedrückt.

    Zum Thema GetAsyncKeyState: Ich meine ich hätte im ursprünglichen Post angesprochen, dass diese Funktion ebenfalls nicht wie erwartet funktioniert. Ich werde aber nochmals deinen Link nachlesen, eventuell finde ich dort nützliche Hinweise. EDIT: Habe nichts gefunden.

    Vielen Dank

    LG
    HarteWare



  • HarteWare schrieb:

    EDIT: Habe nichts gefunden.

    Vielen Dank

    ???
    Die passende Funktionssignatur hast du doch, floorball hat nur auf die entsprechende Doku verlinkt.

    if(kb->vkCode==VK_RETURN)
    ...
    


  • Bei mir funktioniert es bislang, habe aber auch keine Erwartungen mehr, die dann nicht erfüllt werden. Hier mal nach meinem Kenntnisstand:

    Statusänderung einer Taste tritt für GetAsyncKeyState() erst ein, wenn eine gesendete (korrespondierende?) Tastaturbotschaft aus der Nachrichtenschleife des aufrufenden Thread entfernt wird.

    GetAsyncKeyState() und Aufruf einer Tastenstatus-Printfunktion habe ich in KeyProc() innerhalb der Abfrage "if ((code == HC_ACTION) && (wParam == WM_...))". GetAsyncKeyState() liefert 0x8001, wenn in der Abfrage (wParam == WM_KEYUP) eingesetzt wird. Bei (wParam == WM_KEYDOWN) wird auch 0x8001 geliefert, solange dieselbe Taste gedrückt gehalten wird. Sonst wird 0x0000 beim Niederdrücken einer Taste zurückgegeben oder auch dann, wenn die betätigte Taste nicht dem Argument in GetAsyncKeyState() entspricht.

    Auffällig ist (bei mir im Test), daß GetAsyncKeyState(), sofern es nicht 0x0000 zurückgibt, immer 0x8001 liefert, aber nie 0x8000 oder 0x0001. Eine betätigte Taste gilt hier immer gleichzeitig als gedrückt und getoggelt, aber nie nur das Eine oder nur das Andere.

    Übrigends ist auf MSDN auch folgendes zu lesen:
    - Benutzer sollten sich nicht auf Rückgaben von GetAsyncKeyState() verlassen.
    - Eine Nachricht für einen Hook wird bei Ablauf eines Zeitlimit stillschweigend aus der Nachrichtenschleife gelöscht, wenn also z.B. eine Prozedur zuviel Zeit vertrödelt.

    Das kann wohl bedeuten, daß GetAsyncKeyState() nur in unkritischen Fällen und nur zur groben Detektierung von Tastenbetätigungen verwendet werden soll und daß
    Tastaturnachrichten (und die Statusänderungen?) verloren gehen können.

    LG


Anmelden zum Antworten