C getch() nach GetAsyncKeyState()

Gast #5434933
Lesenswert?

Hi Zusammen

Habe ein kleines Problem bzgl. getch() nach GetAsyncKeyState().
Gleich mal mein Codeausschnitt:
1
int retKey;
2
while((GetAsyncKeyState(VK_ESCAPE)) || (GetAsyncKeyState(VK_RETURN)) || (GetAsyncKeyState(VK_LEFT)) || (GetAsyncKeyState(VK_RIGHT))); //warten bis Tasten losgelassen wurden
3
Sleep(20);
4
fflush(stdin); //bringt leider nichts!
5
while(1) //Endlosschleife hier als Beispiel
6
{
7
  retKey = _getch();
8
  printf("%c", ((char)(retKey))); //nur für Testphase
9
}

Eigentlich erwarte ich jetzt, dass ich beliebige Tasten drücken kann und 
mir diese anschliessend auf der Konsole ausgegeben werden. Macht es 
auch, aber erst nachdem der ganze Input Buffer ausgelesen wurde, in 
welchem sich noch alle meine vorangehenden Pfeiltasten, ENTER und co 
befinden! Dh meine Konsole wird erstmal zugemüllt mit '\n' und 'Ó' 
(Ó->0xE0, siehe: https://msdn.microsoft.com/en-us/library/078sfkak.aspx 
unter "Remarks").

Wie kann ich dieses Problem umgehen? fflush(stdin) bringt ja anscheinend 
nichts an dieser Stelle...

Die eingegebenen Tasten sollen später NICHT ausgegeben werden. Ich 
verwende hier den printf nur um das Problem zu veranschaulichen.

Danke im voraus...
#5435013
Lesenswert?

>_getch, _getwch
>When reading a function key or an arrow key, each function must be called twice; 
the first call returns 0 or 0xE0, and the second call returns the actual key code.

Also (sofern extended keycodes ignoriert werden sollen)
1
_getch --> 0 oder 0xE0? -- Nein --> Zeichen ausgeben
2
   ^              |
3
   |              J
4
   |              a
5
   |              |
6
   |              V
7
   ------------ _getch()

Das ist in C eine Schleife mit einem if darin.


GetAsyncKeyState() ist eine ganz andere API auf einer ganz anderen Ebene 
des Betriebssystems.
Gast #5435057
Lesenswert?

