getch() nachbauen
-
Hallo,
ich würde gerne mit C++-Standardmitteln getch() und _kbhit() nachbauen, da ich sowohl Linux als auch Windows nutze und somit plattformunabhängig bleiben will.
Folgende Idee für _kbhit(): die Größe des Inhalts des Buffers überprüfen in einer while()-Schleife, bzw. einen Buffer setzen und dessen Inhalt überprüfen:#include <iostream> #include <thread> #include <chrono> int main(int argc, char* argv[]) { std::cout << "0: false; 1: true\n"; char buffer[16]; auto a = std::cin.rdbuf()->pubsetbuf(buffer, sizeof(buffer)); buffer[0] = '\\'; // while(std::cin.rdbuf()->in_avail() == 0) // while(std::cin.peek() == '\n') while(buffer[0] == '\\') { std::this_thread::sleep_for(std::chrono::milliseconds(250)); } std::cout << "Triggered!"; return 0; }
Irgendwie verändert sich der Buffer aber nicht. Verwendet std::cin diesen gar nicht?
So ähnlich würde es dann natürlich auch für getch() aussehen, nur, dass ich dann eben buffer[0] zurückgebe und ein '\b'-Zeichen ausgebe + Leerstelle.
Nächster Ansatz:
#include <iostream> int main(int argc, char* argv[]) { auto a = std::cin.rdbuf(); auto b = std::cout.rdbuf(); char x; a->pubsetbuf(&x, 0); while(std::cin.peek() == EOF) { } std::cin.putback('\n'); char c = std::cin.get(); return 0; }
Die Idee hier ist, dass ich den Buffer ausschalte und mit std::cin.peek() warte, bis im Buffer etwas ist. Mit std::cin.get() soll das dann sofort gelesen werden, da danach im Stream ja noch ein <Enter> ist.
Beides funktioniert irgendwie nicht. Hat jemand eine Erklärung, warum? Und wie man das zum Laufen bringen kann, bzw. Alternativen?
-
Die erste Variante funktioniert nicht, da die Daten ja nicht "von selbst" (=ohne dass du ne IO Funktion aufrufst) im Puffer landen. Und wenn du ne IO Funktion aufrufst, dann blockiert die natürlich wieder.
Die 2. Variante sollte funktionieren, allerdings nur insofern dass
peek()
aufstdin
so lange blockiert bis ein Zeichen verfügbar ist. (Oder der Stream geschlossen wurde, z.B. wennstdin
gepiped wird und das Daten-generierende Programm terminiert bzw. das "Input-File" EOF ist). Das verfügbare Zeichen liest es dann vonstdin
und steckt es in den Puffer vonstd::cin
, so dass es danach normal ausstd::cin
"gelesen" werden kann.
Wenn du während keine Taste gedrückt wird noch 'was anderes machen möchtest, müsstest du das Lesen vomstd::istream
(bzw. das Peeken) in einen eigenen Thread verlagern.
Ist allerdings auch nicht ganz einfach.Die einfachere Lösung ist also vermutlich ein "ifdef windows" zu verwenden, und die nötigen 2-3 Zeilen Code dann 2x zu schreiben: 1x für POSIX Systeme (Linux, BSD, OS X, ...) und 1x für Windows.
(Hab' jetzt nicht nachgesehen ob es da speziell im POSIX Standard 'was gibt, aber ich würde mal annehmen dass irgenbwo bei POSIX oder Single UNIX Specification bzw. dem Open Group Zeugs was dabei ist mit dem es geht.)