Xmodmap でお好みのキーバインド

前フリ

プログラマのみなさんならキーボードにこだわりを持ってなおかつタイピング速度を0.01秒でも稼ぐために日夜キーバインドを研究されていることと思います。

そんな私は Windows では AutoHotKeyLinux では Xmodmap、Mac では KeyRemap4Mac を愛用しております。

新しい環境や新しいキーボードが手に入ったりするとまずはキーボードの設定から、という方も多いのではないでしょうか。

私は HHK を長年愛用しており、新しいコンピュータを購入したら何はともあれコイツをつないで、キーバインドの設定からはじめます。

とはいえ、もう長いこと使い込んだ設定ファイルの類はそんなに直す機会はないのですが、近頃 RealForce のお下がりをもらったのでこれをもう少し使いこんでみようとしておりまして、久しぶりに設定ファイルを書くハメになったわけです。

このキーボードを Linux で使うことにしたので、Xmodmap の設定ファイルを新たに作る必要があります。

しかし Xmodmap の書き方をすっかり忘れてしまっていたのでメモしておきます。
(どうも Web 上に転がってる情報は古いのが多いのか、設定ファイルのフォーマットとかも最近のものとは異なるようですし、統一的な情報がまとめられたページが日本語/英語ともに見当たりませんでしたので。もしかしてキーバインドを変更するような人ってもはやオールドタイプというか生きた化石というか obsoleted で deprecated な存在!?)


キーバインドの設定の大まかな流れは以下のようになります。

  1. xev コマンドで、どのキーを押したらどのようなキーコードがキーボードから送られてくるかをチェック
  2. キーコードがわかったら .Xmodmap ファイルにキーバインドを記述


私は HHK では左◇キーと h, j, k, l をそれぞれ同時に押したらそれがカーソルキーになるといったキーバインドを設定していますので、RealForce でも同様なキーバインドができるようになることを想定しています。

それ以上複雑なことはしようとは今のところ考えていません。


それでは、さっそく始めましょう。


1. xev コマンドで、どのキーを押したらどのようなキーコードがキーボードから送られてくるかをチェック

まず、おもむろにターミナルから xev コマンドを実行します。
すると、Event Tester という白いウインドウが出てくると思います。
同時に、ターミナルにはいろいろなイベントの情報がずらずらと表示されると思います。

Event Tester にフォーカスを合わせ、何かキーを押してみましょう。

たくさんの情報が表示されると思いますが、そのなかから KeyPress イベントや KeyRelease イベントを探しましょう。

KeyPress event, serial 36, synthetic NO, window 0x4200001,
    root 0xb6, subw 0x0, time 30146314, (1536,-767), root:(1602,494),
    state 0x0, keycode 64 (keysym 0xffe9, Alt_L), same_screen YES,
    XLookupString gives 0 bytes: 
    XmbLookupString gives 0 bytes: 
    XFilterEvent returns: False

KeyRelease event, serial 36, synthetic NO, window 0x4200001,
    root 0xb6, subw 0x0, time 30146434, (1536,-767), root:(1602,494),
    state 0x8, keycode 64 (keysym 0xffe9, Alt_L), same_screen YES,
    XLookupString gives 0 bytes: 
    XFilterEvent returns: False

それぞれ 3 行目くらいに
keycode 64 (keysym 0xffe9, Alt_L)
っていうのが見えると思います。

これは私の持っているキーボードで左 Alt キーを押した時の例です。

目的の数字は 64 です。
他のキーを押すとここが別の値になっていると思います。
また、同じ左 Alt キーでも、環境が異なれば別の値になっているかもしれません。


以下のコマンドを実行すると、現在割り当てられているキーバインドの一覧を確認することができます。

$ xmodmap -pke 


キーバインドを設定したいキーをいろいろ押してみたり、上記の一覧を参照しながら、そのキーコードをメモしておきましょう。

私の場合は、HHK で ◇ キーに相当する位置に RealForce では左 Alt キーがありますので、左 Alt + H, J, K, L でカーソルキーが押されたかのようにしたいと思います。
そこで、左 Alt キー と H, J, K, L の各キーのキーコードを調べます。

