处理器:Intel Celeron® Dual-Core CPU 2.10GHz
操作系统:Windows7 专业版 x86
阅读书籍:《30天自制操作系统》—川合秀实[2015.04.22]
工具:../toolset/
单独创建一个新任务,在新任务中制作命令行窗口。修改HariMain。
void HariMain(void) { …… //sht_console sht_cons = sheet_alloc(shtctl); //获取图层 buf_cons = (unsigned char *) memman_alloc_4k(memman, 256 * 165); sheet_setbuf(sht_cons, buf_cons, 256, 165, -1); //图层与缓冲区,背景色的设置 make_window8(buf_cons, 256, 165, "console", 0); //制作命令行窗口图标 make_textbox8(sht_cons, 8, 28, 240, 128, COL8_000000);//窗口文字输入的背景色 task_cons = task_alloc(); //获取任务 task_cons->tss.esp = memman_alloc_4k(memman, 64 * 1024) + 64 * 1024 - 8; task_cons->tss.eip = (int) &console_task; //任务对应console_task程序 task_cons->tss.es = 1 * 8; task_cons->tss.cs = 2 * 8; task_cons->tss.ss = 1 * 8; task_cons->tss.ds = 1 * 8; task_cons->tss.fs = 1 * 8; task_cons->tss.gs = 1 * 8; *((int *) (task_cons->tss.esp + 4)) = (int) sht_cons; task_run(task_cons, 2, 2); //命令行窗口LEVEL为2,优先级为2(切换时间) …… //设置各图层画面显示的先后顺序(图层高度) sheet_slide(sht_back, 0, 0); sheet_slide(sht_cons, 32, 4); sheet_slide(sht_win, 64, 56); sheet_slide(sht_mouse, mx, my); sheet_updown(sht_back, 0); sheet_updown(sht_cons, 1); sheet_updown(sht_win, 2); sheet_updown(sht_mouse, 3); …… } //命令窗口的任务 void console_task(struct SHEET *sheet) { struct FIFO32 fifo; struct TIMER *timer; struct TASK *task = task_now(); int i, fifobuf[128], cursor_x = 8, cursor_c = COL8_000000; fifo32_init(&fifo, 128, fifobuf, task);//task任务的缓冲区有数据被唤醒 timer = timer_alloc(); timer_init(timer, &fifo, 1); timer_settime(timer, 50); for (;;) { io_cli(); if (fifo32_status(&fifo) == 0) { task_sleep(task); io_sti(); } else { i = fifo32_get(&fifo); io_sti(); if (i <= 1) {//光标定时器 if (i != 0) { timer_init(timer, &fifo, 0); //置0让光标显示白色 cursor_c = COL8_FFFFFF; } else { timer_init(timer, &fifo, 1);//置1让光标显示黑色 cursor_c = COL8_000000; } timer_settime(timer, 50); boxfill8(sheet->buf, sheet->bxsize, cursor_c, cursor_x, 28, cursor_x + 7, 43); sheet_refresh(sheet, cursor_x, 28, cursor_x + 8, 44); } } } }
Figure1. 命令行窗口雏形
在主函数内,通过往显存内写调色板号的方式显示了命令行窗口,并设置命令行窗口所在的图层,然后创建一个新任务来操作命令行窗口。此时只有task_a能够接受键盘输入。
使用Tab按键让绘制出的命令行窗口能够接受键盘输入。
将窗口标题栏显示写成单独的函数。然后在HariMain()函数中设置一个变量key_to,用key_to标志当前Tab键该切换哪个窗口的标题栏颜色。
每个任务都对应一个缓冲区。如果Tab切换到命令行窗口时,只要向命令行窗口所在任务的缓冲区发送键盘输入(CPU管理的任务管不了中断产生),再将缓冲区内的键盘数据显示在命令行窗口中,这样就实现了命令行窗口接受键盘输入。采用相同方式让其它窗口接受键盘输入。
更改描述任务的数据结构。
struct TASK { int sel, flags; int level, priority; struct FIFO32 fifo; //每个任务管理缓冲区的结构体 struct TSS32 tss; };
改写HariMain,判断key_to的值让其往不同任务(2个)的缓冲区内发送键盘数据。
void HariMain(void) { …… for (;;) { io_cli(); if (fifo32_status(&fifo) == 0) { …… } else { i = fifo32_get(&fifo); io_sti(); if (256 <= i && i <= 511) { //键盘数据 …… if (i < 0x54 + 256 && keytable[i - 256] != 0) {//字符 if (key_to == 0) {//发送给task_a if (cursor_x < 128) { //显示后将光标后移一位 s[0] = keytable[i - 256]; s[1] = 0; putfonts8_asc_sht(sht_win, cursor_x, 28, COL8_000000, COL8_FFFFFF, s, 1); cursor_x += 8; } } else { //发送给命令行窗口 fifo32_put(&task_cons->fifo, keytable[i - 256] + 256); } } if (i == 256 + 0x0e) { //退格键 if (key_to == 0) {//发送给task_a if (cursor_x > 8) { //用空格查除光标后移一位 putfonts8_asc_sht(sht_win, cursor_x, 28, COL8_000000, COL8_FFFFFF, " ", 1); cursor_x -= 8; } } else {//发送给命令行窗口 fifo32_put(&task_cons->fifo, 8 + 256); } } …… } else if (i <= 1) { //光标定时 …… } } }
修改console_task处理键盘输入。
void console_task(struct SHEET *sheet) { struct TIMER *timer; struct TASK *task = task_now(); int i, fifobuf[128], cursor_x = 16, cursor_c = COL8_000000; char s[2]; fifo32_init(&task->fifo, 128, fifobuf, task); timer = timer_alloc(); timer_init(timer, &task->fifo, 1); timer_settime(timer, 50); //命令输入提示符 putfonts8_asc_sht(sheet, 8, 28, COL8_FFFFFF, COL8_000000, ">", 1); for (;;) { io_cli(); if (fifo32_status(&task->fifo) == 0) { task_sleep(task); io_sti(); } else { i = fifo32_get(&task->fifo); io_sti(); if (i <= 1) { //光标定时 if (i != 0) { timer_init(timer, &task->fifo, 0);//置0显示白色 cursor_c = COL8_FFFFFF; } else { timer_init(timer, &task->fifo, 1); //置1显示黑色 cursor_c = COL8_000000; } timer_settime(timer, 50); } if (256 <= i && i <= 511) { //键盘字符输入 if (i == 8 + 256) { //退格键 if (cursor_x > 16) { //空格消除光标,光标后移 putfonts8_asc_sht(sheet, cursor_x, 28, COL8_FFFFFF, COL8_000000, " ", 1); cursor_x -= 8; } } else { //键盘字符 if (cursor_x < 240) { //显示字符,光标后移 s[0] = i - 256; s[1] = 0; putfonts8_asc_sht(sheet, cursor_x, 28, COL8_FFFFFF, COL8_000000, s, 1); cursor_x += 8; } } } //显示光标 boxfill8(sheet->buf, sheet->bxsize, cursor_c, cursor_x, 28, cursor_x + 7, 43); sheet_refresh(sheet, cursor_x, 28, cursor_x + 8, 44); } } }
键盘中断调用的fifo32_put函数的缓冲区参数可以设成每个任务的缓冲区。每个任务的缓冲区在内存中独立存在,任务可以访问到本任务之内的缓冲区而访问不到其它任务内的缓冲。
Figure2. 多窗口切换接受键盘字符输入
“书”在程序中定义一个变量key_shift来记录2个Shift键的状态,左Shift按下时key_shift为1,右Shift按下时key_shift为1,2个都不按时key_shift为0。然后再准备两个数组,keytable0保存键盘上的字符(见键盘输入处理),keytable1保存特殊的符号。然后程序根据缓冲区内的数据范围来决定使用哪一个数据显示键盘输入。(harib14e)。
要实现区分大小写字母的输入,必须判断Shift键以及CapsLock的状态。输入小写字母的情况:输入英文字母,CapsLock为OFF& Shift键为OFF或者CapsLock为ON& Shift键为ON。在asmhead.nas中已经调用BIOS程序获取了键盘状态,[LEDS]内存的第4位保存ScrollLock状态,第5位保存NumLock的状态,第6位保存的CapsLock状态。根据这几位具体的含义编写程序就能够显示出大小字母。(CaosLock编码为0x3a;Numlock编码为0x45;ScrollLock编码为0x46)
当收到锁定按键的编码时,需要将[LEDS]中的数据进行改写,这样按键锁定的模式就可以发生切换,但这些按键对应的LED灯的状态却不会改变。关于LED的控制:
根据以上信息编写代码。
#define KEYCMD_LED 0xed void HariMain(void) { …… struct FIFO32 fifo, keycmd; int fifobuf[128], keycmd_buf[32]; …… int key_to = 0, key_shift = 0, key_leds = (binfo->leds >> 4) & 7, keycmd_wait = -1; …… fifo32_init(&keycmd, 32, keycmd_buf, 0); …… //避免冲突,一开始进行设置一下 fifo32_put(&keycmd, KEYCMD_LED); fifo32_put(&keycmd, key_leds); for (;;) { if (fifo32_status(&keycmd) > 0 && keycmd_wait < 0) { //如果有像键盘控制器发送的数据则发送它 keycmd_wait = fifo32_get(&keycmd); wait_KBC_sendready(); io_out8(PORT_KEYDAT, keycmd_wait); } ……. if (i == 256 + 0x3a) { /* CapsLock */ key_leds ^= 4; fifo32_put(&keycmd, KEYCMD_LED); fifo32_put(&keycmd, key_leds); } if (i == 256 + 0x45) { /* NumLock */ key_leds ^= 2; fifo32_put(&keycmd, KEYCMD_LED); fifo32_put(&keycmd, key_leds); } if (i == 256 + 0x46) { /* ScrollLock */ key_leds ^= 1; fifo32_put(&keycmd, KEYCMD_LED); fifo32_put(&keycmd, key_leds); } if (i == 256 + 0xfa) {//键盘成功接收到数据 keycmd_wait = -1; } if (i == 256 + 0xfe) { //键盘接受数据失败 wait_KBC_sendready(); io_out8(PORT_KEYDAT, keycmd_wait); } …… } }
马虎读。
认识所操作对象(硬件)各模块被设计的关联性(独立还是有关联)。
改变笔记风格,不再全贴源码,记录思路。
[x86OS] Note Over.
[2015.04.29]