您的位置:首页 > 其它

《30天自制操作系统》读书笔记Day17

2013-10-07 20:16 447 查看
1.创建命令行窗口

把命令行作为一个新的任务加入操作系统。也不再需要B0~B2了。

添加窗体并删掉B0~B2:

sht_cons = sheet_alloc(shtctl);
buf_cons = (unsigned char *) memman_alloc_4k(memman, 256 * 165);
sheet_setbuf(sht_cons, buf_cons, 256, 165, -1); /* 没有透明色 */
make_window8(buf_cons, 256, 165, "console", 0);
make_textbox8(sht_cons, 8, 28, 240, 128, COL8_000000);
task_cons = task_alloc();
task_cons->tss.esp = memman_alloc_4k(memman, 64 * 1024) + 64 * 1024 - 8;
task_cons->tss.eip = (int) &console_task;
task_cons->tss.es = 1 * 8;
task_cons->tss.cs = 2 * 8;
task_cons->tss.ss = 1 * 8;
task_cons->tss.ds = 1 * 8;
task_cons->tss.fs = 1 * 8;
task_cons->tss.gs = 1 * 8;
*((int *) (task_cons->tss.esp + 4)) = (int) sht_cons;
task_run(task_cons, 2, 2); /* level=2, priority=2 */

sheet_slide(sht_back,  0,  0);
sheet_slide(sht_cons, 32,  4);
sheet_slide(sht_win,  64, 56);
sheet_slide(sht_mouse, mx, my);
sheet_updown(sht_back,  0);
sheet_updown(sht_cons,  1);
sheet_updown(sht_win,   2);
sheet_updown(sht_mouse, 3);

然后是命令行任务:

void console_task(struct SHEET *sheet)
{
struct FIFO32 fifo;
struct TIMER *timer;
struct TASK *task = task_now();

int i, fifobuf[128], cursor_x = 8, cursor_c = COL8_000000;
fifo32_init(&fifo, 128, fifobuf, task);

timer = timer_alloc();
timer_init(timer, &fifo, 1);
timer_settime(timer, 50);

for (;;) {
io_cli();
if (fifo32_status(&fifo) == 0) {
task_sleep(task);
io_sti();
} else {
i = fifo32_get(&fifo);
io_sti();
if (i <= 1) { //光标用定时器
if (i != 0) {
timer_init(timer, &fifo, 0);
cursor_c = COL8_FFFFFF;
} else {
timer_init(timer, &fifo, 1);
cursor_c = COL8_000000;
}
timer_settime(timer, 50);
boxfill8(sheet->buf, sheet->bxsize, cursor_c, cursor_x, 28, cursor_x + 7, 43);
sheet_refresh(sheet, cursor_x, 28, cursor_x + 8, 44);
}
}
}
}

这样就将窗口创建好了。但是现在激活的窗口还是任务A的窗口,想要在按Tab键时将命令行窗口激活。

其实切换窗口就是让窗口标题栏的颜色更改。

将窗口标题栏描绘代码和描绘窗口剩余部分的代码分开:

void make_window8(unsigned char *buf, int xsize, int ysize, char *title, char act)
{
boxfill8(buf, xsize, COL8_C6C6C6, 0,         0,         xsize - 1, 0        );
boxfill8(buf, xsize, COL8_FFFFFF, 1,         1,         xsize - 2, 1        );
boxfill8(buf, xsize, COL8_C6C6C6, 0,         0,         0,         ysize - 1);
boxfill8(buf, xsize, COL8_FFFFFF, 1,         1,         1,         ysize - 2);
boxfill8(buf, xsize, COL8_848484, xsize - 2, 1,         xsize - 2, ysize - 2);
boxfill8(buf, xsize, COL8_000000, xsize - 1, 0,         xsize - 1, ysize - 1);
boxfill8(buf, xsize, COL8_C6C6C6, 2,         2,         xsize - 3, ysize - 3);
boxfill8(buf, xsize, COL8_848484, 1,         ysize - 2, xsize - 2, ysize - 2);
boxfill8(buf, xsize, COL8_000000, 0,         ysize - 1, xsize - 1, ysize - 1);
make_wtitle8(buf, xsize, title, act);
return;
}

