Erfassen Sie Zeichen von der Standardeingabe, ohne zu warten Eingabe gedrückt werden
-
05-07-2019 - |
Frage
Ich kann nie mehr, wie ich dies tun, weil es so selten für mich kommt. Aber in C oder C ++, was ist der beste Weg, um ein Zeichen von der Standardeingabe zu lesen, ohne für eine neue Zeile zu warten (drücken Sie die Eingabetaste).
Auch ideal wäre es nicht das eingegebene Zeichen auf dem Bildschirm echo. Ich möchte nur Tastatureingaben aufzeichnen mit aus dem Konsolenbildschirm zu bewirken.
Lösung
Das ist nicht möglich, in einer tragbaren Weise in reinen C ++, weil es auf dem Terminal zu viel hängt verwendet, die mit stdin
verbunden werden können (sie sind in der Regel Linie gepuffert). Sie können jedoch eine Bibliothek verwenden dafür:
-
conio verfügbar mit Windows-Compiler. Verwenden Sie die Funktion
_getch()
Sie ohne Warten auf die Enter-Taste um ein Zeichen zu geben. Ich bin nicht ein häufiger Windows-Entwickler, aber ich habe meine Mitschüler nur schließen<conio.h>
gesehen und es verwenden. Sieheconio.h
bei Wikipedia. Es listetgetch()
, die in Visual C ++ als veraltet deklariert wird. -
Flüche für Linux. Kompatible Flüche Implementierungen sind für Windows zu Verfügung. Es hat auch eine
getch()
Funktion. (Versuchen Sieman getch
seine manpage zu sehen). Siehe Flüche bei Wikipedia.
Ich würde Ihnen empfehlen, Flüche zu verwenden, wenn Sie für Cross-Plattform-Kompatibilität zielen. Das heißt, ich bin sicher, es gibt Funktionen, die Sie Linie Pufferung verwenden können, um abschalten (Ich glaube, dass „Raw-Modus“ genannt wird, im Gegensatz zu „gekocht Modus“ - schauen Sie in man stty
). Flüche würden, dass in einer tragbaren Weise für Sie erledigen, wenn ich mich nicht irre.
Andere Tipps
Unter Linux (und anderen Unix-artige Systemen) kann dies in folgenden Weise erfolgen:
#include <unistd.h>
#include <termios.h>
char getch() {
char buf = 0;
struct termios old = {0};
if (tcgetattr(0, &old) < 0)
perror("tcsetattr()");
old.c_lflag &= ~ICANON;
old.c_lflag &= ~ECHO;
old.c_cc[VMIN] = 1;
old.c_cc[VTIME] = 0;
if (tcsetattr(0, TCSANOW, &old) < 0)
perror("tcsetattr ICANON");
if (read(0, &buf, 1) < 0)
perror ("read()");
old.c_lflag |= ICANON;
old.c_lflag |= ECHO;
if (tcsetattr(0, TCSADRAIN, &old) < 0)
perror ("tcsetattr ~ICANON");
return (buf);
}
Im Grunde muss man kanonischen Modus (und Echo-Modus zu unterdrücken Echo).
deaktivierenDas fand ich auf einem anderen Forum während Sie das gleiche Problem zu lösen. Ich habe es verändert ein wenig von dem, was ich gefunden habe. Es funktioniert großartig. Ich bin mit OS X, so dass, wenn Sie Microsoft laufen lassen, werden Sie das richtige System () Befehl zum Umschalten auf rohen und gekochten Modi finden müssen.
#include <iostream>
#include <stdio.h>
using namespace std;
int main() {
// Output prompt
cout << "Press any key to continue..." << endl;
// Set terminal to raw mode
system("stty raw");
// Wait for single character
char input = getchar();
// Echo input:
cout << "--" << input << "--";
// Reset terminal to normal "cooked" mode
system("stty cooked");
// And we're out of here
return 0;
}
conio.h
Funktionen, die Sie benötigen, sind:
int getch();
Prototype
int _getch(void);
Description
_getch obtains a character from stdin. Input is unbuffered, and this
routine will return as soon as a character is available without
waiting for a carriage return. The character is not echoed to stdout.
_getch bypasses the normal buffering done by getchar and getc. ungetc
cannot be used with _getch.
Synonym
Function: getch
int kbhit();
Description
Checks if a keyboard key has been pressed but not yet read.
Return Value
Returns a non-zero value if a key was pressed. Otherwise, returns 0.
libconio http://sourceforge.net/projects/libconio
oder
Linux c ++ Implementierung von conio.h http://sourceforge.net/projects/linux-conioh
#include <conio.h>
if (kbhit() != 0) {
cout << getch() << endl;
}
Dies verwendet kbhit()
zu überprüfen, ob die Tastatur gedrückt wird und verwendet getch()
den Charakter zu erhalten, die gedrückt wird.
Wenn Sie auf Fenster sind, können Sie PeekConsoleInput zu erkennen, ob ein Eingang gibt es,
HANDLE handle = GetStdHandle(STD_INPUT_HANDLE);
DWORD events;
INPUT_RECORD buffer;
PeekConsoleInput( handle, &buffer, 1, &events );
dann Read verwenden, um „verbrauchen“ die Eingabezeichen ..
PeekConsoleInput(handle, &buffer, 1, &events);
if(events > 0)
{
ReadConsoleInput(handle, &buffer, 1, &events);
return buffer.Event.KeyEvent.wVirtualKeyCode;
}
else return 0
Um ehrlich zu sein dies aus einem alten Code ist, ich habe, so dass Sie ein bisschen mit ihm Geige haben.
Die kühle Sache ist aber, dass es Eingabe liest, ohne dass irgendetwas aufgefordert, so dass die Zeichen werden nicht angezeigt.
Fenster Unter der Annahme, werfen Sie einen Blick auf die Read Funktion.
C und C eine sehr abstrakte Ansicht von I / O ++ nehmen, und es gibt keine Standardmethode zu tun, was Sie wollen. Es gibt Standard-Möglichkeiten, Zeichen aus dem Standardeingabe-Stream zu bekommen, wenn es welche gibt zu bekommen, und sonst nichts von jeder Sprache definiert ist. Jede Antwort wird daher sein müssen plattformspezifische, vielleicht hängt nicht nur von dem Betriebssystem, sondern auch die Software-Framework.
Es gibt einige vernünftigen Vermutungen hier, aber es gibt keine Möglichkeit, Ihre Frage zu beantworten, ohne zu wissen, was Ihre Zielumgebung ist.
Die nächste Sache, tragbar ist die ncurses
Bibliothek zu verwenden, um das Terminal zu setzen in "cbreak Modus". Die API ist riesig; die Routinen Sie sind die meisten
-
initscr
undendwin
-
cbreak
undnocbreak
-
getch
Viel Glück!
Ich benutze kbhit (), um zu sehen, ob ein Zeichen vorhanden ist, und dann getchar (), um die Daten zu lesen. Unter Windows können Sie „conio.h“ verwenden. Unter Linux haben Sie Ihre eigene kbhit ().
implementierenSiehe Code unten:
// kbhit
#include <stdio.h>
#include <sys/ioctl.h> // For FIONREAD
#include <termios.h>
#include <stdbool.h>
int kbhit(void) {
static bool initflag = false;
static const int STDIN = 0;
if (!initflag) {
// Use termios to turn off line buffering
struct termios term;
tcgetattr(STDIN, &term);
term.c_lflag &= ~ICANON;
tcsetattr(STDIN, TCSANOW, &term);
setbuf(stdin, NULL);
initflag = true;
}
int nbbytes;
ioctl(STDIN, FIONREAD, &nbbytes); // 0 is STDIN
return nbbytes;
}
// main
#include <unistd.h>
int main(int argc, char** argv) {
char c;
//setbuf(stdout, NULL); // Optional: No buffering.
//setbuf(stdin, NULL); // Optional: No buffering.
printf("Press key");
while (!kbhit()) {
printf(".");
fflush(stdout);
sleep(1);
}
c = getchar();
printf("\nChar received:%c\n", c);
printf("Done.\n");
return 0;
}
Das Folgende ist eine Lösung von Expert C Programming extrahiert Deep Secrets , die angeblich auf SVr4 zu arbeiten. Es nutzt stty und ioctl .
#include <sys/filio.h>
int kbhit()
{
int i;
ioctl(0, FIONREAD, &i);
return i; /* return a count of chars available to read */
}
main()
{
int i = 0;
intc='';
system("stty raw -echo");
printf("enter 'q' to quit \n");
for (;c!='q';i++) {
if (kbhit()) {
c=getchar();
printf("\n got %c, on iteration %d",c, i);
}
}
system("stty cooked echo");
}
Ich wollte immer eine Schleife meine Eingabe lesen, ohne Return-Taste zu drücken. Dies funktionierte gut für mich.
#include<stdio.h>
main()
{
char ch;
system("stty raw");//seting the terminal in raw mode
while(1)
{
ch=getchar();
if(ch=='~'){ //terminate or come out of raw mode on "~" pressed
system("stty cooked");
//while(1);//you may still run the code
exit(0); //or terminate
}
printf("you pressed %c\n ",ch); //write rest code here
}
}
funktioniert bei mir unter Windows:
#include <conio.h>
char c = _getch();
Sie können es tun portably SDL (Simple Directmedia Library), obwohl ich Sie vermuten, kann wie sein Verhalten nicht. Als ich es versuchte, musste ich SDL ein neues Video-Fenster erstellen (obwohl ich es nicht für mein Programm brauchte) und haben diese Fenster „greifen“ fast alle Tastatur- und Mauseingaben (was für meine Nutzung in Ordnung war, aber konnte als störend oder undurchführbar in anderen Situationen). Ich vermute, es ist übertrieben und nicht wert, es sei denn, vollständige Portabilität ist ein Muss -. Sonst einen der anderen vorgeschlagenen Lösungen versuchen
Übrigens, dieses Sie Tastendruck geben und Veranstaltungen separat freigeben, wenn Sie, dass sind.
ncurses bietet eine schöne Möglichkeit, dies zu tun! Auch dies ist mein erster Beitrag (das ich mich erinnern kann), so dass alle Kommentare überhaupt sind willkommen. Ich werde Nützlichen zu schätzen wissen, aber alle sind willkommen!
kompilieren: g ++ -std = c ++ 11 -pthread -lncurses CPP -o
#include <iostream>
#include <ncurses.h>
#include <future>
char get_keyboard_input();
int main(int argc, char *argv[])
{
initscr();
raw();
noecho();
keypad(stdscr,true);
auto f = std::async(std::launch::async, get_keyboard_input);
while (f.wait_for(std::chrono::milliseconds(20)) != std::future_status::ready)
{
// do some work
}
endwin();
std::cout << "returned: " << f.get() << std::endl;
return 0;
}
char get_keyboard_input()
{
char input = '0';
while(input != 'q')
{
input = getch();
}
return input;
}