首页 > 其他分享 >30天开发操作系统 第 14 天 -- 高分辨率及键盘输入

30天开发操作系统 第 14 天 -- 高分辨率及键盘输入

时间:2025-01-15 20:29:38浏览次数:3  
标签:asc sht 14 COL8 -- 30 cursor 画面 256

前言

从着手“自制操作系统” 到现在, 不知不觉间已经过去2周了。有的读者朋友读到这里, 可能已经花了更长的时间;也有的朋友, 经过努力也可能只用了一周左右就读到了这里。 开发个操作系统需要些必备知识, 像编程语言的知识, 相关算法和技巧等。 到现在为止,这些知识的介绍就结束了。 知道了这些, 今后只要灵活运用前几章的学习内容,就 可以开发出不错的操作系统了。到现在为止的学 习过程觉得怎么样?回过头来想一想,如果大家有什么不明白的内容,也许趁着现在就弄清楚比较好。 那么我们赶快把操作系统我们的做得更像一个真正的操作系统吧。 大家现在可以接触多任务了。可是按计划,我们是从第15天开始才学# 可多任务的,所以今天还是暂时不学习多任务吧。 所以今天打算学点儿别的。 学点儿什么呢?好吧, 就学提高画面分辨率吧。 嗯, 从开发操作系统的角度来看, 现在这样的320x200的画面也没什么问题, 可毕竟还是大画面好。 以前, 我们特意创建了struct BOOTINFO, 就是为了能在以后扩大画面。那时我们没有写成“320” 而是特意写成了 “binfo ->xsize" , 这种很麻烦的方式。 这种麻烦辛苦, 现在终于得到了回报。

一、提高分辨率

高分辨率的利用方法因显卡不同而不同。首先,为了能通过“make run” 运行,我们只考虑支持QEMU模拟器的显卡。这个卡顺利运行以后,再去支持其他的显卡。 由于画面切换中我们要使用BIOS,所以就需要改写asmhead.nas的“画面模式设定”部分了。 好久没写汇编程序了哦。

; 设定画面模式
		MOV		BX,0x4101		; VBE的640x480x8bi彩色
		MOV		AX,0x4f02
		INT		0x10
		MOV		BYTE [VMODE],8	; 记下画面模式
		MOV		WORD [SCRNX],640
		MOV		WORD [SCRNY],480
		MOV		DWORD [VRAM],0xe0000000

程序的构成几乎没什么变化。但是数值是0x4101或0x4f02,有点儿怪怪的。这些数字是怎样查出来的?估计会有人问这个问题,可与其追问这样的问题,不如先看看画面扩大后的“操作系统”。所以, 我们先运行 make run。
在这里插入图片描述
因为大家已经习惯于以前的大文字显示,所以640x480看起来非常宽阔。高分辨率画面,嗯, 感觉就是不一样,好像变成了另外一个操作系统。

