您的位置:首页 > 其它

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

2013-10-27 15:26 316 查看
GitHub地址:https://github.com/scusjs/

1.控制光标闪烁

运行前面的系统发现不管当前的焦点在哪个窗口,两个窗口光标都在闪烁。。这算是一个bug吧。

对于A任务,当其不是焦点时,将其cursor_c设置为-1,则其不显示光标;是焦点时,重新设置为COL_00000000,然后重新显示光标的时候进行判断:

if (cursor_c >= 0 )
{
boxfill8(sht_win->buf, sht_win->bxsize, cursor_c, cursor_x, 28, cursor_x + 7, 43);
}

最后在光标用计时器中,将所有的光标变化加上判断语句:

if(cursor_c >= 0){}即可。

对于命令窗口,由于不能直接获得HariMain中是否显示光标的值,所以使用FIFO来实现。

将光标开始闪烁定义为2,停止闪烁定义为3:

fifo32_put(&task_cons->fifo, 2);//命令行窗口光标ON
fifo32_put(&task_cons->fifo, 3);//命令行窗口光标OFF

接着修改console_task:

由于系统启动时任务A处于焦点状态,所以这里的cursor_c默认为-1

其他地方每次cursor_c变化时都判断一下if (cursor_c >= 0 ),并加上如下对cursor_c的操作:

i = fifo32_get(&task->fifo);
。。。。。
if (i == 2)//光标ON
{
cursor_c = COL8_FFFFFF;
}
if (i == 3)//光标OFF
{
boxfill8(sheet->buf, sheet->bxsize, COL8_000000, cursor_x, 28, cursor_x + 7, 43);
cursor_c = -1;
}

运行即可。

2.对回车的支持

目前位置程序还不能识别回车的。要相应回车,只要识别出来并换行,并识别输入字符,如果是输入命令则执行。但是现在先实现换行即可。

修改HariMain,当回车被按下时向命令行发送10+256(自己定义,可以是其他值):

if (i == 256 + 0x1c)//回车键
{
if (key_to != 0)
{
fifo32_put(&task_cons->fifo, 10 + 256);
}
}

然后在console_task中创建变量cursor_y变量,当回车按下则加1行(16)即可:

else if (i == 10 + 256) //回车键
{
if (cursor_y < 28 +112)//用空格擦除光标
{
putfonts8_asc_sht(sheet, cursor_x, cursor_y, COL8_FFFFFF, COL8_000000, " ", 1);
cursor_y += 16;
//显示提示符
putfonts8_asc_sht(sheet, 8, cursor_y, COL8_FFFFFF, COL8_000000, ">", 1);
cursor_x = 16;

}
}

并在所有对光标相关操作那里将28改为cursor_y即可(注意:需要将其他涉及到的数值更改,比如44改为cursor_y + 16)。

最后,实现滚屏操作。

当到达最后一行时,继续回车则所有像素上移一行,并将最后一行涂黑即可。

首先定义int型的x,y,用来对所有的像素进行上移操作,将回车键处理过程修改成如下:

else if (i == 10 + 256) //回车键
{
putfonts8_asc_sht(sheet, cursor_x, cursor_y, COL8_FFFFFF, COL8_000000, " ", 1);//用空格擦除光标
if (cursor_y < 28 +112)
{

cursor_y += 16;

}
else//滚屏
{
for (y = 28; y < 28 + 128; y++)
{
for (x = 8; x < 8 + 240; x++)
{
sheet->buf[x + y * sheet->bxsize] = sheet->buf[x + (y + 16) * sheet->bxsize];//所有像素上移
}
}
for (y = 28 + 112; y < 28 + 128; y++)
{
for (x = 8; x < 8 + 240; x++)
{
sheet->buf[x + y * sheet->bxsize] = COL8_000000;//最后一行进行涂黑
}
}
sheet_refresh(sheet, 8, 28, 8 + 240, 28 + 128);
}
//显示提示符
putfonts8_asc_sht(sheet, 8, cursor_y, COL8_FFFFFF, COL8_000000, ">", 1);
cursor_x = 16;
}

3.mem命令

搞定滚屏,尝试实现第一个命令行的命令——mem。

首先,注释掉前面在屏幕上显示的一些系统基本信息。

然后在console_task中实现命令。

