1 #include <stdlib.h>
2
3 #include <wlr/config.h>
4
5 #include <linux/input-event-codes.h>
6
7 #include <xcb/xcb.h>
8 #include <xcb/xfixes.h>
9 #include <xcb/xinput.h>
10
11 #include <wlr/interfaces/wlr_input_device.h>
12 #include <wlr/interfaces/wlr_keyboard.h>
13 #include <wlr/interfaces/wlr_pointer.h>
14 #include <wlr/interfaces/wlr_touch.h>
15 #include <wlr/util/log.h>
16
17 #include "backend/x11.h"
18 #include "util/signal.h"
19
send_key_event(struct wlr_x11_backend * x11,uint32_t key,enum wlr_key_state st,xcb_timestamp_t time)20 static void send_key_event(struct wlr_x11_backend *x11, uint32_t key,
21 enum wlr_key_state st, xcb_timestamp_t time) {
22 struct wlr_event_keyboard_key ev = {
23 .time_msec = time,
24 .keycode = key,
25 .state = st,
26 .update_state = true,
27 };
28 wlr_keyboard_notify_key(&x11->keyboard, &ev);
29 }
30
send_button_event(struct wlr_x11_output * output,uint32_t key,enum wlr_button_state st,xcb_timestamp_t time)31 static void send_button_event(struct wlr_x11_output *output, uint32_t key,
32 enum wlr_button_state st, xcb_timestamp_t time) {
33 struct wlr_event_pointer_button ev = {
34 .device = &output->pointer_dev,
35 .time_msec = time,
36 .button = key,
37 .state = st,
38 };
39 wlr_signal_emit_safe(&output->pointer.events.button, &ev);
40 wlr_signal_emit_safe(&output->pointer.events.frame, &output->pointer);
41 }
42
send_axis_event(struct wlr_x11_output * output,int32_t delta,xcb_timestamp_t time)43 static void send_axis_event(struct wlr_x11_output *output, int32_t delta,
44 xcb_timestamp_t time) {
45 struct wlr_event_pointer_axis ev = {
46 .device = &output->pointer_dev,
47 .time_msec = time,
48 .source = WLR_AXIS_SOURCE_WHEEL,
49 .orientation = WLR_AXIS_ORIENTATION_VERTICAL,
50 // 15 is a typical value libinput sends for one scroll
51 .delta = delta * 15,
52 .delta_discrete = delta,
53 };
54 wlr_signal_emit_safe(&output->pointer.events.axis, &ev);
55 wlr_signal_emit_safe(&output->pointer.events.frame, &output->pointer);
56 }
57
send_pointer_position_event(struct wlr_x11_output * output,int16_t x,int16_t y,xcb_timestamp_t time)58 static void send_pointer_position_event(struct wlr_x11_output *output,
59 int16_t x, int16_t y, xcb_timestamp_t time) {
60 struct wlr_event_pointer_motion_absolute ev = {
61 .device = &output->pointer_dev,
62 .time_msec = time,
63 .x = (double)x / output->wlr_output.width,
64 .y = (double)y / output->wlr_output.height,
65 };
66 wlr_signal_emit_safe(&output->pointer.events.motion_absolute, &ev);
67 wlr_signal_emit_safe(&output->pointer.events.frame, &output->pointer);
68 }
69
send_touch_down_event(struct wlr_x11_output * output,int16_t x,int16_t y,int32_t touch_id,xcb_timestamp_t time)70 static void send_touch_down_event(struct wlr_x11_output *output,
71 int16_t x, int16_t y, int32_t touch_id, xcb_timestamp_t time) {
72 struct wlr_event_touch_down ev = {
73 .device = &output->touch_dev,
74 .time_msec = time,
75 .x = (double)x / output->wlr_output.width,
76 .y = (double)y / output->wlr_output.height,
77 .touch_id = touch_id,
78 };
79 wlr_signal_emit_safe(&output->touch.events.down, &ev);
80 }
81
send_touch_motion_event(struct wlr_x11_output * output,int16_t x,int16_t y,int32_t touch_id,xcb_timestamp_t time)82 static void send_touch_motion_event(struct wlr_x11_output *output,
83 int16_t x, int16_t y, int32_t touch_id, xcb_timestamp_t time) {
84 struct wlr_event_touch_motion ev = {
85 .device = &output->touch_dev,
86 .time_msec = time,
87 .x = (double)x / output->wlr_output.width,
88 .y = (double)y / output->wlr_output.height,
89 .touch_id = touch_id,
90 };
91 wlr_signal_emit_safe(&output->touch.events.motion, &ev);
92 }
93
send_touch_up_event(struct wlr_x11_output * output,int32_t touch_id,xcb_timestamp_t time)94 static void send_touch_up_event(struct wlr_x11_output *output,
95 int32_t touch_id, xcb_timestamp_t time) {
96 struct wlr_event_touch_up ev = {
97 .device = &output->touch_dev,
98 .time_msec = time,
99 .touch_id = touch_id,
100 };
101 wlr_signal_emit_safe(&output->touch.events.up, &ev);
102 }
103
get_touchpoint_from_x11_touch_id(struct wlr_x11_output * output,uint32_t id)104 static struct wlr_x11_touchpoint* get_touchpoint_from_x11_touch_id(struct wlr_x11_output *output,
105 uint32_t id) {
106 struct wlr_x11_touchpoint *touchpoint;
107 wl_list_for_each(touchpoint, &output->touchpoints, link) {
108 if (touchpoint->x11_id == id) {
109 return touchpoint;
110 }
111 }
112 return NULL;
113 }
114
handle_x11_xinput_event(struct wlr_x11_backend * x11,xcb_ge_generic_event_t * event)115 void handle_x11_xinput_event(struct wlr_x11_backend *x11,
116 xcb_ge_generic_event_t *event) {
117 struct wlr_x11_output *output;
118
119 switch (event->event_type) {
120 case XCB_INPUT_KEY_PRESS: {
121 xcb_input_key_press_event_t *ev =
122 (xcb_input_key_press_event_t *)event;
123
124 wlr_keyboard_notify_modifiers(&x11->keyboard, ev->mods.base,
125 ev->mods.latched, ev->mods.locked, ev->mods.effective);
126 send_key_event(x11, ev->detail - 8, WLR_KEY_PRESSED, ev->time);
127 x11->time = ev->time;
128 break;
129 }
130 case XCB_INPUT_KEY_RELEASE: {
131 xcb_input_key_release_event_t *ev =
132 (xcb_input_key_release_event_t *)event;
133
134 wlr_keyboard_notify_modifiers(&x11->keyboard, ev->mods.base,
135 ev->mods.latched, ev->mods.locked, ev->mods.effective);
136 send_key_event(x11, ev->detail - 8, WLR_KEY_RELEASED, ev->time);
137 x11->time = ev->time;
138 break;
139 }
140 case XCB_INPUT_BUTTON_PRESS: {
141 xcb_input_button_press_event_t *ev =
142 (xcb_input_button_press_event_t *)event;
143
144 output = get_x11_output_from_window_id(x11, ev->event);
145 if (!output) {
146 return;
147 }
148
149 switch (ev->detail) {
150 case XCB_BUTTON_INDEX_1:
151 send_button_event(output, BTN_LEFT, WLR_BUTTON_PRESSED,
152 ev->time);
153 break;
154 case XCB_BUTTON_INDEX_2:
155 send_button_event(output, BTN_MIDDLE, WLR_BUTTON_PRESSED,
156 ev->time);
157 break;
158 case XCB_BUTTON_INDEX_3:
159 send_button_event(output, BTN_RIGHT, WLR_BUTTON_PRESSED,
160 ev->time);
161 break;
162 case XCB_BUTTON_INDEX_4:
163 send_axis_event(output, -1, ev->time);
164 break;
165 case XCB_BUTTON_INDEX_5:
166 send_axis_event(output, 1, ev->time);
167 break;
168 }
169
170 x11->time = ev->time;
171 break;
172 }
173 case XCB_INPUT_BUTTON_RELEASE: {
174 xcb_input_button_release_event_t *ev =
175 (xcb_input_button_release_event_t *)event;
176
177 output = get_x11_output_from_window_id(x11, ev->event);
178 if (!output) {
179 return;
180 }
181
182 switch (ev->detail) {
183 case XCB_BUTTON_INDEX_1:
184 send_button_event(output, BTN_LEFT, WLR_BUTTON_RELEASED,
185 ev->time);
186 break;
187 case XCB_BUTTON_INDEX_2:
188 send_button_event(output, BTN_MIDDLE, WLR_BUTTON_RELEASED,
189 ev->time);
190 break;
191 case XCB_BUTTON_INDEX_3:
192 send_button_event(output, BTN_RIGHT, WLR_BUTTON_RELEASED,
193 ev->time);
194 break;
195 }
196
197 x11->time = ev->time;
198 break;
199 }
200 case XCB_INPUT_MOTION: {
201 xcb_input_motion_event_t *ev = (xcb_input_motion_event_t *)event;
202
203 output = get_x11_output_from_window_id(x11, ev->event);
204 if (!output) {
205 return;
206 }
207
208 send_pointer_position_event(output, ev->event_x >> 16,
209 ev->event_y >> 16, ev->time);
210 x11->time = ev->time;
211 break;
212 }
213 case XCB_INPUT_ENTER: {
214 xcb_input_enter_event_t *ev = (xcb_input_enter_event_t *)event;
215
216 output = get_x11_output_from_window_id(x11, ev->event);
217 if (!output) {
218 return;
219 }
220
221 if (!output->cursor_hidden) {
222 xcb_xfixes_hide_cursor(x11->xcb, output->win);
223 xcb_flush(x11->xcb);
224 output->cursor_hidden = true;
225 }
226 break;
227 }
228 case XCB_INPUT_LEAVE: {
229 xcb_input_leave_event_t *ev = (xcb_input_leave_event_t *)event;
230
231 output = get_x11_output_from_window_id(x11, ev->event);
232 if (!output) {
233 return;
234 }
235
236 if (output->cursor_hidden) {
237 xcb_xfixes_show_cursor(x11->xcb, output->win);
238 xcb_flush(x11->xcb);
239 output->cursor_hidden = false;
240 }
241 break;
242 }
243 case XCB_INPUT_TOUCH_BEGIN: {
244 xcb_input_touch_begin_event_t *ev = (xcb_input_touch_begin_event_t *)event;
245
246 output = get_x11_output_from_window_id(x11, ev->event);
247 if (!output) {
248 return;
249 }
250
251 int32_t id = 0;
252 if (!wl_list_empty(&output->touchpoints)) {
253 struct wlr_x11_touchpoint *last_touchpoint = wl_container_of(
254 output->touchpoints.next, last_touchpoint, link);
255 id = last_touchpoint->wayland_id + 1;
256 }
257
258 struct wlr_x11_touchpoint *touchpoint = calloc(1, sizeof(struct wlr_x11_touchpoint));
259 touchpoint->x11_id = ev->detail;
260 touchpoint->wayland_id = id;
261 wl_list_init(&touchpoint->link);
262 wl_list_insert(&output->touchpoints, &touchpoint->link);
263
264 send_touch_down_event(output, ev->event_x >> 16,
265 ev->event_y >> 16, touchpoint->wayland_id, ev->time);
266 x11->time = ev->time;
267 break;
268 }
269 case XCB_INPUT_TOUCH_END: {
270 xcb_input_touch_end_event_t *ev = (xcb_input_touch_end_event_t *)event;
271
272 output = get_x11_output_from_window_id(x11, ev->event);
273 if (!output) {
274 return;
275 }
276
277 struct wlr_x11_touchpoint *touchpoint = get_touchpoint_from_x11_touch_id(output, ev->detail);
278 if (!touchpoint) {
279 return;
280 }
281
282 send_touch_up_event(output, touchpoint->wayland_id, ev->time);
283 x11->time = ev->time;
284
285 wl_list_remove(&touchpoint->link);
286 free(touchpoint);
287 break;
288 }
289 case XCB_INPUT_TOUCH_UPDATE: {
290 xcb_input_touch_update_event_t *ev = (xcb_input_touch_update_event_t *)event;
291
292 output = get_x11_output_from_window_id(x11, ev->event);
293 if (!output) {
294 return;
295 }
296
297 struct wlr_x11_touchpoint *touchpoint = get_touchpoint_from_x11_touch_id(output, ev->detail);
298 if (!touchpoint) {
299 return;
300 }
301
302 send_touch_motion_event(output, ev->event_x >> 16,
303 ev->event_y >> 16, touchpoint->wayland_id, ev->time);
304 x11->time = ev->time;
305 break;
306 }
307 }
308 }
309
input_device_destroy(struct wlr_input_device * wlr_device)310 static void input_device_destroy(struct wlr_input_device *wlr_device) {
311 // Don't free the input device, it's on the stack
312 }
313
314 const struct wlr_input_device_impl input_device_impl = {
315 .destroy = input_device_destroy,
316 };
317
keyboard_destroy(struct wlr_keyboard * wlr_keyboard)318 static void keyboard_destroy(struct wlr_keyboard *wlr_keyboard) {
319 // Don't free the keyboard, it's on the stack
320 }
321
322 const struct wlr_keyboard_impl keyboard_impl = {
323 .destroy = keyboard_destroy,
324 };
325
pointer_destroy(struct wlr_pointer * wlr_pointer)326 static void pointer_destroy(struct wlr_pointer *wlr_pointer) {
327 // Don't free the pointer, it's on the stack
328 }
329
330 const struct wlr_pointer_impl pointer_impl = {
331 .destroy = pointer_destroy,
332 };
333
touch_destroy(struct wlr_touch * wlr_touch)334 static void touch_destroy(struct wlr_touch *wlr_touch) {
335 // Don't free the touch, it's on the stack
336 }
337
338 const struct wlr_touch_impl touch_impl = {
339 .destroy = touch_destroy,
340 };
341
update_x11_pointer_position(struct wlr_x11_output * output,xcb_timestamp_t time)342 void update_x11_pointer_position(struct wlr_x11_output *output,
343 xcb_timestamp_t time) {
344 struct wlr_x11_backend *x11 = output->x11;
345
346 xcb_query_pointer_cookie_t cookie =
347 xcb_query_pointer(x11->xcb, output->win);
348 xcb_query_pointer_reply_t *reply =
349 xcb_query_pointer_reply(x11->xcb, cookie, NULL);
350 if (!reply) {
351 return;
352 }
353
354 send_pointer_position_event(output, reply->win_x, reply->win_y, time);
355
356 free(reply);
357 }
358
wlr_input_device_is_x11(struct wlr_input_device * wlr_dev)359 bool wlr_input_device_is_x11(struct wlr_input_device *wlr_dev) {
360 return wlr_dev->impl == &input_device_impl;
361 }
362