键盘驱动开发:Shift键按下可检测但释放无法识别的问题
问题分析与解决方案
你遇到的Shift释放检测失效,主要有两个核心原因,逐个排查即可解决:
1. SC_MAX的取值过滤掉了释放扫描码
键盘的释放扫描码是按下扫描码加上0x80(比如左Shift按下是0x2A,释放就是0x2A+0x80=0xAA),这类码值普遍大于普通按键的按下扫描码。如果你的SC_MAX定义的是普通按键的最大值(比如0x39),那么代码里if (scancode > SC_MAX) return;这一行会直接跳过所有释放扫描码的处理,自然不会触发shift_hold=false的逻辑。
解决方法:把SC_MAX的取值改为0xFF,确保能覆盖所有可能的键盘扫描码(包括普通通码、释放码和扩展码)。
2. 未处理右Shift的释放扫描码
你只处理了左Shift的释放(0xAA),但右Shift的释放扫描码是0xB6(按下是0x36)。如果测试时按的是右Shift,代码根本不会捕获到释放事件。
解决方法:补充右Shift的按下和释放逻辑。
修改后的代码示例
static void keyboard_callback(registers_t *regs) { uint8_t scancode = port_byte_in(0x60); if (scancode > 0xFF) return; // 替换原SC_MAX判断,直接用0xFF覆盖所有扫描码 // 处理左Shift按下 if (scancode == 0x2A) { shift_hold = true; print_string("Pressed!"); } // 处理左Shift释放 else if (scancode == 0xAA) { shift_hold = false; print_string("Worked!"); } // 处理右Shift按下 else if (scancode == 0x36) { shift_hold = true; print_string("Pressed!"); } // 处理右Shift释放 else if (scancode == 0xB6) { shift_hold = false; print_string("Worked!"); } // 恢复原有逻辑后即可配合Shift状态实现大写字母 /* if (scancode == BACKSPACE) { if (backspace(key_buffer) == true) { print_backspace(); } } else if (scancode == ENTER) { print_string("\n"); execute_command(key_buffer); key_buffer[0] = '\0'; } else { char letter = shift_hold ? scancode_to_shift[(int)scancode] : scancode_to_char[(int)scancode]; append(key_buffer, letter); char str[2] = {letter, '\0'}; print_string(str); } */ }
补充说明:键盘还存在带E0前缀的扩展扫描码,不过基础的Shift功能用上述修改就能实现,后续如果需要处理更多特殊按键再扩展即可。
内容的提问来源于stack exchange,提问作者audiotore
相关产品推荐
相关产品推荐

