首页 > 解决方案 > 为什么按功能键或箭头键时 getch 返回三个值?

问题描述

我有一个函数 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;
}

它可以按您的预期工作。您输入一个密钥,它会打印回给您。如果按删除,程序退出。然而,奇怪的是,如果你按下向上箭头,你会得到如下所示的输出:

Input: 27
Input: 91
Input: 65

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

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

任何帮助深表感谢。如果合适的话,我的平台是 Mac OSX。

标签: c++input

解决方案


您正在读取输入一个字符,一次一个字节;但是,按单个键可能不一定会生成一个字符。向上光标键在按下时会生成三个字符,这是ANSI/VT100 系列终端仿真器中ESC [ A向上光标键的常见映射。

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

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

终端库,如curses通常采用在从终端读取 ESC 后开始短暂超时的方法。如果没有其他字符到达,他们假定 ESC 是自己按下的。如果立即读取更多字符,它们将尝试查找读取的字符序列表示的特殊键。

自己阅读终端时,由您来完成所有这些工作。没有其他东西可以为您完成这项工作。


推荐阅读