下面来说明为什么这个程序能够在640x480画面上运行。 其实说起来也很简单。给AX赋值0x4f02, 给BX赋值画面模式号码,这样就可以切换到高分辨率画面模式了。为什么呢?原本就是这样的。这次我们只是正好使用到了这个功能。以前画面是320x200的时候,我们用的是“AH=0;AL=画面模式号码;”。现在切换 到新画面时就使用“AX=0x4f02;"。 大家是不是很纳闷:“画面模式有新旧之分吗 ”是的,实际上是有新旧之分的。就说显卡吧,每当有新显卡面世时,性能就会提高,反过来想,以前的显卡,声音性能差,颜色数又少, 分辨率又低。刚开始的时候,电脑规格是以IBM公司为中心决定的,他们也规定了画面模式的相关规格。而且各家显卡公司也都迎合IBM的规格来制作显卡。 可是过了一段时间,其他显卡公司的图像处理技术超越了IBM,在IBM制定规格前,就出现 了具有各样画面模式的显卡。这造成了多家显卡 公司的竞争,使得在各家公司之间,画面模式的 设定方法和使用方法都各不相同。 这样的情况,我们这些普通程序员是难以应付的。显卡的种类太多,我们记不住那么多的设 定方法,而且事实上,连参考资料都很难得到。这样一来,本应是高性能的显卡,却只能像老显卡一样,通过BIOS设定为320x200来使用。 有鉴于此,多家显卡公司经过协商,成立了VESA协会(Video Electronics Standards Association 视频电子标准协会)。此后,这个协会制定了虽然不能说完全兼容、但几乎可以通用的设定方法,制作了专用的BIOS。这个追加的 BIOS被称作“VESA BIOS extension”( VESA-BIOS 扩展,简略为VBE)。利用它,就可以使用显卡的高分辨率功能了。 因此,切换到不使用VBE的画面模式时用“AH=0;AL=画面模式号码;而切换到使用VBE 的画面模式时用“AX=0x4f02;BX=画面模式号码;”。而这种必须使用VBE才能利用的画面模式就称作 “新”画面模式。
VBE的画面模式号码如下。
0x101······640x480x 8bit 彩色
0x103······800x 600x 8bit 彩色
0x105······1024x768x 8bit彩色
0x107······1280x1024x 8bit彩色
还有其他一些画面模式,因为现在不需要,我们就省略了。另外,在QEMU中不能指定最下面的0x107。实际指定的时候,要像在asmhead.nas中所做的那样,将以上的画面模式号码值加上0x4000,再赋值到BX中去。不这样做就不能顺利运行。所以,如果想要将画面扩展得特别大的话,请尝试运行以下程序。

MOV BX,0x4105 ;VBE的1024x768x8bit彩色
MOV AX,0x4f02
INT 0x10
MOV BYTE[VMODE],8 ;记下画面模式(参考C语言)
MOV WORD[SCRNX],1024
MOV WORD [SCRNY],768
MOV DWORD[VRAM],0xe0000000

画面会变得很宽哦。

二.键盘输入

对高分辨率的支持我们已经完成了,比预想的要快。所以现在我们通过从键盘输入信息来稍稍放松一下吧。 再对hariblle运行一次“make run" 然后试着按下“A”键。按下“A”键的时候,应该显 示“1E”,键弹起的时候应该显示 9E”。

下面我们按下“B”键吧。按下的时候显示“30”,弹起的时候显示“B0”。再按下“C” 这样罗列下去,可就浪费纸张了,所以我们把这些值都归纳到下表里。表里的值是按下键时的数值。在此基础上加上0x80就可以得到键弹起时的数值。
在这里插入图片描述
这个表中有写着“保留?” 的地方是指, 虽然现在按下哪个键都不出现该数值,但将来键盘 的键数量一旦增加,那个数值就可以被分配使用了。

我们想利用这个表实现当“A”键被按下的时候就显示“A”。嗯,以前曾经通过计数来测试性能,现在也已经腻了,所以我们来修改bootpack.c。 不再是让其计数,而是让其充分HLT(休眠),以便节电。

for (;;) {
		io_cli();
		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);
				}
			} else if (512 <= i && i <= 767) { /* 鼠标数据 */
				
				}
			} else if (i == 10) { /* 10秒定时器} */
				putfonts8_asc_sht(sht_back, 0, 64, COL8_FFFFFF, COL8_008484, "10[sec]", 7);
			} else if (i == 3) { /* 3秒定时器} */
				putfonts8_asc_sht(sht_back, 0, 80, COL8_FFFFFF, COL8_008484, "3[sec]", 6);
			} else if (i == 1) { /* 光标用定时器} */
				timer_init(timer3, &fifo, 0); 
				boxfill8(buf_back, binfo->scrnx, COL8_FFFFFF, 8, 96, 15, 111);
				timer_settime(timer3, 50);
				sheet_refresh(sht_back, 8, 96, 16, 112);
			} else if (i == 0) { /* 光标用定时器 */
				timer_init(timer3, &fifo, 1); 
				boxfill8(buf_back, binfo->scrnx, COL8_008484, 8, 96, 15, 111);
				timer_settime(timer3, 50);
				sheet_refresh(sht_back, 8, 96, 16, 112);
			}
		}
	}
}

