Using kbhit() and getch() on Linux

北城以北 提交于 2019-11-26 05:36:53

问题


On Windows, I have the following code to look for input without interrupting the loop:

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

However, seeing that there is no conio.h, whats the simplest way of achieving this very same thing on Linux?


回答1:


The ncurses howto cited above can be helpful. Here is an example illustrating how ncurses could be used like the conio example:

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

Note that with ncurses, the iostream header is not used. That is because mixing stdio with ncurses can have unexpected results.

ncurses, by the way, defines TRUE and FALSE. A correctly configured ncurses will use the same data-type for ncurses' bool as the C++ compiler used for configuring ncurses.




回答2:


If your linux has no conio.h that supports kbhit() you can look here for Morgan Mattews's code to provide kbhit() functionality in a way compatible with any POSIX compliant system.

As the trick desactivate buffering at termios level, it should also solve the the getchar() issue as demonstrated here.




回答3:


A compact solution based on Christophe's answer is

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

Unlike that answer, this won't leave the terminal in a weird state after the program has exited. However, it still leaves the characters sitting in the input buffer, so the key that was pressed will unwelcomely appear on the next prompt line.

A different solution which fixes this problem is

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

Usage is as follows

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

Now any characters typed between execution of the first and last lines won't show up in the terminal. However, if you exit with Ctrl+C the terminal is left in a weird state. (Sigh)




回答4:


While using ncurses is functionally equivalent to the Turbo C "conio.h" API, a more complete solution is to use a conio implementation, as can be found here.

You download and use it in your program for a very complete implementation of the conio interface, on Linux. (Or OSX.) Written by Ron Burkey.



来源:https://stackoverflow.com/questions/29335758/using-kbhit-and-getch-on-linux

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!