/* 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; }