鍵盤輸入和文本輸出如何工作?
假設我
A
在文本編輯器中按下鍵,這會將字元插入a
到文件中並將其顯示在螢幕上。我知道編輯器應用程序沒有直接與硬體通信(中間有一個核心和其他東西),那麼我的電腦內部發生了什麼?
有幾種不同的情況;我將描述最常見的。連續的宏觀事件是:
- 輸入:按鍵事件從鍵盤硬體傳輸到應用程序。
- 處理:應用程序決定因為按鍵
A
被按下,所以它必須顯示字元a
。- 輸出:應用程序給出在
a
螢幕上顯示的命令。圖形使用者界面應用程序
unix 系統事實上的標準圖形使用者界面是X Window 系統,通常稱為 X11,因為它穩定在應用程序和顯示伺服器之間的核心協議的第 11 版。一個稱為 X 伺服器的程序位於作業系統核心和應用程序之間。它提供的服務包括在螢幕上顯示視窗以及將按鍵傳送到具有焦點的視窗。
輸入
+----------+ +-------------+ +-----+ | keyboard |------------->| motherboard |-------->| CPU | +----------+ +-------------+ +-----+ USB, PS/2, … PCI, … key down/up
首先,關於按鍵和按鍵釋放的資訊從鍵盤傳輸到電腦和電腦內部。細節取決於硬體的類型。我不會更多地討論這部分,因為資訊在整個鏈的這一部分中保持不變:按下或釋放某個鍵。
+--------+ +----------+ +-------------+ -------->| kernel |------->| X server |--------->| application | +--------+ +----------+ +-------------+ interrupt scancode keysym =keycode +modifiers
當硬體事件發生時,CPU 會觸發一個中斷,這會導致核心中的一些程式碼執行。此程式碼檢測硬體事件是來自鍵盤的按鍵或按鍵釋放,並記錄辨識按鍵的掃描程式碼。
X 伺服器通過設備文件讀取輸入事件,例如
/dev/input/eventNNN
在 Linux 上(其中 NNN 是一個數字)。每當發生事件時,核心都會發出信號,表明有數據要從該設備讀取。設備文件使用掃描碼傳輸按鍵向上/向下事件,掃描碼可能與硬體傳輸的值相同也可能不同(核心可以將掃描碼從依賴於鍵盤的值轉換為通用值,而 Linux不會’不要重新傳輸它不知道的掃描碼)。X 呼叫它讀取 keycode 的掃描碼。X 伺服器維護一個將鍵碼轉換為鍵符(“鍵符”的縮寫)的表。鍵碼是數字,而鍵符是名稱,例如
A
,aacute
,F1
,KP_Add
,Control_L
, … 鍵符可能因按下的修飾鍵而異(Shift
,Ctrl
, …)。有兩種機制可以配置從鍵碼到鍵符的映射:
應用程序連接到 X 伺服器並在該應用程序的視窗具有焦點時按下某個鍵時接收通知。該通知表明某個鍵符被按下或釋放,以及目前按下了哪些修飾符。您可以通過
xev
從終端執行程序來查看鍵符。應用程序對資訊的處理取決於它;一些應用程序具有可配置的鍵綁定。在典型配置中,當您按下
A
沒有修飾符的鍵時,這會將鍵符發送a
到應用程序;如果應用程序處於您正在輸入文本的模式下,則會插入字元a
.鍵盤佈局和 xmodmap 的關係更詳細地介紹了鍵盤輸入。滑鼠事件在 linux 中是如何工作的?概述了較低級別的滑鼠輸入。
輸出
+-------------+ +----------+ +-----+ +---------+ | application |------->| X server |---····-->| GPU |-------->| monitor | +-------------+ +----------+ +-----+ +---------+ text or varies VGA, DVI, image HDMI, …
有兩種顯示字元的方法。
- 伺服器端渲染:應用程序告訴 X 伺服器“在這個位置用這個字型繪製這個字元串”。字型駐留在 X 伺服器上。
- 客戶端渲染:應用程序建構一個圖像,以它選擇的字型表示字元,然後告訴 X 伺服器顯示該圖像。
請參閱不同類型的 XWindows 字型的用途是什麼?討論 X11 下的客戶端和伺服器端文本渲染。
X 伺服器和圖形處理單元(影片卡上的處理器)之間發生的事情非常依賴於硬體。簡單的系統讓 X 伺服器在稱為framebuffer的記憶體區域中繪製,GPU 將其用於顯示。任何 21 世紀 PC 或智能手機上的先進系統都允許 GPU 直接執行某些操作以獲得更好的性能。最終,GPU 會每分每秒將螢幕內容逐個像素地傳輸到顯示器。
文本模式應用程序,在終端中執行
如果您的文本編輯器是在終端中執行的文本模式應用程序,那麼終端就是上述部分的應用程序。在本節中,我將解釋文本模式應用程序和終端之間的介面。首先我描述一個在 X11 下執行的終端仿真器的情況。“終端”、“外殼”、“tty”和“控制台”之間的確切區別是什麼?這裡可能是有用的背景。閱讀完本文後,您可能想閱讀更詳細的每個偽終端 (PTY) 組件(軟體、主端、從端)的職責是什麼?
輸入
+-------------------+ +-------------+ ----->| terminal emulator |-------------->| application | +-------------------+ +-------------+ keysym character or escape sequence
終端仿真器接收諸如“
Left
被按下時Shift
被按下”之類的事件。終端仿真器和文本模式應用程序之間的介面是一個偽終端 (pty),一種傳輸字節的字元設備。當終端仿真器接收到按鍵事件時,它會將其轉換為應用程序從 pty 設備讀取的一個或多個字節。ASCII 範圍之外的可列印字元根據字元和編碼作為一個或多個字節傳輸。例如,在Unicode字元集的UTF-8編碼中, ASCII範圍內的字元被編碼為單個字節,而超出該範圍的字元被編碼為多個字節。
對應於功能鍵或帶有修飾符的可列印字元的按鍵,例如
Ctrl
或Alt
作為轉義序列發送。轉義序列通常由字元轉義(字節值 27 = 0x1B =\033
,有時表示為^[
or\e
)後跟一個或多個可列印字元組成。一些鍵或鍵組合在基於 ASCII 的編碼中具有與它們對應的控製字元(今天幾乎所有這些都在使用,包括 Unicode):Ctrl
+letter
產生一個 1-26 範圍內的字元值,Esc
是轉義字元如上所示,也與Ctrl
+相同[
,與+Tab
相同,Ctrl``I``Return``Ctrl
與+M
等相同。不同的終端為給定的鍵或鍵組合發送不同的轉義序列。幸運的是,相反的情況並非如此:給定一個序列,實際上它最多可以編碼一個組合鍵。一個例外是字元 127 = 0x7f =
\0177
這通常是Backspace
但有時是Delete
。在終端中,如果您鍵入
Ctrl
+V
後跟一個組合鍵,這將按字面意思從組合鍵中插入轉義序列的第一個字節。由於轉義序列通常只包含第一個之後的可列印字元,因此這會按字面意思插入整個轉義序列。查看鍵綁定表?在這種情況下討論 zsh。終端可能會為某些修飾符組合傳輸相同的轉義序列(例如,許多終端為
Space
和Shift
+傳輸空格字元Space
;xterm 具有區分修飾符組合的模式,但基於流行的 vte 庫的終端沒有)。一些鍵根本不傳輸,例如修改鍵或觸發終端仿真器綁定的鍵(例如復製或粘貼命令)。如果需要,由應用程序將轉義序列轉換為符號鍵名。
輸出
+-------------+ +-------------------+ | application |-------------->| terminal emulator |---> +-------------+ +-------------------+ character or escape sequence
輸出比輸入更簡單。如果應用程序將字元輸出到 pty 設備文件,終端仿真器會在目前游標位置顯示它。(終端模擬器保持游標位置,如果游標落在螢幕底部下方,則滾動。)應用程序還可以輸出轉義序列(主要以
^[
or開頭^]
)告訴終端執行諸如移動游標之類的操作,更改文本屬性(顏色、粗體……),或擦除部分螢幕。終端仿真器支持的轉義序列在termcap或terminfo數據庫中描述。如今,大多數終端仿真器都與xterm密切相關。請參閱有關 LESS_TERMCAP_* 變數的文件?有關終端功能資訊數據庫的更長時間的討論,以及如何停止游標閃爍以及我可以設置本地機器的終端顏色以使用我 ssh 進入的機器的顏色嗎?一些使用範例。
在文本控制台中執行的應用程序
如果應用程序直接在文本控制台中執行,即由核心提供的終端而不是終端仿真器應用程序,則適用相同的原則。終端和應用程序之間的介面仍然是傳輸字元的字節流,特殊的鍵和命令被編碼為轉義序列。
遠端應用程序,通過網路訪問
遠端文本應用程序
如果您在遠端機器上執行程序,例如通過SSH,那麼網路通信協議會在 pty 級別中繼數據。
+-------------+ +------+ +-----+ +----------+ | application |<--------->| sshd |<--------->| ssh |<--------->| terminal | +-------------+ +------+ +-----+ +----------+ byte stream byte stream byte stream (char/seq) over TCP/… (char/seq)
這主要是透明的,只是有時遠端終端數據庫可能不知道本地終端的所有功能。
遠端 X11 應用程序
應用程序和伺服器之間的通信協議本身就是一個字節流,可以通過 SSH 等網路協議發送。
+-------------+ +------+ +-----+ +----------+ | application |<---------->| sshd |<------>| ssh |<---------->| X server | +-------------+ +------+ +-----+ +----------+ X11 protocol X11 over X11 protocol TCP/…
這主要是透明的,除了一些需要應用程序和顯示器之間直接通信的加速功能(例如電影解碼和 3D 渲染)不可用。