使用控制台与键盘进行输入输出
1、控制台简介与初始化
计算机在上电启动后,显示器被默认配置成80x25列的文本显示模式 。其使用从0xb8000开始,一共32KB的显存用于显示。如要在屏幕上指定位置显示特定的字符,则只需找到该位置对应的显存地址,写入2字节的数据:ascii码和颜色属性字节。
由于一屏共8025个字符,每个字符占用2个字节,所以一屏字符显示需要约4000字节数据。而显存一共32KB,因此这些存储区域可以存储8块屏幕的显示数据。
后续可以通过切换对应的显存屏幕数据。
2、在控制台上显示字符串
采用老式屏幕显示方式,没有采用现在的显卡写。
显示字符,只需要往计算机的显存中写入数据即可。计算机上的显卡会自动从这块区域读取数据,完后控制屏幕显示。
具体显示时,如果需要往屏幕上写字符显示,需要使用两个字节来控制。一个字节用于显示字符,一个字节用于配置显示属性
3、处理换行和清屏
清屏:填入空白字符即可实现清屏功能。即只需要将当前屏幕对应的显存内容全部用空格符号清空,或者用前景色和后景色相同的字符清空
换行:当已经显示满屏时,整个屏幕需要上移滚屏。具体实现采用了非常简单的方式:将整个屏幕区域的数据往上复制一行。
3、设置光标
光标的主要作用是帮助用户感知下一字符显示的位置
在文本模式下,计算机显示硬件自动会提供一个光标,并且经BIOS设置后会显示在屏幕上。但是,当我们在显存上写入字符后,光标并不会自动调整位置。 因此,我们要做的只是随着显示的位置,调整光标的显示位置,无需再初始化。
光标的位置为在整个屏幕中显示的字符符号。在当前的显示模式下,显示范围为80列*25行,因此总共有2000个字符,如果以0开始进行编址,则光标的地址范围为0~1999。即屏幕左上角的位置为0,右下角的位置为1999.
4、保存并恢复光标位置
本小节实现光标位置的保存和恢复,其两个序列如下:
CSI s | SCP – 保存光标位置(Save Cursor Position) | 保存光标的当前位置。 |
---|---|---|
CSI u | RCP – 恢复光标位置(Restore Cursor Position) | 恢复保存的光标位置。 |
示例:
int main (void) {
printf("\0337Hello,word!\0338123\n"); // ESC 7,8 输出123lo,word!
printf("\033[31;42mHello,word!\033[39;49m123\n"); // ESC [pn m, Hello,world红色,>其余绿色
printf("123\033[2DHello,word!\n"); // 光标左移2,1Hello,word!
printf("123\033[2CHello,word!\n"); // 光标右移2,123 Hello,word!
printf("\033[31m"); // ESC [pn m, Hello,world红色,其余绿色
printf("\033[10;10H test!\n"); // 定位到10, 10,test!
printf("\033[20;20H test!\n"); // 定位到20, 20,test!
printf("\033[32;25;39m123\n"); // ESC [pn m, Hello,world红色,其余绿色
}
5、更新显示字体的颜色
| CSI n m | SGR – 选择图形再现(Select Graphic Rendition) | 设置SGR参数 ,包括文字颜色
CSI后可以是0或者更多参数,用分号分隔。如果没有参数,则视为CSI 0 m(重置/常规)。
6、移动光标位置并清屏
CSI n A | CUU – 光标上移(Cursor Up) | 光标向指定的方向移动(默认1)格。如果光标已在屏幕边缘,则无效。 |
---|---|---|
CSI n B | CUD – 光标下移(Cursor Down) | |
CSI n C | CUF – 光标前移(Cursor Forward) | |
CSI n D | CUB – 光标后移(Cursor Back) | |
CSI n E | CNL – 光标移到下一行(Cursor Next Line) | 光标移动到下面第(默认1)行的开头。(非ANSI.SYS |
) | ||
CSI n F | CPL – 光标移到上一行(Cursor Previous Line) | 光标移动到上面第(默认1)行的开头。(非ANSI.SYS) |
CSI n G | CHA – 光标水平绝对(Cursor Horizontal Absolute) | 光标移动到第(默认1)列。(非ANSI.SYS) |
CSI n ; m H | CUP – 光标位置(Cursor Position) | 光标移动到第n行、第m列。值从1开始,且默认为1(左上角)。例如CSI ;5H和CSI 1;5H含义相同;CSI 17;H、CSI 17H和CSI 17;1H三者含义相同。 |
CSI n J | ED – 擦除显示(Erase in Display) | 清除屏幕的部分区域。如果n是0(或缺失),则清除从光标位置到屏幕末尾的部分。如果n是1,则清除从光标位置到屏幕开头的部分。如果n是2,则清除整个屏幕(在DOS ANSI.SYS中,光标还会向左上方移动)。如果n是3,则清除整个屏幕,并删除回滚缓存区中的所有行(这个特性是xterm |
添加的,其他终端应用程序也支持)。 |
7、键盘初始化
PC机中使用键盘控制器(KBC)处理键盘与鼠标的链接。键盘与鼠标通过KBC与CPU进行通信,并链接到中断控制器IRQ1和IRQ2
通过端口0x60和0x64对KBC进行配置以及读取相应的数据
IO Port | 读写 | 功能 |
---|---|---|
0x60 | 读/写 | 数据寄存器 |
0x64 | 只读 | 状态寄存器 |
0x64 | 只写 | 命令寄存器 |
其中状态寄存器的值如下
Bit | Meaning |
---|---|
0 | 输出缓存寄存器(0 = 空,无数据, 1 = 满,有数据) |
1 | 输入缓存寄存器(0 = 空,无数据, 1 = 满,有数据) |
2 | 系统标志位 |
3 | 命令或数据(0 = data written to input buffer is data for PS/2 device, 1 = data written to input buffer is data for PS/2 controller command) |
4 | - |
5 | - |
6 | 是否发生超时错误 (0 = no error, 1 = time-out error) |
7 | 是否发生奇偶校验错误 (0 = no error, 1 = parity error) |
在计算机上电后,BIOS会自动完成对键盘相关的初始化,因此我们只需要使用缺省值即可,无需再次初始化
8、借助按键映射表进行键值转换
主要对读取的键值进行转码,并且处理shift健按下时大小写转换的问题
键盘扫描码
当按键按下时,将触发中断,可从中断中读取按键的键值,但是这个值并非按键上的字符丝印对应的字符,而是某种特定编码的数值,这套编码为键盘扫描码集1(Scan Code Set 1),如下表:
Scan code | Key | Scan code | Key | Scan code | Key | Scan code | Key |
---|---|---|---|---|---|---|---|
0x01 | escape pressed | 0x02 | 1 pressed | 0x03 | 2 pressed | ||
0x04 | 3 pressed | 0x05 | 4 pressed | 0x06 | 5 pressed | 0x07 | 6 pressed |
0x08 | 7 pressed | 0x09 | 8 pressed | 0x0A | 9 pressed | 0x0B | 0 (zero) pressed |
0x0C | - pressed | 0x0D | = pressed | 0x0E | backspace pressed | 0x0F | tab pressed |
0x10 | Q pressed | 0x11 | W pressed | 0x12 | E pressed | 0x13 | R pressed |
0x14 | T pressed | 0x15 | Y pressed | 0x16 | U pressed | 0x17 | I pressed |
0x18 | O pressed | 0x19 | P pressed | 0x1A | [ pressed | 0x1B | ] pressed |
0x1C | enter pressed | 0x1D | left control pressed | 0x1E | A pressed | 0x1F | S pressed |
0x20 | D pressed | 0x21 | F pressed | 0x22 | G pressed | 0x23 | H pressed |
0x24 | J pressed | 0x25 | K pressed | 0x26 | L pressed | 0x27 | ; pressed |
0x28 | ' (single quote) pressed | 0x29 | ` (back tick) pressed | 0x2A | left shift pressed | 0x2B | \ pressed |
0x2C | Z pressed | 0x2D | X pressed | 0x2E | C pressed | 0x2F | V pressed |
0x30 | B pressed | 0x31 | N pressed | 0x32 | M pressed | 0x33 | , pressed |
0x34 | . pressed | 0x35 | / pressed | 0x36 | right shift pressed | 0x37 | (keypad) * pressed |
0x38 | left alt pressed | 0x39 | space pressed | 0x3A | CapsLock pressed | 0x3B | F1 pressed |
0x3C | F2 pressed | 0x3D | F3 pressed | 0x3E | F4 pressed | 0x3F | F5 pressed |
0x40 | F6 pressed | 0x41 | F7 pressed | 0x42 | F8 pressed | 0x43 | F9 pressed |
0x44 | F10 pressed | 0x45 | NumberLock pressed | 0x46 | ScrollLock pressed | 0x47 | (keypad) 7 pressed |
0x48 | (keypad) 8 pressed | 0x49 | (keypad) 9 pressed | 0x4A | (keypad) - pressed | 0x4B | (keypad) 4 pressed |
0x4C | (keypad) 5 pressed | 0x4D | (keypad) 6 pressed | 0x4E | (keypad) + pressed | 0x4F | (keypad) 1 pressed |
0x50 | (keypad) 2 pressed | 0x51 | (keypad) 3 pressed | 0x52 | (keypad) 0 pressed | 0x53 | (keypad) . pressed |
0x57 | F11 pressed | ||||||
0x58 | F12 pressed | ||||||
0x81 | escape released | 0x82 | 1 released | 0x83 | 2 released | ||
0x84 | 3 released | 0x85 | 4 released | 0x86 | 5 released | 0x87 | 6 released |
0x88 | 7 released | 0x89 | 8 released | 0x8A | 9 released | 0x8B | 0 (zero) released |
0x8C | - released | 0x8D | = released | 0x8E | backspace released | 0x8F | tab released |
0x90 | Q released | 0x91 | W released | 0x92 | E released | 0x93 | R released |
0x94 | T released | 0x95 | Y released | 0x96 | U released | 0x97 | I released |
0x98 | O released | 0x99 | P released | 0x9A | [ released | 0x9B | ] released |
0x9C | enter released | 0x9D | left control released | 0x9E | A released | 0x9F | S released |
0xA0 | D released | 0xA1 | F released | 0xA2 | G released | 0xA3 | H released |
0xA4 | J released | 0xA5 | K released | 0xA6 | L released | 0xA7 | ; released |
0xA8 | ' (single quote) released | 0xA9 | ` (back tick) released | 0xAA | left shift released | 0xAB | \ released |
0xAC | Z released | 0xAD | X released | 0xAE | C released | 0xAF | V released |
0xB0 | B released | 0xB1 | N released | 0xB2 | M released | 0xB3 | , released |
0xB4 | . released | 0xB5 | / released | 0xB6 | right shift released | 0xB7 | (keypad) * released |
0xB8 | left alt released | 0xB9 | space released | 0xBA | CapsLock released | 0xBB | F1 released |
0xBC | F2 released | 0xBD | F3 released | 0xBE | F4 released | 0xBF | F5 released |
0xC0 | F6 released | 0xC1 | F7 released | 0xC2 | F8 released | 0xC3 | F9 released |
0xC4 | F10 released | 0xC5 | NumberLock released | 0xC6 | ScrollLock released | 0xC7 | (keypad) 7 released |
0xC8 | (keypad) 8 released | 0xC9 | (keypad) 9 released | 0xCA | (keypad) - released | 0xCB | (keypad) 4 released |
0xCC | (keypad) 5 released | 0xCD | (keypad) 6 released | 0xCE | (keypad) + released | 0xCF | (keypad) 1 released |
0xD0 | (keypad) 2 released | 0xD1 | (keypad) 3 released | 0xD2 | (keypad) 0 released | 0xD3 | (keypad) . released |
0xD7 | F11 released | ||||||
0xD8 | F12 released | ||||||
0xE0, 0x10 | (multimedia) previous track pressed | ||||||
0xE0, 0x19 | (multimedia) next track pressed | ||||||
0xE0, 0x1C | (keypad) enter pressed | 0xE0, 0x1D | right control pressed | ||||
0xE0, 0x20 | (multimedia) mute pressed | 0xE0, 0x21 | (multimedia) calculator pressed | 0xE0, 0x22 | (multimedia) play pressed | ||
0xE0, 0x24 | (multimedia) stop pressed | ||||||
0xE0, 0x2E | (multimedia) volume down pressed | ||||||
0xE0, 0x30 | (multimedia) volume up pressed | 0xE0, 0x32 | (multimedia) WWW home pressed | ||||
0xE0, 0x35 | (keypad) / pressed | ||||||
0xE0, 0x38 | right alt (or altGr) pressed | ||||||
0xE0, 0x47 | home pressed | ||||||
0xE0, 0x48 | cursor up pressed | 0xE0, 0x49 | page up pressed | 0xE0, 0x4B | cursor left pressed | ||
0xE0, 0x4D | cursor right pressed | 0xE0, 0x4F | end pressed | ||||
0xE0, 0x50 | cursor down pressed | 0xE0, 0x51 | page down pressed | 0xE0, 0x52 | insert pressed | 0xE0, 0x53 | delete pressed |
0xE0, 0x5B | left GUI pressed | ||||||
0xE0, 0x5C | right GUI pressed | 0xE0, 0x5D | "apps" pressed | 0xE0, 0x5E | (ACPI) power pressed | 0xE0, 0x5F | (ACPI) sleep pressed |
0xE0, 0x63 | (ACPI) wake pressed | ||||||
0xE0, 0x65 | (multimedia) WWW search pressed | 0xE0, 0x66 | (multimedia) WWW favorites pressed | 0xE0, 0x67 | (multimedia) WWW refresh pressed | ||
0xE0, 0x68 | (multimedia) WWW stop pressed | 0xE0, 0x69 | (multimedia) WWW forward pressed | 0xE0, 0x6A | (multimedia) WWW back pressed | 0xE0, 0x6B | (multimedia) my computer pressed |
0xE0, 0x6C | (multimedia) email pressed | 0xE0, 0x6D | (multimedia) media select pressed | ||||
0xE0, 0x90 | (multimedia) previous track released | ||||||
0xE0, 0x99 | (multimedia) next track released | ||||||
0xE0, 0x9C | (keypad) enter released | 0xE0, 0x9D | right control released | ||||
0xE0, 0xA0 | (multimedia) mute released | 0xE0, 0xA1 | (multimedia) calculator released | 0xE0, 0xA2 | (multimedia) play released | ||
0xE0, 0xA4 | (multimedia) stop released | ||||||
0xE0, 0xAE | (multimedia) volume down released | ||||||
0xE0, 0xB0 | (multimedia) volume up released | 0xE0, 0xB2 | (multimedia) WWW home released | ||||
0xE0, 0xB5 | (keypad) / released | ||||||
0xE0, 0xB8 | right alt (or altGr) released | ||||||
0xE0, 0xC7 | home released | ||||||
0xE0, 0xC8 | cursor up released | 0xE0, 0xC9 | page up released | 0xE0, 0xCB | cursor left released | ||
0xE0, 0xCD | cursor right released | 0xE0, 0xCF | end released | ||||
0xE0, 0xD0 | cursor down released | 0xE0, 0xD1 | page down released | 0xE0, 0xD2 | insert released | 0xE0, 0xD3 | delete released |
0xE0, 0xDB | left GUI released | ||||||
0xE0, 0xDC | right GUI released | 0xE0, 0xDD | "apps" released | 0xE0, 0xDE | (ACPI) power released | 0xE0, 0xDF | (ACPI) sleep released |
0xE0, 0xE3 | (ACPI) wake released | ||||||
0xE0, 0xE5 | (multimedia) WWW search released | 0xE0, 0xE6 | (multimedia) WWW favorites released | 0xE0, 0xE7 | (multimedia) WWW refresh released | ||
0xE0, 0xE8 | (multimedia) WWW stop released | 0xE0, 0xE9 | (multimedia) WWW forward released | 0xE0, 0xEA | (multimedia) WWW back released | 0xE0, 0xEB | (multimedia) my computer released |
0xE0, 0xEC | (multimedia) email released | 0xE0, 0xED | (multimedia) media select released | ||||
0xE0, 0x2A, 0xE0, 0x37 | print screen pressed | ||||||
0xE0, 0xB7, 0xE0, 0xAA | print screen released | ||||||
0xE1, 0x1D, 0x45, 0xE1, 0x9D, 0xC5 | pause pressed |
9、
1)每个键按下和弹起时,都会产生扫描码(scan code)
2)扫描码根据字节量可分为三种:
- 单个字节
- 以E0开头的2字节或4字节
- 以E1开头的6字节(只有一两个键)、
3)扫描码根据按下和弹起,又分为:make code,break code,区别是扫描码的最高位第7位是否为1
例如:
-
当A键按下时,产生扫描码0x1E(第7位为0);断开时,产生扫描码0x9E(第7位为1)
-
当光标向左键按下时,产生扫描码0xE0, 0x4B(第7位为0);断开时,产生扫描码0xE0, 0xCB(第7位为1)
9、处理caplock键
这个键本身并不任何有效的字符输入,而是用于控制其它键输入的效果。
-
capslock:每按1次转换一下,键上方有对应的大小写指示灯(绿灯亮为大写字母输入模式,反之为小写字母输入模式)。如果shift键和Capslock键一起按时,是小写字母模式
10、其他特殊功能健
在不同的操作系统和应用程序下可能有不同的用户,例如在浏览器中,F1键可能是用于打开帮助页面。我们现在是在键盘驱动程序中编写代码,F1等功能键不对应于任何具体的字符,也不对应具体的功能;因此,目前只是在代码中将其识别出来,具体有什么用可以留等以后扩展。