void console_task(struct SHEET *sheet, unsigned int memtotal)
{
struct TIMER *timer;
struct TASK *task = task_now();
int i, fifobuf[128], cursor_x = 16, cursor_c = -1,cursor_y = 28;
char s[30],cmdline[30];
struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR;
int x,y;

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);
if (cursor_c >= 0)
{
cursor_c = COL8_FFFFFF;
}

}
else
{
timer_init(timer, &task->fifo, 1);
if (cursor_c >= 0)
{
cursor_c = COL8_000000;
}

}
timer_settime(timer, 50);
}
if (i == 2)//光标ON
{
cursor_c = COL8_FFFFFF;
}
if (i == 3)//光标OFF
{
boxfill8(sheet->buf, sheet->bxsize, COL8_000000, cursor_x, cursor_y, cursor_x + 7, cursor_y + 15);
cursor_c = -1;
}
if (256 <= i && i <=511)//键盘数据
{
if (i == 8 + 256) //退格键
{
if (cursor_x > 16)
{
putfonts8_asc_sht(sheet, cursor_x, cursor_y, COL8_FFFFFF, COL8_000000, " ", 1);
cursor_x -= 8;
}
}
else if (i == 10 + 256) //回车键
{
putfonts8_asc_sht(sheet, cursor_x, cursor_y, COL8_FFFFFF, COL8_000000, " ", 1);//用空格擦除光标
cmdline[cursor_x /8 - 2] = 0;
cursor_y = cons_newline(cursor_y, sheet);
//执行命令
if (strcmp(cmdline, "mem") == 0)
{
sprintf(s, "total %dMB", memtotal / (1024 * 1024));
putfonts8_asc_sht(sheet, 8, cursor_y, COL8_FFFFFF, COL8_000000, s, 30);
cursor_y = cons_newline(cursor_y, sheet);
sprintf(s, "free %dKB", memman_total(memman) / 1024);
putfonts8_asc_sht(sheet, 8, cursor_y, COL8_FFFFFF, COL8_000000, s, 30);
cursor_y = cons_newline(cursor_y, sheet);
cursor_y = cons_newline(cursor_y, sheet);
}
else if (cmdline[0] != 0)//错误命令
{
putfonts8_asc_sht(sheet, 8, cursor_y, COL8_FFFFFF, COL8_000000, "Bad command.", 12);
cursor_y = cons_newline(cursor_y, sheet);
cursor_y = cons_newline(cursor_y, sheet);
}
//显示提示符
putfonts8_asc_sht(sheet, 8, cursor_y, COL8_FFFFFF, COL8_000000, ">", 1);
cursor_x = 16;
}
else
{
if (cursor_x < 240)
{
s[0] = i - 256;
s[1] = 0;
cmdline[cursor_x / 8 - 2] = i - 256;
putfonts8_asc_sht(sheet, cursor_x, cursor_y, COL8_FFFFFF, COL8_000000, s, 1);
cursor_x += 8;
}
}
}
if (cursor_c >= 0)
{
boxfill8(sheet->buf, sheet->bxsize, cursor_c, cursor_x, cursor_y, cursor_x + 7, cursor_y + 15);
}

sheet_refresh(sheet, cursor_x, cursor_y, cursor_x + 8, cursor_y + 16);

}
}
}
int cons_newline(int cursor_y, struct SHEET *sheet)
/* 换行处理 */
{
int x, y;
if (cursor_y < 28 + 112)
{
cursor_y += 16;
} else
{
//滚屏
for (y = 28; y < 28 + 112; y++) {
for (x = 8; x < 8 + 240; x++) {
sheet->buf[x + y * sheet->bxsize] = sheet->buf[x + (y + 16) * sheet->bxsize];
}
}
for (y = 28 + 112; y < 28 + 128; y++) {
for (x = 8; x < 8 + 240; x++) {
sheet->buf[x + y * sheet->bxsize] = COL8_000000;
}
}
sheet_refresh(sheet, 8, 28, 8 + 240, 28 + 128);
}
return cursor_y;
}


最后在HariMain中修改使memtotal参数传入console_task:
task_cons->tss.esp = memman_alloc_4k(memman, 64 * 1024) + 64 * 1024 - 12;
*((int *) (task_cons->tss.esp + 8)) = memtotal;

运行即可实现mem命令的输入与错误命令的识别。

4.cls(clear)命令

cls、clear命令分别是Windows、Linux平台下对命令行、终端进行清屏工作的命令。

这个命令实质上是把整个窗口涂黑,然后把cursor_y重置为28:

else if ((strcmp(cmdline, "cls") == 0) || (strcmp(cmdline, "clear") == 0))
{
for (y = 28; y < 28 + 128; y ++)
{
for (x = 8; x < 8 + 240; x ++)
{
sheet->buf[x + y * sheet->bxsize] = COL8_000000;
}
}
sheet_refresh(sheet, 8, 28, 8 + 240, 28 + 128);
cursor_y = 28;
}

5.dir(ls)命令

dir、ls命令分别为Windows、Linux平台下列出目录下文件命令。

在day3中已经实现从磁盘读取10个柱面的内容,这些内容中存放文件的数据放在了0x002600以后的位置。

这里先考虑把dogged.sys、ipl10.nas、make.bat这三个文件放入磁盘中,修改Makefile:

dogged.img : ipl10.bin dogged.sys Makefile
$(EDIMG)   imgin:../z_tools/fdimg0at.tek \
wbinimg src:ipl10.bin len:512 from:0 to:0 \
copy from:dogged.sys to:@: \
copy from:ipl10.nas to:@: \
copy from:make.bat to:@: \
imgout:dogged.img

make后可以从img文件中看到,在0x002600开始,显示的是32字节为单位的文件名,这32字节的结构如下:

struct FILEINFO {
unsigned char name[8],ext[3],type;
char reserve[10];
unsigned short time,date,clustno;
unsigned int size;
};

如果文件名第一字节为0xe5,表示已经被删除

如果文件名第一字节为0x00,表示这一段不包含文件名信息

属性信息中:

0x01	只读文件
0x01	隐藏文件
0x04	系统文件
0x08	非文件信息
0x10	目录

接下来就是实现命令了:

struct FILEINFO *finfo = (struct FILEINFO *) (ADR_DISKIMG + 0x002600);
。。。
else if ((strcmp(cmdline, "dir") == 0) || (strcmp(cmdline, "ls") == 0))
{
for (x = 0; x < 224; x++)//最多允许224个文件
{
if (finfo[x].name[0] == 0x00)
{
break;
}
if (finfo[x].name[0] != 0xe5)
{
if ((finfo[x].type & 0x18) == 0)
{
sprintf(s, "filename.ext %7d", finfo[x].size);
for (y = 0; y < 8; y++)
{
s[y] = finfo[x].name[y];
}
s[9] = finfo[x].ext[0];
s[10] = finfo[x].ext[1];
s[11] = finfo[x].ext[2];
putfonts8_asc_sht(sheet, 8, cursor_y, COL8_FFFFFF, COL8_000000, s, 30);
cursor_y = cons_newline(cursor_y, sheet);
}
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: