在Linux上使用kbhit()和getch()

时间:2021-10-05 16:16:28

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

在Windows上,我有以下代码来查找输入而不中断循环:

#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?

但是,看到没有conio.h,在Linux上实现这一点的最简单方法是什么?

4 个解决方案

#1


5  

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

如上所述的ncurses如何引用可能会有所帮助。这是一个示例,说明如何使用ncurses像conio示例:

#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时,不使用iostream标头。这是因为将stdio与ncurses混合会产生意想不到的结果。

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.

顺便说一下,ncurses定义为TRUE和FALSE。正确配置的ncurses将使用与ncurses的bool相同的数据类型作为用于配置ncurses的C ++编译器。

#2


8  

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.

如果您的linux没有支持kbhit()的conio.h,您可以在这里查看Morgan Mattews的代码,以与任何POSIX兼容系统兼容的方式提供kbhit()功能。

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

由于技巧在termios级别停用缓冲,它还应解决此处演示的getchar()问题。

#3


2  

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.

虽然使用ncurses在功能上等同于Turbo C“conio.h”API,但更完整的解决方案是使用conio实现,如此处所示。

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.

您可以在程序中下载并使用它,以便在Linux上完全实现conio接口。 (或OSX。)由Ron Burkey撰写。

#4


2  

A compact solution based on Christophe's answer is

基于Christophe答案的紧凑型解决方案是

#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)

现在,在执行第一行和最后一行之间键入的任何字符都不会显示在终端中。但是,如果您使用Ctrl + C退出,则终端将处于奇怪的状态。 (叹)

#1


5  

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

如上所述的ncurses如何引用可能会有所帮助。这是一个示例,说明如何使用ncurses像conio示例:

#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时,不使用iostream标头。这是因为将stdio与ncurses混合会产生意想不到的结果。

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.

顺便说一下,ncurses定义为TRUE和FALSE。正确配置的ncurses将使用与ncurses的bool相同的数据类型作为用于配置ncurses的C ++编译器。

#2


8  

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.

如果您的linux没有支持kbhit()的conio.h,您可以在这里查看Morgan Mattews的代码,以与任何POSIX兼容系统兼容的方式提供kbhit()功能。

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

由于技巧在termios级别停用缓冲,它还应解决此处演示的getchar()问题。

#3


2  

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.

虽然使用ncurses在功能上等同于Turbo C“conio.h”API,但更完整的解决方案是使用conio实现,如此处所示。

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.

您可以在程序中下载并使用它,以便在Linux上完全实现conio接口。 (或OSX。)由Ron Burkey撰写。

#4


2  

A compact solution based on Christophe's answer is

基于Christophe答案的紧凑型解决方案是

#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)

现在,在执行第一行和最后一行之间键入的任何字符都不会显示在终端中。但是,如果您使用Ctrl + C退出,则终端将处于奇怪的状态。 (叹)