X Window System の Meta キーを設定した話

Macのキーボードにはコマンド(Cmd)キーがあり、シフト・コントロール・オルト(Alt)と同様の修飾(モディファイヤ)キーとして使えます。

Linux等ではメタ(Meta)キーが相当するキーとして扱える場合がありますが(たとえば、MozillaJavaScript のドキュメントにある表にそうある https://developer.mozilla.org/ja/docs/Web/API/KeyboardEvent/getModifierState#Modifier_keys_on_Gecko )手元の環境(FreeBSD)の X Window System で単にキーアサインを設定しただけではうまく行かなかったので、その顛末です。

まず X Window System の基本事項を確認します(X Keyboard Extension (XKB) のことは、とりあえず忘れます)。

X Window System のキーボードまわりには、

  • キーコード
  • キーシム
  • 修飾

の3要素があります。それぞれ、

  • キーコードはキーボードの各ボタンに対応した番号で、基本的には直接に機能には対応しない
  • キーコードからキーシムにマップされることで、何らかの機能と結び付けられる
  • シフト状態などの修飾はキーシムからさらにマップされる

といったようになっていて、xev というツールでXのイベントとして確かめてみると、

state 0x4, keycode 37 (keysym 0xffe3, Control_L)

(抜粋)といったように表示されますが、ここで state とあるのが、修飾キーの状態を示すマスクです(なお、state はその修飾キー自身の押下時のイベントでは設定されない)。

失敗篇

手元のキーボード(ユーシーテクノロジ(株)製造・パーソナルメディア(株)販売の「μTRONキーボード」)で手頃なキー(「Menu」キー)のキーコードが 117 だったので、

keycode 117 = Meta_L NoSymbol Meta_L

のように設定してみたのですが、なぜか修飾としては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 (0x6d)
mod1        Alt_L (0x40),  Alt_R (0x71),  Meta_L (0x9c)
mod2        Num_Lock (0x4d)
mod3
mod4        Super_L (0x73),  Super_R (0x74),  Super_L (0x7f),  Hyper_L (0x80)
mod5        Mode_switch (0x8),  ISO_Level3_Shift (0x7c)

と、なんやら妙なことになっています。これでは同一視されてしまうに決まっています(Meta_Lのコードが0x9cになっているのは、前述の設定より前の状態)。

余談ですが、今までキーコードとキーシムの設定にしか xmodmap コマンドを使ったことがなかったので、なんか変な名前だなと思っていたのですが、引数無しのデフォルトで表示される本来はこちらがこのコマンドの主目的で、そこから派生したとか、多分そんな理由なのですね。

ついでに関係しそうなキーコードとキーシムのほうも調べてみると、

$ xmodmap -pke | grep -e Alt -e Meta
keycode  64 = Alt_L Meta_L Alt_L Meta_L
keycode 113 = Alt_R Meta_R Alt_R Meta_R
keycode 125 = NoSymbol Alt_L NoSymbol Alt_L
keycode 156 = NoSymbol Meta_L NoSymbol Meta_L

となっていました(これも、起動後の初期状態のもの)。

解決篇

状況がわかってしまえば簡単で、今度からは一発で設定できるように次のようなファイルを作っておきます。

$ cat my_modmap.txt
clear mod1
clear mod3
keycode 125 =
keycode 156 =
keycode  64 = Alt_L NoSymbol Alt_L
keycode 113 = Alt_R NoSymbol Alt_R
keycode 117 = Meta_L NoSymbol Meta_L
add mod1 = Alt_L Alt_R
add mod3 = Meta_L

モディファイヤを設定する時に、キーマップの状態からの影響があるので、「モディファイヤをクリア、キーマップを設定、モディファイヤの再設定」という順序になるようにします。mod1がAltキーのモディファイヤ、mod3がMetaキーのモディファイヤです。

謎のマッピングがあったキーコード125と156はマッピングを消しておきます。Altキーがシフト状態ではMeta扱いになるという設定も消して、単純に Alt_L と Alt_R にマッピングします(ここでは示しませんでしたが、左右のShiftとControlは元から同様になっています)。Meta_L も同様に設定します。

最後にモディファイヤの設定をします。Meta_R も、設定だけでもしておきたい気もしますが、ここではそのままLだけを設定しました。

設定した後で、状態を確認すると、以下のようになります。

$ xmodmap my_modmap.txt
$ 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 (0x6d)
mod1        Alt_L (0x40),  Alt_R (0x71)
mod2        Num_Lock (0x4d)
mod3        Meta_L (0x75)
mod4        Super_L (0x73),  Super_R (0x74),  Super_L (0x7f),  Hyper_L (0x80)
mod5        Mode_switch (0x8),  ISO_Level3_Shift (0x7c)
$ xmodmap -pke | grep -e Alt -e Meta
keycode  64 = Alt_L NoSymbol Alt_L
keycode 113 = Alt_R NoSymbol Alt_R
keycode 117 = Meta_L NoSymbol Meta_L