【问题标题】:getchar() avoid escape sequencesgetchar() 避免转义序列
【发布时间】:2019-08-08 12:29:03
【问题描述】:

我正在编写 Linux 控制台应用程序(某种菜单),因此我需要从用户那里获得输入。这是我目前使用的代码:

int getch(void)
{
    int ch;
    struct termios oldt;
    struct termios newt;
    tcgetattr(STDIN_FILENO, &oldt);
    newt = oldt;
    newt.c_lflag &= static_cast<unsigned int>(~(ICANON | ECHO));
    tcsetattr(STDIN_FILENO, TCSANOW, &newt);
    ch = getchar();
    tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
    return ch;
}

#define KEY_UP 65
#define KEY_DOWN 66
#define KEY_ESC 27

while(true)
{
    ch = getch();

    switch(ch)
    {
        case KEY_UP:           
            break;
        case KEY_DOWN:
            break;
        case ESC:
            break;
    }
}

在我需要使用 ESC 之前一切都很好。突然发现 getch() 有时会在循环中返回几个整数。例如:

KEY_UP:   27 91 65
KEY_DOWN: 27 91 66
BKSPACE:  127
ESC:      27

好的,在我的情况下,在循环中进行 3 次迭代后,我将获得正确的值(例如 65 表示 KEY_UP),但是当我真正单击 Esc 按钮时,如何获得 ESC? 如何配置 getch() 以仅返回实际值并避免 esc 序列?

Ubuntu 18.04 gcc 7.4.0 libstdc++.so.6

【问题讨论】:

  • 65 是 not 'KEY_UP 的正确值'。它与字母 'A' 相同(ASCII 0x41 = 65 十进制)
  • 键盘可以包含比 7 位整数中的数字更多的键(这是很久以前的“标准”)。因此有些键需要使用多个数字来区分自己。不然怎么办?向上键的65 与字母'A' 的数字65 不同(假设为ASCII)?
  • 没错!我知道 65 不是正确的键。我只是将它与 getch() 输出兼容。但是如何区分 Up 键(从 27 开始)和真正的 Esc 键(也从 27 开始)?
  • 没有区别。了解转义的唯一方法是转义后是否有有效的转义序列。

标签: c++ console-application getchar


【解决方案1】:

你可以获得真正的 ESC 键来实现 kbhit 函数,基本上 kbhit 返回 true 如果缓冲区中有更多待读取的数据,这里 kbget 是一个包装器,返回你的 @987654324 的结果@ 或KEY_ESCAPE (27):

static int kbhit(void)
{
    int c = 0;

    tcgetattr(0, &oterm);
    memcpy(&term, &oterm, sizeof(term));
    term.c_lflag &= ~(ICANON | ECHO);
    term.c_cc[VMIN] = 0;
    term.c_cc[VTIME] = 1;
    tcsetattr(0, TCSANOW, &term);
    c = getchar();
    tcsetattr(0, TCSANOW, &oterm);
    if (c != -1) ungetc(c, stdin);
    return ((c != -1) ? 1 : 0);
}

static int kbesc(void)
{
    int c;

    if (!kbhit()) return KEY_ESCAPE;
    c = getch();
    if (c == '[') {
        switch (getch()) {
            case 'A':
                c = KEY_UP;
                break;
            case 'B':
                c = KEY_DOWN;
                break;
            case 'C':
                c = KEY_LEFT;
                break;
            case 'D':
                c = KEY_RIGHT;
                break;
            default:
                c = 0;
                break;
        }
    } else {
        c = 0;
    }
    if (c == 0) while (kbhit()) getch();
    return c;
}

static int kbget(void)
{
    int c;

    c = getch();
    return (c == KEY_ESCAPE) ? kbesc() : c;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-05-08
    • 2011-07-11
    • 2014-05-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多