闲置任务
在前文说到,通过采用LEVEL的结构运行系统,但当高层任务A休眠,而下层LEVEL中不存在其他的任务,因此程序就找不到任务而导致运行出行异常,所以优秀的操作系统应该能自动在适当的LEVEL运行适当的任务。
创建一个闲置任务:
这个任务的功能只是执行HTL。
void task_idle(void)
{
for(;;){
io_hlt();
}
}
所以即使高层任务A进入sleep,系统也能自动切换到上面这个闲置任务。移动鼠标,FIFO有数据写入,任务A就会被唤醒,系统自动切换到A继续工作。
所以改写一下HariMain:
void HariMain(void)
{
(passing)
/*sht_win_b*/
for(i=0; i<3;i++){
(passing)
*((int*)(task_b[i]->tss.esp+4)) = (int) sht_win_b[i];
}
(passing)
}
创建命令行窗口
命令行窗口当作任务操作
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);
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);
}
}
}
}
实现字符输入
实现字符输入,需要在键盘被按下的时候向console_task的FIFO发送数据,即需要知道struct FIFO的内存地址才行。
struct TASK{
int sel,flags;/*sel 代表*/
int level,priority;
struct FIFO32 fifo;
struct TSS32 tss;
};
符号的输入
为了能够实现输入“!”和“%”,我们必须要处理Shift键。
左Shift : 0x2a(按下) 0xaa(抬起)
右Shift : 0x36 0xb6
所以准备一个key_shift变量:左Shift按下置1,右Shift按下置2,俩个都不按下置为0,俩个都按下置为3。
当key_shift为0时,我们用keytable0[]将按键编码转换为字符编码,而当key_shift不为0时,则使用keytable1[]进行转换。
大写字母与小写字母
要实现区分大小写字母的输入,我们必须要同时判断Shift键的状态以及CapsLock的状态。
CapsLock为OFF & Shift键为OFF → 小写英文字母
CapsLock为OFF & Shift键为ON → 大写英文字母
CapsLock为ON & Shift键为OFF → 大写英文字母
CapsLock为ON & Shift键为ON → 小写英文字母
即实现小写字母需要满足如下:
①输入的字符为英文字母
②“CapsLock为OFF&Shift键位OFF”或者“CapsLock为ON&Shift键为ON”
而CapsLock信息存储在BIOS中,在asmhead.nas中,通过BIOS获取键盘状态,并保存在binfo->leds中。
binfo->leds的第4位→ ScrollLock状态
binfo->leds的第5位 → NumLock状态
binfo->leds的第6位 → CapsLock状态
对各种锁定键的支持
我们通过上文可知:
CapsLock:0x3a
NumLock:0x45
ScrollLock:0x46
关于LED的控制:
对于NumLock和CapsLock等LED的控制,可采用下面的方法向键盘发送指令和数据。
1.读取状态寄存器,等待bit 1的值变为0。
2.向数据输出(0060)写入要发送的1个字节数据。
3.等待键盘返回1个字节的信息,这和等待键盘输入所采用的方法相同(用IRQ等待或者用轮询状态寄存器bit 1的值直到其变为0都可以)。
4.返回的信息如果为0xfa,表明1个字节的数据已成功发送给键盘。如为0xfe则表明发送失败,需要返回第1步重新发送。
首先,我们创建了一个叫keycmd的FIFO缓冲区,它不是用来接收中断请求的,而是用来管理由任务A向键盘控制器发送数据的顺序的。如果有数据要发送到键盘控制器,首先会在这个keycmd中累积起来。keycmd_wait变量,用来表示向键盘控制器发送数据的状态。当keycmd_wait的值为-1时,表示键盘控制器处于通常状态,可以发送指令;当值不为-1时,表示键盘控制器正在等待发送的数据,这时要发送的数据被保存在keycmd_wait变量中。在for循环的开头,当keycmd中有数据,且keycmd_wait为-1时,向键盘发送1个字节的数据,在开始发送数据的同时,keycmd_wait变为非-1的值。随后,当从键盘接收到0xfa返回信息时,keycmd_wait恢复为-1,继续发送下一个数据。当从键盘接收到的返回信息为0xfe时,则重新发送刚才的数据。