虽然在这段程序中没有出现,但我们已经把窗口的名字由 改为了 counter window 再按一下“A”键,哦, 少 make run “A”显示出来了。
在这里插入图片描述
到了这一步,我们希望也能输入“B”和“C”等字符。那么,我们来动手写程序。 首先我们创建以下程序:

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);
	}
	if(i==0x30+256){
		putfonts8_asc_sht(sht_win,40,28,COL8_000000,COL8_C6C6C6,"B",1);
	}
	if(i ==0x2e+256){
		putfonts8_asc_sht(sht_win,40,28,COL8_000000,COL8_C6C6C6,"C",1);
	}
	if(i==0x20+256){
		putfonts8_asc_sht(sht_win,40,28,COL8_000000,COL8_C6C6C6, "D",1);
	}
	if(i == 0x12+256){
		putfonts8_asc_sht(sht_win,40,28,COL8_000000,COL8 C6C6C6,"E",1);
	}else if(512<=i&& i<= 767){/* 鼠标数据 */

如果我们像上面这样写程序,仅仅是字母(26 个)和数字(10个),就得写36个i语句。必须要想出一个好办法。

大家是不是已经想到了喽:

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', '.'
	};

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 < 256 + 0x54) {
					if (keytable[i - 256] != 0) {
						s[0] = keytable[i - 256];
						s[1] = 0;
						putfonts8_asc_sht(sht_win, 40, 28, COL8_000000, COL8_C6C6C6, s, 1);
					}
				}
			} 

之所以把keytable[]设定为static char,是因为希望程序被编译为汇编语言的时候,static char能编译成DB指令。设定调色板的时候也是如此,大家还记得吗? 现在我们来解释这个程序的运行机制。比如说keytable[0x1e]对应的是“A"。而“A”的字符 代码是0x41。如果i == 0x1e+256的话,keytable[i-256]就是“A”,所以s[0]也就是“A”了。
同理,“B”、 “C”、 “Z”以及“5”等也应该可以显示了。
让我们确认一下吧。运行 'make run”。 不错,很顺利呀。
在这里插入图片描述
运行“make run” 后,按下“@”等键,却显示出“W”。大家也许会想“唉?怎么回事儿?” 这是因为当“@”被按下的时候,HariMain接收到了0x11(请确认左上方的显示内容),这不是 HariMain的bug,而是QEMU的问题。还有其他几个键,按下以后会显示出奇怪的字符。这些好像都是QEMU的问题。

三.追加内容

我们已经进行到了这个阶段, 就想稍稍放松一下了。你看,光标也能闪烁了, 窗口也有了。 我们先把程序放在一边,来看一看画面的截图吧。
在这里插入图片描述

当这个画面出现的时候, 感到一股成功的喜悦。 虽然看起来有了不小的进步,但实际上我们也只是在窗口中添加了一些画,改变了鼠标和字符的显示位置以及颜色而已。如果我们按下退格键(BackSpace键),还可以改写已输入的字符哦。 大家试着输入自己喜欢的信息吧。

int mx, my, i, cursor_x, cursor_c;
make_textbox8(sht_win, 8, 28, 144, 16, COL8_FFFFFF);
cursor_x = 8;
cursor_c = COL8_FFFFFF;

