类 Unix 环境下无需等待回车即可获取来自键盘输入

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

◆ 目的

在类 Unix 操作系统(如 Linux、macOS)中,如何能实现无需等待回车即可获取来自键盘输入?

◆ 解法

通过 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)。

◆ 验证

在命令行中编译代码(-std=c++11),运行可执行文件并检查输出结果(要输入 ASCII 中的控制字符,可参考 命令行中输入 ASCII 字符 )。以下是输出结果的部分内容,

$ ./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 和 凡人只做一事 两位作者。

posted @ 2021-12-16 11:31  green-cnblogs  阅读(138)  评论(0编辑  收藏  举报