Linux 將鍵盤的傳輸層報告、穩定的輸入按鍵碼,以及鍵盤配置產生的文字或動作分離。保持這些層級分開,可以解釋為何 PS/2 與 USB 鍵盤能產生不同的硬體資料,卻都回報 KEY_F。
概觀 #
輸入遵循四個概念階段:
- 傳輸驅動程式接收位元組或報告。
atkbd驅動程式處理 AT 與 PS/2 掃描碼集合,usbhid剖析 USB HID 用法。 - 驅動程式剖析按下、放開、前綴與重複狀態,然後回報 Linux 輸入按鍵碼,例如帶有按下、放開或重複值的
KEY_F(33)。 - 輸入核心透過 evdev 發布事件。圖形合成器或輸入函式庫通常會對這些事件套用自己的配置。
- 對 Linux 虛擬主控台,核心鍵盤層套用作用中的主控台鍵盤映射,並向終端層發出位元組、Unicode 字元、字串或主控台動作。
因此,掃描碼不是字元,而 Linux 按鍵碼也不是 X11、Wayland 或 Unicode 碼點。
IBM PC、XT 與 AT 協定 #
原始的 83 鍵 IBM PC 與 PC/XT 鍵盤建立了現在稱為掃描碼集合 1 的位元組指派。它們的介面實際上是鍵盤到主機:鍵盤提供有時脈的序列資料,但主機沒有用於控制 LED、重複與掃描集合選擇的 AT 命令協定。一般集合 1 按下會使用 0x01 至 0x7f 的按下位元組;放開該按鍵時設定位元 7。例如,Escape 按下產生 0x01,放開產生 0x81。
84 鍵 IBM PC/AT 鍵盤引入雙向介面與掃描碼集合 2。集合 2 變更的是位置,而不是以數值延伸集合 1:左 Control 在集合 2 是 0x14,在集合 1 則是 0x1d。放開序列使用 0xf0 前綴,因此左 Control 按下產生 14,放開產生 f0 14。主機可以傳送命令設定 LED、打字重複行為與作用中的集合。
PC 相容的 AT 控制器通常會將集合 2 位元組轉換為集合 1 形式,以維持軟體相容性。因此 Linux 會將許多內建鍵盤識別為 AT Translated Set 2 keyboard:實體鍵盤使用集合 2,而控制器暴露轉換後的位元組。與 IBM 終端機及後來 PS/2 設計相關的掃描碼集合 3,獨立指派額外按鍵,並支援每鍵的按下、放開與打字重複設定。目前 Linux atkbd 原始碼支援轉換後集合 2、原始集合 2 與集合 3;集合 2 仍是預設值。
USB 鍵盤不會傳送這些 AT 位元組串流。它們傳送包含用法識別碼的 HID 報告,而 HID 輸入驅動程式將這些用法映射至相同的 Linux KEY_* 命名空間。
掃描碼序列 #
按下也稱為按下碼,放開稱為放開碼。按住的打字重複按鍵會在設定的延遲後產生重複按下報告;它不會交替產生按下與放開。Linux 輸入介面將硬體或軟體自動重複表示為 EV_KEY 值 2。
0xe0 前綴擴充集合 1 與集合 2。例如,集合 1 左 Control 使用 1d/9d,而右 Control 使用 e0 1d/e0 9d。集合 2 則使用 14/f0 14 與 e0 14/e0 f0 14。0xe1 前綴引入 Pause 等例外序列。Print Screen 與 Pause 是多位元組相容序列,而不是只有一個位元組的一般按鍵。驅動程式必須將串流剖析為狀態機,因為獨立處理每個位元組會產生虛假的 Shift 或 Control 事件。
「掃描碼」一詞也用於較高層級的傳輸識別碼。例如,evdev EV_MSC/MSC_SCAN 值可以編碼 USB HID 用法,例如 0x70009,而相關的 EV_KEY 事件仍是 KEY_F(33)。舊集合 1 值與早期 Linux 按鍵碼之間的數值巧合是歷史結果,不是介面不變量。
核心掃描碼至按鍵碼映射 #
每個低階驅動程式擁有自己的協定映射。AT 驅動程式索引可替換的預設掃描碼至按鍵碼表;HID 驅動程式從 HID 用法衍生按鍵碼。Linux 按鍵碼定義於 UAPI input-event-codes.h,並超出原始 1–255 主控台範圍。
setkeycodes 會修改主控台 AT 鍵盤路徑的選定映射。它接受逸出的集合 1 掃描碼與十進位按鍵碼等配對:
sudo setkeycodes e06f 112該命令不會重新映射任意 USB HID 裝置,也不會定義按鍵碼 112 產生的字元。使用 loadkeys 載入的主控台鍵盤映射會執行第二項作業。現代桌面輸入堆疊則在使用者空間套用配置。
主控台鍵盤映射、修飾鍵與字元集 #
keymaps(5) 檔案描述 Linux 虛擬主控台的轉譯表。keycode N = ... 依作用中的修飾鍵遮罩選取動作。核心鍵盤層為 Shift(1)、AltGr(2)、Control(4)、Alt(8)、ShiftL(16)、ShiftR(32)、CtrlL(64)、CtrlR(128)與 CapsShift(256)定義權重。映射檔案只列出所需組合:
keymaps 0-2,4-5,8,12
keycode 30 = +a A
control alt keycode 111 = Boot按鍵符號可以發出字元、字串、變更修飾鍵或鎖定、切換虛擬主控台,或要求其他主控台動作。前導 + 表示字母對 Caps Lock 敏感。string F100 = "text" 綁定函式字串動作,而組合定義會在 Compose 或死鍵動作後組合兩個輸入字元:
compose '`' 'a' to 'à'charset "iso-8859-1" 宣告控制後續符號按鍵符號的解讀方式。數值按鍵符號在核心版本間不可攜;應優先使用符號名稱或 U+hhhh Unicode 記法。虛擬主控台的 K_UNICODE 模式會為 Unicode 按鍵符號發出 UTF-8,而 K_XLATE 套用傳統位元組導向轉譯。K_MEDIUMRAW 暴露以按鍵碼為導向的資料,K_RAW 暴露原始掃描位元組的近似值。這些主控台模式不會變更 evdev ABI。
輸入與主控台裝置節點 #
/proc/bus/input/devices 與 /sys/class/input 列舉輸入裝置及其處理器。/dev/input/eventN 是由原生 struct input_event 記錄組成的二進位 evdev 串流。鍵盤記錄通常包括:
- 驅動程式提供時,
EV_MSC/MSC_SCAN表示傳輸識別碼; EV_KEY帶有KEY_*碼及值 0(放開)、1(按下)或 2(重複);以及EV_SYN/SYN_REPORT終止一個事件框架。
請使用 evtest 或 libevdev,而不要解碼 hexdump,因為記錄大小與時間欄位遵循讀取程序的使用者空間 ABI:
grep -A5 -B1 -i keyboard /proc/bus/input/devices
sudo evtest /dev/input/event4讀取事件節點需要系統輸入裝置原則所指定的權限,並可能暴露在該裝置上任何地方輸入的密碼。
/dev/tty1、/dev/tty2 與其他虛擬終端節點,在主控台鍵盤映射轉譯與行規程處理後暴露終端輸入。/dev/tty0 指向作用中的虛擬終端;/dev/console 指向已設定的系統主控台,不是原始鍵盤裝置。
主控台工具 #
請從真正的虛擬終端執行主控台模式工具,而不是終端機模擬器:
showkey -s、showkey -k與showkey -a顯示掃描碼、按鍵碼與以字元為導向的檢視。若程式被中斷,原始模式可能暫時使主控台無法使用。getkeycodes顯示 AT 驅動程式目前的掃描碼映射。setkeycodes SCANCODE KEYCODE ...變更選定的 AT 映射。dumpkeys以keymaps(5)語法寫出目前主控台配置;dumpkeys --long-info也會列出已知按鍵符號。loadkeys FILE將鍵盤映射編譯並安裝至核心主控台表。
上游 Linux 輸入文件、事件碼規格、目前的 atkbd 原始碼與上游 keymaps(5)定義此處所述的介面。
評論
在 GitHub 上閱讀或評論(發表評論需要登入)