Linux下getchar()可读取的键盘字符有哪些?如何分类?
getchar()读取按键的详细说明 刚好碰到过类似的场景,我来给你拆解下getchar()的按键读取逻辑,以及如何处理你遇到的Shift/Ctrl这类按键的问题。
一、getchar()到底能读取哪些按键?
本质上,getchar()是从标准输入流(stdin)读取单个字节,它能捕获的按键完全取决于终端的输入模式(默认是「规范模式」,也就是行缓冲,必须按回车才会把输入提交给程序)。具体能读取的按键大概分为这几类:
1. 所有可打印字符
- 数字(0-9)、大小写字母(a-z/A-Z)、各类标点符号(!@#$%^&*()等)、空格、Tab键(对应ASCII码9)都能被读取,按下这些键后,终端会把对应的字节送入输入流,等你按回车,
getchar()就能拿到这个字节。
2. 部分不可打印的控制字符
- Enter键:按下后终端会发送换行符(ASCII码10)或回车符(ASCII码13,取决于系统),这是
getchar()最常捕获的控制键之一 - ESC键:按下ESC后,终端会直接发送ASCII码27这个字节,按回车后
getchar()就能读到它 - DEL键(ASCII码127):也能被直接读取
- 退格键(Backspace,ASCII码8):默认规范模式下,它只会删除输入框里的前一个字符,不会被
getchar()直接捕获——除非你修改终端的输入模式
3. 完全读不到的按键:修饰键
就是你遇到的Shift、Ctrl(单独按)、Alt(单独按)、Caps Lock、Fn这类键,它们本身不会产生独立的ASCII字节,只是用来修改其他按键的输入:比如Shift+a会输出大写A,Ctrl+c会直接给程序发中断信号(SIGINT)而不是字符。所以单独按这些键时,终端根本不会向stdin发送任何数据,getchar()自然啥也读不到。
二、按键的分类方式
按照getchar()的捕获能力和终端的处理逻辑,我们可以把按键分成三类:
- 独立产生ASCII字节的按键:包括所有可打印字符,以及ESC、Enter、DEL这类有明确ASCII码的控制键,
getchar()能直接读取它们的字节值 - 无独立字节的修饰键:Shift、Ctrl、Alt、Caps Lock等,这类键不单独产生输入,要么和其他键组合改变输出字符,要么触发终端的信号
- 组合键/特殊功能键:比如Ctrl+a、F1-F12、Shift+ESC这类,它们会产生多字节的ANSI控制序列(比如
ESC[11~代表F1键),默认规范模式下getchar()只能读到序列的第一个字节(ESC),要完整读取需要切换到非规范模式
三、如何让程序响应Shift/Ctrl这类修饰键?
如果想让程序捕获单独的修饰键,核心是修改终端的输入模式,从默认的「规范模式(行缓冲)」切换到「非规范模式(无缓冲)」,同时禁用终端的自动信号处理。这里给你一个用C++结合termios库实现的简单示例:
#include <iostream> #include <termios.h> #include <unistd.h> int main() { // 先保存原终端设置,避免程序退出后终端异常 struct termios old_settings, new_settings; tcgetattr(STDIN_FILENO, &old_settings); new_settings = old_settings; // 关闭规范模式、回显、信号触发(比如Ctrl+c不会直接中断程序) new_settings.c_lflag &= ~(ICANON | ECHO | ISIG); new_settings.c_cc[VMIN] = 1; // 至少读取1个字节再返回 new_settings.c_cc[VTIME] = 0; // 无超时等待 // 立即应用新设置 tcsetattr(STDIN_FILENO, TCSANOW, &new_settings); std::cout << "Press any key (including Shift/Ctrl) to exit...\n"; char input_byte; // 用read()直接读终端输入,比getchar()更适合非规范模式 read(STDIN_FILENO, &input_byte, 1); // 程序退出前恢复原终端设置 tcsetattr(STDIN_FILENO, TCSANOW, &old_settings); return 0; }
需要注意的是,单独按Shift/Ctrl时,终端会发送多字节的控制序列(比如Shift可能发送ESC[...这样的序列),上面的示例只是读取了第一个字节,如果要精确判断是哪个修饰键,你需要解析完整的控制序列。如果想更省心地处理所有按键(包括功能键、组合键),推荐用ncurses这类专门的终端处理库,它已经封装好了所有复杂的终端控制逻辑。
内容的提问来源于stack exchange,提问作者Marthe Veldhuis

