本文描述了在类 Unix 操作系统中,无需等待回车即可获取来自键盘输入的办法,并加以了验证。

◆ 问题

在类 Unix 操作系统中,C++ 程序使用 stdio 或 iostream 程序库接收键盘输入时,需等待回车键按下后才能接收到输入内容。如何能在无需等待回车即可获取来自键盘的输入?

◆ 解法

通过 termios 程序库中与终端关联的 termios 结构和 tcgetattr、tcsetattr 函数,改变终端编辑模式为非规范输入且不回显,即可实现“无需等待回车即可获取来自键盘的输入”的功能。

◆ 示例

以下代码片段展示了此实现方案,(how_to_get_input_without_enter.cpp)

#include <stdio.h>
#include <termios.h>          // #1


int hit_key() {
    termios oldattr;
    tcgetattr(0, &oldattr);      // #2

    termios newattr = oldattr;      // #3
    newattr.c_lflag &= ~(ICANON | ECHO);      // #4
    tcsetattr(0, TCSANOW, &newattr);

    int code = getchar();

    tcsetattr(0, TCSANOW, &oldattr);     // #5

    return code;
}

首先需要包含 termios.h 程序库(#1),该文件定义了与终端关联的 termios 结构和 tcgetattr、tcsetattr 函数。使用 tcgetattr 函数获取当前终端的属性,并保存在 termios 结构的变量中(#2)。为了能将终端属性恢复成原有值,先用原有终端属性复制出一份临时属性(#3)。改变终端编辑模式的关键,在于 termios.c_lflag 字段。将临时属性的 c_lflag 字段改变为非规范输入且不回显(#4),并设置终端属性为新值。应用结束后,将终端属性恢复成原有值(#5)。

◆ 验证

编译代码成功后运行可执行文件(要输入 ASCII 中的控制字符,可参考 命令行中输入 ASCII 字符 )。

以下是运行过程中的部分输出,

macos:15691156 green$ ./a.out 

Please hit a key (Ctrl-C to quit).

......

Your input is A, its ASCII code is 65.

Your input is [, its ASCII code is 91.

Your input is B, its ASCII code is 66.

Your input is 5, its ASCII code is 53.

Your input is ~, its ASCII code is 126.

......

◆ 最后

完整示例代码请参考 [gitee] cnblogs/15691156

写作过程中,笔者参考了 Linux下C++/C终端获取键盘事件/termios结构详细解释LINUX 使用tcgetattr与tcsetattr函数控制终端。致 Liuqz2009 和 凡人只做一事 两位作者。