Wie vermeide ich, mit getchar () die Eingabetaste zu drücken, um nur ein einzelnes Zeichen zu lesen?

80

Im nächsten Code:

Ich muss drücken Enter, um alle Buchstaben zu drucken, mit getchardenen ich eingegeben habe , aber ich möchte dies nicht tun. Ich möchte den Buchstaben drücken und sofort sehen, dass der von mir eingeführte Buchstabe wiederholt wird, ohne zu drücken Enter. Wenn ich zum Beispiel den Buchstaben 'a' drücke, möchte ich ein anderes 'a' daneben sehen und so weiter:

Aber wenn ich 'a' drücke, passiert nichts, ich kann andere Buchstaben schreiben und die Kopie erscheint nur, wenn ich drücke Enter:

Wie kann ich das machen?

Ich benutze den Befehl cc -o example example.cunter Ubuntu zum Kompilieren.

Javier
quelle
5
Dies hängt stark davon ab, wie Ihr Betriebssystem und Ihr Terminal Eingaben verarbeiten. Wenn Sie Ihre Betriebsumgebung angeben, erhalten Sie wahrscheinlich bessere Antworten.
GoldPseudo
Die Antwort unter cplusplus.com/forum/articles/19975 funktioniert unter Windows mit WinAPI.

Antworten:

71

Auf einem Linux-System können Sie das Terminalverhalten mit dem sttyBefehl ändern . Standardmäßig puffert das Terminal alle Informationen, bis sie Entergedrückt werden, bevor es überhaupt an das C-Programm gesendet wird.

Ein schnelles, schmutziges und nicht besonders portables Beispiel, um das Verhalten innerhalb des Programms selbst zu ändern:

Bitte beachten Sie, dass dies nicht wirklich optimal ist, da nur davon ausgegangen wird, dass dies stty cookeddas gewünschte Verhalten beim Beenden des Programms ist, anstatt die ursprünglichen Terminaleinstellungen zu überprüfen. Da alle speziellen Verarbeitungen im Raw-Modus übersprungen werden, funktionieren viele Tastenfolgen (wie STRG-C oder STRG-D ) nicht so, wie Sie es erwarten, ohne sie explizit im Programm zu verarbeiten.

Sie können man sttydas Terminalverhalten besser steuern, je nachdem, was Sie genau erreichen möchten.

goldPseudo
quelle
Verwenden systemist eine schlechte Idee.
Sapphire_Brick
Zu viel roh ... Ich suchte nach einer Lösung, mit der ich nicht auf ENTER warten konnte. Diese Lösung bremst alle Funktionen der Eingangsklemmen.
ABC
93

Dies hängt von Ihrem Betriebssystem ab. Wenn Sie sich in einer UNIX-ähnlichen Umgebung befinden, ist das ICANON-Flag standardmäßig aktiviert, sodass die Eingabe bis zum nächsten '\n'oder gepuffert wird EOF. Wenn Sie den kanonischen Modus deaktivieren, erhalten Sie die Zeichen sofort. Dies ist auch auf anderen Plattformen möglich, es gibt jedoch keine einfache plattformübergreifende Lösung.

EDIT: Ich sehe, Sie haben angegeben, dass Sie Ubuntu verwenden. Ich habe gestern gerade etwas Ähnliches gepostet, aber sei dir bewusst, dass dies viele Standardverhalten deines Terminals deaktiviert.

Sie werden feststellen, dass jedes Zeichen zweimal erscheint. Dies liegt daran, dass die Eingabe sofort an das Terminal zurückgesendet wird und Ihr Programm sie dann auch wieder zurückgibt putchar(). Wenn Sie die Eingabe von der Ausgabe trennen möchten, müssen Sie auch das ECHO-Flag deaktivieren. Sie können dies tun, indem Sie einfach die entsprechende Zeile ändern in:

Lucas
quelle
9
+1 Obwohl tbh, ist dies wahrscheinlich nicht die Codeebene, mit der das Originalplakat
vertraut
2
Großartig! Das habe ich gesucht!
Denilson Sá Maia
Vielen Dank für die Hilfe zusammen mit den detaillierten Kommentaren, es hat mein Problem gelöst.
Kaminsknator
Es ist unglaublich, dass etwas so Grundlegendes so schwer zu erreichen und nicht tragbar ist.
Pedro77
12

getchar () ist eine Standardfunktion, bei der Sie auf vielen Plattformen die EINGABETASTE drücken müssen, um die Eingabe abzurufen, da die Plattform die Eingabe puffert, bis diese Taste gedrückt wird. Viele Compiler / Plattformen unterstützen das nicht standardmäßige getch (), das sich nicht für ENTER interessiert (umgeht die Plattformpufferung und behandelt ENTER wie einen anderen Schlüssel).

