公司网站建设和推广,爱网恋的男生,wordpress layui,北京seo网站开发本篇内容依然比较简单#xff0c;主要是优化窗口功能以及开发定时器应用程序。首先是优化窗口的切换功能#xff0c;实现通过键盘和鼠标切换窗口#xff0c;然后是实现通过鼠标关闭窗口。接着实现不同窗口输入状态的切换#xff0c;最后是实现定时器的API与应用程序。
1.…本篇内容依然比较简单主要是优化窗口功能以及开发定时器应用程序。首先是优化窗口的切换功能实现通过键盘和鼠标切换窗口然后是实现通过鼠标关闭窗口。接着实现不同窗口输入状态的切换最后是实现定时器的API与应用程序。
1. 窗口优化
前面已经完成了窗口的基本功能现在需要对窗口功能进行进一步优化。首先是增加窗口的切换功能。
1.1 通过按键实现窗口切换
先从简单的开始实现按下F11后将最下面的窗口放在最上面。F11的按键编码为0x57只需要在主程序中添加如下代码
……
if (i 256 0x57 shtctl-top 2)
{ /* F11 */sheet_updown(shtctl-sheets[1], shtctl-top - 1);
}
……代码很简单sheets[0]表示背景图层sheets[1]即为最下层的窗口。top图层为鼠标图层按下F11键后将最下层的窗口调整到鼠标图层下一层即可(因为不能覆盖鼠标)。 1.2 通过鼠标实现窗口切换
接下来实现通过鼠标点击实现的窗口切换。鼠标点击画面上的某个地方时我们需要按照从上到下的顺序判断鼠标的位置落在哪个图层的范围内并且还需要确保该位置不是透明色区域
else if (512 i i 767)
{ /* 鼠标数据 */if (mouse_decode(mdec, i - 512) ! 0) {/* 鼠标指针移动 */mx mdec.x;my mdec.y;if (mx 0) {mx 0;}if (my 0) {my 0;}if (mx binfo-scrnx - 1) {mx binfo-scrnx - 1;}if (my binfo-scrny - 1) {my binfo-scrny - 1;}sheet_slide(sht_mouse, mx, my);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;}}}}}这一部分的逻辑也比较清楚。按照从上到下的顺序寻找鼠标点击的图层如果鼠标点击的位置处于该图层的范围之内就将该图层移动到最上面。如果将命令行窗口移动到最上面则会遮挡其他窗口。不过这时又可以通过F11将下面的窗口切换上来。
1.3 窗口移动
窗口的切换功能基本完成了接下来实现窗口的移动功能。之前单独实现了任务A窗口的实现功能现在有了多个任务窗口需要重新进行实现。
当鼠标左键点击窗口时如果点击窗口的标题栏区域则进入窗口移动模式使窗口位置随着鼠标指针移动而放开鼠标左键时退出窗口移动模式返回普通模式。实现窗口的移动需要记录鼠标移动的距离这里添加了两个变量mmx和mmy用于记录移动之前的坐标并且规定mmx-1时不处于窗口移动模式。
……
int j, x, y, mmx -1, mmy -1;
struct SHEET *sht 0;else if (512 i i 767)
{ /* 鼠标数据 */if (mouse_decode(mdec, i - 512) ! 0) {/*按下左键 */mx mdec.x;my mdec.y;if (mx 0) {mx 0;}if (my 0) {my 0;}if (mx binfo-scrnx - 1) {mx binfo-scrnx - 1;}if (my binfo-scrny - 1) {my binfo-scrny - 1;}sheet_slide(sht_mouse, mx, my);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;}} else {/* 没有按下左键 */mmx -1; /* 返回通常模式 */}}
}
虽然代码长了一些但基本没有什么新东西主要还是利用之前已经实现的内容与熟悉的方法。这样就可以通过鼠标移动窗口更有操作系统的样子了。 1.4 用鼠标关闭窗口
有了前面用鼠标切换窗口的基础用鼠标关闭窗口的实现也就顺理成章了。原理基本一致只是需要增加判断鼠标点击的位置范围是否在窗口右上角的X号并根据点击结束程序就可以了。
……
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;}if (sht-bxsize - 21 x x sht-bxsize - 5 5 y y 19) {/* 点击X按钮 */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();}}break;}
}
……1.5 切换输入到应用窗口
现在有了多个应用程序窗口并且像walk这样的应用程序已经可以接受键盘输入了。应该使应用程序的窗口能够切换到输入状态然后通过键盘进行输入。这里仍然通过tab键来切换多个应用程序窗口使用key_win变量保存当前处于输入状态的窗口地址。另外如果应用程序的窗口处于输入状态时被关闭这是就让操作系统自动切换到最上层的窗口。
if (256 i i 511)
{ /* 键盘数据 */
……if (s[0] ! 0) { /* 一般字符 */if (key_win sht_win) { /* 发送给任务A */if (cursor_x 128) {/* 显示一个字符光标后移一位 */s[1] 0;putfonts8_asc_sht(sht_win, cursor_x, 28, COL8_000000, COL8_FFFFFF, s, 1);cursor_x 8;}} else { /* 发送至命令行窗口 */fifo32_put(key_win-task-fifo, s[0] 256);}}if (i 256 0x0e) { /* BackSpace键 */if (key_win sht_win) { /* 发送给任务A */if (cursor_x 8) {/* 空格擦除光标后后移一位 */putfonts8_asc_sht(sht_win, cursor_x, 28, COL8_000000, COL8_FFFFFF, , 1);cursor_x - 8;}} else { /* 发送至命令行窗口 */fifo32_put(key_win-task-fifo, 8 256);}}if (i 256 0x1c) { /* Enter */if (key_win ! sht_win) { /* 发送至任务A */fifo32_put(key_win-task-fifo, 10 256);}}if (i 256 0x0f) { /* Tab */cursor_c keywin_off(key_win, sht_win, cursor_c, cursor_x);j key_win-height - 1;if (j 0) {j shtctl-top - 1;}key_win shtctl-sheets[j];cursor_c keywin_on(key_win, sht_win, cursor_c);}
……
}key_winon与key_winoff两个函数用于控制串口标题栏的颜色与任务A窗口的光标
int keywin_off(struct SHEET *key_win, struct SHEET *sht_win, int cur_c, int cur_x)
{change_wtitle8(key_win, 0);if (key_win sht_win) {cur_c -1; /* 删除光标 */boxfill8(sht_win-buf, sht_win-bxsize, COL8_FFFFFF, cur_x, 28, cur_x 7, 43);} else {if ((key_win-flags 0x20) ! 0) {fifo32_put(key_win-task-fifo, 3); /* 命令行窗口光标OFF */}}return cur_c;
}int keywin_on(struct SHEET *key_win, struct SHEET *sht_win, int cur_c)
{change_wtitle8(key_win, 1);if (key_win sht_win) {cur_c COL8_000000; /* 显示光标 */} else {if ((key_win-flags 0x20) ! 0) {fifo32_put(key_win-task-fifo, 2); /* 命令行窗口光标ON */}}return cur_c;
}通过tab键可以实现窗口输入的切换
1.6 鼠标切换输入窗口
实现鼠标的窗口输入切换只需要再增加一点改动
……
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;}
……}
}2. 定时器API与应用程序
2.1 定时器应用程序
为了编写定时器的应用程序先编写了定时器的API:
_api_alloctimer: ; int api_alloctimer(void);MOV EDX,16INT 0x40RET_api_inittimer: ; void api_inittimer(int timer, int data);PUSH EBXMOV EDX,17MOV EBX,[ESP 8] ; timerMOV EAX,[ESP12] ; dataINT 0x40POP EBXRET_api_settimer: ; void api_settimer(int timer, int time);PUSH EBXMOV EDX,18MOV EBX,[ESP 8] ; timerMOV EAX,[ESP12] ; timeINT 0x40POP EBXRET_api_freetimer: ; void api_freetimer(int timer);PUSH EBXMOV EDX,19MOV EBX,[ESP 8] ; timerINT 0x40POP EBXRET……
else if (edx 16)
{reg[7] (int) timer_alloc();
}
else if (edx 17)
{timer_init((struct TIMER *) ebx, task-fifo, eax 256);
}
else if (edx 18)
{timer_settime((struct TIMER *) ebx, eax);
}
else if (edx 19)
{timer_free((struct TIMER *) ebx);
}
……分别实现了获取定时器、设置定时器的发送数据、设置定时器时间、释放定时器的API。应用程序如下
#include stdio.hint api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title);
void api_putstrwin(int win, int x, int y, int col, int len, char *str);
void api_boxfilwin(int win, int x0, int y0, int x1, int y1, int col);
void api_initmalloc(void);
char *api_malloc(int size);
int api_getkey(int mode);
int api_alloctimer(void);
void api_inittimer(int timer, int data);
void api_settimer(int timer, int time);
void api_end(void);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, noodle);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();
}
实现的效果就是显示时间
2.2 取消定时器
定时器超时时会发送设置好的数据。但如果定时器超时之前应用程序已经退出了定时器超时时会产生什么效果呢 运行定时器程序关闭应用程序。过1秒钟后(产生超时)命令行窗口中会出现一个异常字符。 为了解决这种异常的情况我们需要再应用程序关闭后取消定时器。
首先编写用于取消指定定时器的函数
int timer_cancel(struct TIMER *timer)
{int e;struct TIMER *t;e io_load_eflags();io_cli(); /*设置过程中禁止改变定时器状态 */if (timer-flags TIMER_FLAGS_USING) { /* 是否需要取消 */if (timer timerctl.t0) {/* 取消第一个定时器的处理 */t timer-next;timerctl.t0 t;timerctl.next t-timeout;} else {/* 非第一个定时器的取消处理 *//* 找到timer前的一个定时器 */t timerctl.t0;for (;;) {if (t-next timer) {break;}t t-next;}t-next timer-next; }timer-flags TIMER_FLAGS_ALLOC;io_store_eflags(e);return 1; /* 取消处理成功 */}io_store_eflags(e);return 0; /* 不需要取消处理 */
}在此基础上再来编写应用结束时取消定时器的函数。同时需要在定时器上增加一个标记防止命令行窗口中的光标定时器也被取消
struct TIMER {struct TIMER *next;unsigned int timeout;char flags, flags2;// 增加标志位struct FIFO32 *fifo;int data;
};通常情况下将flags2置为0
struct TIMER *timer_alloc(void)
{int i;for (i 0; i MAX_TIMER; i) {if (timerctl.timers0[i].flags 0) {timerctl.timers0[i].flags TIMER_FLAGS_ALLOC;timerctl.timers0[i].flags2 0;return timerctl.timers0[i];}}return 0;
}对于应用程序申请的定时器将flags2置为1
else if (edx 16)
{reg[7] (int) timer_alloc();((struct TIMER *) reg[7])-flags2 1;
}这样就可以在程序结束取消不需要的定时器了
void timer_cancelall(struct FIFO32 *fifo)
{int e, i;struct TIMER *t;e io_load_eflags();io_cli(); for (i 0; i MAX_TIMER; i) {t timerctl.timers0[i];if (t-flags ! 0 t-flags2 ! 0 t-fifo fifo) {timer_cancel(t);timer_free(t);}}io_store_eflags(e);return;
}运行定时器程序并关闭超时也不会再出现异常字符了。 本篇的内容逻辑清楚代码简单但却使操作系统看起来更像样了。下一篇继续优化命令行窗口敬请期待。