commit dbaa0c4
uint
·
2026-08-04 13:32:54 +0000 UTC
parent f6d9d01
X11: XInput2 backend (with fallback)
4 files changed,
+96,
-3
+1,
-1
1@@ -24,7 +24,7 @@ EOF
2 case "$backend" in
3 x11)
4 echo "CONF_CPPFLAGS = -DBACKEND_X11" >> config.mk
5- echo "CONF_LDFLAGS = -lX11 -lXext" >> config.mk
6+ echo "CONF_LDFLAGS = -lX11 -lXext -lXi" >> config.mk
7 echo "CONF_SRC = source/maus_x11.c" >> config.mk
8 echo "CONF_OBJS = build/maus_x11.o" >> config.mk
9 echo "CONF_LIB_NAME = libmaus_x11.a" >> config.mk
+2,
-0
1@@ -20,6 +20,8 @@ typedef struct {
2
3 int8_t cur_rel; /* relative cursor */
4 int8_t ignore_warp;
5+ int8_t xi2;
6+ int xi2_opcode;
7 int32_t mouse_x;
8 int32_t mouse_y;
9 int8_t mouse_pos_set;
+1,
-0
1@@ -31,6 +31,7 @@ if backend == 'x11'
2 deps += [
3 dependency('x11'),
4 dependency('xext'),
5+ dependency('xi'),
6 ]
7 backend_sources += ['source/maus_x11.c']
8
+92,
-2
1@@ -9,6 +9,7 @@
2 #include <X11/keysym.h>
3 #include <X11/cursorfont.h>
4 #include <X11/extensions/XShm.h>
5+#include <X11/extensions/XInput2.h>
6
7 #include "maus.h"
8 #include "maus_input.h"
9@@ -28,6 +29,8 @@ static int8_t handle_event(XEvent* xev, MausEvent* ev, Maus* mw);
10 static MausKey keysym_to_mauskey(KeySym sym);
11 static MausMouseButton mouse_button_to_maus(int btn);
12 static int xerr(Display* dpy, XErrorEvent* ev);
13+static int8_t xi2_handle_event(Maus* mw, XGenericEventCookie* cookie, MausEvent* ev);
14+static void xi2_init(Maus* mw);
15
16 static const KeyMapEntry keymap[] = {
17 { XK_BackSpace, MAUS_KEY_BACKSPACE }, { XK_Tab, MAUS_KEY_TAB },
18@@ -210,6 +213,13 @@ static int8_t handle_event(XEvent* xev, MausEvent* ev, Maus* mw)
19
20 int cx;
21 int cy;
22+ int8_t handled;
23+
24+ if (xev->type == GenericEvent && XGetEventData(be->display, &xev->xcookie)) {
25+ handled = xi2_handle_event(mw, &xev->xcookie, ev);
26+ XFreeEventData(be->display, &xev->xcookie);
27+ return handled;
28+ }
29
30 switch (xev->type) {
31 case Expose:
32@@ -292,6 +302,9 @@ static int8_t handle_event(XEvent* xev, MausEvent* ev, Maus* mw)
33
34 case MotionNotify:
35 if (be->cur_rel) {
36+ if (be->xi2)
37+ return 0;
38+
39 cx = mw->width / 2;
40 cy = mw->height / 2;
41
42@@ -412,6 +425,78 @@ static int xerr(Display* dpy, XErrorEvent* ev)
43 return 0;
44 }
45
46+static int8_t xi2_handle_event(Maus* mw, XGenericEventCookie* cookie, MausEvent* ev)
47+{
48+ MausBackend* be = &mw->backend;
49+ XIRawEvent* raw;
50+ double* values;
51+ double dx;
52+ double dy;
53+ int valuator;
54+ int value;
55+
56+ if (!be->cur_rel || !be->xi2 || cookie->extension != be->xi2_opcode)
57+ return 0;
58+ if (cookie->evtype != XI_RawMotion)
59+ return 0;
60+
61+ raw = cookie->data;
62+ values = raw->raw_values;
63+ dx = 0.0;
64+ dy = 0.0;
65+ value = 0;
66+
67+ for (valuator = 0; valuator < raw->valuators.mask_len * 8; valuator++) {
68+ if (!XIMaskIsSet(raw->valuators.mask, valuator))
69+ continue;
70+ if (valuator == 0)
71+ dx = values[value];
72+ else if (valuator == 1)
73+ dy = values[value];
74+ value++;
75+ }
76+
77+ ev->type = MAUS_EV_MOUSE_MOTION;
78+ ev->mouse.motion.x = (int32_t)dx;
79+ ev->mouse.motion.y = (int32_t)dy;
80+ ev->mouse.motion.dx = ev->mouse.motion.x;
81+ ev->mouse.motion.dy = ev->mouse.motion.y;
82+ return ev->mouse.motion.dx != 0 || ev->mouse.motion.dy != 0;
83+}
84+
85+static void xi2_init(Maus* mw)
86+{
87+ MausBackend* be = &mw->backend;
88+ int event;
89+ int error;
90+ int major;
91+ int minor;
92+ unsigned char mask[(XI_LASTEVENT + 7) / 8];
93+ XIEventMask evmask;
94+
95+ be->xi2 = 0;
96+ be->xi2_opcode = 0;
97+
98+ if (!XQueryExtension(be->display, "XInputExtension", &be->xi2_opcode, &event, &error))
99+ return;
100+
101+ major = 2;
102+ minor = 0;
103+ if (XIQueryVersion(be->display, &major, &minor) != Success)
104+ return;
105+
106+ memset(mask, 0, sizeof(mask));
107+ XISetMask(mask, XI_RawMotion);
108+
109+ evmask.deviceid = XIAllMasterDevices;
110+ evmask.mask_len = sizeof(mask);
111+ evmask.mask = mask;
112+ XISelectEvents(be->display, be->root, &evmask, 1);
113+ XFlush(be->display);
114+
115+ be->xi2 = 1;
116+}
117+
118 void maus_clipboard_set_text(Maus* mw, const char* text)
119 {
120 MausBackend* be = &mw->backend;
121@@ -599,6 +684,7 @@ Maus* maus_init(const char* title, int x, int y, int width, int height)
122 be->mouse_x = 0;
123 be->mouse_y = 0;
124 be->mouse_pos_set = 0;
125+ xi2_init(mw);
126
127 mw->frame_time_last = maus_get_time_ns();
128 mw->title = title;
129@@ -788,8 +874,12 @@ void maus_cur_set_mode(Maus* mw, MausCursorState state)
130 }
131
132 be->cur_rel = 1;
133- be->ignore_warp = 1;
134- XWarpPointer(dpy, None, win, 0, 0, 0, 0, mw->width/2, mw->height/2);
135+ if (!be->xi2) { /* fallback */
136+ be->ignore_warp = 1;
137+ XWarpPointer(dpy, None, win, 0, 0, 0, 0, mw->width/2, mw->height/2);
138+ }
139+ else
140+ be->ignore_warp = 0;
141 XFlush(dpy);
142 return;
143 }