また、Alt + H などを入力したときにカーソルキーとして動くようになってしまうと、本当に Alt + H を入力したいときにできなくなってしまいますので、Windows キーを潰して代わりにそれを Alt キーのように使いたいと思います。

つまり、左 Alt キー を ◇ キーのようなキーに変更し、Windows キーを新しい左 Alt キーに変更します。
ついでに Caps Lock は不要なので Control キーに変更してみたいと思います。

キーボード上の物理的なキー キーコード 新しい役割
左 Alt 64 HHK の ◇ キーのようなキー
Windows 133 左 Alt
Caps Lock 66 左 Control
H 43 ◇+H でカーソルの左キー
J 44 ◇+J でカーソルの下キー
K 45 ◇+K でカーソルの上キー
L 46 ◇+L でカーソルの右キー

なお、上記のキーコードは私の環境でそうだったというだけで、環境が異なれば値も異なります。


調べ終わったら、xev のウインドウを閉じます。


2. キーコードがわかったら .Xmodmap ファイルにキーバインドを記述

さて、キーコードがわかったら、~/.Xmodmap ファイルを開いて編集しましょう。

ポインタ(マウス)の設定

Ubuntu 12.04 もしくは類似の環境の場合、デフォルトでは、次のような内容のファイルが存在しているかもしれません。存在していなければこのセクションは無視してください。

pointer = 1 2 3 4 5 6 7 8 9 10 11 12

これの意味するところは、マウスのボタンの入れ替え設定です。

とはいえ、上記の設定ではボタンの入れ替えはしていません。つまり、
物理的に 1 番のボタンが押されたらボタンコード 1 番が生成されて、
物理的に 2 番のボタンが押されたらボタンコード 2 番が生成されて、
 :
物理的に 12番のボタンが押されたらボタンコード 12番が生成されるように設定されています。

pointer = のあとに、物理ボタンの番号順に、生成したいボタンコードをスペースで区切って書いていきます。

ちなみに、普通のマウスでは 1 番のボタンとは左ボタン、2番のボタンが中ボタン、3番のボタンが右ボタンと割り当てられているようです。また、ホイールを上向きに回すと4番のボタンが押されたかのようにコードが生成され、下向きに回すと5番のボタンが押されたとみなされるようです。私の環境でもそうなっていました。

普通の人が持っているマウスはせいぜいその 5 つくらいのボタンを持っていると思いますが、Xmodmap の設定ファイルではもっとたくさんのボタンを持っているマウスのために、デフォルトで12個のボタンの定義が書かれているのだと思います。

もし、左ボタンと右ボタンの役割を入れ替えたいのであれば、

pointer = 3 2 1 4 5 6 7 8 9 10 11 12

と記述すれば良いようです。

こうすると、物理的に1番のボタン(左)が押されるとボタンコード3番(右)が生成され、物理的に3番(右)のボタンからはボタンコード1番(左)が生成されます。

また、4 と 5 を入れ替えると Natural Scrolling のような事ができるかもしれません。

マウスのボタンの入れ替えを考えていないのであれば、この行は元のまま残しておきましょう。

キーコードと keysym

さて、話がそれました。キーバインドの設定をしましょう。


以下のコマンドを実行すると、現在割り当てられているキーバインドの一覧を確認することができるのでした。

$ xmodmap -pke 


たとえば A キーの割り当ては、

keycode  38 = a A a A

となっていました。

これの意味するところは、右辺の左から順番に

  • A キーだけを押したら小文字の a
  • Shift + A を押したら大文字の A
  • Mode_switch + A を押したら小文字の a
  • Mode_switch + Shift + A を押したら大文字の A

が入力されるということです。

さて、ここで Mode_swtich とはなんでしょう?
聞いたことのないキーです。

$ xmodmap -pke | grep -i mode_switch

と実行すると、私の環境では

keycode 203 = Mode_switch NoSymbol Mode_switch

となっていました。

しかし、私のキーボード上のどのキーを押しても、このキーコードを発生させることができませんでした。

キーボードによっては、このキーコードを発生させる AltGr というキーを持っているものもあるそうですが、私のキーボードにはそのような物理的なキーはありません。