Eric J.
quelle
1
+1 Richtig, getchar()beginnt das Lesen von Zeichen nacheinander, nachdem Sie die Eingabetaste gedrückt haben
Andomar
32
getchar()ENTER ist mir egal, es verarbeitet nur alles, was durch stdin kommt. Die Zeilenpufferung ist in der Regel ein vom Betriebssystem / Terminal definiertes Verhalten.
GoldPseudo
1
@goldPseudo: Richtig, aber fast alle Plattformen puffern Eingaben, so dass dies das Verhalten ist, das Sie in den meisten praktischen Fällen sehen werden. Wenn unterstützt, wird getch () die Pufferung entweder verwalten oder ignorieren. Ich weiß, dass einige alte DOS-Implementierungen die Betriebssystempufferung umgangen haben, um direkt mit der Hardware zu interagieren. Andere Implementierungen löschen möglicherweise stdin, um das gleiche Verhalten zu erzielen.
Eric J.
10
Es ist jedoch nicht so getchar(), dass Sie die Eingabetaste drücken müssen, sondern die Umgebung.
Benji XVI
1
Sehr prägnant und leicht zu verstehen. Andere bestbewertete Antworten werfen nur über überwältigende unnötige technische Details.
Mzoz
6

E / A ist eine Betriebssystemfunktion. In vielen Fällen übergibt das Betriebssystem ein eingegebenes Zeichen erst an ein Programm, wenn die EINGABETASTE gedrückt wird. Auf diese Weise kann der Benutzer die Eingabe (z. B. Backspacing und Retyping) ändern, bevor er sie an das Programm sendet. Für die meisten Zwecke funktioniert dies gut, bietet dem Benutzer eine konsistente Benutzeroberfläche und entlastet das Programm davon, sich damit befassen zu müssen. In einigen Fällen ist es wünschenswert, dass ein Programm Zeichen von Tasten abruft, wenn diese gedrückt werden.

Die C-Bibliothek selbst befasst sich mit Dateien und kümmert sich nicht darum, wie Daten in die Eingabedatei gelangen. Daher gibt es in der Sprache selbst keine Möglichkeit, Tasten zu erhalten, wenn sie gedrückt werden. Stattdessen ist dies plattformspezifisch. Da Sie kein Betriebssystem oder keinen Compiler angegeben haben, können wir es nicht für Sie nachschlagen.

Außerdem wird die Standardausgabe normalerweise aus Effizienzgründen gepuffert. Dies wird von den C-Bibliotheken durchgeführt, und so gibt es eine C-Lösung, die fflush(stdout);nach jedem geschriebenen Zeichen steht. Danach hängt es vom Betriebssystem ab, ob die Zeichen sofort angezeigt werden, aber alle mir bekannten Betriebssysteme zeigen die Ausgabe sofort an, sodass dies normalerweise kein Problem darstellt.

David Thornley
quelle
6

Ich mag Lucas Antwort, aber ich würde es gerne ein bisschen ausarbeiten. Es gibt eine eingebaute Funktion in termios.hnamens, cfmakeraw()die der Mensch beschreibt als:

Dies entspricht im Wesentlichen dem, was Lucas vorgeschlagen hat, und Sie können die genauen Flags auf den Manpages sehen: termios (3) .

Anwendungsfall

dann scheint
quelle
Beachten Sie, dass dies cfmakeraw()eine nicht tragbare, nicht standardmäßige Erweiterung von POSIX isttermios.h und nicht unbedingt verfügbar ist.
Andrew Henle
4

Da Sie an einem Unix-Derivat (Ubuntu) arbeiten, gibt es eine Möglichkeit, dies zu tun - nicht empfohlen, aber es wird funktionieren (solange Sie Befehle genau eingeben können):

Verwenden Sie Interrupt, um das Programm zu stoppen, wenn Sie sich langweilen.

  • In der Zeile "Echo" werden die aktuellen Terminaleinstellungen als Shell-Skript gespeichert, mit dem sie wiederhergestellt werden.
  • Die Zeile 'stty' schaltet den größten Teil der Spezialverarbeitung aus ( Control-Dhat also beispielsweise keine Auswirkung) und sendet Zeichen an das Programm, sobald sie verfügbar sind. Dies bedeutet, dass Sie Ihre Eingabe nicht mehr bearbeiten können.
  • Die Zeile 'sh' stellt Ihre ursprünglichen Terminaleinstellungen wieder her.

Sie können sparen, wenn 'stty sane' Ihre Einstellungen für Ihre Zwecke ausreichend genau wiederherstellt. Das Format von '-g' ist nicht für alle Versionen von 'stty' portierbar (was unter Solaris 10 generiert wird, funktioniert also nicht unter Linux oder umgekehrt), aber das Konzept funktioniert überall. Die Option 'stty sane' ist nicht allgemein verfügbar, AFAIK (aber unter Linux).

