Xmodmapからhwdb + xkbへ

新しい環境をセットアップするたびに問題になる「X.orgのままにするか、Waylandに移行するか」問題。実家に帰省中にやることがなかったので、その作業を進めてみた。

設定したいキー読み替え

物理的に押すキー 機能してほしいキー
CapsLock Escape
Right Alt 変換
Right Shift 無変換
PgUp Home
PgDown End
: ;
; :
  • NeoVimを使う際にEscは連打したいので、Capsに割り当てる。
  • 日本語切り替えにはMozc側で「変換で日本語入力ON」、「変換無変換で日本語入力OFF」としている(日本語キーボードを使っていたなごり)ので、変わりにR AltとRシフトを使う。
  • XPS13はカーソルキーの斜め上にPageUp/Downが付いているが、Home/Endとして使う。
  • コロンはシフトなしで押せるようにする。

という状況である。.Xmodmap

! vi: set ft=xmodmap :

clear lock
keysym Caps_Lock = Escape

remove mod1 = Alt_R
keysym Alt_R = Henkan_Mode

remove shift = Shift_R
keysym Shift_R = Muhenkan

! 47 -> : ;
keycode 47 = colon semicolon

!PageUp -> Home
keycode 112 = Home Home Home Home

!PageDown -> End
keycode 117 = End End End End

という感じであった。これと同等の設定をWaylandで実現できればいい。

hwdb

基本的にスキャンコードをキーコードにマップ - ArchWikiを参考に設定する。

こいつはキーボードのボタン自体のコードを書き換えるやつである。CapsをEscやCtrlにするなどボタンのラベルを変えたり、位置をまるごと逆にする場合などは適切だが、Modキーとのコンビネーションについてはこいつでは扱えない。例えばシフトキーの状態で入力が変化するコロンとセミコロンを逆にしたりはできない。

アプリケーションによってはキーコードを直接拾うものもあるので、こちらでいじれるものはできるだけこっちでやる。

キーコードは以下のように調べる。

$ ls -l /dev/input/by-path/* | grep kbd
lrwxrwxrwx 1 root root  9  9月 25 03:48 /dev/input/by-path/platform-i8042-serio-0-event-kbd -> ../event4

で番号を調べて、evtestでイベントを調べる。

# sudo evtest /dev/input/event4
(**中略**)
Event: time 1664045570.619893, -------------- SYN_REPORT ------------
Event: time 1664045570.653465, type 4 (EV_MSC), code 4 (MSC_SCAN), value 3a
Event: time 1664045570.653465, type 1 (EV_KEY), code 1 (KEY_ESC), value 2
Event: time 1664045570.653465, -------------- SYN_REPORT ------------
Event: time 1664045570.682258, type 4 (EV_MSC), code 4 (MSC_SCAN), value 3a
Event: time 1664045570.682258, type 1 (EV_KEY), code 1 (KEY_ESC), value 2
Event: time 1664045570.682258, -------------- SYN_REPORT ------------
Event: time 1664045570.715827, type 4 (EV_MSC), code 4 (MSC_SCAN), value 3a
Event: time 1664045570.715827, type 1 (EV_KEY), code 1 (KEY_ESC), value 2
Event: time 1664045570.715827, -------------- SYN_REPORT ------------

これは変更後の出力だが、例えばCapsLockを押すとこのような出力になり、CapsLockのキーコードはvalue 3aであることがわかる。そして実際にcode 1のEscとして機能していることがわかる。

設定するには/etc/udev/hwdb.d/*.hwdb という感じでファイルを作る。自分の場合はXPS 13 9305を使っているので、/etc/udev/hwdb.d/10-xps.hwdbとした。

evdev:atkbd:dmi:*
  KEYBOARD_KEY_3a=esc
  KEYBOARD_KEY_36=muhenkan
  KEYBOARD_KEY_b8=henkan
  KEYBOARD_KEY_c9=home
  KEYBOARD_KEY_d1=end

一応evdev:のセクションでキーボードのモデルの指定できるが、今回はatkbd:dmi:*であらゆるATキーボードを対象としている。

ちなみに新しいキーコードは、

$ sed -n '/KEY_/{s/.*KEY_\([A-Za-z0-9_]\+\).*/\L\1/g;p}' /usr/include/linux/input-event-codes.h | fzf

といった感じに調べることができる。

XKB

これでレイアウトを指定する。JPキーボードからUSキーボードに移行した際に入力がおかしくなるのを経験すると思うが、レイアウト指定がずれることによって起こる齟齬である。

このレイアウト設定自体をカスタマイズすることで好きなキー割当を実現できる。

デフォルトで様々なレイアウトや固定の読み替えオプション(Caps as Ctrl)が定義されており、デフォルトレイアウトにそれらを組み合わせることもできるが、今回は特殊な事例なのでusレイアウトやjpレイアウトなどとともに提供される、customレイアウトをいじることにする。

XKBレイアウトとfcitx5組み込みのレイアウトについて

実際に使用するレイアウトはfcitx5で設定するが、そのレイアウトは$XDG_CONFIG_HOME/fcitx5/conf/cached_layoutsとしてキャッシュされている。そしてこのレイアウトはおそらく/usr/share/X11/xkb/rules/base.lstなどから読み取られている。

しかし単純にbase.lstの方にエントリーを追加するだけではキャッシュ側に反映されなかった。validなレイアウトを追加には他にも記述すべきファイルがあるはずだが、それを調べる手間もあるし、何より編集するファイル数が増え、手続きが煩雑となるはずである。

なので今回は元から用意されているcustomレイアウトを流用する。

/usr/share/X11/xkb/symbols/custom というファイルを作って以下のように記述する。

default partial alphanumeric_keys modifier_keys
xkb_symbols "basic" {
    include "us(basic)"
    name[Group1]= "CUSTOM";
    key <AC10>	{[ colon, semicolon ]};

    // hwdbを使わずここで設定することも可能である
    // key <CAPS> {[ Escape ]};
    // key <RALT> {[ Henkan_Mode, Henkan_Mode ]};
    // key <RTSH> {[ Muhenkan ]};
    // key <UP>   {[ Home, Home, Home, Home ] };
    // key <DOWN> {[ End, End, End, End ] };
};

xkb_symbolsセクションではinclude "us(basic)"とった形で、他のシンボル定義をインクルードできる。基本的なUS配列をコピーした上で、上記のコロンとセミコロンの入れ替えを定義する。

fcitxでレイアウト指定する

「A user-defined custom Layout」というエントリがcustomのそれ

fcitx5_config.png

ここでcustomを指定すれば設定完了。

あとがき

「なんだれ面倒くせえなあ」と思っていたが、キーボードの入力は

物理ボタン→キーコード→文字の対応

という2つのフェーズがあることがわかる。hwdbは1つ目の矢印、xkbは2つ目の矢印を制御するものだと思えば、それぞれどちらも必要であることがわかる。

この調子で自宅のデスクトップも移行したいが、Waylandだとデスクトップセッションが起動すらしなかった。NVIDIA関連に落とし穴が多そうなのでまた時間があるときにゆっくりやろうと思う。

参考