昨天鼠标不动的问题,是因为相关的设定还没到位。鼠标和键盘的情况很类似,在解决鼠标问题之前,先拿键盘练练手。
获取按键编码(hiarib04a)
现在在键盘上按一个键,就在屏幕上显示出信息。我们把程序修改成,键盘按下一个键后不直接结束,可以接着在屏幕上显示按键的值,其他就先不做了。
需要修改的是int.c中的inthandler21函数:
#define PORT_KEYDAT 0x0060
void inthandler21(int *esp)
{
struct BOOTINFO *binfo = (struct BOOTINFO *) ADR_BOOTINFO;
unsigned char data, s[4];
io_out8(PIC0_OCW2, 0x61); /* 通知PIC"IRQ-01"已经受理完毕 */
data = io_in8(PORT_KEYDAT);
sprintf(s, "%02X", data);
boxfill8(binfo->vram, binfo->scrnx, COL8_008484, 0, 16, 15, 31);
putfonts8_asc(binfo->vram, binfo->scrnx, 0, 16, COL8_FFFFFF, s);
return;
}
io_out8(PIC0_OCW2, 0x61);这句是告知PIC已经发生了IRQ1中断,如果是IRQ3,则写成0x63,即将“0x60+IRQ号码”输出给OCW2就可以了。执行这句后,PIC继续监视IRQ1中断是否发生。
应该注意的是从编号为0x0060的设备输入的8位信息是按键编码,编号为0x0060的设备是键盘。
那么现在将接收到的按键编码显示在画面上,然后处理中断。
我们现在运行以下make run,看一下结果——
随便按下一个按键,屏幕上就会显示出一个十六进制的数字,这里我们发现键盘按下去会显示一个数字,松开会显示另一个数字,其中原因我们后面再说。
加快中断处理(hiarib04b)
现在程序里有一个问题,就算字符显示的内容也放在了中断处理的程序之中。由于中断处理本身是打断CPU正在执行的工作,强行加入请求进行处理,中断期间也不再接受别的中断。
而且在计算机看来字符显示是要花很多时间处理的,中断处理速度过慢就会出现鼠标卡顿的等问题,因此字符显示的内容最好不要加在中断函数里。
那么应该怎么处理呢?
方法很简单,将按键的编码先接收下来,保存在变量中,之后由HariMain偶尔去查看这个变量。如果有了新数据,就把它显示出来。
int.c节选:
#define PORT_KEYDAT 0x0060
struct KEYBUF keybuf;
void inthandler21(int *esp)
{
unsigned char data;
io_out8(PIC0_OCW2, 0x61); /* 通知PIC IRQ-01已经受理完毕 */
data = io_in8(PORT_KEYDAT);
if (keybuf.flag == 0) {
keybuf.data = data;
keybuf.flag = 1;
}
return;
}
由于键盘输入时需要缓冲区,我们定义了一个结构体,命名为keybuf。keybuf中的flag变量用于表示这个缓冲区是否为空,如果flag是0,表示缓冲区为空;如果flag是1,就表示缓冲区中存有数据。 若果缓冲区中存有数据,这时来了一个中断该怎么处理了,这里我们先不做处理,把这个数据丢掉。
我们对bootpack.c的HariMain函数里的无线循环for(;;)模块进行修改。
HariMain函数节选:
for (;;) {
io_cli();
if (keybuf.flag == 0) {
io_stihlt();
} else {
i = keybuf.data;
keybuf.flag = 0;
io_sti();
sprintf(s, "%02X", i);
boxfill8(binfo->vram, binfo->scrnx, COL8_008484, 0, 16, 15, 31);
putfonts8_asc(binfo->vram, binfo->scrnx, 0, 16, COL8_FFFFFF, s);
}
}
循环开始时,先用io_cli指令屏蔽中断。
为什么这时要屏蔽中断呢?
这是因为在执行后面的处理时,要是中断突然闯进来,可就乱套了。