XKB
XKB は、X のキーボードに関する拡張機能です。
これを使うことによって、コアの X で出来ないことが出来るようになったり、扱いにくい部分を、よりわかりやすく扱うことができるようになります。
XKB は Xlib (X11R6 以降) 内に含まれているので、拡張機能のライブラリをリンクする必要はありません。
インクルードファイルは、<X11/XKBlib.h> が必要です。
クライアントが XKB を明示的に使わない場合でも、Xlib のキーボード関連の関数は、XKB を使うように置き換えられているので、間接的に XKB が使用される形になります。
XKB とコアプロトコルの間には互換性があります。
これを使うことによって、コアの X で出来ないことが出来るようになったり、扱いにくい部分を、よりわかりやすく扱うことができるようになります。
XKB は Xlib (X11R6 以降) 内に含まれているので、拡張機能のライブラリをリンクする必要はありません。
インクルードファイルは、<X11/XKBlib.h> が必要です。
クライアントが XKB を明示的に使わない場合でも、Xlib のキーボード関連の関数は、XKB を使うように置き換えられているので、間接的に XKB が使用される形になります。
XKB とコアプロトコルの間には互換性があります。
初期化
クライアントが明示的に XKB の API を使用したい場合は、まず初期化を行う必要があります。
X ディスプレイのオープンと、XKB の初期化をまとめて行いたい場合は、XkbOpenDisplay() を使うことができます。
個別に XKB の初期化を行いたい場合は、XkbLibraryVersion() で XKB のライブラリのバージョンを確認し、XkbQueryExtension() で初期化&拡張機能の情報を取得します。
動的または静的にリンクされている XKB ライブラリのバージョンを確認します。
lib_major_in_out, lib_minor_in_out の各変数に、使用したいバージョンをセットして渡すと、ライブラリで実際に使用できるバージョンが返ります。
戻り値が True で、ライブラリのバージョンに互換性があります。
ヘッダで定義されているバージョンを使用したい場合は、lib_major_in_out に XkbMajorVersion を、lib_minor_in_out に XkbMinorVersion をセットします。
サーバーに XKB 拡張機能が存在するかを確認し、バージョンの互換性の確認と初期化を行って、各情報を取得します。
major_in_out, minor_in_out には、XkbLibraryVersion() で取得したバージョンを指定します。
event_rtrn で取得した値は、XKB のイベントを判別するために使います。
戻り値が True で、拡張機能が存在し、バージョンに互換性があります。
X ディスプレイのオープンと、XKB の初期化をまとめて行いたい場合は、XkbOpenDisplay() を使うことができます。
個別に XKB の初期化を行いたい場合は、XkbLibraryVersion() で XKB のライブラリのバージョンを確認し、XkbQueryExtension() で初期化&拡張機能の情報を取得します。
XKB ライブラリのバージョン確認
Bool XkbLibraryVersion(int *lib_major_in_out, int *lib_minor_in_out);
動的または静的にリンクされている XKB ライブラリのバージョンを確認します。
lib_major_in_out, lib_minor_in_out の各変数に、使用したいバージョンをセットして渡すと、ライブラリで実際に使用できるバージョンが返ります。
戻り値が True で、ライブラリのバージョンに互換性があります。
ヘッダで定義されているバージョンを使用したい場合は、lib_major_in_out に XkbMajorVersion を、lib_minor_in_out に XkbMinorVersion をセットします。
XKB の初期化
Bool XkbQueryExtension(Display *dpy, int *opcode_rtrn, int *event_rtrn, int *error_rtrn, int *major_in_out, int *minor_in_out);
サーバーに XKB 拡張機能が存在するかを確認し、バージョンの互換性の確認と初期化を行って、各情報を取得します。
major_in_out, minor_in_out には、XkbLibraryVersion() で取得したバージョンを指定します。
event_rtrn で取得した値は、XKB のイベントを判別するために使います。
戻り値が True で、拡張機能が存在し、バージョンに互換性があります。
キーボードの状態
現在のキーボードの状態を取得するには、XkbGetState() を使います。
XInput 拡張機能におけるデバイス ID、または、XkbUseCoreKbd を指定します。
任意のキーボードデバイスを個別に指定したい場合は、デバイス ID を調べる必要があります。
XkbUseCoreKbd の場合、コアのキーボードデバイスになります (XInput 2.x の場合、マスターキーボードデバイス)。
キーボード全体を一つのデバイスとして扱いたい場合は、XkbUseCoreKbd を指定します。
Status XkbGetState(Display *display, unsigned int device_spec, XkbStatePtr state_return);
device_spec
XKB 関数では、device_spec 引数で、対象となるキーボードデバイスを指定する場合が多いです。XInput 拡張機能におけるデバイス ID、または、XkbUseCoreKbd を指定します。
任意のキーボードデバイスを個別に指定したい場合は、デバイス ID を調べる必要があります。
XkbUseCoreKbd の場合、コアのキーボードデバイスになります (XInput 2.x の場合、マスターキーボードデバイス)。
キーボード全体を一つのデバイスとして扱いたい場合は、XkbUseCoreKbd を指定します。
XkbStateRec
XKB キーボードの状態は、修飾子の状態、キーボードグループ、ポインタボタンの状態で構成されます。
構造体の実体は XkbStateRec で、そのポインタは XkbStatePtr 型となります。
XKB で定義されている構造体は、基本的に、*Rec が実体、*Ptr がポインタ型になります。
typedef struct { unsigned char group; /* effective group index */ unsigned char base_group; /* base group index */ unsigned char latched_group; /* latched group index */ unsigned char locked_group; /* locked group index */ unsigned char mods; /* effective modifiers */ unsigned char base_mods; /* base modifiers */ unsigned char latched_mods; /* latched modifiers */ unsigned char locked_mods; /* locked modifiers */ unsigned char compat_state; /* effective group -> modifiers */ unsigned char grab_mods; /* modifiers used for grabs */ unsigned char compat_grab_mods; /* mods used for compatibility mode grabs */ unsigned char lookup_mods; /* mods used to lookup symbols */ unsigned char compat_lookup_mods; /* mods used for compatibility lookup */ unsigned short ptr_buttons; /* ポインタボタンのマスク */ } XkbStateRec, *XkbStatePtr;
構造体の実体は XkbStateRec で、そのポインタは XkbStatePtr 型となります。
XKB で定義されている構造体は、基本的に、*Rec が実体、*Ptr がポインタ型になります。
修飾子
キーボードの修飾子は、コアプロトコルで定義されている「Shift、Lock、Control、Mod1〜Mod5」が使用されます。
修飾子はそれぞれ、ON/OFF の状態に切り替えることができるものと考えます。
「ロックされた (Locked)」修飾子は、一度ロックされると、明示的に解除されるまで、ON の状態が継続します (NumLock や CapsLock など)。
「ラッチされた (Latched)」修飾子は、ON になると、次に通常のキーが押された時に自動で解除されます (一度だけの一時的な ON 状態)。
修飾子はそれぞれ、ON/OFF の状態に切り替えることができるものと考えます。
「ロックされた (Locked)」修飾子は、一度ロックされると、明示的に解除されるまで、ON の状態が継続します (NumLock や CapsLock など)。
「ラッチされた (Latched)」修飾子は、ON になると、次に通常のキーが押された時に自動で解除されます (一度だけの一時的な ON 状態)。
グループ
XKB では、4つのグループを定義することができ、0〜3 のインデックスで指定されます。
グループが変更されると、キーが押された時に変換される KeySym が変化します。
一つのグループでは、修飾子の状態によって KeySym を切り替えることができるので、基本的には1つのグループのみが使われます。
/usr/share/X11/xkb/symbols/jp ファイルに、日本語キーボード用の XKB 定義があるので、見てみてください。
グループが変更されると、キーが押された時に変換される KeySym が変化します。
一つのグループでは、修飾子の状態によって KeySym を切り替えることができるので、基本的には1つのグループのみが使われます。
/usr/share/X11/xkb/symbols/jp ファイルに、日本語キーボード用の XKB 定義があるので、見てみてください。
グループと修飾子
base_group と base_mods は、現在、物理的または論理的に押されているキーを表しています。
locked_group と locked_mods は、ロック状態にあるキーを示します。
latched_group と latched_mods は、ラッチ状態にあるキーを示します。
mods は、base_mods, locked_mods, latched_mods それぞれの値を OR した値であり、修飾子が ON の状態であるかを判定する時に使います。
group は、base_group, latched_group, locked_group から計算されたインデックス値です。
lookup_mods は、KeyPress/KeyRelease イベント時に、キーコードから KeySym を取得する時に使用するための修飾子状態です。
grab_mods は、パッシブグラブ時の一致判定に使用される修飾子状態です。
compat_* は、XKB が無効な状態のクライアントに適用される値です。
locked_group と locked_mods は、ロック状態にあるキーを示します。
latched_group と latched_mods は、ラッチ状態にあるキーを示します。
mods は、base_mods, locked_mods, latched_mods それぞれの値を OR した値であり、修飾子が ON の状態であるかを判定する時に使います。
group は、base_group, latched_group, locked_group から計算されたインデックス値です。
lookup_mods は、KeyPress/KeyRelease イベント時に、キーコードから KeySym を取得する時に使用するための修飾子状態です。
grab_mods は、パッシブグラブ時の一致判定に使用される修飾子状態です。
compat_* は、XKB が無効な状態のクライアントに適用される値です。
イベント
キーボードの状態が変化した時に、XKB イベントを受け取ることができます。
XKB イベント
XKB のイベントかどうかは、XEvent 共用体の type メンバが、XkbQueryExtension 関数の event_rtrn 引数で取得したイベントタイプ値と同じであるかどうかで判定します。
XKB のイベントは複数ありますが、このイベントタイプはすべて同じ値になります。
XKB のすべてのイベント構造体では、先頭に同じデータがあり、それらは XkbAnyEvent 構造体で定義されています。
XKB イベントの詳細なイベントタイプを判断するには、xkb_type を参照します。
device は、キーボードのデバイス ID です。イベント選択時などで XkbUseCoreKbd が指定されていた場合、実際のデバイス ID になります。
※XKB のイベント構造体は、XEvent のサイズを超えることはありません。
XKB のイベントは複数ありますが、このイベントタイプはすべて同じ値になります。
XKB のすべてのイベント構造体では、先頭に同じデータがあり、それらは XkbAnyEvent 構造体で定義されています。
typedef struct { int type; //XkbQueryExtension で取得した値 unsigned long serial; Bool send_event; Display * display; Time time; //イベントが起きたときのタイムスタンプ int xkb_type; //XKB イベントの詳細タイプ unsigned int device; //デバイスID } XkbAnyEvent;
XKB イベントの詳細なイベントタイプを判断するには、xkb_type を参照します。
device は、キーボードのデバイス ID です。イベント選択時などで XkbUseCoreKbd が指定されていた場合、実際のデバイス ID になります。
XkbEvent 構造体
なお、XEvent 共用体と同じように、すべての XKB イベント構造体と XEvent を含んだ、XkbEvent 共用体が定義されています。※XKB のイベント構造体は、XEvent のサイズを超えることはありません。
typedef union _XkbEvent { int type; XkbAnyEvent any; XkbStateNotifyEvent state; XkbMapNotifyEvent map; XkbControlsNotifyEvent ctrls; XkbIndicatorNotifyEvent indicators; XkbBellNotifyEvent bell; XkbAccessXNotifyEvent accessx; XkbNamesNotifyEvent names; XkbCompatMapNotifyEvent compat; XkbActionMessageEvent message; XkbExtensionDeviceNotifyEvent device; XkbNewKeyboardNotifyEvent new_kbd; XEvent core; } XkbEvent;
XKB イベントの選択
受信したい XKB イベントがある場合は、クライアントとデバイスごとに、イベントを選択する必要があります。
XkbSelectEvents と XkbSelectEventDetails の2つの関数を使って、選択または選択解除することができます。
XkbSelectEvents は、指定した XKB イベントの選択と選択解除を行います。
XkbSelectEventDetails は、指定した XKB イベントで、さらに詳細な条件を指定します。
XKB イベントの選択と選択解除を行います。
device_spec は、デバイス ID または XkbUseCoreKbd です。
bits_to_change で、設定を変更するイベントのマスクを指定します。
values_for_bits で、それぞれのイベントを選択するか解除するかのマスクを指定します (ON なら選択、OFF なら解除)。
XKB イベントの詳細を選択または選択解除します。
event_type で、対象となる XKB イベントタイプを指定し、bits_to_change と values_for_bits で、そのイベントの詳細なマスクを指定します。
bits_to_change と values_for_bits に何を指定するかは、XKB イベントのタイプによって異なります。
XkbStateNotify イベントであれば、XkbStateNotifyEvent 構造体の changed で使われるのと同じ値を指定します。
XkbSelectEvents と XkbSelectEventDetails の2つの関数を使って、選択または選択解除することができます。
XkbSelectEvents は、指定した XKB イベントの選択と選択解除を行います。
XkbSelectEventDetails は、指定した XKB イベントで、さらに詳細な条件を指定します。
XkbSelectEvents
Bool XkbSelectEvents(Display *display, unsigned int device_spec, unsigned long int bits_to_change, unsigned long int values_for_bits);
XKB イベントの選択と選択解除を行います。
device_spec は、デバイス ID または XkbUseCoreKbd です。
bits_to_change で、設定を変更するイベントのマスクを指定します。
values_for_bits で、それぞれのイベントを選択するか解除するかのマスクを指定します (ON なら選択、OFF なら解除)。
//XkbStateNotifyMask を選択 XkbSelectEvents(disp, XkbUseCoreKbd, XkbStateNotifyMask, XkbStateNotifyMask); //XkbStateNotifyMask を解除 XkbSelectEvents(disp, XkbUseCoreKbd, XkbStateNotifyMask, 0);
XkbSelectEventDetails
Bool XkbSelectEventDetails(Display *display, unsigned int device_spec, unsigned int event_type, unsigned long int bits_to_change, unsigned long int values_for_bits);
XKB イベントの詳細を選択または選択解除します。
event_type で、対象となる XKB イベントタイプを指定し、bits_to_change と values_for_bits で、そのイベントの詳細なマスクを指定します。
bits_to_change と values_for_bits に何を指定するかは、XKB イベントのタイプによって異なります。
XkbStateNotify イベントであれば、XkbStateNotifyEvent 構造体の changed で使われるのと同じ値を指定します。
//XkbStateNotify イベントで mods が変化した時のみ受信 XkbSelectEventDetails(disp, XkbUseCoreKbd, XkbStateNotify, XkbModifierStateMask, XkbModifierStateMask);
XkbStateNotify イベント
XkbStateNotify イベントは、修飾子の ON/OFF が変化したり、グループが変更されたり、ポインタボタンの押し状態が変化した時に来ます。
※ウィンドウに関係なく送られてくるので、他のクライアントが作成したウィンドウ上で状態が変化した場合でも、常にイベントが送られてきます。
※ウィンドウに関係なく送られてくるので、他のクライアントが作成したウィンドウ上で状態が変化した場合でも、常にイベントが送られてきます。
typedef struct { int type; unsigned long serial; Bool send_event; Display * display; Time time; int xkb_type; int device; unsigned int changed; int group; int base_group; int latched_group; int locked_group; unsigned int mods; unsigned int base_mods; unsigned int latched_mods; unsigned int locked_mods; int compat_state; unsigned char grab_mods; unsigned char compat_grab_mods; unsigned char lookup_mods; unsigned char compat_lookup_mods; int ptr_buttons; KeyCode keycode; char event_type; char req_major; char req_minor; } XkbStateNotifyEvent; //changed #define XkbModifierStateMask (1L << 0) #define XkbModifierBaseMask (1L << 1) #define XkbModifierLatchMask (1L << 2) #define XkbModifierLockMask (1L << 3) #define XkbGroupStateMask (1L << 4) #define XkbGroupBaseMask (1L << 5) #define XkbGroupLatchMask (1L << 6) #define XkbGroupLockMask (1L << 7) #define XkbCompatStateMask (1L << 8) #define XkbGrabModsMask (1L << 9) #define XkbCompatGrabModsMask (1L << 10) #define XkbLookupModsMask (1L << 11) #define XkbCompatLookupModsMask (1L << 12) #define XkbPointerButtonMask (1L << 13) #define XkbAllStateComponentsMask (0x3fff)
changed | 何が変更されたかを示すフラグ。 |
---|---|
keycode | イベントを引き起こしたキーコード。プログラムによる場合は 0。 |
event_type | req_major または req_minor が 0 以外の場合、コアイベントのタイプ。 キーイベントによる状態変化の場合、KeyPress (2) または KeyRelease (3)。 ボタンイベントの場合、ButtonPress (4) または ButtonRelease (5)。keycode はボタン番号。 それ以外の場合は、状態変更を引き起こしたリクエストのコードが、req_major,req_minor に設定される。keycode は 0。 |
プログラム
XkbStateNotify イベントを受け取って表示します。
閉じるボタンで終了します。
なお、ポインタボタンの状態変化を受け取ると、ちょっと面倒な状態になるので (あらゆる場所でポインタボタンが押されると、毎回イベントが来る)、ポインタボタンの状態変化は受け取らないようにしています。
閉じるボタンで終了します。
$ cc -o run e07-xkb1.c util.c -lX11
なお、ポインタボタンの状態変化を受け取ると、ちょっと面倒な状態になるので (あらゆる場所でポインタボタンが押されると、毎回イベントが来る)、ポインタボタンの状態変化は受け取らないようにしています。
#include <stdio.h> #include <X11/Xlib.h> #include <X11/XKBlib.h> #include "util.h" static unsigned int g_count = 0; static void _put_state(XkbStateNotifyEvent *ev) { unsigned int f = ev->changed; printf("----[%d]-----\n" "device: %d / changed: 0x%x\n", g_count++, ev->device, ev->changed); if(f & XkbModifierStateMask) printf("mods: 0x%x\n", ev->mods); if(f & XkbModifierBaseMask) printf("base_mods: 0x%x\n", ev->base_mods); if(f & XkbModifierLatchMask) printf("latched_mods: 0x%x\n", ev->latched_mods); if(f & XkbModifierLockMask) printf("locked_mods: 0x%x\n", ev->locked_mods); if(f & XkbGroupStateMask) printf("group: %d\n", ev->group); if(f & XkbGroupBaseMask) printf("base_group: %d\n", ev->base_group); if(f & XkbGroupLatchMask) printf("latched_group: %d\n", ev->latched_group); if(f & XkbGroupLockMask) printf("locked_group: %d\n", ev->locked_group); if(f & XkbCompatStateMask) printf("compat_state: 0x%x\n", ev->compat_state); if(f & XkbGrabModsMask) printf("grab_mods: 0x%x\n", ev->grab_mods); if(f & XkbCompatGrabModsMask) printf("compat_grab_mods: 0x%x\n", ev->compat_grab_mods); if(f & XkbLookupModsMask) printf("lookup_mods: 0x%x\n", ev->lookup_mods); if(f & XkbCompatLookupModsMask) printf("compat_lookup_mods: 0x%x\n", ev->compat_lookup_mods); //if(f & XkbPointerButtonMask) printf("ptr_buttons: 0x%x\n", ev->ptr_buttons); printf("keycode: %d / event_type: %d / req_major: %d / req_minor: %d\n", ev->keycode, ev->event_type, ev->req_major, ev->req_minor); } int main(int argc,char **argv) { Display *disp; Window win; XkbEvent ev; int major,minor,opcode,event_type,error_base; unsigned long mask; //XKB ライブラリ major = XkbMajorVersion; minor = XkbMinorVersion; if(!XkbLibraryVersion(&major, &minor)) { printf("unsupported XKB library\n"); return 1; } printf("library: ver %d.%d\n", major, minor); // disp = XOpenDisplay(NULL); if(!disp) return 1; set_display(disp); //XKB 初期化 if(!XkbQueryExtension(disp, &opcode, &event_type, &error_base, &major, &minor)) { XCloseDisplay(disp); printf("unsupported XKB (server)\n"); return 1; } printf("server: ver %d.%d\n", major, minor); printf("opcode: %d\nevent:%d\nerror:%d\n\n", opcode, event_type, error_base); // win = create_test_window2(disp, 200, 200, 0, ButtonPress); //XKB イベント選択 (ポインタボタン以外) mask = XkbAllStateComponentsMask - XkbPointerButtonMask; XkbSelectEventDetails(disp, XkbUseCoreKbd, XkbStateNotify, mask, mask); //イベント XMapWindow(disp, win); while(1) { XNextEvent(disp, (XEvent *)&ev); if(event_quit((XEvent *)&ev)) break; if(ev.type == event_type && ev.any.xkb_type == XkbStateNotify) { _put_state((XkbStateNotifyEvent *)&ev); } } XCloseDisplay(disp); return 0; }
実行例
Shift キー
Shift キーを押して離すと、以下のようになります。
device は、xinput コマンドで調べてみると、id=3 は "Virtual core keyboard" でした。
これは、サーバーによって作成されているマスターキーボードデバイスです。
Shift キーが押された時、NumLock と Shift の2つが ON の状態なので、mods は (ShiftMask | Mod2Mask) です。
現在物理的にキーが押されているのは Shift だけなので、base_mods は ShiftMask のみです。
----[4]----- # Shift 押し device: 3 / changed: 0x1f03 mods: 0x11 base_mods: 0x1 compat_state: 0x11 grab_mods: 0x11 compat_grab_mods: 0x11 lookup_mods: 0x11 compat_lookup_mods: 0x11 keycode: 50 / event_type: 2 / req_major: 0 / req_minor: 0 ----[5]----- # Shift 離し device: 3 / changed: 0x1f03 mods: 0x10 base_mods: 0x0 compat_state: 0x10 grab_mods: 0x10 compat_grab_mods: 0x10 lookup_mods: 0x10 compat_lookup_mods: 0x10 keycode: 50 / event_type: 3 / req_major: 0 / req_minor: 0
device は、xinput コマンドで調べてみると、id=3 は "Virtual core keyboard" でした。
これは、サーバーによって作成されているマスターキーボードデバイスです。
Shift キーが押された時、NumLock と Shift の2つが ON の状態なので、mods は (ShiftMask | Mod2Mask) です。
現在物理的にキーが押されているのは Shift だけなので、base_mods は ShiftMask のみです。
NumLock の解除とセット
----[82]----- # NumLock 押し device: 3 / changed: 0x2 base_mods: 0x10 keycode: 77 / event_type: 2 / req_major: 0 / req_minor: 0 ----[83]----- # NumLock 離し (解除) device: 3 / changed: 0x1f0b mods: 0x0 base_mods: 0x0 locked_mods: 0x0 compat_state: 0x0 grab_mods: 0x0 compat_grab_mods: 0x0 lookup_mods: 0x0 compat_lookup_mods: 0x0 keycode: 77 / event_type: 3 / req_major: 0 / req_minor: 0 ----[84]----- # NumLock 押し (セット) device: 3 / changed: 0x1f0b mods: 0x10 base_mods: 0x10 locked_mods: 0x10 compat_state: 0x10 grab_mods: 0x10 compat_grab_mods: 0x10 lookup_mods: 0x10 compat_lookup_mods: 0x10 keycode: 77 / event_type: 2 / req_major: 0 / req_minor: 0 ----[85]----- # NumLock 離し device: 3 / changed: 0x2 base_mods: 0x0 keycode: 77 / event_type: 3 / req_major: 0 / req_minor: 0
NumLock が ON の状態で、NumLock キーを押して離した時、NumLock が解除され、mods が 0 になります。
NumLock が OFF の状態で、NumLock キーを押した時、mods = Mod2Mask で、NumLock が ON になります。
CapsLock ON
----[195]----- # CapsLock 押し device: 3 / changed: 0x1f0b mods: 0x13 base_mods: 0x3 locked_mods: 0x12 compat_state: 0x13 grab_mods: 0x13 compat_grab_mods: 0x13 lookup_mods: 0x13 compat_lookup_mods: 0x13 keycode: 66 / event_type: 2 / req_major: 0 / req_minor: 0 ----[196]----- # CapsLock 離し device: 3 / changed: 0x2 base_mods: 0x1 keycode: 66 / event_type: 3 / req_major: 0 / req_minor: 0 ----[197]----- # Shift 離し device: 3 / changed: 0x1f03 mods: 0x12 base_mods: 0x0 compat_state: 0x12 grab_mods: 0x12 compat_grab_mods: 0x12 lookup_mods: 0x12 compat_lookup_mods: 0x12 keycode: 50 / event_type: 3 / req_major: 0 / req_minor: 0
Shift + CapsLock(英数) で、CapsLock の ON/OFF ができます。
CapsLock は LockMask (0x02) です。
mods は、(ShiftMask | LockMask | Mod2Mask) で、Shift, CapsLock, NumLock が ON の状態です。
現在押されている修飾子キーは Shift と Lock なので、base_mods は (ShiftMask | LockMask) です。
locked_mods は、ロック状態にある修飾子です。NumLock と CapsLock が ON なので、(LockMask | Mod2Mask) です。