为什么在按下功能或箭头键时getch返回三个值?

时间:2018-09-07 01:10:46

标签: c++ input

我有一个getch()函数,其功能与Unix(Mac OSX?)getchar()或Windows _getch()大致相同,不同之处在于它不等待用户按Enter才返回值。我想使用它,因为它避免了必须使用system()进行实时输入。 (我必须做类似system(“ stty raw”)之类的事情才能使用上述功能做等效的事情,而无论出于何种原因,stty raw确实会弄乱我的终端的缩进。)这是代码:

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


int main() {
    //std::thread InputThread(GetInput);
    int c = 0;
    while(c != 127) { // Delete key is 127
        c = getch();
        std::cout << "Input: " << c << "\n" << endl;
    }
    std::cout << "Broke!" << endl;
    std::this_thread::sleep_for(std::chrono::seconds(3));
    Quit();
    //InputThread.detach();
    return 0;
}

它可以按您期望的那样工作。您键入一个密钥,它会被打印回给您。如果按Delete键,程序将退出。但是,奇怪的是,如果按下例如向上箭头,您将获得如下所示的输出:

Input: 27
Input: 91
Input: 65

功能键的输出和其他箭头键看起来相似。 (我会注意,如果我使用getchar(),也会发生这种情况)

std :: cout仅被调用一次。那么为什么要打印三遍呢?我希望我的程序检测到按下F1的用户,然后退出。但是,如果我的程序以这种方式运行,我看不到该怎么做。

非常感谢您的帮助。如果适用的话,我的平台是Mac OSX。

1 个答案:

答案 0 :(得分:1)

您正在读取输入一个字符,一次读取一个字节;但是按一个键不一定会产生一个字符。按下光标向上键ESC [ A会生成三个字符,这是光标向上键in the ANSI/VT100 series of terminal emulators的常见映射。

使用非英语键盘映射时,甚至字母本身也会生成多个字符。例如,在西里尔字母键盘上按下西里尔字母“а”,将读取两个字符:208、176。

请注意,“ ESC”键本身读取单个ESC字符。读完ESC之后,没有任何迹象表明这是独立的“ Esc”按键,还是代表特殊键的许多可能的多字符序列中的第一个。

终端库(如 curses )通常采用从终端读取ESC后开始短暂超时的方法。如果没有其他字符到达,则它们会认为ESC被自身按下了。如果立即读取更多字符,它们将尝试查找读取的字符序列代表的特殊键。

亲自阅读终端时,由您自己完成所有这些工作。没有别的事情可以为您做。