Verwenden von kbhit() und getch() unter Linux

Lesezeit: 6 Minuten

Unter Windows habe ich den folgenden Code, um nach Eingaben zu suchen, ohne die Schleife zu unterbrechen:

#include <conio.h>
#include <Windows.h>
#include <iostream>

int main()
{
    while (true)
    {
        if (_kbhit())
        {
            if (_getch() == 'g')
            {
                std::cout << "You pressed G" << std::endl;
            }
        }
        Sleep(500);
        std::cout << "Running" << std::endl;
    }
}

Da es jedoch keine gibt conio.hwas ist der einfachste Weg, um genau dasselbe unter Linux zu erreichen?

  • Die ncurses Bibliothek soll helfen.

    – 5gon12eder

    29. März 2015 um 22:43 Uhr

  • Ich habe das noch nie gemacht, weil es unter Linux schwieriger ist als unter Windows. Ich werde gehen ein Link zu einem NCURSES-Howto, wie man das mit ncurses.h macht.

    – Matthäus Carlson

    29. März 2015 um 22:44 Uhr


  • ncurses funktionierte perfekt, danke!

    – Boxom

    30. März 2015 um 2:11 Uhr

Verwenden von kbhit und getch unter
Christoph

Wenn Ihr Linux keine hat conio.h das unterstützt kbhit() Du kannst sehen hier für den Code von Morgan Mattews bereitstellen kbhit() Funktionalität in einer Weise, die mit jedem POSIX-kompatiblen System kompatibel ist.

Da der Trick das Puffern auf Termios-Ebene deaktivieren sollte, sollte es auch das lösen getchar() Ausgabe wie gezeigt Hier.

  • Der Getch ist wahrscheinlich wichtiger für @Boxiom.

    – Matthäus Carlson

    29. März 2015 um 22:42 Uhr

  • Diese Antwort hat mein Problem gelöst, also danke Christophe. Aber ich möchte hinzufügen, dass „#include “ erforderlich war, damit ich die Funktion von Morgan McGuire aufgrund der Verwendung von FIONREAD in meinem Programm zum Laufen bekomme, und dass dies nicht explizit als erforderlich auf der aufgeführt ist Webseite, wo sein Code zu finden ist.

    – Benutzer251563

    22. November 2015 um 23:59 Uhr


  • stropts.h keine solche Datei oder Verzeichnis. Anscheinend unterstützt Linux dies nicht mehr

    – elig

    29. Juli 2020 um 17:21 Uhr

  • @elig in der Tat scheint es in letzter Zeit einige Änderungen in der Linux-Welt zu geben: bugs.debian.org/cgi-bin/bugreport.cgi?bug=954552 – Es gibt bereits einige neuere Antworten zu ähnlichen Problemen mit stropts.h auf SO: Vielleicht finden Sie eine passende, vielleicht eröffnen Sie eine neue. Es wäre großartig, einen Kommentar hinzuzufügen, wenn Sie eine Lösung für diejenigen finden, die möglicherweise dasselbe Problem mit derselben Distribution haben.

    – Christoph

    29. Juli 2020 um 17:46 Uhr

Das oben zitierte ncurses howto kann hilfreich sein. Hier ist ein Beispiel, das veranschaulicht, wie ncurses wie das conio-Beispiel verwendet werden könnte:

#include <ncurses.h>

int
main()
{
    initscr();
    cbreak();
    noecho();
    scrollok(stdscr, TRUE);
    nodelay(stdscr, TRUE);
    while (true) {
        if (getch() == 'g') {
            printw("You pressed G\n");
        }
        napms(500);
        printw("Running\n");
    }
}

Beachten Sie, dass bei ncurses die iostream Kopfzeile wird nicht verwendet. Das liegt daran, dass das Mischen von stdio mit ncurses zu unerwarteten Ergebnissen führen kann.

ncurses definiert übrigens TRUE und FALSE. Ein korrekt konfiguriertes Ncurses verwendet denselben Datentyp für Ncurses. bool als C++-Compiler, der zum Konfigurieren von ncurses verwendet wird.

  • afaik sollten Sie ein hinzufügen endwin() am Ende des Programms

    – 463035818_ist_keine_Nummer

    27. September 2018 um 14:16 Uhr

  • nur erforderlich, wenn das Programm beendet wird – in der Frage von OP nicht.

    – Thomas Dickey

    27. September 2018 um 19:48 Uhr

  • Es tut nicht. Es wird ewig geloopt.

    – Thomas Dickey

    27. September 2018 um 20:30 Uhr

  • ohh…sorry 😉 aber musst du das terminal nicht zurücksetzen?

    – 463035818_ist_keine_Nummer

    27. September 2018 um 20:37 Uhr


  • nicht in diesem Fall: man könnte mit a aussteigen ^Cund ncurses würde wie in beschrieben zurückgesetzt Endgewinn.

    – Thomas Dickey

    27. September 2018 um 21:38 Uhr

Eine kompakte Lösung, die auf Christophes Antwort basiert, ist

#include <sys/ioctl.h>
#include <termios.h>

