1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
|
/* Exercise native XI2 samples through the backend and public input queue. */
#include "../../src/x11/window.c"
static struct yasl_mouse_event next(struct x11_surface *surface)
{
struct yasl_input_event event;
assert(yasl_surface_input_poll(&surface->base, &event));
assert(event.surface == &surface->base && event.kind == YASL_INPUT_MOUSE);
return event.mouse;
}
int main(void)
{
struct x11_display display = {
.base.ops = &yasl_x11_backend, .abs_pressure = 10, .abs_tilt_x = 11, .abs_tilt_y = 12,
};
struct x11_surface surface = {.base.display = &display.base, .window = 42};
display.surfaces = &surface;
XIValuatorClassInfo pressure = {.type = XIValuatorClass, .number = 2,
.label = 10, .min = 100, .max = 1100, .mode = XIModeAbsolute};
XIValuatorClassInfo tilt_x = {.type = XIValuatorClass, .number = 4,
.label = 11, .min = -64, .max = 63, .mode = XIModeAbsolute};
XIValuatorClassInfo tilt_y = {.type = XIValuatorClass, .number = 7,
.label = 12, .min = -64, .max = 63, .mode = XIModeAbsolute};
XIAnyClassInfo *classes[] = {(void *)&pressure, (void *)&tilt_x, (void *)&tilt_y};
XIDeviceInfo info = {.deviceid = 8, .name = "Tablet pen", .num_classes = 3, .classes = classes};
struct x11_pointer pointer = {0};
pointer_info(&display, &pointer, &info);
assert(pointer.device == YASL_PTR_DEV_PEN);
display.pointers = &pointer; /* Cache avoids requiring a real X server. */
unsigned char mask[1] = {0};
XISetMask(mask, 2);
XISetMask(mask, 4);
XISetMask(mask, 7);
double values[] = {600, -35, 42};
XIDeviceEvent sample = {.evtype = XI_ButtonPress, .sourceid = 8, .event = 42,
.detail = 1, .event_x = 200.5, .event_y = 175.25,
.mods.effective = ShiftMask, .valuators = {sizeof(mask), mask, values}};
XGenericEventCookie cookie = {.evtype = XI_ButtonPress, .data = &sample};
xi_event(&display, &cookie);
struct yasl_mouse_event ev = next(&surface);
assert(ev.kind == YASL_PTR_PRESS && ev.button == 0 && ev.device == YASL_PTR_DEV_PEN);
assert(ev.pos.x == 201 && ev.pos.y == 175 && ev.mods == YASL_MOD_SHIFT);
assert(ev.pen.pressure == 32768 && ev.pen.tilt_x == -35 && ev.pen.tilt_y == 42);
/* XI2 sends only changed axes, with values packed in mask order. */
mask[0] = 0;
XISetMask(mask, 2);
values[0] = 1100;
sample.evtype = cookie.evtype = XI_Motion;
xi_event(&display, &cookie);
ev = next(&surface);
assert(ev.kind == YASL_PTR_MOTION && ev.pen.pressure == 65535);
assert(ev.pen.tilt_x == -35 && ev.pen.tilt_y == 42);
values[0] = 5000;
xi_event(&display, &cookie);
assert(next(&surface).pen.pressure == 65535);
values[0] = -50;
xi_event(&display, &cookie);
assert(next(&surface).pen.pressure == 0);
info.name = "Tablet ERASER";
pointer_info(&display, &pointer, &info);
assert(pointer.device == YASL_PTR_DEV_ERASER);
values[0] = 900;
sample.evtype = cookie.evtype = XI_ButtonPress;
xi_event(&display, &cookie);
ev = next(&surface);
assert(ev.device == YASL_PTR_DEV_ERASER && ev.pen.pressure > 0);
/* Release must clear pressure even when the driver omits that valuator. */
sample.valuators.mask_len = 0;
sample.evtype = cookie.evtype = XI_ButtonRelease;
xi_event(&display, &cookie);
ev = next(&surface);
assert(ev.kind == YASL_PTR_RELEASE && ev.button == 0 && ev.pen.pressure == 0);
assert(ev.device == YASL_PTR_DEV_ERASER);
XIEnterEvent crossing = {.sourceid = 8, .event = 42, .event_x = 200, .event_y = 175};
cookie = (XGenericEventCookie){.evtype = XI_Leave, .data = &crossing};
xi_event(&display, &cookie);
ev = next(&surface);
assert(ev.kind == YASL_PTR_LEAVE && ev.device == YASL_PTR_DEV_ERASER && !ev.pen.pressure);
/* No tablet axes must produce an ordinary, pressure-free mouse. */
info.num_classes = 0;
pointer_info(&display, &pointer, &info);
sample.evtype = XI_ButtonPress;
sample.detail = 3;
xi_pointer_event(&surface, &sample);
ev = next(&surface);
assert(ev.device == YASL_PTR_DEV_MOUSE && ev.button == 2 && ev.pen.pressure == 0);
assert(pointer_button(2) == 1 && pointer_button(8) == 3);
pointer.pressure = (struct tablet_axis){2, 1, 1, 50};
assert(pressure_value(&pointer.pressure) == 0);
pointer.tilt_x = (struct tablet_axis){4, -90, 90, -200};
assert(tilt_value(&pointer.tilt_x) == -90);
pointer.tilt_x.value = 200;
assert(tilt_value(&pointer.tilt_x) == 90);
display.pointers = NULL;
input_queue_clear(&surface.input);
return 0;
}
|