void make_wtitle8(unsigned char *buf, int xsize, char *title, char act)
{
static char closebtn[14][16] = {
"OOOOOOOOOOOOOOO@",
"OQQQQQQQQQQQQQ$@",
"OQQQQQQQQQQQQQ$@",
"OQQQ@@QQQQ@@QQ$@",
"OQQQQ@@QQ@@QQQ$@",
"OQQQQQ@@@@QQQQ$@",
"OQQQQQQ@@QQQQQ$@",
"OQQQQQ@@@@QQQQ$@",
"OQQQQ@@QQ@@QQQ$@",
"OQQQ@@QQQQ@@QQ$@",
"OQQQQQQQQQQQQQ$@",
"OQQQQQQQQQQQQQ$@",
"O$$$$$$$$$$$$$$@",
"@@@@@@@@@@@@@@@@"
};
int x, y;
char c, tc, tbc;
if (act != 0) {
tc = COL8_FFFFFF;
tbc = COL8_000084;
} else {
tc = COL8_C6C6C6;
tbc = COL8_848484;
}
boxfill8(buf, xsize, tbc, 3, 3, xsize - 4, 20);
putfonts8_asc(buf, xsize, 24, 4, tc, title);
for (y = 0; y < 14; y++) {
for (x = 0; x < 16; x++) {
c = closebtn[y][x];
if (c == '@') {
c = COL8_000000;
} else if (c == '$') {
c = COL8_848484;
} else if (c == 'Q') {
c = COL8_C6C6C6;
} else {
c = COL8_FFFFFF;
}
buf[(5 + y) * xsize + (xsize - 21 + x)] = c;
}
}
return;
}

接着修改bootpack.c:

if (i == 256 + 0x0f) /* Tab */
{
if (key_to == 0) //key_to用于记录键盘数据发送到哪个窗口
{
key_to = 1;
make_wtitle8(buf_win,  sht_win->bxsize,  "task_a",  0);
make_wtitle8(buf_cons, sht_cons->bxsize, "console", 1);
}
else
{
key_to = 0;
make_wtitle8(buf_win,  sht_win->bxsize,  "task_a",  1);
make_wtitle8(buf_cons, sht_cons->bxsize, "console", 0);
}
sheet_refresh(sht_win,  0, 0, sht_win->bxsize,  21);
sheet_refresh(sht_cons, 0, 0, sht_cons->bxsize, 21);
}

2.实现命令行中字符串的输入

要实现命令行字符的输入,只需要在按键时向命令行任务发送FIFO数据即可。为了方便,把FIFO结构体放在TASK中:

struct TASK {
int sel, flags; //sel用于存放GDT的编号
struct TSS32 tss;
int priority;	//优先级
int level;
struct FIFO32 fifo;
};

接下来修改HariMain,根据key_to的值向task_cons的FIFO发送数据:

if (i <= 511 && i >=256) //键盘数据
{
sprintf(s, "%02X", i - 256);
putfonts8_asc_sht(sht_back, 0, 16, COL8_FFFFFF, COL8_008484, s, 2);
if (i < 256 + 0x54 && keytable[i - 256] != 0)//一般字符
{
if (key_to == 0)	//发送给任务A
{
if (cursor_x < 128)
{
s[0] = keytable[i - 256 ];
s[1] = 0;
putfonts8_asc_sht(sht_win, cursor_x, 28, COL8_000000, COL8_FFFFFF, s, 1);
cursor_x += 8;
}

}
else 	//发送到命令行
{
fifo32_put(&task_cons->fifo, keytable[i-256]+256);
}
}
if (i == 256 + 0x0e )	//退格
{
if (key_to ==0)//任务A
{
if (cursor_x > 8)
{
putfonts8_asc_sht(sht_win, cursor_x, 28, COL8_000000, COL8_FFFFFF, " ", 1);
cursor_x -= 8;
}
}
else
fifo32_put(&task_cons->fifo, 8 + 256);

}
if (i == 256 + 0x0f) /* Tab */
{
if (key_to == 0)
{
key_to = 1;
make_wtitle8(buf_win,  sht_win->bxsize,  "task_a",  0);
make_wtitle8(buf_cons, sht_cons->bxsize, "console", 1);
}
else
{
key_to = 0;
make_wtitle8(buf_win,  sht_win->bxsize,  "task_a",  1);
make_wtitle8(buf_cons, sht_cons->bxsize, "console", 0);
}
sheet_refresh(sht_win,  0, 0, sht_win->bxsize,  21);
sheet_refresh(sht_cons, 0, 0, sht_cons->bxsize, 21);
}
//光标再显示
boxfill8(sht_win->buf, sht_win->bxsize, cursor_c, cursor_x, 28, cursor_x + 7, 43);
sheet_refresh(sht_win, cursor_x, 28, cursor_x + 8, 44);

}

然后修改console_task让它能够接收并处理键盘数据,并且把&fifo改成&task->fifo:

