tablet
unstable の「tablet-unstable-v2.xml」のプロトコルを解説します。
これは、ペンタブレットからの入力を行うためのものです。
2019年12月時点では、GNOME が対応しています。
scanner で、「tablet-unstable-v2-client-protocol.h」「tablet-unstable-v2-protocol.c」を生成してください。
p03_tablet.c
マウスの中ボタン押しで終了します。
これは、ペンタブレットからの入力を行うためのものです。
2019年12月時点では、GNOME が対応しています。
プログラム
$ cc -o test p03_tablet.c client.c imagebuf.c \ tablet-unstable-v2-protocol.c -lwayland-client -lrt
scanner で、「tablet-unstable-v2-client-protocol.h」「tablet-unstable-v2-protocol.c」を生成してください。
p03_tablet.c
/****************************** * tablet-unstable-v2 ******************************/ #include <stdio.h> #include <string.h> #include <linux/input.h> #include <wayland-client.h> #include "tablet-unstable-v2-client-protocol.h" #include "client.h" #include "imagebuf.h" //------------------ typedef struct { Client b; struct zwp_tablet_manager_v2 *manager; struct zwp_tablet_seat_v2 *tablet_seat; }ClientEx; //------------------ //---------------------- // zwp_tablet_tool_v2 //---------------------- static void _tablettool_type(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t tool_type) { printf("zwp_tablet_tool_v2 # type | tool_type:0x%X\n", tool_type); } static void _tablettool_hardware_serial(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t hardware_serial_hi, uint32_t hardware_serial_lo) { printf("zwp_tablet_tool_v2 # hardware_serial | 0x%X%08X\n", hardware_serial_hi, hardware_serial_lo); } static void _tablettool_hardware_id_wacom(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t hardware_id_hi, uint32_t hardware_id_lo) { printf("zwp_tablet_tool_v2 # hardware_id_wacom | 0x%X%08X\n", hardware_id_hi, hardware_id_lo); } static void _tablettool_capability(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t capability) { printf("zwp_tablet_tool_v2 # capability | %u\n", capability); } static void _tablettool_done(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2) { printf("zwp_tablet_tool_v2 # done\n"); } static void _tablettool_removed(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2) { printf("zwp_tablet_tool_v2 # removed\n"); zwp_tablet_tool_v2_destroy(zwp_tablet_tool_v2); } static void _tablettool_proximity_in(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t serial, struct zwp_tablet_v2 *tablet, struct wl_surface *surface) { printf("zwp_tablet_tool_v2 # proximity_in | serial:%u\n", serial); } static void _tablettool_proximity_out(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2) { printf("zwp_tablet_tool_v2 # proximity_out\n"); } static void _tablettool_down(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t serial) { printf("zwp_tablet_tool_v2 # down | serial:%u\n", serial); } static void _tablettool_up(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2) { printf("zwp_tablet_tool_v2 # up\n"); } static void _tablettool_motion(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, wl_fixed_t x, wl_fixed_t y) { printf("zwp_tablet_tool_v2 # motion | (%.2f, %.2f)\n", x / 256.0, y / 256.0); } static void _tablettool_pressure(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t pressure) { printf("zwp_tablet_tool_v2 # pressure | %u (%.4f)\n", pressure, pressure / 65535.0); } static void _tablettool_distance(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t distance) { printf("zwp_tablet_tool_v2 # distance | %u (%.4f)\n", distance, distance / 65535.0); } static void _tablettool_tilt(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, wl_fixed_t tilt_x, wl_fixed_t tilt_y) { printf("zwp_tablet_tool_v2 # tilt | x:%.2f, y:%.2f\n", tilt_x / 256.0, tilt_y / 256.0); } static void _tablettool_rotation(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, wl_fixed_t degrees) { printf("zwp_tablet_tool_v2 # rotation | %.2f\n", degrees / 256.0); } static void _tablettool_slider(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, int32_t position) { printf("zwp_tablet_tool_v2 # slider | %d\n", position); } static void _tablettool_wheel(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, wl_fixed_t degrees, int32_t clicks) { printf("zwp_tablet_tool_v2 # wheel | degrees:%.2f, clicks:%d\n", degrees / 256.0, clicks); } static void _tablettool_button(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t serial, uint32_t button, uint32_t state) { printf("zwp_tablet_tool_v2 # button | serial:%u, button:0x%X, state:%u\n", serial, button, state); } static void _tablettool_frame(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t time) { printf("- zwp_tablet_tool_v2 # frame | time:%u\n", time); } static const struct zwp_tablet_tool_v2_listener g_tablet_tool_listener = { _tablettool_type, _tablettool_hardware_serial, _tablettool_hardware_id_wacom, _tablettool_capability, _tablettool_done, _tablettool_removed, _tablettool_proximity_in, _tablettool_proximity_out, _tablettool_down, _tablettool_up, _tablettool_motion, _tablettool_pressure, _tablettool_distance, _tablettool_tilt, _tablettool_rotation, _tablettool_slider, _tablettool_wheel, _tablettool_button, _tablettool_frame }; //---------------------- // zwp_tablet_v2 //---------------------- static void _tablet_name(void *data, struct zwp_tablet_v2 *zwp_tablet_v2, const char *name) { printf("zwp_tablet_v2 # name | name:\"%s\"\n", name); } static void _tablet_id(void *data, struct zwp_tablet_v2 *zwp_tablet_v2, uint32_t vid, uint32_t pid) { printf("zwp_tablet_v2 # id | vid:0x%X, pid:0x%X\n", vid, pid); } static void _tablet_path(void *data, struct zwp_tablet_v2 *zwp_tablet_v2, const char *path) { printf("zwp_tablet_v2 # path | path:\"%s\"\n", path); } static void _tablet_done(void *data, struct zwp_tablet_v2 *zwp_tablet_v2) { printf("zwp_tablet_v2 # done\n"); } static void _tablet_removed(void *data, struct zwp_tablet_v2 *zwp_tablet_v2) { printf("zwp_tablet_v2 # removed\n"); zwp_tablet_v2_destroy(zwp_tablet_v2); } static const struct zwp_tablet_v2_listener g_tablet_listener = { _tablet_name, _tablet_id, _tablet_path, _tablet_done, _tablet_removed }; //---------------------- // zwp_tablet_seat_v2 //---------------------- static void _tabletseat_tablet_added(void *data, struct zwp_tablet_seat_v2 *zwp_tablet_seat_v2, struct zwp_tablet_v2 *id) { printf("zwp_tablet_seat_v2 # tablet_added\n"); zwp_tablet_v2_add_listener(id, &g_tablet_listener, data); } static void _tabletseat_tool_added(void *data, struct zwp_tablet_seat_v2 *zwp_tablet_seat_v2, struct zwp_tablet_tool_v2 *id) { printf("zwp_tablet_seat_v2 # tool_added\n"); zwp_tablet_tool_v2_add_listener(id, &g_tablet_tool_listener, data); } static void _tabletseat_pad_added(void *data, struct zwp_tablet_seat_v2 *zwp_tablet_seat_v2, struct zwp_tablet_pad_v2 *id) { printf("zwp_tablet_seat_v2 # pad_added\n"); } static const struct zwp_tablet_seat_v2_listener g_tablet_seat_listener = { _tabletseat_tablet_added, _tabletseat_tool_added, _tabletseat_pad_added }; //---------------------- // wl_pointer //---------------------- /* enter */ static void _pointer_enter(void *data, struct wl_pointer *pointer, uint32_t serial, struct wl_surface *surface, wl_fixed_t x, wl_fixed_t y) { printf("wl_pointer # enter | surface:%p\n", surface); } static void _pointer_leave(void *data, struct wl_pointer *pointer, uint32_t serial, struct wl_surface *surface) { printf("wl_pointer # leave | surface:%p\n", surface); } static void _pointer_motion(void *data, struct wl_pointer *pointer, uint32_t time, wl_fixed_t x, wl_fixed_t y) { printf("wl_pointer # motion | (%d,%d)\n", x >> 8, y >> 8); } /* ボタン */ static void _pointer_button(void *data, struct wl_pointer *pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state) { printf("wl_pointer # button | %s, button:0x%X, serial:%u\n", (state == WL_POINTER_BUTTON_STATE_PRESSED)? "press":"release", button, serial); if(state != WL_POINTER_BUTTON_STATE_PRESSED) return; switch(button) { //中ボタンで終了 case BTN_MIDDLE: CLIENT(data)->finish_loop = 1; break; } } static void _pointer_axis(void *data, struct wl_pointer *pointer, uint32_t time, uint32_t axis, wl_fixed_t value) { } static void _pointer_frame(void *data, struct wl_pointer *pointer) { } static void _pointer_axis_source(void *data, struct wl_pointer *pointer, uint32_t axis_source) { } static void _pointer_axis_stop(void *data, struct wl_pointer *pointer, uint32_t time, uint32_t axis) { } static void _pointer_axis_discrete(void *data, struct wl_pointer *pointer, uint32_t axis, int32_t discrete) { } static const struct wl_pointer_listener g_pointer_listener = { _pointer_enter, _pointer_leave, _pointer_motion, _pointer_button, _pointer_axis, _pointer_frame, _pointer_axis_source, _pointer_axis_stop, _pointer_axis_discrete }; //----------------- static void _registry_global( void *data,struct wl_registry *reg,uint32_t id,const char *name,uint32_t ver) { ClientEx *p = (ClientEx *)data; if(strcmp(name, "zwp_tablet_manager_v2") == 0) p->manager = wl_registry_bind(reg, id, &zwp_tablet_manager_v2_interface, 1); } /* ClientEx 解放 */ static void _clientex_destroy(Client *cl) { ClientEx *p = (ClientEx *)cl; if(p->tablet_seat) zwp_tablet_seat_v2_destroy(p->tablet_seat); if(p->manager) zwp_tablet_manager_v2_destroy(p->manager); } //----------------- int main(void) { ClientEx *p; Window *win; p = (ClientEx *)Client_new(sizeof(ClientEx)); p->b.destroy = _clientex_destroy; p->b.init_flags = INIT_FLAGS_SEAT | INIT_FLAGS_POINTER; p->b.pointer_listener = &g_pointer_listener; p->b.registry_global = _registry_global; Client_init(CLIENT(p)); if(!p->manager) { Client_destroy(CLIENT(p)); printf("[!] not found 'zwp_tablet_manager_v2'\n"); return 1; } //zwp_tablet_seat_v2 p->tablet_seat = zwp_tablet_manager_v2_get_tablet_seat(p->manager, p->b.seat); zwp_tablet_seat_v2_add_listener(p->tablet_seat, &g_tablet_seat_listener, p); //メインウィンドウ win = Window_create(CLIENT(p), 256, 256, NULL); ImageBuf_fill(win->img, 0xffff0000); Window_update(win); //イベントループ Client_loop_simple(CLIENT(p)); //解放 Window_destroy(win); Client_destroy(CLIENT(p)); return 0; }
マウスの中ボタン押しで終了します。
解説
大まかな流れだけ説明します。
詳細は関数リファレンスをご覧ください。
※ ここでは、zwp_tablet_pad_v2 の処理は省略しています。
詳細は関数リファレンスをご覧ください。
- zwp_tablet_manager_v2 をバインド。
- zwp_tablet_seat_v2 を作成。
(wl_seat が必要) - zwp_tablet_seat_v2 にハンドラを設定。
- zwp_tablet_seat_v2 のハンドラ内で、各オブジェクトにハンドラを設定。
tablet_added : 各デバイスごとの zwp_tablet_v2
tool_added : 各ツールごとの zwp_tablet_tool_v2
pad_added : パッドの zwp_tablet_pad_v2 - 各オブジェクトでイベントを処理。
※ ここでは、zwp_tablet_pad_v2 の処理は省略しています。
zwp_tablet_v2
zwp_tablet_v2 は、タブレットのデバイスの情報を取得するためのものです。
イベントでデータが送られてきます。
イベントでデータが送られてきます。
zwp_tablet_seat_v2 # tablet_added zwp_tablet_v2 # name | name:"Wacom One by Wacom M Pen" zwp_tablet_v2 # path | path:"/dev/input/event4" zwp_tablet_v2 # id | vid:0x56A, pid:0x37B zwp_tablet_v2 # done
zwp_tablet_tool_v2
zwp_tablet_tool_v2 は、タブレットの各ツールの情報を取得するためのもです。
メインで使うのはこのオブジェクトです。
ツールは、通常のスタイラスペンや、ペンの消しゴム部分などです。
アプリケーションを起動して、デバイスを認識した段階では、すべてのツールを列挙することはできません。
実際にタブレット上でツールを使うことで、初めて認識されます。
イベントでは、ツールの初期情報や、座標・筆圧などを取得できます。
最初に、ツールの情報が送られてきます。
ここでは、タイプは「ZWP_TABLET_TOOL_V2_TYPE_PEN」で、筆圧と距離の情報を持っています。
zwp_tablet_tool_v2:proximity_in で、ツールが、指定サーフェスに焦点が合っている状態となります。
ボタンの値は、"linux/input-event-codes.h" で定義されている値です。
0x14b は「BTN_STYLUS」で、スタイラスペンに付いている一番目 (下側) のボタンとなります。
グラブは自動的に行われるので、ツールを接地面から離すか、ツールがタブレットから認識できなくなるまで、イベントは継続されます。
メインで使うのはこのオブジェクトです。
ツールは、通常のスタイラスペンや、ペンの消しゴム部分などです。
アプリケーションを起動して、デバイスを認識した段階では、すべてのツールを列挙することはできません。
実際にタブレット上でツールを使うことで、初めて認識されます。
イベントでは、ツールの初期情報や、座標・筆圧などを取得できます。
イベント
▼ カーソルがウィンドウ内に入った wl_pointer # enter | surface:0x56071f9e96e0 zwp_tablet_seat_v2 # tool_added zwp_tablet_tool_v2 # type | tool_type:0x140 zwp_tablet_tool_v2 # hardware_serial | 0x000000000 zwp_tablet_tool_v2 # hardware_id_wacom | 0x000000000 zwp_tablet_tool_v2 # capability | 2 zwp_tablet_tool_v2 # capability | 3 zwp_tablet_tool_v2 # done zwp_tablet_tool_v2 # proximity_in | serial:438 - zwp_tablet_tool_v2 # frame | time:1501273 zwp_tablet_tool_v2 # motion | (174.62, 253.90) zwp_tablet_tool_v2 # pressure | 0 (0.0000) zwp_tablet_tool_v2 # distance | 46810 (0.7143) - zwp_tablet_tool_v2 # frame | time:1501273 ▼ ペンのボタンを押した zwp_tablet_tool_v2 # button | serial:445, button:0x14b, state:1 - zwp_tablet_tool_v2 # frame | time:1510157 ▼ ペンを接地させた zwp_tablet_tool_v2 # down | serial:447 - zwp_tablet_tool_v2 # frame | time:1510861 zwp_tablet_tool_v2 # motion | (190.89, 157.19) zwp_tablet_tool_v2 # pressure | 22026 (0.3361) zwp_tablet_tool_v2 # distance | 0 (0.0000)
カーソルがサーフェス内に入った
wl_pointer の enter が来た時に、zwp_tablet_seat_v2:tool_added イベントが来ています。最初に、ツールの情報が送られてきます。
ここでは、タイプは「ZWP_TABLET_TOOL_V2_TYPE_PEN」で、筆圧と距離の情報を持っています。
zwp_tablet_tool_v2:proximity_in で、ツールが、指定サーフェスに焦点が合っている状態となります。
ペンのボタンを押した
タブレットまたはペンに付いているボタンを押した時は、zwp_tablet_tool_v2:button イベントが来ます。ボタンの値は、"linux/input-event-codes.h" で定義されている値です。
0x14b は「BTN_STYLUS」で、スタイラスペンに付いている一番目 (下側) のボタンとなります。
ツールを接地させた
ペンをタブレットの接地面に着けた時、zwp_tablet_tool_v2:down イベントが来ます。グラブは自動的に行われるので、ツールを接地面から離すか、ツールがタブレットから認識できなくなるまで、イベントは継続されます。
カーソル形状について
タブレット入力では、各ツールごとにカーソル形状をセットする必要があります。
GNOME では、デスクトップ上でペンを操作すると、十字カーソルになりました。
カーソル形状の変更は、zwp_tablet_tool_v2_set_cursor() を使ってください。
GNOME では、デスクトップ上でペンを操作すると、十字カーソルになりました。
カーソル形状の変更は、zwp_tablet_tool_v2_set_cursor() を使ってください。