XInput
XInput 拡張機能は、マウス、キーボード、タッチスクリーン、ペンタブレットなどの入力デバイスを扱うための機能です。
XInput を使うと、入力デバイスの詳細な情報を取得することができるため、例えばペンタブレットの筆圧を取得したり、座標を double で取得することができます。
XInput には ver 1.x と ver 2.x があり、この二つのバージョンでは扱いが大きく異なります。
ここでは、XInput ver 2 (XI2) のみを扱います。
XInput を使うと、入力デバイスの詳細な情報を取得することができるため、例えばペンタブレットの筆圧を取得したり、座標を double で取得することができます。
XInput には ver 1.x と ver 2.x があり、この二つのバージョンでは扱いが大きく異なります。
ここでは、XInput ver 2 (XI2) のみを扱います。
ヘッダとライブラリ
XInput のライブラリは、どちらのバージョンでも -lXi でリンクします。
ヘッダファイルは、ver1 と ver2 で分かれています。
ver2 の場合は、<X11/extensions/XInput2.h> をインクルードしてください。
ヘッダファイルは、ver1 と ver2 で分かれています。
ver2 の場合は、<X11/extensions/XInput2.h> をインクルードしてください。
初期化
バージョンの確認
Status XIQueryVersion(Display *dpy, int *major_version_inout, int *minor_version_inout);
サーバーが対応している XI2 のバージョンを確認します。
major_version_inout, minor_version_inout の変数に、クライアントが要求する XI2 バージョンを指定しておく必要があります。
関数が返ると、そのバージョン以下で、サーバーがサポートしている XI2 バージョンが返ります。
※ major_version_inout には、2 以上を指定すること。
ver 2.2 でマルチタッチ、ver 2.3 でバリア、ver 2.4 でジェスチャーの機能が追加されています。
サーバーが XI2 をサポートしている場合、Success が返ります。
サーバーがサポートしているバージョンが、要求したバージョン以上であるかどうかは判断されないので、必要に応じて、クライアント側が、返ったバージョンを判断する必要があります。
(要求するバージョン以下ならエラーとするか、または、返ったバージョンを超える機能は個別に使用しないようにするか)
XQueryExtension
XI2 のイベントを判定する場合、オペコード値が必要になりますが、XI2 用の XQueryExtension に相当する関数は定義されていないため、Xlib の XQueryExtension 関数を使い、拡張機能名に "XInputExtension" を指定して取得します。
int opcode,event,error; if(!XQueryExtension(didp, "XInputExtension", &opcode, &event, &error)) { ...error... }
デバイスの情報
まずは、使用できる入力デバイスの情報が必要になります。
複数の入力デバイスの情報を取得します。
XIQueryDevice() で返されたポインタは、XIFreeDeviceInfo() で解放します。
配列全体を丸ごと解放するため、一度呼ぶだけで構いません。
デバイス情報の構造体です。
XIQueryDevice
XIDeviceInfo *XIQueryDevice(Display *dpy, int deviceid, int *ndevices_return);
複数の入力デバイスの情報を取得します。
deviceid | 情報を取得するデバイスのID。 XIAllDevices (0) で、すべてのデバイス。 XIAllMasterDevices (1) で、すべてのマスターデバイス。 |
---|---|
ndevices_return | 情報を取得したデバイスの数が返る |
戻り値 | XIDeviceInfo 構造体の配列のポインタが返る |
XIFreeDeviceInfo
void XIFreeDeviceInfo(XIDeviceInfo *info);
XIQueryDevice() で返されたポインタは、XIFreeDeviceInfo() で解放します。
配列全体を丸ごと解放するため、一度呼ぶだけで構いません。
XIDeviceInfo 構造体
typedef struct { int deviceid; char *name; int use; int attachment; Bool enabled; int num_classes; XIAnyClassInfo **classes; } XIDeviceInfo; typedef struct { int type; int sourceid; } XIAnyClassInfo;
デバイス情報の構造体です。
deviceid | デバイスのID。 接続されている間は常に同じ値ですが、起動中、削除されたデバイスの ID が再利用される場合もあります。 |
---|---|
name | デバイスの名前 |
use | デバイスのタイプ。 XIMasterPointer : マスターポインタ。attachment はペアリングされたマスターキーボードのデバイス ID。 XIMasterKeyboard : マスターキーボード。attachment はペアリングされたマスターポインタの ID。 XISlavePointer : スレーブデバイス。現在、attachment で指定されたマスターポインタに接続されている。 XISlaveKeyboard : スレーブデバイス。現在、attachment で指定されたマスターキーボードに接続されている。 XIFloatingSlave : 現在どのマスターデバイスにも接続されていない、スレーブデバイス。attachment の値は未定義。 |
attachment | デバイスタイプによって異なります。 |
enabled | True の場合、デバイスが現在有効であり、イベントを送信できます。 無効状態のデバイスは、イベントを送信しません。 |
num_classes | classes の個数 |
classes | デバイスが持っている各クラスの情報のポインタの配列。 XIAnyClassInfo 構造体のポインタの配列になっていますが、実際はクラスのタイプごとに構造体が異なるため、type 値を元に、各クラスの構造体のポインタに型変換する必要があります。 各クラス構造体の先頭には、常に type と sourceid があります。 type はクラスのタイプ。以下のいずれかです。 XIKeyClass, XIButtonClass, XIValuatorClass, XIScrollClass, XITouchClass, XIGestureClass sourceid は、このクラスの生成元のデバイス ID。 マスターデバイスの場合、通常、現在イベントを送信しているスレーブデバイスの ID です。 スレーブデバイスの場合、通常、そのデバイスの ID です。 |
デバイスについて
XI2 が扱うデバイスは、大きく分けて、「マスターデバイス (MD)」と「スレーブデバイス (SD)」の2つに分かれています。
「マスターポインタ」と「マスターキーボード」の2つが存在し、この2つは、X のコアイベントと XInput のイベントのいずれかを生成できます。
マスターポインタは、現在ポインタが操作されているデバイスとして扱うことができ、マスターキーボードも同様に、現在操作されているキーボードデバイスとして扱うことができます。
デバイスごとに処理するのではなく、ポインタとキーボードの2つを総合的に扱いたい場合に使います。
マスターポインタとマスターキーボードは、それぞれがペアリングされており、両方が存在する間は一定です。
スレーブデバイスは、マスターデバイス(ポインタかキーボード)に接続される場合があります。
スレーブデバイスでイベントが発生すると、接続されているマスターデバイスに応じて、ポインタの位置が移動したり、キーイベントが生成されたりします。
マスターデバイス
X サーバーによって作成される、仮想のデバイスです。「マスターポインタ」と「マスターキーボード」の2つが存在し、この2つは、X のコアイベントと XInput のイベントのいずれかを生成できます。
マスターポインタは、現在ポインタが操作されているデバイスとして扱うことができ、マスターキーボードも同様に、現在操作されているキーボードデバイスとして扱うことができます。
デバイスごとに処理するのではなく、ポインタとキーボードの2つを総合的に扱いたい場合に使います。
マスターポインタとマスターキーボードは、それぞれがペアリングされており、両方が存在する間は一定です。
スレーブデバイス
実際にパソコンに接続されている個々のデバイスや、それに関連する仮想的なデバイスです。スレーブデバイスは、マスターデバイス(ポインタかキーボード)に接続される場合があります。
スレーブデバイスでイベントが発生すると、接続されているマスターデバイスに応じて、ポインタの位置が移動したり、キーイベントが生成されたりします。
プログラム
XI デバイスの一覧を表示するプログラムです。
各クラスの値については、次回で行います。
<e07-xi1.c>
各クラスの値については、次回で行います。
$ cc -o run e07-xi1.c -lXlib -lXi
<e07-xi1.c>
#include <stdio.h> #include <X11/Xlib.h> #include <X11/extensions/XInput2.h> const char *g_use[] = { "MasterPointer", "MasterKeyboard", "SlavePointer", "SlaveKeyboard", "FloatingSlave" }; int main(int argc,char **argv) { Display *disp; XIDeviceInfo *info,*pi; int major,minor,dnum,i; disp = XOpenDisplay(NULL); if(!disp) return 1; //version major = 2, minor = 4; if(XIQueryVersion(disp, &major, &minor) != Success) { printf("unsupported XI2\n"); XCloseDisplay(disp); return 1; } printf("ver %d.%d\n\n", major, minor); //デバイス情報 info = XIQueryDevice(disp, XIAllDevices, &dnum); for(i = 0; i < dnum; i++) { pi = info + i; printf("-- [%s] --\ndeviceid(%d) use(%s) attachment(%d) enabled(%d) num_classes(%d)\n", pi->name, pi->deviceid, g_use[pi->use - 1], pi->attachment, pi->enabled, pi->num_classes); } XIFreeDeviceInfo(info); // XCloseDisplay(disp); return 0; }
結果例
ver 2.4 -- [Virtual core pointer] -- deviceid(2) use(MasterPointer) attachment(3) enabled(1) num_classes(7) -- [Virtual core keyboard] -- deviceid(3) use(MasterKeyboard) attachment(2) enabled(1) num_classes(1) -- [Virtual core XTEST pointer] -- deviceid(4) use(SlavePointer) attachment(2) enabled(1) num_classes(3) -- [Virtual core XTEST keyboard] -- deviceid(5) use(SlaveKeyboard) attachment(3) enabled(1) num_classes(1) -- [Power Button] -- deviceid(6) use(SlaveKeyboard) attachment(3) enabled(1) num_classes(1) -- [Video Bus] -- deviceid(7) use(SlaveKeyboard) attachment(3) enabled(1) num_classes(1) -- [Power Button] -- deviceid(8) use(SlaveKeyboard) attachment(3) enabled(1) num_classes(1) -- [Sleep Button] -- deviceid(9) use(SlaveKeyboard) attachment(3) enabled(1) num_classes(1) -- [Wacom One by Wacom M Pen stylus] -- deviceid(10) use(SlavePointer) attachment(2) enabled(1) num_classes(12) -- [ELECOM ELECOM BlueLED Mouse] -- deviceid(11) use(SlavePointer) attachment(2) enabled(1) num_classes(7) -- [SEM USB Keyboard] -- deviceid(12) use(SlaveKeyboard) attachment(3) enabled(1) num_classes(1) -- [SEM USB Keyboard Consumer Control] -- deviceid(13) use(SlavePointer) attachment(2) enabled(1) num_classes(7) -- [SEM USB Keyboard System Control] -- deviceid(14) use(SlaveKeyboard) attachment(3) enabled(1) num_classes(1) -- [Wacom One by Wacom M Pen eraser] -- deviceid(15) use(SlavePointer) attachment(2) enabled(1) num_classes(12) -- [SEM USB Keyboard Consumer Control] -- deviceid(16) use(SlaveKeyboard) attachment(3) enabled(1) num_classes(1)
このパソコンには、キーボード、マウス、ペンタブレットがそれぞれ1つ接続されています。
"Virtual core pointer" がマスターポインタ、"Virtual core keyboard" がマスターキーボードで、他のスレーブデバイスは、そのどちらかに接続されています。
なお、"Virtual core XTEST *" は、XTEST 拡張機能に関するスレーブデバイスです。
スレーブキーボードには、実際のキーボードの他に、電源ボタンやスリープボタンもデバイスとして存在しています。
マウスとペンタブレットは、マスターポインタに接続されています。
そのため、どちらを操作しても、画面上のポインタは移動します。
なお、このペンタブレットの実際のペンには、消しゴム機能がありませんが、"eraser" の名前が付いて、ペンの消しゴム部分で操作した時用のデバイスが存在します。
このように、物理的に接続されているデバイスだけではなく、仮想的なデバイスがいくつかあります。
クライアントがデバイスを判断する際は、名前やクラスの情報を見て、何のデバイスかを判断するか、もしくは、対象のデバイスを直接ユーザーに選択してもらう必要があります。