公開日: 2021年7月4日

Xorg のキーマップをカスタマイズしようと思う

私はデスクトップ PC、ノート PC、VMware 仮想マシン上の計 3 ヵ所に FreeBSD をインストールして利用していますが、こうなるとキーボード事情も三者三様であり、「あっちで使えていたキーバインドがこっちじゃ使えねえ!」といったことが起こります。これを解消すべく xmodmap というソフトウェアでいろいろ試したところ、そこそこ納得のいく結果が得られたので、記事にまとめておきます。

きっかけとゴール

私はデスクトップ PC でサンワサプライの SKB-SL18BKN というキーボードを使用しています。また、それとは別にヒューレット・パッカードの SPECTRE 13-af520TU というノート PC も所有しています。はじめのうちは気がつかなかったんですが、両者のキーボードには重大な (?) 相違があるんですね…。それぞれのキーボードの左下を見てください (図 1)。そう!SPECTRE のキーボードには「無変換」キーがないんです1)awesome というウィンドウマネージャの紹介記事で Mod4 修飾キーについて触れました。当初、思いつきで 無変換キーに Mod4 を割り当てたのですが、SPECTRE のキーボードではそれが不可能であることに気がつき、できるだけ両者に共通のキー配列にしたいと考えたのがことの次第です。

もう一点、これも同記事で触れましたが、Xorg のデフォルトでは Mod4 キーはたいてい Windows キーが割り当てられており、このことが VMware で FreeBSD をゲスト OS として使う場合に問題となります。ホスト OS である Windows のショートカットキーとかち合ってしまうのです。例えば、awesome のマスターウィンドウの幅を広げるつもりで「Mod4 + l」を押すとWindows 側でログアウトが発生します。という訳で VMware 上での使用も考慮に入れます。

さらにもう一点、重要な動機があります。「CapsLock と 左 Ctrl の入れ替え」です (メジャーすぎる話題ですが…)。

  1. SPECTRE 13-af520TU はカラーが「アッシュブラック」「セラミックホワイト」の 2 種類あり、なぜか「アッシュブラック」のモデルだけが英語キーボード仕様のため無変換キーがないのです。

以上をまとめて、日本語キーボード、英語キーボードそれぞれ下記のように変更しようと思います (図 2)。

  • 日/英共通設定
    • CapsLock キーを Control とする
    • 左 Ctrl キーを Mod4 とする
  • 日本語キーボード向け設定
    • 無変換キーを Mod1 (Alt) とする
    • 変換キーを Mod1 (Alt) とする
    • カタカナ/ひらがなキーを Mod4 とする
    • アプリケーションキーを Mod4 とする
  • 英語キーボード向け設定
    • 右 Ctrl キーを Mod4 とする

ちなみに「アプリケーションキー」とは、図 1 でいうところのカタカナ/ひらがなキーと左矢印キーの間にあるキーのことらしいです。

なお、「日本語キーボード」「英語キーボード」といっても広範であり、本記事の内容がそのまま別のケースに適用できるとは限りません。そこで本記事では「日本語キーボード」といったらサンワサプライの SKB-SL18BKN を、「英語キーボード」といったらヒューレット・パッカード SPECTRE 13-af520TU の英語キーボードを指すものとします。

図 1
図 1
図 2
図 2

キーコードとキーシム

キー配列を変更するためには、変更するキーの「キーコード」と「キーシム」を調べる必要があります。
キーコード:キーボード上の物理的なキーの各々に対して振られる番号。環境によって異なる番号になることもある。
キーシム:キーコードに割り当てられている値。キャラクタコード表に対応している (キャラクタコード表についてはググってください)。
例えば「a」キーの場合、私の環境では、キーコードが 38、キーシムが 0x61 でした。CapsLock キーの右隣にあるキーをぽちっと押すと、画面に「a」と表示されるのは、この対応表に因っています。この表のことを「キーマップテーブル」と呼びます。上にも書いたように、キーコードは環境によって異なるので、何らかの方法で自分の環境のキーコードを知る必要がある訳ですが、xev というツールがその役に立ちます。端末エミュレータから次のようにして起動します。
% xev | grep keycode
すると黒い正方形が描かれた小さなウィンドウが表示されるので、その中にマウスカーソルを持っていって、何かキーを押してみましょう。例えば a キーとか。xev を起動した端末エミュレータに次のように出力されるはずです。
state 0x0, keycode 38 (keysym 0x61, a), same_screen YES,
state 0x0, keycode 38 (keysym 0x61, a), same_screen YES,
キーコードが 38、キーシムが 0x61 とわかります。キーシムの隣にある「a」はキーシム名です。キー配列を変更するということは、当該キーコードに与えられているキーシムに別のキーシムを与えなおすということになります。ただし、そのキーが修飾キーである場合はもうひと手間必要です。

