自制操作系统日志——第十四天
今天主要的任务是给我们的分辨率升升级!然后,将继续开发出一个输入栏,以供我们随意的进行输入并删除数据。
前言
在前面几天呢,我们总是能看到我们再进行不断的优化代码,不断的加快一下中断的执行速度!这一些如此细微的改动,也许我们可能会觉得没什么必要。但是,要知道随着我们后面不断的开发,以及多任务下更多程序的介入,我们之前所作的一些优化的效果将会越来越重要。就比如,我们对于中断速度的优化,在后期当同时一很多中断发生时,这些优化后精进的速度,将会使得我们系统的反应能力大幅度的提高!!!
接着,我们已经大约度过了两周的时间了!!前两周我们对于开发操作系统所需的编程语言的学习呀,算法技巧的学习呀等等都已经大致的学完了。那么,此后就可以好好的利用其前面所学的继续我们的完善之路。然后,就是说前面13天的内容也是十分的重要且有意义的,希望我能够继续好好的多品味品味!!!
一、提高分辨率
在这之前我们使用的显卡模式主要是VGA模式,其分辨率主要是320x200x8的模式!!那么这一个分辨率明显是有所不足的!因此啊,下面我们将利用VBE模式下进行设置!
首先,VBE是多家显卡公司一起协商制定的统一显卡的设定标准。他们专门的制作了一个BIOS进行设定,以此来解决不同显卡设定、接口不同的问题。因此,以下我可能会使用VBE2.0以上的BIOS显卡设定,如果真机(vmware)不支持此类设定的话,那就只能继续使用VGA显卡了!
非VBE画面模式的设定:
AH=0; 调用0号子中断程序
AL = 画面模式号码
VBE画面模式的设定:
AX = 0x4f02
BX = 画面模式的设定
画面模式设定信息:
0x101 ⇒ 640x480x8
0x103 ⇒ 800x600x8
0x105 ⇒ 1024x768x8
0x107 ⇒ 1280x1024x8
在实际设定时一般还要加上0x4000后再赋值到bx中。
画面模式的存储信息内容:
word [es:di + 0x00] ⇒ 模式属性 …其中存储的bit7(第七位)上如果是1 则代表可以加上0x4000后进行传入!!!
word [es:di + 0x12] ⇒ x的分辨率
word [es:di + 0x14] ⇒ y的分辨率
byte [es:di + 0x19] ⇒ 颜色数…必须是8
byte [es:di + 0x1b] ⇒ 颜色指定方法,必须是4 (4 指调色板模式)
dword [es:di + 0x12] ⇒ VRAM地址
其中,es的段地址应该是:0x9000
那么以下,就让我们开始修改asmhead.nas:
我们主要做如下的工作:以下所采用中断后,读取的信息都会存入到90000:0000之中!
- 确认VBE是否存在,通过调用int 0x10 以及利用ax值是否改变进行确认;
- 确认版本,通过读取1中存取的信息来进行比较;
- 读取画面模式,并存入对应的内存之中;
- 进行画面模式的确认,确认颜色数是否为8,是否为调色版模式,是否模式属性的bit7位置上是1;
- 进行画面的切换;
- 如果以上有一个不行就跳转到此,恢复VGA 320x200x8模式
[INSTRSET "i486p"]
VBEMODE EQU 0x105
ORG 0xc200 ;程序最终被装载到内存的地址
;即0x8000+0x4200=0xc2000;0x8000是内存存放软盘的地址,0x4200是软盘存放文件的地方
;确认VBE是否存在
MOV AX,0x9000
MOV ES,AX
MOV DI,0
MOV AX,0X4f00;有vbe的话值会自动编程0x004f
INT 0x10 ;取得的数据也是放在es:di中
CMP AX,0x004f
JNE scrn320
;确认VBE版本,非2.0版本不能使用高分辨率
MOV AX,[ES:DI+4]
CMP AX,0x0200
JB scrn320
;取得画面模式信息,这里的数据将会被放在es:di开始的256字节中
MOV CX,VBEMODE
MOV AX,0x4f01
INT 0x10
CMP AX,0x004f
JNE scrn320
;画面模式信息确认
CMP BYTE [ES:DI+0x19],8
JNE scrn320
CMP BYTE [ES:DI+0x1b],4
JNE scrn320
MOV AX,[ES:DI+0x00]
AND AX,0x0080
JZ scrn320
;画面模式切换
MOV BX,VBEMODE+0x4000
mov AX,0x4f02 ;
int 0x10
mov byte [VMODE],8 ; 屏幕的模式(参考C语言的引用)
MOV AX,[ES:DI+0x12]
MOV [SCRNX],AX
MOV AX,[ES:DI+0x14]
MOV [SCRNY],AX
MOV EAX,[ES:DI+0x28]
MOV [VRAM],EAX
JMP keystatus
scrn320:
MOV AL,0x13 ; VGA模式, 320x200
MOV AH,0x00
INT 0x10
MOV BYTE [VMODE],8 ; 记下画面模式,参考c
MOV WORD [SCRNX],320
MOV WORD [SCRNY],200
MOV DWORD [VRAM],0x000a0000
keystatus:
;用BIOS取得键盘上各种LED指示灯的状态
mov ah,0x02
int 0x16 ;键盘BIOS
mov [LEDS],al
然后,让我们make run一下看看!!
很棒,明显vmwar是支持的,那么至此我们就可以进入高分辨率的模式了!!!
二、增加键盘输入字符功能
1.输入单个字符
首先,我们打开该系统,可以发现再我们之前所作的设置里,当我们按下键盘的a时,按下是弹出1E,按起后弹出的就是9e。在书本里作者给我们罗列了很多按下键时的值。然后我们只需在此基础上+0x80就为按其后的值了!!
之所以会有两个值,也是因为方便告诉计算机:我按下了这个键,以及我松开了这个键。方便计算机知道什么时候开始,什么时候结束!!
然后,针对此我们进行更改一下主函数:
if (fifo32_status(&fifo) == 0)
{
io_stihlt();
}else
{
i = fifo32_get(&fifo);
io_sti();
if (256 <= i && i <= 511) { /*键盘数据 */
sprintf(s, "%02X", i - 256);
putfonts8_asc_sht(sht_back, 0, 16, COL8_FFFFFF, COL8_008484, s, 2);
if( i == 0x1e + 256)
{
putfonts8_asc_sht(sht_win, 40, 28, COL8_000000, COL8_C6C6C6, "A", 1);
}
哇哦,成功了!!
那么,继续再接再励,做一个输入框,然后可以任意输入数据并删除输入吧!!
2.输入框制作
根据上述的按下时的字符编码,我们在主函数中制作如下的数据:
static char keytable[0x54] = {
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, 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', '.'
};
然后进一步的我们增加输入框以及实现输入删除的功能:(这其中涉及了光标的显示)
int mx,my,i, cursor_x, cursor_c ;
略
make_textbox8(sht_win, 8, 28, 144, 16, COL8_FFFFFF);
for(;;)
{
io_cli(); //IF=0
if (fifo32_status(&fifo) == 0)
{
io_stihlt();
}else
{
i = fifo32_get(&fifo);
io_sti();
if (256 <= i && i <= 511) { /*键盘数据 */
sprintf(s, "%02X", i - 256);
putfonts8_asc_sht(sht_back, 0, 16, COL8_FFFFFF, COL8_008484, s, 2);
if( i < 0x54 + 256)
{
if(keytable[i-256] != 0 && cursor_x < 144) //一般字符
{//显示一个字符光标就向前移动一次
s[0] = keytable[i-256];
s[1] = 0;
putfonts8_asc_sht(sht_win, cursor_x, 28, COL8_000000, COL8_C6C6C6, s, 1);
cursor_x +=8;
}
if(i == 256 + 0x0e && cursor_x > 8) //退格键
{//用空格把光标消去后移动一次
putfonts8_asc_sht(sht_win, cursor_x, 28, COL8_000000, COL8_FFFFFF, " ", 1);
cursor_x -=8;
}
//光标在显示
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);
}
然后是输入框的代码:
//x0,y0是起始位置 ,sx是长度,sy是宽度
void make_textbox8(struct SHEET *sht, int x0, int y0, int sx, int sy, int c)
{
int x1 = x0 + sx, y1 = y0 + sy;
boxfill8(sht->buf, sht->bxsize, COL8_848484, x0 - 2, y0 - 3, x1 + 1, y0 - 3);
boxfill8(sht->buf, sht->bxsize, COL8_848484, x0 - 3, y0 - 3, x0 - 3, y1 + 1);
boxfill8(sht->buf, sht->bxsize, COL8_FFFFFF, x0 - 3, y1 + 2, x1 + 1, y1 + 2);
boxfill8(sht->buf, sht->bxsize, COL8_FFFFFF, x1 + 2, y0 - 3, x1 + 2, y1 + 2);
boxfill8(sht->buf, sht->bxsize, COL8_000000, x0 - 1, y0 - 2, x1 + 0, y0 - 2);
boxfill8(sht->buf, sht->bxsize, COL8_000000, x0 - 2, y0 - 2, x0 - 2, y1 + 0);
boxfill8(sht->buf, sht->bxsize, COL8_C6C6C6, x0 - 2, y1 + 1, x1 + 0, y1 + 1);
boxfill8(sht->buf, sht->bxsize, COL8_C6C6C6, x1 + 1, y0 - 2, x1 + 1, y1 + 1);
boxfill8(sht->buf, sht->bxsize, c, x0 - 1, y0 - 1, x1 + 0, y1 + 0);
return;
}
三、增加拖动窗口功能
这里我们先简单制作一个拖动窗口的功能,即按下鼠标左键就会显示窗口的位置!!
这里由于我们之前已经利用过图层来显示了,因此,这里的拖动,我们仅仅只需将图层位置和鼠标关联一下即可:
略
if (my > binfo->scrny - 1) {
my = binfo->scrny - 1;
}
sprintf(s, "(%3d, %3d)", mx, my);
putfonts8_asc_sht(sht_back, 0, 0, COL8_FFFFFF, COL8_008484, s, 10);
sheet_slide(sht_mouse, mx, my);
if((mdec.btn & 0x01) != 0)//按下左键,移动窗口
{
sheet_slide(sht_win, mx - 80, my - 8);
}
总结
以上就是我们今天进行内容,主要就是将分辨率进行了提高,然后还利用图层技术实现了简单的拖动功能!!!以及字符串的输入等等。
已经越来越像一个小型的操作系统了,继续努力加油!!