ottijp blog

initramとttyとxorgのキーマップを合わせる

もうmacOSを動かすには老朽化してしまったMacBook ProにArch Linuxを入れて遊んでます.

cf. 前回の記事

linuxのキーマップは色々設定の仕方があり,競合しないようにしたり統一するのが大変だったのでメモしておきます.

やりたいこと

  • initram(LUKSの暗号化パスワード入力時)でもttyでもxorgでも,ctrlとcapslockを入れ替えたい
  • ttyとxorgではctrl+gでESCを入力したい
    • 昔なぜか設定したこのキーマップで慣れてしまっているので,今更変えられない.
    • vimを使っているがctrl+[は両手が必要で使いづらいので,片手でタイプできてかつあまり他で使っていないctrl+gを割り当てている.
    • macOSではHammerspoonで実現している.

環境

  • MacBook Pro: 13-inch, 2017, Thunderbolt 3ポートx2 (A1708, MacBookPro14,1)
  • Arch Linux
  • Linux Kernel: 6.16.6-arch1-1

最終的な解決方法

以下のように設定することで,「やりたいこと」が実現できました.

initram

ctrlとcapslockを入れ替えるキーマップをusをベースに作成し,カスタムのHookを作ってinitramfsを作成しました. personal.map.gzはこちらで作成したものです. (FILESにカスタムしたキーマップファイルを入れるだけでそれを読んでくれるとPerplexyは言っていたのですが,それではうまく動かなかったのでカスタムHookを作成しました.)

まずはincludeされているマップを含んだフラットなキーマップファイルを作成します.

sudo loadkeys personal
dumpkeys | sudo tee /usr/local/share/kbd/keymaps/personal-flat.map

次にinitram用のカスタムHookを作成します.

/etc/initcpio/hooks/mykeymap
run_hook() {
    loadkeys /usr/local/share/kbd/keymaps/personal-flat.map
}
/etc/initcpio/install/mykeymap
build() {
    add_binary /usr/bin/loadkeys
    add_file /usr/local/share/kbd/keymaps/personal-flat.map
    add_runscript
}

initramfsの設定におけるHOOKSにあるkeymapmykeymapに入れ替えます.

/etc/mkinitcpio.conf(抜粋)
HOOKS=(base udev modconf keyboard mykeymap autodetect microcode kms consolefont block encrypt filesystems fsck)

initramfsを再作成します.

sudo mkinitcpio -P

ttyとxorg

後述するように,色々試した結果,私がやりたいESCへのキーマップはrootでxremapする方法でしかできなかったので,xremapの設定を作ってサービス化しました.

まずはxremapをインストールします.

sudo paru -S xremap-x11-bin

ctrlとcapslockの入れ替え,ctrl+gからESCのキーマップを行うxremapの設定を作成します.

/etc/xremap/config.yml
modmap:
  - name: swap Ctrl and CapsLock
    remap:
      CapsLock: Control_L
      Control_L: CapsLock
keymap:
  - name: remap Ctrl+G to Escape
    remap:
      C-g: esc

xremapをサービス化します.

/etc/systemd/system/xremap.service
[Unit]
Description=Xremap
After=default.target

[Service]
ExecStart=/usr/bin/xremap --watch=device /etc/xremap/config.yml
Restart=always
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=default.target
sudo systemctl enable xremap

これで,ログインプロンプトの時点から設定したキーマップが有効になります.

xremapはttyでも効くので(ttyでswapが2回効いてしまい戻ってしまうので),もともとカスタマイズしていた/etc/vconsle.confの設定はデフォルトに戻しました.

/etc/vconsole.conf
#KEYMAP=/usr/local/share/kbd/keymaps/personal

試したけどダメだったこと

特にctrl+gをESCにマップできなくて苦労しました.

xfce4のキーボードショートカットとxdotool

xfce4のキーボード設定にあるキーボードショートカットに,ctrl+gに対するコマンドとしてxdotoolによるキー送信を設定してみましたが,ダメでした.

  • xdotool key Escape
    • ショートカットが発動したときにCtrlが押されたままの状態でEscapeが送信されることで,コンテクストポップアップメニューが開いてしまう.
  • xdotool keyup Control_L && xdotool key Escape && xdotool keydown Control_L
    • コンテキストポップアップメニューは出ないが,Escapeが入力されない.
  • xdotool keyup Control_L && sleep 0.01 && xdotool key Escape && sleep 0.01 && xdotool keydown Control_L
    • 一瞬うまくいった時があった気もするが安定しない.
    • 動作後,Ctrlが押されっぱなしになったりする.

autokey-gtk

xfce4上で実行しても起動しなかったです(やり方が悪いのかも).

xkb

どうやらxkbはcontrol単独をレベル選択にはできないようで.どうやってもだめだった.

具体的にはxkbcomp $DISPLAY my.xkbとして作成したmy.xkbに対して以下のように編集をして,

my.xkb(抜粋)
type "BASE_SHIFT_CTRL" {
    modifiers= Shift+Control;
    map[None]= Level1;
    map[Shift]= Level2;
    map[Control]= Level3;
    level_name[Level1]= "Base";
    level_name[Level2]= "Shift";
    level_name[Level3]= "Cntrol";
};

key <AC05> {
    type= "BASE_SHIFT_CTRL",
    symbols= [g, G ,Escape]
};

それを読み込んだ後で

xkbcomp my.xkb $DISPLAY

ctrl+gを押した時の状況をxevコマンドで確認したところ,KeymapNotifyが表示され,マップしたつもりのESCが出力されませんでした. これはESC以外の”G”のような印字可能なキャラクタをctrl+gにマップしても同じでした.

xorgの設定でswapとcapslockの入れ替え

これはダメだったことではないですが,xremapを導入したことで不要になったので以下の設定は削除しました.

/etc/X11/xorg.conf.d/00-keyboard.conf
Section "InputClass"
    Identifier "system-keyboard"
    MatchIsKeyboard "on"
    Option "XkbOptions" "ctrl:swapcaps"
EndSection

xremapを非rootで実行する

公式のGitHubの説明に従ってやってみましたが,非rootでxremapを実行時に以下のようなエラーが出てうまく動きませんでした.

Error: Failed to prepare an output device: Permission denied (os error 13)

私の環境では私しかこのマシンを使わないので,非rootでの実行は必須ではなく,rootでのサービス化をしました.


© 2025, ottijp