summaryrefslogtreecommitdiff
path: root/tests/x11/test_tablet.c
diff options
context:
space:
mode:
authorBerke Güzel <wenekar1@gmail.com>2026-10-12 10:53:22 +0300
committerBerke Güzel <wenekar1@gmail.com>2026-10-12 10:53:22 +0300
commit5206933399775e5ff46baefbbb3a776c2a9bb84c (patch)
treee7549216ac626c1f3ac22345f79fbf80cc5a90fb /tests/x11/test_tablet.c
parent881fb6cb1d64868132287bd9637f4ae1cbc3504c (diff)
feat: add type-safe native platform headers and portable drag support
- Add include/yasl/native/{wayland,cocoa,x11}.h with type-safe handle accessors. - Unify drag-and-drop and window carry support across Wayland, X11, and Cocoa. - Preserve full ABI compatibility for capability flags. - Install native headers conditionally based on enabled backend. - Include missing tablet example and backend test suites.
Diffstat (limited to 'tests/x11/test_tablet.c')
-rw-r--r--tests/x11/test_tablet.c103
1 files changed, 103 insertions, 0 deletions
diff --git a/tests/x11/test_tablet.c b/tests/x11/test_tablet.c
new file mode 100644
index 0000000..39717df
--- /dev/null
+++ b/tests/x11/test_tablet.c
@@ -0,0 +1,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;
+}