QEMU平台UART驱动按下退格键收到delete字节而非backspace问题
问题原因
- 终端默认字符映射:Unix-like系统的终端默认将backspace键映射为ASCII 127(DEL字符),而非ASCII 8(BS字符),你通过
-serial mon:stdio将宿主机的标准输入绑定到QEMU的UART串口,所以按下backspace时UART收到的是127。 - 输入设备冲突:你在启动参数中额外添加了
-device virtio-keyboard-device参数,该参数会额外注册一个virtio标准键盘设备,物理键盘的delete键输入会被路由到这个virtio键盘设备的输入队列,而非UART的输入缓冲区,你当前只读取UART的输入,自然无法捕获delete键的输入。
修复方案
1. 适配backspace的输入映射
两种方案可选,推荐第二种无需修改外部环境:
方案一:启动QEMU前在当前终端执行如下命令,将终端的erase字符改为BS:
stty erase ^H
方案二:直接修改驱动的按键处理逻辑,将收到的127映射为退格操作,代码示例:
while (1) { char c = read_char(); if (c == 127 || c == 8) { // 同时兼容两种退格输入 // 退格处理逻辑,比如删除光标前字符 puts("HERE: backspace\n"); } else if (c == 10 || c == 13) { putchar('\n'); } else { putchar(c); } }
2. 解决delete键无响应问题
两种方案可选,根据需求选择:
方案一:如果不需要独立的virtio键盘设备,直接删除启动参数中的-device virtio-keyboard-device,所有按键输入都会走UART流。此时delete键默认会发送\x1b[3~的三字节转义序列,新增转义序列解析逻辑即可识别delete操作,示例代码:
// 新增转义序列状态变量 static int esc_state = 0; while (1) { char c = read_char(); if (esc_state == 0 && c == 0x1b) { // 收到ESC开头 esc_state = 1; continue; } else if (esc_state == 1 && c == '[') { esc_state = 2; continue; } else if (esc_state == 2 && c == '3') { esc_state = 3; continue; } else if (esc_state == 3 && c == '~') { esc_state = 0; puts("HERE: delete\n"); continue; } else { esc_state = 0; // 不匹配的转义序列重置状态 } // 原有按键处理逻辑 if (c == 127 || c == 8) { puts("HERE: backspace\n"); } else if (c == 10 || c == 13) { putchar('\n'); } else { putchar(c); } }
方案二:如果需要使用virtio键盘设备,补充实现virtio键盘的驱动,读取设备的输入事件队列,解析键盘扫描码后映射为对应的输入字符,再接入现有按键处理逻辑即可。
内容的提问来源于stack exchange,提问作者abumandour
相关产品推荐
相关产品推荐