void console_task(struct SHEET *sheet)
{
struct TIMER *timer;
struct TASK *task = task_now();
int i, fifobuf[128], cursor_x = 16, cursor_c = COL8_000000;
char s[2];

fifo32_init(&task->fifo, 128, fifobuf, task);

timer = timer_alloc();
timer_init(timer, &task->fifo, 1);
timer_settime(timer, 50);

//显示提示符
putfonts8_asc_sht(sheet, 8, 28, COL8_FFFFFF, COL8_000000, ">", 1);

for (;;) {
io_cli();
if (fifo32_status(&task->fifo) == 0) {
task_sleep(task);
io_sti();
} else {
i = fifo32_get(&task->fifo);
io_sti();
if (i <= 1)
{ //光标用定时器
if (i != 0)
{
timer_init(timer, &task->fifo, 0);
cursor_c = COL8_FFFFFF;
}
else
{
timer_init(timer, &task->fifo, 1);
cursor_c = COL8_000000;
}
timer_settime(timer, 50);
}
if (256 <= i && i <=511)//键盘数据
{
if (i == 8 + 256)
{
if (cursor_x > 16)
{
putfonts8_asc_sht(sheet, cursor_x, 28, COL8_FFFFFF, COL8_000000, " ", 1);
cursor_x -= 8;
}
}
else
{
if (cursor_x < 240)
{
s[0] = i - 256;
s[1] = 0;
putfonts8_asc_sht(sheet, cursor_x, 28, COL8_FFFFFF, COL8_000000, s, 1);
cursor_x += 8;
}
}
}
boxfill8(sheet->buf, sheet->bxsize, cursor_c, cursor_x, 28, cursor_x + 7, 43);
sheet_refresh(sheet, cursor_x, 28, cursor_x + 8, 44);

}
}
}

运行系统,按Tab键后即可在命令行窗口中进行输入。

接下来实现shift按键输入其他符号功能。

运行系统发现shift的按键编码如下:

按下		抬起
左shift		0x2a		0xaa
右shift		0x36		0xb

准备一个key_shift变量记录shift状态,并且使用两个按键编码到字符编码的转换表(分别用于按下时与不按时)。

static char keytable0[0x80] = {
0,   0,   '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', 0,   0,
'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '[', ']', 0,   0,   'A', 'S',
'D', 'F', 'G', 'H', 'J', 'K', 'L', ';', '\'', '`',   0,   '\\', 'Z', 'X', 'C', 'V',
'B', 'N', 'M', ',', '.', '/', 0,   '*', 0,   ' ', 0,   0,   0,   0,   0,   0,
0,   0,   0,   0,   0,   0,   0,   '7', '8', '9', '-', '4', '5', '6', '+', '1',
'2', '3', '0', '.', 0,   0,   0,   0,    0,   0,   0,   0,   0,   0,   0,   0,
0,    0,   0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,   0,   0,   0,
0,    0,   0,   0x5c,0,   0,   0,   0,    0,   0,   0,   0,   0,   0x5c,   0,   0,
};
static char keytable1[0x80] = {
0,   0,   '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '-', '=', 0,   0,
'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', 0,   0,   'A', 'S',
'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '\"', '~',   0,   '|', 'Z', 'X', 'C', 'V',
'B', 'N', 'M', '<', '>', '?', 0,   '*', 0,   ' ', 0,   0,   0,   0,   0,   0,
0,   0,   0,   0,   0,   0,   0,   '7', '8', '9', '-', '4', '5', '6', '+', '1',
'2', '3', '0', '.', 0,   0,   0,   0,    0,   0,   0,   0,   0,   0,   0,   0,
0,    0,   0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,   0,   0,   0,
0,    0,   0,   0x5c,0,   0,   0,   0,    0,   0,   0,   0,   0,   0x5c,   0,   0,
};
int key_shift = 0;
if (i <= 511 && i >=256) //键盘数据
{
sprintf(s, "%02X", i - 256);
putfonts8_asc_sht(sht_back, 0, 16, COL8_FFFFFF, COL8_008484, s, 2);
if (i < 0x80 + 256)
{
if (key_shift ==0)
{
s[0] = keytable0[i - 256];
}
else
s[0] = keytable1[i - 256];
}
else
s[0] = 0;
if (s[0] != 0)
{
if (key_to == 0)	//发送给任务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(&task_cons->fifo, s[0] + 256);
}
}

if (i == 256 + 0x0e )	//退格
{
if (key_to ==0)//任务A
{
if (cursor_x > 8)
{
putfonts8_asc_sht(sht_win, cursor_x, 28, COL8_000000, COL8_FFFFFF, " ", 1);
cursor_x -= 8;
}
}
else
fifo32_put(&task_cons->fifo, 8 + 256);

}
if (i == 256 + 0x0f) /* Tab */
{
if (key_to == 0)
{
key_to = 1;
make_wtitle8(buf_win,  sht_win->bxsize,  "task_a",  0);
make_wtitle8(buf_cons, sht_cons->bxsize, "console", 1);
}
else
{
key_to = 0;
make_wtitle8(buf_win,  sht_win->bxsize,  "task_a",  1);
make_wtitle8(buf_cons, sht_cons->bxsize, "console", 0);
}
sheet_refresh(sht_win,  0, 0, sht_win->bxsize,  21);
sheet_refresh(sht_cons, 0, 0, sht_cons->bxsize, 21);
}
if (i == 256 + 0x2a) //左shift按下
{
key_shift |= 1;
}
if (i == 256 + 0x36) //右shift按下
{
key_shift |= 2;
}
if (i == 256 + 0xaa) //左shift松开
{
key_shift &= ~1;
}
if (i == 256 + 0xb6) //右shift松开
{
key_shift &= ~2;
}
//光标再显示
boxfill8(sht_win->buf, sht_win->bxsize, cursor_c, cursor_x, 28, cursor_x + 7, 43);
sheet_refresh(sht_win, cursor_x, 28, cursor_x + 8, 44);

}

