类DOS EFI操作系统0x01-0x1F键值捕获异常及ESC/ENTER问题修复咨询
EFI按键捕获模块修复:控制键捕获+ESC/ENTER异常处理
问题原因拆解
无法捕获0x01-0x1F控制键:
这类控制键的UnicodeChar对应ASCII控制码,直接用printf("%c")输出会显示不可见字符,且原代码仅通过ScanCode判断功能键,遗漏了仅靠UnicodeChar标识的Ctrl组合键(如Ctrl+A的ScanCode为0,UnicodeChar为0x01)。ESC键触发时复制之前输入的字符:
ESC键的UnicodeChar是0x1B(而非空),若原代码逻辑误将ESC的处理放在输出之后,会输出该字符并触发终端异常回显;另外未对功能键的输出做过滤,导致终端行为混乱。ENTER键触发时光标回到行首:
ENTER键的UnicodeChar是0x0D(回车符),仅输出这个字符只会让光标回到行首,不会换行;且原代码未在终止前跳过该字符的输出。
修复方案及代码
调整逻辑顺序,区分功能键、控制键和普通字符的处理:
#include "uefi/uefi.h" // 若uefi.h未定义扫描码,手动添加常用键定义 #define SCAN_ESC 0x01 #define SCAN_RETURN 0x1C int main(int argc, char **argv) { efi_input_key_t ch; char command[1024] = ""; int len = 0; while (1) { // 等待按键事件 ST->BootServices->WaitForEvent(1, &(ST->ConIn->WaitForKey), NULL); ST->ConIn->ReadKeyStroke(ST->ConIn, &ch); // 先处理终止键,避免误输出 if (ch.ScanCode == SCAN_ESC) { break; } if (ch.ScanCode == SCAN_RETURN) { // 输出完整换行,解决光标回行首问题 printf("\r\n"); // 若要把ENTER设为终止键,取消下面的注释 // break; // 否则将换行符存入缓冲区(可选) if (len < sizeof(command) - 1) { command[len++] = '\n'; command[len] = '\0'; } continue; } // 处理0x01-0x1F的控制键,转为^A、^B等可见形式 if (ch.UnicodeChar >= 0x01 && ch.UnicodeChar <= 0x1F) { printf("^%c", ch.UnicodeChar + '@'); // 可选:将控制键的可见形式存入缓冲区 if (len < sizeof(command) - 2) { command[len++] = '^'; command[len++] = ch.UnicodeChar + '@'; command[len] = '\0'; } continue; } // 仅处理可打印的ASCII字符(0x20-0x7E) if (ch.UnicodeChar >= 0x20 && ch.UnicodeChar <= 0x7E) { printf("%c", ch.UnicodeChar); if (len < sizeof(command) - 1) { command[len++] = ch.UnicodeChar; command[len] = '\0'; } } } return 0; }
关键修改点
- 终止键优先判断:把ESC/ENTER的判断放在最前面,彻底避免功能键的Unicode字符被误输出
- 控制键可视化:将0x01-0x1F的控制键转为
^A这类可见标识,既解决捕获问题,又方便调试 - ENTER键正确换行:输出
\r\n实现DOS风格的换行,避免光标停在行首 - 过滤无效字符:仅处理可打印字符,防止乱码或终端异常行为
内容的提问来源于stack exchange,提问作者user14683910
相关产品推荐
相关产品推荐

