6 键盘输入API(harib20f)
那么,我们就给这个应用程序增加接受键盘输入的功能,当按下回车键时再结束运行,这样就不会出现窗口显示时间过短的问题了。
要接受键盘输入,其实只要从和任务绑定的FIFO缓冲区中取出1个就可以了。哦对了,等待键盘输入的这段时间程序没有什么事情好做,因此我们还要加上休眠的功能。
键盘输入
EDX = 15
EAX = 0……没有键盘输入时返回-1,不休眠
= 1……休眠直到发生键盘输入
EAX = 输入的字符编码
本次的console.c节选
int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax)
{
int ds_base = *((int *) 0xfe8);
(中略)
int i;
(中略)
} else if (edx == 15) {
for (;;) {
io_cli();
if (fifo32_status(&task->fifo) == 0) {
if (eax != 0) {
task_sleep(task); /* FIFO为空,休眠并等待*/
} else {
io_sti();
reg[7] = -1;
return 0;
}
}
i = fifo32_get(&task->fifo);
io_sti();
if (i <= 1) { /*光标用定时器*/
/*应用程序运行时不需要显示光标,因此总是将下次显示用的值置为1*/
timer_init(cons->timer, &task->fifo, 1); /*下次置为1*/
timer_settime(cons->timer, 50);
}
if (i == 2) { /*光标ON */
cons->cur_c = COL8_FFFFFF;
}
if (i == 3) { /*光标OFF */
cons->cur_c = -1;
}
if (256 <= i && i <= 511) { /*键盘数据(通过任务A)*/
reg[7] = i - 256;
return 0;
}
}
}
return 0;
}
这次的代码有点长。首先,从整体上看,我们通过一个for语句来进行循环。为什么要这样做呢?当FIFO为空或成功接收到键盘输入后循环结束,在这个过程里,FIFO中还会收到诸如计时器光标ON、OFF之类的数据,这时,我们需要简单地将它们处理掉,然后再重新循环轮询FIFO的状态。当确认接收到键盘输入的数据,或者FIFO缓冲区为空时,则通过return命令结束API的处理。这样一来,从结果上来说,就相当于跳出了for循环。
这段程序是仿照console_task的FIFO数据处理部分写的,将它们对比着看应该会更容易理解。
还有cons —> timer的地方需要讲一下。为了设置定时器我们需要timer的地址,不过这是console_task中的变量,hrb_api是无法获取的,虽然像ds_base的时候那样,随便找一个地址存放一下也可以解决,不过这次我们采用了不同的方法。
本次的bootpack.h节选
struct CONSOLE {
struct SHEET *sht;
int cur_x, cur_y, cur_c;
struct TIMER *timer;
};
像这样,我们将定时器加入到struct CONSOLE中了。因为这个定时器是用来控制光标闪烁的,对于命令行窗口来说是必需的,所以放在CONSOLE结构中也没什么问题(笔者希望将相关的成员都封装到同一个结构中)。
因此我们还修改了console_task,去掉timer变量,以cons.timer取而代之。
■■■■■
操作系统的修改已经完成了,接下来轮到应用程序了。写一个新程序太麻烦,所以我们还是来改造lines.c吧。
本次的a_nask.nas节选
_api_getkey: ; int api_getkey(int mode);
MOV EDX,15
MOV EAX,[ESP+4] ; mode
INT 0x40
RET
本次的lines.c节选
int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title);
void api_initmalloc(void);
char *api_malloc(int size);
void api_refreshwin(int win, int x0, int y0, int x1, int y1);
void api_linewin(int win, int x0, int y0, int x1, int y1, int col);
void api_closewin(int win);
int api_getkey(int mode);
void api_end(void);
void HariMain(void)
{
(中略)
api_refreshwin(win, 6, 26, 154, 90);
for (;;) {
if (api_getkey(1) == 0x0a) {
break; /*按下回车键则break; */
}
}
api_closewin(win);
api_end();
}
写好啦。应用程序很简单,当然,编写API也不是什么很难的事情啦。
我们赶紧“make run”吧,不知道能不能成功呢。哦哦,这次没有马上消失!
看,这次不会自动消失了哦
而且,按空格键或者其他字母键都没有反应,但按下回车键时窗口就关闭了,看来很成功呢。
按下回车键程序结束