それでは、左 Alt キーを Mode_switch のように働かせて、Mode_switch + H, J, K, L の役割をカーソルキーの上下左右に割り当てれば良さそうです。

まず物理的な左 Alt キー(私の環境ではキーコードは 64 でした)を Mode_switch キーに変更するには、.Xmodmap ファイルに以下の行を書きます。

keycode 64 = Mode_switch

これで、キーコード 64 のキー(物理的な左 Alt キー)に Mode_switch という役割を割り当てたことになります。ちなみに、この、右辺に書かれているキーの役割のことを keysym と言います。

キーコードの数字は、私は10進数で書きましたが、16進数などで書いても良いようです。
keysym は大文字小文字を区別します。Mode_switch の s は小文字ですので気をつけてください。

他にどのような keysym があるかは /usr/include/X11/keysymdef.h というファイルの中に記述されています。(XK_ というプリフィクスを取り除いたものが keysym になります。)
なお、このファイルは x11proto-core-dev というパッケージをインストールしておかないと存在しません。


さて、これだけで済めば良いのですが、実はそうもいきません。

キーコード 64 のキーは元々 Alt_L という keysym を持っていて、そのキーコード 64 のキーはモディファイアキーという特殊なキーに割り当てられていますので、上記の行だけではまだ足りないのです。
(モディファイアキーに割り当てられていないキーは上記の行だけで設定変更が可能)


モディファイアキー

モディファイアキーとは、Control や Shift、Alt などのように、他のキーと組み合わせて使うためのキーです。

あなたの環境でどのようなモディファイアキーが定義されているかは以下のように単に xmodmap コマンドを実行することで知ることができます。

$ xmodmap
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)

上記は私の環境でのデフォルトの例です。

例えば shift というモディファイアキーの役割を実行するには、キーコード 0x32 のキー(Shift_L という役割を与えられているが物理的に左シフトキーとは限らない)かキーコード 0x3e のキー(Shift_R という役割を与えられているが物理的に右シフトキーとは限らない)を押せば良いということを表しています。

キーコード 0x40 のキー(0x40 は 10 進数で 64 なので、上記調査結果からこれは物理的な左 Alt キーです)を押すと、mod1 というモディファイアキーになるようです。

shift、lock、control についてはなんとなくどんな役割か想像がつきますが、mod1〜mod5 のモディファイアキーについてはなんだかよくわかりませんね。
普通に生活している分には mod1〜mod5 のモディファイアにはお世話にならない気がしますので、気にしないでおきましょう。

さて、モディファイアキーに割り当てられている keycode に、別の keysym を割り当てるときは、一旦モディファイアキーのグループから抜けさせないといけない、というルールがあるようです。

私の例では左 Alt キー(キーコード 64)は mod1 のグループに入れられていますので、別の keysym(役割)を割り当てるまえに、このグループから抜けさせないといけません。

そこで、先ほどの .Xmodmap の設定ファイルの先頭に以下の行を追加します。

! この行を追加
remove mod1 = Alt_L

! これはさきほど書いておいた行
keycode 64 = Mode_switch

(行の先頭に ! がある行はコメントとみなされます。)

remove mod1 = Alt_L という書き方はなんとなく気持ち悪いですが、mod1 というグループから Alt_L を削除するという意味です。

これで、物理的に左 Alt キーを押すと Mode_switch キーとして働くようになります。

.Xmodmap ファイルを保存したら、以下のコマンドで読み込んでみましょう。

$ xmodmap ~/.Xmodmap

エラーは起こらなかったでしょうか?
大丈夫なようなら xev コマンドを起動し、物理的な左 Alt キーを押した時の keysym がどうなったか見てみましょう。

KeyPress event, serial 36, synthetic NO, window 0x1c00001,
    root 0xb6, subw 0x0, time 148526330, (1151,-215), root:(1201,557),
    state 0x0, keycode 64 (keysym 0xff7e, Mode_switch), same_screen YES,
    XLookupString gives 0 bytes: 
    XmbLookupString gives 0 bytes: 
    XFilterEvent returns: False

KeyRelease event, serial 36, synthetic NO, window 0x1c00001,
    root 0xb6, subw 0x0, time 148526458, (1151,-215), root:(1201,557),
    state 0x0, keycode 64 (keysym 0xff7e, Mode_switch), same_screen YES,
    XLookupString gives 0 bytes: 
    XFilterEvent returns: False

