Erfassen Sie Zeichen von der Standardeingabe, ohne zu warten Eingabe gedrückt werden

StackOverflow https://stackoverflow.com/questions/421860

  •  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.

War es hilfreich?

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:

  1. 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. Siehe conio.h bei Wikipedia. Es listet getch(), die in Visual C ++ als veraltet deklariert wird.

  2. Flüche für Linux. Kompatible Flüche Implementierungen sind für Windows zu Verfügung. Es hat auch eine getch() Funktion. (Versuchen Sie man 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).

deaktivieren

Das 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

wollen
  • initscr und endwin
  • cbreak und nocbreak
  • 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 ().

implementieren

Siehe 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;
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top