键盘输入 - 常见错误
错误 1:按键无反应
症状
键盘输入没有任何效果,屏幕无回显。
排查步骤
- 确认中断系统正常(时钟中断是否在工作?)
- 确认IRQ1没有被PIC掩码屏蔽
- 确认处理程序注册在向量33(而非向量1)
- 使用QEMU的
-d int选项查看中断是否触发
常见原因
// 错误:注册到了向量1(CPU异常)
register_interrupt_handler(1, keyboard_handler);
// 正确:IRQ1 → 向量33(PIC重映射后32+1=33)
register_interrupt_handler(33, keyboard_handler);错误 2:每个键都显示相同字符
症状
无论按什么键,都显示同一个字符或乱码。
原因
未读取扫描码,或映射表有误。
解决方案
// 确保从正确端口读取
uint8_t scancode = inb(0x60); // 数据端口
// 确保映射表大小足够
if (scancode < sizeof(scancode_ascii)) {
char c = scancode_ascii[scancode];
}错误 3:按一次键出现两个字符
症状
按一次键显示两次字符。
原因
没有区分Make Code(按下)和Break Code(释放)。
解决方案
if (scancode & 0x80) {
// 这是释放事件,不要处理为字符
return;
}错误 4:Shift键不工作
症状
Shift键按下后字符没有变成大写。
原因
只处理了左Shift但忘了右Shift,或者在释放时没有清除标志。
解决方案
// Make Code
case 0x2A: shift_pressed = true; break; // 左Shift
case 0x36: shift_pressed = true; break; // 右Shift
// Break Code
case 0xAA: shift_pressed = false; break; // 左Shift释放
case 0xB6: shift_pressed = false; break; // 右Shift释放错误 5:缓冲区溢出
症状
快速输入后丢失字符。
原因
环形缓冲区已满但没有检查。
解决方案
bool buffer_put(char c) {
uint32_t next = (head + 1) % BUFFER_SIZE;
if (next == tail) return false; // 满了就丢弃
buffer[head] = c;
head = next;
return true;
}调试技巧
# 在QEMU中查看键盘中断是否触发
qemu-system-x86_64 -fda os-image.bin -d int 2>&1 | grep "v=21"
# v=21 是十六进制33,即IRQ1的向量号