鍵盤涤躲,萌寶相信大家都不陌生,天天與它打交道贡未。
但熟歸熟种樱,清楚鍵盤背后的原理嗎蒙袍?
鍵盤上都標(biāo)有各鍵的名稱,表明了各鍵所代表的意義缸托,但是計算機是如何知道的左敌?
組合鍵是怎樣實現(xiàn)的瘾蛋?
按下一個代表字符的鍵俐镐,怎么變成平常使用的ASCII碼的?
#第七魂技?武魂真身#
01
相關(guān)介紹
鍵盤編碼器
鍵盤編碼器(i8048)哺哼,是鍵盤里的芯片佩抹,主要用來監(jiān)控是否有鍵按下,彈起取董,然后向鍵盤控制器報告此鍵的相關(guān)信息棍苹。
鍵盤掃描碼
一個鍵有按下就會有彈起,所以每個鍵會有兩個狀態(tài)茵汰,即每個鍵將會對應(yīng)兩個掃描碼枢里,鍵被按下時的編碼叫做通碼(makecode),彈起時的編碼叫做斷碼(breakcode)蹂午。
鍵盤控制器
鍵盤控制器(i8042)栏豺,不在鍵盤內(nèi)部,被集成在南橋芯片上豆胸。
它主要是接收鍵盤編碼器發(fā)來的掃描碼(第二套)奥洼,解碼(轉(zhuǎn)成第一套)后保存到自己的寄存器中,然后通過中斷控制器發(fā)送中斷請求晚胡。
i8042有4個寄存器灵奖,如下所示:
注:輸入輸出要視對象決定,對鍵盤控制器來說是輸出估盘,那么對CPU來說則是輸入瓷患,使用 in 指令。
02
鍵盤中斷流程
其實上述的相關(guān)介紹已經(jīng)涉及了部分鍵盤中斷流程遣妥,在此從頭至尾具體說說尉尾,先看流程圖:
03
鍵盤中斷服務(wù)程序
鍵盤中斷在所有的可屏蔽中斷中優(yōu)先級僅次于時鐘中斷,也需要盡快的處理燥透。
在Linux 0.11里的整個鍵盤服務(wù)程序都是用匯編來寫的沙咏,匯編語言直接操作底層的指令,沒有編譯器來增加額外的東西班套,所以運行起來比高級語言寫的程序快肢藐,但也增加了編寫程序的難度。
linux0.11版本的鍵盤中斷服務(wù)程序的框架源碼如下圖所示:
這個框架程序主要做了以下事情:
保護現(xiàn)場——壓棧
上文中寫到壓棧ss, esp, ?eflags, cs, eip, error_code (若有特權(quán)級變化且中斷帶有錯誤碼) 來保存現(xiàn)場吱韭,那只是CPU自動執(zhí)行的部分吆豹,完全保存原任務(wù)的信息還是在中斷處理程序中進行的鱼的。
如上圖所示,鍵盤中斷服務(wù)程序里通用寄存器只保存了4個痘煤,eax, ebx, ecx, edx凑阶,若為了省事不追求效率完全可以無腦操作pushad壓榨所有的通用寄存器。
#壞了壞了#
讀取掃描碼
inb $0x60, al ?從鍵盤控制器的輸出緩存區(qū)0x60端口讀取掃描碼衷快。
若不從輸出緩沖區(qū)讀取數(shù)據(jù)的話宙橱,鍵盤控制器是不會繼續(xù)工作的,意思是無論你怎么按鍵蘸拔,鍵盤控制器不會響應(yīng)鍵盤操作师郑,不會存下新的掃描碼發(fā)送中斷信號等。
當(dāng)然不讀取掃描碼后續(xù)的鍵盤中斷程序也沒法工作沒有意義调窍。
判斷是否為 0xe0 或 0xe1
如果掃描碼是 0xe0 或者 0xe1宝冕,那說明這個鍵的掃描碼是有多個字節(jié)的,需要先保存下來等待接下來的掃描碼組合成完整的掃描碼邓萨。?
尋址地梨、調(diào)用相應(yīng)的鍵處理程序
拿到完整的掃描碼之后就該去尋找相應(yīng)的鍵處理程序了
源碼中有個key_table,table, 說明它是一張表缔恳,或者說一個數(shù)組
這里面就按照掃描碼大小存放了各個鍵的實際處理程序地址宝剖。
如何找到相應(yīng)的鍵處理程序呢?
其實跟數(shù)組用下表獲取元素一樣
據(jù)源碼所示采用比例變址尋址的方式褐耳,即key_table(, %eax, 4)
也就是說相應(yīng)的鍵處理程序的地址是key_table + eax * 4诈闺。key_table
相當(dāng)于數(shù)組首地址;
eax里面存放的掃描碼铃芦,掃描碼可以看成數(shù)字索引號
相當(dāng)于數(shù)組下標(biāo)雅镊;
地址32位,4字節(jié)刃滓,所以乘4
回復(fù)現(xiàn)場—出線
壓棧保護現(xiàn)場的逆過程仁烹,在此不再贅述
萌寶要提醒各位,需要注意執(zhí)行到 iret 時的棧頂應(yīng)是 eip哦~