for (;;) {
		io_cli();
		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) { /* 一般字符 */
						/* 显示1个字符就前移1次光标 */
						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;
					}
				}
				if (i == 256 + 0x0e && cursor_x > 8) { /* 退格键 */
					/* 用空格键把光标消去后,后移1次光标 */
					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);
			} else if (512 <= i && i <= 767) { /* 鼠标数据 */
				...
			} else if (i == 10) { /* 10秒定时器} */
				putfonts8_asc_sht(sht_back, 0, 64, COL8_FFFFFF, COL8_008484, "10[sec]", 7);
			} else if (i == 3) { /* 3秒定时器} */
				putfonts8_asc_sht(sht_back, 0, 80, COL8_FFFFFF, COL8_008484, "3[sec]", 6);
			} else if (i <= 1) { /* 光标} */
				if (i != 0) {
					timer_init(timer3, &fifo, 0); 
					cursor_c = COL8_000000;
				} else {
					timer_init(timer3, &fifo, 1); 
					cursor_c = COL8_FFFFFF;
				}
				timer_settime(timer3, 50);
				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);
			}
		}
	}
}

cursor_x是用来记住光标显示位置的变量 ,输入一个字符后,这个变量就递增“8”。cursor_c 变量则表示现在光标的颜色。 它每0.5秒变化一次。 make_textb0x8的数是用来描绘文字输入背景的,内容如下。 这个函数没什么特别难的东西, 大家大致读一下就可以了。

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;
}

像haribllh那样玩儿是最高兴的了。这才是操作系统的乐趣所在!那么,我们继续玩点儿别的吧。 大家还记得,为了使鼠标动起来,我们付出了多少辛苦吗?我们付出了辛苦,终于让鼠标动 了起来,可鼠标动起来后,却一点儿都没用到。它只是一个装饰物(也许还碍手碍脚的?)。 好不容易让鼠标动起来了,我们看看能用它干些什么吧。做什么好呢?嗯,还是来移动窗口 吧。所以下面我们就使用鼠标完成窗口移动吧。 只要添写4行程序就可以了。
一说到窗口的移动,感觉好像很难。但实际并不难,4行代码就搞定啦!

for (;;) {
		io_cli();
		if (fifo32_status(&fifo) == 0) {
			io_stihlt();
		} else {
			i = fifo32_get(&fifo);
			io_sti();
			if (256 <= i && i <= 511) { /* 键盘数据 */
				
			} else if (512 <= i && i <= 767) { /* 鼠标数据 */
				if (mouse_decode(&mdec, i - 512) != 0) {
					/* 从这里开始! */
					sheet_slide(sht_mouse, mx, my);
					if ((mdec.btn & 0x01) != 0) {
						/* 按下左键、移动sht_win */
						sheet_slide(sht_win, mx - 80, my - 8);
					}
					/* 到这里结束! */
				}
			} else if (i == 10) { /* 10秒定时器} */
				putfonts8_asc_sht(sht_back, 0, 64, COL8_FFFFFF, COL8_008484, "10[sec]", 7);
			} else if (i == 3) { /* 3秒定时器 */
				putfonts8_asc_sht(sht_back, 0, 80, COL8_FFFFFF, COL8_008484, "3[sec]", 6);
			} else if (i <= 1) { 
	
		}
	}
}

这样就完成了。 我们赶紧运行启动之后, 请随意在画面上某个地方。 make run – 点击一下, 窗口很快就移动到那里了。

即使窗口跑到了画面外,也没有问题。因为我们已经针对鼠标指针提前采取了对策,这就如同图层跑到了画面外面也可以动起来一样。
在这里插入图片描述

总结

真棒!能简单地实现这个功能,多亏在制作图层时下的一番苦功。做得不错!先表扬一下几天前的自己吧(笑) 唉,玩得正高兴,不知不觉就到了今天的结束时间了。明天我们就要挑战,“多任务”了。 今天正好是第2周, 我们看看haribote.sys的大小吧。23908字节也就是23KB。到现在为止,仅用 23KB就可以完成像操作系统那样的功能了,不错不错。今天的内容不算多,大家可以复习一下之前的内容哦。好了,我们明天见吧。

标签:asc,sht,14,COL8,--,30,cursor,画面,256
From: https://blog.csdn.net/suy123/article/details/145166461