修飾キー (モディファイアキー)

Shift キーや Ctrl キーなど、他のキーと組み合わせて使用するキーを修飾キー (モディファイアキー) と呼びます。どのような修飾キーがあるかは xmodmap -pm コマンドで調べることができます。
% xmodmap -pm
xmodmap:  up to 4 keys per modifier, (keycodes in parentheses):

shift       Shift_L (0x32),  Shift_R (0x3e)
lock        Caps_Lock (0x42)
control     Control_L (0x25),  Control_R (0x69)
mod1        Alt_L (0x40),  Alt_R (0x6c),  Meta_L (0xcd)
mod2        Num_Lock (0x4d)
mod3
mod4        Super_L (0x85),  Super_R (0x86),  Super_L (0xce),  Hyper_L (0xcf)
mod5        ISO_Level3_Shift (0x5c),  Mode_switch (0xcb)
この表から、例えばキーコード 50 (0x32) と 62 (0x3e) のキーが Shift の役割を果たす修飾キーとして登録されていることがわかります。この対応表を「モディファイアマップテーブル」と呼び、ここに登録されているキーのキーシムを変更する場合は、当該キーをいったんテーブルから削除し、キーシムを与えなおした後、再度テーブルに登録するという操作が必要になります。

設定ファイルを準備する

それでは実際のカスタマイズに入ります。自分のホームディレクトリに .Xmodmap というファイルを用意し (中身は後述)、ログイン時にそれが読み込まれるようにします。X Window System の導入記事に書いた方法で /usr/local/etc/X11/xinit/xinitrc をコピーして ~/.xinitrc を作成した場合は、ログイン時に ~/.Xmodmap を読み込む設定がすでに書かれています。ない場合は次のような記述を加えてください。
~/.xinitrc
usermodmap=$HOME/.Xmodmap
...
if [ -f "$usermodmap" ]; then
    xmodmap "$usermodmap"
fi
.Xmodmap の具体的な中身は次節以降に掲載しますが、先に記述方法についてざっくり説明します。詳しくは xmodmap(1) の man ページを参照してください。ここで使用する操作は下記の 4 種類です。
  • remove MODIFIERNAME = KEYSYMNAME ...

    KEYSYMNAME で指定されたキーシムを、MODIFIERNAME で指定されたモディファイヤマップから削除する。

  • clear MODIFIERNAME

    MODIFIERNAME で指定されたモディファイヤマップに登録されているすべてのキーシムを削除する。

  • keycode NUMBER = KEYSYMNAME ...

    NUMBER で指定されたキーコードに KEYSYMNAME で指定されたキーシムを割り当てる。

  • add MODIFIERNAME = KEYSYMNAME ...

    MODIFIERNAME で指定されたモディファイヤマップに KEYSYMNAME で指定されたキーシムを登録する。

それでは次節以降で、日本語キーボード、VMware における日本語キーボード、英語キーボードそれぞれのケース別に ~/.Xmodmap を紹介します。

日本語キーボードの場合

スペースキーの左右に陣取るキーはゴッソリ Mod1 と Mod4 にしてしまいます。
日本語キーボードの場合
変更前のモディファイアマップテーブル
shift       Shift_L (0x32),  Shift_R (0x3e)
lock        Caps_Lock (0x42)
control     Control_L (0x25),  Control_R (0x69)
mod1        Alt_L (0x40),  Alt_R (0x6c),  Meta_L (0xcd)
mod2        Num_Lock (0x4d)
mod3
mod4        Super_L (0x85),  Super_R (0x86),  Super_L (0xce),  Hyper_L (0xcf)
mod5        ISO_Level3_Shift (0x5c),  Mode_switch (0xcb)
~/.Xmodmap
remove lock = Caps_Lock
remove control = Control_L
keycode 66 = Control_L
keycode 37 = Super_L
keycode 101 = Super_R
keycode 102 = Alt_L
keycode 100 = Alt_R
keycode 135 = Super_R
add control = Control_L
add mod1 = Alt_L Alt_R
add mod4 = Super_L Super_R
変更後のモディファイアマップテーブル
shift       Shift_L (0x32),  Shift_R (0x3e)
lock
control     Control_L (0x42),  Control_R (0x69)
mod1        Alt_L (0x40),  Alt_R (0x64),  Alt_L (0x66),  Alt_R (0x6c),  Alt_L (0xcc),  Meta_L (0xcd)
mod2        Num_Lock (0x4d)
mod3
mod4        Super_L (0x25),  Super_R (0x65),  Super_L (0x85),  Super_R (0x86),  Super_R (0x87),  Super_L (0xce),  Hyper_L (0xcf)
mod5        ISO_Level3_Shift (0x5c),  Mode_switch (0xcb)

VMware における日本語キーボードの場合

VMware への FreeBSD の導入については別記事を参照してください。

前提として、ホスト OS である Windows 側では、レジストリ設定により CapsLock キーと左 Ctrl キーを交換済みであるとします。その具体的な方法についてはググっていただきたいのですが、ざっくり説明すると、次のようなテキストファイルを書いて「SwapCapsCtrl.reg」とか何とか適当に名前をつけて保存し、ダブルクリックすることでレジストリに反映させます。レジストリをいじることになるので、やっていることを理解の上、自己責任で行ってください。

Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout]
"Scancode Map"=hex:00,00,00,00,00,00,00,00,\
                   03,00,00,00,3a,00,1d,00,\
                   1d,00,3a,00,00,00,00,00
こちらのケースも、スペースキーの左右に陣取るキーをゴッソリ Mod1 と Mod4 にしてしまいます。上記の前提があるので、CapsLock と 左 Ctrl の変更前のキーシムが前節とは逆になっています。
VMware における日本語キーボードの場合
変更前のモディファイアマップテーブル
shift       Shift_L (0x32),  Shift_R (0x3e)
lock        Caps_Lock (0x42)
control     Control_L (0x25),  Control_R (0x69)
mod1        Alt_L (0x40),  Alt_R (0x6c),  Meta_L (0xcd)
mod2        Num_Lock (0x4d)
mod3
mod4        Super_L (0x85),  Super_R (0x86),  Super_L (0xce),  Hyper_L (0xcf)
mod5        ISO_Level3_Shift (0x5c),  Mode_switch (0xcb)
~/.Xmodmap
remove lock = Caps_Lock
keycode 66 = Super_L
keycode 101 = Super_R
keycode 102 = Alt_L
keycode 100 = Alt_R
keycode 147 = Super_R
add mod1 = Alt_L Alt_R
add mod4 = Super_L Super_R
変更後のモディファイアマップテーブル
shift       Shift_L (0x32),  Shift_R (0x3e)
lock
control     Control_L (0x25),  Control_R (0x69)
mod1        Alt_L (0x40),  Alt_R (0x64),  Alt_L (0x66),  Alt_R (0x6c),  Alt_L (0xcc),  Meta_L (0xcd)
mod2        Num_Lock (0x4d)
mod3
mod4        Super_L (0x42),  Super_R (0x65),  Super_L (0x85),  Super_R (0x86),  Super_R (0x93),  Super_L (0xce),  Hyper_L (0xcf)
mod5        ISO_Level3_Shift (0x5c),  Mode_switch (0xcb)

英語キーボードの場合

日本語キーボードの場合とだいたい同じ配置になるように、左右の Ctrl キーにMod4 を割り当てます。
英語キーボードの場合
変更前のモディファイアマップテーブル
shift       Shift_L (0x32),  Shift_R (0x3e)
lock        Caps_Lock (0x42)
control     Control_L (0x25),  Control_R (0x69)
mod1        Alt_L (0x40),  Alt_R (0x6c),  Meta_L (0xcd)
mod2        Num_Lock (0x4d)
mod3
mod4        Super_L (0x85),  Super_R (0x86),  Super_L (0xce),  Hyper_L (0xcf)
mod5        ISO_Level3_Shift (0x5c),  Mode_switch (0xcb)
~/.Xmodmap
remove lock = Caps_Lock
clear control
keycode 66 = Control_L
keycode 37 = Super_L
keycode 105 = Super_R
add control = Control_L
add mod4 = Super_L Super_R
変更後のモディファイアマップテーブル
shift       Shift_L (0x32),  Shift_R (0x3e)
lock
control     Control_L (0x42)
mod1        Alt_L (0x40),  Alt_R (0x6c),  Meta_L (0xcd)
mod2        Num_Lock (0x4d)
mod3
mod4        Super_L (0x25),  Super_R (0x69),  Super_L (0x85),  Super_R (0x86),  Super_L (0xce),  Hyper_L (0xcf)
mod5        ISO_Level3_Shift (0x5c),  Mode_switch (0xcb)

Xorg のキーマップを三つのケースに分けて検討しました。そもそも日本語キーボードと英語キーボードを両方使っている人がどれくらいいるんだろう?とか awesome を使う人じゃないと Mod4 なんか使わないよなーとか考え出すと、大して需要もなさそうな記事に随分労力をつぎ込んだものです。でも何かしらご参考になれば幸いでございます。