Wäre ne ganz einfache Idee, aber kann ich leider nicht nutzen :(
Problem ist, wenn man zuvor versehentlich eine andere Taste (zB einen 
Buchstaben) gedrückt hatte. Die Schleife würde alles bis zu diesem 
Zeichen perfekt entfernen, dann aber den versehentlichen Wert übernehmen 
und wenn jetzt danach noch ein ENTER kommt (und das wird so sein), wird 
ein falscher Wert abgespeichert. (mit ENTER oder ESC wird die while(1) 
quasi wieder verlassen)
Wäre super einfach deine Schleife, aber ist leider nutzlos für mein 
Problem :(

Gibt es keine andere Möglichkeit diesen Input Buffer zu leeren?
#5435941
Lesenswert?

Llemaban schrieb:
> Wäre ne ganz einfache Idee, aber kann ich leider nicht nutzen :(
Das solltest Du aber, denn sonst druckst du da Steuerzeichen in die 
Konsole...

Aber dann zum Problem:
Kann man den Buffer nicht leer lesen oder ggf. das File-Handle neu 
öffnen?

Tendenziell würde ich nicht versuchen, APIs zu mischen, die auf 
verschiedenen Ebenen liegen, da ist sowas vorprogrammiert, weil die 
Interaktion zwischen diesen Ebenen nicht ganz durchsichtig ist.

Vielleicht ist das hier für deine Zwecke besser geeignet:
https://docs.microsoft.com/en-us/windows/console/console-functions

Die Standard-Handles (stdin, stdout, stderr) sind eigentlich nicht 
unbedingt für interaktive Nutzung vorgesehen: Sie können das so 
nebenbei, allerdings mit Einschränkungen (wie Du merkst). Die sind 
interessant, wenn Pipes oder Redirection des Outputs in Dateien genutzt 
werden sollen: Da ist "Datei" eher eine passende Abstraktion.
Gast #5436470
Lesenswert?

Heiko L. schrieb:
> Vielleicht ist das hier für deine Zwecke besser geeignet:
> https://docs.microsoft.com/en-us/windows/console/console-functions

Tatsache... FlushConsoleInputBuffer() ist die Antwort, ganz oben auf der 
Liste der Cosole Functions!

Danke für den Link! Darauf kam ich bisher noch nicht.

Dh du würdest davon abraten GetAsyncKeyState() und getch() im gleichen 
Code zu verwenden?

lg Llemaban
Moderator Persönliche Seite #5436587
Lesenswert?

Llemaban schrieb:
> Dh du würdest davon abraten GetAsyncKeyState() und getch() im gleichen
> Code zu verwenden?

Ja, auf jeden Fall.

Ich verwende sowas hier:
1
static unsigned short
2
get_keypress()
3
{
4
    HANDLE         input_handle = GetStdHandle(STD_INPUT_HANDLE);
5
    DWORD          events = 0;
6
    INPUT_RECORD   input_record;
7
    DWORD          input_size = 1;
8
    unsigned short virtual_key = 0;
9

10
    int not_a_keypress = 1;
11

12
    do
13
    {
14
        FlushConsoleInputBuffer(input_handle);
15
        ReadConsoleInput(input_handle, &input_record, input_size, &events);
16
        
17
        if(input_record.EventType == KEY_EVENT && input_record.Event.KeyEvent.bKeyDown)
18
        {
19
            virtual_key = input_record.Event.KeyEvent.wVirtualKeyCode;
20
            not_a_keypress = 0;
21
        }
22
    } while(not_a_keypress);
23

24
    return virtual_key;
25
}
Gast #5436602
Lesenswert?

Frank M. schrieb:
> Llemaban schrieb:
>> Dh du würdest davon abraten GetAsyncKeyState() und getch() im gleichen
>> Code zu verwenden?
>
> Ja, auf jeden Fall.

Ein grundlegendes Problem dürfte sein, dass die Software blockierend 
arbeietn soll, während die Key-Verarbeitung von Windows Event-Gesteuert 
ist. Da sind Funktionen wie "Warte auf eine Taste" zumindest 
unerwünscht, eigentlich sollten sie verboten sein.

Im konkreten Fall: das Konsolenprogramm wartet auf einen Tastendruck, 
der aber nur kommen kann, wenn das Konsolenfenster auch den Focus hat, 
sonst bekommt ein anderes Windowsprogramm die Taste. Eine Funktion wie 
GetAsyncKeyState() weiss aber garnicht wer den Focus hat. Ist eben das 
falsche API an dieser Stelle.

Georg
Gast #5437956
Lesenswert?

Hier meine Asynchrone Abfrage:
1
#define GetAsyncKeyInputFormat_AsciiChar    0  //Retrun Value Ascii-Character (8 Bit)
2
#define GetAsyncKeyInputFormat_UnicodeChar    1  //Return Value Unicode-Character (16 Bit)
3
#define GetAsyncKeyInputFormat_VirtualKeyCode  2  //Return Value VK_KEY (16 Bit)
4

5
int GetAsyncKeyInput(const char format)
6
{
7
  HANDLE input_handle = GetStdHandle(STD_INPUT_HANDLE);
8
  DWORD input_n;
9
  int retVal = -1;
10
  
11
  GetNumberOfConsoleInputEvents(input_handle, &input_n);
12
  if(input_n > 0)
13
  {
14
    INPUT_RECORD input_record;
15
    DWORD input_size = 1, events = 0;
16
    ReadConsoleInput(input_handle, &input_record, input_size, &events);
17
    if((input_record.EventType == KEY_EVENT) && (input_record.Event.KeyEvent.bKeyDown))
18
    {
19
      switch(format)
20
      {
21
      case GetAsyncKeyInputFormat_AsciiChar:
22
        retVal = (int)input_record.Event.KeyEvent.uChar.AsciiChar;
23
        break;
24
      case GetAsyncKeyInputFormat_UnicodeChar:
25
        retVal = (int)input_record.Event.KeyEvent.uChar.UnicodeChar;
26
        break;
27
      case GetAsyncKeyInputFormat_VirtualKeyCode:
28
        retVal = (int)input_record.Event.KeyEvent.wVirtualKeyCode;
29
        break;
30
      }
31
    }
32
  }
33

34
  return retVal;
35
}

Für "format" entsprechend einer der definierten Formate verwenden, 
dementsprechend wird der Rückgabewert erstellt.
Ein Rückgabewert von -1 entsteht, wenn der console input buffer leer 
ist.

lg Llemaban

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren