第四天,用C语言编写了操作系统代码中,对显示器的控制。先显示了一个黑白的条纹,又显示了一个彩色的条纹,最后,显示了一个彩色窗口。
第四天的教程:https://www.toutiao.com/a7065574857265758757
那么今天,第5天,内容是操作系统显示文字和开始控制鼠标,我们要在彩色窗口上显示点内容:文字和鼠标。显示文字其实挺简单的,显示鼠标其实也挺简单的,但是控制鼠标就稍微有点复杂。
我们本次教程就先把文字的显示和鼠标的显示讲解一下,鼠标的控制部分需要在第六,七,八天逐步讲解。
虽然鼠标的控制部分有点麻烦,但是一旦完成鼠标的控制,再去控制键盘等其他外设,就简单很多了,因为思路大体相同,代码基本可以复用。
本教程的pipeline:
- 显示一个字符
- 显示一个字符串
- 显示鼠标
- 鼠标中断函数使用前需要设定GDT和IDT
如何显示一个字符?
先回忆一下,如何显示一个长方形,如下代码:
void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1)
{
int x, y;
for (y = y0; y <= y1; y ) {
for (x = x0; x <= x1; x )
vram[y * xsize x] = c;
}
return;
}
如上代码第6行,把c幅值给varm[y*xsize x],
然后在4,5行循环给x,y以不同的值,就可完成长方形的绘制。
其中,varm是显示器缓冲区的首地址:0x000a0000.
显示长方形就是给长方形内的每个位置的像素给定同样的颜色 c就可以了。
那么绘制一个字符呢?
图1
如果我要显示上图中的字符A,我该如何操作?
其实相当于把A放在了一个白色的长方形中,然后在白色的长方形中,再绘制出黑色的字符A的轮廓来。比如把字符A绘制到一个宽8高16的长方形中,如下图:
图2
也就是说,绘制字符的程序是可以改动绘制长方形的程序而得到的。
如何改动?
长方形的内部都是一种颜色c.
而字符内部需要两种颜色,或者我们就只绘制需要显示字符的像素,其他位置就不绘制了。
所以,绘制字符时,我们要区分出哪些像素需要绘制黑色,哪些像素不需要绘制。
最终绘制字符的程序我们写了一个函数putfont8:
void putfont8(char *vram, int xsize, int x, int y, char c, char *font)
{
int i;
char *p, d /* data */;
for (i = 0; i < 16; i ) {
p = vram (y i) * xsize x;
d = font[i];
if ((d & 0x80) != 0) { p[0] = c; }
if ((d & 0x40) != 0) { p[1] = c; }
if ((d & 0x20) != 0) { p[2] = c; }
if ((d & 0x10) != 0) { p[3] = c; }
if ((d & 0x08) != 0) { p[4] = c; }
if ((d & 0x04) != 0) { p[5] = c; }
if ((d & 0x02) != 0) { p[6] = c; }
if ((d & 0x01) != 0) { p[7] = c; }
}
return;
}
函数的输入为:vram: 显示屏数据缓冲区首地址
xsize: 显示屏的宽度
int x ,int y: 往 坐标(x,y)处显示文字
char c:文字的颜色,这个颜色可以是黑色,也可以是其他任意颜色。我这里用黑色举例子。
char * font: 能够表明哪些像素需要显示黑色的数组。
这个函数的第5行是一个for 循环,表示需要显示16行的像素。
然后从第8行至第15行,一共设定了8个像素的值。注意到p[0]就是第一个像素,p[7]就是第8个像素。因为第6行p=vram (y i)*xsize x ,p就是第8行像素的首地址。
为什么在设置每个像素的值时,还要用一个if?
因为要检查当前像素是否需要绘制黑色,如果d&0x80不为零,说明最左边需要绘制黑色,所以p[0]=c.
这里用d,一个从font中取得的char型数据,来表示一行8个像素的信息。
一个字符16行,所以font存了16个char型的数据,如下:
图3
这里的0x00, 对应于图2中的A字符的第一行:0000 0000
这里的0x18, 对应于图2中的A字符的第二行:0001 1000
。。。
这里的0xe7, 对应于图2中的A字符的第十四行:1110 0111
这就是绘制一个字符了。
我们发现,绘制一个字符其实跟绘制一个长方形差不多,都是想办法设置像素的值就行了。