仮想修飾子について
キー修飾子は「Shift, Lock, Ctrl, Mod1〜Mod5」が使われます。
Shift, Ctrl, CapsLock は、そのまま名前通りのキーになるので問題ありませんが、Mod1〜Mod5 は、キーボードのセットによって割り当てが異なるため、コア X のみで、どの修飾子がどのキーに対応するかを判断するには、少し面倒な手順が必要になります。
なお、Mod1〜Mod5 で使われるのは、NumLock, Alt, Windows キーなどです。
Shift, Ctrl, CapsLock は、そのまま名前通りのキーになるので問題ありませんが、Mod1〜Mod5 は、キーボードのセットによって割り当てが異なるため、コア X のみで、どの修飾子がどのキーに対応するかを判断するには、少し面倒な手順が必要になります。
なお、Mod1〜Mod5 で使われるのは、NumLock, Alt, Windows キーなどです。
修飾子に対応するキーを調べる
例えば、コア X で、Alt がどの修飾子 (Mod1〜Mod5) に対応しているかを調べたい場合は、以下のようにする必要があります。
※X のキーマッピングについては、(X11) キーマッピング を参照してください。
ただし、キーマッピングや修飾子マッピングは、X サーバーの起動中に変更される可能性があるので、マッピングが変更された場合 (MappingNotify イベントが来た時) は、上記の処理を再度行う必要があります。
※X のキーマッピングについては、(X11) キーマッピング を参照してください。
- キーマッピングと修飾子マッピングを取得する (XGetKeyboardMapping, XGetModifierMapping)。
キーマッピング = キーコードに対応する KeySym のリスト。
修飾子マッピング = 各修飾子に対応するキーコードのリスト。 - 修飾子マッピングから、Mod1〜Mod5 に対応する各キーコードを取得。
- 上記のキーコードを元に、キーマッピングを参照し、XK_Alt_R または XK_Alt_L の KeySym が含まれているものを調べる。
- 存在すれば、その修飾子は Alt キーである。
ただし、キーマッピングや修飾子マッピングは、X サーバーの起動中に変更される可能性があるので、マッピングが変更された場合 (MappingNotify イベントが来た時) は、上記の処理を再度行う必要があります。
仮想修飾子
このように、コア X では、Alt キーや Windows キーなどの修飾子が扱いにくいので、XKB では、この負担軽減のために、仮想修飾子を使うことができます。
仮想修飾子は、名前付きで16個まで定義でき、それぞれに、「Shift, Lock, Ctrl, Mod1〜Mod5」の任意のセットを設定することができます。
仮想修飾子は、名前付きで16個まで定義でき、それぞれに、「Shift, Lock, Ctrl, Mod1〜Mod5」の任意のセットを設定することができます。
仮想修飾子の情報
仮想修飾子は、XKB の設定によって、あらかじめ定義されています。
名前
各仮想修飾子の名前は、前回行った、XkbDescRec 構造体の names->vmods (Atom) から取得することができます。
この名前を元に、特定の仮想修飾子のインデックス (0〜15) を取得することができます。
上記の場合、Alt キーを使いたいなら、index 1 であることを記憶しておきます。
[0] "NumLock" [1] "Alt" [2] "LevelThree" [3] "LevelFive" [4] "Meta" [5] "Super" [6] "Hyper" [7] "ScrollLock"
この名前を元に、特定の仮想修飾子のインデックス (0〜15) を取得することができます。
上記の場合、Alt キーを使いたいなら、index 1 であることを記憶しておきます。
仮想修飾子と実際の修飾子の関連付け
仮想修飾子には、X で使われる実際の修飾子のマスクが関連付けられています。
この情報は、サーバーマップ (XkbDescRec 構造体の server) の vmods にあります。
vmods には、各仮想修飾子に対応する、実際の修飾子のマスクが設定されています。
※ScrollLock が実際のキーボードに存在していたとしても、XKB の設定で修飾子として指定されていなければ、キーは動作しません。ここでは、Mod1〜Mod5 まですべて使用されているので、ScrollLock 修飾子が設定できる余地がありません。
この情報によって、Alt (Meta) が Mod1Mask に対応している、というようなことが判定できます。
この情報は、サーバーマップ (XkbDescRec 構造体の server) の vmods にあります。
#define XkbNumVirtualMods 16 typedef struct { unsigned short num_acts; unsigned short size_acts; XkbAction * acts; XkbBehavior * behaviors; unsigned short * key_acts; unsigned char * explicit; unsigned char vmods[XkbNumVirtualMods]; unsigned short * vmodmap; } XkbServerMapRec, *XkbServerMapPtr;
vmods には、各仮想修飾子に対応する、実際の修飾子のマスクが設定されています。
[0] "NumLock" 0x10 (Mod2Mask) [1] "Alt" 0x08 (Mod1Mask) [2] "LevelThree" 0x80 (Mod5Mask) [3] "LevelFive" 0x20 (Mod3Mask) [4] "Meta" 0x08 (Mod1Mask) [5] "Super" 0x40 (Mod4Mask) [6] "Hyper" 0x40 (Mod4Mask) [7] "ScrollLock" 0
※ScrollLock が実際のキーボードに存在していたとしても、XKB の設定で修飾子として指定されていなければ、キーは動作しません。ここでは、Mod1〜Mod5 まですべて使用されているので、ScrollLock 修飾子が設定できる余地がありません。
この情報によって、Alt (Meta) が Mod1Mask に対応している、というようなことが判定できます。
キーコードに対応する仮想修飾子
サーバーマップの vmodmap には、各キーコードに対応する、仮想修飾子のマスクが設定されています。
キーコードをインデックスとした、unsigned short の配列になっています。
例えば、左 Alt・右 Alt に対応するキーコードには、それぞれ、0x12 ((1<<1) | (1<<4)) が設定されます。
上記の例では、Alt (index = 1) と Meta (index = 4) が、両方とも Mod1 としての扱いになるので、そのインデックスをビット位置としたマスクになります。
基本的には 8〜255 の範囲となるので、256 個です。
※min_key_code 未満のキーコードは使用されませんが、配列上にはその分のデータも存在します。
キーコードをインデックスとした、unsigned short の配列になっています。
例えば、左 Alt・右 Alt に対応するキーコードには、それぞれ、0x12 ((1<<1) | (1<<4)) が設定されます。
上記の例では、Alt (index = 1) と Meta (index = 4) が、両方とも Mod1 としての扱いになるので、そのインデックスをビット位置としたマスクになります。
配列数
なお、vmodmap の配列数がどこにも定義されていませんが、キーコードをインデックスとして扱う配列データの場合、キーコードは XkbDescRec 構造体の min_key_code から max_key_code の範囲まで存在するので、array[max_key_code] までの値が取得できるようにするため、(max_key_code + 1) 個は確実に存在します。基本的には 8〜255 の範囲となるので、256 個です。
※min_key_code 未満のキーコードは使用されませんが、配列上にはその分のデータも存在します。
キーコードに対応する実際の修飾子
各キーコードに対応する、実際の修飾子を取得したい場合は、クライアントマップ (XkbDescRec 構造体の map) の modmap を参照します。
modmap は、キーコードをインデックスとした配列で、そのキーに対応する、実際の修飾子のマスクが設定されています。
配列の数に関しては、vmodmap と同様です。
なお、サーバーマップの修飾子情報が変更されると、このデータも自動的に更新されます。
(XkbDescRec 構造体ですでに値を取得している場合は、データの再取得が必要)
typedef struct { unsigned char size_types; unsigned char num_types; XkbKeyTypePtr types; unsigned short size_syms; unsigned short num_syms; KeySym * syms; XkbSymMapPtr key_sym_map; unsigned char * modmap; } XkbClientMapRec, *XkbClientMapPtr;
modmap は、キーコードをインデックスとした配列で、そのキーに対応する、実際の修飾子のマスクが設定されています。
配列の数に関しては、vmodmap と同様です。
なお、サーバーマップの修飾子情報が変更されると、このデータも自動的に更新されます。
(XkbDescRec 構造体ですでに値を取得している場合は、データの再取得が必要)
プログラム
仮想修飾子の情報を表示します。
<e13-xkb3.c>
$ cc -o run e13-xkb3.c util.c -lXlib
<e13-xkb3.c>
#include <stdio.h> #include <X11/Xlib.h> #include <X11/XKBlib.h> #include "util.h" static void _put_vmods(XkbDescPtr p) { int i; printf("--- vmods ---\n"); for(i = 0; i < XkbNumVirtualMods; i++) { if(p->names->vmods[i]) { printf("[%d] \"", i); put_atom_name(p->names->vmods[i]); printf("\" 0x%02x\n", p->server->vmods[i]); } } } static void _put_vmodmap(XkbDescPtr p) { int i; printf("--- vmodmap ---\n"); for(i = p->min_key_code; i <= p->max_key_code; i++) { if(p->server->vmodmap[i]) { printf("[%d] %.4s (0x%04x)\n", i, p->names->keys[i].name, p->server->vmodmap[i]); } } } int main(int argc,char **argv) { Display *disp; XkbDescPtr desc; disp = XOpenDisplay(NULL); if(!disp) return 1; set_display(disp); //XKB 初期化 if(init_xkb(disp, NULL)) return 1; //データ取得 desc = XkbGetKeyboard(disp, XkbAllComponentsMask, XkbUseCoreKbd); printf("keycode: %d - %d\n", desc->min_key_code, desc->max_key_code); _put_vmods(desc); _put_vmodmap(desc); XkbFreeKeyboard(desc, 0, True); XCloseDisplay(disp); return 0; }
実行例
keycode: 8 - 255 --- vmods --- [0] "NumLock" 0x10 [1] "Alt" 0x08 [2] "LevelThree" 0x80 [3] "LevelFive" 0x20 [4] "Meta" 0x08 [5] "Super" 0x40 [6] "Hyper" 0x40 [7] "ScrollLock" 0x00 --- vmodmap --- [64] LALT (0x0012) [77] NMLK (0x0001) [92] LVL3 (0x0004) [108] RALT (0x0012) [133] LWIN (0x0020) [134] RWIN (0x0020) [203] LVL5 (0x0008) [204] ALT (0x0002) [205] META (0x0010) [206] SUPR (0x0020) [207] HYPR (0x0040)
キーコード 77 の "NMLK" キーは NumLock なので、vmodmap では、仮想修飾子の index = 0 (0x0001) が ON になっています。
"LALT" が左 Alt、"RALT" が右 Alt。
"LWIN" が左 Windows キー、"RWIN" が 右 Windows キーで、仮想修飾子の index = 5 (Super) が ON です。