更詳細(xì)的講解和代碼調(diào)試演示過程蒲凶,請參看視頻
Linux kernel Hacker, 從零構(gòu)建自己的內(nèi)核
前幾節(jié),我們花費不少精力在鍵盤響應(yīng)的處理之上帝雇,到目前為止绪爸,我們的內(nèi)核能夠準(zhǔn)確的將按鍵字符合理的顯示在指定窗口上。但目前還有一些遺憾厕宗,就是當(dāng)前內(nèi)核對shift 鍵的按下不做反應(yīng)画舌。按理堕担,當(dāng)shift鍵按下后,再按數(shù)字鍵1曲聂,那么顯示的字符應(yīng)該是"!"而不是“1”霹购,本節(jié)我們要處理的就是響應(yīng)shift鍵的點擊處理,完成本節(jié)后朋腋,內(nèi)核效果如下:
我們可以看到厕鹃,當(dāng)按下shift鍵后,再點擊數(shù)字鍵1乍丈,2,3,顯示的不再是數(shù)字字符把将,而是對應(yīng)的特殊字符.我們看看對應(yīng)代碼的實現(xiàn)轻专,首先需要修改的是write_vga_desktop.c:
static char keytable1[0x80] = {
0, 0, '!', '@', '#', '$', '%','^', '&', '*', '(', ')', '-', '=', '~', 0, 0,
'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '`', '{', 0, 0, 'A', 'S',
'D', 'F', 'G', 'H', 'J', 'K', 'L', '+', '*', 0, 0, '}', 'Z', 'X', 'C', 'V',
'B', 'N', 'M', '<', '>', '?', 0, '*', 0, ' ', 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, '7', '8', '9', '-', '4', '5', '6', '+', '1',
'2', '3', '0', '.', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, '_', 0, 0, 0, 0, 0, 0, 0, 0, 0, '|', 0, 0
};
int key_shift = 0;
首先我們增加了一個輸入表keytable1,已經(jīng)一個變量key_shift, 當(dāng)shift鍵被按下時這個變量的值變?yōu)榉?,當(dāng)shift鍵松開后察蹲,該變量的值恢復(fù)為0.對應(yīng)的當(dāng)shift鍵按下時请垛,顯示鍵盤字符時使用keytable1表,如果shift鍵沒有被按下洽议,那么使用keytable表宗收。
char transferScanCode(int data) {
if (data == 0x2a) {//left shift key down
key_shift |= 1;
}
if (data == 0x36) {
//right shift key down
key_shift |= 2;
}
if (data == 0xaa) {
//left shift key up
key_shift &= ~1;
}
if (data == 0xb6) {
//right shift key up
key_shift &= ~2;
}
if (data == 0x2a || data == 0x36 || data == 0xaa || data == 0xb6 ||
data >= 0x54) {
return 0;
}
char c = 0;
if (key_shift == 0 && data<0x54 && keytable[data] != 0) {
c = keytable[data];
}
else if (key_shift != 0 && data < 0x80 && keytable1[data] != 0){
c = keytable1[data];
}
else {
c = 0;
}
return c;
}
上面的函數(shù)用于處理按鍵產(chǎn)生的掃描碼和斷碼,當(dāng)左邊的shift鍵按下時亚兄,鍵盤發(fā)出的掃描碼是0x2a, 右邊的shift鍵按下時混稽,鍵盤的掃描碼是0x36,當(dāng)左邊的shift按鍵松開時,鍵盤發(fā)送的斷碼是0xaa,右邊的shift鍵放開后审胚,鍵盤發(fā)送的斷碼是0xb6. 一旦左邊的shift鍵按下時匈勋,key_shift的值設(shè)置為1,右邊shift鍵按下時膳叨,key_shift的值為2洽洁。當(dāng)shift按鍵松開后,key_shift的值變?yōu)?.
從代碼中也可以看到菲嘴,如果key_shift的值不等于0饿自,也就是shift鍵被按下,那么我們到keytable1里面去查找按鍵對應(yīng)的字符龄坪,如果key_shift值是0昭雌,也就是shift鍵沒有被按下,那么我們到 keytable表中去查找按鍵對應(yīng)的字符悉默。我們再看看字符是如何顯示出來的:
void CMain(void) {
....
for(;;) {
....
else if (key_to == 0) {
if (transferScanCode(data) != 0 && cursor_x < 144) {
boxfill8(shtMsgBox->buf, shtMsgBox->bxsize, COL8_FFFFFF,cursor_x,
28, cursor_x + 7, 43);
sheet_refresh(shtctl, shtMsgBox, cursor_x, 28, cursor_x+8, 44);
char c = transferScanCode(data);
char buf[2] = {c, 0};
showString(shtctl, shtMsgBox, cursor_x, 28, COL8_000000, buf);
cursor_x += 8;
stop_task_A = 1;
boxfill8(shtMsgBox->buf, shtMsgBox->bxsize, cursor_c, cursor_x,
28, cursor_x + 7, 43);
sheet_refresh(shtctl, shtMsgBox, cursor_x, 28, cursor_x+8, 44);
}
}
....
}
void console_task(struct SHEET *sheet) {
....
for(;;) {
....
else {
if (cursor_x < 240 && transferScanCode(i) != 0) {
boxfill8(sheet->buf, sheet->bxsize, COL8_000000, cursor_x,
28, cursor_x + 7, 43);
sheet_refresh(shtctl, sheet, cursor_x, 28, cursor_x+8, 44);
s[0] = transferScanCode(i);
s[1] = 0;
showString(shtctl, sheet, cursor_x, 28, COL8_FFFFFF, s);
cursor_x += 8;
}
....
}
}
從上面的代碼我們可以看到城豁,無論是控制臺窗口還是文本框窗口,在顯示字符前抄课,都先調(diào)用transferScanCode函數(shù)去將鍵盤發(fā)過來的數(shù)值進行轉(zhuǎn)換唱星,如果轉(zhuǎn)換的結(jié)果不是0雳旅,那么將得到的字符顯示到窗口中。完成上面代碼后间聊,即可得本文開頭所描述的運行結(jié)果攒盈。
更詳細(xì)的代碼講解和調(diào)試,請參看視頻哎榴。
更多技術(shù)信息型豁,包括操作系統(tǒng),編譯器尚蝌,面試算法迎变,機器學(xué)習(xí),人工智能飘言,請關(guān)照我的公眾號: