【问题标题】:C++ getchar() is there data still waiting to be readC++ getchar() 是否还有数据等待读取
【发布时间】:2013-05-22 05:02:31
【问题描述】:

我正在用 c/c++ 实现一个密钥阅读器程序。我正在使用Linux。我知道无缓冲的 getchar 函数将返回很少的键数据值。对于所有 ASCII 键(a-z、A-Z、1-9、标点符号、回车、制表符和 ESC),getchar() 将返回一个值。对于其他键,例如方向键,会有ESC键读取,但是当再次调用getchar()时,它会得到另一个值(A、B、C或D)。

A = 65

B = 66

向上箭头 = 27 91 65

F5 = 27 91 49 53 126

ESC = 27

满桌here

有什么方法可以检查是否有更多的字符要读取,或者是否只有一个字符?当一个键被读取并且它的第一个值是 ESC 我不知道它是一个以 ESC 开头的功能键还是只是 ESC 键。

#include <stdlib.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <iostream>
#include <string>
#include <termios.h>
#include <unistd.h>

using namespace std;

int main(int argc, char *argv[]) {

    int ch[5];
    int i;
    struct termios term;

    tcgetattr( STDIN_FILENO, &term );
    term.c_lflag &= ~( ICANON | ECHO );
    tcsetattr( STDIN_FILENO, TCSANOW, &term );

    ch[0] = getchar();

    // If ch[0] = 27 and there is more data in the buffer
    // printf("You pressed a function key");
    // Else
    // printf("You pressed ESC");

    return 0;   

}

【问题讨论】:

  • 你的目标是什么操作系统?
  • 尝试在 stdin 上使用 read 并将 stdin 的属性设置为非阻塞。读取直到返回大小为 0。
  • 如果您输入的键超出了 ASCII 字符集中所包含的内容(例如功能键或带有另一个键的控制键),则返回值通常是没有意义的。这些键在 ANSI C 定义之外,因此 getchar() 在处理这些键和/或键组合时的行为取决于系统。
  • @paddy 我正在使用 linux。
  • 您会考虑使用ncurses 作为您的输入吗?我很确定它会为你处理所有的 ANSI 代码。

标签: c++ c getchar


【解决方案1】:

您可以在转义时将 stdio 标记为非阻塞,然后尽可能多地阅读。 您需要包含

if (ch[0] == 27) {
    int flags = fcntl(STDIN_FILENO, F_GETFL, 0);
    fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK);
    for (;;) {
        int c = getchar();
        if (c == EOF)
            break;
        printf("%u ", c);
    }
    fcntl(STDIN_FILENO, F_SETFL, flags);
    puts("\n");
}

两个键相继出现仍然存在问题,因为循环将读取直到没有更多可用数据。

【讨论】:

  • 您有时需要致电clearerr(stdin);否则所有后续的getchar 调用都将返回 EOF...
【解决方案2】:

获得第一个 ESC 字符后,无需等待即可读取其他字符(例如通过在 termios 结构中设置 c_cc[VMIN] = 0 和 c_cc[VTIME] = 0),然后如果您找到的字符不匹配功能键模式,您将已读取的字符插入缓冲区中以进行回读。然后,在下一次获取时,您首先返回缓冲的字符(如果有)。

【讨论】:

    【解决方案3】:

    在循环中添加 getchar() 并在输入的键为 ENTER 时退出循环。 例如:

    char ch[5];
    int i=0;
    while(1)
    {
       ch[i] = getchar();
       if('\n'==ch[i])
       {
         break;
       }
       i++;
       if(i==5)
       {
         break;
       }
    
    }
    

    【讨论】:

    • 您可能需要注意是否写入超过 ch 缓冲区的末尾。
    • 如果您输入超过 5 个字符,这将导致缓冲区溢出。
    • 你可以使用 std::vector 来避免这个问题。
    • @akhil 请阅读我正在使用 unbuffered 输入的问题。您的答案对于除五序列键或 Enter 之外的任何键的无缓冲输入均无效。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多