2 应用程序运行时关闭命令行窗口(harib24b)*
终于除掉了bug,神清气爽。命令行窗口的功能已经实现得差不多了,不过还有一个地方不太满意,就是在应用程序运行的时候无法关闭所对应的命令行窗口。
我们先不考虑ncst命令,用普通的方法运行应用程序的时候,在应用程序退出之前,我们是无法关闭用来启动这个程序的命令行窗口的。直到程序运行之后才觉得命令行窗口太碍事了,但事已至此也不想再重新启动应用程序(比如说,热水已经倒好了,总不能这个时候重新启动noodle.hrb吧!),于是就只好将就了。
因此还是想办法解决这个问题比较好。
■■■■■
首先我们来修改bootpack.c。
本次的bootpack.c节选
void HariMain(void)
{
(中略)
struct SHEET *sht = 0, *key_win, *sht2; /*添加sht2 */
(中略)
for (;;) {
(中略)
if (fifo32_status(&fifo) == 0) {
(中略)
} else {
(中略)
if (256 <= i && i <= 511) { /*键盘数据*/
(中略)
} 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) { /*是否为应用程序窗口*/
(中略)
} else { /*命令行窗口*/
task = sht->task;
/*从此开始*/ sheet_updown(sht, -1); /*暂且隐藏该图层*/
keywin_off(key_win);
key_win = shtctl->sheets[shtctl->top - 1];
/*到此结束*/ keywin_on(key_win);
io_cli();
fifo32_put(&task->fifo, 4);
io_sti();
}
}
break;
}
}
}
} else {
(中略)
}
} else {
(中略)
}
}
} else if (768 <= i && i <= 1023) { /*命令行结束处理*/
close_console(shtctl->sheets0 + (i - 768));
} else if (1024 <= i && i <= 2023) {
close_constask(taskctl->tasks0 + (i - 1024));
} else if (2024 <= i && i <= 2279) { /*只关闭命令行窗口*/ /*从此开始*/
sht2 = shtctl->sheets0 + (i - 2024);
memman_free_4k(memman, (int) sht2->buf, 256 * 165);
sheet_free(sht2); /*到此结束*/
}
}
}
}
我们修改了bootpack.c中的两个地方。前面一个地方的修改是让系统在按下“×”按钮时暂且将命令行窗口从画面上隐藏起来。为什么要耍这样一个小聪明呢?这是因为关闭有的应用程序的命令行窗口时需要消耗一定的时间,如果点了按钮还不关闭用户会觉得很烦躁,先隐藏窗口就可以避免这样的问题。总之这只是一个小技巧而已,并不是本次修改的重点。
后面一处修改是当FIFO接收到从console.c发送的“关闭窗口”请求数据时所进行的处理,主要是释放指定的图层。关于这一处修改的内容,看了对console.c进行修改的部分之后会更容易理解。
■■■■■
下面就是对console.c的修改。
本次的console.c节选
void console_task(struct SHEET *sheet, int memtotal)
{
(中略)
if (cons.sht != 0) { /*这里!*/
(中略)
}
(中略)
for (;;) {
io_cli();
if (fifo32_status(&task->fifo) == 0) {
(中略)
} else {
(中略)
if (i <= 1 && cons.sht != 0) { /*光标用定时器*/ /*这里!*/
(中略)
}
(中略)
if (i == 3) { /*光标OFF */
if (cons.sht != 0) { /*这里!*/
boxfill8(cons.sht->buf, cons.sht->bxsize, COL8_000000, /*这里!*/
cons.cur_x, cons.cur_y, cons.cur_x + 7, cons.cur_y + 15);
}
cons.cur_c = -1;
}
(中略)
if (256 <= i && i <= 511) { /*键盘数据(通过任务A)*/
if (i == 8 + 256) {
(中略)
} else if (i == 10 + 256) {
(中略)
if (cons.sht == 0) { /*这里!*/
cmd_exit(&cons, fat);
}
(中略)
} else {
(中略)
}
}
/*重新显示光标*/
if (cons.sht != 0) { /*这里!*/
if (cons.cur_c >= 0) {
boxfill8(cons.sht->buf, cons.sht->bxsize, cons.cur_c, /*这里!*/
cons.cur_x, cons.cur_y, cons.cur_x + 7, cons.cur_y + 15);
}
/*这里!*/ sheet_refresh(cons.sht, cons.cur_x, cons.cur_y, cons.cur_x + 8, cons.cur_y + 16);
}
}
}
}
修改的要点是将变量sheet的部分改用变量cons.sht代替。虽然两个变量的值基本上是一致的,但cons.sht在命令行窗口关闭后会被置为0,而sheet则不变,因此在这里我们需要使用前者。
接下来我们来修改API中键盘输入的部分。
本次的console.c节选
int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax)
{
(中略)
struct FIFO32 *sys_fifo = (struct FIFO32 *) *((int *) 0x0fec); /*这里!*/
(中略)
} else if (edx == 15) {
for (;;) {
(中略)
if (i == 4) { /*只关闭命令行窗口*/ /*从此开始*/
timer_cancel(cons->timer);
io_cli();
fifo32_put(sys_fifo, cons->sht - shtctl->sheets0 + 2024); /*2024~2279*/
cons->sht = 0;
io_sti();
} /*到此结束*/
(中略)
}
} else if (edx == 16) {
(中略)
}
在等待键盘输入期间,如果FIFO中接收到4这个数据,则表示收到了关闭命令行窗口的信号,此时取消定时器,并发出清理图层的消息,然后将cons—>sht置为0。
■■■■■
好,大功告成了,我们来“make run”吧。
我们故意不使用ncst命令,而是用一般的方法运行笔者最喜欢的color2.hrb,程序启动后尝试关闭命令行窗口……耶!
![]() | ![]() | |
color2.hrb启动时的样子 | 关闭命令行窗口后的样子 |