键盘输入 - 练习题
练习 1:扩展扫描码表
当前映射表只覆盖了主键盘区域。添加以下按键支持:
- F1-F12 功能键(扫描码 0x3B-0x46, 0x57-0x58)
- 方向键(扫描码 0x48上, 0x50下, 0x4B左, 0x4D右)
提示:功能键和方向键不产生ASCII字符,可以用特殊编码表示。
练习 2:实现简单命令行
在回显基础上实现行编辑功能:
#define LINE_BUFFER_SIZE 128
static char line[LINE_BUFFER_SIZE];
static uint32_t line_pos = 0;
void process_input(void) {
char c = keyboard_getchar();
if (c == '\n') {
line[line_pos] = '\0';
process_command(line); // 处理命令
line_pos = 0;
} else if (c == '\b' && line_pos > 0) {
line_pos--;
} else if (line_pos < LINE_BUFFER_SIZE - 1) {
line[line_pos++] = c;
}
}实现一个能识别 “help”、“clear”、“version” 命令的简单shell。
练习 3:LED控制
PS/2键盘有3个LED灯(Num Lock、Caps Lock、Scroll Lock)。 通过端口0x60发送命令控制它们:
void keyboard_set_leds(bool scroll, bool num, bool caps) {
uint8_t leds = (scroll) | (num << 1) | (caps << 2);
// 等待键盘准备好
while (inb(0x64) & 0x02);
outb(0x60, 0xED); // LED控制命令
while (inb(0x64) & 0x02);
outb(0x60, leds); // LED状态
}实现并测试:按Caps Lock时切换Caps Lock LED。
练习 4:按键速率控制
实现按键重复(长按时持续产生输入)的速率控制:
提示:使用定时器中断(IRQ0)配合键盘状态,当检测到持续按下同一个键时,按固定间隔重复产生字符。
思考题
- 为什么QEMU中的键盘使用的是PS/2协议而非USB?
- 如果两个键同时按下(非修饰键),键盘控制器会如何处理?
- 环形缓冲区在中断上下文中使用是否需要加锁?为什么?