窗口及输入切换
我们先来实现用键盘切换窗口,按下F11键,将最下面的窗口移动到最上面,这里F11按键的编码为0x57。
bootpack.c节选:
void HariMain(void)
{
(略)
for (;;) {
(略)
if (fifo32_status(&fifo) == 0) {
(略)
} else {
(略)
if (256 <= i && i <= 511) { /* 键盘数据 */
(略)
if (i == 256 + 0x57 && shtctl->top > 2) { /* F11 */
sheet_updown(shtctl->sheets[1], shtctl->top - 1);
}
(略)
} else if (512 <= i && i <= 767) { /* 鼠标数据 */
(略)
} else if (i <= 1) { /* 光标用定时器 */
(略)
}
}
}
}
shtctl->top是最上面的一个图层,这个图层是用于绘制鼠标指针,要将窗口放在鼠标指针图层的下一个图层。
接下来实现鼠标点击来切换窗口的功能,鼠标点击画面时,要从上到下判断鼠标点击的是哪个图层,接着判断鼠标点击的位置落在哪个图层范围内。
bootpack.c节选
if ((mdec.btn & 0x01) != 0) {/* 按下左键 */
/* 按照从上到下的顺序寻找鼠标所指向的图层 */
for (j = shtctl->top - 1; j > 0; j--) {
sht = shtctl->sheets[j];
x = mx - sht->vx0;
y = my - sht->vy0;
if (0 <= x && x < sht->bxsize && 0 <= y && y < sht->bysize) {
if (sht->buf[y * sht->bxsize + x] != sht->col_inv) {
sheet_updown(sht, shtctl->top - 1);
break;
}
}
}
}
make run一下,可以用F11键和鼠标点击切换窗口了。
现在虽然已经将窗口切换过来了,但是输入状态还是命令行窗口,现在将输入也切换到应用程序窗口吧。使用key_win变量存放当前处于输入模式的窗口地址,当处于输入模式的窗口被关闭时,系统自动切换到最上层的窗口。新建keywin_on和kinwin_off两个函数,控制窗口标题栏的颜色,选中的窗口标题栏为蓝色,未选中的窗口标题栏为灰色。
鼠标在选中窗口上点击一下,该选中窗口就会被切换到画面的最上方,同时键盘输入也会自动切换到该窗口。
bootpack.c节选
/* 按下左键 */
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) {
sheet_updown(sht, shtctl->top - 1);
if (sht != key_win) {
cursor_c = keywin_off(key_win, sht_win, cursor_c, cursor_x);
key_win = sht;
cursor_c = keywin_on(key_win, sht_win, cursor_c);
}
if (3 <= x && x < sht->bxsize - 3 && 3 <= y && y < 21) {
mmx = mx; /* 进入窗口移动模式 */
mmy = my;
}
if (sht->bxsize - 21 <= x && x < sht->bxsize - 5 && 5 <= y && y < 19) {
/* 点击"×"按钮 */
(略)
}
break;
}
}
}
}
make run执行一下——

移动窗口
接下来实现像windows一样的方式来移动窗口,左键点击窗口,若点击的位置刚好位于窗口的标题栏区域则进入移动模式。窗口跟随着鼠标移动,当鼠标左键松开时,退出移动模式。这里添加了两个变量mmx和mmy ,用于记录移动之前的坐标。当mmx为负数时,代表当前不处于窗口移动模式。
bootpack.c节选:
if ((mdec.btn & 0x01) != 0) {/* 按下左键 */
if (mmx < 0) {
/* 按照从上到下的顺序寻找鼠标所指向的图层 */
for (j = shtctl->top - 1; j > 0; j--) {
sht = shtctl->sheets[j];
x = mx - sht->vx0;
y = my - sht->vy0;
if (0 <= x && x < sht->bxsize && 0 <= y && y < sht->bysize) {
if (sht->buf[y * sht->bxsize + x] != sht->col_inv) {
sheet_updown(sht, shtctl->top - 1);
if (3 <= x && x < sht->bxsize - 3 && 3 <= y && y < 21) {
mmx = mx; /* 进入窗口移动模式 */
mmy = my;
}
break;
}
}
}
} else {
/* 如果处于窗口移动模式 */
x = mx - mmx; /* 计算鼠标的移动距离 */
y = my - mmy;
sheet_slide(sht, sht->vx0 + x, sht->vy0 + y);
mmx = mx; /* 更新为移动后的坐标 */
mmy = my;
}
}
关闭窗口
实现鼠标左键点击窗口上的“ × ” 按钮后关闭窗口,这里先判断鼠标左键点击的位置刚好位于窗口上的“ × ” 位置,若处于该位置则强制结束。
bootpack.c节选
if (sht->bxsize - 21 <= x && x < sht->bxsize - 5 && 5 <= y && y < 19) {
/* 点击“×” 按钮 */
if (sht->task != 0) { /* 判断该窗口是否为应用程序 */
cons = (struct CONSOLE *) *((int *) 0x0fec);
cons_putstr0(cons, "\nBreak(mouse) :\n");
io_cli(); /* 禁止中断发生 */
task_cons->tss.eax = (int) &(task_cons->tss.esp0);
task_cons->tss.eip = (int) asm_end_app;
io_sti();
}
}
定时器
窗口切换,窗口移动,输入切换的操作已经全部完成了,现在我们来用命令开启一个定时器的窗口吧,可以用它来记个时。
void HariMain(void)
{
char *buf, s[12];
int win, timer, sec = 0, min = 0, hou = 0;
api_initmalloc();
buf = api_malloc(150 * 50);
win = api_openwin(buf, 150, 50, -1, "timers");
timer = api_alloctimer();
api_inittimer(timer, 128);
for (;;) {
sprintf(s, "%5d:%02d:%02d", hou, min, sec);
api_boxfilwin(win, 28, 27, 115, 41, 7 /* 白色 */);
api_putstrwin(win, 28, 27, 0 /* 黑色 */, 11, s);
api_settimer(timer, 100); /* 1秒 */
if (api_getkey(1) != 128) {
break;
}
sec++;
if (sec == 60) {
sec = 0;
min++;
if (min == 60) {
min = 0;
hou++;
}
}
}
api_end();
}
执行make run——

注:本文参照《30天自制操作系统》制作,感谢各位的持续关注,原著源码链接见第十九篇。
这篇博客讲述了在自制操作系统中实现窗口操作的过程,包括窗口及输入切换、移动窗口和关闭窗口的功能。通过F11键和鼠标点击可以切换窗口,窗口移动通过检测鼠标在标题栏的点击实现,而关闭窗口则是通过点击‘×’按钮。此外,还介绍了如何设置定时器窗口。
522

被折叠的 条评论
为什么被折叠?