bool kbhit()
{
    termios term;
    tcgetattr(0, &term);

    termios term2 = term;
    term2.c_lflag &= ~ICANON;
    tcsetattr(0, TCSANOW, &term2);

    int byteswaiting;
    ioctl(0, FIONREAD, &byteswaiting);

    tcsetattr(0, TCSANOW, &term);

    return byteswaiting > 0;
}

Im Gegensatz zu dieser Antwort wird das Terminal nach dem Beenden des Programms nicht in einem seltsamen Zustand bleiben. Die Zeichen bleiben jedoch weiterhin im Eingabepuffer, sodass die gedrückte Taste unerwünschterweise in der nächsten Eingabeaufforderungszeile angezeigt wird.

Eine andere Lösung, die dieses Problem behebt, ist

void enable_raw_mode()
{
    termios term;
    tcgetattr(0, &term);
    term.c_lflag &= ~(ICANON | ECHO); // Disable echo as well
    tcsetattr(0, TCSANOW, &term);
}

void disable_raw_mode()
{
    termios term;
    tcgetattr(0, &term);
    term.c_lflag |= ICANON | ECHO;
    tcsetattr(0, TCSANOW, &term);
}

bool kbhit()
{
    int byteswaiting;
    ioctl(0, FIONREAD, &byteswaiting);
    return byteswaiting > 0;
}

Die Verwendung ist wie folgt

enable_raw_mode();
// ...
if (kbhit()) ...
// ...
disable_raw_mode();
tcflush(0, TCIFLUSH); // Clear stdin to prevent characters appearing on prompt

Jetzt werden alle Zeichen, die zwischen der Ausführung der ersten und letzten Zeile eingegeben wurden, nicht im Terminal angezeigt. Wenn Sie jedoch mit Strg + C das Terminal verlassen ist in einem seltsamen Zustand zurückgelassen. (Seufzen)

  • Dies funktioniert, um festzustellen, ob eine Taste gedrückt wurde, bietet jedoch keine Möglichkeit, das entsprechende Zeichen zu erhalten (wenn Sie getc() verwenden, müssen Sie immer noch darauf warten, dass der Benutzer die Eingabetaste drückt). Sehen Sie sich diese Lösung an, wenn Sie auf das Drücken einer Taste warten und sofort das Zeichen erhalten möchten: stackoverflow.com/a/912796/544099

    – Ismael

    25. Februar 2019 um 13:47 Uhr

1646178007 439 Verwenden von kbhit und getch unter
Prof. Falken

Während die Verwendung von ncurses funktional der API “conio.h” von Turbo C entspricht, besteht eine vollständigere Lösung darin, eine conio-Implementierung zu verwenden, wie es möglich ist hier gefunden.

Sie laden es herunter und verwenden es in Ihrem Programm für eine sehr vollständige Implementierung der conio-Schnittstelle unter Linux. (Oder OSX.) Geschrieben von Ron Burkey.

1646178008 295 Verwenden von kbhit und getch unter
orlov_dumitru

Wenn Sie Linux verwenden, habe ich diese Lösung gefunden, mit der Sie Ihre eigene lokale Bibliothek erstellen können:

http://linux-sxs.org/programming/kbhit.html

kbhit.cpp


#include "kbhit.h"
#include <unistd.h> // read()
    
keyboard::keyboard(){
    tcgetattr(0,&initial_settings);
    new_settings = initial_settings;
    new_settings.c_lflag &= ~ICANON;
    new_settings.c_lflag &= ~ECHO;
    new_settings.c_lflag &= ~ISIG;
    new_settings.c_cc[VMIN] = 1;
    new_settings.c_cc[VTIME] = 0;
    tcsetattr(0, TCSANOW, &new_settings);
    peek_character=-1;
}
    
keyboard::~keyboard(){
    tcsetattr(0, TCSANOW, &initial_settings);
}
    
int keyboard::kbhit(){
    unsigned char ch;
    int nread;
    if (peek_character != -1) return 1;
    new_settings.c_cc[VMIN]=0;
    tcsetattr(0, TCSANOW, &new_settings);
    nread = read(0,&ch,1);
    new_settings.c_cc[VMIN]=1;
    tcsetattr(0, TCSANOW, &new_settings);

    if (nread == 1){
        peek_character = ch;
        return 1;
    }
    return 0;
}
    
int keyboard::getch(){
    char ch;

    if (peek_character != -1){
        ch = peek_character;
        peek_character = -1;
    }
    else read(0,&ch,1);
    return ch;
}

kbhit.h

#ifndef KBHIT_H
#define KBHIT_H
    
#include <termios.h>
    
class keyboard{
    public:
        keyboard();
        ~keyboard();
        int kbhit();
        int getch();

    private:
        struct termios initial_settings, new_settings;
        int peek_character;
};
    
#endif

in main.cpp habe ich eine Instanz erstellt:

#include "kbhit.h"

int main(){
    int key_nr;
    char key;
    keyboard keyb;
    while(true){
        if( keyb.kbhit() ){
            key_nr = keyb.getch(); //return int
            key = key_nr; // get ascii char
            // do some stuff
        }
    }
    return 0;
}

906070cookie-checkVerwenden von kbhit() und getch() unter Linux

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

Privacy policy