运行即可实现键盘上基本所有符号的输入。

最后,尝试实现大小写。

已知大小写规则如下:

CapsLock 为 OFF & Shift 为 OFF --> 小写英文字母
CapsLock 为 ON  & Shift 为 ON  --> 小写英文字母
CapsLock 为 OFF & Shift 为 ON  --> 大写英文字母
CapsLock 为 ON  & Shift 为 OFF --> 大写英文字母

即CapsLock和Shift状态相同时输入小写,其余为大写。

CapsLock状态已经通过asmhead.nas获取,保存在binfo->leds中:

binfo->leds 第4位   ----->ScrollLock状态
binfo->leds 第5位   ----->NumLockLock状态
binfo->leds 第6位   ----->CapsLock状态

修改HariMain以实现小写输入:

int key_leds = (binfo->leds >> 4) & 7;

if ('A' <= s[0] && s[0] <= 'Z')
{
if (((key_leds & 4) == 0 && key_shift == 0) || ((key_leds & 4) != 0 && key_shift != 0))
{
s[0] += 0x20;//将大写字母转换为小写
}
}

3.对锁定键的支持

前面已经能够读取大小写锁定的状态了,这里尝试对3种锁定的支持。这里不具体描述步骤了,太麻烦了,上传了一份文件:i8042_键盘.pdf

#define KEYCMD_LED		0xed		/* 需要发送的LED数据 */

struct FIFO32 keycmd;	/* 用来存放向键盘发送的命令 */
int keycmd_buf[32];
int keycmd_wait = -1;
fifo32_init(&keycmd, 32, keycmd_buf, 0);	/* 初始化键盘命令缓冲区 */

/* 为了避免和键盘当前状态冲突,在一开始先进行设置 */
fifo32_put(&keycmd, KEYCMD_LED);
fifo32_put(&keycmd, key_leds);
/* 所有对键盘LED的设置都是对键盘中的一块芯片8048的设置 */
/* 不是以前设置的i8042,但是通过i8042间接的对8048进行设置 */
/* 详见我上传的资源:i8042_键盘.pdf
*/

if (fifo32_status(&keycmd) > 0 && keycmd_wait < 0)
{
/* 如果存在要向键盘发生的数据,则发送它 */
keycmd_wait = fifo32_get(&keycmd);	/* 取出数据 */
wait_KBC_sendready();	/* 清空i8042的输入缓冲区 */
io_out8(PORT_KEYDAT, keycmd_wait);	/* 向0x60端口发生0xed */
/* 发生了该命令之后,需要继续向0x60端口发生LED设置字节 */
/* 在下面等待确认是否有按下控制LED灯的键后来决定LED设置字节的值,然后再发生 */
}

if (i == 256 + 0x3a)
{	/* CapsLock */
key_leds ^= 4;		/* key_leds中标识CapsLock的bit位取反 */
fifo32_put(&keycmd, KEYCMD_LED);	/* 向i8042发生命令来修改8048 */
fifo32_put(&keycmd, key_leds);		/* 改变CapsLock等的状态 */
}
if (i == 256 + 0x45)
{	/* NumLock */
key_leds ^= 2;		/* 和CapsLock类似的处理 */
fifo32_put(&keycmd, KEYCMD_LED);
fifo32_put(&keycmd, key_leds);
}
if (i == 256 + 0x46)
{	/* ScrollLock */
key_leds ^= 1;		/* 和CapsLock类似的处理 */
fifo32_put(&keycmd, KEYCMD_LED);
fifo32_put(&keycmd, key_leds);
}
/* 0xfa是ACK信息 */
if (i == 256 + 0xfa)
{	/* 键盘成功接收到数据 */
keycmd_wait = -1;	/* 等于-1表示可以发送指令 */
}
if (i == 256 + 0xfe)
{	/* 键盘没有成功接收到数据 */
wait_KBC_sendready();
io_out8(PORT_KEYDAT, keycmd_wait);	/* 重新发送上次的指令 */
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: