[ Home > ソフトウェア > xvkbd > キー・イベントの送信 ]

キー・イベントの送信

キー・イベントの送信

キー・イベントの送信のためには、 標準の Xlib 関数である XSendEvent() や、 XTEST エクステンションのインターフェースである XTestFakeKeyEvent() を用いることができる。

XSendEvent() によるイベントの送信

XSendEvent() を用いてキー・イベントを送信するためには、 XKeyEvent 構造体に必要な値を設定した上で XSendEvent() を呼び出せば良い。
  XKeyEvent event;

  event.display = display;
  event.window = destination of the event;
  event.root = the root window;
  event.subwindow = None;
  event.time = CurrentTime;
  event.x = 1;
  event.y = 1;
  event.x_root = 1;
  event.y_root = 1;
  event.same_screen = TRUE;

  event.type = KeyPress;  or  event.type = KeyRelease;
  event.keycode = keycode;
  event.state = modifiers;

  XSendEvent(event.display, event.window, TRUE, KeyPressMask, (XEvent *)event);

event.type は送信するイベントの種類を指定するものであり、 キーの押下をシミュレートする際には KeyPress を、 キーの開放をシミュレートする際には KeyRelease を指定する。

event.window (そして XSendEvent() の2番目のパラメータ) はイベントの宛先のウィンドウの ID である。 これには、その時点でキーボード・フォーカスを設定されているウィンドウに イベントを送りたい場合には XGetInputFocus() によって取得した値を設定すれば良いだろう。 また、指定したウィンドウにイベントを送りたい場合には、 event.window としてそのウィンドウ ID を指定するとともに、 XSendEvent() の呼び出しに先立って XSetInputFocus() によってキーボード・フォーカスを設定すれば良い。

event.keycode は送信するキーコードであり、 イベントを受け取ったクライアントは この値と event.state で指定されたモディファイアの値とから キーシムを再生することができる。

event.state はモディファイアの状態を示すものであり、 有効としたいモディファイアに対応する値のビット毎の論理和を取ったものを指定する。 Shift や Control に対応する値は定数 (ShiftMask、及び ControlMask) として定義されている。 Meta や Mode_switch などによる修飾が必要であれば、 その値は XGetModifierMapping() を用いて取得できる。

XSendEvent() の使用における最大の問題は、 クライアントによっては XSendEvent() によって送信された (Event 構造体の send_event フラグがセットされた) イベントを無視する場合があるということである。

XTEST エクステンション

XTEST エクステンション を用いたキー・イベントの送信は、 ある意味では XSendEvent() を用いた場合よりはるかに単純である。 しかし、これには使用が難しい面もある。

XTestFakeKeyEvent() は、 XTEST エクステンションによるキー・イベントの送信のためのものである。

  XTestFakeKeyEvent(display, keycode, True, 0);

XTestFakeKeyEvent() の3番目のパラメータは キーが押されたのか開放されたのかを示すものであり、 これが True であれば KeyPress イベントが、 False であれば KeyRelease イベントが送信される。

XSendEvent() を使用する場合と異なり、 XTestFakeKeyEvent() ではイベントの宛先を指定することはできず、 送信されたイベントは本物のキーボードによって生成されたイベントと同様に 通常のイベント配送メカニズムに従って配送される。 これは、その時点でポインタが置かれているウィンドウが キー・イベントを受け取るような状況においては、若干の困難を生じる。 一般的な状況において、イベントを送信する際に そのイベントを送りたいウィンドウにポインタが置かれていると 期待することはできないので、明らかに何らかの対処が必要となる。 xvkbd では、XTestFakeKeyEvent() の呼び出しに先立って XWarpPointer() によってポインタをそのウィンドウに移動させる (そしてその後で元の場所に戻す) ことで対処しているが、 これは常に期待したように機能するとは限らない。

送信する文字は、XSendEvent() の場合と同様に キーコードによって指定する。 しかし、モディファイアを直接指定することはできず、 必要に応じて修飾キーの KeyPress/KeyRelease イベントを送信することによって 修飾キーの状態を設定することが必要となる。

XTEST エクステンションは 全ての X サーバーでサポートされているとは限らない。 XTEST エクステンションがサポートされているかどうかは、 XQueryExtension(dpy, "XTEST", ...) によって調べることができる。


キーシムとキーコード

キーコードからキーシムへの変換

X サーバーは、キーが押されるとそのキーに対応するキーコードを出力する。 キーコードはシステムに依存するが、 クライアントは XLookupKeysym() などを用いて これをポータブルなキーシムに変換できる。 1つのキーに複数のキーシムが対応付けられているのは普通であり、 従ってキーコードからキーシムへの変換には そのキーコードのみではなくモディファイアの状態も関係する。

キーコードとキーシムのあいだのマッピングは XChangeKeyboardMapping() 関数や xmodmap コマンドなどを用いて変更できる。

キーシムからキーコードへの変換

キー・イベントをシミュレートする際には、 入力の場合とは逆にキーコードへの変換を行なうことが必要となる。 キーシムに対応するキーコードは XKeysymToKeycode() によって取得することができるが、 1つのキーコードに複数のキーシムが対応する場合があるため、 そのイベントの受信者がキーシムを再現できるようにするためには モディファイアの状態も伝えることが必要となることに注意が必要である。

モディファイア

あるキーの意味が他のキー (例えば Shift、Control など) の状態によって 変わるのは珍しくはない。 例えば、通常のレイアウトでは、`a' キーは、 Shift キーと同時に押した場合には `A' となり、 Control キーと同時に押した場合には Control-A となる。 この Shift や Control などは、モディファイアと呼ばれる。

モディファイアのうち、Shift や Mode_switch (AltGr) は、 キーコードとキーシムとの変換に影響する。 XChangeKeyboardMapping() のマニュアルに書かれているように、 それぞれのキーコードに対して複数のキーシムを対応させることが可能である。

これに関して文書化されたものを見付けることはできなかったが、 それぞれのキーコードに対応するキーシムの最初の4つ (もしあれば) は、順に:

  1. Shift も Mode_switch も押されていない
  2. Shift が押されている
  3. Mode_switch が押されている
  4. Shift と Mode_switch の双方が押されている
場合に対応するものと考えて良いであろう。


by T.Sato, 2001-01-08