6 键盘输入API(harib20f)

那么,我们就给这个应用程序增加接受键盘输入的功能,当按下回车键时再结束运行,这样就不会出现窗口显示时间过短的问题了。

要接受键盘输入,其实只要从和任务绑定的FIFO缓冲区中取出1个就可以了。哦对了,等待键盘输入的这段时间程序没有什么事情好做,因此我们还要加上休眠的功能。

键盘输入

EDX = 15

EAX = 0……没有键盘输入时返回-1,不休眠

    = 1……休眠直到发生键盘输入

EAX = 输入的字符编码

本次的console.c节选

  1. int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax)
  2. {
  3. int ds_base = *((int *) 0xfe8);
  4. (中略)
  5. int i;
  6. (中略)
  7. } else if (edx == 15) {
  8. for (;;) {
  9. io_cli();
  10. if (fifo32_status(&task->fifo) == 0) {
  11. if (eax != 0) {
  12. task_sleep(task); /* FIFO为空,休眠并等待*/
  13. } else {
  14. io_sti();
  15. reg[7] = -1;
  16. return 0;
  17. }
  18. }
  19. i = fifo32_get(&task->fifo);
  20. io_sti();
  21. if (i <= 1) { /*光标用定时器*/
  22. /*应用程序运行时不需要显示光标,因此总是将下次显示用的值置为1*/
  23. timer_init(cons->timer, &task->fifo, 1); /*下次置为1*/
  24. timer_settime(cons->timer, 50);
  25. }
  26. if (i == 2) { /*光标ON */
  27. cons->cur_c = COL8_FFFFFF;
  28. }
  29. if (i == 3) { /*光标OFF */
  30. cons->cur_c = -1;
  31. }
  32. if (256 <= i && i <= 511) { /*键盘数据(通过任务A)*/
  33. reg[7] = i - 256;
  34. return 0;
  35. }
  36. }
  37. }
  38. return 0;
  39. }

这次的代码有点长。首先,从整体上看,我们通过一个for语句来进行循环。为什么要这样做呢?当FIFO为空或成功接收到键盘输入后循环结束,在这个过程里,FIFO中还会收到诸如计时器光标ON、OFF之类的数据,这时,我们需要简单地将它们处理掉,然后再重新循环轮询FIFO的状态。当确认接收到键盘输入的数据,或者FIFO缓冲区为空时,则通过return命令结束API的处理。这样一来,从结果上来说,就相当于跳出了for循环。

这段程序是仿照console_task的FIFO数据处理部分写的,将它们对比着看应该会更容易理解。

还有cons —> timer的地方需要讲一下。为了设置定时器我们需要timer的地址,不过这是console_task中的变量,hrb_api是无法获取的,虽然像ds_base的时候那样,随便找一个地址存放一下也可以解决,不过这次我们采用了不同的方法。

本次的bootpack.h节选

  1. struct CONSOLE {
  2. struct SHEET *sht;
  3. int cur_x, cur_y, cur_c;
  4. struct TIMER *timer;
  5. };

像这样,我们将定时器加入到struct CONSOLE中了。因为这个定时器是用来控制光标闪烁的,对于命令行窗口来说是必需的,所以放在CONSOLE结构中也没什么问题(笔者希望将相关的成员都封装到同一个结构中)。

因此我们还修改了console_task,去掉timer变量,以cons.timer取而代之。

■■■■■

操作系统的修改已经完成了,接下来轮到应用程序了。写一个新程序太麻烦,所以我们还是来改造lines.c吧。

本次的a_nask.nas节选

  1. _api_getkey: ; int api_getkey(int mode);
  2. MOV EDX,15
  3. MOV EAX,[ESP+4] ; mode
  4. INT 0x40
  5. RET

本次的lines.c节选

  1. int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title);
  2. void api_initmalloc(void);
  3. char *api_malloc(int size);
  4. void api_refreshwin(int win, int x0, int y0, int x1, int y1);
  5. void api_linewin(int win, int x0, int y0, int x1, int y1, int col);
  6. void api_closewin(int win);
  7. int api_getkey(int mode);
  8. void api_end(void);
  9. void HariMain(void)
  10. {
  11. (中略)
  12. api_refreshwin(win, 6, 26, 154, 90);
  13. for (;;) {
  14. if (api_getkey(1) == 0x0a) {
  15. break; /*按下回车键则break; */
  16. }
  17. }
  18. api_closewin(win);
  19. api_end();
  20. }

写好啦。应用程序很简单,当然,编写API也不是什么很难的事情啦。

我们赶紧“make run”吧,不知道能不能成功呢。哦哦,这次没有马上消失!

6 键盘输入API(harib20f) - 图1

看,这次不会自动消失了哦

而且,按空格键或者其他字母键都没有反应,但按下回车键时窗口就关闭了,看来很成功呢。

6 键盘输入API(harib20f) - 图2

按下回车键程序结束