【读书笔记-《30天自制操作系统》-13】Day14

2024-09-02 03:28

本文主要是介绍【读书笔记-《30天自制操作系统》-13】Day14,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

相比前几篇的内容,本篇不仅内容更为简单,而且与显示相关,更为有趣。首先通过调用VBE的显示模式提高显示画面的分辨率,然后分别实现按下键盘按键显示对应的字符,以及通过鼠标移动窗口。因为是以前面讲过的很多内容为基础,程序代码很简单,而且能切实看到成果,也更有趣。
在这里插入图片描述

1. 提高画面分辨率

现在要把显示画面的分辨率提高到640x480,就又要修改BIOS的画面模式设定所用的汇编语言代码了。

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

记得之前切换画面模式用的汇编语言指令是“AH = 0, AL = 画面模式号码”,但是上面这段代码却有所不同,用的是AX = 0x4f02。这是什么原因呢?

从前电脑的规格是以IBM公司为中心决定的,IBM规定了画面显示模式的规格,各家显卡公司也按照这一规格来进行实现。而后来各个显卡公司开发出了更多性能更好的显卡,具有各种画面显示模式,设置和使用的方法也各不相同,导致程序员比较无所适从。于是多家显卡公司进行协商,成立了VESA协会。这个协会制定了几乎可以通用的设置方法,制作了专门的BIOS,这个追加的BIOS被称为VESA BIOS extension,简称为VBE。利用它就可以扩展显卡的显示模式了。

VBE的画面模式号码如下:

  • 0x101: 640x480x8bit 彩色
  • 0x103: 800x600x8bit 彩色
  • 0x105: 1024x768x8bit 彩色
  • 0x107: 1280x1024x8bit 彩色

为了在真机上使用VBE的显示模式,我们还需要进行一些确认。

(1) 确认是否支持VBE?
有些公司的产品仍然不支持VBE,因此无法使用VBE的显示模式。我们通过如下操作来进行确认:

; 确认VBE是否存在MOV		AX,0x9000MOV		ES,AXMOV		DI,0MOV		AX,0x4f00INT		0x10CMP		AX,0x004fJNE		scrn320

这里给ES赋值0x9000,给DI赋值为0,给AX赋值为0x4f00,再执行INT 0x10,如果有VBE的话,AX就会变成0x004f。否则说明没有VBE,仍然只能使用之前320x200的画面。而为ES和DI进行赋值,是因为此显卡能利用的VBE信息将要写入内存中以ES:DI开始的512字节中。

(2) 确认VBE的版本是否在2.0以上
使用高分辨率,也需要VBE的版本在2.0以上。

; VBE版本确认MOV		AX,[ES:DI+4]CMP		AX,0x0200JB		scrn320			; if (AX < 0x0200) goto scrn320

(3) 即使VBE版本在2.0以上,也还是需要确认画面模式0x105是否能够使用:

; 获取画面模式信息MOV		CX,VBEMODEMOV		AX,0x4f01INT		0x10CMP		AX,0x004fJNE		scrn320

这里对AX的值进行了确认,如果是0x004f以外的值,所指定的画面模式就不能使用。
此次取得的画面模式信息也被写入内存从ES:DI开始的256字节中,这样刚才VBE的版本信息会被覆盖。但确认VBE版本之后这个信息就不需要了,因此没什么影响。

(4) 其他画面模式信息确认

这还没完,还有最后的几项信息需要确认:

  • 颜色数是否为8
  • 是否为调色板模式
  • 画面模式号码是否可以加上0x4000再进行指定
; 画面模式信息确认CMP		BYTE [ES:DI+0x19],8JNE		scrn320CMP		BYTE [ES:DI+0x1b],4JNE		scrn320MOV		AX,[ES:DI+0x00]AND		AX,0x0080JZ		scrn320			; 模式属性的bit7是0,放弃

以上这些信息如果都确认OK,那么就可以使用VBE的画面模式了。如果确认不通过,则还是只能使用之前的分辨率。

