Linux は、キーボードの転送レベルのレポートを、安定した入力キーコード、および
キーボードレイアウトが生成するテキストやアクションから分離します。これらの層を
分けることで、PS/2 と USB キーボードが異なるハードウェアデータを生成しながら、
どちらも KEY_F を報告できる理由を説明できます。
概要 #
入力は概念的に 4 段階をたどります。
- 転送ドライバーがバイトまたはレポートを受け取ります。
atkbdドライバーは AT と PS/2 のスキャンコードセットを処理し、usbhidは USB HID usage を解析します。 - ドライバーは make、break、プレフィックス、repeat の状態を解析し、押下、解放、
repeat の値とともに
KEY_F(33) などの Linux 入力キーコードを報告します。 - 入力コアは evdev を通じてイベントを公開します。グラフィカルコンポジターまたは 入力ライブラリは通常、これらのイベントに独自のレイアウトを適用します。
- Linux 仮想コンソールでは、カーネルキーボード層がアクティブなコンソールキーマップ を適用し、バイト、Unicode 文字、文字列、コンソールアクションを端末層へ出力します。
したがってスキャンコードは文字ではなく、Linux キーコードは X11、Wayland、Unicode のコードポイントではありません。
IBM PC、XT、AT プロトコル #
初期の 83 キー IBM PC および PC/XT キーボードは、現在スキャンコードセット 1 と
呼ばれるバイト割り当てを確立しました。インターフェイスは実質的にキーボードから
ホストへの一方向で、キーボードはクロック付きシリアルデータを供給しましたが、
ホストには LED、repeat、スキャンセット選択を制御する AT コマンドプロトコルが
ありませんでした。通常のセット 1 の押下は 0x01 から 0x7f の make バイトを使い、
そのキーを解放するとビット 7 が設定されます。たとえば Escape は押下時に 0x01、
解放時に 0x81 を生成します。
84 キー IBM PC/AT キーボードは双方向インターフェイスとスキャンコードセット 2 を
導入しました。セット 2 はセット 1 を数値的に拡張するのではなく位置を変更しました。
左 Control はセット 2 では 0x14、セット 1 では 0x1d です。break シーケンスは
0xf0 プレフィックスを使うため、左 Control は押下時に 14、解放時に f0 14 を
生成します。ホストは LED、typematic 動作、アクティブセットを設定するコマンドを
送信できます。
PC 互換 AT コントローラーは、ソフトウェア互換性のためにキーボードのセット 2 の
バイトをセット 1 形式へ変換することがよくあります。そのため Linux は多くの内蔵
キーボードを AT Translated Set 2 keyboard と識別します。物理キーボードはセット 2
を話し、コントローラーは変換済みバイトを公開します。IBM 端末と後期 PS/2 設計に
関連するスキャンコードセット 3 は、追加キーを独立して割り当て、キーごとの make、
break、typematic 設定をサポートします。現在の Linux atkbd ソースは変換済み
セット 2、raw セット 2、セット 3 をサポートし、セット 2 がデフォルトです。
USB キーボードはこれらの AT バイトストリームを送信しません。usage 識別子を含む
HID レポートを送信し、HID 入力ドライバーがその usage を同じ Linux KEY_* 名前空間
へマッピングします。
スキャンコードシーケンス #
押下は make、解放は break とも呼ばれます。押し続けた typematic キーは設定
された遅延後に make レポートを繰り返し生成し、make と break を交互に生成するわけ
ではありません。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 値は 0x70009 のような USB HID usage をエンコード
できますが、対応する EV_KEY イベントは依然として KEY_F (33) です。古いセット 1
値と初期 Linux キーコードの数値的一致は歴史的なもので、インターフェイス不変条件
ではありません。
カーネルのスキャンコードからキーコードへのマッピング #
各低レベルドライバーがプロトコルのマッピングを所有します。AT ドライバーはデフォルト
で置換可能なスキャンコードからキーコードへのテーブルを索引付けし、HID ドライバー
は HID usage からキーコードを導出します。Linux キーコードは UAPI の
input-event-codes.h
and extend beyond the original 1–255 console range.
setkeycodes はコンソール AT キーボード経路の選択したマッピングを変更します。
エスケープされたセット 1 スキャンコードと 10 進キーコードなどのペアを受け取ります。
sudo setkeycodes e06f 112このコマンドは任意の USB HID デバイスをリマップせず、キーコード 112 が生成する文字
も定義しません。loadkeys でロードしたコンソールキーマップが後者の操作を行います。
現代のデスクトップ入力スタックは代わりにユーザー空間のレイアウトを適用します。
Console Keymaps, Modifiers, and Character Sets #
A keymaps(5) file describes the Linux virtual-console translation table.
keycode N = ... selects an action according to the active modifier mask. The
kernel keyboard layer defines weights for Shift (1), AltGr (2), Control (4), Alt
(8), ShiftL (16), ShiftR (32), CtrlL (64), CtrlR (128), and CapsShift (256).
Map files list only the combinations they need:
keymaps 0-2,4-5,8,12
keycode 30 = +a A
control alt keycode 111 = BootKeysyms can emit characters, strings, change a modifier or lock, switch virtual
consoles, or request another console action. A leading + marks a letter as
Caps-Lock-sensitive. string F100 = "text" binds a function-string action, while a
compose definition combines two input characters after a Compose or dead-key action:
compose '`' 'a' to 'à'A charset "iso-8859-1" declaration controls how subsequent symbolic keysyms are
interpreted. Numeric keysyms are not portable between kernel versions; symbolic
names or U+hhhh Unicode notation are preferable. The virtual console’s
K_UNICODE mode emits UTF-8 for Unicode keysyms, whereas K_XLATE applies the
legacy byte-oriented translation. K_MEDIUMRAW exposes keycode-oriented data and
K_RAW exposes an approximation of raw scan bytes. Those console modes do not
change the evdev ABI.
Input and Console Device Nodes #
/proc/bus/input/devices and /sys/class/input enumerate input devices and their
handlers. /dev/input/eventN is a binary evdev stream of native
struct input_event records. Keyboard records commonly include:
EV_MSC/MSC_SCANfor a transport identifier when the driver supplies one;EV_KEYwith aKEY_*code and value 0 (release), 1 (press), or 2 (repeat); andEV_SYN/SYN_REPORTto terminate one event frame.
Use evtest or libevdev rather than decoding a hexdump, because record size and
time fields follow the userspace ABI of the reading process:
grep -A5 -B1 -i keyboard /proc/bus/input/devices
sudo evtest /dev/input/event4Reading an event node requires the permissions assigned by the system’s input-device policy and can expose passwords typed anywhere on that device.
/dev/tty1, /dev/tty2, and the other virtual-terminal nodes expose terminal input
after console keymap translation and line-discipline processing. /dev/tty0 refers
to the active virtual terminal; /dev/console refers to the configured system
console and is not a raw keyboard device.
Console Utilities #
Run console-mode tools from a real virtual terminal rather than a terminal emulator:
showkey -s,showkey -k, andshowkey -adisplay scan-code, keycode, and character-oriented views. Raw mode can make the console temporarily unusable if the program is interrupted.getkeycodesdisplays the AT driver’s current scan-code mappings.setkeycodes SCANCODE KEYCODE ...changes selected AT mappings.dumpkeyswrites the current console layout inkeymaps(5)syntax;dumpkeys --long-infoalso lists known keysyms.loadkeys FILEcompiles and installs a keymap into the kernel console tables.
The upstream Linux input documentation,
event-code specification, current
atkbd source,
and upstream keymaps(5)
define the interfaces described here.
コメント
GitHub で閲覧・コメントする(投稿にはログインが必要です)