Linux kernel Hacker, 從零構(gòu)建自己的內(nèi)核
上一節(jié),我們實現(xiàn)了按鍵轉(zhuǎn)換成字符的功能,這一節(jié)坤塞,我們更近一步预皇,在message box中實現(xiàn)一個輸入文本框,按鍵時诉植,字符顯示在文本框內(nèi),并且輸入光標(biāo)在文本框中不斷閃動。
在內(nèi)核的C語言部分张弛,也就是write_vga_desktop.c中做如下改動:
void make_textbox8(struct SHEET *sht, int x0, int y0, int sx, int sy, int c) {
int x1 = x0 + sx, y1 = y0 + sy;
boxfill8(sht->buf, sht->bxsize, COL8_848484, x0 - 2, y0 - 3, x1 + 1, y0 - 3);
boxfill8(sht->buf, sht->bxsize, COL8_848484, x0 - 3, y0 - 3, x0 - 3, y1 + 1);
boxfill8(sht->buf, sht->bxsize, COL8_FFFFFF, x0 - 3, y1 + 2, x1 + 1, y1 + 2);
boxfill8(sht->buf, sht->bxsize, COL8_FFFFFF, x1 + 2, y0 - 3, x1 + 2, y1 + 2);
boxfill8(sht->buf, sht->bxsize, COL8_000000, x0 - 1, y0 - 2, x1 + 0, y0 - 2);
boxfill8(sht->buf, sht->bxsize, COL8_000000, x0 - 2, y0 - 2, x0 - 2, y1 + 0);
boxfill8(sht->buf, sht->bxsize, COL8_C6C6C6, x0 - 2, y1 + 1, x1 + 0, y1 + 1);
boxfill8(sht->buf, sht->bxsize, COL8_C6C6C6, x1 + 1, y0 - 2, x1 + 1, y1 + 1);
boxfill8(sht->buf, sht->bxsize, c, x0 - 1, y0 - 1, x1 + 0, y1 + 0);
}
我們增加了一個函數(shù)叫make_textbox8, 它的作用是繪制一個有邊框的白色方塊,這個方塊其實就模擬了輸入文本框酪劫。然后我們對繪制message box的實現(xiàn)方法做一些修改吞鸭,以便文本框能輸入到message box的主窗體里:
struct SHEET* message_box(struct SHTCTL *shtctl, char *title) {
struct SHEET *sht_win;
unsigned char *buf_win;
sht_win = sheet_alloc(shtctl);
buf_win = (unsigned char *)memman_alloc_4k(memman, 160 * 68);
sheet_setbuf(sht_win, buf_win, 160, 68, -1);
make_window8(shtctl, sht_win, title);
make_textbox8(sht_win, 8, 28, 144, 16, COL8_FFFFFF);
sheet_slide(shtctl, sht_win, 80, 72);
sheet_updown(shtctl, sht_win, 2);
return sht_win;
}
上面的窗體繪制函數(shù)中,在繪制好message box的主窗體后覆糟,里面把白色文本框畫到主窗體的中央刻剥。有了文本框后,我們可以接著實現(xiàn)字符輸入功能滩字。
void CMain(void) {
....
int cursor_x = 8, cursor_c=COL8_FFFFFF
....
for(;;) {
....
else if (keytable[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 buf[2] = {keytable[data], 0};
showString(shtctl, shtMsgBox, cursor_x, 28, COL8_000000, buf);
cursor_x += 8;
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);
}
}
....
else if (fifo8_status(&timerinfo) != 0) {
io_sti();
int i = fifo8_get(&timerinfo);
if (i == 10) {
showString(shtctl, sht_back, 0, 0, COL8_FFFFFF, " new 5[sec]");
} else if (i == 2) {
showString(shtctl, sht_back, 0, 16, COL8_FFFFFF, "3[sec]");
} else {
if (i != 0) {
timer_init(timer3, &timerinfo, 0);
cursor_c = COL8_000000;
} else {
timer_init(timer3, &timerinfo, 1);
cursor_c = COL8_FFFFFF;
}
timer_settime(timer3, 50);
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);
}
}
......
}
....
}
一旦有鍵盤事件時造虏,內(nèi)核先把掃描碼轉(zhuǎn)換成對應(yīng)的字符,然后繪制到message box窗體的文本框中麦箍,cursor_x是字符輸入的位置漓藕,沒輸入一個字符,它的值增加8挟裂,因為一個字符的像素寬度是8.為何在輸入字符前享钞,需要調(diào)用boxfill8,和sheet_refresh這兩個函數(shù)呢诀蓉,這是因為光標(biāo)閃爍時栗竖,會由黑色變成白色,如果光標(biāo)變成黑色時渠啤,我們正好按下鍵盤的話狐肢,那么字符顯示時的背景將是黑色的,但是我們的字體本身就是黑色的埃篓,所以一旦這種情況發(fā)生的時处坪,如果不調(diào)用這兩個函數(shù)先把字體要顯示的位置刷成白色的話,字體就顯示不出來,而顯示的是一個黑色小方塊同窘,具體情形玄帕,大家參考視頻講解會更明白。
在主循環(huán)中想邦,當(dāng)timer3 超時時裤纹,我們可以變換光標(biāo)的顏色,如果原來是白色丧没,那么把它轉(zhuǎn)換成黑色鹰椒,如果原來是黑色,則轉(zhuǎn)換成白色呕童,需要注意的是漆际,此時光標(biāo)顯示的位置是在message box的文本框內(nèi)。
上面代碼編譯運行后夺饲,效果如下:
鼠標(biāo)移動窗體
接下來奸汇,我們看看如何實現(xiàn)鼠標(biāo)移動message box的效果,這個實現(xiàn)很簡單往声,在內(nèi)核的C語言部分做如下改動:
void show_mouse_info(struct SHTCTL *shtctl, struct SHEET *sht_back,struct SHEET *sht_mouse) {
char*vram = buf_back;
unsigned char data = 0;
io_sti();
data = fifo8_get(&mouseinfo);
if (mouse_decode(&mdec, data) != 0) {
computeMousePosition(shtctl, sht_back, &mdec);
sheet_slide(shtctl, sht_mouse, mx, my);
if ((mdec.btn & 0x01) != 0) {
sheet_slide(shtctl, shtMsgBox, mx - 80, my - 8);
}
}
}
在鼠標(biāo)事件發(fā)生后擂找,硬件會給端口發(fā)送鼠標(biāo)相關(guān)數(shù)據(jù),內(nèi)核拿到數(shù)據(jù)后會進行解析浩销,如果結(jié)構(gòu)體mdec.btn的第0位設(shè)置成1的話贯涎,就表明,此時鼠標(biāo)的左鍵按下了慢洋,這樣塘雳,當(dāng)我們繪制鼠標(biāo)時,把message box 窗體同步移動到鼠標(biāo)的相應(yīng)位置且警,這樣就能實現(xiàn)窗體隨鼠標(biāo)移動了粉捻,當(dāng)然礁遣,當(dāng)前做法存在一個問題是斑芜,我們沒有判斷鼠標(biāo)左鍵按下時,鼠標(biāo)是否在message box的窗體范圍內(nèi)祟霍,這個功能往后我們再添加上杏头,上面的代碼編譯后運行效果如下:
窗體被從左上角移動到了右下角,具體效果沸呐,參看視頻會更加明顯醇王。