; 画面模式切换MOV		BX,VBEMODE+0x4000MOV		AX,0x4f02INT		0x10MOV		BYTE [VMODE],8	; MOV		AX,[ES:DI+0x12]MOV		[SCRNX],AXMOV		AX,[ES:DI+0x14]MOV		[SCRNY],AXMOV		EAX,[ES:DI+0x28]MOV		[VRAM],EAXJMP		keystatusscrn320:MOV		AL,0x13			; VGA图,320x200x8bit彩色MOV		AH,0x00INT		0x10MOV		BYTE [VMODE],8	; MOV		WORD [SCRNX],320MOV		WORD [SCRNY],200MOV		DWORD [VRAM],0x000a0000

调整分辨率后,画面明显变大了。
在这里插入图片描述

2. 键盘输入与鼠标移动窗口

前面已经讲过关于键盘和鼠标的内容了。但是键盘只是实现了按下按键显示按键码,而鼠标也只是实现了移动鼠标箭头,其实还没有什么实用的功能。本篇中来实现按下键盘按键显示对应的字符,以及通过鼠标移动窗口的功能。

2.1 键盘信息输入

前面已经讲过,按下一个键盘按键,会显示一个按键码,松开的时候也会显示一个按键码。利用这一点,我们来实现按键显示对应字符的功能。
比如按下按键A时,显示的按键码是1E,按下B的时候,显示的按键码是30,……,关于每个按键的按键码形成了一张对照表。根据表中的按键码数值,可以编写keytable对照表,根据按键码来显示按键的字符。

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

