30天自制操作系统——第二十三天窗口操作

这篇博客讲述了在自制操作系统中实现窗口操作的过程,包括窗口及输入切换、移动窗口和关闭窗口的功能。通过F11键和鼠标点击可以切换窗口,窗口移动通过检测鼠标在标题栏的点击实现,而关闭窗口则是通过点击‘×’按钮。此外,还介绍了如何设置定时器窗口。

窗口及输入切换

我们先来实现用键盘切换窗口,按下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天自制操作系统》制作,感谢各位的持续关注,原著源码链接见第十九篇。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值