5 增加命令行窗口(1)(harib22e)
我们在25.2节和25.3节中分别编写了color.hrb和color2.hrb,如果要仔细对比一下这两个程序显示出来的画面有什么区别,就要把两个程序的窗口并排起来看才行,可是我们不能同时启动两个应用程序啊。这实在是太郁闷了,我们辛辛苦苦实现的多任务到底是为了什么呢?
要解决这个问题,我们可以考虑修改一下命令行窗口,使其在应用程序运行中就可以输入下一条命令,不过这样的修改量实在太大,讲解起来也会很麻烦,因此我们还是改用同时启动两个命令行窗口的方法吧。如果可以启动两个命令行窗口,就可以在每个窗口中各自启动一个应用程序,这就相当于同时运行了两个应用程序。而命令行窗口我们一开始就是作为任务来编写的,所以要同时启动两个也很容易。
不过我们的程序中还有一部分是以只有一个命令行窗口为前提设计的,所以如果只是启动两个命令行窗口任务的话肯定是行不通的。不过我们不妨先启动两个命令行窗口试试看,如果有什么不对的地方再去一点一点地修改(一上来就想做得完美,反而会遇到麻烦的问题呢)。
■■■■■
于是,我们这次只修改bootpack.c,将命令行窗口的相关变量(buf_cons、sht_cons、task_cons和cons)各准备2个,分别分给命令行1和命令行2。
例如:task_cons
→ task_cons1
和task_cons2
不过这样一来,如果要将命令行窗口增加到10个,岂不是要写10组这样的变量吗?虽说可以复制粘贴,但还是太麻烦了,因此我们稍微动点脑筋改成下面这样就好了。
task_cons
→ task_cons[0]
和task_cons[1]
这样的话我们就可以用一个循环来进行相同的处理,管它10个还是100个都没问题!
本次的bootpack.c节选
void HariMain(void)
{
(中略)
unsigned char *buf_back, buf_mouse[256], *buf_win, *buf_cons[2]; /*从此开始*/
struct SHEET *sht_back, *sht_mouse, *sht_win, *sht_cons[2];
struct TASK *task_a, *task_cons[2]; /*到此结束*/
(中略)
/* sht_cons */
for (i = 0; i < 2; i++) { /*从此开始*/
sht_cons[i] = sheet_alloc(shtctl);
buf_cons[i] = (unsigned char *) memman_alloc_4k(memman, 256 * 165);
sheet_setbuf(sht_cons[i], buf_cons[i], 256, 165, -1); /*没有透明色*/
make_window8(buf_cons[i], 256, 165, "console", 0);
make_textbox8(sht_cons[i], 8, 28, 240, 128, COL8_000000);
task_cons[i] = task_alloc();
task_cons[i]->tss.esp = memman_alloc_4k(memman, 64 * 1024) + 64 * 1024 - 12;
task_cons[i]->tss.eip = (int) &console_task;
task_cons[i]->tss.es = 1 * 8;
task_cons[i]->tss.cs = 2 * 8;
task_cons[i]->tss.ss = 1 * 8;
task_cons[i]->tss.ds = 1 * 8;
task_cons[i]->tss.fs = 1 * 8;
task_cons[i]->tss.gs = 1 * 8;
*((int *) (task_cons[i]->tss.esp + 4)) = (int) sht_cons[i];
*((int *) (task_cons[i]->tss.esp + 8)) = memtotal;
task_run(task_cons[i], 2, 2); /* level=2, priority=2 */
sht_cons[i]->task = task_cons[i];
sht_cons[i]->flags |= 0x20; /*有光标*/
} /*到此结束*/
(中略)
sheet_slide(sht_back, 0, 0);
sheet_slide(sht_cons[1], 56, 6); /*这里! */
sheet_slide(sht_cons[0], 8, 2); /*这里! */
sheet_slide(sht_win, 64, 56);
sheet_slide(sht_mouse, mx, my);
sheet_updown(sht_back, 0);
sheet_updown(sht_cons[1], 1); /*从此开始*/
sheet_updown(sht_cons[0], 2);
sheet_updown(sht_win, 3);
sheet_updown(sht_mouse, 4); /*到此结束*/
key_win = sht_win;
(中略)
for (;;) {
(中略)
io_cli();
if (fifo32_status(&fifo) == 0) {
(中略)
} else {
(中略)
if (256 <= i && i <= 511) { /*键盘数据*/
(中略)
/*从此开始*/ if (i == 256 + 0x3b && key_shift != 0 && task_cons[0]->tss.ss0 != 0) { /* Shift+F1 */
cons = (struct CONSOLE *) *((int *) 0x0fec);
cons_putstr0(cons, "\nBreak(key) :\n");
io_cli(); /*强制结束处理时禁止任务切换*/
task_cons[0]->tss.eax = (int) &(task_cons[0]->tss.esp0);
/*到此结束*/ task_cons[0]->tss.eip = (int) asm_end_app;
io_sti();
}
(中略)
} else if (512 <= i && i <= 767) { /*鼠标数据*/
if (mouse_decode(&mdec, i - 512) != 0) {
(中略)
if ((mdec.btn & 0x01) != 0) {
/*按下左键时*/
if (mmx < 0) {
(中略)
for (j = shtctl->top - 1; j > 0; j--) {
(中略)
if (0 <= x && x < sht->bxsize && 0 <= y && y < sht->bysize) {
if (sht->buf[y * sht->bxsize + x] != sht->col_inv) {
(中略)
if (sht->bxsize - 21 <= x && x < sht->bxsize - 5 && 5 <= y && y < 19) {
/*点击“×”按钮*/
if ((sht->flags & 0x10) != 0) { /*是否为应用程序窗口*/
cons = (struct CONSOLE *) *((int *) 0x0fec);
cons_putstr0(cons, "\nBreak(mouse) :\n");
io_cli(); /*强制结束处理时禁止任务切换*/
/*从此开始*/ task_cons[0]->tss.eax = (int) &(task_cons[0]->tss.esp0);
/*到此结束*/ task_cons[0]->tss.eip = (int) asm_end_app;
io_sti();
}
}
break;
}
}
}
} else {
(中略)
}
} else {
(中略)
}
}
} else if (i <= 1) { /*光标用定时器*/
(中略)
}
}
}
}
前半部分代码应该还很容易看懂,不过后半部分Shift+F1以及“×”按钮的处理是不是觉得有些蹊跷?为什么不判断就直接写cons[0]呢?其实呢,这里纯粹是偷懒了(笑)。如果我们不加上[0]或者[1]的话编译器通不过,因此就先写了[0],关于这一块,我们会在25.8节中进行修复。
因此,在运行harib22e和harib22f的时候,大家记得千万别按Shift+F1或者“×”按钮哦。
好了,我们来“make run”,目前打开两个命令行窗口应该没问题吧。好,出来了!
出现了两个命令行窗口
在两个窗口之间切换一下,貌似都能够执行命令。之所以说“貌似”,是因为笔者知道剩下的问题还有很多,至于后面到底能不能顺利运行,说实话笔者真没什么自信。
尝试执行一下mem和dir命令
那么现在到底能不能同时启动两个应用程序呢?虽然很想用color.hrb和color2.hrb来试一下,不过大抵是不会成功的,所以我们还是从基本中的基本——a.hrb开始测试吧。咦?什么都没显示出来???……晕!在这儿呢!居然显示到没运行这个程序的命令行窗口中去了。
运行a.hrb的情形……
这样可不行啊,我们得解决这个问题。