Jonathan Leffler
quelle
2

Sie können die Bibliothek 'ncurses' einschließen und getch()stattdessen verwenden getchar().

AShelly
quelle
1

Ja, Sie können dies auch unter Windows tun. Hier ist der folgende Code, der die conio.h-Bibliothek verwendet

djaa2807
quelle
6
Die Frage ist mit c markiert , nicht mit c ++
Spikatrix
@CoolGuy Na und? Warum sollte es jemandem helfen, wenn jemand genau dieselbe Frage öffnete, aber das Tag von c in c ++ änderte?
Andreas Haferburg
@AndreasHaferburg Weil wir würden hier nicht C ++ Antworten haben, vor allem nicht schlecht geschriebenen, wink wink .
Sapphire_Brick
1

Ich hatte dieses Problem / diese Frage in einer Aufgabe, an der ich gerade arbeite. Dies hängt auch davon ab, von welchem ​​Eingang Sie greifen. ich benutze

um Eingaben zu erhalten, während das Programm ausgeführt wird, muss dies der dem Befehl zugeordnete Dateistream sein.

Auf der Ubuntu-Maschine muss ich testen / zielen, es war mehr als nur erforderlich

oder

Ich musste das Flag --file sowie den Pfad zum Befehl wie folgt hinzufügen:

Jetzt ist alles kopaketisch.

Chad Chabot
quelle
2
Bitte beachten Sie, dass diese Lösung vom Betriebssystem abhängig ist.
Ottavio Campana
0

Dieser Code hat bei mir funktioniert. Achtung: Dies ist nicht Teil der Standardbibliothek, auch wenn die meisten Compiler (ich verwende GCC) dies unterstützen.

Dieser Code erkennt den ersten Tastendruck.

Firefnix
quelle
0

" Wie vermeide ich es, Entermit zu drücken getchar()? "

Erstens ist der Terminaleingang üblicherweise entweder leitungsgebunden oder vollständig gepuffert. Dies bedeutet, dass das Betriebssystem die tatsächliche Eingabe vom Terminal in einem Puffer speichert. Normalerweise wird dieser Puffer in das Programm geleert, wenn zB \nsignalisiert / bereitgestellt wurde stdin. Dies wird zB durch eine Presse gemacht Enter.

getchar()ist gerade am Ende der Kette. Es ist nicht in der Lage, den Pufferungsprozess tatsächlich zu beeinflussen.


" Wie kann ich das machen? "

Ditchgetchar() in erster Linie, wenn Sie keine spezifischen Systemaufrufe verwenden möchten, um das Verhalten des Terminals explizit zu ändern, wie in den anderen Antworten erläutert.

Es gibt leider keine Standardbibliotheksfunktion und damit keine tragbare Möglichkeit, den Puffer bei der Eingabe einzelner Zeichen zu leeren. Es gibt jedoch implementierungsbasierte und nicht portable Lösungen.


In Windows / MS-DOS gibt es die getch()und getche()-Funktionen in der conio.hHeader-Datei, die genau das tun, was Sie wollen - ein einzelnes Zeichen lesen, ohne darauf warten zu müssen, dass die neue Zeile den Puffer leert.

Der Hauptunterschied zwischen getch()und getche()besteht darin, dass getch()das eigentliche Eingabezeichen in der Konsole nicht sofort ausgegeben wird, während dies der getche()Fall ist. Das zusätzliche "e"steht für Echo .

Beispiel:


In Linux, eine Möglichkeit , direkte Zeichenverarbeitung und Ausgabe zu erhalten , ist es, die zu verwenden cbreak()und echo()Optionen und die getch()und refresh()Routinen in der ncurses-Bibliothek.

Beachten Sie, dass Sie den sogenannten Standardbildschirm mit dem initialisieren initscr()und diesen mit den endwin()Routinen schließen müssen.

Beispiel:


Hinweis: Sie müssen den Compiler mit der -lncursesOption aufrufen , damit der Linker die ncurses-Bibliothek suchen und finden kann.

RobertS unterstützt Monica Cellio
quelle
-1

Standardmäßig puffert die C-Bibliothek die Ausgabe, bis eine Rückgabe angezeigt wird. Verwenden Sie zum sofortigen Ausdrucken der Ergebnisse fflush:

Andomar
quelle
2
Die Ausgabe ist jedoch Teil des Problems. Der Fragesteller möchte, dass das Programm die Tasten beim Drücken liest und sofort auf dem Bildschirm druckt. Das ist sowohl ein Eingabe- als auch ein Ausgabeproblem.
David Thornley
dh fflush spült nur die Ausgabe, aber getchar kehrt nach dem Drücken der Taste immer noch nicht zurück (Tasten werden gepuffert).
NickSoft