Wie simulieren Sie “Drücken Sie eine beliebige Taste, um fortzufahren?”
Lesezeit: 10 Minuten
seinaboutcode
Ich versuche, ein C++-Programm zu schreiben, in dem der Benutzer, wenn er ein beliebiges Zeichen über die Tastatur eingibt, zur nächsten Codezeile wechseln sollte.
Hier ist mein Code:
char c;
cin>>c;
cout<<"Something"<<endl;
aber das funktioniert nicht, weil es nur zur nächsten Zeile wechselt, wenn ich ein Zeichen eingebe und dann ENTER drücke.
ODER
Wenn ich das verwende
cin.get() or cin.get(c)
Es geht zur nächsten Anweisungszeile, wenn ich die Eingabetaste drücke.
Aber ich wollte, dass es bei jeder Taste, die auf der Tastatur gedrückt wird, zur nächsten Zeile wechselt, wie kann das gemacht werden?
Soweit ich weiß, besteht das Problem darin, dass Ihre Shell darauf wartet, dass Sie ENTER oder EOF drücken, und dann Ihr Programm sich um alles kümmern lässt, was sich im Puffer befindet, oder so ähnlich. Vielleicht kann jemand mit etwas mehr Wissen eine echte Erklärung liefern. Aber ich denke, es ist nicht so einfach, wie es zunächst scheint.
– Lukas
19. September 2009 um 21:02 Uhr
Der bei weitem einfachste Weg, dies zu handhaben, und der einzige tragbare Weg, besteht darin, Ihre Eingabeaufforderung von „Drücken Sie eine beliebige Taste, um fortzufahren“ in „Drücken Sie die Eingabetaste, um fortzufahren“ zu ändern.
– Mayoff ausrauben
23. Februar 12 um 4:44 Uhr
@Lucas – Ich verwende Mac mit xcode.
– sein Aboutcode
23. Februar 2012 um 19:25 Uhr
@Lucas: Es ist nicht die Shell, es ist das Programm selbst.
– Keith Thompson
23. Februar 2012 um 19:25 Uhr
@KeithThompson: Das ist mehr als zwei Jahre her, aber ich glaube, ich habe versucht, darauf hinzuweisen, dass die Eingabewarteschlange nicht vom Benutzerprozess, sondern im Kernel behandelt wird.
– Lukas
24. Februar 12 um 3:13 Uhr
Unter Windows:
system("pause");
und auf Mac und Linux:
system("read");
gibt “Drücken Sie eine beliebige Taste, um fortzufahren …” aus und wartet offensichtlich darauf, dass eine Taste gedrückt wird. Ich hoffe das war was du meintest
system ruft externes Programm auf. Sie müssen kein externes Programm aufrufen, um auf eine Taste zu warten! Es ist, als würde man eine andere Person anrufen, damit sie den Computer einschaltet, während man davor sitzt – das ist eine langsame Lösung.
– IngwerPlusPlus
25. August 14 um 9:51 Uhr
Stimmt, aber es ist nur eine Zeile lang! Manchmal lohnt es sich einfach nicht, dem Computer einige Zyklen zu sparen…
– Elliot Cameron
24. November 14 um 17:02 Uhr
Vergessen Sie langsam, es ruft das erste Programm mit dem Namen “pause” auf, das es zufällig in PATH findet, und gibt ihm die Berechtigungsstufe des aufrufenden Programms. Selbst wenn Sie als Student nur Ihren eigenen Code testen, ist dies immer noch ein massives Sicherheitsrisiko.
– Anne Quinn
14. Dezember 14 um 11:11 Uhr
@XDfaceme – pause ist ein tatsächliches Programm, das system() Windows zur Ausführung auffordert. Wenn es jedoch ein anderes Programm namens “Pause” gibt und Windows dieses Programm zuerst findet, wird es stattdessen ausgeführt. Ich nehme an, ich habe die Bedeutung vielleicht ein wenig übertrieben, aber es ist immer noch einfacher, einfach cin.get() zu verwenden und die Eingabetaste zu drücken, um ein Programm anzuhalten / fortzusetzen
– Anne Quinn
27. Januar 15 um 23:32 Uhr
Ich bin kein Fan von Absolutheiten. Eine pauschale Aussage zu machen, dass system(“pause”) ein Sicherheitsrisiko ist und dass es schlecht ist, selbst wenn Sie Ihren eigenen Code testen, bläst die Dinge hier völlig überproportional auf. cin.get() könnte die richtige Lösung sein, aber es löst nicht die Frage, die gestellt wurde … cin.get() antwortet nur, nachdem “enter” oder “return” gedrückt wurden. Die Frage war speziell, auf jeden Tastendruck zu reagieren. system(“pause”) macht genau das. Zunächst einmal ist die einzige Stelle, an der ich dies als nützlich angesehen habe, in einer Entwicklerklasse beim Debuggen von Visual Studio, daher denke ich, dass system (“pause”) funktioniert
– Gregor
4. September 17 um 23:07 Uhr
Vinay Sajip
Wenn Sie Windows verwenden, können Sie verwenden kbhit() die Teil der Microsoft-Laufzeitbibliothek ist. Wenn Sie Linux verwenden, können Sie implementieren kbhit daher (Quelle):
Aktualisieren: Die obige Funktion funktioniert unter OS X (zumindest unter OS X 10.5.8 – Leopard, daher würde ich erwarten, dass sie unter neueren Versionen von OS X funktioniert). Dies Kern kann gespeichert werden als kbhit.c und sowohl auf Linux als auch auf OS X mit kompiliert
gcc -o kbhit kbhit.c
Beim Laufen mit
./kbhit
Es fordert Sie zu einem Tastendruck auf und wird beendet, wenn Sie eine Taste drücken (nicht auf die Eingabetaste oder druckbare Tasten beschränkt).
@Johnsyweb – Bitte erläutern Sie, was Sie mit “detaillierte kanonische Antwort” und “alle Bedenken” meinen. Auch zu “plattformübergreifend”: Mit dieser Implementierung von kbhit() Sie können dieselbe Funktionalität in einem C++-Programm unter Linux/Unix/OS X/Windows haben – auf welche anderen Plattformen beziehen Sie sich möglicherweise?
Weiteres Update für @Johnsyweb: C++-Anwendungen leben nicht in einer hermetisch abgeschlossenen C++-Umgebung. Ein wichtiger Grund für den Erfolg von C++ ist die Interoperabilität mit C. Alle Mainstream-Plattformen sind mit C-Schnittstellen implementiert (auch wenn die interne Implementierung C++ verwendet), sodass Ihre Rede von „Legacy“ fehl am Platz zu sein scheint. Und da wir über eine einzelne Funktion sprechen, warum brauchen Sie C++ dafür (“C mit Klassen”)? Wie ich bereits erwähnt habe, können Sie in C++ schreiben und auf diese Funktionalität einfach zugreifen, und die Benutzer Ihrer Anwendung werden sich wahrscheinlich nicht darum kümmern wie du hast es umgesetzt.
Es ist eine Schande, dass es keine Standardmethode gibt, um mit der Konsole umzugehen, Sie müssen immer etwas OS-Magik verwenden
– Varga
20. September 2009 um 0:29 Uhr
@Johnsyweb: Danke Sie, aber Ihr Beispiel zeigt Funktionen, die mich an C++ deprimieren. Deine kbhit() Funktion deklariert a terminal_settings Variable in einer Zeile, die nichts zu tun scheint und doch alles tut. Einige mögen es nett finden, aber ich finde es undurchsichtig bis zur Unlesbarkeit.
– Vinay Sajip
25. Februar 2012 um 23:05 Uhr
@VinaySajip: Meine Implementierung verwendet RAII, eines der wichtigsten Idiome in C++. Obwohl dies in diesem Beispiel nicht unbedingt erforderlich ist, habe ich festgestellt, dass es eine gute Angewohnheit ist, sich darauf einzulassen, wenn Sie einen Zustand speichern und wiederherstellen möchten.
– Johnsyweb
26. Februar 2012 um 2:00 Uhr
@Johnsyweb: Ich kenne RAII und die Vorteile, die es bringt, ich bin selbst ein alter C++-Hasen. Mein Punkt bleibt: Es gibt keine klare Verbindung zwischen der Erklärung und dem, was sie hinter den Kulissen tut. Auch wenn es glänzende C++-Ausdrücke anstelle von einfachem altem C verwendet, bin ich der Ansicht, dass es wenig dazu beiträgt, etwas zu beleuchten, und viel dazu beiträgt, zu verschleiern, was vor sich geht. Dies ist in keiner Weise an Sie persönlich gerichtet – es ist nur eine Meinung darüber, wie C++ verwendet werden kann, um Code zu erstellen, der unnötig schwer zu verstehen ist. Ich steige jetzt aus meiner Seifenkiste, sagte nuff.
– Vinay Sajip
26. Februar 12 um 21:53 Uhr
Es ist nett und alles, fängt aber immer noch irgendwelchen vorherigen Müll auf der stdin 🙂
– Thiago
25. März 15 um 15:52 Uhr
Es gibt keine vollständig tragbare Lösung.
Frage 19.1 des comp.lang.c FAQ deckt dies ausführlich ab, mit Lösungen für Windows, Unix-ähnliche Systeme und sogar MS-DOS und VMS.
Eine kurze und unvollständige Zusammenfassung:
Du kannst den … benutzen curses Bücherei; Anruf cbreak() gefolgt von getch() (Nicht zu verwechseln mit der Windows-spezifischen getch()Funktion). Beachten Sie, dass curses übernimmt im Allgemeinen die Kontrolle über das Terminal, daher ist dies wahrscheinlich übertrieben.
Kannst du vielleicht verwenden ioctl() um die Terminaleinstellungen zu manipulieren.
Auf POSIX-kompatiblen Systemen tcgetattr() und tcsetattr() kann eine bessere Lösung sein.
Unter Unix können Sie verwenden system() um die anzurufen stty Befehl.
Unter MS-DOS können Sie verwenden getch() oder getche().
Auf VMS (jetzt OpenVMS genannt) ist die Bildschirmverwaltung (SMG$)-Routinen könnten den Zweck erfüllen.
Alle diese C-Lösungen sollten in C++ gleich gut funktionieren; Ich kenne keine C++-spezifische Lösung.
All diese plattformübergreifenden Lösungen könnten mit jemandem auskommen, der eine Funktion schreibt, die so implementiert ist, dass sie abhängig von Ihrer Plattform das Richtige tut, mit vielen Präprozessoren, um festzustellen, was diese Plattform ist.
#include<iostream.h>
#include<conio.h>
using namespace std;
void check()
{
char chk; int j;
cout<<"nnPress any key to continue...";
chk=getch();
j=chk;
for(int i=1;i<=256;i++)
if(i==j) break;
clrscr();
}
void main()
{
clrscr();
check();
cout<<"nnIt works!";
getch();
}
Zu beachten ist, dass getch nicht Teil der Standardbibliothek ist.
Um diese Funktionalität zu erreichen, könnten Sie verwenden ncurses Bibliothek, die sowohl unter Windows als auch unter Linux (und MacOS, soweit ich weiß) implementiert wurde.
Nun, das ist eine Art Aufgabe, bei der ich keine externen Bibliotheken usw. verwenden kann, also nur im “Kapitelkontext” lox bleiben muss.
– sein Aboutcode
19. September 2009 um 19:48 Uhr
Dann besteht die einzige Option darin, die erforderliche Funktionalität für jedes Betriebssystem zu implementieren, das Sie unterstützen möchten.
– Kirill W. Ljadwinski
19. September 2009 um 20:01 Uhr
ncurses ist mehr oder weniger ein VT200-Client. Ein bisschen übertrieben, um einfach aus dem TTY zu lesen.
– Grauschimmer
19. September 2009 um 20:11 Uhr
Gemeinschaft
Ich habe mir angesehen, was Sie zu erreichen versuchen, weil ich mich erinnere, dass ich dasselbe tun wollte. Inspiriert von Vinay habe ich etwas geschrieben, das für mich funktioniert und das ich irgendwie verstehe. Aber ich bin kein Experte, also seien Sie bitte vorsichtig.
Ich weiß nicht, woher Vinay weiß, dass Sie Mac OS X verwenden. Aber es sollte mit den meisten Unix-ähnlichen Betriebssystemen so funktionieren. Wirklich hilfreich, da Ressource ist opengroup.org
Achten Sie darauf, den Puffer zu leeren, bevor Sie die Funktion verwenden.
#include <stdio.h>
#include <termios.h> //termios, TCSANOW, ECHO, ICANON
#include <unistd.h> //STDIN_FILENO
void pressKey()
{
//the struct termios stores all kinds of flags which can manipulate the I/O Interface
//I have an old one to save the old settings and a new
static struct termios oldt, newt;
printf("Press key to continue....n");
//tcgetattr gets the parameters of the current terminal
//STDIN_FILENO will tell tcgetattr that it should write the settings
// of stdin to oldt
tcgetattr( STDIN_FILENO, &oldt);
//now the settings will be copied
newt = oldt;
//two of the c_lflag will be turned off
//ECHO which is responsible for displaying the input of the user in the terminal
//ICANON is the essential one! Normally this takes care that one line at a time will be processed
//that means it will return if it sees a "n" or an EOF or an EOL
newt.c_lflag &= ~(ICANON | ECHO );
//Those new settings will be set to STDIN
//TCSANOW tells tcsetattr to change attributes immediately.
tcsetattr( STDIN_FILENO, TCSANOW, &newt);
//now the char wil be requested
getchar();
//the old settings will be written back to STDIN
tcsetattr( STDIN_FILENO, TCSANOW, &oldt);
}
int main(void)
{
pressKey();
printf("ENDn");
return 0;
}
O_NONBLOCK scheint auch ein wichtiges Flag zu sein, aber es hat nichts für mich geändert.
Ich schätze es, wenn Leute mit etwas tieferem Wissen dies kommentieren und Ratschläge geben würden.
Nun, das ist eine Art Aufgabe, bei der ich keine externen Bibliotheken usw. verwenden kann, also nur im “Kapitelkontext” lox bleiben muss.
– sein Aboutcode
19. September 2009 um 19:48 Uhr
Dann besteht die einzige Option darin, die erforderliche Funktionalität für jedes Betriebssystem zu implementieren, das Sie unterstützen möchten.
– Kirill W. Ljadwinski
19. September 2009 um 20:01 Uhr
ncurses ist mehr oder weniger ein VT200-Client. Ein bisschen übertrieben, um einfach aus dem TTY zu lesen.
– Grauschimmer
19. September 2009 um 20:11 Uhr
Keith Thompson
Sie könnten die Microsoft-spezifische Funktion verwenden _getch:
Soweit ich weiß, besteht das Problem darin, dass Ihre Shell darauf wartet, dass Sie ENTER oder EOF drücken, und dann Ihr Programm sich um alles kümmern lässt, was sich im Puffer befindet, oder so ähnlich. Vielleicht kann jemand mit etwas mehr Wissen eine echte Erklärung liefern. Aber ich denke, es ist nicht so einfach, wie es zunächst scheint.
– Lukas
19. September 2009 um 21:02 Uhr
Der bei weitem einfachste Weg, dies zu handhaben, und der einzige tragbare Weg, besteht darin, Ihre Eingabeaufforderung von „Drücken Sie eine beliebige Taste, um fortzufahren“ in „Drücken Sie die Eingabetaste, um fortzufahren“ zu ändern.
– Mayoff ausrauben
23. Februar 12 um 4:44 Uhr
@Lucas – Ich verwende Mac mit xcode.
– sein Aboutcode
23. Februar 2012 um 19:25 Uhr
@Lucas: Es ist nicht die Shell, es ist das Programm selbst.
– Keith Thompson
23. Februar 2012 um 19:25 Uhr
@KeithThompson: Das ist mehr als zwei Jahre her, aber ich glaube, ich habe versucht, darauf hinzuweisen, dass die Eingabewarteschlange nicht vom Benutzerprozess, sondern im Kernel behandelt wird.
– Lukas
24. Februar 12 um 3:13 Uhr