Linux で X よりも低レイヤでキーマップを変更する
まとめ
USB 接続の ThinkPad トラックポイントキーボードで、半角/全角
を Esc
、CapsLock
を Ctrl
として使うには、/etc/udev/hwdb.d/10-tmtms.hwdb
というファイル(ファイル名は何でもいい)を次の内容で作って:
evdev:name:Lenovo ThinkPad Compact USB Keyboard with TrackPoint:dmi:bvn*:bvr*:bd*:svnLENOVO:pn*
KEYBOARD_KEY_70035=esc
KEYBOARD_KEY_70039=leftctrl
次のコマンドを実行する:
% sudo udevadm hwdb --update
% sudo udevadm trigger
以下は調査とかなので読まなくてもいい
30年くらい Emacs を使ってたんだけど、そろそろ VSCode を使ってみようかーと思って使ってみた。
デフォルトではカーソル移動がカーソルキーだけでショートカットキーが用意されてないっぽくて、使い始めくらいはデフォルト設定のまま使ってみようと思ってたんだけど、さすがにカーソルキーを使うのは厳しいので、結局 Awesome Emacs Keymap というのを入れた。
Use Meta Prefix Escape
という設定を有効にすれば M-
に Esc
キーを使うこともできる。
が、うまく動かなかった。元々の物理キーの Esc
であれば効くんだけど、xmodmap や XKB で設定した Esc
だと効かない(1
の左隣の 半角/全角
を Esc
に変更してる)。
xev で調べてもちゃんと keysym は Escape になってる:
KeyPress event, serial 37, synthetic NO, window 0x1800001,
root 0x7c7, subw 0x0, time 906346, (72,68), root:(3823,1069),
state 0x0, keycode 49 (keysym 0xff1b, Escape), same_screen YES,
XKeysymToKeycode returns keycode: 9
XLookupString gives 1 bytes: (1b) "
mbLookupString gives 1 bytes: (1b) "
FilterEvent returns: False
ということは keysym じゃなくて keycode を使ってるのかもしれない。
X レベルではどうしようもなさそうなので、それよりも低いレイヤで keycode を変更できないかとググってみたら、setkeycodes というのでできるらしい。
どうやらキーボードからの物理的なコード(スキャンコード)をキーコードに変換するマップを変更できるらしい。
X 上じゃ駄目で、コンソールでやる必要があるみたいなので、Ctrl-Alt-1
とかでコンソールに移ってから実行する(Alt-7
とかで X に戻れる)。
showkey -s
で 半角/全角
のスキャンコードを調べる:
% showkey -s
kb mode was UNICODE
[ if you are trying this under X, it might not work
since the X server is also reading /dev/console ]
press any key (program terminates 10s after last keypress)...
0x29 0xa9
Ctrl-C
では止まらない。10秒以上放置すると終了する。
showkey -k
で Esc
のキーコードを調べる:
% showkey -s
kb mode was UNICODE
[ if you are trying this under X, it might not work
since the X server is also reading /dev/console ]
press any key (program terminates 10s after last keypress)...
keycode 1 press
keycode 1 release
スキャンコード 0x29 をキーコード 1 に変換すればいいらしいので、setkeycodes
を実行:
% sudo setkeycodes 0x29 1
これでノートPCの本体キーボードの方はちゃんと変わったんだけど、USBキーボードの方は効いてない。
man page には次のように書いてあった。(Ubuntu の man setkeycodes にはこの記述は無かった)
setkeycodes affects only the "first" input device that has modifiable scancode-to-keycode mapping. If there is more than one such device, setkeycodes cannot change the mapping of other devices than the "first" one.
ということで、USB の ThinkPad トラックポイントキーボードを使ってる自分は別の方法を考える必要があるのだった。
またググってみたら、こんなページを見つけた。
どうやら udev を使えばできるらしい。
evdev:name:<input device name>:dmi:bvn*:bvr*:bd*:svn<vendor>:pn*
KEYBOARD_KEY_<scancode>=<keycode>
という形式で指定すれば良さそう。
<input device name>
はたぶん xinput の名前を使えば良さそう:
% xinput
⎡ Virtual core pointer id=2 [master pointer (3)]
⎜ ↳ Virtual core XTEST pointer id=4 [slave pointer (2)]
⎜ ↳ TPPS/2 IBM TrackPoint id=16 [slave pointer (2)]
⎜ ↳ Lenovo ThinkPad Compact USB Keyboard with TrackPoint id=10 [slave pointer (2)]
⎜ ↳ Synaptics TM3145-003 id=15 [slave pointer (2)]
⎣ Virtual core keyboard id=3 [master keyboard (2)]
↳ Virtual core XTEST keyboard id=5 [slave keyboard (3)]
↳ Power Button id=6 [slave keyboard (3)]
↳ Video Bus id=7 [slave keyboard (3)]
↳ Sleep Button id=8 [slave keyboard (3)]
↳ Generic USB2.0 Microphone id=11 [slave keyboard (3)]
↳ Integrated Camera: Integrated C id=12 [slave keyboard (3)]
↳ AT Translated Set 2 keyboard id=13 [slave keyboard (3)]
↳ ThinkPad Extra Buttons id=14 [slave keyboard (3)]
↳ Lenovo ThinkPad Compact USB Keyboard with TrackPoint id=9 [slave keyboard (3)]
↳ Lenovo ThinkPad Compact USB Keyboard with TrackPoint id=17 [slave keyboard (3)]
Lenovo ThinkPad Compact USB Keyboard with TrackPoint
という名前らしい。
<vendor>
はよくわからなかったけど、たぶん LENOVO
。*
でもいいのかもしれない。
<scancode>
の調べ方は evtest を使えばいいらしい。
入ってなかったので sudo apt insttall evtest
でインストール。
引数の /dev/input/eventXX
はこんな感じで調べられた:
% ls -l /dev/input/by-path/*usb*kbd
lrwxrwxrwx 1 root root 9 9月 24 12:15 /dev/input/by-path/pci-0000:00:14.0-usb-0:3:1.0-event-kbd -> ../event5
evtest を起動して 半角/全角
キーと Esc
を押す:
% sudo evtest /dev/input/event5
...
Testing ... (interrupt to exit)
Event: time 1632465959.559163, type 4 (EV_MSC), code 4 (MSC_SCAN), value 70035
Event: time 1632465959.559163, type 1 (EV_KEY), code 41 (KEY_GRAVE), value 1
Event: time 1632465959.559163, -------------- SYN_REPORT ------------
Event: time 1632465959.606785, type 4 (EV_MSC), code 4 (MSC_SCAN), value 70035
Event: time 1632465959.606785, type 1 (EV_KEY), code 41 (KEY_GRAVE), value 0
Event: time 1632465959.606785, -------------- SYN_REPORT ------------
Event: time 1632465965.087102, type 4 (EV_MSC), code 4 (MSC_SCAN), value 70029
Event: time 1632465965.087102, type 1 (EV_KEY), code 1 (KEY_ESC), value 1
Event: time 1632465965.087102, -------------- SYN_REPORT ------------
Event: time 1632465965.126598, type 4 (EV_MSC), code 4 (MSC_SCAN), value 70029
Event: time 1632465965.126598, type 1 (EV_KEY), code 1 (KEY_ESC), value 0
Event: time 1632465965.126598, -------------- SYN_REPORT ------------
半角/全角
のスキャンコードは 70035
で、Esc
のキーコードは ESC
らしい。
(半角/全角
なのに GRAVE
と表示されてるのは気にしなくていい。日本語キーボードなのに英語配列を選択してるためなので。)
Esc
だけじゃなくて、ついでに CapsLock
を左Ctrl
に変更する方法も同様にして調べた。
Capslock
のスキャンコードは 70039
で、左Ctrl
のキーコードは LEFTCTRL
だった。
/etc/udev/hwdb.d/10-tmtms.hwdb
というファイルを作る(ファイル名は何でもいい):
evdev:name:Lenovo ThinkPad Compact USB Keyboard with TrackPoint:dmi:bvn*:bvr*:bd*:svnLENOVO:pn*
KEYBOARD_KEY_70035=esc
KEYBOARD_KEY_70039=leftctrl
キーコードは小文字で書かないといけないらしい。
データベースファイルを更新:
% sudo udevadm hwdb --update
反映:
% sudo udevadm trigger
確認:
% udevadm info /dev/input/event5 | grep KEYBOARD_KEY
E: KEYBOARD_KEY_70035=esc
E: KEYBOARD_KEY_70039=leftctrl
ということでちゃんと VSCode でも 半角/全角
を Esc
として使えるようになった。この記事も VSCode で書いてみた。(まだ慣れない)
Discussion