最好的输入是输出
输入
综述
这里面有两个核心函数,keyboard_handler()
和 keyboard_read()
。其中,keyboard_handler()
是键盘中断的处理程序,作用是将扫描码加入到缓冲区中。这个缓冲区,其实就是一个 队列
,p_tail
指向下一个要被处理的字节, p_head
指向下一个空闲的空间。而 keyboard_read
是我们的 tty
进程的守护程序,功能是从缓冲区读取扫描码并解析。
代码解析
在 keyboard_read()
这个函数中有一句
make = (scan_code & FLAG_BREAK ? FALSE : TRUE) ;
这一句的作用是判断扫描码是 make code 还是 break code,至于 Why it works ?
,解释如下:
纵观
make code
的键盘扫描码,除去0xE0
0xE1
开头的,没有一个可打印的扫描码是0x8X
或者以上的,或者说,两位十六进制的扫描码化成 8 位二进制后最高位没有是 1 的。所以,与上FLAG_BREAK
:0x80
或者10000000
能够将make code
清零。
之前我在看这一部分的内容的时候,有一个问题总是不能理解,就是程序究竟是如何处理 shift
被长按的呢?下载终于有了解答:
我们的
keyboard_read()
每一次都只从缓冲区里面读出一个扫描码,所以如果是按下shift
然后按下其他的键的,第一次首先处理shift
,标志变量shift_l
或者shift_r
被置位,然后读取下一个扫描码,注意由于此时 shift 键没有松手,所以下一个读到的扫描码是你按完 shift 之后按的那个讲的扫描码,而不是 shift 键的break code
。由于shift_l
或者shift_r
已经被置位,所以在 扫描数组读的是第二列。注意,虽然我们的扫描数组是一个一维数组,不过这个是为了方便,操作时我们还是将它视作一个二位数组,变量column
就是用来控制列的。这样,就可以处理 shfit 键被按下了。
TTY
目前 TTY
的作用就是能够控制输出的位置,它将我们的可用的 32k
显存分成了 3 块,每一块就是一个 TTY
。因为多了这样的一层,所以,在处理上也就多了一层。之前我们是这样子处理的:
按下键盘 -> 触发中断 -> 调用
keyboard_handler()
->keyboard_handler()
函数不断地将扫描码
加入到缓冲区中 -> 任务TTY
(注意,它现在只是名字叫TTY
而已,还不具备TTY
的功能)不断地调用keyboard_read()
,解析扫描码并且输出。
现在,我们有了 TTY
,可以实现 多终端
了,由于每一个 终端
都有自己的显示区间,所以,在显示的时候,过程就是这样:
按下键盘 -> 触发中断 -> 调用
keyboard_handler()
->keyboard_handler()
函数不断地将扫描码
加入到缓冲区中 -> 任务task_tty
设置好当前的终端console
,再进行一系列的初始化 -> 其实task_tty()
的任务主线就是一个守护进程, 不断轮询所有的console
,对每个console
都进行tty_do_write()
还有tty_do_read
不停地切换。tty_do_read()
的作用是如果轮询到的console
是当前终端的话,那么就从键盘缓冲区中读取一个扫描码并且进行解析,然后交给in_process()
函数进行处理,这里的处理跟我们没有 多终端 的时候有一点区别。我们之前是直接输出,现在的话,是将解析之后的key
放在当前console
自己的缓冲区。tty_do_write()
的作用就是在当前console
的缓冲区里面读取一个已经解析好的key
值,然后交给out_char()
进行相应的输出。
这样,这个 TTY
的过程应该就相当的清晰了~
遇到的问题
今天,在编译的时候遇到了一个很奇怪的问题,一直报下面的错误:
static declaration of ‘tty_do_read’ follows non-static declaration
一直无解,百度以后,发现了错误的根源:
出这个问题是把实现放在调用后面了
C 语言里面要么需要先申明函数,要么就必须把函数实现放到函数调用之前
经验
前几天在实现 printf
的时候,出现了一个问题,然后解决无果。因此懈怠了很多天,今天终于把问题解决了。我发现,解决问题的方法就是从问题本身出发,根据问题找到相应的出错点,在找到相应的代码,一点一点地找,总会找到的。不过,这需要你对你的代码相当地熟悉。
这一章总算是结束了,向 下篇 进军!!!
EOF
Author: simowce
Permalink: https://blog.simowce.com/chapter-7-input/
本作品采用 知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议 进行许可。