在这里插入图片描述
目前的程序还只能显示一个字符,再对程序进行修改,使其可以显示多个字符,并且修改了显示画面。

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) { /* 一般字符 *//* 显示一个字符就前移一次光标 */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) { /* backspace *//* 用空格键把光标消去后,后移一次光标 */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) { if (mouse_decode(&mdec, i - 512) != 0) {sprintf(s, "[lcr %4d %4d]", mdec.x, mdec.y);if ((mdec.btn & 0x01) != 0) {s[1] = 'L';}if ((mdec.btn & 0x02) != 0) {s[3] = 'R';}if ((mdec.btn & 0x04) != 0) {s[2] = 'C';}putfonts8_asc_sht(sht_back, 32, 16, COL8_FFFFFF, COL8_008484, s, 15);mx += mdec.x;my += mdec.y;if (mx < 0) {mx = 0;}if (my < 0) {my = 0;}if (mx > binfo->scrnx - 1) {mx = binfo->scrnx - 1;}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);}} else if (i == 10) { putfonts8_asc_sht(sht_back, 0, 64, COL8_FFFFFF, COL8_008484, "10[sec]", 7);} else if (i == 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.5s变化一次,产生闪烁效果。显示效果如下:
在这里插入图片描述
不过我这里遇到一个问题,按下一个按键松开之后,输入框中会一直重复输入这个字符,把输入框占满,而此时再按backspace键也没有反应。暂时还没找到原因,先继续往下学,看看后续能否解决这个问题

键盘显示字符做完了,鼠标也修改一下,程序也很简单,只需要在主程序鼠标处理的部分增加几行代码:

	if ((mdec.btn & 0x01) != 0) {/* 按下左键之后,就移动sht_win窗口 */sheet_slide(sht_win, mx - 80, my - 8);}

在这里插入图片描述
这样只要点击鼠标,窗口就会移动到鼠标点击的位置。

这一篇的内容可以说是非常简单了,而且实现效果立竿见影。不过从下一篇开始就要进入多任务的学习了,这部分内容是个难点,还是提前做好准备吧。

这篇关于【读书笔记-《30天自制操作系统》-13】Day14的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1128859

相关文章

Java进阶13讲__第12讲_1/2

多线程、线程池 1.  线程概念 1.1  什么是线程 1.2  线程的好处 2.   创建线程的三种方式 注意事项 2.1  继承Thread类 2.1.1 认识  2.1.2  编码实现  package cn.hdc.oop10.Thread;import org.slf4j.Logger;import org.slf4j.LoggerFactory

30常用 Maven 命令

Maven 是一个强大的项目管理和构建工具,它广泛用于 Java 项目的依赖管理、构建流程和插件集成。Maven 的命令行工具提供了大量的命令来帮助开发人员管理项目的生命周期、依赖和插件。以下是 常用 Maven 命令的使用场景及其详细解释。 1. mvn clean 使用场景:清理项目的生成目录,通常用于删除项目中自动生成的文件(如 target/ 目录)。共性规律:清理操作

2024网安周今日开幕,亚信安全亮相30城

2024年国家网络安全宣传周今天在广州拉开帷幕。今年网安周继续以“网络安全为人民,网络安全靠人民”为主题。2024年国家网络安全宣传周涵盖了1场开幕式、1场高峰论坛、5个重要活动、15场分论坛/座谈会/闭门会、6个主题日活动和网络安全“六进”活动。亚信安全出席2024年国家网络安全宣传周开幕式和主论坛,并将通过线下宣讲、创意科普、成果展示等多种形式,让广大民众看得懂、记得住安全知识,同时还

Linux操作系统 初识

在认识操作系统之前,我们首先来了解一下计算机的发展: 计算机的发展 世界上第一台计算机名叫埃尼阿克,诞生在1945年2月14日,用于军事用途。 后来因为计算机的优势和潜力巨大,计算机开始飞速发展,并产生了一个当时一直有效的定律:摩尔定律--当价格不变时,集成电路上可容纳的元器件的数目,约每隔18-24个月便会增加一倍,性能也将提升一倍。 那么相应的,计算机就会变得越来越快,越来越小型化。

13 transition数组的动画使用

划重点 动画:transitiontransition-group :数组动画数组的 添加 / 删除 豆腐粉丝汤 清淡又健康 <!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><me

《C++标准库》读书笔记/第一天(C++新特性(1))

C++11新特性(1) 以auto完成类型自动推导 auto i=42; //以auto声明的变量,其类型会根据其初值被自动推倒出来,因此一定需要一个初始化操作; static auto a=0.19;//可以用额外限定符修饰 vector<string> v;  auto pos=v.begin();//如果类型很长或类型表达式复杂 auto很有用; auto l=[] (int

【CTF Web】BUUCTF Upload-Labs-Linux Pass-13 Writeup(文件上传+PHP+文件包含漏洞+PNG图片马)

Upload-Labs-Linux 1 点击部署靶机。 简介 upload-labs是一个使用php语言编写的,专门收集渗透测试和CTF中遇到的各种上传漏洞的靶场。旨在帮助大家对上传漏洞有一个全面的了解。目前一共20关,每一关都包含着不同上传方式。 注意 1.每一关没有固定的通关方法,大家不要自限思维! 2.本项目提供的writeup只是起一个参考作用,希望大家可以分享出自己的通关思路

c++习题30-求10000以内N的阶乘

目录 一,题目  二,思路 三,代码    一,题目  描述 求10000以内n的阶乘。 输入描述 只有一行输入,整数n(0≤n≤10000)。 输出描述 一行,即n!的值。 用例输入 1  4 用例输出 1  24   二,思路 n    n!           0    1 1    1*1=1 2    1*2=2 3    2*3=6 4

Chapter 13 普通组件的注册使用

欢迎大家订阅【Vue2+Vue3】入门到实践 专栏,开启你的 Vue 学习之旅! 文章目录 前言一、组件创建二、局部注册三、全局注册 前言 在 Vue.js 中,组件是构建应用程序的基本单元。本章详细讲解了注册和使用 Vue 的普通组件的两种方式:局部注册和全局注册。 本篇文章参考黑马程序员 一、组件创建 ①定义 Vue 组件是一种具有特定功能的 Vue 实

读书笔记(一):双脑记

谁又知道年轻人那反复无常的大脑有着怎样的运行机制?尽管他们的大脑已被荷尔蒙折腾地七荤八素;却偶尔还会有灵感跻身夹缝之间; 层级化:每时每刻,人类都在进行抽象化,也就是说,从客观事实中发展出更具普遍意义的理论和知识。利用这种方法,我们得以不断地开发出新的更为简洁的描述层级,方便我们那容量有限的大脑加以处理。分层的概念几乎可以应用于任何复杂系统,甚至包括我们的社交世界,也即是人们的个人生