自定义C语言内核Shift键大小写切换失效问题求助
自定义内核键盘Shift键切换大小写失效问题
我用C语言开发自定义内核,键盘输入基本正常,但Shift键存在问题:第一次按左/右Shift键可以输入大写字母,但再次按下Shift键无法切换回小写,始终输出大写。
现有键盘处理主函数代码
void keyboard_handler_main(void){ unsigned char status; char keycode; /* write EOI */ write_port(0x20, 0x20); status = read_port(KEYBOARD_STATUS_PORT); /* lowest bit of status will be set if buffer is not empty */ if(status & 0x1){ keycode = read_port(KEYBOARD_DATA_PORT); if(keycode < 0) return; if(keycode == ENTRY_KEY_CODE){ kprint_newline(); return; } // change the state when the shift is pressed if (keycode == 0x2A || keycode == 0x36) { // Left or Right Shift pressed if(shift_pressed) shift_pressed = 0; else shift_pressed = 1; vidptr[current_loc++] = '1'; // Debugging output (you can remove this later) vidptr[current_loc++] = 0x07; // Light grey on black background return; } }
全局变量char shift_pressed初始值为0,负责控制大小写切换状态。
尝试过的修改(未解决问题)
if(keycode == 0x2A || keycode == 0x36 ){ shift_pressed = !(keycode & 0x80); vidptr[current_loc++] ='1'; /* the character's ASCII */ vidptr[current_loc++] = 0x07; /* attribute byte : light grey black screen */ return; }
问题原因与解决方案
核心问题
你没处理键盘的断码(Break Code)。键盘的工作逻辑是:
- 按下按键时发送通码(Make Code):比如左Shift按下发
0x2A,右Shift按下发0x36; - 松开按键时发送断码(Break Code):通码加上
0x80,比如左Shift松开发0xAA,右Shift松开发0xB6。
你当前的代码只处理了Shift的通码,每次按Shift都会把shift_pressed设为1,但松开Shift时没有处理断码,状态永远不会变回0,导致一直输出大写。另外char keycode是有符号类型,断码(大于0x80)会被当成负数,被if(keycode <0) return;过滤掉,根本没机会处理。
修改方案
- 把
char keycode改成unsigned char keycode,避免符号错误导致断码被过滤; - 移除
if(keycode <0) return;这行,保留断码的处理机会; - 同时处理Shift的通码和断码,根据按键的按下/松开状态切换
shift_pressed。
修改后的代码示例
void keyboard_handler_main(void){ unsigned char status; unsigned char keycode; // 改为无符号char,避免断码被误判为负数 /* write EOI */ write_port(0x20, 0x20); status = read_port(KEYBOARD_STATUS_PORT); if(status & 0x1){ keycode = read_port(KEYBOARD_DATA_PORT); // 移除这行,断码不会再被过滤 // if(keycode < 0) // return; if(keycode == ENTRY_KEY_CODE){ kprint_newline(); return; } // 分离通码和断码 unsigned char make_code = keycode & 0x7F; // 取低7位得到原始通码 int is_key_released = (keycode & 0x80) != 0; // 判断是否是松开按键的断码 // 匹配Shift键的通码 if (make_code == 0x2A || make_code == 0x36) { shift_pressed = !is_key_released; // 按下设为1,松开设为0 // 调试输出可以改为显示当前状态,方便排查 vidptr[current_loc++] = shift_pressed ? '1' : '0'; vidptr[current_loc++] = 0x07; return; } // 后续处理普通字符逻辑,根据shift_pressed决定输出大小写 // ... } }
为什么之前的修改无效
你尝试的shift_pressed = !(keycode & 0x80)逻辑本身没问题,但你只判断了keycode == 0x2A || 0x36——这两个都是通码,keycode & 0x80结果为0,!(0)就是1,所以每次执行这行都会把shift_pressed设为1,永远不会触发断码的判断逻辑,自然没法切回小写。
内容的提问来源于stack exchange,提问作者rayen
相关产品推荐
相关产品推荐

