Erfassen Sie Zeichen aus der Standardeingabe, ohne auf das Drücken der Eingabetaste zu warten

Lesezeit: 8 Minuten

Erfassen Sie Zeichen aus der Standardeingabe ohne auf das Drucken
Adam

Ich kann mich nie erinnern, wie ich das mache, weil es so selten für mich vorkommt. Aber in C oder C++, was ist der beste Weg, um ein Zeichen von der Standardeingabe zu lesen, ohne auf einen Zeilenumbruch zu warten (drücken Sie die Eingabetaste).

Idealerweise würde es das eingegebene Zeichen auch nicht auf dem Bildschirm wiedergeben. Ich möchte nur Tastenanschläge erfassen, ohne den Konsolenbildschirm zu beeinflussen.

  • @adam – Können Sie klarstellen: Möchten Sie eine Funktion, die sofort zurückkehrt, wenn kein Zeichen verfügbar ist, oder eine, die immer auf einen einzelnen Tastendruck wartet?

    – Roddy

    8. Januar 2009 um 9:47 Uhr

  • @Roddy – Ich möchte eine Funktion, die immer auf einen einzelnen Tastendruck wartet.

    – Adam

    28. Mai 2009 um 4:52 Uhr

Erfassen Sie Zeichen aus der Standardeingabe ohne auf das Drucken
Johannes Schaub – litb

Das ist portabel in reinem C++ nicht möglich, da es zu sehr vom verwendeten Endgerät abhängt, mit dem man sich verbinden kann stdin (sie sind normalerweise zeilengepuffert). Sie können dafür jedoch eine Bibliothek verwenden:

  1. conio verfügbar mit Windows-Compilern. Verwenden Sie die _getch() Funktion, um Ihnen ein Zeichen zu geben, ohne auf die Eingabetaste zu warten. Ich bin kein häufiger Windows-Entwickler, aber ich habe gesehen, dass meine Klassenkameraden einfach enthalten <conio.h> und benutze es. Sehen conio.h bei Wikipedia. Es listet auf getch()die in Visual C++ als veraltet deklariert ist.

  2. Flüche für Linux verfügbar. Kompatible Curses-Implementierungen sind auch für Windows verfügbar. Es hat auch eine getch() Funktion. (Versuchen man getch um seine Manpage anzuzeigen). Sehen Flüche bei Wikipedia.

Ich würde Ihnen empfehlen, Flüche zu verwenden, wenn Sie plattformübergreifende Kompatibilität anstreben. Ich bin mir jedoch sicher, dass es Funktionen gibt, mit denen Sie die Zeilenpufferung ausschalten können (ich glaube, das heißt “Raw-Modus” im Gegensatz zum “Cooked-Modus” – schauen Sie sich das an man stty). Wenn ich mich nicht irre, würden Curses das auf tragbare Weise für Sie erledigen.

  • Beachten Sie, dass heutzutage ncurses ist die empfohlene Variante von curses.

    – Nik

    7. Mai 2016 um 3:04 Uhr

  • Wenn Sie eine Bibliothek brauchen, wie haben sie es dann gemacht? Um die Bibliothek zu erstellen, mussten Sie sie sicherlich programmieren, und das bedeutet, dass jeder sie programmieren könnte. Warum können wir also nicht einfach den Bibliothekscode programmieren, den wir selbst benötigen? das würde das auch machen Das ist in reinem C++ unmöglich portierbar falsch

    Benutzer6053405

    3. Januar 2017 um 9:49 Uhr

  • @kid8 verstehe ich nicht

    – Johannes Schaub – litb

    3. Januar 2017 um 16:51 Uhr

  • @JohannesSchaub-litb er versucht wahrscheinlich zu sagen, wie der Bibliotheksimplementierer diese portable Methode in reinem c/c++ erstellt hat, wenn Sie sagen, dass dies nicht möglich ist.

    – Abhinav Gauniyal

    18. Januar 2017 um 2:30 Uhr

  • @AbhinavGauniyal ah, ich verstehe. Ich habe jedoch nicht gesagt, dass die Bibliotheks-Implementierer keine portablen Methoden erstellt haben (dh von einigermaßen portablen Programmen verwendet werden können). Ich habe angedeutet, dass sie kein portables C++ verwendet haben. Da dies offensichtlich nicht der Fall ist, verstehe ich nicht, warum sein Kommentar besagt, dass dieser Teil meiner Antwort falsch ist.

    – Johannes Schaub – litb

    18. Januar 2017 um 13:51 Uhr

Unter Linux (und anderen Unix-ähnlichen Systemen) kann dies auf folgende 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);
}

