summaryrefslogtreecommitdiff
path: root/tests/x11/test_tablet.c
blob: 39717df01ab435d6466fb028884b4bfb55bc9b97 (plain)
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;
}