相关文章

  • Python----Python高级(面向对象:对象,类,属性,方法)
    一、面向对象简介Python完全采用了面向对象的思想,是真正面向对象的编程语言,完全支持面向对象的基本功能,例如:继承、多态、封装等。Python中,一切皆对象。python数据类型、函数等,都是对象。面向对象(ObjectorientedProgramming,OOP)编程的思想主要是针对大型软件设计而来的......
  • 分支和循环
    引言c语言有三个结构,包括:顺序结构,循环结构,选择结构。if、switch实现分支结构,for、whlie、dowhlie实现循环结构。1.if语句基本概念-if语句是一种条件控制语句,用于根据给定条件的真假来决定是否执行某段代码。它允许程序根据不同的情况做出不同的反应,这在实现逻辑判断和流......
  • C语言常见的概念
    1.C语⾔是什么? c语言是一种通用的、高级的编程语言。 我们可以联想一下,⼈和⼈交流使⽤的是⾃然语⾔,如:汉语、英语、⽇语。那⼈和计算机使⽤计算机语⾔。⽬前已知已经有上千种计算机语⾔,⼈们是通过计算机语⾔写的程序,给计算机下达指令,让计算机⼯作的。C语⾔就是众多计算机......
  • 基于STM32的AI物联网计算实现指南
    基于STM32的AI物联网计算实现指南版权所有©深圳市为也科技有限公司摘要随着人工智能(AI)和物联网(IoT)的快速发展,智能设备在各行各业中的应用日益广泛。STM32系列微控制器凭借其高性能、低功耗和丰富的外设接口,成为实现AI物联网计算的理想选择。本文将全面介绍如何利用S......
  • 基于STM32控制VS1053B芯片的音频处理开发指南
    基于STM32控制VS1053B芯片的音频处理开发指南版权所有©深圳市为也科技有限公司摘要VS1053B是由VLSISolution推出的一款功能强大的音频编解码芯片,广泛应用于音频播放器、语音记录设备和其他嵌入式音频应用中。结合STM32微控制器,开发者可以实现高质量的音频处理功能......
  • ​​​​​​​敏捷赋能汽车行业:Scrum中文网如何助力企业加速转型
    在汽车行业,这些关键词已变得越来越重要:智能化、电动化、网联化、共享化。快速发展的市场环境要求企业具备更高的灵活性和创新能力。而在实现这些目标的道路上,Scrum中文网以其专业的敏捷培训和咨询服务,成为众多汽车企业转型升级的重要伙伴。汽车行业为何需要敏捷?在传统汽车研发模......
  • java面向对象
    java面向对象1.类和对象1.1类和对象的理解客观存在的事物皆为对象,所以我们也常常说万物皆对象。类类的理解类是对现实生活中一类具有共同属性和行为的事物的抽象类是对象的数据类型,类是具有相同属性和行为的一组对象的集合简单理解:类就是对现实事物的一种描述类......
  • Java常用类
    一、字符串相关的类1、String类及常用方法String类:代表字符串。Java程序中的所有字符串字面值(如"abc")都作为此类的实例实现。String是一个final类,代表不可变的字符序列。字符串是常量,用双引号引起来表示。它们的值在创建之后不能更改。String对象的字符内容是存储在一个......
  • Java RestTemplate 发送 POST 请求设置请求体示例
    在Java中使用RestTemplate​发送POST请求并设置请求体(body)参数,可以按照以下步骤进行。RestTemplate​是Spring提供的一个用于发送HTTP请求的工具类。示例代码以下是一个完整的示例,展示如何使用RestTemplate​发送POST请求并设置请求体参数:importorg.sp......
  • java第二章数组
    java第二章数组数组的概念和特点数组的概念数组(Array),是多个相同类型数据按一定顺序排列的集合,并使用一个名字命名,并通过编号的方式对这些数据进行统一管理。数组的特点特点是一个可以存储同一种数据类型元素的容器,对于同一个数组而言,里面的元素类型都是一样。数......