keysym が Mode_switch になっていますね。やりました!

$ xmodmap
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_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)

mod1 から Alt_L (0x40) が抜かれていますね。


それでは、ようやく目的の H, J, K, L との組み合わせを .Xmodmap に記述していきましょう。

remove mod1 = Alt_L
keycode 64 = Mode_switch

! ここから下を追加
keycode 43 = h H Left Left
keycode 44 = j J Down Down
keycode 45 = k K Up Up
keycode 46 = l L Right Right


保存したら、また同じコマンドで .Xmodmap を読み込ませてみます。

$ xmodmap ~/.Xmodmap


左 Alt + H, J, K, L で上下左右にカーソルが動いたら成功です!


あとは残りの Windows キーと Caps Lock キーの変更を行いましょう。
私の環境では、Windows キーはキーコード 133 で、Super_L という keysym を持っていました。また、mod4 というモディファイアキーのグループに入っていました。

Caps Lock キーはキーコード 66 で、Caps_Lock という keysym を持っており、lock というモディファイアキーのグループに入っています。

したがって、キーコード 133(Windows キー)やキーコード 66(Caps Lock キー)に別の役割(keysym)を割り当てるために、それぞれモディファイアキーのグループから一旦抜けさせないといけません。

また、Caps Lock キーは Control キーとして生まれ変わるために、keysym を割り当てたあとに control モディファイアキーのグループに仲間入りさせてあげないといけません。

これらを総合すると、.Xmodmap ファイルは以下のようになるでしょう。

remove mod1 = Alt_L
remove mod4 = Super_L
remove lock = Caps_Lock

keycode 64 = Mode_switch
keycode 133 = Alt_L
keycode 66 = Control_L

keycode 43 = h H Left Left
keycode 44 = j J Down Down
keycode 45 = k K Up Up
keycode 46 = l L Right Right

add control = Control_L

一般的に、.Xmodmap ファイルの中身は以下の順番で記述すると良いようです。


  1. モディファイアキーのグループから remove
    (役割を変更したい keycode にその時点で割り当てられている keysym を remove)

  2. keycode に keysym を割り当てる
    (物理キーに役割を割り当てる)

  3. モディファイアキーのグループに add
    (新しく割り当てられた役割に応じてモディファイアキーとして動作するように再割当て)



この .Xmodmap を読み込ませたあとのモディファイアキーの割り当ては以下のようになっています。

$ xmodmap
xmodmap:  up to 3 keys per modifier, (keycodes in parentheses):

shift       Shift_L (0x32),  Shift_R (0x3e)
lock      
control     Control_L (0x25),  Control_L (0x42),  Control_R (0x69)
mod1        Alt_R (0x6c),  Meta_L (0xcd)
mod2        Num_Lock (0x4d)
mod3      
mod4        Super_R (0x86),  Hyper_L (0xcf)
mod5        ISO_Level3_Shift (0x5c),  Mode_switch (0xcb)

lock グループに割り当てられているキーはなくなりました。
これでどんなキーを押しても Caps Lock として働くことはなくなったということです。

代わりに、キーコード 0x42(66)の Control_L が control グループに仲間入りしています。
元々あった左 Control キーに加え、Caps Lock キーもコントロールキーとして働くようになったということです。

また、Super_L もなくなりました。新しく割り当てた Mode_switch もどこにも入っていません。
これらのキーをモディファイアキーとして使いたければ、add を使って mod4 とか mod5 に追加してあげるとよいかもしれません。(私はいずれにしろ mod1〜mod5 は使いませんのであえて add しませんでした)

これで .Xmodmap で設定できることはだいたい説明し終わったはずです。
ここまでのことが理解できていれば、あとは man xmodmap でも見れば十分なはずです。


またいつか新しいキーボードを手にした時の自分のための長いメモを以上で終えたいと思います。

東プレ REALFORCE 86U /静電容量無接点/変荷重/86キー/USB SE0500

東プレ REALFORCE 86U /静電容量無接点/変荷重/86キー/USB SE0500