Grundsätzlich müssen Sie den kanonischen Modus (und den Echomodus zur Unterdrückung von Echos) ausschalten.

  • Ich habe versucht, diesen Code zu implementieren, aber ich habe einen Fehler beim Aufruf von erhalten read. Ich habe beide Header eingefügt.

    – Michael Dorst

    21. Juli 2012 um 1:59 Uhr

  • Möglicherweise, weil dieser Code falsch ist, da read() ein in unistd.h definierter POSIX-Systemaufruf ist. stdio.h könnte es zufällig enthalten, aber Sie brauchen stdio.h für diesen Code überhaupt nicht; Ersetzen Sie es durch unistd.h und es sollte gut sein.

    – Falke Momot

    22. Juli 2012 um 13:41 Uhr

  • Ich weiß nicht, wie ich hier gelandet bin, während ich nach Tastatureingaben am ROS-Terminal in Raspberry Pi gesucht habe. Dieser Codeschnipsel funktioniert bei mir.

    – ja

    23. März 2015 um 9:07 Uhr

  • @FalconMomot In meiner NetBeans IDE 8.1 (bei Kali Linux) heißt es: error: ‘perror’ was not declared in this scope beim Kompilieren, funktioniert aber gut, wenn es enthalten ist stdio.h zusammen mit unistd.h.

    – Abhishek Kashyap

    5. August 2016 um 22:37 Uhr

  • Gibt es eine einfache Möglichkeit, dies so zu erweitern, dass es nicht blockiert?

    – Joe Strout

    21. Juli 2017 um 14:21 Uhr

1647264612 496 Erfassen Sie Zeichen aus der Standardeingabe ohne auf das Drucken
cwiii

Ich habe dies in einem anderen Forum gefunden, als ich nach der Lösung des gleichen Problems suchte. Ich habe es ein wenig von dem, was ich gefunden habe, modifiziert. Es funktioniert großartig. Ich verwende OS X. Wenn Sie also Microsoft ausführen, müssen Sie den richtigen system() -Befehl finden, um in den Raw- und den Cooked-Modus zu wechseln.

#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; 
}

  • Obwohl dies funktioniert, ist es meiner Meinung nach selten der “beste” Weg, das System zu berappen. Das stty-Programm ist in C geschrieben, sodass Sie oder einschließen und denselben Code aufrufen können, den stty verwendet, ohne von einem externen Programm/Fork/whatnot abhängig zu sein.

    – Chris Lutz

    26. Mai 2009 um 21:29 Uhr

  • Ich brauchte das für zufällige Proof-of-Concept-Sachen und Herumspielen. Genau das, was ich brauchte. Danke. Es sollte beachtet werden: Ich würde auf jeden Fall das stty cooked an das Ende des Programms stellen, sonst bleibt Ihre Shell im stty raw-Modus, was im Grunde genommen meine Shell kaputt gemacht hat, lol, nachdem das Programm gestoppt wurde.

    – Benjamin

    4. November 2014 um 5:32 Uhr

  • Ich glaube, du hast es vergessen #include <stdlib.h>

    – NerdOfCode

    9. Juni 2018 um 5:35 Uhr

  • Verwenden system ist eine sehr schlechte idee.

    – Saphir_Ziegel

    21. August 2020 um 16:40 Uhr

CONIO.H

Die 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

1647264613 28 Erfassen Sie Zeichen aus der Standardeingabe ohne auf das Drucken
Hasen

Wenn Sie Windows verwenden, können Sie verwenden PeekConsoleInput um zu erkennen, ob es eine Eingabe gibt,

HANDLE handle = GetStdHandle(STD_INPUT_HANDLE);
DWORD events;
INPUT_RECORD buffer;
PeekConsoleInput( handle, &buffer, 1, &events );

Verwenden Sie dann ReadConsoleInput, um das Eingabezeichen zu “verbrauchen”.

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, stammt das aus einem alten Code, den ich habe, also müssen Sie ein bisschen damit herumspielen.

Das Coole ist jedoch, dass Eingaben ohne Aufforderung gelesen werden, sodass die Zeichen überhaupt nicht angezeigt werden.

#include <conio.h>

if (kbhit() != 0) {
    cout << getch() << endl;
}

Dies nutzt kbhit() um zu überprüfen, ob die Tastatur gedrückt und verwendet wird getch() um das gedrückte Zeichen zu erhalten.

Erfassen Sie Zeichen aus der Standardeingabe ohne auf das Drucken
sinfod

Ich verwende 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 müssen Sie Ihr eigenes 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;
}

  • Habe hier eine Variante dieser Lösung gepostet: stackoverflow.com/a/67363091/1599699 Es funktioniert gut, danke.

    – Andreas

    3. Mai 2021 um 3:12 Uhr

1001740cookie-checkErfassen Sie Zeichen aus der Standardeingabe, ohne auf das Drücken der Eingabetaste zu warten

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy