1 /*
2 * Copyright © 2014-2015 Red Hat, Inc.
3 * Copyright © 2014 Lyude Paul
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 */
24
25 #include <config.h>
26
27 #include <check.h>
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <libinput.h>
31 #include <unistd.h>
32 #include <stdbool.h>
33 #include <stdarg.h>
34
35 #include "libinput-util.h"
36 #include "evdev-tablet.h"
37 #include "litest.h"
38 #include "util-input-event.h"
39
40 static inline unsigned int
pick_stylus_or_btn0(struct litest_device * dev)41 pick_stylus_or_btn0(struct litest_device *dev)
42 {
43 if (libevdev_has_event_code(dev->evdev, EV_KEY, BTN_STYLUS))
44 return BTN_STYLUS;
45
46 if (libevdev_has_event_code(dev->evdev, EV_KEY, BTN_0))
47 return BTN_0; /* totem */
48
49 abort();
50 }
51
START_TEST(button_down_up)52 START_TEST(button_down_up)
53 {
54 struct litest_device *dev = litest_current_device();
55 struct libinput *li = dev->libinput;
56 struct libinput_event *event;
57 struct libinput_event_tablet_tool *tev;
58 struct axis_replacement axes[] = {
59 { ABS_DISTANCE, 10 },
60 { ABS_PRESSURE, 0 },
61 { -1, -1 }
62 };
63 unsigned int button = pick_stylus_or_btn0(dev);
64
65 litest_tablet_proximity_in(dev, 10, 10, axes);
66 litest_drain_events(li);
67
68 litest_button_click(dev, button, true);
69 libinput_dispatch(li);
70
71 event = libinput_get_event(li);
72 tev = litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_BUTTON);
73 ck_assert_int_eq(libinput_event_tablet_tool_get_button(tev),
74 button);
75 ck_assert_int_eq(libinput_event_tablet_tool_get_button_state(tev),
76 LIBINPUT_BUTTON_STATE_PRESSED);
77 libinput_event_destroy(event);
78 litest_assert_empty_queue(li);
79
80 litest_button_click(dev, button, false);
81 libinput_dispatch(li);
82
83 event = libinput_get_event(li);
84 tev = litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_BUTTON);
85 ck_assert_int_eq(libinput_event_tablet_tool_get_button(tev),
86 button);
87 ck_assert_int_eq(libinput_event_tablet_tool_get_button_state(tev),
88 LIBINPUT_BUTTON_STATE_RELEASED);
89 libinput_event_destroy(event);
90 litest_assert_empty_queue(li);
91 }
92 END_TEST
93
START_TEST(button_seat_count)94 START_TEST(button_seat_count)
95 {
96 struct litest_device *dev = litest_current_device();
97 struct libinput *li = dev->libinput;
98 struct libinput_event *event;
99 struct libinput_event_tablet_tool *tev;
100 struct litest_device *dev2;
101 struct axis_replacement axes[] = {
102 { ABS_DISTANCE, 10 },
103 { ABS_PRESSURE, 0 },
104 { -1, -1 }
105 };
106 unsigned int button = pick_stylus_or_btn0(dev);
107
108 switch (button) {
109 case BTN_STYLUS:
110 dev2 = litest_add_device(li, LITEST_WACOM_CINTIQ_13HDT_PEN);
111 break;
112 case BTN_0:
113 dev2 = litest_add_device(li, LITEST_DELL_CANVAS_TOTEM);
114 break;
115 default:
116 ck_abort();
117 }
118
119 litest_tablet_proximity_in(dev, 10, 10, axes);
120 litest_tablet_proximity_in(dev2, 10, 10, axes);
121 litest_drain_events(li);
122
123 litest_button_click(dev, button, true);
124 litest_button_click(dev2, button, true);
125 libinput_dispatch(li);
126
127 event = libinput_get_event(li);
128 tev = litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_BUTTON);
129 ck_assert_int_eq(libinput_event_tablet_tool_get_button(tev), button);
130 ck_assert_int_eq(libinput_event_tablet_tool_get_button_state(tev),
131 LIBINPUT_BUTTON_STATE_PRESSED);
132 ck_assert_int_eq(libinput_event_tablet_tool_get_seat_button_count(tev), 1);
133 libinput_event_destroy(event);
134
135 event = libinput_get_event(li);
136 tev = litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_BUTTON);
137 ck_assert_int_eq(libinput_event_tablet_tool_get_button(tev), button);
138 ck_assert_int_eq(libinput_event_tablet_tool_get_button_state(tev),
139 LIBINPUT_BUTTON_STATE_PRESSED);
140 ck_assert_int_eq(libinput_event_tablet_tool_get_seat_button_count(tev), 2);
141 libinput_event_destroy(event);
142
143 litest_assert_empty_queue(li);
144
145 litest_button_click(dev2, button, false);
146 litest_button_click(dev, button, false);
147 libinput_dispatch(li);
148
149 event = libinput_get_event(li);
150 tev = litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_BUTTON);
151 ck_assert_int_eq(libinput_event_tablet_tool_get_button_state(tev),
152 LIBINPUT_BUTTON_STATE_RELEASED);
153 ck_assert_int_eq(libinput_event_tablet_tool_get_button(tev), button);
154 ck_assert_int_eq(libinput_event_tablet_tool_get_seat_button_count(tev), 1);
155 libinput_event_destroy(event);
156
157 event = libinput_get_event(li);
158 tev = litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_BUTTON);
159 ck_assert_int_eq(libinput_event_tablet_tool_get_button_state(tev),
160 LIBINPUT_BUTTON_STATE_RELEASED);
161 ck_assert_int_eq(libinput_event_tablet_tool_get_button(tev), button);
162 ck_assert_int_eq(libinput_event_tablet_tool_get_seat_button_count(tev), 0);
163 libinput_event_destroy(event);
164 litest_assert_empty_queue(li);
165
166 litest_delete_device(dev2);
167 }
168 END_TEST
169
START_TEST(button_up_on_delete)170 START_TEST(button_up_on_delete)
171 {
172 struct libinput *li = litest_create_context();
173 struct litest_device *dev = litest_add_device(li, LITEST_WACOM_INTUOS);
174 struct libevdev *evdev = libevdev_new();
175 unsigned int code;
176
177 litest_tablet_proximity_in(dev, 10, 10, NULL);
178 litest_drain_events(li);
179
180 for (code = BTN_LEFT; code <= BTN_TASK; code++) {
181 if (!libevdev_has_event_code(dev->evdev, EV_KEY, code))
182 continue;
183
184 libevdev_enable_event_code(evdev, EV_KEY, code, NULL);
185 litest_event(dev, EV_KEY, code, 1);
186 litest_event(dev, EV_SYN, SYN_REPORT, 0);
187 libinput_dispatch(li);
188 }
189
190 litest_drain_events(li);
191 litest_delete_device(dev);
192 libinput_dispatch(li);
193
194 for (code = BTN_LEFT; code <= BTN_TASK; code++) {
195 if (!libevdev_has_event_code(evdev, EV_KEY, code))
196 continue;
197
198 litest_assert_tablet_button_event(li,
199 code,
200 LIBINPUT_BUTTON_STATE_RELEASED);
201 }
202
203 litest_assert_tablet_proximity_event(li,
204 LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT);
205 libevdev_free(evdev);
206 litest_destroy_context(li);
207 }
208 END_TEST
209
START_TEST(tip_down_up)210 START_TEST(tip_down_up)
211 {
212 struct litest_device *dev = litest_current_device();
213 struct libinput *li = dev->libinput;
214 struct libinput_event *event;
215 struct libinput_event_tablet_tool *tablet_event;
216 struct axis_replacement axes[] = {
217 { ABS_DISTANCE, 10 },
218 { ABS_PRESSURE, 0 },
219 { -1, -1 }
220 };
221
222 litest_tablet_proximity_in(dev, 10, 10, axes);
223 litest_drain_events(li);
224
225 litest_axis_set_value(axes, ABS_DISTANCE, 0);
226 litest_axis_set_value(axes, ABS_PRESSURE, 30);
227 litest_tablet_tip_down(dev, 10, 10, axes);
228
229 libinput_dispatch(li);
230
231 event = libinput_get_event(li);
232 tablet_event = litest_is_tablet_event(event,
233 LIBINPUT_EVENT_TABLET_TOOL_TIP);
234 ck_assert_int_eq(libinput_event_tablet_tool_get_tip_state(tablet_event),
235 LIBINPUT_TABLET_TOOL_TIP_DOWN);
236 libinput_event_destroy(event);
237 litest_assert_empty_queue(li);
238
239 litest_axis_set_value(axes, ABS_DISTANCE, 10);
240 litest_axis_set_value(axes, ABS_PRESSURE, 0);
241 litest_tablet_tip_up(dev, 10, 10, axes);
242
243 libinput_dispatch(li);
244 event = libinput_get_event(li);
245 tablet_event = litest_is_tablet_event(event,
246 LIBINPUT_EVENT_TABLET_TOOL_TIP);
247 ck_assert_int_eq(libinput_event_tablet_tool_get_tip_state(tablet_event),
248 LIBINPUT_TABLET_TOOL_TIP_UP);
249 libinput_event_destroy(event);
250
251 litest_assert_empty_queue(li);
252
253 }
254 END_TEST
255
START_TEST(tip_down_up_eraser)256 START_TEST(tip_down_up_eraser)
257 {
258 struct litest_device *dev = litest_current_device();
259 struct libinput *li = dev->libinput;
260 struct libinput_event *event;
261 struct libinput_event_tablet_tool *tablet_event;
262 struct libinput_tablet_tool *tool;
263 struct axis_replacement axes[] = {
264 { ABS_DISTANCE, 10 },
265 { ABS_PRESSURE, 0 },
266 { -1, -1 }
267 };
268
269 if (!libevdev_has_event_code(dev->evdev, EV_KEY, BTN_TOOL_RUBBER))
270 return;
271
272 litest_tablet_set_tool_type(dev, BTN_TOOL_RUBBER);
273
274 litest_tablet_proximity_in(dev, 10, 10, axes);
275 litest_drain_events(li);
276
277 litest_axis_set_value(axes, ABS_DISTANCE, 0);
278 litest_axis_set_value(axes, ABS_PRESSURE, 30);
279 litest_tablet_tip_down(dev, 10, 10, axes);
280
281 libinput_dispatch(li);
282
283 event = libinput_get_event(li);
284 tablet_event = litest_is_tablet_event(event,
285 LIBINPUT_EVENT_TABLET_TOOL_TIP);
286 ck_assert_int_eq(libinput_event_tablet_tool_get_tip_state(tablet_event),
287 LIBINPUT_TABLET_TOOL_TIP_DOWN);
288 tool = libinput_event_tablet_tool_get_tool(tablet_event);
289 ck_assert_int_eq(libinput_tablet_tool_get_type(tool), LIBINPUT_TABLET_TOOL_TYPE_ERASER);
290 libinput_event_destroy(event);
291 litest_assert_empty_queue(li);
292
293 litest_axis_set_value(axes, ABS_DISTANCE, 10);
294 litest_axis_set_value(axes, ABS_PRESSURE, 0);
295 litest_tablet_tip_up(dev, 10, 10, axes);
296
297 libinput_dispatch(li);
298 event = libinput_get_event(li);
299 tablet_event = litest_is_tablet_event(event,
300 LIBINPUT_EVENT_TABLET_TOOL_TIP);
301 ck_assert_int_eq(libinput_event_tablet_tool_get_tip_state(tablet_event),
302 LIBINPUT_TABLET_TOOL_TIP_UP);
303 tool = libinput_event_tablet_tool_get_tool(tablet_event);
304 ck_assert_int_eq(libinput_tablet_tool_get_type(tool), LIBINPUT_TABLET_TOOL_TYPE_ERASER);
305 libinput_event_destroy(event);
306
307 litest_assert_empty_queue(li);
308
309 }
310 END_TEST
311
START_TEST(tip_down_prox_in)312 START_TEST(tip_down_prox_in)
313 {
314 struct litest_device *dev = litest_current_device();
315 struct libinput *li = dev->libinput;
316 struct libinput_event *event;
317 struct libinput_event_tablet_tool *tablet_event;
318 struct axis_replacement axes[] = {
319 { ABS_DISTANCE, 0 },
320 { ABS_PRESSURE, 30 },
321 { -1, -1 }
322 };
323
324 litest_drain_events(li);
325
326 litest_push_event_frame(dev);
327 litest_tablet_proximity_in(dev, 10, 10, axes);
328 litest_tablet_tip_down(dev, 10, 10, axes);
329 litest_pop_event_frame(dev);
330
331 libinput_dispatch(li);
332 event = libinput_get_event(li);
333 tablet_event = litest_is_tablet_event(event,
334 LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
335 ck_assert_int_eq(libinput_event_tablet_tool_get_proximity_state(tablet_event),
336 LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN);
337 libinput_event_destroy(event);
338
339 event = libinput_get_event(li);
340 tablet_event = litest_is_tablet_event(event,
341 LIBINPUT_EVENT_TABLET_TOOL_TIP);
342 ck_assert_int_eq(libinput_event_tablet_tool_get_tip_state(tablet_event),
343 LIBINPUT_TABLET_TOOL_TIP_DOWN);
344 libinput_event_destroy(event);
345
346 litest_assert_empty_queue(li);
347
348 }
349 END_TEST
350
START_TEST(tip_up_prox_out)351 START_TEST(tip_up_prox_out)
352 {
353 struct litest_device *dev = litest_current_device();
354 struct libinput *li = dev->libinput;
355 struct libinput_event *event;
356 struct libinput_event_tablet_tool *tablet_event;
357 struct axis_replacement axes[] = {
358 { ABS_DISTANCE, 0 },
359 { ABS_PRESSURE, 30 },
360 { -1, -1 }
361 };
362
363 litest_tablet_proximity_in(dev, 10, 10, axes);
364 litest_tablet_tip_down(dev, 10, 10, axes);
365 litest_drain_events(li);
366
367 litest_axis_set_value(axes, ABS_DISTANCE, 30);
368 litest_axis_set_value(axes, ABS_PRESSURE, 0);
369 litest_push_event_frame(dev);
370 litest_tablet_tip_up(dev, 10, 10, axes);
371 litest_tablet_proximity_out(dev);
372 litest_pop_event_frame(dev);
373
374 libinput_dispatch(li);
375 event = libinput_get_event(li);
376 tablet_event = litest_is_tablet_event(event,
377 LIBINPUT_EVENT_TABLET_TOOL_TIP);
378 ck_assert_int_eq(libinput_event_tablet_tool_get_tip_state(tablet_event),
379 LIBINPUT_TABLET_TOOL_TIP_UP);
380 libinput_event_destroy(event);
381
382 litest_timeout_tablet_proxout();
383 libinput_dispatch(li);
384 event = libinput_get_event(li);
385 tablet_event = litest_is_tablet_event(event,
386 LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
387 ck_assert_int_eq(libinput_event_tablet_tool_get_proximity_state(tablet_event),
388 LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT);
389 libinput_event_destroy(event);
390
391 litest_assert_empty_queue(li);
392
393 }
394 END_TEST
395
START_TEST(tip_up_btn_change)396 START_TEST(tip_up_btn_change)
397 {
398 struct litest_device *dev = litest_current_device();
399 struct libinput *li = dev->libinput;
400 struct libinput_event *event;
401 struct libinput_event_tablet_tool *tablet_event;
402 struct axis_replacement axes[] = {
403 { ABS_DISTANCE, 0 },
404 { ABS_PRESSURE, 30 },
405 { -1, -1 }
406 };
407
408 litest_tablet_proximity_in(dev, 10, 10, axes);
409 litest_tablet_tip_down(dev, 10, 10, axes);
410 litest_drain_events(li);
411
412 litest_axis_set_value(axes, ABS_DISTANCE, 30);
413 litest_axis_set_value(axes, ABS_PRESSURE, 0);
414 litest_push_event_frame(dev);
415 litest_tablet_tip_up(dev, 10, 20, axes);
416 litest_event(dev, EV_KEY, BTN_STYLUS, 1);
417 litest_pop_event_frame(dev);
418
419 libinput_dispatch(li);
420
421 event = libinput_get_event(li);
422 tablet_event = litest_is_tablet_event(event,
423 LIBINPUT_EVENT_TABLET_TOOL_TIP);
424 ck_assert_int_eq(libinput_event_tablet_tool_get_tip_state(tablet_event),
425 LIBINPUT_TABLET_TOOL_TIP_UP);
426 libinput_event_destroy(event);
427
428 event = libinput_get_event(li);
429 tablet_event = litest_is_tablet_event(event,
430 LIBINPUT_EVENT_TABLET_TOOL_BUTTON);
431 ck_assert_int_eq(libinput_event_tablet_tool_get_button(tablet_event),
432 BTN_STYLUS);
433 ck_assert_int_eq(libinput_event_tablet_tool_get_button_state(tablet_event),
434 LIBINPUT_BUTTON_STATE_PRESSED);
435 libinput_event_destroy(event);
436
437 litest_assert_empty_queue(li);
438
439 litest_axis_set_value(axes, ABS_DISTANCE, 0);
440 litest_axis_set_value(axes, ABS_PRESSURE, 30);
441 litest_tablet_tip_down(dev, 10, 10, axes);
442 litest_drain_events(li);
443
444 /* same thing with a release at tip-up */
445 litest_axis_set_value(axes, ABS_DISTANCE, 30);
446 litest_axis_set_value(axes, ABS_PRESSURE, 0);
447 litest_push_event_frame(dev);
448 litest_tablet_tip_up(dev, 10, 10, axes);
449 litest_event(dev, EV_KEY, BTN_STYLUS, 0);
450 litest_pop_event_frame(dev);
451
452 libinput_dispatch(li);
453
454 event = libinput_get_event(li);
455 tablet_event = litest_is_tablet_event(event,
456 LIBINPUT_EVENT_TABLET_TOOL_TIP);
457 ck_assert_int_eq(libinput_event_tablet_tool_get_tip_state(tablet_event),
458 LIBINPUT_TABLET_TOOL_TIP_UP);
459 libinput_event_destroy(event);
460
461 event = libinput_get_event(li);
462 tablet_event = litest_is_tablet_event(event,
463 LIBINPUT_EVENT_TABLET_TOOL_BUTTON);
464 ck_assert_int_eq(libinput_event_tablet_tool_get_button(tablet_event),
465 BTN_STYLUS);
466 ck_assert_int_eq(libinput_event_tablet_tool_get_button_state(tablet_event),
467 LIBINPUT_BUTTON_STATE_RELEASED);
468 libinput_event_destroy(event);
469
470 litest_assert_empty_queue(li);
471 }
472 END_TEST
473
START_TEST(tip_down_btn_change)474 START_TEST(tip_down_btn_change)
475 {
476 struct litest_device *dev = litest_current_device();
477 struct libinput *li = dev->libinput;
478 struct libinput_event *event;
479 struct libinput_event_tablet_tool *tablet_event;
480 struct axis_replacement axes[] = {
481 { ABS_DISTANCE, 10 },
482 { ABS_PRESSURE, 0 },
483 { -1, -1 }
484 };
485
486 litest_tablet_proximity_in(dev, 10, 10, axes);
487 litest_drain_events(li);
488
489 litest_axis_set_value(axes, ABS_DISTANCE, 0);
490 litest_axis_set_value(axes, ABS_PRESSURE, 30);
491 litest_push_event_frame(dev);
492 litest_tablet_tip_down(dev, 10, 20, axes);
493 litest_event(dev, EV_KEY, BTN_STYLUS, 1);
494 litest_pop_event_frame(dev);
495
496 libinput_dispatch(li);
497
498 event = libinput_get_event(li);
499 tablet_event = litest_is_tablet_event(event,
500 LIBINPUT_EVENT_TABLET_TOOL_TIP);
501 ck_assert_int_eq(libinput_event_tablet_tool_get_tip_state(tablet_event),
502 LIBINPUT_TABLET_TOOL_TIP_DOWN);
503 libinput_event_destroy(event);
504
505 libinput_dispatch(li);
506 event = libinput_get_event(li);
507 tablet_event = litest_is_tablet_event(event,
508 LIBINPUT_EVENT_TABLET_TOOL_BUTTON);
509 ck_assert_int_eq(libinput_event_tablet_tool_get_button(tablet_event),
510 BTN_STYLUS);
511 ck_assert_int_eq(libinput_event_tablet_tool_get_button_state(tablet_event),
512 LIBINPUT_BUTTON_STATE_PRESSED);
513 libinput_event_destroy(event);
514
515 litest_assert_empty_queue(li);
516
517 litest_axis_set_value(axes, ABS_DISTANCE, 30);
518 litest_axis_set_value(axes, ABS_PRESSURE, 0);
519 litest_tablet_tip_up(dev, 10, 20, axes);
520 litest_drain_events(li);
521
522 /* same thing with a release at tip-down */
523 litest_axis_set_value(axes, ABS_DISTANCE, 0);
524 litest_axis_set_value(axes, ABS_PRESSURE, 30);
525 litest_push_event_frame(dev);
526 litest_tablet_tip_down(dev, 10, 20, axes);
527 litest_event(dev, EV_KEY, BTN_STYLUS, 0);
528 litest_pop_event_frame(dev);
529
530 libinput_dispatch(li);
531
532 event = libinput_get_event(li);
533 tablet_event = litest_is_tablet_event(event,
534 LIBINPUT_EVENT_TABLET_TOOL_TIP);
535 ck_assert_int_eq(libinput_event_tablet_tool_get_tip_state(tablet_event),
536 LIBINPUT_TABLET_TOOL_TIP_DOWN);
537 libinput_event_destroy(event);
538
539 libinput_dispatch(li);
540 event = libinput_get_event(li);
541 tablet_event = litest_is_tablet_event(event,
542 LIBINPUT_EVENT_TABLET_TOOL_BUTTON);
543 ck_assert_int_eq(libinput_event_tablet_tool_get_button(tablet_event),
544 BTN_STYLUS);
545 ck_assert_int_eq(libinput_event_tablet_tool_get_button_state(tablet_event),
546 LIBINPUT_BUTTON_STATE_RELEASED);
547 libinput_event_destroy(event);
548
549 litest_assert_empty_queue(li);
550 }
551 END_TEST
552
START_TEST(tip_down_motion)553 START_TEST(tip_down_motion)
554 {
555 struct litest_device *dev = litest_current_device();
556 struct libinput *li = dev->libinput;
557 struct libinput_event *event;
558 struct libinput_event_tablet_tool *tablet_event;
559 struct axis_replacement axes[] = {
560 { ABS_DISTANCE, 10 },
561 { ABS_PRESSURE, 0 },
562 { -1, -1 }
563 };
564 double x, y, last_x, last_y;
565
566 litest_drain_events(li);
567
568 litest_tablet_proximity_in(dev, 10, 10, axes);
569 libinput_dispatch(li);
570 event = libinput_get_event(li);
571 tablet_event = litest_is_tablet_event(event,
572 LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
573 last_x = libinput_event_tablet_tool_get_x(tablet_event);
574 last_y = libinput_event_tablet_tool_get_y(tablet_event);
575 libinput_event_destroy(event);
576
577 /* move x/y on tip down, make sure x/y changed */
578 litest_axis_set_value(axes, ABS_DISTANCE, 0);
579 litest_axis_set_value(axes, ABS_PRESSURE, 20);
580 litest_tablet_tip_down(dev, 70, 70, axes);
581
582 libinput_dispatch(li);
583 event = libinput_get_event(li);
584 tablet_event = litest_is_tablet_event(event,
585 LIBINPUT_EVENT_TABLET_TOOL_TIP);
586 ck_assert_int_eq(libinput_event_tablet_tool_get_tip_state(tablet_event),
587 LIBINPUT_TABLET_TOOL_TIP_DOWN);
588 ck_assert(libinput_event_tablet_tool_x_has_changed(tablet_event));
589 ck_assert(libinput_event_tablet_tool_y_has_changed(tablet_event));
590 x = libinput_event_tablet_tool_get_x(tablet_event);
591 y = libinput_event_tablet_tool_get_y(tablet_event);
592 ck_assert_double_lt(last_x, x);
593 ck_assert_double_lt(last_y, y);
594 libinput_event_destroy(event);
595
596 litest_assert_empty_queue(li);
597 }
598 END_TEST
599
START_TEST(tip_up_motion)600 START_TEST(tip_up_motion)
601 {
602 struct litest_device *dev = litest_current_device();
603 struct libinput *li = dev->libinput;
604 struct libinput_event *event;
605 struct libinput_event_tablet_tool *tablet_event;
606 struct axis_replacement axes[] = {
607 { ABS_DISTANCE, 0 },
608 { ABS_PRESSURE, 0 },
609 { -1, -1 }
610 };
611 double x, y, last_x, last_y;
612
613 litest_tablet_proximity_in(dev, 10, 10, axes);
614 litest_drain_events(li);
615
616 litest_axis_set_value(axes, ABS_PRESSURE, 20);
617 litest_tablet_tip_down(dev, 70, 70, axes);
618
619 libinput_dispatch(li);
620 event = libinput_get_event(li);
621 tablet_event = litest_is_tablet_event(event,
622 LIBINPUT_EVENT_TABLET_TOOL_TIP);
623 last_x = libinput_event_tablet_tool_get_x(tablet_event);
624 last_y = libinput_event_tablet_tool_get_y(tablet_event);
625 libinput_event_destroy(event);
626
627 /* move x/y on tip up, make sure x/y changed */
628 litest_axis_set_value(axes, ABS_PRESSURE, 0);
629 litest_tablet_tip_up(dev, 40, 40, axes);
630
631 libinput_dispatch(li);
632 event = libinput_get_event(li);
633 tablet_event = litest_is_tablet_event(event,
634 LIBINPUT_EVENT_TABLET_TOOL_TIP);
635 ck_assert_int_eq(libinput_event_tablet_tool_get_tip_state(tablet_event),
636 LIBINPUT_TABLET_TOOL_TIP_UP);
637 ck_assert(libinput_event_tablet_tool_x_has_changed(tablet_event));
638 ck_assert(libinput_event_tablet_tool_y_has_changed(tablet_event));
639 x = libinput_event_tablet_tool_get_x(tablet_event);
640 y = libinput_event_tablet_tool_get_y(tablet_event);
641 ck_assert_double_ne(last_x, x);
642 ck_assert_double_ne(last_y, y);
643 libinput_event_destroy(event);
644
645 litest_assert_empty_queue(li);
646 }
647 END_TEST
648
START_TEST(tip_up_motion_one_axis)649 START_TEST(tip_up_motion_one_axis)
650 {
651 struct litest_device *dev = litest_current_device();
652 struct libinput *li = dev->libinput;
653 struct libinput_event *event;
654 struct libinput_event_tablet_tool *tablet_event;
655 struct axis_replacement axes[] = {
656 { ABS_DISTANCE, 0 },
657 { ABS_PRESSURE, 0 },
658 { -1, -1 }
659 };
660 unsigned int axis = _i; /* ranged test */
661 double x, y, last_x, last_y;
662 double start_x = 20,
663 start_y = 20;
664
665 switch (axis) {
666 case ABS_X:
667 start_x = 15;
668 start_y = 20;
669 break;
670 case ABS_Y:
671 start_x = 20;
672 start_y = 15;
673 break;
674 default:
675 abort();
676 }
677
678 /* generate enough events to fill the history and move alonge the
679 * current axis to avoid axis smoothing interference */
680 litest_tablet_proximity_in(dev, start_x, start_y, axes);
681 litest_axis_set_value(axes, ABS_PRESSURE, 20);
682 for (int i = 0; i < 5; i++) {
683 litest_tablet_tip_down(dev, start_x, start_y, axes);
684
685 switch (axis) {
686 case ABS_X:
687 start_x++;
688 break;
689 case ABS_Y:
690 start_y++;
691 break;
692 }
693
694 }
695 litest_drain_events(li);
696
697 litest_tablet_motion(dev, 20, 20, axes);
698 libinput_dispatch(li);
699 event = libinput_get_event(li);
700 tablet_event = litest_is_tablet_event(event,
701 LIBINPUT_EVENT_TABLET_TOOL_AXIS);
702 last_x = libinput_event_tablet_tool_get_x(tablet_event);
703 last_y = libinput_event_tablet_tool_get_y(tablet_event);
704 libinput_event_destroy(event);
705
706 /* move x on tip up, make sure x/y changed */
707 litest_axis_set_value(axes, ABS_PRESSURE, 0);
708 switch (axis) {
709 case ABS_X:
710 litest_tablet_tip_up(dev, 40, 20, axes);
711 break;
712 case ABS_Y:
713 litest_tablet_tip_up(dev, 20, 40, axes);
714 break;
715 }
716
717 libinput_dispatch(li);
718 event = libinput_get_event(li);
719 tablet_event = litest_is_tablet_event(event,
720 LIBINPUT_EVENT_TABLET_TOOL_TIP);
721 ck_assert_int_eq(libinput_event_tablet_tool_get_tip_state(tablet_event),
722 LIBINPUT_TABLET_TOOL_TIP_UP);
723 x = libinput_event_tablet_tool_get_x(tablet_event);
724 y = libinput_event_tablet_tool_get_y(tablet_event);
725
726 switch(axis) {
727 case ABS_X:
728 ck_assert(libinput_event_tablet_tool_x_has_changed(tablet_event));
729 ck_assert(!libinput_event_tablet_tool_y_has_changed(tablet_event));
730 ck_assert_double_ne(last_x, x);
731 ck_assert_double_eq(last_y, y);
732 break;
733 case ABS_Y:
734 ck_assert(!libinput_event_tablet_tool_x_has_changed(tablet_event));
735 ck_assert(libinput_event_tablet_tool_y_has_changed(tablet_event));
736 ck_assert_double_eq(last_x, x);
737 ck_assert_double_ne(last_y, y);
738 break;
739 }
740
741 libinput_event_destroy(event);
742
743 litest_assert_empty_queue(li);
744 }
745 END_TEST
746
START_TEST(tip_state_proximity)747 START_TEST(tip_state_proximity)
748 {
749 struct litest_device *dev = litest_current_device();
750 struct libinput *li = dev->libinput;
751 struct libinput_event *event;
752 struct libinput_event_tablet_tool *tablet_event;
753 struct axis_replacement axes[] = {
754 { ABS_DISTANCE, 10 },
755 { ABS_PRESSURE, 0 },
756 { -1, -1 }
757 };
758
759 litest_drain_events(li);
760
761 litest_tablet_proximity_in(dev, 10, 10, axes);
762 libinput_dispatch(li);
763
764 event = libinput_get_event(li);
765 tablet_event = litest_is_tablet_event(event,
766 LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
767 ck_assert_int_eq(libinput_event_tablet_tool_get_tip_state(tablet_event),
768 LIBINPUT_TABLET_TOOL_TIP_UP);
769 libinput_event_destroy(event);
770
771 litest_axis_set_value(axes, ABS_PRESSURE, 30);
772 litest_axis_set_value(axes, ABS_DISTANCE, 0);
773 litest_tablet_tip_down(dev, 10, 10, axes);
774
775 litest_axis_set_value(axes, ABS_PRESSURE, 0);
776 litest_axis_set_value(axes, ABS_DISTANCE, 10);
777 litest_tablet_tip_up(dev, 10, 10, axes);
778
779 litest_drain_events(li);
780
781 litest_tablet_proximity_out(dev);
782 libinput_dispatch(li);
783
784 litest_timeout_tablet_proxout();
785 libinput_dispatch(li);
786
787 event = libinput_get_event(li);
788 tablet_event = litest_is_tablet_event(event,
789 LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
790 ck_assert_int_eq(libinput_event_tablet_tool_get_tip_state(tablet_event),
791 LIBINPUT_TABLET_TOOL_TIP_UP);
792 libinput_event_destroy(event);
793 }
794 END_TEST
795
START_TEST(tip_state_axis)796 START_TEST(tip_state_axis)
797 {
798 struct litest_device *dev = litest_current_device();
799 struct libinput *li = dev->libinput;
800 struct libinput_event *event;
801 struct libinput_event_tablet_tool *tablet_event;
802 struct axis_replacement axes[] = {
803 { ABS_DISTANCE, 10 },
804 { ABS_PRESSURE, 0 },
805 { -1, -1 }
806 };
807
808 litest_tablet_proximity_in(dev, 10, 10, axes);
809 litest_drain_events(li);
810
811 litest_tablet_motion(dev, 70, 70, axes);
812 libinput_dispatch(li);
813
814 event = libinput_get_event(li);
815 tablet_event = litest_is_tablet_event(event,
816 LIBINPUT_EVENT_TABLET_TOOL_AXIS);
817 ck_assert_int_eq(libinput_event_tablet_tool_get_tip_state(tablet_event),
818 LIBINPUT_TABLET_TOOL_TIP_UP);
819 libinput_event_destroy(event);
820
821 litest_axis_set_value(axes, ABS_PRESSURE, 30);
822 litest_axis_set_value(axes, ABS_DISTANCE, 0);
823 litest_tablet_tip_down(dev, 40, 40, axes);
824 litest_drain_events(li);
825
826 litest_tablet_motion(dev, 30, 30, axes);
827 libinput_dispatch(li);
828
829 event = libinput_get_event(li);
830 tablet_event = litest_is_tablet_event(event,
831 LIBINPUT_EVENT_TABLET_TOOL_AXIS);
832 ck_assert_int_eq(libinput_event_tablet_tool_get_tip_state(tablet_event),
833 LIBINPUT_TABLET_TOOL_TIP_DOWN);
834 libinput_event_destroy(event);
835
836 litest_axis_set_value(axes, ABS_PRESSURE, 0);
837 litest_axis_set_value(axes, ABS_DISTANCE, 10);
838 litest_tablet_tip_up(dev, 40, 40, axes);
839 litest_drain_events(li);
840
841 litest_tablet_motion(dev, 40, 80, axes);
842 libinput_dispatch(li);
843
844 event = libinput_get_event(li);
845 tablet_event = litest_is_tablet_event(event,
846 LIBINPUT_EVENT_TABLET_TOOL_AXIS);
847 ck_assert_int_eq(libinput_event_tablet_tool_get_tip_state(tablet_event),
848 LIBINPUT_TABLET_TOOL_TIP_UP);
849 libinput_event_destroy(event);
850
851 litest_assert_empty_queue(li);
852 }
853 END_TEST
854
START_TEST(tip_state_button)855 START_TEST(tip_state_button)
856 {
857 struct litest_device *dev = litest_current_device();
858 struct libinput *li = dev->libinput;
859 struct libinput_event *event;
860 struct libinput_event_tablet_tool *tablet_event;
861 struct axis_replacement axes[] = {
862 { ABS_DISTANCE, 10 },
863 { ABS_PRESSURE, 0 },
864 { -1, -1 }
865 };
866 unsigned int button = pick_stylus_or_btn0(dev);
867
868 litest_tablet_proximity_in(dev, 10, 10, axes);
869 litest_drain_events(li);
870
871 litest_button_click(dev, button, true);
872 libinput_dispatch(li);
873
874 event = libinput_get_event(li);
875 tablet_event = litest_is_tablet_event(event,
876 LIBINPUT_EVENT_TABLET_TOOL_BUTTON);
877 ck_assert_int_eq(libinput_event_tablet_tool_get_tip_state(tablet_event),
878 LIBINPUT_TABLET_TOOL_TIP_UP);
879 libinput_event_destroy(event);
880
881 litest_axis_set_value(axes, ABS_PRESSURE, 30);
882 litest_axis_set_value(axes, ABS_DISTANCE, 0);
883 litest_tablet_tip_down(dev, 40, 40, axes);
884 litest_drain_events(li);
885
886 litest_button_click(dev, button, false);
887 libinput_dispatch(li);
888
889 event = libinput_get_event(li);
890 tablet_event = litest_is_tablet_event(event,
891 LIBINPUT_EVENT_TABLET_TOOL_BUTTON);
892 ck_assert_int_eq(libinput_event_tablet_tool_get_tip_state(tablet_event),
893 LIBINPUT_TABLET_TOOL_TIP_DOWN);
894 libinput_event_destroy(event);
895
896 litest_axis_set_value(axes, ABS_PRESSURE, 0);
897 litest_axis_set_value(axes, ABS_DISTANCE, 10);
898 litest_tablet_tip_up(dev, 40, 40, axes);
899 litest_drain_events(li);
900
901 litest_button_click(dev, button, true);
902 libinput_dispatch(li);
903
904 event = libinput_get_event(li);
905 tablet_event = litest_is_tablet_event(event,
906 LIBINPUT_EVENT_TABLET_TOOL_BUTTON);
907 ck_assert_int_eq(libinput_event_tablet_tool_get_tip_state(tablet_event),
908 LIBINPUT_TABLET_TOOL_TIP_UP);
909 libinput_event_destroy(event);
910
911 litest_button_click(dev, button, false);
912 libinput_dispatch(li);
913
914 event = libinput_get_event(li);
915 tablet_event = litest_is_tablet_event(event,
916 LIBINPUT_EVENT_TABLET_TOOL_BUTTON);
917 ck_assert_int_eq(libinput_event_tablet_tool_get_tip_state(tablet_event),
918 LIBINPUT_TABLET_TOOL_TIP_UP);
919 libinput_event_destroy(event);
920
921 litest_assert_empty_queue(li);
922 }
923 END_TEST
924
START_TEST(tip_up_on_delete)925 START_TEST(tip_up_on_delete)
926 {
927 struct libinput *li = litest_create_context();
928 struct litest_device *dev = litest_add_device(li, LITEST_WACOM_INTUOS);
929 struct libinput_event *event;
930 struct libinput_event_tablet_tool *tablet_event;
931 struct axis_replacement axes[] = {
932 { ABS_DISTANCE, 10 },
933 { ABS_PRESSURE, 0 },
934 { -1, -1 }
935 };
936
937 litest_tablet_proximity_in(dev, 10, 10, axes);
938 litest_drain_events(li);
939
940 litest_axis_set_value(axes, ABS_DISTANCE, 0);
941 litest_axis_set_value(axes, ABS_PRESSURE, 30);
942 litest_tablet_tip_down(dev, 10, 10, axes);
943
944 litest_drain_events(li);
945 litest_delete_device(dev);
946 libinput_dispatch(li);
947
948 event = libinput_get_event(li);
949 tablet_event = litest_is_tablet_event(event,
950 LIBINPUT_EVENT_TABLET_TOOL_TIP);
951 ck_assert_int_eq(libinput_event_tablet_tool_get_tip_state(tablet_event),
952 LIBINPUT_TABLET_TOOL_TIP_UP);
953 libinput_event_destroy(event);
954
955 litest_destroy_context(li);
956 }
957 END_TEST
958
START_TEST(proximity_in_out)959 START_TEST(proximity_in_out)
960 {
961 struct litest_device *dev = litest_current_device();
962 struct libinput *li = dev->libinput;
963 struct libinput_event_tablet_tool *tablet_event;
964 struct libinput_event *event;
965 enum libinput_tablet_tool_type type;
966 bool have_tool_update = false,
967 have_proximity_out = false;
968
969 struct axis_replacement axes[] = {
970 { ABS_DISTANCE, 10 },
971 { ABS_PRESSURE, 0 },
972 { -1, -1 }
973 };
974
975 litest_drain_events(li);
976
977 switch (dev->which) {
978 case LITEST_DELL_CANVAS_TOTEM:
979 type = LIBINPUT_TABLET_TOOL_TYPE_TOTEM;
980 break;
981 default:
982 type = LIBINPUT_TABLET_TOOL_TYPE_PEN;
983 break;
984 }
985
986 litest_tablet_proximity_in(dev, 10, 10, axes);
987 libinput_dispatch(li);
988
989 while ((event = libinput_get_event(li))) {
990 if (libinput_event_get_type(event) ==
991 LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY) {
992 struct libinput_tablet_tool * tool;
993
994 ck_assert(!have_tool_update);
995 have_tool_update = true;
996 tablet_event = libinput_event_get_tablet_tool_event(event);
997 tool = libinput_event_tablet_tool_get_tool(tablet_event);
998 ck_assert_int_eq(libinput_tablet_tool_get_type(tool), type);
999 }
1000 libinput_event_destroy(event);
1001 }
1002 ck_assert(have_tool_update);
1003
1004 litest_tablet_proximity_out(dev);
1005 libinput_dispatch(li);
1006
1007 litest_timeout_tablet_proxout();
1008 libinput_dispatch(li);
1009
1010 while ((event = libinput_get_event(li))) {
1011 if (libinput_event_get_type(event) ==
1012 LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY) {
1013 struct libinput_event_tablet_tool *t =
1014 libinput_event_get_tablet_tool_event(event);
1015
1016 if (libinput_event_tablet_tool_get_proximity_state(t) ==
1017 LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT)
1018 have_proximity_out = true;
1019 }
1020
1021 libinput_event_destroy(event);
1022 }
1023 ck_assert(have_proximity_out);
1024
1025 /* Proximity out must not emit axis events */
1026 litest_assert_empty_queue(li);
1027 }
1028 END_TEST
1029
START_TEST(proximity_in_button_down)1030 START_TEST(proximity_in_button_down)
1031 {
1032 struct litest_device *dev = litest_current_device();
1033 struct libinput *li = dev->libinput;
1034 struct axis_replacement axes[] = {
1035 { ABS_DISTANCE, 10 },
1036 { ABS_PRESSURE, 0 },
1037 { -1, -1 }
1038 };
1039 unsigned int button = pick_stylus_or_btn0(dev);
1040
1041 litest_drain_events(li);
1042
1043 litest_push_event_frame(dev);
1044 litest_tablet_proximity_in(dev, 10, 10, axes);
1045 litest_event(dev, EV_KEY, button, 1);
1046 litest_pop_event_frame(dev);
1047 libinput_dispatch(li);
1048
1049 litest_assert_tablet_proximity_event(li,
1050 LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN);
1051 litest_drain_events_of_type(li, LIBINPUT_EVENT_TABLET_TOOL_TIP, -1);
1052 litest_assert_tablet_button_event(li,
1053 button,
1054 LIBINPUT_BUTTON_STATE_PRESSED);
1055 litest_assert_empty_queue(li);
1056 }
1057 END_TEST
1058
START_TEST(proximity_out_button_up)1059 START_TEST(proximity_out_button_up)
1060 {
1061 struct litest_device *dev = litest_current_device();
1062 struct libinput *li = dev->libinput;
1063 struct axis_replacement axes[] = {
1064 { ABS_DISTANCE, 10 },
1065 { ABS_PRESSURE, 0 },
1066 { -1, -1 }
1067 };
1068 unsigned int button = pick_stylus_or_btn0(dev);
1069
1070 litest_tablet_proximity_in(dev, 10, 10, axes);
1071
1072 litest_button_click(dev, button, true);
1073 litest_drain_events(li);
1074
1075 litest_push_event_frame(dev);
1076 litest_tablet_proximity_out(dev);
1077 litest_event(dev, EV_KEY, button, 0);
1078 litest_pop_event_frame(dev);
1079 libinput_dispatch(li);
1080
1081 litest_timeout_tablet_proxout();
1082 libinput_dispatch(li);
1083
1084 litest_assert_tablet_button_event(li,
1085 button,
1086 LIBINPUT_BUTTON_STATE_RELEASED);
1087 litest_drain_events_of_type(li, LIBINPUT_EVENT_TABLET_TOOL_TIP, -1);
1088 litest_assert_tablet_proximity_event(li,
1089 LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT);
1090 litest_assert_empty_queue(li);
1091 }
1092 END_TEST
1093
START_TEST(proximity_out_clear_buttons)1094 START_TEST(proximity_out_clear_buttons)
1095 {
1096 struct litest_device *dev = litest_current_device();
1097 struct libinput *li = dev->libinput;
1098 struct libinput_event_tablet_tool *tablet_event;
1099 struct libinput_event *event;
1100 uint32_t button;
1101 struct axis_replacement axes[] = {
1102 { ABS_DISTANCE, 10 },
1103 { ABS_PRESSURE, 0 },
1104 { -1, -1 }
1105 };
1106 bool have_proximity = false;
1107 double x = 50, y = 50;
1108
1109 litest_drain_events(li);
1110
1111 /* Test that proximity out events send button releases for any currently
1112 * pressed stylus buttons
1113 */
1114 for (button = BTN_STYLUS; button <= BTN_STYLUS2; button++) {
1115 bool button_released = false;
1116 uint32_t event_button = 0;
1117 enum libinput_button_state state;
1118
1119 if (!libevdev_has_event_code(dev->evdev, EV_KEY, button))
1120 continue;
1121
1122 litest_tablet_proximity_in(dev, x++, y++, axes);
1123 litest_drain_events(li);
1124
1125 litest_event(dev, EV_KEY, button, 1);
1126 litest_event(dev, EV_SYN, SYN_REPORT, 0);
1127 litest_tablet_proximity_out(dev);
1128 libinput_dispatch(li);
1129
1130 event = libinput_get_event(li);
1131 ck_assert_notnull(event);
1132 do {
1133 tablet_event = libinput_event_get_tablet_tool_event(event);
1134
1135 if (libinput_event_get_type(event) ==
1136 LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY) {
1137 have_proximity = true;
1138 libinput_event_destroy(event);
1139 break;
1140 }
1141
1142 if (libinput_event_get_type(event) ==
1143 LIBINPUT_EVENT_TABLET_TOOL_BUTTON) {
1144
1145 event_button = libinput_event_tablet_tool_get_button(tablet_event);
1146 state = libinput_event_tablet_tool_get_button_state(tablet_event);
1147
1148 if (event_button == button &&
1149 state == LIBINPUT_BUTTON_STATE_RELEASED)
1150 button_released = true;
1151 }
1152
1153 libinput_event_destroy(event);
1154 } while ((event = libinput_get_event(li)));
1155
1156 ck_assert_msg(button_released,
1157 "Button %s (%d) was not released.",
1158 libevdev_event_code_get_name(EV_KEY, button),
1159 event_button);
1160 litest_assert(have_proximity);
1161 litest_assert_empty_queue(li);
1162 }
1163 }
1164 END_TEST
1165
START_TEST(proximity_has_axes)1166 START_TEST(proximity_has_axes)
1167 {
1168 struct litest_device *dev = litest_current_device();
1169 struct libinput *li = dev->libinput;
1170 struct libinput_event_tablet_tool *tablet_event;
1171 struct libinput_event *event;
1172 struct libinput_tablet_tool *tool;
1173 double x, y,
1174 distance;
1175 double last_x, last_y,
1176 last_distance = 0.0,
1177 last_tx = 0.0, last_ty = 0.0;
1178
1179 struct axis_replacement axes[] = {
1180 { ABS_DISTANCE, 10 },
1181 { ABS_PRESSURE, 0 },
1182 { ABS_TILT_X, 10 },
1183 { ABS_TILT_Y, 10 },
1184 { -1, -1}
1185 };
1186
1187 litest_drain_events(li);
1188
1189 litest_tablet_proximity_in(dev, 10, 10, axes);
1190 libinput_dispatch(li);
1191
1192 event = libinput_get_event(li);
1193 tablet_event = litest_is_tablet_event(event,
1194 LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
1195 tool = libinput_event_tablet_tool_get_tool(tablet_event);
1196
1197 ck_assert(libinput_event_tablet_tool_x_has_changed(tablet_event));
1198 ck_assert(libinput_event_tablet_tool_y_has_changed(tablet_event));
1199
1200 x = libinput_event_tablet_tool_get_x(tablet_event);
1201 y = libinput_event_tablet_tool_get_y(tablet_event);
1202
1203 litest_assert_double_ne(x, 0);
1204 litest_assert_double_ne(y, 0);
1205
1206 if (libinput_tablet_tool_has_distance(tool)) {
1207 ck_assert(libinput_event_tablet_tool_distance_has_changed(
1208 tablet_event));
1209
1210 distance = libinput_event_tablet_tool_get_distance(tablet_event);
1211 litest_assert_double_ne(distance, 0);
1212 }
1213
1214 if (libinput_tablet_tool_has_tilt(tool)) {
1215 ck_assert(libinput_event_tablet_tool_tilt_x_has_changed(
1216 tablet_event));
1217 ck_assert(libinput_event_tablet_tool_tilt_y_has_changed(
1218 tablet_event));
1219
1220 x = libinput_event_tablet_tool_get_tilt_x(tablet_event);
1221 y = libinput_event_tablet_tool_get_tilt_y(tablet_event);
1222
1223 litest_assert_double_ne(x, 0);
1224 litest_assert_double_ne(y, 0);
1225 }
1226
1227 litest_drain_events_of_type(li, LIBINPUT_EVENT_TABLET_TOOL_TIP, -1);
1228
1229 litest_assert_empty_queue(li);
1230 libinput_event_destroy(event);
1231
1232 litest_axis_set_value(axes, ABS_DISTANCE, 20);
1233 litest_axis_set_value(axes, ABS_TILT_X, 15);
1234 litest_axis_set_value(axes, ABS_TILT_Y, 25);
1235
1236 /* work around axis smoothing */
1237 litest_tablet_motion(dev, 20, 30, axes);
1238 litest_tablet_motion(dev, 20, 29, axes);
1239 litest_tablet_motion(dev, 20, 31, axes);
1240 litest_drain_events(li);
1241
1242 litest_tablet_motion(dev, 20, 30, axes);
1243 libinput_dispatch(li);
1244 event = libinput_get_event(li);
1245 tablet_event = litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_AXIS);
1246
1247 last_x = libinput_event_tablet_tool_get_x(tablet_event);
1248 last_y = libinput_event_tablet_tool_get_y(tablet_event);
1249 if (libinput_tablet_tool_has_distance(tool))
1250 last_distance = libinput_event_tablet_tool_get_distance(
1251 tablet_event);
1252 if (libinput_tablet_tool_has_tilt(tool)) {
1253 last_tx = libinput_event_tablet_tool_get_tilt_x(tablet_event);
1254 last_ty = libinput_event_tablet_tool_get_tilt_y(tablet_event);
1255 }
1256
1257 libinput_event_destroy(event);
1258
1259 /* Make sure that the axes are still present on proximity out */
1260 litest_tablet_proximity_out(dev);
1261 libinput_dispatch(li);
1262
1263 litest_timeout_tablet_proxout();
1264 libinput_dispatch(li);
1265
1266 litest_drain_events_of_type(li, LIBINPUT_EVENT_TABLET_TOOL_TIP, -1);
1267
1268 event = libinput_get_event(li);
1269 tablet_event = litest_is_tablet_event(event,
1270 LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
1271 tool = libinput_event_tablet_tool_get_tool(tablet_event);
1272
1273 ck_assert(!libinput_event_tablet_tool_x_has_changed(tablet_event));
1274 ck_assert(!libinput_event_tablet_tool_y_has_changed(tablet_event));
1275
1276 x = libinput_event_tablet_tool_get_x(tablet_event);
1277 y = libinput_event_tablet_tool_get_y(tablet_event);
1278 litest_assert_double_ge(x, last_x - 1);
1279 litest_assert_double_le(x, last_x + 1);
1280 litest_assert_double_ge(y, last_y - 1);
1281 litest_assert_double_le(y, last_y + 1);
1282
1283 if (libinput_tablet_tool_has_distance(tool)) {
1284 ck_assert(!libinput_event_tablet_tool_distance_has_changed(
1285 tablet_event));
1286
1287 distance = libinput_event_tablet_tool_get_distance(
1288 tablet_event);
1289 litest_assert_double_eq(distance, last_distance);
1290 }
1291
1292 if (libinput_tablet_tool_has_tilt(tool)) {
1293 ck_assert(!libinput_event_tablet_tool_tilt_x_has_changed(
1294 tablet_event));
1295 ck_assert(!libinput_event_tablet_tool_tilt_y_has_changed(
1296 tablet_event));
1297
1298 x = libinput_event_tablet_tool_get_tilt_x(tablet_event);
1299 y = libinput_event_tablet_tool_get_tilt_y(tablet_event);
1300
1301 litest_assert_double_eq(x, last_tx);
1302 litest_assert_double_eq(y, last_ty);
1303 }
1304
1305 litest_assert_empty_queue(li);
1306 libinput_event_destroy(event);
1307 }
1308 END_TEST
1309
START_TEST(proximity_range_enter)1310 START_TEST(proximity_range_enter)
1311 {
1312 struct litest_device *dev = litest_current_device();
1313 struct libinput *li = dev->libinput;
1314 struct axis_replacement axes[] = {
1315 { ABS_DISTANCE, 90 },
1316 { -1, -1 }
1317 };
1318
1319 litest_drain_events(li);
1320
1321 litest_push_event_frame(dev);
1322 litest_filter_event(dev, EV_KEY, BTN_TOOL_PEN);
1323 litest_tablet_proximity_in(dev, 10, 10, axes);
1324 litest_event(dev, EV_KEY, BTN_TOOL_MOUSE, 1);
1325 litest_unfilter_event(dev, EV_KEY, BTN_TOOL_PEN);
1326 litest_pop_event_frame(dev);
1327 litest_assert_empty_queue(li);
1328
1329 litest_axis_set_value(axes, ABS_DISTANCE, 20);
1330 litest_tablet_motion(dev, 10, 10, axes);
1331 libinput_dispatch(li);
1332
1333 litest_assert_tablet_proximity_event(li,
1334 LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN);
1335
1336 litest_axis_set_value(axes, ABS_DISTANCE, 90);
1337 litest_tablet_motion(dev, 10, 10, axes);
1338 libinput_dispatch(li);
1339 litest_assert_tablet_proximity_event(li,
1340 LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT);
1341
1342 litest_push_event_frame(dev);
1343 litest_filter_event(dev, EV_KEY, BTN_TOOL_PEN);
1344 litest_tablet_proximity_out(dev);
1345 litest_event(dev, EV_KEY, BTN_TOOL_MOUSE, 0);
1346 litest_unfilter_event(dev, EV_KEY, BTN_TOOL_PEN);
1347 litest_pop_event_frame(dev);
1348 litest_assert_empty_queue(li);
1349 }
1350 END_TEST
1351
START_TEST(proximity_range_in_out)1352 START_TEST(proximity_range_in_out)
1353 {
1354 struct litest_device *dev = litest_current_device();
1355 struct libinput *li = dev->libinput;
1356 struct axis_replacement axes[] = {
1357 { ABS_DISTANCE, 20 },
1358 { -1, -1 }
1359 };
1360
1361 litest_drain_events(li);
1362
1363 litest_push_event_frame(dev);
1364 litest_filter_event(dev, EV_KEY, BTN_TOOL_PEN);
1365 litest_tablet_proximity_in(dev, 10, 10, axes);
1366 litest_event(dev, EV_KEY, BTN_TOOL_MOUSE, 1);
1367 litest_unfilter_event(dev, EV_KEY, BTN_TOOL_PEN);
1368 litest_pop_event_frame(dev);
1369 libinput_dispatch(li);
1370 litest_assert_tablet_proximity_event(li,
1371 LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN);
1372
1373 litest_axis_set_value(axes, ABS_DISTANCE, 90);
1374 litest_tablet_motion(dev, 10, 10, axes);
1375 libinput_dispatch(li);
1376 litest_assert_tablet_proximity_event(li,
1377 LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT);
1378
1379 litest_tablet_motion(dev, 30, 30, axes);
1380 litest_assert_empty_queue(li);
1381
1382 litest_axis_set_value(axes, ABS_DISTANCE, 20);
1383 litest_tablet_motion(dev, 10, 10, axes);
1384 libinput_dispatch(li);
1385 litest_assert_tablet_proximity_event(li,
1386 LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN);
1387
1388 litest_push_event_frame(dev);
1389 litest_filter_event(dev, EV_KEY, BTN_TOOL_PEN);
1390 litest_tablet_proximity_out(dev);
1391 litest_event(dev, EV_KEY, BTN_TOOL_MOUSE, 0);
1392 litest_unfilter_event(dev, EV_KEY, BTN_TOOL_PEN);
1393 litest_pop_event_frame(dev);
1394 litest_assert_tablet_proximity_event(li,
1395 LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT);
1396 litest_assert_empty_queue(li);
1397 }
1398 END_TEST
1399
START_TEST(proximity_range_button_click)1400 START_TEST(proximity_range_button_click)
1401 {
1402 struct litest_device *dev = litest_current_device();
1403 struct libinput *li = dev->libinput;
1404 struct axis_replacement axes[] = {
1405 { ABS_DISTANCE, 90 },
1406 { -1, -1 }
1407 };
1408
1409 litest_drain_events(li);
1410
1411 litest_push_event_frame(dev);
1412 litest_filter_event(dev, EV_KEY, BTN_TOOL_PEN);
1413 litest_tablet_proximity_in(dev, 10, 10, axes);
1414 litest_event(dev, EV_KEY, BTN_TOOL_MOUSE, 1);
1415 litest_unfilter_event(dev, EV_KEY, BTN_TOOL_PEN);
1416 litest_pop_event_frame(dev);
1417 litest_drain_events(li);
1418
1419 litest_event(dev, EV_KEY, BTN_STYLUS, 1);
1420 litest_event(dev, EV_SYN, SYN_REPORT, 0);
1421 libinput_dispatch(li);
1422 litest_event(dev, EV_KEY, BTN_STYLUS, 0);
1423 litest_event(dev, EV_SYN, SYN_REPORT, 0);
1424 libinput_dispatch(li);
1425
1426 litest_push_event_frame(dev);
1427 litest_filter_event(dev, EV_KEY, BTN_TOOL_PEN);
1428 litest_tablet_proximity_out(dev);
1429 litest_event(dev, EV_KEY, BTN_TOOL_MOUSE, 0);
1430 litest_unfilter_event(dev, EV_KEY, BTN_TOOL_PEN);
1431 litest_pop_event_frame(dev);
1432 litest_assert_empty_queue(li);
1433 }
1434 END_TEST
1435
START_TEST(proximity_range_button_press)1436 START_TEST(proximity_range_button_press)
1437 {
1438 struct litest_device *dev = litest_current_device();
1439 struct libinput *li = dev->libinput;
1440 struct axis_replacement axes[] = {
1441 { ABS_DISTANCE, 20 },
1442 { -1, -1 }
1443 };
1444
1445 litest_push_event_frame(dev);
1446 litest_filter_event(dev, EV_KEY, BTN_TOOL_PEN);
1447 litest_tablet_proximity_in(dev, 10, 10, axes);
1448 litest_event(dev, EV_KEY, BTN_TOOL_MOUSE, 1);
1449 litest_unfilter_event(dev, EV_KEY, BTN_TOOL_PEN);
1450 litest_pop_event_frame(dev);
1451 litest_drain_events(li);
1452
1453 litest_event(dev, EV_KEY, BTN_STYLUS, 1);
1454 litest_event(dev, EV_SYN, SYN_REPORT, 0);
1455 libinput_dispatch(li);
1456
1457 litest_assert_tablet_button_event(li,
1458 BTN_STYLUS,
1459 LIBINPUT_BUTTON_STATE_PRESSED);
1460
1461 litest_axis_set_value(axes, ABS_DISTANCE, 90);
1462 litest_tablet_motion(dev, 15, 15, axes);
1463 libinput_dispatch(li);
1464
1465 /* expect fake button release */
1466 litest_assert_tablet_button_event(li,
1467 BTN_STYLUS,
1468 LIBINPUT_BUTTON_STATE_RELEASED);
1469 litest_assert_tablet_proximity_event(li,
1470 LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT);
1471
1472 litest_event(dev, EV_KEY, BTN_STYLUS, 0);
1473 litest_event(dev, EV_SYN, SYN_REPORT, 0);
1474 libinput_dispatch(li);
1475
1476 litest_push_event_frame(dev);
1477 litest_filter_event(dev, EV_KEY, BTN_TOOL_PEN);
1478 litest_tablet_proximity_out(dev);
1479 litest_event(dev, EV_KEY, BTN_TOOL_MOUSE, 0);
1480 litest_unfilter_event(dev, EV_KEY, BTN_TOOL_PEN);
1481 litest_pop_event_frame(dev);
1482 litest_assert_empty_queue(li);
1483 }
1484 END_TEST
1485
START_TEST(proximity_range_button_release)1486 START_TEST(proximity_range_button_release)
1487 {
1488 struct litest_device *dev = litest_current_device();
1489 struct libinput *li = dev->libinput;
1490 struct axis_replacement axes[] = {
1491 { ABS_DISTANCE, 90 },
1492 { -1, -1 }
1493 };
1494
1495 litest_push_event_frame(dev);
1496 litest_filter_event(dev, EV_KEY, BTN_TOOL_PEN);
1497 litest_tablet_proximity_in(dev, 10, 10, axes);
1498 litest_event(dev, EV_KEY, BTN_TOOL_MOUSE, 1);
1499 litest_unfilter_event(dev, EV_KEY, BTN_TOOL_PEN);
1500 litest_pop_event_frame(dev);
1501 litest_drain_events(li);
1502
1503 litest_event(dev, EV_KEY, BTN_STYLUS, 1);
1504 litest_event(dev, EV_SYN, SYN_REPORT, 0);
1505 litest_assert_empty_queue(li);
1506
1507 litest_axis_set_value(axes, ABS_DISTANCE, 20);
1508 litest_tablet_motion(dev, 15, 15, axes);
1509 libinput_dispatch(li);
1510
1511 litest_assert_tablet_proximity_event(li,
1512 LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN);
1513 /* expect fake button press */
1514 litest_assert_tablet_button_event(li,
1515 BTN_STYLUS,
1516 LIBINPUT_BUTTON_STATE_PRESSED);
1517 litest_assert_empty_queue(li);
1518
1519 litest_event(dev, EV_KEY, BTN_STYLUS, 0);
1520 litest_event(dev, EV_SYN, SYN_REPORT, 0);
1521 libinput_dispatch(li);
1522 litest_assert_tablet_button_event(li,
1523 BTN_STYLUS,
1524 LIBINPUT_BUTTON_STATE_RELEASED);
1525
1526 litest_push_event_frame(dev);
1527 litest_filter_event(dev, EV_KEY, BTN_TOOL_PEN);
1528 litest_tablet_proximity_out(dev);
1529 litest_event(dev, EV_KEY, BTN_TOOL_MOUSE, 0);
1530 litest_unfilter_event(dev, EV_KEY, BTN_TOOL_PEN);
1531 litest_pop_event_frame(dev);
1532 litest_assert_tablet_proximity_event(li,
1533 LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT);
1534 }
1535 END_TEST
1536
START_TEST(proximity_out_slow_event)1537 START_TEST(proximity_out_slow_event)
1538 {
1539 struct litest_device *dev = litest_current_device();
1540 struct libinput *li = dev->libinput;
1541 struct axis_replacement axes[] = {
1542 { ABS_DISTANCE, 90 },
1543 { -1, -1 }
1544 };
1545
1546 litest_tablet_proximity_in(dev, 10, 10, axes);
1547 litest_tablet_motion(dev, 12, 12, axes);
1548 litest_drain_events(li);
1549
1550 litest_timeout_tablet_proxout();
1551 libinput_dispatch(li);
1552
1553 /* The forced prox out */
1554 litest_assert_tablet_proximity_event(li,
1555 LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT);
1556 litest_assert_empty_queue(li);
1557
1558 litest_tablet_proximity_out(dev);
1559 litest_assert_empty_queue(li);
1560 }
1561 END_TEST
1562
START_TEST(proximity_out_not_during_contact)1563 START_TEST(proximity_out_not_during_contact)
1564 {
1565 struct litest_device *dev = litest_current_device();
1566 struct libinput *li = dev->libinput;
1567 struct axis_replacement axes[] = {
1568 { ABS_DISTANCE, 0 },
1569 { ABS_PRESSURE, 10 },
1570 { -1, -1 }
1571 };
1572
1573 litest_tablet_proximity_in(dev, 10, 10, axes);
1574 litest_tablet_motion(dev, 12, 12, axes);
1575 litest_drain_events(li);
1576
1577 litest_timeout_tablet_proxout();
1578 libinput_dispatch(li);
1579
1580 /* No forced proxout yet */
1581 litest_assert_empty_queue(li);
1582
1583 litest_axis_set_value(axes, ABS_PRESSURE, 0);
1584 litest_tablet_motion(dev, 14, 14, axes);
1585 litest_drain_events(li);
1586
1587 litest_timeout_tablet_proxout();
1588 libinput_dispatch(li);
1589
1590 /* The forced prox out */
1591 litest_assert_tablet_proximity_event(li,
1592 LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT);
1593
1594 litest_tablet_proximity_out(dev);
1595 litest_assert_empty_queue(li);
1596 }
1597 END_TEST
1598
START_TEST(proximity_out_not_during_buttonpress)1599 START_TEST(proximity_out_not_during_buttonpress)
1600 {
1601 struct litest_device *dev = litest_current_device();
1602 struct libinput *li = dev->libinput;
1603 struct axis_replacement axes[] = {
1604 { ABS_DISTANCE, 10 },
1605 { ABS_PRESSURE, 0 },
1606 { -1, -1 }
1607 };
1608
1609 litest_tablet_proximity_in(dev, 10, 10, axes);
1610 litest_tablet_motion(dev, 12, 12, axes);
1611 litest_drain_events(li);
1612
1613 litest_event(dev, EV_KEY, BTN_STYLUS, 1);
1614 litest_event(dev, EV_SYN, SYN_REPORT, 0);
1615 libinput_dispatch(li);
1616
1617 litest_assert_only_typed_events(li, LIBINPUT_EVENT_TABLET_TOOL_BUTTON);
1618
1619 litest_timeout_tablet_proxout();
1620 libinput_dispatch(li);
1621
1622 /* No forced proxout yet */
1623 litest_assert_empty_queue(li);
1624
1625 litest_event(dev, EV_KEY, BTN_STYLUS, 0);
1626 litest_event(dev, EV_SYN, SYN_REPORT, 0);
1627 libinput_dispatch(li);
1628
1629 litest_assert_only_typed_events(li, LIBINPUT_EVENT_TABLET_TOOL_BUTTON);
1630
1631 litest_timeout_tablet_proxout();
1632 libinput_dispatch(li);
1633
1634 /* The forced prox out */
1635 litest_assert_tablet_proximity_event(li,
1636 LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT);
1637
1638 litest_tablet_proximity_out(dev);
1639 litest_assert_empty_queue(li);
1640 }
1641 END_TEST
1642
START_TEST(proximity_out_disables_forced)1643 START_TEST(proximity_out_disables_forced)
1644 {
1645 struct litest_device *dev = litest_current_device();
1646 struct libinput *li = dev->libinput;
1647 struct axis_replacement axes[] = {
1648 { ABS_DISTANCE, 10 },
1649 { ABS_PRESSURE, 0 },
1650 { -1, -1 }
1651 };
1652
1653 /* A correct proximity out sequence from the device should disable
1654 the forced proximity out */
1655 litest_tablet_proximity_in(dev, 10, 10, axes);
1656 litest_tablet_proximity_out(dev);
1657 litest_drain_events(li);
1658
1659 /* expect no timeout-based prox out */
1660 litest_tablet_proximity_in(dev, 10, 10, axes);
1661 litest_drain_events(li);
1662
1663 litest_timeout_tablet_proxout();
1664 libinput_dispatch(li);
1665
1666 litest_assert_empty_queue(li);
1667 litest_tablet_proximity_out(dev);
1668 litest_assert_tablet_proximity_event(li,
1669 LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT);
1670 libinput_dispatch(li);
1671 }
1672 END_TEST
1673
START_TEST(proximity_out_disables_forced_after_forced)1674 START_TEST(proximity_out_disables_forced_after_forced)
1675 {
1676 struct litest_device *dev = litest_current_device();
1677 struct libinput *li = dev->libinput;
1678 struct axis_replacement axes[] = {
1679 { ABS_DISTANCE, 10 },
1680 { ABS_PRESSURE, 0 },
1681 { -1, -1 }
1682 };
1683
1684 /* A correct proximity out sequence from the device should disable
1685 the forced proximity out, even when we had a forced prox-out */
1686 litest_tablet_proximity_in(dev, 10, 10, axes);
1687 litest_drain_events(li);
1688
1689 /* timeout-based forced prox out */
1690 litest_timeout_tablet_proxout();
1691 libinput_dispatch(li);
1692 litest_assert_tablet_proximity_event(li,
1693 LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT);
1694 litest_assert_empty_queue(li);
1695
1696 /* now send the real prox out (we're already in proximity out) and
1697 * that should disable the proxout quirk */
1698 litest_tablet_proximity_out(dev);
1699 libinput_dispatch(li);
1700 litest_assert_empty_queue(li);
1701
1702 /* same again, but this time we expect no timeout-based prox out */
1703 litest_tablet_proximity_in(dev, 10, 10, axes);
1704 litest_drain_events(li);
1705
1706 litest_timeout_tablet_proxout();
1707 libinput_dispatch(li);
1708
1709 litest_assert_empty_queue(li);
1710 litest_tablet_proximity_out(dev);
1711 litest_assert_tablet_proximity_event(li,
1712 LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT);
1713 libinput_dispatch(li);
1714 }
1715 END_TEST
1716
START_TEST(proximity_out_on_delete)1717 START_TEST(proximity_out_on_delete)
1718 {
1719 struct libinput *li = litest_create_context();
1720 struct litest_device *dev = litest_add_device(li, LITEST_WACOM_INTUOS);
1721
1722 litest_tablet_proximity_in(dev, 10, 10, NULL);
1723 litest_drain_events(li);
1724
1725 litest_delete_device(dev);
1726 libinput_dispatch(li);
1727
1728 litest_assert_tablet_proximity_event(li,
1729 LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT);
1730 litest_destroy_context(li);
1731 }
1732 END_TEST
1733
START_TEST(motion)1734 START_TEST(motion)
1735 {
1736 struct litest_device *dev = litest_current_device();
1737 struct libinput *li = dev->libinput;
1738 struct libinput_event_tablet_tool *tablet_event;
1739 struct libinput_event *event;
1740 int test_x, test_y;
1741 double last_reported_x = 0, last_reported_y = 0;
1742 enum libinput_event_type type;
1743 struct axis_replacement axes[] = {
1744 { ABS_DISTANCE, 10 },
1745 { ABS_PRESSURE, 0 },
1746 { -1, -1 }
1747 };
1748 bool x_changed, y_changed;
1749 double reported_x, reported_y;
1750
1751 litest_drain_events(li);
1752
1753 litest_tablet_proximity_in(dev, 5, 100, axes);
1754 libinput_dispatch(li);
1755
1756 event = libinput_get_event(li);
1757 tablet_event = litest_is_tablet_event(event,
1758 LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
1759 x_changed = libinput_event_tablet_tool_x_has_changed(tablet_event);
1760 y_changed = libinput_event_tablet_tool_y_has_changed(tablet_event);
1761 ck_assert(x_changed);
1762 ck_assert(y_changed);
1763
1764 reported_x = libinput_event_tablet_tool_get_x(tablet_event);
1765 reported_y = libinput_event_tablet_tool_get_y(tablet_event);
1766
1767 litest_assert_double_lt(reported_x, reported_y);
1768
1769 last_reported_x = reported_x;
1770 last_reported_y = reported_y;
1771
1772 libinput_event_destroy(event);
1773
1774 for (test_x = 10, test_y = 90;
1775 test_x <= 100;
1776 test_x += 10, test_y -= 10) {
1777 bool x_changed, y_changed;
1778 double reported_x, reported_y;
1779
1780 litest_tablet_motion(dev, test_x, test_y, axes);
1781 libinput_dispatch(li);
1782
1783 while ((event = libinput_get_event(li))) {
1784 tablet_event = libinput_event_get_tablet_tool_event(event);
1785 type = libinput_event_get_type(event);
1786
1787 if (type == LIBINPUT_EVENT_TABLET_TOOL_AXIS) {
1788 x_changed = libinput_event_tablet_tool_x_has_changed(
1789 tablet_event);
1790 y_changed = libinput_event_tablet_tool_y_has_changed(
1791 tablet_event);
1792
1793 ck_assert(x_changed);
1794 ck_assert(y_changed);
1795
1796 reported_x = libinput_event_tablet_tool_get_x(
1797 tablet_event);
1798 reported_y = libinput_event_tablet_tool_get_y(
1799 tablet_event);
1800
1801 litest_assert_double_gt(reported_x,
1802 last_reported_x);
1803 litest_assert_double_lt(reported_y,
1804 last_reported_y);
1805
1806 last_reported_x = reported_x;
1807 last_reported_y = reported_y;
1808 }
1809
1810 libinput_event_destroy(event);
1811 }
1812 }
1813 }
1814 END_TEST
1815
START_TEST(left_handed)1816 START_TEST(left_handed)
1817 {
1818 #if HAVE_LIBWACOM
1819 struct litest_device *dev = litest_current_device();
1820 struct libinput *li = dev->libinput;
1821 struct libinput_event *event;
1822 struct libinput_event_tablet_tool *tablet_event;
1823 double libinput_max_x, libinput_max_y;
1824 double last_x = -1.0, last_y = -1.0;
1825 double x, y;
1826 struct axis_replacement axes[] = {
1827 { ABS_DISTANCE, 10 },
1828 { ABS_PRESSURE, 0 },
1829 { -1, -1 }
1830 };
1831
1832 litest_drain_events(li);
1833
1834 ck_assert(libinput_device_config_left_handed_is_available(dev->libinput_device));
1835
1836 libinput_device_get_size (dev->libinput_device,
1837 &libinput_max_x,
1838 &libinput_max_y);
1839
1840 /* Test that left-handed mode doesn't go into effect until the tool has
1841 * left proximity of the tablet. In order to test this, we have to bring
1842 * the tool into proximity and make sure libinput processes the
1843 * proximity events so that it updates it's internal tablet state, and
1844 * then try setting it to left-handed mode. */
1845 litest_tablet_proximity_in(dev, 0, 100, axes);
1846 libinput_dispatch(li);
1847 libinput_device_config_left_handed_set(dev->libinput_device, 1);
1848
1849 event = libinput_get_event(li);
1850 tablet_event = litest_is_tablet_event(event,
1851 LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
1852
1853 last_x = libinput_event_tablet_tool_get_x(tablet_event);
1854 last_y = libinput_event_tablet_tool_get_y(tablet_event);
1855
1856 litest_assert_double_eq(last_x, 0);
1857 litest_assert_double_eq(last_y, libinput_max_y);
1858
1859 libinput_event_destroy(event);
1860
1861 /* work around smoothing */
1862 litest_axis_set_value(axes, ABS_DISTANCE, 9);
1863 litest_tablet_motion(dev, 100, 0, axes);
1864 litest_axis_set_value(axes, ABS_DISTANCE, 7);
1865 litest_tablet_motion(dev, 100, 0, axes);
1866 litest_axis_set_value(axes, ABS_DISTANCE, 10);
1867 litest_tablet_motion(dev, 100, 0, axes);
1868 litest_drain_events(li);
1869
1870 litest_axis_set_value(axes, ABS_DISTANCE, 5);
1871 litest_tablet_motion(dev, 100, 0, axes);
1872 libinput_dispatch(li);
1873
1874 event = libinput_get_event(li);
1875 tablet_event = litest_is_tablet_event(event,
1876 LIBINPUT_EVENT_TABLET_TOOL_AXIS);
1877
1878 x = libinput_event_tablet_tool_get_x(tablet_event);
1879 y = libinput_event_tablet_tool_get_y(tablet_event);
1880
1881 litest_assert_double_eq(x, libinput_max_x);
1882 litest_assert_double_eq(y, 0);
1883
1884 litest_assert_double_gt(x, last_x);
1885 litest_assert_double_lt(y, last_y);
1886
1887 libinput_event_destroy(event);
1888
1889 litest_tablet_proximity_out(dev);
1890 litest_drain_events(li);
1891
1892 /* Since we've drained the events and libinput's aware the tool is out
1893 * of proximity, it should have finally transitioned into left-handed
1894 * mode, so the axes should be inverted once we bring it back into
1895 * proximity */
1896 litest_tablet_proximity_in(dev, 0, 100, axes);
1897 libinput_dispatch(li);
1898
1899 event = libinput_get_event(li);
1900 tablet_event = litest_is_tablet_event(event,
1901 LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
1902
1903 last_x = libinput_event_tablet_tool_get_x(tablet_event);
1904 last_y = libinput_event_tablet_tool_get_y(tablet_event);
1905
1906 litest_assert_double_eq(last_x, libinput_max_x);
1907 litest_assert_double_eq(last_y, 0);
1908
1909 libinput_event_destroy(event);
1910
1911 /* work around smoothing */
1912 litest_axis_set_value(axes, ABS_DISTANCE, 9);
1913 litest_tablet_motion(dev, 100, 0, axes);
1914 litest_axis_set_value(axes, ABS_DISTANCE, 7);
1915 litest_tablet_motion(dev, 100, 0, axes);
1916 litest_axis_set_value(axes, ABS_DISTANCE, 10);
1917 litest_tablet_motion(dev, 100, 0, axes);
1918 litest_drain_events(li);
1919
1920 litest_axis_set_value(axes, ABS_DISTANCE, 5);
1921 litest_tablet_motion(dev, 100, 0, axes);
1922 libinput_dispatch(li);
1923
1924 event = libinput_get_event(li);
1925 tablet_event = litest_is_tablet_event(event,
1926 LIBINPUT_EVENT_TABLET_TOOL_AXIS);
1927
1928 x = libinput_event_tablet_tool_get_x(tablet_event);
1929 y = libinput_event_tablet_tool_get_y(tablet_event);
1930
1931 litest_assert_double_eq(x, 0);
1932 litest_assert_double_eq(y, libinput_max_y);
1933
1934 litest_assert_double_lt(x, last_x);
1935 litest_assert_double_gt(y, last_y);
1936
1937 libinput_event_destroy(event);
1938 #endif
1939 }
1940 END_TEST
1941
START_TEST(no_left_handed)1942 START_TEST(no_left_handed)
1943 {
1944 struct litest_device *dev = litest_current_device();
1945
1946 /* Without libwacom we default to left-handed being available */
1947 #if HAVE_LIBWACOM
1948 ck_assert(!libinput_device_config_left_handed_is_available(dev->libinput_device));
1949 #else
1950 ck_assert(libinput_device_config_left_handed_is_available(dev->libinput_device));
1951 #endif
1952 }
1953 END_TEST
1954
START_TEST(left_handed_tilt)1955 START_TEST(left_handed_tilt)
1956 {
1957 #if HAVE_LIBWACOM
1958 struct litest_device *dev = litest_current_device();
1959 struct libinput *li = dev->libinput;
1960 struct libinput_event *event;
1961 struct libinput_event_tablet_tool *tev;
1962 enum libinput_config_status status;
1963 struct axis_replacement axes[] = {
1964 { ABS_DISTANCE, 10 },
1965 { ABS_PRESSURE, 0 },
1966 { ABS_TILT_X, 90 },
1967 { ABS_TILT_Y, 10 },
1968 { -1, -1 }
1969 };
1970 double tx, ty;
1971
1972 status = libinput_device_config_left_handed_set(dev->libinput_device, 1);
1973 ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
1974
1975 litest_drain_events(li);
1976
1977 litest_tablet_proximity_in(dev, 10, 10, axes);
1978 libinput_dispatch(li);
1979 event = libinput_get_event(li);
1980 tev = litest_is_tablet_event(event,
1981 LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
1982 tx = libinput_event_tablet_tool_get_tilt_x(tev);
1983 ty = libinput_event_tablet_tool_get_tilt_y(tev);
1984
1985 ck_assert_double_lt(tx, 0);
1986 ck_assert_double_gt(ty, 0);
1987
1988 libinput_event_destroy(event);
1989 #endif
1990 }
1991 END_TEST
1992
1993 static inline double
rotate_event(struct litest_device * dev,int angle_degrees)1994 rotate_event(struct litest_device *dev, int angle_degrees)
1995 {
1996 struct libinput *li = dev->libinput;
1997 struct libinput_event *event;
1998 struct libinput_event_tablet_tool *tev;
1999 const struct input_absinfo *abs;
2000 double a = (angle_degrees - 90 - 175)/180.0 * M_PI;
2001 double val;
2002 int x, y;
2003 int tilt_center_x, tilt_center_y;
2004
2005 abs = libevdev_get_abs_info(dev->evdev, ABS_TILT_X);
2006 ck_assert_notnull(abs);
2007 tilt_center_x = absinfo_range(abs) / 2;
2008
2009 abs = libevdev_get_abs_info(dev->evdev, ABS_TILT_Y);
2010 ck_assert_notnull(abs);
2011 tilt_center_y = absinfo_range(abs) / 2;
2012
2013 x = cos(a) * 20 + tilt_center_x;
2014 y = sin(a) * 20 + tilt_center_y;
2015
2016 litest_event(dev, EV_ABS, ABS_TILT_X, x);
2017 litest_event(dev, EV_ABS, ABS_TILT_Y, y);
2018 litest_event(dev, EV_SYN, SYN_REPORT, 0);
2019 libinput_dispatch(li);
2020
2021 event = libinput_get_event(li);
2022 tev = litest_is_tablet_event(event,
2023 LIBINPUT_EVENT_TABLET_TOOL_AXIS);
2024 ck_assert(libinput_event_tablet_tool_rotation_has_changed(tev));
2025 val = libinput_event_tablet_tool_get_rotation(tev);
2026
2027 libinput_event_destroy(event);
2028 litest_assert_empty_queue(li);
2029
2030 return val;
2031 }
2032
START_TEST(left_handed_mouse_rotation)2033 START_TEST(left_handed_mouse_rotation)
2034 {
2035 #if HAVE_LIBWACOM
2036 struct litest_device *dev = litest_current_device();
2037 struct libinput *li = dev->libinput;
2038 enum libinput_config_status status;
2039 int angle;
2040 double val, old_val = 0;
2041 struct axis_replacement axes[] = {
2042 { ABS_DISTANCE, 10 },
2043 { ABS_PRESSURE, 0 },
2044 { ABS_TILT_X, 0 },
2045 { ABS_TILT_Y, 0 },
2046 { -1, -1 }
2047 };
2048
2049 status = libinput_device_config_left_handed_set(dev->libinput_device, 1);
2050 ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
2051
2052 litest_drain_events(li);
2053
2054 litest_push_event_frame(dev);
2055 litest_filter_event(dev, EV_KEY, BTN_TOOL_PEN);
2056 litest_tablet_proximity_in(dev, 10, 10, axes);
2057 litest_event(dev, EV_KEY, BTN_TOOL_MOUSE, 1);
2058 litest_unfilter_event(dev, EV_KEY, BTN_TOOL_PEN);
2059 litest_pop_event_frame(dev);
2060
2061 litest_drain_events(li);
2062
2063 /* cos/sin are 90 degrees offset from the north-is-zero that
2064 libinput uses. 175 is the CCW offset in the mouse HW */
2065 for (angle = 185; angle < 540; angle += 5) {
2066 int expected_angle = angle - 180;
2067
2068 val = rotate_event(dev, angle % 360);
2069
2070 /* rounding error galore, we can't test for anything more
2071 precise than these */
2072 litest_assert_double_lt(val, 360.0);
2073 litest_assert_double_gt(val, old_val);
2074 litest_assert_double_lt(val, expected_angle + 5);
2075
2076 old_val = val;
2077 }
2078 #endif
2079 }
2080 END_TEST
2081
START_TEST(left_handed_artpen_rotation)2082 START_TEST(left_handed_artpen_rotation)
2083 {
2084 #if HAVE_LIBWACOM
2085 struct litest_device *dev = litest_current_device();
2086 struct libinput *li = dev->libinput;
2087 struct libinput_event *event;
2088 struct libinput_event_tablet_tool *tev;
2089 const struct input_absinfo *abs;
2090 enum libinput_config_status status;
2091 double val;
2092 double scale;
2093 int angle;
2094
2095 if (!libevdev_has_event_code(dev->evdev,
2096 EV_ABS,
2097 ABS_Z))
2098 return;
2099
2100 status = libinput_device_config_left_handed_set(dev->libinput_device, 1);
2101 ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
2102
2103 litest_drain_events(li);
2104
2105 abs = libevdev_get_abs_info(dev->evdev, ABS_Z);
2106 ck_assert_notnull(abs);
2107 scale = absinfo_range(abs)/360.0;
2108
2109 litest_event(dev, EV_KEY, BTN_TOOL_BRUSH, 1);
2110 litest_event(dev, EV_ABS, ABS_MISC, 0x804); /* Art Pen */
2111 litest_event(dev, EV_MSC, MSC_SERIAL, 1000);
2112 litest_event(dev, EV_SYN, SYN_REPORT, 0);
2113
2114 litest_event(dev, EV_ABS, ABS_Z, abs->minimum);
2115 litest_event(dev, EV_SYN, SYN_REPORT, 0);
2116
2117 litest_drain_events(li);
2118
2119 for (angle = 188; angle < 540; angle += 8) {
2120 int a = angle * scale + abs->minimum;
2121 int expected_angle = angle - 180;
2122
2123 litest_event(dev, EV_ABS, ABS_Z, a);
2124 litest_event(dev, EV_SYN, SYN_REPORT, 0);
2125 libinput_dispatch(li);
2126 event = libinput_get_event(li);
2127 tev = litest_is_tablet_event(event,
2128 LIBINPUT_EVENT_TABLET_TOOL_AXIS);
2129 ck_assert(libinput_event_tablet_tool_rotation_has_changed(tev));
2130 val = libinput_event_tablet_tool_get_rotation(tev);
2131
2132 /* artpen has a 90 deg offset cw */
2133 ck_assert_int_eq(round(val), (expected_angle + 90) % 360);
2134
2135 libinput_event_destroy(event);
2136 litest_assert_empty_queue(li);
2137
2138 }
2139 #endif
2140 }
2141 END_TEST
2142
START_TEST(motion_event_state)2143 START_TEST(motion_event_state)
2144 {
2145 struct litest_device *dev = litest_current_device();
2146 struct libinput *li = dev->libinput;
2147 struct libinput_event *event;
2148 struct libinput_event_tablet_tool *tablet_event;
2149 int test_x, test_y;
2150 double last_x, last_y;
2151 struct axis_replacement axes[] = {
2152 { ABS_DISTANCE, 10 },
2153 { ABS_PRESSURE, 0 },
2154 { -1, -1 }
2155 };
2156 unsigned int button = pick_stylus_or_btn0(dev);
2157
2158 litest_drain_events(li);
2159 litest_tablet_proximity_in(dev, 5, 100, axes);
2160 litest_drain_events(li);
2161
2162 /* couple of events that go left/bottom to right/top */
2163 for (test_x = 0, test_y = 100; test_x < 100; test_x += 10, test_y -= 10)
2164 litest_tablet_motion(dev, test_x, test_y, axes);
2165
2166 libinput_dispatch(li);
2167
2168 event = libinput_get_event(li);
2169 tablet_event = litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_AXIS);
2170
2171 last_x = libinput_event_tablet_tool_get_x(tablet_event);
2172 last_y = libinput_event_tablet_tool_get_y(tablet_event);
2173
2174 /* mark with a button event, then go back to bottom/left */
2175 litest_button_click(dev, button, true);
2176
2177 for (test_x = 100, test_y = 0; test_x > 0; test_x -= 10, test_y += 10)
2178 litest_tablet_motion(dev, test_x, test_y, axes);
2179
2180 libinput_event_destroy(event);
2181 libinput_dispatch(li);
2182 ck_assert_int_eq(libinput_next_event_type(li),
2183 LIBINPUT_EVENT_TABLET_TOOL_AXIS);
2184
2185 /* we expect all events up to the button event to go from
2186 bottom/left to top/right */
2187 while ((event = libinput_get_event(li))) {
2188 double x, y;
2189
2190 if (libinput_event_get_type(event) != LIBINPUT_EVENT_TABLET_TOOL_AXIS)
2191 break;
2192
2193 tablet_event = libinput_event_get_tablet_tool_event(event);
2194 ck_assert_notnull(tablet_event);
2195
2196 x = libinput_event_tablet_tool_get_x(tablet_event);
2197 y = libinput_event_tablet_tool_get_y(tablet_event);
2198
2199 ck_assert(x > last_x);
2200 ck_assert(y < last_y);
2201
2202 last_x = x;
2203 last_y = y;
2204 libinput_event_destroy(event);
2205 }
2206
2207 ck_assert_int_eq(libinput_event_get_type(event),
2208 LIBINPUT_EVENT_TABLET_TOOL_BUTTON);
2209 libinput_event_destroy(event);
2210 }
2211 END_TEST
2212
START_TEST(motion_outside_bounds)2213 START_TEST(motion_outside_bounds)
2214 {
2215 struct litest_device *dev = litest_current_device();
2216 struct libinput *li = dev->libinput;
2217 struct libinput_event *event;
2218 struct libinput_event_tablet_tool *tablet_event;
2219 double val;
2220 int i;
2221
2222 struct axis_replacement axes[] = {
2223 { ABS_DISTANCE, 10 },
2224 { ABS_PRESSURE, 0 },
2225 { -1, -1 }
2226 };
2227
2228 litest_tablet_proximity_in(dev, 50, 50, axes);
2229 litest_drain_events(li);
2230
2231 /* Work around smoothing */
2232 for (i = 5; i > 0; i--) {
2233 litest_event(dev, EV_ABS, ABS_X, 0 + 5 * i);
2234 litest_event(dev, EV_ABS, ABS_Y, 1000);
2235 litest_event(dev, EV_SYN, SYN_REPORT, 0);
2236 libinput_dispatch(li);
2237 }
2238 litest_drain_events(li);
2239
2240 /* On the 24HD x/y of 0 is outside the limit */
2241 litest_event(dev, EV_ABS, ABS_X, 0);
2242 litest_event(dev, EV_ABS, ABS_Y, 1000);
2243 litest_event(dev, EV_SYN, SYN_REPORT, 0);
2244 libinput_dispatch(li);
2245
2246 event = libinput_get_event(li);
2247 tablet_event = litest_is_tablet_event(event,
2248 LIBINPUT_EVENT_TABLET_TOOL_AXIS);
2249 val = libinput_event_tablet_tool_get_x(tablet_event);
2250 ck_assert_double_lt(val, 0.0);
2251 val = libinput_event_tablet_tool_get_y(tablet_event);
2252 ck_assert_double_gt(val, 0.0);
2253
2254 val = libinput_event_tablet_tool_get_x_transformed(tablet_event, 100);
2255 ck_assert_double_lt(val, 0.0);
2256
2257 libinput_event_destroy(event);
2258
2259 /* Work around smoothing */
2260 for (i = 5; i > 0; i--) {
2261 litest_event(dev, EV_ABS, ABS_X, 1000);
2262 litest_event(dev, EV_ABS, ABS_Y, 0 + 5 * i);
2263 litest_event(dev, EV_SYN, SYN_REPORT, 0);
2264 libinput_dispatch(li);
2265 }
2266 litest_drain_events(li);
2267
2268 /* On the 24HD x/y of 0 is outside the limit */
2269 litest_event(dev, EV_ABS, ABS_X, 1000);
2270 litest_event(dev, EV_ABS, ABS_Y, 0);
2271 litest_event(dev, EV_SYN, SYN_REPORT, 0);
2272 libinput_dispatch(li);
2273
2274 event = libinput_get_event(li);
2275 tablet_event = litest_is_tablet_event(event,
2276 LIBINPUT_EVENT_TABLET_TOOL_AXIS);
2277 val = libinput_event_tablet_tool_get_x(tablet_event);
2278 ck_assert_double_gt(val, 0.0);
2279 val = libinput_event_tablet_tool_get_y(tablet_event);
2280 ck_assert_double_lt(val, 0.0);
2281
2282 val = libinput_event_tablet_tool_get_y_transformed(tablet_event, 100);
2283 ck_assert_double_lt(val, 0.0);
2284
2285 libinput_event_destroy(event);
2286 }
2287 END_TEST
2288
START_TEST(bad_distance_events)2289 START_TEST(bad_distance_events)
2290 {
2291 struct litest_device *dev = litest_current_device();
2292 struct libinput *li = dev->libinput;
2293 const struct input_absinfo *absinfo;
2294 struct axis_replacement axes[] = {
2295 { -1, -1 },
2296 };
2297
2298 litest_tablet_proximity_in(dev, 10, 10, axes);
2299 litest_tablet_proximity_out(dev);
2300 litest_drain_events(li);
2301
2302 absinfo = libevdev_get_abs_info(dev->evdev, ABS_DISTANCE);
2303 ck_assert_notnull(absinfo);
2304
2305 litest_event(dev, EV_ABS, ABS_DISTANCE, absinfo->maximum);
2306 litest_event(dev, EV_SYN, SYN_REPORT, 0);
2307 litest_event(dev, EV_ABS, ABS_DISTANCE, absinfo->minimum);
2308 litest_event(dev, EV_SYN, SYN_REPORT, 0);
2309
2310 litest_assert_empty_queue(li);
2311 }
2312 END_TEST
2313
START_TEST(tool_unique)2314 START_TEST(tool_unique)
2315 {
2316 struct litest_device *dev = litest_current_device();
2317 struct libinput *li = dev->libinput;
2318 struct libinput_event_tablet_tool *tablet_event;
2319 struct libinput_event *event;
2320 struct libinput_tablet_tool *tool;
2321
2322 litest_drain_events(li);
2323
2324 litest_event(dev, EV_KEY, BTN_TOOL_PEN, 1);
2325 litest_event(dev, EV_MSC, MSC_SERIAL, 1000);
2326 litest_event(dev, EV_SYN, SYN_REPORT, 0);
2327
2328 libinput_dispatch(li);
2329 event = libinput_get_event(li);
2330 tablet_event = litest_is_tablet_event(event,
2331 LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
2332 tool = libinput_event_tablet_tool_get_tool(tablet_event);
2333 ck_assert(libinput_tablet_tool_is_unique(tool));
2334 libinput_event_destroy(event);
2335 }
2336 END_TEST
2337
START_TEST(tool_serial)2338 START_TEST(tool_serial)
2339 {
2340 struct litest_device *dev = litest_current_device();
2341 struct libinput *li = dev->libinput;
2342 struct libinput_event_tablet_tool *tablet_event;
2343 struct libinput_event *event;
2344 struct libinput_tablet_tool *tool;
2345
2346 litest_drain_events(li);
2347
2348 litest_event(dev, EV_KEY, BTN_TOOL_PEN, 1);
2349 litest_event(dev, EV_MSC, MSC_SERIAL, 1000);
2350 litest_event(dev, EV_SYN, SYN_REPORT, 0);
2351 libinput_dispatch(li);
2352
2353 event = libinput_get_event(li);
2354 tablet_event = litest_is_tablet_event(event,
2355 LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
2356 tool = libinput_event_tablet_tool_get_tool(tablet_event);
2357 ck_assert_uint_eq(libinput_tablet_tool_get_serial(tool), 1000);
2358 libinput_event_destroy(event);
2359 }
2360 END_TEST
2361
START_TEST(tool_id)2362 START_TEST(tool_id)
2363 {
2364 struct litest_device *dev = litest_current_device();
2365 struct libinput *li = dev->libinput;
2366 struct libinput_event_tablet_tool *tablet_event;
2367 struct libinput_event *event;
2368 struct libinput_tablet_tool *tool;
2369 uint64_t tool_id;
2370
2371 litest_drain_events(li);
2372
2373 litest_tablet_proximity_in(dev, 10, 10, NULL);
2374 libinput_dispatch(li);
2375
2376 event = libinput_get_event(li);
2377 tablet_event = litest_is_tablet_event(event,
2378 LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
2379 tool = libinput_event_tablet_tool_get_tool(tablet_event);
2380
2381 ck_assert_int_eq(libinput_device_get_id_vendor(dev->libinput_device),
2382 VENDOR_ID_WACOM);
2383
2384 switch (libinput_device_get_id_product(dev->libinput_device)) {
2385 case 0x27: /* Intuos 5 */
2386 tool_id = 1050626;
2387 break;
2388 case 0xc6: /* Cintiq 12WX */
2389 case 0xf4: /* Cintiq 24HD */
2390 case 0x333: /* Cintiq 13HD */
2391 case 0x350: /* Cintiq Pro 16 */
2392 tool_id = 2083;
2393 break;
2394 default:
2395 ck_abort();
2396 }
2397
2398 ck_assert(tool_id == libinput_tablet_tool_get_tool_id(tool));
2399 libinput_event_destroy(event);
2400 }
2401 END_TEST
2402
START_TEST(serial_changes_tool)2403 START_TEST(serial_changes_tool)
2404 {
2405 struct litest_device *dev = litest_current_device();
2406 struct libinput *li = dev->libinput;
2407 struct libinput_event_tablet_tool *tablet_event;
2408 struct libinput_event *event;
2409 struct libinput_tablet_tool *tool;
2410
2411 litest_drain_events(li);
2412
2413 litest_event(dev, EV_KEY, BTN_TOOL_PEN, 1);
2414 litest_event(dev, EV_MSC, MSC_SERIAL, 1000);
2415 litest_event(dev, EV_SYN, SYN_REPORT, 0);
2416 litest_event(dev, EV_KEY, BTN_TOOL_PEN, 0);
2417 litest_event(dev, EV_SYN, SYN_REPORT, 0);
2418 litest_drain_events(li);
2419
2420 litest_event(dev, EV_KEY, BTN_TOOL_PEN, 1);
2421 litest_event(dev, EV_MSC, MSC_SERIAL, 2000);
2422 litest_event(dev, EV_SYN, SYN_REPORT, 0);
2423 libinput_dispatch(li);
2424
2425 event = libinput_get_event(li);
2426 tablet_event = litest_is_tablet_event(event,
2427 LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
2428 tool = libinput_event_tablet_tool_get_tool(tablet_event);
2429
2430 ck_assert_uint_eq(libinput_tablet_tool_get_serial(tool), 2000);
2431 libinput_event_destroy(event);
2432 }
2433 END_TEST
2434
START_TEST(invalid_serials)2435 START_TEST(invalid_serials)
2436 {
2437 struct litest_device *dev = litest_current_device();
2438 struct libinput *li = dev->libinput;
2439 struct libinput_event *event;
2440 struct libinput_event_tablet_tool *tablet_event;
2441 struct libinput_tablet_tool *tool;
2442
2443 litest_drain_events(li);
2444
2445 litest_event(dev, EV_KEY, BTN_TOOL_PEN, 1);
2446 litest_event(dev, EV_MSC, MSC_SERIAL, 1000);
2447 litest_event(dev, EV_SYN, SYN_REPORT, 0);
2448 litest_event(dev, EV_KEY, BTN_TOOL_PEN, 0);
2449 litest_event(dev, EV_SYN, SYN_REPORT, 0);
2450 litest_drain_events(li);
2451
2452 litest_event(dev, EV_KEY, BTN_TOOL_PEN, 1);
2453 litest_event(dev, EV_MSC, MSC_SERIAL, -1);
2454 litest_event(dev, EV_SYN, SYN_REPORT, 0);
2455
2456 libinput_dispatch(li);
2457 while ((event = libinput_get_event(li))) {
2458 if (libinput_event_get_type(event) ==
2459 LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY) {
2460 tablet_event = libinput_event_get_tablet_tool_event(event);
2461 tool = libinput_event_tablet_tool_get_tool(tablet_event);
2462
2463 ck_assert_uint_eq(libinput_tablet_tool_get_serial(tool), 1000);
2464 }
2465
2466 libinput_event_destroy(event);
2467 }
2468 }
2469 END_TEST
2470
START_TEST(tool_ref)2471 START_TEST(tool_ref)
2472 {
2473 struct litest_device *dev = litest_current_device();
2474 struct libinput *li = dev->libinput;
2475 struct libinput_event_tablet_tool *tablet_event;
2476 struct libinput_event *event;
2477 struct libinput_tablet_tool *tool;
2478
2479 litest_drain_events(li);
2480
2481 litest_event(dev, EV_KEY, BTN_TOOL_PEN, 1);
2482 litest_event(dev, EV_MSC, MSC_SERIAL, 1000);
2483 litest_event(dev, EV_SYN, SYN_REPORT, 0);
2484 libinput_dispatch(li);
2485
2486 event = libinput_get_event(li);
2487 tablet_event = litest_is_tablet_event(event,
2488 LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
2489 tool = libinput_event_tablet_tool_get_tool(tablet_event);
2490
2491 ck_assert_notnull(tool);
2492 ck_assert(tool == libinput_tablet_tool_ref(tool));
2493 ck_assert(tool == libinput_tablet_tool_unref(tool));
2494 libinput_event_destroy(event);
2495
2496 ck_assert(libinput_tablet_tool_unref(tool) == NULL);
2497 }
2498 END_TEST
2499
START_TEST(tool_user_data)2500 START_TEST(tool_user_data)
2501 {
2502 struct litest_device *dev = litest_current_device();
2503 struct libinput *li = dev->libinput;
2504 struct libinput_event_tablet_tool *tablet_event;
2505 struct libinput_event *event;
2506 struct libinput_tablet_tool *tool;
2507 void *userdata = &dev; /* not dereferenced */
2508
2509 litest_drain_events(li);
2510
2511 litest_event(dev, EV_KEY, BTN_TOOL_PEN, 1);
2512 litest_event(dev, EV_MSC, MSC_SERIAL, 1000);
2513 litest_event(dev, EV_SYN, SYN_REPORT, 0);
2514 libinput_dispatch(li);
2515
2516 event = libinput_get_event(li);
2517 tablet_event = litest_is_tablet_event(event,
2518 LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
2519 tool = libinput_event_tablet_tool_get_tool(tablet_event);
2520 ck_assert_notnull(tool);
2521
2522 ck_assert(libinput_tablet_tool_get_user_data(tool) == NULL);
2523 libinput_tablet_tool_set_user_data(tool, userdata);
2524 ck_assert(libinput_tablet_tool_get_user_data(tool) == userdata);
2525 libinput_tablet_tool_set_user_data(tool, NULL);
2526 ck_assert(libinput_tablet_tool_get_user_data(tool) == NULL);
2527
2528 libinput_event_destroy(event);
2529 }
2530 END_TEST
2531
START_TEST(pad_buttons_ignored)2532 START_TEST(pad_buttons_ignored)
2533 {
2534 struct litest_device *dev = litest_current_device();
2535 struct libinput *li = dev->libinput;
2536 struct axis_replacement axes[] = {
2537 { ABS_DISTANCE, 10 },
2538 { ABS_PRESSURE, 0 },
2539 { -1, -1 }
2540 };
2541 int button;
2542
2543 litest_drain_events(li);
2544
2545 for (button = BTN_0; button < BTN_MOUSE; button++) {
2546 litest_event(dev, EV_KEY, button, 1);
2547 litest_event(dev, EV_SYN, SYN_REPORT, 0);
2548 litest_event(dev, EV_KEY, button, 0);
2549 litest_event(dev, EV_SYN, SYN_REPORT, 0);
2550 libinput_dispatch(li);
2551 }
2552
2553 litest_assert_empty_queue(li);
2554
2555 /* same thing while in prox */
2556 litest_tablet_proximity_in(dev, 10, 10, axes);
2557 litest_drain_events(li);
2558
2559 for (button = BTN_0; button < BTN_MOUSE; button++)
2560 litest_event(dev, EV_KEY, button, 1);
2561
2562 litest_event(dev, EV_SYN, SYN_REPORT, 0);
2563 libinput_dispatch(li);
2564
2565 for (button = BTN_0; button < BTN_MOUSE; button++)
2566 litest_event(dev, EV_KEY, button, 0);
2567
2568 litest_event(dev, EV_SYN, SYN_REPORT, 0);
2569 libinput_dispatch(li);
2570
2571 litest_assert_empty_queue(li);
2572 }
2573 END_TEST
2574
START_TEST(tools_with_serials)2575 START_TEST(tools_with_serials)
2576 {
2577 struct libinput *li = litest_create_context();
2578 struct litest_device *dev[2];
2579 struct libinput_tablet_tool *tool[2] = {0};
2580 struct libinput_event *event;
2581 struct libinput_event_tablet_tool *tev;
2582 int i;
2583
2584 for (i = 0; i < 2; i++) {
2585 dev[i] = litest_add_device(li, LITEST_WACOM_INTUOS);
2586 litest_drain_events(li);
2587
2588 /* WARNING: this test fails if UI_GET_SYSNAME isn't
2589 * available or isn't used by libevdev (1.3, commit 2ff45c73).
2590 * Put a sleep(1) here and that usually fixes it.
2591 */
2592
2593 litest_push_event_frame(dev[i]);
2594 litest_tablet_proximity_in(dev[i], 10, 10, NULL);
2595 litest_event(dev[i], EV_MSC, MSC_SERIAL, 100);
2596 litest_pop_event_frame(dev[i]);
2597
2598 libinput_dispatch(li);
2599 event = libinput_get_event(li);
2600 tev = litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
2601 tool[i] = libinput_event_tablet_tool_get_tool(tev);
2602 libinput_event_destroy(event);
2603 }
2604
2605 /* We should get the same object for both devices */
2606 ck_assert_notnull(tool[0]);
2607 ck_assert_notnull(tool[1]);
2608 ck_assert_ptr_eq(tool[0], tool[1]);
2609
2610 litest_delete_device(dev[0]);
2611 litest_delete_device(dev[1]);
2612 litest_destroy_context(li);
2613 }
2614 END_TEST
2615
START_TEST(tools_without_serials)2616 START_TEST(tools_without_serials)
2617 {
2618 struct libinput *li = litest_create_context();
2619 struct litest_device *dev[2];
2620 struct libinput_tablet_tool *tool[2] = {0};
2621 struct libinput_event *event;
2622 struct libinput_event_tablet_tool *tev;
2623 int i;
2624
2625 for (i = 0; i < 2; i++) {
2626 dev[i] = litest_add_device_with_overrides(li,
2627 LITEST_WACOM_ISDV4,
2628 NULL,
2629 NULL,
2630 NULL,
2631 NULL);
2632
2633 litest_drain_events(li);
2634
2635 /* WARNING: this test fails if UI_GET_SYSNAME isn't
2636 * available or isn't used by libevdev (1.3, commit 2ff45c73).
2637 * Put a sleep(1) here and that usually fixes it.
2638 */
2639
2640 litest_tablet_proximity_in(dev[i], 10, 10, NULL);
2641
2642 libinput_dispatch(li);
2643 event = libinput_get_event(li);
2644 tev = litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
2645 tool[i] = libinput_event_tablet_tool_get_tool(tev);
2646 libinput_event_destroy(event);
2647 }
2648
2649 /* We should get different tool objects for each device */
2650 ck_assert_notnull(tool[0]);
2651 ck_assert_notnull(tool[1]);
2652 ck_assert_ptr_ne(tool[0], tool[1]);
2653
2654 litest_delete_device(dev[0]);
2655 litest_delete_device(dev[1]);
2656 litest_destroy_context(li);
2657 }
2658 END_TEST
2659
START_TEST(tool_delayed_serial)2660 START_TEST(tool_delayed_serial)
2661 {
2662 struct litest_device *dev = litest_current_device();
2663 struct libinput *li = dev->libinput;
2664 struct libinput_event *event;
2665 struct libinput_event_tablet_tool *tev;
2666 struct libinput_tablet_tool *tool;
2667 unsigned int serial;
2668
2669 litest_drain_events(li);
2670
2671 litest_event(dev, EV_ABS, ABS_X, 4500);
2672 litest_event(dev, EV_ABS, ABS_Y, 2000);
2673 litest_event(dev, EV_MSC, MSC_SERIAL, 0);
2674 litest_event(dev, EV_KEY, BTN_TOOL_PEN, 1);
2675 litest_event(dev, EV_SYN, SYN_REPORT, 0);
2676 libinput_dispatch(li);
2677
2678 event = libinput_get_event(li);
2679 tev = litest_is_tablet_event(event,
2680 LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
2681 tool = libinput_event_tablet_tool_get_tool(tev);
2682 serial = libinput_tablet_tool_get_serial(tool);
2683 ck_assert_int_eq(serial, 0);
2684 libinput_event_destroy(event);
2685
2686 for (int x = 4500; x < 8000; x += 1000) {
2687 litest_event(dev, EV_ABS, ABS_X, x);
2688 litest_event(dev, EV_ABS, ABS_Y, 2000);
2689 litest_event(dev, EV_MSC, MSC_SERIAL, 0);
2690 litest_event(dev, EV_SYN, SYN_REPORT, 0);
2691 libinput_dispatch(li);
2692 }
2693 litest_drain_events(li);
2694
2695 /* Now send the serial */
2696 litest_event(dev, EV_ABS, ABS_X, 4500);
2697 litest_event(dev, EV_ABS, ABS_Y, 2000);
2698 litest_event(dev, EV_MSC, MSC_SERIAL, 1234566);
2699 litest_event(dev, EV_SYN, SYN_REPORT, 0);
2700 libinput_dispatch(li);
2701
2702 event = libinput_get_event(li);
2703 tev = litest_is_tablet_event(event,
2704 LIBINPUT_EVENT_TABLET_TOOL_AXIS);
2705 tool = libinput_event_tablet_tool_get_tool(tev);
2706 serial = libinput_tablet_tool_get_serial(tool);
2707 ck_assert_int_eq(serial, 0);
2708 libinput_event_destroy(event);
2709
2710 for (int x = 4500; x < 8000; x += 500) {
2711 litest_event(dev, EV_ABS, ABS_X, x);
2712 litest_event(dev, EV_ABS, ABS_Y, 2000);
2713 litest_event(dev, EV_MSC, MSC_SERIAL, 1234566);
2714 litest_event(dev, EV_SYN, SYN_REPORT, 0);
2715 libinput_dispatch(li);
2716 }
2717
2718 event = libinput_get_event(li);
2719 do {
2720 tev = litest_is_tablet_event(event,
2721 LIBINPUT_EVENT_TABLET_TOOL_AXIS);
2722 tool = libinput_event_tablet_tool_get_tool(tev);
2723 serial = libinput_tablet_tool_get_serial(tool);
2724 ck_assert_int_eq(serial, 0);
2725 libinput_event_destroy(event);
2726 event = libinput_get_event(li);
2727 } while (event != NULL);
2728
2729 /* Quirk: tool out event is a serial of 0 */
2730 litest_event(dev, EV_ABS, ABS_X, 4500);
2731 litest_event(dev, EV_ABS, ABS_Y, 2000);
2732 litest_event(dev, EV_MSC, MSC_SERIAL, 0);
2733 litest_event(dev, EV_KEY, BTN_TOOL_PEN, 0);
2734 litest_event(dev, EV_SYN, SYN_REPORT, 0);
2735 libinput_dispatch(li);
2736
2737 event = libinput_get_event(li);
2738 tev = litest_is_tablet_event(event,
2739 LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
2740 tool = libinput_event_tablet_tool_get_tool(tev);
2741 serial = libinput_tablet_tool_get_serial(tool);
2742 ck_assert_int_eq(serial, 0);
2743 libinput_event_destroy(event);
2744 }
2745 END_TEST
2746
START_TEST(tool_capability)2747 START_TEST(tool_capability)
2748 {
2749 struct litest_device *dev = litest_current_device();
2750 struct libinput_device *device = dev->libinput_device;
2751
2752 ck_assert(libinput_device_has_capability(device,
2753 LIBINPUT_DEVICE_CAP_TABLET_TOOL));
2754 }
2755 END_TEST
2756
START_TEST(tool_capabilities)2757 START_TEST(tool_capabilities)
2758 {
2759 struct libinput *li = litest_create_context();
2760 struct litest_device *intuos;
2761 struct litest_device *bamboo;
2762 struct libinput_event *event;
2763 struct libinput_event_tablet_tool *t;
2764 struct libinput_tablet_tool *tool;
2765
2766 /* The axis capabilities of a tool can differ depending on the type of
2767 * tablet the tool is being used with */
2768 bamboo = litest_add_device(li, LITEST_WACOM_BAMBOO);
2769 intuos = litest_add_device(li, LITEST_WACOM_INTUOS);
2770 litest_drain_events(li);
2771
2772 litest_event(bamboo, EV_KEY, BTN_TOOL_PEN, 1);
2773 litest_event(bamboo, EV_SYN, SYN_REPORT, 0);
2774
2775 libinput_dispatch(li);
2776
2777 event = libinput_get_event(li);
2778 t = litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
2779 tool = libinput_event_tablet_tool_get_tool(t);
2780
2781 ck_assert(libinput_tablet_tool_has_pressure(tool));
2782 ck_assert(libinput_tablet_tool_has_distance(tool));
2783 ck_assert(!libinput_tablet_tool_has_tilt(tool));
2784
2785 libinput_event_destroy(event);
2786 litest_assert_empty_queue(li);
2787
2788 litest_event(intuos, EV_KEY, BTN_TOOL_PEN, 1);
2789 litest_event(intuos, EV_SYN, SYN_REPORT, 0);
2790 libinput_dispatch(li);
2791
2792 event = libinput_get_event(li);
2793 t = litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
2794 tool = libinput_event_tablet_tool_get_tool(t);
2795
2796 ck_assert(libinput_tablet_tool_has_pressure(tool));
2797 ck_assert(libinput_tablet_tool_has_distance(tool));
2798 ck_assert(libinput_tablet_tool_has_tilt(tool));
2799
2800 libinput_event_destroy(event);
2801 litest_assert_empty_queue(li);
2802
2803 litest_delete_device(bamboo);
2804 litest_delete_device(intuos);
2805 litest_destroy_context(li);
2806 }
2807 END_TEST
2808
2809 static inline bool
tablet_has_mouse(struct litest_device * dev)2810 tablet_has_mouse(struct litest_device *dev)
2811 {
2812 return libevdev_has_event_code(dev->evdev, EV_KEY, BTN_TOOL_MOUSE) &&
2813 libevdev_get_id_vendor(dev->evdev) == VENDOR_ID_WACOM;
2814 }
2815
START_TEST(tool_type)2816 START_TEST(tool_type)
2817 {
2818 struct litest_device *dev = litest_current_device();
2819 struct libinput *li = dev->libinput;
2820 struct libinput_event *event;
2821 struct libinput_event_tablet_tool *t;
2822 struct libinput_tablet_tool *tool;
2823 struct axis_replacement axes[] = {
2824 { ABS_DISTANCE, 10 },
2825 { ABS_PRESSURE, 0 },
2826 { ABS_TILT_X, 0 },
2827 { ABS_TILT_Y, 0 },
2828 { -1, -1 }
2829 };
2830 struct tool_type_match {
2831 int code;
2832 enum libinput_tablet_tool_type type;
2833 } types[] = {
2834 { BTN_TOOL_PEN, LIBINPUT_TABLET_TOOL_TYPE_PEN },
2835 { BTN_TOOL_RUBBER, LIBINPUT_TABLET_TOOL_TYPE_ERASER },
2836 { BTN_TOOL_BRUSH, LIBINPUT_TABLET_TOOL_TYPE_BRUSH },
2837 { BTN_TOOL_PENCIL, LIBINPUT_TABLET_TOOL_TYPE_PENCIL },
2838 { BTN_TOOL_AIRBRUSH, LIBINPUT_TABLET_TOOL_TYPE_AIRBRUSH },
2839 { BTN_TOOL_MOUSE, LIBINPUT_TABLET_TOOL_TYPE_MOUSE },
2840 { BTN_TOOL_LENS, LIBINPUT_TABLET_TOOL_TYPE_LENS },
2841 { -1, -1 }
2842 };
2843 struct tool_type_match *tt;
2844 double x = 50, y = 50;
2845
2846 litest_drain_events(li);
2847
2848 for (tt = types; tt->code != -1; tt++) {
2849 enum libinput_tablet_tool_type type;
2850
2851 if (!libevdev_has_event_code(dev->evdev,
2852 EV_KEY,
2853 tt->code))
2854 continue;
2855
2856 if ((tt->code == BTN_TOOL_MOUSE || tt->code == BTN_TOOL_LENS) &&
2857 !tablet_has_mouse(dev))
2858 continue;
2859
2860 litest_tablet_set_tool_type(dev, tt->code);
2861 litest_tablet_proximity_in(dev, x, y, axes);
2862 libinput_dispatch(li);
2863
2864 event = libinput_get_event(li);
2865 t = litest_is_tablet_event(event,
2866 LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
2867 tool = libinput_event_tablet_tool_get_tool(t);
2868 type = libinput_tablet_tool_get_type(tool);
2869
2870 /* Devices with doubled-up tool bits send the pen
2871 * in-prox and immediately out-of-prox before the real tool
2872 * type. Drop those two and continue with what we expect is
2873 * the real prox in event */
2874 if (tt->type != LIBINPUT_TABLET_TOOL_TYPE_PEN &&
2875 type == LIBINPUT_TABLET_TOOL_TYPE_PEN) {
2876 libinput_event_destroy(event);
2877 event = libinput_get_event(li);
2878 litest_is_tablet_event(event,
2879 LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
2880 libinput_event_destroy(event);
2881 event = libinput_get_event(li);
2882 t = litest_is_tablet_event(event,
2883 LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
2884 tool = libinput_event_tablet_tool_get_tool(t);
2885 type = libinput_tablet_tool_get_type(tool);
2886 }
2887
2888 ck_assert_int_eq(type, tt->type);
2889
2890 libinput_event_destroy(event);
2891 litest_assert_empty_queue(li);
2892
2893 litest_tablet_proximity_out(dev);
2894 litest_drain_events(li);
2895
2896 x++;
2897 y++;
2898 }
2899 }
2900 END_TEST
2901
START_TEST(tool_in_prox_before_start)2902 START_TEST(tool_in_prox_before_start)
2903 {
2904 struct libinput *li;
2905 struct litest_device *dev = litest_current_device();
2906 struct libinput_event *event;
2907 struct libinput_event_tablet_tool *tev;
2908 struct libinput_tablet_tool *tool;
2909 struct axis_replacement axes[] = {
2910 { ABS_DISTANCE, 10 },
2911 { ABS_PRESSURE, 0 },
2912 { ABS_TILT_X, 0 },
2913 { ABS_TILT_Y, 0 },
2914 { -1, -1 }
2915 };
2916 const char *devnode;
2917 unsigned int serial;
2918
2919 litest_tablet_proximity_in(dev, 10, 10, axes);
2920
2921 /* for simplicity, we create a new litest context */
2922 devnode = libevdev_uinput_get_devnode(dev->uinput);
2923 li = litest_create_context();
2924 libinput_path_add_device(li, devnode);
2925
2926 litest_drain_events_of_type(li, LIBINPUT_EVENT_DEVICE_ADDED, -1);
2927
2928 litest_assert_empty_queue(li);
2929
2930 litest_tablet_motion(dev, 10, 20, axes);
2931 libinput_dispatch(li);
2932 event = libinput_get_event(li);
2933 tev = litest_is_tablet_event(event,
2934 LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
2935 tool = libinput_event_tablet_tool_get_tool(tev);
2936 serial = libinput_tablet_tool_get_serial(tool);
2937 libinput_event_destroy(event);
2938
2939 litest_drain_events_of_type(li, LIBINPUT_EVENT_TABLET_TOOL_TIP, -1);
2940
2941 litest_tablet_motion(dev, 30, 40, axes);
2942 libinput_dispatch(li);
2943 event = libinput_get_event(li);
2944 tev = litest_is_tablet_event(event,
2945 LIBINPUT_EVENT_TABLET_TOOL_AXIS);
2946 tool = libinput_event_tablet_tool_get_tool(tev);
2947 ck_assert_int_eq(serial,
2948 libinput_tablet_tool_get_serial(tool));
2949 libinput_event_destroy(event);
2950
2951 litest_assert_empty_queue(li);
2952 litest_button_click(dev, BTN_STYLUS, true);
2953 litest_button_click(dev, BTN_STYLUS, false);
2954 litest_assert_only_typed_events(li, LIBINPUT_EVENT_TABLET_TOOL_BUTTON);
2955 litest_tablet_proximity_out(dev);
2956 libinput_dispatch(li);
2957
2958 litest_timeout_tablet_proxout();
2959 libinput_dispatch(li);
2960
2961 event = libinput_get_event(li);
2962 litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
2963 libinput_event_destroy(event);
2964
2965 litest_destroy_context(li);
2966 }
2967 END_TEST
2968
START_TEST(tool_direct_switch_skip_tool_update)2969 START_TEST(tool_direct_switch_skip_tool_update)
2970 {
2971 struct litest_device *dev = litest_current_device();
2972 struct libinput *li = dev->libinput;
2973 struct libinput_event *event;
2974 struct libinput_event_tablet_tool *tev;
2975 struct libinput_tablet_tool *tool;
2976 struct axis_replacement axes[] = {
2977 { ABS_DISTANCE, 10 },
2978 { ABS_PRESSURE, 0 },
2979 { -1, -1 }
2980 };
2981
2982 if (!libevdev_has_event_code(dev->evdev, EV_KEY, BTN_TOOL_RUBBER))
2983 return;
2984
2985 litest_drain_events(li);
2986
2987 litest_tablet_proximity_in(dev, 10, 10, axes);
2988 libinput_dispatch(li);
2989
2990 event = libinput_get_event(li);
2991 tev = litest_is_tablet_event(event,
2992 LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
2993 tool = libinput_event_tablet_tool_get_tool(tev);
2994 libinput_tablet_tool_ref(tool);
2995 libinput_event_destroy(event);
2996
2997 litest_event(dev, EV_KEY, BTN_TOOL_RUBBER, 1);
2998 litest_event(dev, EV_SYN, SYN_REPORT, 0);
2999 libinput_dispatch(li);
3000
3001 event = libinput_get_event(li);
3002 tev = litest_is_tablet_event(event,
3003 LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
3004 ck_assert_int_eq(libinput_event_tablet_tool_get_proximity_state(tev),
3005 LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT);
3006 ck_assert_ptr_eq(libinput_event_tablet_tool_get_tool(tev), tool);
3007 libinput_event_destroy(event);
3008
3009 event = libinput_get_event(li);
3010 tev = litest_is_tablet_event(event,
3011 LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
3012 ck_assert_int_eq(libinput_event_tablet_tool_get_proximity_state(tev),
3013 LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN);
3014 ck_assert_ptr_ne(libinput_event_tablet_tool_get_tool(tev), tool);
3015 libinput_tablet_tool_unref(tool);
3016 tool = libinput_event_tablet_tool_get_tool(tev);
3017 libinput_tablet_tool_ref(tool);
3018 libinput_event_destroy(event);
3019
3020 litest_tablet_motion(dev, 20, 30, axes);
3021 libinput_dispatch(li);
3022
3023 event = libinput_get_event(li);
3024 tev = litest_is_tablet_event(event,
3025 LIBINPUT_EVENT_TABLET_TOOL_AXIS);
3026 ck_assert_ptr_eq(libinput_event_tablet_tool_get_tool(tev),
3027 tool);
3028 libinput_event_destroy(event);
3029
3030 litest_event(dev, EV_KEY, BTN_TOOL_RUBBER, 0);
3031 litest_event(dev, EV_SYN, SYN_REPORT, 0);
3032 libinput_dispatch(li);
3033
3034 event = libinput_get_event(li);
3035 tev = litest_is_tablet_event(event,
3036 LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
3037 ck_assert_int_eq(libinput_event_tablet_tool_get_proximity_state(tev),
3038 LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT);
3039 ck_assert_ptr_eq(libinput_event_tablet_tool_get_tool(tev),
3040 tool);
3041 libinput_event_destroy(event);
3042
3043 litest_push_event_frame(dev);
3044 litest_event(dev, EV_KEY, BTN_TOOL_RUBBER, 1);
3045 litest_tablet_motion(dev, 30, 40, axes);
3046 litest_pop_event_frame(dev);
3047 libinput_dispatch(li);
3048
3049 event = libinput_get_event(li);
3050 tev = litest_is_tablet_event(event,
3051 LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
3052 ck_assert_int_eq(libinput_event_tablet_tool_get_proximity_state(tev),
3053 LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN);
3054 ck_assert_ptr_eq(libinput_event_tablet_tool_get_tool(tev),
3055 tool);
3056 libinput_event_destroy(event);
3057
3058 litest_tablet_motion(dev, 40, 30, axes);
3059 libinput_dispatch(li);
3060
3061 event = libinput_get_event(li);
3062 tev = litest_is_tablet_event(event,
3063 LIBINPUT_EVENT_TABLET_TOOL_AXIS);
3064 ck_assert_ptr_eq(libinput_event_tablet_tool_get_tool(tev),
3065 tool);
3066 libinput_event_destroy(event);
3067
3068 litest_push_event_frame(dev);
3069 litest_event(dev, EV_KEY, BTN_TOOL_RUBBER, 0);
3070 litest_tablet_proximity_out(dev);
3071 litest_pop_event_frame(dev);
3072 libinput_dispatch(li);
3073 litest_timeout_tablet_proxout();
3074 libinput_dispatch(li);
3075
3076 event = libinput_get_event(li);
3077 tev = litest_is_tablet_event(event,
3078 LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
3079 ck_assert_ptr_eq(libinput_event_tablet_tool_get_tool(tev),
3080 tool);
3081 libinput_event_destroy(event);
3082
3083 litest_event(dev, EV_KEY, BTN_TOOL_RUBBER, 0);
3084 litest_event(dev, EV_SYN, SYN_REPORT, 0);
3085 litest_assert_empty_queue(li);
3086
3087 libinput_tablet_tool_unref(tool);
3088 }
3089 END_TEST
3090
START_TEST(tool_direct_switch_with_forced_proxout)3091 START_TEST(tool_direct_switch_with_forced_proxout)
3092 {
3093 struct litest_device *dev = litest_current_device();
3094 struct libinput *li = dev->libinput;
3095 struct libinput_event *event;
3096 struct axis_replacement axes[] = {
3097 { ABS_DISTANCE, 10 },
3098 { ABS_PRESSURE, 0 },
3099 { -1, -1 }
3100 };
3101
3102 if (!libevdev_has_event_code(dev->evdev, EV_KEY, BTN_TOOL_RUBBER))
3103 return;
3104
3105 litest_drain_events(li);
3106
3107 /* This is a *very* specific event sequence to trigger a bug:
3108 - pen proximity in
3109 - pen proximity forced out
3110 - eraser proximity in without axis movement
3111 - eraser axis move
3112 */
3113
3114 /* pen prox in */
3115 litest_tablet_proximity_in(dev, 10, 10, axes);
3116 libinput_dispatch(li);
3117 event = libinput_get_event(li);
3118 litest_is_proximity_event(event,
3119 LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN);
3120 libinput_event_destroy(event);
3121
3122 /* pen motion */
3123 litest_tablet_motion(dev, 20, 30, axes);
3124 libinput_dispatch(li);
3125
3126 event = libinput_get_event(li);
3127 litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_AXIS);
3128 libinput_event_destroy(event);
3129
3130 /* pen forced prox out */
3131 litest_timeout_tablet_proxout();
3132 libinput_dispatch(li);
3133
3134 /* actual prox out for tablets that don't do forced prox out */
3135 litest_tablet_proximity_out(dev);
3136 libinput_dispatch(li);
3137
3138 event = libinput_get_event(li);
3139 litest_is_proximity_event(event,
3140 LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT);
3141 libinput_event_destroy(event);
3142
3143 /* eraser prox in without axes */
3144 litest_event(dev, EV_KEY, BTN_TOOL_RUBBER, 1);
3145 litest_event(dev, EV_SYN, SYN_REPORT, 0);
3146 libinput_dispatch(li);
3147 event = libinput_get_event(li);
3148 litest_is_proximity_event(event,
3149 LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN);
3150 libinput_event_destroy(event);
3151
3152 /* eraser motion */
3153 litest_tablet_motion(dev, 30, 40, axes);
3154 litest_tablet_motion(dev, 40, 50, axes);
3155 libinput_dispatch(li);
3156
3157 event = libinput_get_event(li);
3158 litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_AXIS);
3159 libinput_event_destroy(event);
3160
3161 event = libinput_get_event(li);
3162 litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_AXIS);
3163 libinput_event_destroy(event);
3164
3165 litest_assert_empty_queue(li);
3166 }
3167 END_TEST
3168
START_TEST(mouse_tool)3169 START_TEST(mouse_tool)
3170 {
3171 struct litest_device *dev = litest_current_device();
3172 struct libinput *li = dev->libinput;
3173 struct libinput_event *event;
3174 struct libinput_event_tablet_tool *tev;
3175 struct libinput_tablet_tool *tool;
3176
3177 litest_drain_events(li);
3178
3179 litest_event(dev, EV_KEY, BTN_TOOL_MOUSE, 1);
3180 litest_event(dev, EV_MSC, MSC_SERIAL, 1000);
3181 litest_event(dev, EV_SYN, SYN_REPORT, 0);
3182 libinput_dispatch(li);
3183
3184 event = libinput_get_event(li);
3185 tev = litest_is_tablet_event(event,
3186 LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
3187 tool = libinput_event_tablet_tool_get_tool(tev);
3188 ck_assert_notnull(tool);
3189 ck_assert_int_eq(libinput_tablet_tool_get_type(tool),
3190 LIBINPUT_TABLET_TOOL_TYPE_MOUSE);
3191
3192 libinput_event_destroy(event);
3193 }
3194 END_TEST
3195
START_TEST(mouse_buttons)3196 START_TEST(mouse_buttons)
3197 {
3198 struct litest_device *dev = litest_current_device();
3199 struct libinput *li = dev->libinput;
3200 struct libinput_event *event;
3201 struct libinput_event_tablet_tool *tev;
3202 struct libinput_tablet_tool *tool;
3203 int code;
3204
3205 litest_drain_events(li);
3206
3207 litest_event(dev, EV_KEY, BTN_TOOL_MOUSE, 1);
3208 litest_event(dev, EV_ABS, ABS_MISC, 0x806); /* 5-button mouse tool_id */
3209 litest_event(dev, EV_MSC, MSC_SERIAL, 1000);
3210 litest_event(dev, EV_SYN, SYN_REPORT, 0);
3211 libinput_dispatch(li);
3212
3213 event = libinput_get_event(li);
3214 tev = litest_is_tablet_event(event,
3215 LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
3216 tool = libinput_event_tablet_tool_get_tool(tev);
3217 ck_assert_notnull(tool);
3218 libinput_tablet_tool_ref(tool);
3219
3220 libinput_event_destroy(event);
3221
3222 for (code = BTN_LEFT; code <= BTN_TASK; code++) {
3223 bool has_button = libevdev_has_event_code(dev->evdev,
3224 EV_KEY,
3225 code);
3226 ck_assert_int_eq(!!has_button,
3227 !!libinput_tablet_tool_has_button(tool, code));
3228
3229 if (!has_button)
3230 continue;
3231
3232 litest_event(dev, EV_KEY, code, 1);
3233 litest_event(dev, EV_SYN, SYN_REPORT, 0);
3234 libinput_dispatch(li);
3235 litest_event(dev, EV_KEY, code, 0);
3236 litest_event(dev, EV_SYN, SYN_REPORT, 0);
3237 libinput_dispatch(li);
3238
3239 litest_assert_tablet_button_event(li,
3240 code,
3241 LIBINPUT_BUTTON_STATE_PRESSED);
3242 litest_assert_tablet_button_event(li,
3243 code,
3244 LIBINPUT_BUTTON_STATE_RELEASED);
3245 }
3246
3247 libinput_tablet_tool_unref(tool);
3248 }
3249 END_TEST
3250
START_TEST(mouse_rotation)3251 START_TEST(mouse_rotation)
3252 {
3253 struct litest_device *dev = litest_current_device();
3254 struct libinput *li = dev->libinput;
3255 int angle;
3256 double val, old_val = 0;
3257
3258 struct axis_replacement axes[] = {
3259 { ABS_DISTANCE, 10 },
3260 { ABS_PRESSURE, 0 },
3261 { ABS_TILT_X, 0 },
3262 { ABS_TILT_Y, 0 },
3263 { -1, -1 }
3264 };
3265
3266 litest_drain_events(li);
3267
3268 litest_push_event_frame(dev);
3269 litest_filter_event(dev, EV_KEY, BTN_TOOL_PEN);
3270 litest_tablet_proximity_in(dev, 10, 10, axes);
3271 litest_event(dev, EV_KEY, BTN_TOOL_MOUSE, 1);
3272 litest_unfilter_event(dev, EV_KEY, BTN_TOOL_PEN);
3273 litest_pop_event_frame(dev);
3274
3275 litest_drain_events(li);
3276
3277 /* cos/sin are 90 degrees offset from the north-is-zero that
3278 libinput uses. 175 is the CCW offset in the mouse HW */
3279 for (angle = 5; angle < 360; angle += 5) {
3280 val = rotate_event(dev, angle);
3281
3282 /* rounding error galore, we can't test for anything more
3283 precise than these */
3284 litest_assert_double_lt(val, 360.0);
3285 litest_assert_double_gt(val, old_val);
3286 litest_assert_double_lt(val, angle + 5);
3287
3288 old_val = val;
3289 }
3290 }
3291 END_TEST
3292
START_TEST(mouse_wheel)3293 START_TEST(mouse_wheel)
3294 {
3295 struct litest_device *dev = litest_current_device();
3296 struct libinput *li = dev->libinput;
3297 struct libinput_event *event;
3298 struct libinput_event_tablet_tool *tev;
3299 struct libinput_tablet_tool *tool;
3300 const struct input_absinfo *abs;
3301 double val;
3302 int i;
3303
3304 if (!libevdev_has_event_code(dev->evdev,
3305 EV_REL,
3306 REL_WHEEL))
3307 return;
3308
3309 litest_drain_events(li);
3310
3311 litest_event(dev, EV_KEY, BTN_TOOL_MOUSE, 1);
3312 litest_event(dev, EV_ABS, ABS_MISC, 0x806); /* 5-button mouse tool_id */
3313 litest_event(dev, EV_MSC, MSC_SERIAL, 1000);
3314 litest_event(dev, EV_SYN, SYN_REPORT, 0);
3315 libinput_dispatch(li);
3316
3317 event = libinput_get_event(li);
3318 tev = litest_is_tablet_event(event,
3319 LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
3320 tool = libinput_event_tablet_tool_get_tool(tev);
3321 ck_assert_notnull(tool);
3322 libinput_tablet_tool_ref(tool);
3323
3324 libinput_event_destroy(event);
3325
3326 ck_assert(libinput_tablet_tool_has_wheel(tool));
3327
3328 for (i = 0; i < 3; i++) {
3329 litest_event(dev, EV_REL, REL_WHEEL, -1);
3330 litest_event(dev, EV_SYN, SYN_REPORT, 0);
3331 libinput_dispatch(li);
3332
3333 event = libinput_get_event(li);
3334 tev = litest_is_tablet_event(event,
3335 LIBINPUT_EVENT_TABLET_TOOL_AXIS);
3336 ck_assert(libinput_event_tablet_tool_wheel_has_changed(tev));
3337
3338 val = libinput_event_tablet_tool_get_wheel_delta(tev);
3339 ck_assert_int_eq(val, 15);
3340
3341 val = libinput_event_tablet_tool_get_wheel_delta_discrete(tev);
3342 ck_assert_int_eq(val, 1);
3343
3344 libinput_event_destroy(event);
3345
3346 litest_assert_empty_queue(li);
3347 }
3348
3349 for (i = 2; i < 5; i++) {
3350 /* send x/y events to make sure we reset the wheel */
3351 abs = libevdev_get_abs_info(dev->evdev, ABS_X);
3352 litest_event(dev, EV_ABS, ABS_X, absinfo_range(abs)/i);
3353 abs = libevdev_get_abs_info(dev->evdev, ABS_Y);
3354 litest_event(dev, EV_ABS, ABS_Y, absinfo_range(abs)/i);
3355 litest_event(dev, EV_SYN, SYN_REPORT, 0);
3356 libinput_dispatch(li);
3357
3358 event = libinput_get_event(li);
3359 tev = litest_is_tablet_event(event,
3360 LIBINPUT_EVENT_TABLET_TOOL_AXIS);
3361 ck_assert(!libinput_event_tablet_tool_wheel_has_changed(tev));
3362
3363 val = libinput_event_tablet_tool_get_wheel_delta(tev);
3364 ck_assert_int_eq(val, 0);
3365
3366 val = libinput_event_tablet_tool_get_wheel_delta_discrete(tev);
3367 ck_assert_int_eq(val, 0);
3368
3369 libinput_event_destroy(event);
3370
3371 litest_assert_empty_queue(li);
3372 }
3373
3374 libinput_tablet_tool_unref(tool);
3375 }
3376 END_TEST
3377
START_TEST(airbrush_tool)3378 START_TEST(airbrush_tool)
3379 {
3380 struct litest_device *dev = litest_current_device();
3381 struct libinput *li = dev->libinput;
3382 struct libinput_event *event;
3383 struct libinput_event_tablet_tool *tev;
3384 struct libinput_tablet_tool *tool;
3385
3386 if (!libevdev_has_event_code(dev->evdev,
3387 EV_KEY,
3388 BTN_TOOL_AIRBRUSH))
3389 return;
3390
3391 litest_drain_events(li);
3392
3393 litest_event(dev, EV_KEY, BTN_TOOL_AIRBRUSH, 1);
3394 litest_event(dev, EV_MSC, MSC_SERIAL, 1000);
3395 litest_event(dev, EV_SYN, SYN_REPORT, 0);
3396 libinput_dispatch(li);
3397
3398 event = libinput_get_event(li);
3399 tev = litest_is_tablet_event(event,
3400 LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
3401 tool = libinput_event_tablet_tool_get_tool(tev);
3402
3403 ck_assert_notnull(tool);
3404 ck_assert_int_eq(libinput_tablet_tool_get_type(tool),
3405 LIBINPUT_TABLET_TOOL_TYPE_AIRBRUSH);
3406
3407 ck_assert(libinput_tablet_tool_has_slider(tool));
3408
3409 libinput_event_destroy(event);
3410 }
3411 END_TEST
3412
START_TEST(airbrush_slider)3413 START_TEST(airbrush_slider)
3414 {
3415 struct litest_device *dev = litest_current_device();
3416 struct libinput *li = dev->libinput;
3417 struct libinput_event *event;
3418 struct libinput_event_tablet_tool *tev;
3419 const struct input_absinfo *abs;
3420 double val;
3421 double scale;
3422 double expected;
3423 int v;
3424
3425 if (!libevdev_has_event_code(dev->evdev,
3426 EV_KEY,
3427 BTN_TOOL_AIRBRUSH))
3428 return;
3429
3430 litest_drain_events(li);
3431
3432 abs = libevdev_get_abs_info(dev->evdev, ABS_WHEEL);
3433 ck_assert_notnull(abs);
3434
3435 litest_event(dev, EV_KEY, BTN_TOOL_AIRBRUSH, 1);
3436 litest_event(dev, EV_MSC, MSC_SERIAL, 1000);
3437 litest_event(dev, EV_SYN, SYN_REPORT, 0);
3438
3439 /* start with non-zero */
3440 litest_event(dev, EV_ABS, ABS_WHEEL, 10);
3441 litest_event(dev, EV_SYN, SYN_REPORT, 0);
3442
3443 litest_drain_events(li);
3444
3445 scale = absinfo_range(abs);
3446 for (v = abs->minimum; v < abs->maximum; v += 8) {
3447 litest_event(dev, EV_ABS, ABS_WHEEL, v);
3448 litest_event(dev, EV_SYN, SYN_REPORT, 0);
3449 libinput_dispatch(li);
3450 event = libinput_get_event(li);
3451 tev = litest_is_tablet_event(event,
3452 LIBINPUT_EVENT_TABLET_TOOL_AXIS);
3453 ck_assert(libinput_event_tablet_tool_slider_has_changed(tev));
3454 val = libinput_event_tablet_tool_get_slider_position(tev);
3455
3456 expected = ((v - abs->minimum)/scale) * 2 - 1;
3457 ck_assert_double_eq(val, expected);
3458 ck_assert_double_ge(val, -1.0);
3459 ck_assert_double_le(val, 1.0);
3460 libinput_event_destroy(event);
3461 litest_assert_empty_queue(li);
3462 }
3463 }
3464 END_TEST
3465
START_TEST(artpen_tool)3466 START_TEST(artpen_tool)
3467 {
3468 struct litest_device *dev = litest_current_device();
3469 struct libinput *li = dev->libinput;
3470 struct libinput_event *event;
3471 struct libinput_event_tablet_tool *tev;
3472 struct libinput_tablet_tool *tool;
3473
3474 if (!libevdev_has_event_code(dev->evdev,
3475 EV_ABS,
3476 ABS_Z))
3477 return;
3478
3479 litest_drain_events(li);
3480
3481 litest_event(dev, EV_KEY, BTN_TOOL_PEN, 1);
3482 litest_event(dev, EV_ABS, ABS_MISC, 0x804); /* Art Pen */
3483 litest_event(dev, EV_MSC, MSC_SERIAL, 1000);
3484 litest_event(dev, EV_SYN, SYN_REPORT, 0);
3485 libinput_dispatch(li);
3486 event = libinput_get_event(li);
3487 tev = litest_is_tablet_event(event,
3488 LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
3489 tool = libinput_event_tablet_tool_get_tool(tev);
3490 ck_assert_notnull(tool);
3491 ck_assert_int_eq(libinput_tablet_tool_get_type(tool),
3492 LIBINPUT_TABLET_TOOL_TYPE_PEN);
3493 ck_assert(libinput_tablet_tool_has_rotation(tool));
3494
3495 libinput_event_destroy(event);
3496 }
3497 END_TEST
3498
START_TEST(artpen_rotation)3499 START_TEST(artpen_rotation)
3500 {
3501 struct litest_device *dev = litest_current_device();
3502 struct libinput *li = dev->libinput;
3503 struct libinput_event *event;
3504 struct libinput_event_tablet_tool *tev;
3505 const struct input_absinfo *abs;
3506 double val;
3507 double scale;
3508 int angle;
3509
3510 if (!libevdev_has_event_code(dev->evdev,
3511 EV_ABS,
3512 ABS_Z))
3513 return;
3514
3515 litest_drain_events(li);
3516
3517 abs = libevdev_get_abs_info(dev->evdev, ABS_Z);
3518 ck_assert_notnull(abs);
3519 scale = absinfo_range(abs)/360.0;
3520
3521 litest_event(dev, EV_KEY, BTN_TOOL_BRUSH, 1);
3522 litest_event(dev, EV_ABS, ABS_MISC, 0x804); /* Art Pen */
3523 litest_event(dev, EV_MSC, MSC_SERIAL, 1000);
3524 litest_event(dev, EV_SYN, SYN_REPORT, 0);
3525
3526 litest_event(dev, EV_ABS, ABS_Z, abs->minimum);
3527 litest_event(dev, EV_SYN, SYN_REPORT, 0);
3528
3529 litest_drain_events(li);
3530
3531 for (angle = 8; angle < 360; angle += 8) {
3532 int a = angle * scale + abs->minimum;
3533
3534 litest_event(dev, EV_ABS, ABS_Z, a);
3535 litest_event(dev, EV_SYN, SYN_REPORT, 0);
3536 libinput_dispatch(li);
3537 event = libinput_get_event(li);
3538 tev = litest_is_tablet_event(event,
3539 LIBINPUT_EVENT_TABLET_TOOL_AXIS);
3540 ck_assert(libinput_event_tablet_tool_rotation_has_changed(tev));
3541 val = libinput_event_tablet_tool_get_rotation(tev);
3542
3543 /* artpen has a 90 deg offset cw */
3544 ck_assert_int_eq(round(val), (angle + 90) % 360);
3545
3546 libinput_event_destroy(event);
3547 litest_assert_empty_queue(li);
3548
3549 }
3550 }
3551 END_TEST
3552
START_TEST(tablet_time_usec)3553 START_TEST(tablet_time_usec)
3554 {
3555 struct litest_device *dev = litest_current_device();
3556 struct libinput *li = dev->libinput;
3557 struct libinput_event *event;
3558 struct libinput_event_tablet_tool *tev;
3559 struct axis_replacement axes[] = {
3560 { ABS_DISTANCE, 10 },
3561 { ABS_PRESSURE, 0 },
3562 { -1, -1 }
3563 };
3564 uint64_t time_usec;
3565
3566 litest_drain_events(li);
3567
3568 litest_tablet_proximity_in(dev, 5, 100, axes);
3569 libinput_dispatch(li);
3570
3571 event = libinput_get_event(li);
3572 tev = litest_is_tablet_event(event,
3573 LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
3574 time_usec = libinput_event_tablet_tool_get_time_usec(tev);
3575 ck_assert_int_eq(libinput_event_tablet_tool_get_time(tev),
3576 (uint32_t) (time_usec / 1000));
3577 libinput_event_destroy(event);
3578 }
3579 END_TEST
3580
START_TEST(tablet_pressure_distance_exclusive)3581 START_TEST(tablet_pressure_distance_exclusive)
3582 {
3583 struct litest_device *dev = litest_current_device();
3584 struct libinput *li = dev->libinput;
3585 struct libinput_event *event;
3586 struct libinput_event_tablet_tool *tev;
3587 struct axis_replacement axes[] = {
3588 { ABS_DISTANCE, 10 },
3589 { ABS_PRESSURE, 0 },
3590 { -1, -1 },
3591 };
3592 double pressure, distance;
3593
3594 litest_tablet_proximity_in(dev, 5, 50, axes);
3595 litest_drain_events(li);
3596
3597 /* We have 0.1% pressure above minimum threshold but we're still below
3598 * the tip threshold */
3599 litest_axis_set_value(axes, ABS_PRESSURE, 1.1);
3600 litest_tablet_motion(dev, 70, 70, axes);
3601 libinput_dispatch(li);
3602
3603 event = libinput_get_event(li);
3604 tev = litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_AXIS);
3605
3606 pressure = libinput_event_tablet_tool_get_pressure(tev);
3607 distance = libinput_event_tablet_tool_get_distance(tev);
3608
3609 ck_assert_double_eq(pressure, 0.001);
3610 ck_assert_double_eq(distance, 0.0);
3611 libinput_event_destroy(event);
3612
3613 /* We have pressure and we're above the tip threshold now */
3614 litest_axis_set_value(axes, ABS_PRESSURE, 5.5);
3615 litest_tablet_motion(dev, 70, 70, axes);
3616 libinput_dispatch(li);
3617
3618 event = libinput_get_event(li);
3619 tev = litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_TIP);
3620
3621 pressure = libinput_event_tablet_tool_get_pressure(tev);
3622 distance = libinput_event_tablet_tool_get_distance(tev);
3623
3624 ck_assert_double_gt(pressure, 0.0);
3625 ck_assert_double_eq(distance, 0.0);
3626
3627 libinput_event_destroy(event);
3628 }
3629 END_TEST
3630
START_TEST(tablet_calibration_has_matrix)3631 START_TEST(tablet_calibration_has_matrix)
3632 {
3633 struct litest_device *dev = litest_current_device();
3634 struct libinput_device *d = dev->libinput_device;
3635 enum libinput_config_status status;
3636 int rc;
3637 float calibration[6] = {1, 0, 0, 0, 1, 0};
3638 int has_calibration;
3639
3640 has_calibration = libevdev_has_property(dev->evdev, INPUT_PROP_DIRECT);
3641
3642 rc = libinput_device_config_calibration_has_matrix(d);
3643 ck_assert_int_eq(rc, has_calibration);
3644 rc = libinput_device_config_calibration_get_matrix(d, calibration);
3645 ck_assert_int_eq(rc, 0);
3646 rc = libinput_device_config_calibration_get_default_matrix(d,
3647 calibration);
3648 ck_assert_int_eq(rc, 0);
3649
3650 status = libinput_device_config_calibration_set_matrix(d,
3651 calibration);
3652 if (has_calibration)
3653 ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
3654 else
3655 ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_UNSUPPORTED);
3656 }
3657 END_TEST
3658
START_TEST(tablet_calibration_set_matrix_delta)3659 START_TEST(tablet_calibration_set_matrix_delta)
3660 {
3661 struct litest_device *dev = litest_current_device();
3662 struct libinput *li = dev->libinput;
3663 struct libinput_device *d = dev->libinput_device;
3664 enum libinput_config_status status;
3665 float calibration[6] = {0.5, 0, 0, 0, 0.5, 0};
3666 struct libinput_event *event;
3667 struct libinput_event_tablet_tool *tablet_event;
3668 struct axis_replacement axes[] = {
3669 { ABS_DISTANCE, 0 },
3670 { ABS_PRESSURE, 10 },
3671 { -1, -1 }
3672 };
3673 int has_calibration;
3674 double x, y, dx, dy, mdx, mdy;
3675
3676 has_calibration = libevdev_has_property(dev->evdev, INPUT_PROP_DIRECT);
3677 if (!has_calibration)
3678 return;
3679
3680 litest_drain_events(li);
3681
3682 litest_tablet_proximity_in(dev, 100, 100, axes);
3683 libinput_dispatch(li);
3684 event = libinput_get_event(li);
3685 tablet_event = litest_is_tablet_event(event,
3686 LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
3687 x = libinput_event_tablet_tool_get_x(tablet_event);
3688 y = libinput_event_tablet_tool_get_y(tablet_event);
3689 libinput_event_destroy(event);
3690
3691 event = libinput_get_event(li);
3692 litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_TIP);
3693 libinput_event_destroy(event);
3694
3695 litest_tablet_motion(dev, 80, 80, axes);
3696 libinput_dispatch(li);
3697
3698 event = libinput_get_event(li);
3699 tablet_event = litest_is_tablet_event(event,
3700 LIBINPUT_EVENT_TABLET_TOOL_AXIS);
3701
3702 dx = libinput_event_tablet_tool_get_x(tablet_event) - x;
3703 dy = libinput_event_tablet_tool_get_y(tablet_event) - y;
3704 libinput_event_destroy(event);
3705 litest_tablet_proximity_out(dev);
3706 litest_drain_events(li);
3707
3708 status = libinput_device_config_calibration_set_matrix(d,
3709 calibration);
3710 ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
3711
3712 litest_tablet_proximity_in(dev, 100, 100, axes);
3713 libinput_dispatch(li);
3714 event = libinput_get_event(li);
3715 tablet_event = litest_is_tablet_event(event,
3716 LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
3717 x = libinput_event_tablet_tool_get_x(tablet_event);
3718 y = libinput_event_tablet_tool_get_y(tablet_event);
3719 libinput_event_destroy(event);
3720
3721 event = libinput_get_event(li);
3722 litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_TIP);
3723 libinput_event_destroy(event);
3724
3725 litest_tablet_motion(dev, 80, 80, axes);
3726 libinput_dispatch(li);
3727
3728 event = libinput_get_event(li);
3729 tablet_event = litest_is_tablet_event(event,
3730 LIBINPUT_EVENT_TABLET_TOOL_AXIS);
3731
3732 mdx = libinput_event_tablet_tool_get_x(tablet_event) - x;
3733 mdy = libinput_event_tablet_tool_get_y(tablet_event) - y;
3734 libinput_event_destroy(event);
3735 litest_drain_events(li);
3736
3737 ck_assert_double_gt(dx, mdx * 2 - 1);
3738 ck_assert_double_lt(dx, mdx * 2 + 1);
3739 ck_assert_double_gt(dy, mdy * 2 - 1);
3740 ck_assert_double_lt(dy, mdy * 2 + 1);
3741 }
3742 END_TEST
3743
START_TEST(tablet_calibration_set_matrix)3744 START_TEST(tablet_calibration_set_matrix)
3745 {
3746 struct litest_device *dev = litest_current_device();
3747 struct libinput *li = dev->libinput;
3748 struct libinput_device *d = dev->libinput_device;
3749 enum libinput_config_status status;
3750 float calibration[6] = {0.5, 0, 0, 0, 1, 0};
3751 struct libinput_event *event;
3752 struct libinput_event_tablet_tool *tablet_event;
3753 struct axis_replacement axes[] = {
3754 { ABS_DISTANCE, 10 },
3755 { ABS_PRESSURE, 0 },
3756 { -1, -1 }
3757 };
3758 int has_calibration;
3759 double x, y;
3760
3761 has_calibration = libevdev_has_property(dev->evdev, INPUT_PROP_DIRECT);
3762 if (!has_calibration)
3763 return;
3764
3765 litest_drain_events(li);
3766
3767 status = libinput_device_config_calibration_set_matrix(d,
3768 calibration);
3769 ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
3770
3771 litest_tablet_proximity_in(dev, 100, 100, axes);
3772 libinput_dispatch(li);
3773
3774 event = libinput_get_event(li);
3775 tablet_event = litest_is_tablet_event(event,
3776 LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
3777 x = libinput_event_tablet_tool_get_x_transformed(tablet_event, 100);
3778 y = libinput_event_tablet_tool_get_y_transformed(tablet_event, 100);
3779 libinput_event_destroy(event);
3780
3781 ck_assert_double_gt(x, 49.0);
3782 ck_assert_double_lt(x, 51.0);
3783 ck_assert_double_gt(y, 99.0);
3784 ck_assert_double_lt(y, 100.0);
3785
3786 litest_tablet_proximity_out(dev);
3787 libinput_dispatch(li);
3788 litest_tablet_proximity_in(dev, 50, 50, axes);
3789 litest_tablet_proximity_out(dev);
3790 litest_drain_events(li);
3791
3792 calibration[0] = 1;
3793 calibration[4] = 0.5;
3794 status = libinput_device_config_calibration_set_matrix(d,
3795 calibration);
3796 ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
3797
3798 litest_tablet_proximity_in(dev, 100, 100, axes);
3799 libinput_dispatch(li);
3800
3801 event = libinput_get_event(li);
3802 tablet_event = litest_is_tablet_event(event,
3803 LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
3804 x = libinput_event_tablet_tool_get_x_transformed(tablet_event, 100);
3805 y = libinput_event_tablet_tool_get_y_transformed(tablet_event, 100);
3806 libinput_event_destroy(event);
3807
3808 ck_assert(x > 99.0);
3809 ck_assert(x < 100.0);
3810 ck_assert(y > 49.0);
3811 ck_assert(y < 51.0);
3812
3813 litest_tablet_proximity_out(dev);
3814 }
3815 END_TEST
3816
3817 static void
assert_pressure(struct libinput * li,enum libinput_event_type type,double expected_pressure)3818 assert_pressure(struct libinput *li, enum libinput_event_type type, double expected_pressure)
3819 {
3820 struct libinput_event *event = libinput_get_event(li);
3821 struct libinput_event_tablet_tool *tev = litest_is_tablet_event(event, type);
3822 double pressure = libinput_event_tablet_tool_get_pressure(tev);
3823 ck_assert_double_eq_tol(pressure, expected_pressure, 0.01);
3824 libinput_event_destroy(event);
3825 }
3826
START_TEST(tablet_pressure_offset_set)3827 START_TEST(tablet_pressure_offset_set)
3828 {
3829 struct litest_device *dev = litest_current_device();
3830 struct libinput *li = dev->libinput;
3831 struct libinput_event *event;
3832 struct axis_replacement axes[] = {
3833 { ABS_DISTANCE, 70 },
3834 { ABS_PRESSURE, 20 },
3835 { -1, -1 },
3836 };
3837
3838 litest_drain_events(li);
3839
3840 if (!libevdev_has_event_code(dev->evdev, EV_ABS, ABS_DISTANCE)) {
3841 /* First two prox ins won't do anything, coming with 10% should give
3842 * us ~10% pressure */
3843 for (int i = 0; i < 2; i++) {
3844 litest_tablet_proximity_in(dev, 5, 100, axes);
3845 libinput_dispatch(li);
3846
3847 assert_pressure(li, LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY, 0.20);
3848 assert_pressure(li, LIBINPUT_EVENT_TABLET_TOOL_TIP, 0.20);
3849 litest_tablet_proximity_out(dev);
3850 litest_drain_events(li);
3851 }
3852 }
3853
3854 /* This activates the pressure offset */
3855 litest_tablet_proximity_in(dev, 5, 100, axes);
3856 litest_drain_events(li);
3857
3858 /* Put the pen down, with a pressure high enough to meet the
3859 * new offset */
3860 litest_axis_set_value(axes, ABS_DISTANCE, 0);
3861 litest_axis_set_value(axes, ABS_PRESSURE, 26);
3862
3863 /* Tablet motion above threshold should trigger axis + tip down. Use
3864 * the litest motion helper here to avoid false positives caused by
3865 * BTN_TOUCH */
3866 litest_tablet_motion(dev, 70, 70, axes);
3867 libinput_dispatch(li);
3868 event = libinput_get_event(li);
3869 litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_TIP);
3870 libinput_event_destroy(event);
3871
3872 /* Reduce pressure to just a tick over the offset, otherwise we get
3873 * the tip up event again */
3874 litest_axis_set_value(axes, ABS_PRESSURE, 20.1);
3875 litest_tablet_motion(dev, 70, 70, axes);
3876 libinput_dispatch(li);
3877
3878 /* we can't actually get a real 0.0 because that would trigger a tip
3879 up. but it's close enough to zero. */
3880 assert_pressure(li, LIBINPUT_EVENT_TABLET_TOOL_AXIS, 0.01);
3881 litest_drain_events(li);
3882
3883 litest_axis_set_value(axes, ABS_PRESSURE, 21);
3884 litest_tablet_motion(dev, 70, 70, axes);
3885
3886 libinput_dispatch(li);
3887 assert_pressure(li, LIBINPUT_EVENT_TABLET_TOOL_AXIS, 0.015);
3888
3889
3890 /* Make sure we can reach the upper range too */
3891 litest_axis_set_value(axes, ABS_PRESSURE, 100);
3892 litest_tablet_motion(dev, 70, 70, axes);
3893
3894 libinput_dispatch(li);
3895 assert_pressure(li, LIBINPUT_EVENT_TABLET_TOOL_AXIS, 1.0);
3896
3897 /* Tablet motion at offset should trigger tip up. Use
3898 * the litest motion helper here to avoid false positives caused by
3899 * BTN_TOUCH */
3900 litest_axis_set_value(axes, ABS_PRESSURE, 20);
3901 litest_tablet_motion(dev, 71, 71, axes);
3902 libinput_dispatch(li);
3903 event = libinput_get_event(li);
3904 litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_TIP);
3905 libinput_event_destroy(event);
3906
3907 }
3908 END_TEST
3909
START_TEST(tablet_pressure_offset_decrease)3910 START_TEST(tablet_pressure_offset_decrease)
3911 {
3912 struct litest_device *dev = litest_current_device();
3913 struct libinput *li = dev->libinput;
3914 struct axis_replacement axes[] = {
3915 { ABS_DISTANCE, 70 },
3916 { ABS_PRESSURE, 20 },
3917 { -1, -1 },
3918 };
3919
3920 /* offset 20 on prox in */
3921 litest_tablet_proximity_in(dev, 5, 100, axes);
3922 litest_tablet_proximity_out(dev);
3923 litest_drain_events(li);
3924
3925 /* offset 15 on prox in - this one is so we trigger on the next prox
3926 * in for the no-distance tablets */
3927 litest_axis_set_value(axes, ABS_PRESSURE, 15);
3928 litest_tablet_proximity_in(dev, 5, 100, axes);
3929 litest_tablet_proximity_out(dev);
3930 litest_drain_events(li);
3931
3932 /* a reduced pressure value must reduce the offset */
3933 litest_axis_set_value(axes, ABS_PRESSURE, 10);
3934 litest_tablet_proximity_in(dev, 5, 100, axes);
3935 litest_tablet_proximity_out(dev);
3936 litest_drain_events(li);
3937
3938 litest_tablet_proximity_in(dev, 5, 100, axes);
3939 libinput_dispatch(li);
3940 assert_pressure(li, LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY, 0.0);
3941 litest_drain_events(li);
3942
3943 /* trigger the pressure threshold */
3944 litest_axis_set_value(axes, ABS_PRESSURE, 15);
3945 litest_tablet_tip_down(dev, 70, 70, axes);
3946 libinput_dispatch(li);
3947
3948 /* offset 10 + lower threshold of ~1% of original range,
3949 * value 15 is 5% over original range but with the above taken into
3950 * account it's closer to 5% into the remaining effective 89% range
3951 */
3952 assert_pressure(li, LIBINPUT_EVENT_TABLET_TOOL_TIP, 0.05);
3953
3954 /* a reduced pressure value during motion events must reduce the offset
3955 * - here back down to 5%.
3956 * FIXME: this causes a tip up event which is a bug but working around
3957 * this is more effort than it's worth for what should be quite a niche
3958 * case.
3959 */
3960 litest_axis_set_value(axes, ABS_PRESSURE, 5);
3961 litest_tablet_motion(dev, 75, 75, axes);
3962 libinput_dispatch(li);
3963 assert_pressure(li, LIBINPUT_EVENT_TABLET_TOOL_TIP, 0.0);
3964 litest_drain_events(li);
3965
3966 /* back to 10% should now give us 5% pressure because we reduced the
3967 * offset */
3968 litest_axis_set_value(axes, ABS_PRESSURE, 10);
3969 litest_tablet_motion(dev, 75, 75, axes);
3970 libinput_dispatch(li);
3971 assert_pressure(li, LIBINPUT_EVENT_TABLET_TOOL_TIP, 0.05);
3972 litest_drain_events(li);
3973 }
3974 END_TEST
3975
START_TEST(tablet_pressure_offset_increase)3976 START_TEST(tablet_pressure_offset_increase)
3977 {
3978 struct litest_device *dev = litest_current_device();
3979 struct libinput *li = dev->libinput;
3980 struct axis_replacement axes[] = {
3981 { ABS_DISTANCE, 70 },
3982 { ABS_PRESSURE, 20 },
3983 { -1, -1 },
3984 };
3985
3986 /* offset 20 on first prox in */
3987 litest_tablet_proximity_in(dev, 5, 100, axes);
3988 litest_tablet_proximity_out(dev);
3989 litest_drain_events(li);
3990
3991 /* offset 25 on second prox in - must not change the offset */
3992 litest_axis_set_value(axes, ABS_PRESSURE, 25);
3993 litest_tablet_proximity_in(dev, 5, 100, axes);
3994 litest_tablet_proximity_out(dev);
3995 litest_drain_events(li);
3996
3997 /* offset 30 on third prox in - must not change the offset */
3998 litest_axis_set_value(axes, ABS_PRESSURE, 30);
3999 litest_tablet_proximity_in(dev, 5, 100, axes);
4000 litest_drain_events(li);
4001
4002 litest_axis_set_value(axes, ABS_DISTANCE, 0);
4003 litest_axis_set_value(axes, ABS_PRESSURE, 31);
4004 litest_tablet_tip_down(dev, 70, 70, axes);
4005 libinput_dispatch(li);
4006 litest_drain_events(li);
4007
4008 litest_axis_set_value(axes, ABS_PRESSURE, 30);
4009 litest_tablet_motion(dev, 70, 70, axes);
4010 libinput_dispatch(li);
4011
4012 /* offset 20 + lower threshold of 1% of original range,
4013 * value 30 is 5% over original range but with the above taken into
4014 * account it's closer to 12% into the remaining effective 79% range
4015 */
4016 assert_pressure(li, LIBINPUT_EVENT_TABLET_TOOL_AXIS, 0.12);
4017
4018 litest_drain_events(li);
4019
4020 litest_axis_set_value(axes, ABS_PRESSURE, 20);
4021 litest_tablet_motion(dev, 70, 70, axes);
4022 libinput_dispatch(li);
4023
4024 assert_pressure(li, LIBINPUT_EVENT_TABLET_TOOL_TIP, 0.0);
4025 }
4026 END_TEST
4027
START_TEST(tablet_pressure_min_max)4028 START_TEST(tablet_pressure_min_max)
4029 {
4030 struct litest_device *dev = litest_current_device();
4031 struct libinput *li = dev->libinput;
4032 struct axis_replacement axes[] = {
4033 { ABS_DISTANCE, 10 },
4034 { ABS_PRESSURE, 0 },
4035 { -1, -1 },
4036 };
4037
4038 if (!libevdev_has_event_code(dev->evdev, EV_ABS, ABS_PRESSURE))
4039 return;
4040
4041 litest_tablet_proximity_in(dev, 5, 50, axes);
4042 litest_drain_events(li);
4043 libinput_dispatch(li);
4044
4045 litest_axis_set_value(axes, ABS_DISTANCE, 0);
4046 /* Default pressure threshold is 1% of range */
4047 litest_axis_set_value(axes, ABS_PRESSURE, 1.1);
4048 litest_tablet_motion(dev, 5, 50, axes);
4049 libinput_dispatch(li);
4050 assert_pressure(li, LIBINPUT_EVENT_TABLET_TOOL_AXIS, 0.0);
4051
4052 /* skip over pressure-based tip down */
4053 litest_axis_set_value(axes, ABS_PRESSURE, 90);
4054 litest_tablet_motion(dev, 5, 50, axes);
4055 litest_drain_events(li);
4056
4057 /* need to fill the motion history */
4058 litest_axis_set_value(axes, ABS_PRESSURE, 100);
4059 litest_tablet_motion(dev, 5, 50, axes);
4060 litest_tablet_motion(dev, 6, 50, axes);
4061 litest_tablet_motion(dev, 7, 50, axes);
4062 litest_tablet_motion(dev, 8, 50, axes);
4063 litest_drain_events(li);
4064
4065 litest_tablet_motion(dev, 5, 50, axes);
4066 libinput_dispatch(li);
4067 assert_pressure(li, LIBINPUT_EVENT_TABLET_TOOL_AXIS, 1.0);
4068 }
4069 END_TEST
4070
START_TEST(tablet_pressure_range)4071 START_TEST(tablet_pressure_range)
4072 {
4073 struct litest_device *dev = litest_current_device();
4074 struct libinput *li = dev->libinput;
4075 struct libinput_event *event;
4076 struct libinput_event_tablet_tool *tev;
4077 struct axis_replacement axes[] = {
4078 { ABS_DISTANCE, 0 },
4079 { ABS_PRESSURE, 10 },
4080 { -1, -1 },
4081 };
4082 int pressure;
4083 double p;
4084
4085 litest_tablet_proximity_in(dev, 5, 100, axes);
4086 litest_drain_events(li);
4087 libinput_dispatch(li);
4088
4089 for (pressure = 10; pressure <= 100; pressure += 10) {
4090 litest_axis_set_value(axes, ABS_PRESSURE, pressure);
4091 litest_tablet_motion(dev, 70, 70, axes);
4092 libinput_dispatch(li);
4093
4094 event = libinput_get_event(li);
4095 tev = litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_AXIS);
4096 p = libinput_event_tablet_tool_get_pressure(tev);
4097 ck_assert_double_ge(p, 0.0);
4098 ck_assert_double_le(p, 1.0);
4099 libinput_event_destroy(event);
4100 }
4101 }
4102 END_TEST
4103
4104 static void
pressure_threshold_warning(struct libinput * libinput,enum libinput_log_priority priority,const char * format,va_list args)4105 pressure_threshold_warning(struct libinput *libinput,
4106 enum libinput_log_priority priority,
4107 const char *format,
4108 va_list args)
4109 {
4110 struct litest_user_data *user_data = libinput_get_user_data(libinput);
4111 int *warning_triggered = user_data->private;
4112
4113 if (priority == LIBINPUT_LOG_PRIORITY_ERROR &&
4114 strstr(format, "pressure offset greater"))
4115 (*warning_triggered)++;
4116 }
4117
START_TEST(tablet_pressure_offset_exceed_threshold)4118 START_TEST(tablet_pressure_offset_exceed_threshold)
4119 {
4120 struct litest_device *dev = litest_current_device();
4121 struct libinput *li = dev->libinput;
4122 struct axis_replacement axes[] = {
4123 { ABS_DISTANCE, 70 },
4124 { ABS_PRESSURE, 60 },
4125 { -1, -1 },
4126 };
4127 int warning_triggered = 0;
4128 struct litest_user_data *user_data = libinput_get_user_data(li);
4129
4130 /* Tablet without distance: offset takes effect on third prox-in */
4131 if (!libevdev_has_event_code(dev->evdev, EV_ABS, ABS_DISTANCE)) {
4132 for (int i = 0; i < 2; i++) {
4133 litest_tablet_proximity_in(dev, 5, 100, axes);
4134 litest_tablet_proximity_out(dev);
4135 libinput_dispatch(li);
4136 }
4137 }
4138
4139 litest_drain_events(li);
4140
4141 user_data->private = &warning_triggered;
4142
4143 libinput_log_set_handler(li, pressure_threshold_warning);
4144 litest_tablet_proximity_in(dev, 5, 100, axes);
4145 libinput_dispatch(li);
4146 assert_pressure(li, LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY, 0.60);
4147
4148 ck_assert_int_eq(warning_triggered, 1);
4149 litest_restore_log_handler(li);
4150 }
4151 END_TEST
4152
START_TEST(tablet_pressure_offset_none_for_zero_distance)4153 START_TEST(tablet_pressure_offset_none_for_zero_distance)
4154 {
4155 struct litest_device *dev = litest_current_device();
4156 struct libinput *li = dev->libinput;
4157 struct axis_replacement axes[] = {
4158 { ABS_DISTANCE, 0 },
4159 { ABS_PRESSURE, 20 },
4160 { -1, -1 },
4161 };
4162
4163 litest_drain_events(li);
4164
4165 /* we're going straight to touch on proximity, make sure we don't
4166 * offset the pressure here */
4167 litest_push_event_frame(dev);
4168 litest_tablet_proximity_in(dev, 5, 100, axes);
4169 litest_tablet_tip_down(dev, 5, 100, axes);
4170 litest_pop_event_frame(dev);
4171 libinput_dispatch(li);
4172
4173 assert_pressure(li, LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY, 0.20);
4174 }
4175 END_TEST
4176
START_TEST(tablet_pressure_offset_none_for_small_distance)4177 START_TEST(tablet_pressure_offset_none_for_small_distance)
4178 {
4179 struct litest_device *dev = litest_current_device();
4180 struct libinput *li = dev->libinput;
4181 struct axis_replacement axes[] = {
4182 { ABS_DISTANCE, 20 },
4183 { ABS_PRESSURE, 20 },
4184 { -1, -1 },
4185 };
4186
4187 /* stylus too close to the tablet on the proximity in, ignore any
4188 * pressure offset */
4189 litest_tablet_proximity_in(dev, 5, 100, axes);
4190 litest_drain_events(li);
4191 libinput_dispatch(li);
4192
4193 litest_axis_set_value(axes, ABS_DISTANCE, 0);
4194 litest_axis_set_value(axes, ABS_PRESSURE, 21);
4195 litest_tablet_tip_down(dev, 70, 70, axes);
4196 litest_drain_events(li);
4197
4198 litest_axis_set_value(axes, ABS_PRESSURE, 20);
4199 litest_tablet_motion(dev, 70, 70, axes);
4200 libinput_dispatch(li);
4201
4202 assert_pressure(li, LIBINPUT_EVENT_TABLET_TOOL_AXIS, 0.20);
4203 }
4204 END_TEST
4205
START_TEST(tablet_distance_range)4206 START_TEST(tablet_distance_range)
4207 {
4208 struct litest_device *dev = litest_current_device();
4209 struct libinput *li = dev->libinput;
4210 struct libinput_event *event;
4211 struct libinput_event_tablet_tool *tev;
4212 struct axis_replacement axes[] = {
4213 { ABS_DISTANCE, 20 },
4214 { ABS_PRESSURE, 0 },
4215 { -1, -1 },
4216 };
4217 int distance;
4218 double dist;
4219
4220 litest_tablet_proximity_in(dev, 5, 100, axes);
4221 litest_drain_events(li);
4222 libinput_dispatch(li);
4223
4224 for (distance = 0; distance <= 100; distance += 10) {
4225 litest_axis_set_value(axes, ABS_DISTANCE, distance);
4226 litest_tablet_motion(dev, 70, 70, axes);
4227 libinput_dispatch(li);
4228
4229 event = libinput_get_event(li);
4230 tev = litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_AXIS);
4231 dist = libinput_event_tablet_tool_get_distance(tev);
4232 ck_assert_double_ge(dist, 0.0);
4233 ck_assert_double_le(dist, 1.0);
4234 libinput_event_destroy(event);
4235 }
4236 }
4237 END_TEST
4238
START_TEST(tilt_available)4239 START_TEST(tilt_available)
4240 {
4241 struct litest_device *dev = litest_current_device();
4242 struct libinput *li = dev->libinput;
4243 struct libinput_event *event;
4244 struct libinput_event_tablet_tool *tev;
4245 struct libinput_tablet_tool *tool;
4246 struct axis_replacement axes[] = {
4247 { ABS_DISTANCE, 10 },
4248 { ABS_PRESSURE, 0 },
4249 { ABS_TILT_X, 80 },
4250 { ABS_TILT_Y, 20 },
4251 { -1, -1 }
4252 };
4253
4254 litest_drain_events(li);
4255
4256 litest_tablet_proximity_in(dev, 10, 10, axes);
4257 libinput_dispatch(li);
4258 event = libinput_get_event(li);
4259 tev = litest_is_tablet_event(event,
4260 LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
4261
4262 tool = libinput_event_tablet_tool_get_tool(tev);
4263 ck_assert(libinput_tablet_tool_has_tilt(tool));
4264
4265 libinput_event_destroy(event);
4266 }
4267 END_TEST
4268
START_TEST(tilt_not_available)4269 START_TEST(tilt_not_available)
4270 {
4271 struct litest_device *dev = litest_current_device();
4272 struct libinput *li = dev->libinput;
4273 struct libinput_event *event;
4274 struct libinput_event_tablet_tool *tev;
4275 struct libinput_tablet_tool *tool;
4276 struct axis_replacement axes[] = {
4277 { ABS_DISTANCE, 10 },
4278 { ABS_PRESSURE, 0 },
4279 { ABS_TILT_X, 80 },
4280 { ABS_TILT_Y, 20 },
4281 { -1, -1 }
4282 };
4283
4284 litest_drain_events(li);
4285
4286 litest_tablet_proximity_in(dev, 10, 10, axes);
4287 libinput_dispatch(li);
4288 event = libinput_get_event(li);
4289 tev = litest_is_tablet_event(event,
4290 LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
4291
4292 tool = libinput_event_tablet_tool_get_tool(tev);
4293 ck_assert(!libinput_tablet_tool_has_tilt(tool));
4294
4295 libinput_event_destroy(event);
4296 }
4297 END_TEST
4298
START_TEST(tilt_x)4299 START_TEST(tilt_x)
4300 {
4301 struct litest_device *dev = litest_current_device();
4302 struct libinput *li = dev->libinput;
4303 struct libinput_event *event;
4304 struct libinput_event_tablet_tool *tev;
4305 struct axis_replacement axes[] = {
4306 { ABS_DISTANCE, 10 },
4307 { ABS_PRESSURE, 0 },
4308 { ABS_TILT_X, 10 },
4309 { ABS_TILT_Y, 0 },
4310 { -1, -1 }
4311 };
4312 double tx, ty;
4313 int tilt;
4314 double expected_tx;
4315
4316 litest_drain_events(li);
4317
4318 litest_tablet_proximity_in(dev, 10, 10, axes);
4319 libinput_dispatch(li);
4320 event = libinput_get_event(li);
4321 tev = litest_is_tablet_event(event,
4322 LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
4323
4324 /* 90% of the actual axis but mapped into a [-64, 64] tilt range, so
4325 * we expect 51 degrees ± rounding errors */
4326 tx = libinput_event_tablet_tool_get_tilt_x(tev);
4327 ck_assert_double_le(tx, -50);
4328 ck_assert_double_ge(tx, -52);
4329
4330 ty = libinput_event_tablet_tool_get_tilt_y(tev);
4331 ck_assert_double_ge(ty, -65);
4332 ck_assert_double_lt(ty, -63);
4333
4334 libinput_event_destroy(event);
4335
4336 expected_tx = -64.0;
4337
4338 litest_axis_set_value(axes, ABS_DISTANCE, 0);
4339 litest_axis_set_value(axes, ABS_PRESSURE, 1);
4340
4341 for (tilt = 0; tilt <= 100; tilt += 5) {
4342 litest_axis_set_value(axes, ABS_TILT_X, tilt);
4343 /* work around smoothing */
4344 litest_tablet_motion(dev, 10, 10, axes);
4345 litest_tablet_motion(dev, 10, 11, axes);
4346 litest_tablet_motion(dev, 10, 10, axes);
4347 litest_drain_events(li);
4348 litest_tablet_motion(dev, 10, 11, axes);
4349 libinput_dispatch(li);
4350 event = libinput_get_event(li);
4351 tev = litest_is_tablet_event(event,
4352 LIBINPUT_EVENT_TABLET_TOOL_AXIS);
4353
4354 tx = libinput_event_tablet_tool_get_tilt_x(tev);
4355 ck_assert_double_ge(tx, expected_tx - 2);
4356 ck_assert_double_le(tx, expected_tx + 2);
4357
4358 ty = libinput_event_tablet_tool_get_tilt_y(tev);
4359 ck_assert_double_ge(ty, -65);
4360 ck_assert_double_lt(ty, -63);
4361
4362 libinput_event_destroy(event);
4363
4364 expected_tx = tx + 6.04;
4365 }
4366
4367 /* the last event must reach the max */
4368 ck_assert_double_ge(tx, 63.0);
4369 ck_assert_double_le(tx, 64.0);
4370 }
4371 END_TEST
4372
START_TEST(tilt_y)4373 START_TEST(tilt_y)
4374 {
4375 struct litest_device *dev = litest_current_device();
4376 struct libinput *li = dev->libinput;
4377 struct libinput_event *event;
4378 struct libinput_event_tablet_tool *tev;
4379 struct axis_replacement axes[] = {
4380 { ABS_DISTANCE, 10 },
4381 { ABS_PRESSURE, 0 },
4382 { ABS_TILT_X, 0 },
4383 { ABS_TILT_Y, 10 },
4384 { -1, -1 }
4385 };
4386 double tx, ty;
4387 int tilt;
4388 double expected_ty;
4389
4390 litest_drain_events(li);
4391
4392 litest_tablet_proximity_in(dev, 10, 10, axes);
4393 libinput_dispatch(li);
4394 event = libinput_get_event(li);
4395 tev = litest_is_tablet_event(event,
4396 LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
4397
4398 /* 90% of the actual axis but mapped into a [-64, 64] tilt range, so
4399 * we expect 50 degrees ± rounding errors */
4400 ty = libinput_event_tablet_tool_get_tilt_y(tev);
4401 ck_assert_double_le(ty, -50);
4402 ck_assert_double_ge(ty, -52);
4403
4404 tx = libinput_event_tablet_tool_get_tilt_x(tev);
4405 ck_assert_double_ge(tx, -65);
4406 ck_assert_double_lt(tx, -63);
4407
4408 libinput_event_destroy(event);
4409
4410 expected_ty = -64;
4411
4412 litest_axis_set_value(axes, ABS_DISTANCE, 0);
4413 litest_axis_set_value(axes, ABS_PRESSURE, 1);
4414
4415 for (tilt = 0; tilt <= 100; tilt += 5) {
4416 litest_axis_set_value(axes, ABS_TILT_Y, tilt);
4417 /* work around smoothing */
4418 litest_tablet_motion(dev, 10, 11, axes);
4419 litest_tablet_motion(dev, 10, 10, axes);
4420 litest_tablet_motion(dev, 10, 11, axes);
4421 litest_drain_events(li);
4422 litest_tablet_motion(dev, 10, 10, axes);
4423 libinput_dispatch(li);
4424 event = libinput_get_event(li);
4425 tev = litest_is_tablet_event(event,
4426 LIBINPUT_EVENT_TABLET_TOOL_AXIS);
4427
4428 ty = libinput_event_tablet_tool_get_tilt_y(tev);
4429 ck_assert_double_ge(ty, expected_ty - 2);
4430 ck_assert_double_le(ty, expected_ty + 2);
4431
4432 tx = libinput_event_tablet_tool_get_tilt_x(tev);
4433 ck_assert_double_ge(tx, -65);
4434 ck_assert_double_lt(tx, -63);
4435
4436 libinput_event_destroy(event);
4437
4438 expected_ty = ty + 6;
4439 }
4440
4441 /* the last event must reach the max */
4442 ck_assert_double_ge(ty, 63.0);
4443 ck_assert_double_le(tx, 64.0);
4444 }
4445 END_TEST
4446
START_TEST(relative_no_profile)4447 START_TEST(relative_no_profile)
4448 {
4449 struct litest_device *dev = litest_current_device();
4450 struct libinput_device *device = dev->libinput_device;
4451 enum libinput_config_accel_profile profile;
4452 enum libinput_config_status status;
4453 uint32_t profiles;
4454
4455 ck_assert(libinput_device_config_accel_is_available(device));
4456
4457 profile = libinput_device_config_accel_get_default_profile(device);
4458 ck_assert_int_eq(profile, LIBINPUT_CONFIG_ACCEL_PROFILE_NONE);
4459
4460 profile = libinput_device_config_accel_get_profile(device);
4461 ck_assert_int_eq(profile, LIBINPUT_CONFIG_ACCEL_PROFILE_NONE);
4462
4463 profiles = libinput_device_config_accel_get_profiles(device);
4464 ck_assert_int_eq(profiles & LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE, 0);
4465 ck_assert_int_eq(profiles & LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT, 0);
4466
4467 status = libinput_device_config_accel_set_profile(device,
4468 LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT);
4469 ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_UNSUPPORTED);
4470 profile = libinput_device_config_accel_get_profile(device);
4471 ck_assert_int_eq(profile, LIBINPUT_CONFIG_ACCEL_PROFILE_NONE);
4472
4473 status = libinput_device_config_accel_set_profile(device,
4474 LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE);
4475 ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_UNSUPPORTED);
4476 profile = libinput_device_config_accel_get_profile(device);
4477 ck_assert_int_eq(profile, LIBINPUT_CONFIG_ACCEL_PROFILE_NONE);
4478 }
4479 END_TEST
4480
START_TEST(relative_no_delta_prox_in)4481 START_TEST(relative_no_delta_prox_in)
4482 {
4483 struct litest_device *dev = litest_current_device();
4484 struct libinput *li = dev->libinput;
4485 struct libinput_event *event;
4486 struct libinput_event_tablet_tool *tev;
4487 struct axis_replacement axes[] = {
4488 { ABS_DISTANCE, 10 },
4489 { ABS_PRESSURE, 0 },
4490 { -1, -1 }
4491 };
4492 double dx, dy;
4493
4494 litest_drain_events(li);
4495
4496 litest_tablet_proximity_in(dev, 10, 10, axes);
4497 libinput_dispatch(li);
4498 event = libinput_get_event(li);
4499 tev = litest_is_tablet_event(event,
4500 LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
4501 dx = libinput_event_tablet_tool_get_dx(tev);
4502 dy = libinput_event_tablet_tool_get_dy(tev);
4503 ck_assert(dx == 0.0);
4504 ck_assert(dy == 0.0);
4505
4506 libinput_event_destroy(event);
4507 }
4508 END_TEST
4509
START_TEST(relative_delta)4510 START_TEST(relative_delta)
4511 {
4512 struct litest_device *dev = litest_current_device();
4513 struct libinput *li = dev->libinput;
4514 struct libinput_event *event;
4515 struct libinput_event_tablet_tool *tev;
4516 struct axis_replacement axes[] = {
4517 { ABS_DISTANCE, 10 },
4518 { ABS_PRESSURE, 0 },
4519 { -1, -1 }
4520 };
4521 double dx, dy;
4522
4523 litest_tablet_proximity_in(dev, 10, 10, axes);
4524 litest_drain_events(li);
4525
4526 /* flush the motion history */
4527 for (int i = 0; i < 5; i ++)
4528 litest_tablet_motion(dev, 10 + i, 10, axes);
4529 litest_drain_events(li);
4530
4531 litest_tablet_motion(dev, 20, 10, axes);
4532 libinput_dispatch(li);
4533
4534 event = libinput_get_event(li);
4535 tev = litest_is_tablet_event(event,
4536 LIBINPUT_EVENT_TABLET_TOOL_AXIS);
4537 dx = libinput_event_tablet_tool_get_dx(tev);
4538 dy = libinput_event_tablet_tool_get_dy(tev);
4539 ck_assert(dx > 0.0);
4540 ck_assert(dy == 0.0);
4541 libinput_event_destroy(event);
4542
4543 /* flush the motion history */
4544 for (int i = 0; i < 5; i ++)
4545 litest_tablet_motion(dev, 20 - i, 10, axes);
4546 litest_drain_events(li);
4547
4548 litest_tablet_motion(dev, 5, 10, axes);
4549 libinput_dispatch(li);
4550 event = libinput_get_event(li);
4551 tev = litest_is_tablet_event(event,
4552 LIBINPUT_EVENT_TABLET_TOOL_AXIS);
4553 dx = libinput_event_tablet_tool_get_dx(tev);
4554 dy = libinput_event_tablet_tool_get_dy(tev);
4555 ck_assert(dx < 0.0);
4556 ck_assert(dy == 0.0);
4557 libinput_event_destroy(event);
4558
4559 /* flush the motion history */
4560 for (int i = 0; i < 5; i ++)
4561 litest_tablet_motion(dev, 5, 10 + i, axes);
4562 litest_drain_events(li);
4563
4564 litest_tablet_motion(dev, 5, 20, axes);
4565 libinput_dispatch(li);
4566 event = libinput_get_event(li);
4567 tev = litest_is_tablet_event(event,
4568 LIBINPUT_EVENT_TABLET_TOOL_AXIS);
4569 dx = libinput_event_tablet_tool_get_dx(tev);
4570 dy = libinput_event_tablet_tool_get_dy(tev);
4571 ck_assert(dx == 0.0);
4572 ck_assert(dy > 0.0);
4573 libinput_event_destroy(event);
4574
4575
4576 /* flush the motion history */
4577 for (int i = 0; i < 5; i ++)
4578 litest_tablet_motion(dev, 5, 20 - i, axes);
4579 litest_drain_events(li);
4580
4581 litest_tablet_motion(dev, 5, 10, axes);
4582 libinput_dispatch(li);
4583 event = libinput_get_event(li);
4584 tev = litest_is_tablet_event(event,
4585 LIBINPUT_EVENT_TABLET_TOOL_AXIS);
4586 dx = libinput_event_tablet_tool_get_dx(tev);
4587 dy = libinput_event_tablet_tool_get_dy(tev);
4588 ck_assert(dx == 0.0);
4589 ck_assert(dy < 0.0);
4590 libinput_event_destroy(event);
4591 }
4592 END_TEST
4593
START_TEST(relative_no_delta_on_tip)4594 START_TEST(relative_no_delta_on_tip)
4595 {
4596 struct litest_device *dev = litest_current_device();
4597 struct libinput *li = dev->libinput;
4598 struct libinput_event *event;
4599 struct libinput_event_tablet_tool *tev;
4600 struct axis_replacement axes[] = {
4601 { ABS_DISTANCE, 10 },
4602 { ABS_PRESSURE, 0 },
4603 { -1, -1 }
4604 };
4605 double dx, dy;
4606
4607 litest_tablet_proximity_in(dev, 10, 10, axes);
4608 litest_drain_events(li);
4609
4610 litest_tablet_motion(dev, 20, 10, axes);
4611 litest_drain_events(li);
4612
4613 /* tip down */
4614 litest_axis_set_value(axes, ABS_DISTANCE, 0);
4615 litest_axis_set_value(axes, ABS_PRESSURE, 30);
4616 litest_tablet_tip_down(dev, 30, 20, axes);
4617
4618 libinput_dispatch(li);
4619 event = libinput_get_event(li);
4620 tev = litest_is_tablet_event(event,
4621 LIBINPUT_EVENT_TABLET_TOOL_TIP);
4622 ck_assert(libinput_event_tablet_tool_x_has_changed(tev));
4623 ck_assert(libinput_event_tablet_tool_y_has_changed(tev));
4624 dx = libinput_event_tablet_tool_get_dx(tev);
4625 dy = libinput_event_tablet_tool_get_dy(tev);
4626 ck_assert(dx == 0.0);
4627 ck_assert(dy == 0.0);
4628 libinput_event_destroy(event);
4629
4630 /* normal motion */
4631 litest_tablet_motion(dev, 40, 30, axes);
4632 libinput_dispatch(li);
4633 event = libinput_get_event(li);
4634 tev = litest_is_tablet_event(event,
4635 LIBINPUT_EVENT_TABLET_TOOL_AXIS);
4636 dx = libinput_event_tablet_tool_get_dx(tev);
4637 dy = libinput_event_tablet_tool_get_dy(tev);
4638 ck_assert(dx > 0.0);
4639 ck_assert(dy > 0.0);
4640 libinput_event_destroy(event);
4641
4642 /* tip up */
4643 litest_axis_set_value(axes, ABS_DISTANCE, 10);
4644 litest_axis_set_value(axes, ABS_PRESSURE, 0);
4645 litest_tablet_tip_up(dev, 50, 40, axes);
4646 libinput_dispatch(li);
4647 event = libinput_get_event(li);
4648 tev = litest_is_tablet_event(event,
4649 LIBINPUT_EVENT_TABLET_TOOL_TIP);
4650 ck_assert(libinput_event_tablet_tool_x_has_changed(tev));
4651 ck_assert(libinput_event_tablet_tool_y_has_changed(tev));
4652 dx = libinput_event_tablet_tool_get_dx(tev);
4653 dy = libinput_event_tablet_tool_get_dy(tev);
4654 ck_assert(dx == 0.0);
4655 ck_assert(dy == 0.0);
4656 libinput_event_destroy(event);
4657 }
4658 END_TEST
4659
START_TEST(relative_calibration)4660 START_TEST(relative_calibration)
4661 {
4662 struct litest_device *dev = litest_current_device();
4663 struct libinput *li = dev->libinput;
4664 struct libinput_event *event;
4665 struct libinput_event_tablet_tool *tev;
4666 struct axis_replacement axes[] = {
4667 { ABS_DISTANCE, 10 },
4668 { ABS_PRESSURE, 0 },
4669 { -1, -1 }
4670 };
4671 double dx, dy;
4672 float calibration[] = { -1, 0, 1, 0, -1, 1 };
4673 enum libinput_config_status status;
4674
4675 if (!libinput_device_config_calibration_has_matrix(dev->libinput_device))
4676 return;
4677
4678 status = libinput_device_config_calibration_set_matrix(
4679 dev->libinput_device,
4680 calibration);
4681 ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
4682
4683 litest_tablet_proximity_in(dev, 10, 10, axes);
4684 litest_drain_events(li);
4685
4686 litest_tablet_motion(dev, 20, 10, axes);
4687 libinput_dispatch(li);
4688
4689 event = libinput_get_event(li);
4690 tev = litest_is_tablet_event(event,
4691 LIBINPUT_EVENT_TABLET_TOOL_AXIS);
4692 dx = libinput_event_tablet_tool_get_dx(tev);
4693 dy = libinput_event_tablet_tool_get_dy(tev);
4694 ck_assert(dx < 0.0);
4695 ck_assert(dy == 0.0);
4696 libinput_event_destroy(event);
4697
4698 /* work around axis smoothing */
4699 litest_tablet_motion(dev, 19, 10, axes);
4700 litest_tablet_motion(dev, 18, 10, axes);
4701 litest_tablet_motion(dev, 17, 10, axes);
4702 litest_drain_events(li);
4703
4704 litest_tablet_motion(dev, 5, 10, axes);
4705 libinput_dispatch(li);
4706 event = libinput_get_event(li);
4707 tev = litest_is_tablet_event(event,
4708 LIBINPUT_EVENT_TABLET_TOOL_AXIS);
4709 dx = libinput_event_tablet_tool_get_dx(tev);
4710 dy = libinput_event_tablet_tool_get_dy(tev);
4711 ck_assert(dx > 0.0);
4712 ck_assert(dy == 0.0);
4713 libinput_event_destroy(event);
4714
4715 /* work around axis smoothing */
4716 litest_tablet_motion(dev, 5, 11, axes);
4717 litest_tablet_motion(dev, 5, 12, axes);
4718 litest_tablet_motion(dev, 5, 13, axes);
4719 litest_drain_events(li);
4720
4721 litest_tablet_motion(dev, 5, 20, axes);
4722 libinput_dispatch(li);
4723 event = libinput_get_event(li);
4724 tev = litest_is_tablet_event(event,
4725 LIBINPUT_EVENT_TABLET_TOOL_AXIS);
4726 dx = libinput_event_tablet_tool_get_dx(tev);
4727 dy = libinput_event_tablet_tool_get_dy(tev);
4728 ck_assert(dx == 0.0);
4729 ck_assert(dy < 0.0);
4730 libinput_event_destroy(event);
4731
4732 /* work around axis smoothing */
4733 litest_tablet_motion(dev, 5, 19, axes);
4734 litest_tablet_motion(dev, 5, 18, axes);
4735 litest_tablet_motion(dev, 5, 17, axes);
4736 litest_drain_events(li);
4737
4738 litest_tablet_motion(dev, 5, 5, axes);
4739 libinput_dispatch(li);
4740 event = libinput_get_event(li);
4741 tev = litest_is_tablet_event(event,
4742 LIBINPUT_EVENT_TABLET_TOOL_AXIS);
4743 dx = libinput_event_tablet_tool_get_dx(tev);
4744 dy = libinput_event_tablet_tool_get_dy(tev);
4745 ck_assert(dx == 0.0);
4746 ck_assert(dy > 0.0);
4747 libinput_event_destroy(event);
4748 }
4749 END_TEST
4750
4751 static enum litest_device_type
paired_device(struct litest_device * dev)4752 paired_device(struct litest_device *dev)
4753 {
4754 switch(dev->which) {
4755 case LITEST_WACOM_INTUOS:
4756 return LITEST_WACOM_FINGER;
4757 case LITEST_WACOM_FINGER:
4758 return LITEST_WACOM_INTUOS;
4759 case LITEST_WACOM_CINTIQ_13HDT_PEN:
4760 return LITEST_WACOM_CINTIQ_13HDT_FINGER;
4761 case LITEST_WACOM_CINTIQ_13HDT_FINGER:
4762 return LITEST_WACOM_CINTIQ_13HDT_PEN;
4763 default:
4764 return LITEST_NO_DEVICE;
4765 }
4766 }
4767
4768 static void
assert_touch_is_arbitrated(struct litest_device * dev,struct litest_device * finger)4769 assert_touch_is_arbitrated(struct litest_device *dev, struct litest_device *finger)
4770 {
4771 struct libinput *li = dev->libinput;
4772 bool is_touchpad = !libevdev_has_property(finger->evdev, INPUT_PROP_DIRECT);
4773 struct axis_replacement axes[] = {
4774 { ABS_TILT_X, 80 },
4775 { ABS_TILT_Y, 80 },
4776 { ABS_DISTANCE, 10 },
4777 { ABS_PRESSURE, 0 },
4778 { -1, -1 }
4779 };
4780
4781 litest_tablet_proximity_in(dev, 10, 10, axes);
4782 litest_tablet_motion(dev, 10, 10, axes);
4783 litest_tablet_motion(dev, 20, 40, axes);
4784 litest_drain_events(li);
4785
4786 double tx = 20;
4787 double ty = 40;
4788 double x = 21;
4789 double y = 41;
4790 litest_touch_down(finger, 0, x, y);
4791
4792 /* We need to intersperce the touch events with tablets so we don't
4793 trigger the tablet proximity timeout. */
4794 for (int i = 0; i < 60; i += 5) {
4795 litest_touch_move(finger, 0, x + i, y + i);
4796 litest_tablet_motion(dev, tx + 0.1 * i, ty + 0.1 * i, axes);
4797 }
4798 litest_assert_only_typed_events(li,
4799 LIBINPUT_EVENT_TABLET_TOOL_AXIS);
4800 litest_tablet_proximity_out(dev);
4801 litest_assert_only_typed_events(li,
4802 LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
4803
4804 litest_timeout_touch_arbitration();
4805 libinput_dispatch(li);
4806
4807 /* finger still down */
4808 litest_touch_move_to(finger, 0, 80, 80, 30, 30, 10);
4809 litest_touch_up(finger, 0);
4810 litest_assert_empty_queue(li);
4811
4812 litest_timeout_touch_arbitration();
4813 libinput_dispatch(li);
4814
4815 /* lift finger, expect expect events */
4816 litest_touch_down(finger, 0, 30, 30);
4817 litest_touch_move_to(finger, 0, 30, 30, 80, 80, 10);
4818 litest_touch_up(finger, 0);
4819 libinput_dispatch(li);
4820
4821 if (is_touchpad)
4822 litest_assert_only_typed_events(li,
4823 LIBINPUT_EVENT_POINTER_MOTION);
4824 else
4825 litest_assert_touch_sequence(li);
4826 }
4827
START_TEST(touch_arbitration)4828 START_TEST(touch_arbitration)
4829 {
4830 struct litest_device *dev = litest_current_device();
4831 enum litest_device_type other;
4832 struct libinput *li = dev->libinput;
4833
4834 other = paired_device(dev);
4835 if (other == LITEST_NO_DEVICE)
4836 return;
4837
4838 struct litest_device *finger = litest_add_device(li, other);
4839 litest_drain_events(li);
4840
4841 bool is_touchpad = !libevdev_has_property(finger->evdev, INPUT_PROP_DIRECT);
4842 if (is_touchpad)
4843 litest_disable_hold_gestures(finger->libinput_device);
4844
4845 assert_touch_is_arbitrated(dev, finger);
4846
4847 litest_delete_device(finger);
4848 }
4849 END_TEST
4850
START_TEST(touch_arbitration_outside_rect)4851 START_TEST(touch_arbitration_outside_rect)
4852 {
4853 struct litest_device *dev = litest_current_device();
4854 enum litest_device_type other;
4855 struct litest_device *finger;
4856 struct libinput *li = dev->libinput;
4857 struct axis_replacement axes[] = {
4858 { ABS_TILT_X, 80 },
4859 { ABS_TILT_Y, 80 },
4860 { ABS_DISTANCE, 10 },
4861 { ABS_PRESSURE, 0 },
4862 { -1, -1 }
4863 };
4864 double x, y;
4865 bool is_touchpad;
4866
4867 other = paired_device(dev);
4868 if (other == LITEST_NO_DEVICE)
4869 return;
4870
4871 finger = litest_add_device(li, other);
4872 litest_drain_events(li);
4873
4874 is_touchpad = !libevdev_has_property(finger->evdev, INPUT_PROP_DIRECT);
4875 if (is_touchpad)
4876 return;
4877
4878 x = 20;
4879 y = 70;
4880
4881 /* disable prox-out timer quirk */
4882 litest_tablet_proximity_in(dev, x, y - 1, axes);
4883 litest_tablet_proximity_out(dev);
4884
4885 litest_tablet_proximity_in(dev, x, y - 1, axes);
4886 litest_drain_events(li);
4887
4888 /* these are in percent, but the pen/finger have different
4889 * resolution and the rect works in mm, so the numbers below are
4890 * hand-picked for the test device */
4891 litest_tablet_motion(dev, x, y, axes);
4892 litest_drain_events(li);
4893
4894 /* left of rect */
4895 litest_touch_sequence(finger, 0, x - 10, y + 2, x - 10, y + 20, 3);
4896 libinput_dispatch(li);
4897 litest_assert_touch_sequence(li);
4898
4899 /* above rect */
4900 litest_touch_sequence(finger, 0, x + 2, y - 65, x + 20, y - 40, 3);
4901 libinput_dispatch(li);
4902 litest_assert_touch_sequence(li);
4903
4904 /* right of rect */
4905 litest_touch_sequence(finger, 0, x + 80, y + 2, x + 20, y + 10, 3);
4906 libinput_dispatch(li);
4907 litest_assert_touch_sequence(li);
4908
4909 #if 0
4910 /* This *should* work but the Cintiq test devices is <200mm
4911 high, so we can't test for anything below the tip */
4912 x = 20;
4913 y = 10;
4914 litest_tablet_proximity_out(dev);
4915 litest_tablet_motion(dev, x, y, axes);
4916 litest_tablet_proximity_in(dev, x, y - 1, axes);
4917 litest_drain_events(li);
4918
4919 /* below rect */
4920 litest_touch_sequence(finger, 0, x + 2, y + 80, x + 20, y + 20, 30);
4921 libinput_dispatch(li);
4922 litest_assert_touch_sequence(li);
4923 #endif
4924
4925 litest_delete_device(finger);
4926 }
4927 END_TEST
4928
START_TEST(touch_arbitration_remove_after)4929 START_TEST(touch_arbitration_remove_after)
4930 {
4931 struct litest_device *dev = litest_current_device();
4932 enum litest_device_type other;
4933 struct litest_device *finger;
4934 struct libinput *li = dev->libinput;
4935 struct axis_replacement axes[] = {
4936 { ABS_TILT_X, 80 },
4937 { ABS_TILT_Y, 80 },
4938 { ABS_DISTANCE, 10 },
4939 { ABS_PRESSURE, 0 },
4940 { -1, -1 }
4941 };
4942 bool is_touchpad;
4943
4944 other = paired_device(dev);
4945 if (other == LITEST_NO_DEVICE)
4946 return;
4947
4948 finger = litest_add_device(li, other);
4949 litest_drain_events(li);
4950
4951 is_touchpad = !libevdev_has_property(finger->evdev, INPUT_PROP_DIRECT);
4952 if (is_touchpad)
4953 return;
4954
4955 litest_tablet_proximity_in(dev, 50, 50, axes);
4956 litest_drain_events(li);
4957
4958 litest_touch_down(finger, 0, 70, 70);
4959 litest_drain_events(li);
4960 litest_tablet_proximity_out(dev);
4961 libinput_dispatch(li);
4962
4963 /* Delete the device immediately after the tablet goes out of prox.
4964 * This merely tests that the arbitration timer gets cleaned up */
4965 litest_delete_device(finger);
4966 }
4967 END_TEST
4968
START_TEST(touch_arbitration_stop_touch)4969 START_TEST(touch_arbitration_stop_touch)
4970 {
4971 struct litest_device *dev = litest_current_device();
4972 enum litest_device_type other;
4973 struct litest_device *finger;
4974 struct libinput *li = dev->libinput;
4975 struct axis_replacement axes[] = {
4976 { ABS_DISTANCE, 10 },
4977 { ABS_PRESSURE, 0 },
4978 { -1, -1 }
4979 };
4980 bool is_touchpad;
4981
4982 other = paired_device(dev);
4983 if (other == LITEST_NO_DEVICE)
4984 return;
4985
4986 finger = litest_add_device(li, other);
4987
4988 is_touchpad = !libevdev_has_property(finger->evdev, INPUT_PROP_DIRECT);
4989
4990 if (is_touchpad)
4991 litest_disable_hold_gestures(finger->libinput_device);
4992
4993 /* disable prox-out timer quirk */
4994 litest_tablet_proximity_in(dev, 30, 30, axes);
4995 litest_tablet_proximity_out(dev);
4996 litest_drain_events(li);
4997
4998 litest_touch_down(finger, 0, 30, 30);
4999 litest_touch_move_to(finger, 0, 30, 30, 80, 80, 10);
5000
5001 litest_tablet_proximity_in(dev, 10, 10, axes);
5002 litest_tablet_motion(dev, 10, 10, axes);
5003 litest_tablet_motion(dev, 20, 40, axes);
5004 litest_drain_events(li);
5005
5006 litest_touch_move_to(finger, 0, 80, 80, 30, 30, 10);
5007 litest_assert_empty_queue(li);
5008
5009 /* tablet event so we don't time out for proximity */
5010 litest_tablet_motion(dev, 30, 40, axes);
5011 litest_drain_events(li);
5012
5013 /* start another finger to make sure that one doesn't send events
5014 either */
5015 litest_touch_down(finger, 1, 30, 30);
5016 litest_touch_move_to(finger, 1, 30, 30, 80, 80, 3);
5017 litest_assert_empty_queue(li);
5018
5019 litest_tablet_motion(dev, 10, 10, axes);
5020 litest_tablet_motion(dev, 20, 40, axes);
5021 litest_assert_only_typed_events(li,
5022 LIBINPUT_EVENT_TABLET_TOOL_AXIS);
5023 litest_tablet_proximity_out(dev);
5024 litest_drain_events(li);
5025
5026 litest_timeout_tablet_proxout();
5027 litest_drain_events(li);
5028
5029 /* Finger needs to be lifted for events to happen*/
5030 litest_touch_move_to(finger, 0, 30, 30, 80, 80, 3);
5031 litest_assert_empty_queue(li);
5032 litest_touch_move_to(finger, 1, 80, 80, 30, 30, 3);
5033 litest_assert_empty_queue(li);
5034 litest_touch_up(finger, 0);
5035 litest_touch_move_to(finger, 1, 30, 30, 80, 80, 3);
5036 litest_assert_empty_queue(li);
5037 litest_touch_up(finger, 1);
5038 libinput_dispatch(li);
5039
5040 litest_touch_down(finger, 0, 30, 30);
5041 litest_touch_move_to(finger, 0, 30, 30, 80, 80, 3);
5042 litest_touch_up(finger, 0);
5043 libinput_dispatch(li);
5044
5045 if (is_touchpad)
5046 litest_assert_only_typed_events(li,
5047 LIBINPUT_EVENT_POINTER_MOTION);
5048 else
5049 litest_assert_touch_sequence(li);
5050
5051 litest_delete_device(finger);
5052 litest_assert_only_typed_events(li, LIBINPUT_EVENT_DEVICE_REMOVED);
5053 }
5054 END_TEST
5055
START_TEST(touch_arbitration_suspend_touch_device)5056 START_TEST(touch_arbitration_suspend_touch_device)
5057 {
5058 struct litest_device *dev = litest_current_device();
5059 enum litest_device_type other;
5060 struct litest_device *tablet;
5061 struct libinput *li = dev->libinput;
5062 enum libinput_config_status status;
5063 struct axis_replacement axes[] = {
5064 { ABS_DISTANCE, 10 },
5065 { ABS_PRESSURE, 0 },
5066 { -1, -1 }
5067 };
5068 bool is_touchpad;
5069
5070 other = paired_device(dev);
5071 if (other == LITEST_NO_DEVICE)
5072 return;
5073
5074 tablet = litest_add_device(li, other);
5075
5076 is_touchpad = !libevdev_has_property(dev->evdev, INPUT_PROP_DIRECT);
5077
5078 if (is_touchpad)
5079 litest_disable_hold_gestures(dev->libinput_device);
5080
5081 /* we can't force a device suspend, but we can at least make sure
5082 the device doesn't send events */
5083 status = libinput_device_config_send_events_set_mode(
5084 dev->libinput_device,
5085 LIBINPUT_CONFIG_SEND_EVENTS_DISABLED);
5086 ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
5087
5088 litest_drain_events(li);
5089
5090 litest_tablet_proximity_in(tablet, 10, 10, axes);
5091 litest_tablet_motion(tablet, 10, 10, axes);
5092 litest_tablet_motion(tablet, 20, 40, axes);
5093 litest_drain_events(li);
5094
5095 litest_touch_down(dev, 0, 30, 30);
5096 litest_touch_move_to(dev, 0, 30, 30, 80, 80, 10);
5097 litest_touch_up(dev, 0);
5098 litest_assert_empty_queue(li);
5099
5100 /* Remove tablet device to unpair, still disabled though */
5101 litest_delete_device(tablet);
5102 litest_assert_tablet_proximity_event(li,
5103 LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT);
5104 litest_assert_only_typed_events(li, LIBINPUT_EVENT_DEVICE_REMOVED);
5105
5106 litest_timeout_touch_arbitration();
5107 libinput_dispatch(li);
5108
5109 litest_touch_down(dev, 0, 30, 30);
5110 litest_touch_move_to(dev, 0, 30, 30, 80, 80, 10);
5111 litest_touch_up(dev, 0);
5112 litest_assert_empty_queue(li);
5113
5114 /* Touch device is still disabled */
5115 litest_touch_down(dev, 0, 30, 30);
5116 litest_touch_move_to(dev, 0, 30, 30, 80, 80, 10);
5117 litest_touch_up(dev, 0);
5118 litest_assert_empty_queue(li);
5119
5120 status = libinput_device_config_send_events_set_mode(
5121 dev->libinput_device,
5122 LIBINPUT_CONFIG_SEND_EVENTS_ENABLED);
5123 ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
5124
5125 litest_touch_down(dev, 0, 30, 30);
5126 litest_touch_move_to(dev, 0, 30, 30, 80, 80, 10);
5127 litest_touch_up(dev, 0);
5128 libinput_dispatch(li);
5129
5130 if (is_touchpad)
5131 litest_assert_only_typed_events(li,
5132 LIBINPUT_EVENT_POINTER_MOTION);
5133 else
5134 litest_assert_touch_sequence(li);
5135 }
5136 END_TEST
5137
START_TEST(touch_arbitration_remove_touch)5138 START_TEST(touch_arbitration_remove_touch)
5139 {
5140 struct litest_device *dev = litest_current_device();
5141 enum litest_device_type other;
5142 struct litest_device *finger;
5143 struct libinput *li = dev->libinput;
5144 struct axis_replacement axes[] = {
5145 { ABS_DISTANCE, 10 },
5146 { ABS_PRESSURE, 0 },
5147 { -1, -1 }
5148 };
5149
5150 other = paired_device(dev);
5151 if (other == LITEST_NO_DEVICE)
5152 return;
5153
5154 finger = litest_add_device(li, other);
5155 litest_touch_down(finger, 0, 30, 30);
5156 litest_touch_move_to(finger, 0, 30, 30, 80, 80, 10);
5157
5158 litest_tablet_proximity_in(dev, 10, 10, axes);
5159 litest_drain_events(li);
5160
5161 litest_delete_device(finger);
5162 libinput_dispatch(li);
5163 litest_assert_only_typed_events(li, LIBINPUT_EVENT_DEVICE_REMOVED);
5164 litest_assert_empty_queue(li);
5165
5166 litest_tablet_motion(dev, 10, 10, axes);
5167 litest_tablet_motion(dev, 20, 40, axes);
5168 litest_assert_only_typed_events(li,
5169 LIBINPUT_EVENT_TABLET_TOOL_AXIS);
5170 }
5171 END_TEST
5172
START_TEST(touch_arbitration_remove_tablet)5173 START_TEST(touch_arbitration_remove_tablet)
5174 {
5175 struct litest_device *dev = litest_current_device();
5176 enum litest_device_type other;
5177 struct litest_device *tablet;
5178 struct libinput *li = dev->libinput;
5179 struct axis_replacement axes[] = {
5180 { ABS_DISTANCE, 10 },
5181 { ABS_PRESSURE, 0 },
5182 { -1, -1 }
5183 };
5184 bool is_touchpad;
5185
5186 other = paired_device(dev);
5187 if (other == LITEST_NO_DEVICE)
5188 return;
5189
5190 tablet = litest_add_device(li, other);
5191
5192 is_touchpad = !libevdev_has_property(dev->evdev, INPUT_PROP_DIRECT);
5193
5194 if (is_touchpad)
5195 litest_disable_hold_gestures(dev->libinput_device);
5196
5197 libinput_dispatch(li);
5198 litest_tablet_proximity_in(tablet, 10, 10, axes);
5199 litest_tablet_motion(tablet, 10, 10, axes);
5200 litest_tablet_motion(tablet, 20, 40, axes);
5201 litest_drain_events(li);
5202
5203 litest_touch_down(dev, 0, 30, 30);
5204 litest_touch_move_to(dev, 0, 30, 30, 80, 80, 10);
5205 litest_assert_empty_queue(li);
5206
5207 litest_delete_device(tablet);
5208 litest_assert_tablet_proximity_event(li,
5209 LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT);
5210 litest_assert_only_typed_events(li, LIBINPUT_EVENT_DEVICE_REMOVED);
5211
5212 litest_timeout_touch_arbitration();
5213 libinput_dispatch(li);
5214
5215 /* Touch is still down, don't enable */
5216 litest_touch_move_to(dev, 0, 80, 80, 30, 30, 10);
5217 litest_touch_up(dev, 0);
5218 litest_assert_empty_queue(li);
5219
5220 litest_touch_down(dev, 0, 30, 30);
5221 litest_touch_move_to(dev, 0, 30, 30, 80, 80, 10);
5222 litest_touch_up(dev, 0);
5223 libinput_dispatch(li);
5224
5225 if (is_touchpad)
5226 litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
5227 else
5228 litest_assert_touch_sequence(li);
5229 }
5230 END_TEST
5231
START_TEST(touch_arbitration_keep_ignoring)5232 START_TEST(touch_arbitration_keep_ignoring)
5233 {
5234 struct litest_device *tablet = litest_current_device();
5235 enum litest_device_type other;
5236 struct litest_device *finger;
5237 struct libinput *li = tablet->libinput;
5238 struct axis_replacement axes[] = {
5239 { ABS_DISTANCE, 10 },
5240 { ABS_PRESSURE, 0 },
5241 { -1, -1 }
5242 };
5243
5244 other = paired_device(tablet);
5245 if (other == LITEST_NO_DEVICE)
5246 return;
5247
5248 finger = litest_add_device(li, other);
5249 litest_tablet_proximity_in(tablet, 10, 10, axes);
5250 litest_tablet_motion(tablet, 10, 10, axes);
5251 litest_tablet_motion(tablet, 20, 40, axes);
5252
5253 litest_touch_down(finger, 0, 30, 30);
5254 litest_drain_events(li);
5255
5256 litest_tablet_proximity_out(tablet);
5257 litest_drain_events(li);
5258
5259 /* a touch during pen interaction stays a palm after the pen lifts.
5260 */
5261 litest_touch_move_to(finger, 0, 30, 30, 80, 80, 10);
5262 litest_touch_up(finger, 0);
5263 libinput_dispatch(li);
5264
5265 litest_assert_empty_queue(li);
5266
5267 litest_delete_device(finger);
5268 }
5269 END_TEST
5270
START_TEST(touch_arbitration_late_touch_lift)5271 START_TEST(touch_arbitration_late_touch_lift)
5272 {
5273 struct litest_device *tablet = litest_current_device();
5274 enum litest_device_type other;
5275 struct litest_device *finger;
5276 struct libinput *li = tablet->libinput;
5277 struct axis_replacement axes[] = {
5278 { ABS_DISTANCE, 10 },
5279 { ABS_PRESSURE, 0 },
5280 { -1, -1 }
5281 };
5282 bool is_touchpad;
5283
5284 other = paired_device(tablet);
5285 if (other == LITEST_NO_DEVICE)
5286 return;
5287
5288 finger = litest_add_device(li, other);
5289 is_touchpad = !libevdev_has_property(finger->evdev, INPUT_PROP_DIRECT);
5290 if (is_touchpad) {
5291 litest_enable_tap(finger->libinput_device);
5292 litest_disable_hold_gestures(finger->libinput_device);
5293 }
5294
5295 litest_tablet_proximity_in(tablet, 10, 10, axes);
5296 litest_tablet_motion(tablet, 10, 10, axes);
5297 litest_tablet_motion(tablet, 20, 40, axes);
5298 litest_drain_events(li);
5299
5300 litest_tablet_proximity_out(tablet);
5301 litest_drain_events(li);
5302
5303 /* with kernel arbitration, a finger + stylus in prox only generates
5304 * stylus events. When a user lifts the hand with the stylus, the
5305 * stylus usually goes out of prox while the hand is still touching
5306 * the surface. This causes a touch down event now that the stylus
5307 * is out of proximity. A few ms later, the hand really lifts off
5308 * the surface, causing a touch down and thus a fake tap event.
5309 */
5310 litest_touch_down(finger, 0, 30, 30);
5311 litest_touch_up(finger, 0);
5312 libinput_dispatch(li);
5313 litest_timeout_tap();
5314 libinput_dispatch(li);
5315
5316 litest_assert_empty_queue(li);
5317
5318 litest_delete_device(finger);
5319 }
5320 END_TEST
5321
START_TEST(touch_arbitration_swap_device)5322 START_TEST(touch_arbitration_swap_device)
5323 {
5324 struct litest_device *tablet = litest_current_device();
5325 struct libinput *li = tablet->libinput;
5326
5327 enum litest_device_type paired = paired_device(tablet);
5328 if (paired == LITEST_NO_DEVICE)
5329 return;
5330
5331 /* First, add a normal touchscreen */
5332 struct litest_device *touchscreen = litest_add_device(li, LITEST_GENERIC_MULTITOUCH_SCREEN);
5333 libinput_device_config_gesture_set_hold_enabled(touchscreen->libinput_device,
5334 LIBINPUT_CONFIG_HOLD_DISABLED);
5335 litest_drain_events(li);
5336 assert_touch_is_arbitrated(tablet, touchscreen);
5337
5338 /* Now add a better device to override the pairing */
5339 struct litest_device *finger = litest_add_device(li, paired);
5340 libinput_device_config_gesture_set_hold_enabled(finger->libinput_device,
5341 LIBINPUT_CONFIG_HOLD_DISABLED);
5342 litest_drain_events(li);
5343 assert_touch_is_arbitrated(tablet, finger);
5344
5345 litest_delete_device(touchscreen);
5346 litest_delete_device(finger);
5347 }
5348 END_TEST
5349
5350 #if HAVE_LIBWACOM
5351 static void
verify_left_handed_tablet_motion(struct litest_device * tablet,struct libinput * li,int x,int y,bool left_handed)5352 verify_left_handed_tablet_motion(struct litest_device *tablet,
5353 struct libinput *li,
5354 int x, int y,
5355 bool left_handed)
5356 {
5357 struct libinput_event *event;
5358 struct libinput_event_tablet_tool *t;
5359
5360 /* proximity in/out must be handled by caller */
5361
5362 for (int i = 5; i < 25; i += 5) {
5363 litest_tablet_motion(tablet, x + i, y - i, NULL);
5364 libinput_dispatch(li);
5365 }
5366
5367 event = libinput_get_event(li);
5368 t = litest_is_tablet_event(event,
5369 LIBINPUT_EVENT_TABLET_TOOL_AXIS);
5370 x = libinput_event_tablet_tool_get_x(t);
5371 y = libinput_event_tablet_tool_get_y(t);
5372 libinput_event_destroy(event);
5373
5374 event = libinput_get_event(li);
5375 litest_assert_ptr_notnull(event);
5376
5377 while (event) {
5378 double last_x = x, last_y = y;
5379
5380 t = litest_is_tablet_event(event,
5381 LIBINPUT_EVENT_TABLET_TOOL_AXIS);
5382 x = libinput_event_tablet_tool_get_x(t);
5383 y = libinput_event_tablet_tool_get_y(t);
5384
5385 if (left_handed) {
5386 litest_assert_double_lt(x, last_x);
5387 litest_assert_double_gt(y, last_y);
5388 } else {
5389 litest_assert_double_gt(x, last_x);
5390 litest_assert_double_lt(y, last_y);
5391 }
5392
5393 libinput_event_destroy(event);
5394 event = libinput_get_event(li);
5395 }
5396 }
5397
5398 static void
verify_left_handed_tablet_sequence(struct litest_device * tablet,struct libinput * li,bool left_handed)5399 verify_left_handed_tablet_sequence(struct litest_device *tablet,
5400 struct libinput *li,
5401 bool left_handed)
5402 {
5403 double x, y;
5404
5405 /* verifies a whole sequence, including prox in/out and timeouts */
5406 x = 60;
5407 y = 60;
5408 litest_tablet_proximity_in(tablet, x, y, NULL);
5409 libinput_dispatch(li);
5410 litest_drain_events(li);
5411 verify_left_handed_tablet_motion(tablet, li, x, y, left_handed);
5412 litest_tablet_proximity_out(tablet);
5413 libinput_dispatch(li);
5414 litest_timeout_tablet_proxout();
5415 litest_drain_events(li);
5416 }
5417
5418 static void
verify_left_handed_touch_motion(struct litest_device * finger,struct libinput * li,double x,double y,bool left_handed)5419 verify_left_handed_touch_motion(struct litest_device *finger,
5420 struct libinput *li,
5421 double x, double y,
5422 bool left_handed)
5423 {
5424 struct libinput_event *event;
5425 struct libinput_event_pointer *p;
5426
5427 /* touch down/up must be handled by caller */
5428
5429 litest_touch_move_to(finger, 0, x + 1, y - 1, x + 20, y - 20, 10);
5430 libinput_dispatch(li);
5431
5432 event = libinput_get_event(li);
5433 ck_assert_notnull(event);
5434
5435 while (event) {
5436 p = litest_is_motion_event(event);
5437 x = libinput_event_pointer_get_dx(p);
5438 y = libinput_event_pointer_get_dy(p);
5439
5440 if (left_handed) {
5441 litest_assert_double_lt(x, 0);
5442 litest_assert_double_gt(y, 0);
5443 } else {
5444 litest_assert_double_gt(x, 0);
5445 litest_assert_double_lt(y, 0);
5446 }
5447
5448 libinput_event_destroy(event);
5449 event = libinput_get_event(li);
5450 }
5451 }
5452
5453 static void
verify_left_handed_touch_sequence(struct litest_device * finger,struct libinput * li,bool left_handed)5454 verify_left_handed_touch_sequence(struct litest_device *finger,
5455 struct libinput *li,
5456 bool left_handed)
5457 {
5458 double x, y;
5459
5460 /* verifies a whole sequence, including prox in/out and timeouts */
5461
5462 x = 10;
5463 y = 30;
5464 litest_touch_down(finger, 0, x, y);
5465 litest_drain_events(li);
5466 verify_left_handed_touch_motion(finger, li, x, y, left_handed);
5467 litest_touch_up(finger, 0);
5468 libinput_dispatch(li);
5469 }
5470 #endif
5471
START_TEST(tablet_rotation_left_handed)5472 START_TEST(tablet_rotation_left_handed)
5473 {
5474 #if HAVE_LIBWACOM
5475 struct litest_device *tablet = litest_current_device();
5476 enum litest_device_type other;
5477 struct litest_device *finger;
5478 struct libinput *li = tablet->libinput;
5479 unsigned int transition = _i; /* ranged test */
5480 bool tablet_from, touch_from, tablet_to, touch_to;
5481 bool enabled_from, enabled_to;
5482
5483 other = paired_device(tablet);
5484 if (other == LITEST_NO_DEVICE)
5485 return;
5486
5487 finger = litest_add_device(li, other);
5488 litest_drain_events(li);
5489
5490 if (libevdev_has_property(finger->evdev, INPUT_PROP_DIRECT))
5491 goto out;
5492
5493 tablet_from = !!(transition & bit(0));
5494 touch_from = !!(transition & bit(1));
5495 tablet_to = !!(transition & bit(2));
5496 touch_to = !!(transition & bit(3));
5497
5498 enabled_from = tablet_from || touch_from;
5499 enabled_to = tablet_to || touch_to;
5500
5501 litest_disable_hold_gestures(finger->libinput_device);
5502 libinput_device_config_left_handed_set(tablet->libinput_device,
5503 tablet_from);
5504 libinput_device_config_left_handed_set(finger->libinput_device,
5505 touch_from);
5506 verify_left_handed_tablet_sequence(tablet, li, enabled_from);
5507 verify_left_handed_touch_sequence(finger, li, enabled_from);
5508
5509 libinput_device_config_left_handed_set(tablet->libinput_device,
5510 tablet_to);
5511 libinput_device_config_left_handed_set(finger->libinput_device,
5512 touch_to);
5513 verify_left_handed_tablet_sequence(tablet, li, enabled_to);
5514 verify_left_handed_touch_sequence(finger, li, enabled_to);
5515
5516 out:
5517 litest_delete_device(finger);
5518 #endif
5519 }
5520 END_TEST
5521
START_TEST(tablet_rotation_left_handed_configuration)5522 START_TEST(tablet_rotation_left_handed_configuration)
5523 {
5524 #if HAVE_LIBWACOM
5525 struct litest_device *tablet = litest_current_device();
5526 enum litest_device_type other;
5527 struct litest_device *finger;
5528 struct libinput *li = tablet->libinput;
5529 unsigned int transition = _i; /* ranged test */
5530 bool tablet_from, touch_from, tablet_to, touch_to;
5531 bool tablet_enabled, touch_enabled;
5532 struct libinput_device *tablet_dev, *touch_dev;
5533
5534 other = paired_device(tablet);
5535 if (other == LITEST_NO_DEVICE)
5536 return;
5537
5538 finger = litest_add_device(li, other);
5539 litest_drain_events(li);
5540
5541 if (libevdev_has_property(finger->evdev, INPUT_PROP_DIRECT))
5542 goto out;
5543
5544 tablet_from = !!(transition & bit(0));
5545 touch_from = !!(transition & bit(1));
5546 tablet_to = !!(transition & bit(2));
5547 touch_to = !!(transition & bit(3));
5548
5549 tablet_dev = tablet->libinput_device;
5550 touch_dev = finger->libinput_device;
5551
5552 /* Make sure that toggling one device doesn't toggle the other one */
5553
5554 libinput_device_config_left_handed_set(tablet_dev, tablet_from);
5555 libinput_device_config_left_handed_set(touch_dev, touch_from);
5556 libinput_dispatch(li);
5557 tablet_enabled = libinput_device_config_left_handed_get(tablet_dev);
5558 touch_enabled = libinput_device_config_left_handed_get(touch_dev);
5559 ck_assert_int_eq(tablet_enabled, tablet_from);
5560 ck_assert_int_eq(touch_enabled, touch_from);
5561
5562 libinput_device_config_left_handed_set(tablet_dev, tablet_to);
5563 libinput_device_config_left_handed_set(touch_dev, touch_to);
5564 libinput_dispatch(li);
5565 tablet_enabled = libinput_device_config_left_handed_get(tablet_dev);
5566 touch_enabled = libinput_device_config_left_handed_get(touch_dev);
5567 ck_assert_int_eq(tablet_enabled, tablet_to);
5568 ck_assert_int_eq(touch_enabled, touch_to);
5569
5570 out:
5571 litest_delete_device(finger);
5572 #endif
5573 }
5574 END_TEST
5575
START_TEST(tablet_rotation_left_handed_while_in_prox)5576 START_TEST(tablet_rotation_left_handed_while_in_prox)
5577 {
5578 #if HAVE_LIBWACOM
5579 struct litest_device *tablet = litest_current_device();
5580 enum litest_device_type other;
5581 struct litest_device *finger;
5582 struct libinput *li = tablet->libinput;
5583 unsigned int transition = _i; /* ranged test */
5584 bool tablet_from, touch_from, tablet_to, touch_to;
5585 bool enabled_from, enabled_to;
5586 double x, y;
5587 double tx, ty;
5588
5589 other = paired_device(tablet);
5590 if (other == LITEST_NO_DEVICE)
5591 return;
5592
5593 finger = litest_add_device(li, other);
5594 litest_drain_events(li);
5595
5596 if (libevdev_has_property(finger->evdev, INPUT_PROP_DIRECT))
5597 goto out;
5598
5599 tablet_from = !!(transition & bit(0));
5600 touch_from = !!(transition & bit(1));
5601 tablet_to = !!(transition & bit(2));
5602 touch_to = !!(transition & bit(3));
5603
5604 enabled_from = tablet_from || touch_from;
5605 enabled_to = tablet_to || touch_to;
5606
5607 litest_disable_hold_gestures(finger->libinput_device);
5608 libinput_device_config_left_handed_set(finger->libinput_device,
5609 touch_from);
5610 libinput_device_config_left_handed_set(tablet->libinput_device,
5611 tablet_from);
5612
5613
5614 /* Tablet in-prox when setting to left-handed */
5615 tx = 60;
5616 ty = 60;
5617 litest_tablet_proximity_in(tablet, tx, ty, NULL);
5618 libinput_dispatch(li);
5619 litest_drain_events(li);
5620
5621 libinput_device_config_left_handed_set(tablet->libinput_device,
5622 tablet_to);
5623 libinput_device_config_left_handed_set(finger->libinput_device,
5624 touch_to);
5625
5626 /* not yet neutral, so still whatever the original was */
5627 verify_left_handed_tablet_motion(tablet, li, tx, ty, enabled_from);
5628 litest_drain_events(li);
5629
5630 /* test pointer, should be left-handed already */
5631 #if 0
5632 /* Touch arbitration discards events, so we can't check for the
5633 right behaviour here. */
5634 verify_left_handed_touch_sequence(finger, li, enabled_to);
5635 #else
5636 x = 10;
5637 y = 30;
5638 litest_touch_down(finger, 0, x, y);
5639
5640 /* We need to intersperce the touch events with tablets so we don't
5641 trigger the tablet proximity timeout. */
5642 for (int i = 0; i < 10; i++) {
5643 litest_touch_move(finger, 0, x + i, y - i);
5644 litest_tablet_motion(tablet,
5645 tx + 0.1 * i, ty + 0.1 * i,
5646 NULL);
5647 }
5648
5649 litest_touch_up(finger, 0);
5650 libinput_dispatch(li);
5651 /* this will fail once we have location-based touch arbitration on
5652 * touchpads */
5653 litest_assert_only_typed_events(li, LIBINPUT_EVENT_TABLET_TOOL_AXIS);
5654 #endif
5655 litest_tablet_proximity_out(tablet);
5656 libinput_dispatch(li);
5657 litest_timeout_tablet_proxout();
5658 litest_drain_events(li);
5659
5660 /* now both should've switched */
5661 verify_left_handed_tablet_sequence(tablet, li, enabled_to);
5662 verify_left_handed_touch_sequence(finger, li, enabled_to);
5663
5664 out:
5665 litest_delete_device(finger);
5666 #endif
5667 }
5668 END_TEST
5669
START_TEST(tablet_rotation_left_handed_while_touch_down)5670 START_TEST(tablet_rotation_left_handed_while_touch_down)
5671 {
5672 #if HAVE_LIBWACOM
5673 struct litest_device *tablet = litest_current_device();
5674 enum litest_device_type other;
5675 struct litest_device *finger;
5676 struct libinput *li = tablet->libinput;
5677 unsigned int transition = _i; /* ranged test */
5678 bool tablet_from, touch_from, tablet_to, touch_to;
5679 bool enabled_from, enabled_to;
5680
5681 double x, y;
5682
5683 other = paired_device(tablet);
5684 if (other == LITEST_NO_DEVICE)
5685 return;
5686
5687 finger = litest_add_device(li, other);
5688 litest_drain_events(li);
5689
5690 if (libevdev_has_property(finger->evdev, INPUT_PROP_DIRECT))
5691 goto out;
5692
5693 tablet_from = !!(transition & bit(0));
5694 touch_from = !!(transition & bit(1));
5695 tablet_to = !!(transition & bit(2));
5696 touch_to = !!(transition & bit(3));
5697
5698 enabled_from = tablet_from || touch_from;
5699 enabled_to = tablet_to || touch_to;
5700
5701 litest_disable_hold_gestures(finger->libinput_device);
5702 libinput_device_config_left_handed_set(finger->libinput_device,
5703 touch_from);
5704 libinput_device_config_left_handed_set(tablet->libinput_device,
5705 tablet_from);
5706
5707 /* Touch down when setting to left-handed */
5708 x = 10;
5709 y = 30;
5710 litest_touch_down(finger, 0, x, y);
5711 libinput_dispatch(li);
5712 litest_drain_events(li);
5713
5714 libinput_device_config_left_handed_set(tablet->libinput_device,
5715 tablet_to);
5716 libinput_device_config_left_handed_set(finger->libinput_device,
5717 touch_to);
5718
5719 /* not yet neutral, so still whatever the original was */
5720 verify_left_handed_touch_motion(finger, li, x, y, enabled_from);
5721 litest_assert_empty_queue(li);
5722
5723 /* test tablet, should be left-handed already */
5724 verify_left_handed_tablet_sequence(tablet, li, enabled_to);
5725
5726 litest_touch_up(finger, 0);
5727 litest_drain_events(li);
5728
5729 /* now both should've switched */
5730 verify_left_handed_tablet_sequence(tablet, li, enabled_to);
5731 verify_left_handed_touch_sequence(finger, li, enabled_to);
5732
5733 out:
5734 litest_delete_device(finger);
5735 #endif
5736 }
5737 END_TEST
5738
START_TEST(tablet_rotation_left_handed_add_touchpad)5739 START_TEST(tablet_rotation_left_handed_add_touchpad)
5740 {
5741 #if HAVE_LIBWACOM
5742 struct litest_device *tablet = litest_current_device();
5743 enum litest_device_type other;
5744 struct litest_device *finger;
5745 struct libinput *li = tablet->libinput;
5746 unsigned int transition = _i; /* ranged test */
5747 bool tablet_from, touch_from, tablet_to, touch_to;
5748 bool enabled_from, enabled_to;
5749
5750 other = paired_device(tablet);
5751 if (other == LITEST_NO_DEVICE)
5752 return;
5753
5754 tablet_from = !!(transition & bit(0));
5755 touch_from = !!(transition & bit(1));
5756 tablet_to = !!(transition & bit(2));
5757 touch_to = !!(transition & bit(3));
5758
5759 enabled_from = tablet_from || touch_from;
5760 enabled_to = tablet_to || touch_to;
5761
5762 /* change left-handed before touchpad appears */
5763
5764 libinput_device_config_left_handed_set(tablet->libinput_device,
5765 tablet_from);
5766
5767 finger = litest_add_device(li, other);
5768 litest_drain_events(li);
5769
5770 if (libevdev_has_property(finger->evdev, INPUT_PROP_DIRECT))
5771 goto out;
5772
5773 libinput_device_config_left_handed_set(finger->libinput_device,
5774 touch_from);
5775 litest_disable_hold_gestures(finger->libinput_device);
5776
5777 verify_left_handed_touch_sequence(finger, li, enabled_from);
5778 verify_left_handed_tablet_sequence(tablet, li, enabled_from);
5779
5780 libinput_device_config_left_handed_set(tablet->libinput_device,
5781 tablet_to);
5782 libinput_device_config_left_handed_set(finger->libinput_device,
5783 touch_to);
5784
5785 verify_left_handed_touch_sequence(finger, li, enabled_to);
5786 verify_left_handed_tablet_sequence(tablet, li, enabled_to);
5787
5788 out:
5789 litest_delete_device(finger);
5790 #endif
5791 }
5792 END_TEST
5793
START_TEST(tablet_rotation_left_handed_add_tablet)5794 START_TEST(tablet_rotation_left_handed_add_tablet)
5795 {
5796 #if HAVE_LIBWACOM
5797 struct litest_device *finger = litest_current_device();
5798 enum litest_device_type other;
5799 struct litest_device *tablet;
5800 struct libinput *li = finger->libinput;
5801 unsigned int transition = _i; /* ranged test */
5802 bool tablet_from, touch_from, tablet_to, touch_to;
5803 bool enabled_from, enabled_to;
5804
5805 if (libevdev_has_property(finger->evdev, INPUT_PROP_DIRECT))
5806 return;
5807
5808 other = paired_device(finger);
5809 if (other == LITEST_NO_DEVICE)
5810 return;
5811
5812 tablet_from = !!(transition & bit(0));
5813 touch_from = !!(transition & bit(1));
5814 tablet_to = !!(transition & bit(2));
5815 touch_to = !!(transition & bit(3));
5816
5817 enabled_from = tablet_from || touch_from;
5818 enabled_to = tablet_to || touch_to;
5819
5820 /* change left-handed before tablet appears */
5821 libinput_device_config_left_handed_set(finger->libinput_device,
5822 touch_from);
5823 litest_disable_hold_gestures(finger->libinput_device);
5824
5825 tablet = litest_add_device(li, other);
5826 litest_drain_events(li);
5827
5828 libinput_device_config_left_handed_set(tablet->libinput_device,
5829 tablet_from);
5830
5831 verify_left_handed_touch_sequence(finger, li, enabled_from);
5832 verify_left_handed_tablet_sequence(tablet, li, enabled_from);
5833
5834 libinput_device_config_left_handed_set(tablet->libinput_device,
5835 tablet_to);
5836 libinput_device_config_left_handed_set(finger->libinput_device,
5837 touch_to);
5838
5839 verify_left_handed_touch_sequence(finger, li, enabled_to);
5840 verify_left_handed_tablet_sequence(tablet, li, enabled_to);
5841
5842 litest_delete_device(tablet);
5843 #endif
5844 }
5845 END_TEST
5846
START_TEST(huion_static_btn_tool_pen)5847 START_TEST(huion_static_btn_tool_pen)
5848 {
5849 struct litest_device *dev = litest_current_device();
5850 struct libinput *li = dev->libinput;
5851 int i;
5852
5853 litest_drain_events(li);
5854
5855 litest_event(dev, EV_ABS, ABS_X, 20000);
5856 litest_event(dev, EV_ABS, ABS_Y, 20000);
5857 litest_event(dev, EV_ABS, ABS_PRESSURE, 100);
5858 litest_event(dev, EV_KEY, BTN_TOOL_PEN, 1);
5859 litest_event(dev, EV_SYN, SYN_REPORT, 0);
5860 litest_drain_events(li);
5861
5862 for (i = 0; i < 10; i++) {
5863 litest_event(dev, EV_ABS, ABS_X, 20000 + 10 * i);
5864 litest_event(dev, EV_ABS, ABS_Y, 20000 - 10 * i);
5865 litest_event(dev, EV_SYN, SYN_REPORT, 0);
5866 libinput_dispatch(li);
5867 }
5868 litest_assert_only_typed_events(li,
5869 LIBINPUT_EVENT_TABLET_TOOL_AXIS);
5870
5871 /* Wait past the timeout to expect a proximity out */
5872 litest_timeout_tablet_proxout();
5873 libinput_dispatch(li);
5874 litest_assert_tablet_proximity_event(li,
5875 LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT);
5876 libinput_dispatch(li);
5877
5878 /* New events should fake a proximity in again */
5879 litest_event(dev, EV_ABS, ABS_X, 20000);
5880 litest_event(dev, EV_ABS, ABS_Y, 20000);
5881 litest_event(dev, EV_SYN, SYN_REPORT, 0);
5882 libinput_dispatch(li);
5883 litest_assert_tablet_proximity_event(li,
5884 LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN);
5885 libinput_dispatch(li);
5886
5887 for (i = 0; i < 10; i++) {
5888 litest_event(dev, EV_ABS, ABS_X, 20000 + 10 * i);
5889 litest_event(dev, EV_ABS, ABS_Y, 20000 - 10 * i);
5890 litest_event(dev, EV_SYN, SYN_REPORT, 0);
5891 libinput_dispatch(li);
5892 }
5893 litest_assert_only_typed_events(li,
5894 LIBINPUT_EVENT_TABLET_TOOL_AXIS);
5895 litest_timeout_tablet_proxout();
5896 libinput_dispatch(li);
5897 litest_assert_tablet_proximity_event(li,
5898 LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT);
5899 libinput_dispatch(li);
5900
5901 /* New events, just to ensure cleanup paths are correct */
5902 litest_event(dev, EV_ABS, ABS_X, 20000);
5903 litest_event(dev, EV_ABS, ABS_Y, 20000);
5904 litest_event(dev, EV_SYN, SYN_REPORT, 0);
5905 libinput_dispatch(li);
5906 }
5907 END_TEST
5908
START_TEST(huion_static_btn_tool_pen_no_timeout_during_usage)5909 START_TEST(huion_static_btn_tool_pen_no_timeout_during_usage)
5910 {
5911 struct litest_device *dev = litest_current_device();
5912 struct libinput *li = dev->libinput;
5913 int i;
5914
5915 litest_drain_events(li);
5916
5917 litest_event(dev, EV_ABS, ABS_X, 20000);
5918 litest_event(dev, EV_ABS, ABS_Y, 20000);
5919 litest_event(dev, EV_ABS, ABS_PRESSURE, 100);
5920 litest_event(dev, EV_KEY, BTN_TOOL_PEN, 1);
5921 litest_event(dev, EV_SYN, SYN_REPORT, 0);
5922 litest_drain_events(li);
5923
5924 /* take longer than the no-activity timeout */
5925 for (i = 0; i < 50; i++) {
5926 litest_event(dev, EV_ABS, ABS_X, 20000 + 10 * i);
5927 litest_event(dev, EV_ABS, ABS_Y, 20000 - 10 * i);
5928 litest_event(dev, EV_SYN, SYN_REPORT, 0);
5929 libinput_dispatch(li);
5930 msleep(5);
5931 }
5932 litest_assert_only_typed_events(li,
5933 LIBINPUT_EVENT_TABLET_TOOL_AXIS);
5934 litest_timeout_tablet_proxout();
5935 libinput_dispatch(li);
5936 litest_assert_tablet_proximity_event(li,
5937 LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT);
5938 libinput_dispatch(li);
5939 }
5940 END_TEST
5941
START_TEST(huion_static_btn_tool_pen_disable_quirk_on_prox_out)5942 START_TEST(huion_static_btn_tool_pen_disable_quirk_on_prox_out)
5943 {
5944 struct litest_device *dev = litest_current_device();
5945 struct libinput *li = dev->libinput;
5946 bool with_timeout = _i; /* ranged test */
5947 int i;
5948
5949 /* test is run twice, once where the real BTN_TOOL_PEN is triggered
5950 * during proximity out, one where the real BTN_TOOL_PEN is
5951 * triggered after we already triggered the quirk timeout
5952 */
5953
5954 litest_drain_events(li);
5955
5956 litest_event(dev, EV_ABS, ABS_X, 20000);
5957 litest_event(dev, EV_ABS, ABS_Y, 20000);
5958 litest_event(dev, EV_ABS, ABS_PRESSURE, 100);
5959 litest_event(dev, EV_KEY, BTN_TOOL_PEN, 1);
5960 litest_event(dev, EV_SYN, SYN_REPORT, 0);
5961 litest_drain_events(li);
5962
5963 for (i = 0; i < 10; i++) {
5964 litest_event(dev, EV_ABS, ABS_X, 20000 + 10 * i);
5965 litest_event(dev, EV_ABS, ABS_Y, 20000 - 10 * i);
5966 litest_event(dev, EV_SYN, SYN_REPORT, 0);
5967 libinput_dispatch(li);
5968 }
5969 litest_assert_only_typed_events(li,
5970 LIBINPUT_EVENT_TABLET_TOOL_AXIS);
5971
5972 /* Wait past the timeout to expect a proximity out */
5973 if (with_timeout) {
5974 litest_timeout_tablet_proxout();
5975 libinput_dispatch(li);
5976 litest_assert_tablet_proximity_event(li,
5977 LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT);
5978 }
5979
5980 /* Send a real prox out, expect quirk to be disabled */
5981 litest_event(dev, EV_KEY, BTN_TOOL_PEN, 0);
5982 litest_event(dev, EV_SYN, SYN_REPORT, 0);
5983 libinput_dispatch(li);
5984
5985 if (with_timeout) {
5986 /* we got the proximity event above already */
5987 litest_assert_empty_queue(li);
5988 } else {
5989 litest_assert_tablet_proximity_event(li,
5990 LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT);
5991 }
5992
5993 litest_tablet_proximity_in(dev, 50, 50, NULL);
5994 libinput_dispatch(li);
5995 litest_assert_tablet_proximity_event(li,
5996 LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN);
5997
5998 for (i = 0; i < 10; i++) {
5999 litest_tablet_motion(dev, 50 + i, 50 + i, NULL);
6000 libinput_dispatch(li);
6001 }
6002
6003 litest_assert_only_typed_events(li,
6004 LIBINPUT_EVENT_TABLET_TOOL_AXIS);
6005
6006 libinput_dispatch(li);
6007 litest_timeout_tablet_proxout();
6008 libinput_dispatch(li);
6009
6010 litest_assert_empty_queue(li);
6011
6012 litest_push_event_frame(dev);
6013 litest_tablet_proximity_out(dev);
6014 litest_event(dev, EV_KEY, BTN_TOOL_PEN, 0);
6015 litest_event(dev, EV_SYN, SYN_REPORT, 0);
6016 litest_pop_event_frame(dev);
6017 libinput_dispatch(li);
6018
6019 litest_assert_tablet_proximity_event(li,
6020 LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT);
6021 litest_assert_empty_queue(li);
6022 }
6023 END_TEST
6024
START_TEST(tablet_smoothing)6025 START_TEST(tablet_smoothing)
6026 {
6027 #if HAVE_LIBWACOM
6028 struct litest_device *dev = litest_current_device();
6029 struct libinput *li = dev->libinput;
6030 double x, y;
6031 struct point {
6032 double x, y;
6033 } coordinates[100] = {0};
6034 size_t npoints = 0;
6035 size_t idx = 0;
6036 struct axis_replacement axes[] = {
6037 { ABS_DISTANCE, 10 },
6038 { ABS_PRESSURE, 0 },
6039 { -1, -1 }
6040 };
6041
6042 litest_drain_events(li);
6043
6044 litest_tablet_proximity_in(dev, 10, 10, axes);
6045 libinput_dispatch(li);
6046 litest_drain_events(li);
6047
6048 /* Move in a straight line, collect the resulting points */
6049 for (x = 11, y = 11; x < 50; x++, y++) {
6050 struct libinput_event *event;
6051 struct libinput_event_tablet_tool *tev;
6052 struct point *p = &coordinates[npoints++];
6053
6054 litest_assert(npoints <= ARRAY_LENGTH(coordinates));
6055
6056 litest_tablet_motion(dev, x, y, axes);
6057 libinput_dispatch(li);
6058
6059 event = libinput_get_event(li);
6060 tev = litest_is_tablet_event(event,
6061 LIBINPUT_EVENT_TABLET_TOOL_AXIS);
6062 p->x = libinput_event_tablet_tool_get_x(tev);
6063 p->y = libinput_event_tablet_tool_get_y(tev);
6064
6065 libinput_event_destroy(event);
6066 }
6067
6068 litest_tablet_proximity_out(dev);
6069 litest_tablet_proximity_in(dev, 10, 10, axes);
6070 libinput_dispatch(li);
6071 litest_drain_events(li);
6072
6073 /* Move in a wobbly line, collect every second point */
6074 for (x = 11, y = 11; x < 50; x++, y++) {
6075 struct libinput_event *event;
6076 struct libinput_event_tablet_tool *tev;
6077 double ex, ey;
6078 struct point *p = &coordinates[idx++];
6079
6080 litest_assert(idx <= npoints);
6081
6082 /* point off position */
6083 litest_tablet_motion(dev, x - 2, y + 1, axes);
6084 libinput_dispatch(li);
6085 event = libinput_get_event(li);
6086 litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_AXIS);
6087 libinput_event_destroy(event);
6088
6089 /* same position as before */
6090 litest_tablet_motion(dev, x, y, axes);
6091 libinput_dispatch(li);
6092 event = libinput_get_event(li);
6093 tev = litest_is_tablet_event(event,
6094 LIBINPUT_EVENT_TABLET_TOOL_AXIS);
6095 ex = libinput_event_tablet_tool_get_x(tev);
6096 ey = libinput_event_tablet_tool_get_y(tev);
6097
6098 ck_assert_double_eq(ex, p->x);
6099 ck_assert_double_eq(ey, p->y);
6100
6101 libinput_event_destroy(event);
6102 }
6103 #endif
6104 }
6105 END_TEST
6106
TEST_COLLECTION(tablet)6107 TEST_COLLECTION(tablet)
6108 {
6109 struct range with_timeout = { 0, 2 };
6110 struct range xyaxes = { ABS_X, ABS_Y + 1 };
6111 struct range lh_transitions = {0, 16}; /* 2 bits for in, 2 bits for out */
6112
6113 litest_add(tool_ref, LITEST_TABLET | LITEST_TOOL_SERIAL, LITEST_ANY);
6114 litest_add(tool_user_data, LITEST_TABLET | LITEST_TOOL_SERIAL, LITEST_ANY);
6115 litest_add(tool_capability, LITEST_TABLET, LITEST_ANY);
6116 litest_add_no_device(tool_capabilities);
6117 litest_add(tool_type, LITEST_TABLET, LITEST_FORCED_PROXOUT);
6118 litest_add(tool_in_prox_before_start, LITEST_TABLET, LITEST_TOTEM);
6119 litest_add(tool_direct_switch_skip_tool_update, LITEST_TABLET, LITEST_ANY);
6120 litest_add(tool_direct_switch_with_forced_proxout, LITEST_TABLET, LITEST_ANY);
6121
6122 /* Tablets hold back the proximity until the first event from the
6123 * kernel, the totem sends it immediately */
6124 litest_add(tool_in_prox_before_start, LITEST_TABLET, LITEST_TOTEM);
6125 litest_add(tool_unique, LITEST_TABLET | LITEST_TOOL_SERIAL, LITEST_ANY);
6126 litest_add(tool_serial, LITEST_TABLET | LITEST_TOOL_SERIAL, LITEST_ANY);
6127 litest_add(tool_id, LITEST_TABLET | LITEST_TOOL_SERIAL, LITEST_ANY);
6128 litest_add(serial_changes_tool, LITEST_TABLET | LITEST_TOOL_SERIAL, LITEST_ANY);
6129 litest_add(invalid_serials, LITEST_TABLET | LITEST_TOOL_SERIAL, LITEST_ANY);
6130 litest_add_no_device(tools_with_serials);
6131 litest_add_no_device(tools_without_serials);
6132 litest_add_for_device(tool_delayed_serial, LITEST_WACOM_HID4800_PEN);
6133 litest_add(proximity_out_clear_buttons, LITEST_TABLET, LITEST_FORCED_PROXOUT);
6134 litest_add(proximity_in_out, LITEST_TABLET, LITEST_ANY);
6135 litest_add(proximity_in_button_down, LITEST_TABLET, LITEST_ANY);
6136 litest_add(proximity_out_button_up, LITEST_TABLET, LITEST_ANY);
6137 litest_add(proximity_has_axes, LITEST_TABLET, LITEST_ANY);
6138 litest_add(bad_distance_events, LITEST_TABLET | LITEST_DISTANCE, LITEST_ANY);
6139 litest_add(proximity_range_enter, LITEST_TABLET | LITEST_DISTANCE | LITEST_TOOL_MOUSE, LITEST_ANY);
6140 litest_add(proximity_range_in_out, LITEST_TABLET | LITEST_DISTANCE | LITEST_TOOL_MOUSE, LITEST_ANY);
6141 litest_add(proximity_range_button_click, LITEST_TABLET | LITEST_DISTANCE | LITEST_TOOL_MOUSE, LITEST_ANY);
6142 litest_add(proximity_range_button_press, LITEST_TABLET | LITEST_DISTANCE | LITEST_TOOL_MOUSE, LITEST_ANY);
6143 litest_add(proximity_range_button_release, LITEST_TABLET | LITEST_DISTANCE | LITEST_TOOL_MOUSE, LITEST_ANY);
6144 litest_add(proximity_out_slow_event, LITEST_TABLET | LITEST_DISTANCE, LITEST_ANY);
6145 litest_add(proximity_out_not_during_contact, LITEST_TABLET | LITEST_DISTANCE, LITEST_ANY);
6146 litest_add(proximity_out_not_during_buttonpress, LITEST_TABLET | LITEST_DISTANCE, LITEST_ANY);
6147 litest_add(proximity_out_disables_forced, LITEST_TABLET, LITEST_FORCED_PROXOUT|LITEST_TOTEM);
6148 litest_add(proximity_out_disables_forced_after_forced, LITEST_TABLET, LITEST_FORCED_PROXOUT|LITEST_TOTEM);
6149 litest_add_no_device(proximity_out_on_delete);
6150 litest_add(button_down_up, LITEST_TABLET, LITEST_ANY);
6151 litest_add(button_seat_count, LITEST_TABLET, LITEST_ANY);
6152 litest_add_no_device(button_up_on_delete);
6153 litest_add(tip_down_up, LITEST_TABLET|LITEST_HOVER, LITEST_ANY);
6154 litest_add(tip_down_prox_in, LITEST_TABLET, LITEST_ANY);
6155 litest_add(tip_up_prox_out, LITEST_TABLET, LITEST_ANY);
6156 litest_add(tip_down_btn_change, LITEST_TABLET|LITEST_HOVER, LITEST_ANY);
6157 litest_add(tip_up_btn_change, LITEST_TABLET|LITEST_HOVER, LITEST_ANY);
6158 litest_add(tip_down_motion, LITEST_TABLET|LITEST_HOVER, LITEST_ANY);
6159 litest_add(tip_up_motion, LITEST_TABLET|LITEST_HOVER, LITEST_ANY);
6160 litest_add(tip_down_up_eraser, LITEST_TABLET|LITEST_HOVER, LITEST_ANY);
6161 litest_add_ranged(tip_up_motion_one_axis, LITEST_TABLET|LITEST_HOVER, LITEST_ANY, &xyaxes);
6162 litest_add(tip_state_proximity, LITEST_TABLET|LITEST_HOVER, LITEST_ANY);
6163 litest_add(tip_state_axis, LITEST_TABLET|LITEST_HOVER, LITEST_ANY);
6164 litest_add(tip_state_button, LITEST_TABLET|LITEST_HOVER, LITEST_ANY);
6165 litest_add_no_device(tip_up_on_delete);
6166 litest_add(motion, LITEST_TABLET, LITEST_ANY);
6167 litest_add(motion_event_state, LITEST_TABLET, LITEST_ANY);
6168 litest_add_for_device(motion_outside_bounds, LITEST_WACOM_CINTIQ_24HD);
6169 litest_add(tilt_available, LITEST_TABLET|LITEST_TILT, LITEST_ANY);
6170 litest_add(tilt_not_available, LITEST_TABLET, LITEST_TILT);
6171 litest_add(tilt_x, LITEST_TABLET|LITEST_TILT, LITEST_ANY);
6172 litest_add(tilt_y, LITEST_TABLET|LITEST_TILT, LITEST_ANY);
6173 litest_add_for_device(left_handed, LITEST_WACOM_INTUOS);
6174 litest_add_for_device(left_handed_tilt, LITEST_WACOM_INTUOS);
6175 litest_add_for_device(left_handed_mouse_rotation, LITEST_WACOM_INTUOS);
6176 litest_add_for_device(left_handed_artpen_rotation, LITEST_WACOM_INTUOS);
6177 litest_add_for_device(no_left_handed, LITEST_WACOM_CINTIQ);
6178 litest_add(pad_buttons_ignored, LITEST_TABLET, LITEST_TOTEM);
6179 litest_add(mouse_tool, LITEST_TABLET | LITEST_TOOL_MOUSE, LITEST_ANY);
6180 litest_add(mouse_buttons, LITEST_TABLET | LITEST_TOOL_MOUSE, LITEST_ANY);
6181 litest_add(mouse_rotation, LITEST_TABLET | LITEST_TOOL_MOUSE, LITEST_ANY);
6182 litest_add(mouse_wheel, LITEST_TABLET | LITEST_TOOL_MOUSE, LITEST_WHEEL);
6183 litest_add(airbrush_tool, LITEST_TABLET, LITEST_ANY);
6184 litest_add(airbrush_slider, LITEST_TABLET, LITEST_ANY);
6185 litest_add(artpen_tool, LITEST_TABLET, LITEST_ANY);
6186 litest_add(artpen_rotation, LITEST_TABLET, LITEST_ANY);
6187
6188 litest_add(tablet_time_usec, LITEST_TABLET, LITEST_ANY);
6189 litest_add(tablet_pressure_distance_exclusive, LITEST_TABLET | LITEST_DISTANCE, LITEST_ANY);
6190
6191 /* The totem doesn't need calibration */
6192 litest_add(tablet_calibration_has_matrix, LITEST_TABLET, LITEST_TOTEM|LITEST_PRECALIBRATED);
6193 litest_add(tablet_calibration_set_matrix, LITEST_TABLET, LITEST_TOTEM|LITEST_PRECALIBRATED);
6194 litest_add(tablet_calibration_set_matrix_delta, LITEST_TABLET, LITEST_TOTEM|LITEST_PRECALIBRATED);
6195
6196 litest_add(tablet_pressure_min_max, LITEST_TABLET, LITEST_ANY);
6197 /* Tests for pressure offset with distance */
6198 litest_add_for_device(tablet_pressure_range, LITEST_WACOM_INTUOS);
6199 litest_add_for_device(tablet_pressure_offset_set, LITEST_WACOM_INTUOS);
6200 litest_add_for_device(tablet_pressure_offset_decrease, LITEST_WACOM_INTUOS);
6201 litest_add_for_device(tablet_pressure_offset_increase, LITEST_WACOM_INTUOS);
6202 litest_add_for_device(tablet_pressure_offset_exceed_threshold, LITEST_WACOM_INTUOS);
6203 litest_add_for_device(tablet_pressure_offset_none_for_zero_distance, LITEST_WACOM_INTUOS);
6204 litest_add_for_device(tablet_pressure_offset_none_for_small_distance, LITEST_WACOM_INTUOS);
6205 /* Tests for pressure offset without distance */
6206 litest_add_for_device(tablet_pressure_range, LITEST_WACOM_HID4800_PEN);
6207 litest_add_for_device(tablet_pressure_offset_set, LITEST_WACOM_HID4800_PEN);
6208 litest_add_for_device(tablet_pressure_offset_decrease, LITEST_WACOM_HID4800_PEN);
6209 litest_add_for_device(tablet_pressure_offset_increase, LITEST_WACOM_HID4800_PEN);
6210 litest_add_for_device(tablet_pressure_offset_exceed_threshold, LITEST_WACOM_HID4800_PEN);
6211
6212
6213 litest_add_for_device(tablet_distance_range, LITEST_WACOM_INTUOS);
6214
6215 litest_add(relative_no_profile, LITEST_TABLET, LITEST_ANY);
6216 litest_add(relative_no_delta_prox_in, LITEST_TABLET, LITEST_ANY);
6217 litest_add(relative_delta, LITEST_TABLET, LITEST_ANY);
6218 litest_add(relative_no_delta_on_tip, LITEST_TABLET|LITEST_HOVER, LITEST_ANY);
6219 litest_add(relative_calibration, LITEST_TABLET, LITEST_PRECALIBRATED);
6220
6221 litest_add(touch_arbitration, LITEST_TABLET, LITEST_ANY);
6222 litest_add(touch_arbitration_stop_touch, LITEST_TABLET, LITEST_ANY);
6223 litest_add(touch_arbitration_suspend_touch_device, LITEST_TOUCH, LITEST_ANY);
6224 litest_add(touch_arbitration_remove_touch, LITEST_TABLET, LITEST_ANY);
6225 litest_add(touch_arbitration_remove_tablet, LITEST_TOUCH, LITEST_ANY);
6226 litest_add(touch_arbitration_keep_ignoring, LITEST_TABLET, LITEST_ANY);
6227 litest_add(touch_arbitration_late_touch_lift, LITEST_TABLET, LITEST_ANY);
6228 litest_add(touch_arbitration_outside_rect, LITEST_TABLET | LITEST_DIRECT, LITEST_ANY);
6229 litest_add(touch_arbitration_remove_after, LITEST_TABLET | LITEST_DIRECT, LITEST_ANY);
6230 litest_add(touch_arbitration_swap_device, LITEST_TABLET, LITEST_ANY);
6231
6232 litest_add_ranged(tablet_rotation_left_handed, LITEST_TABLET, LITEST_ANY, &lh_transitions);
6233 litest_add_ranged(tablet_rotation_left_handed_configuration, LITEST_TABLET, LITEST_ANY, &lh_transitions);
6234 litest_add_ranged(tablet_rotation_left_handed_while_in_prox, LITEST_TABLET, LITEST_ANY, &lh_transitions);
6235 litest_add_ranged(tablet_rotation_left_handed_while_touch_down, LITEST_TABLET, LITEST_ANY, &lh_transitions);
6236 litest_add_ranged(tablet_rotation_left_handed_add_touchpad, LITEST_TABLET, LITEST_ANY, &lh_transitions);
6237 litest_add_ranged(tablet_rotation_left_handed_add_tablet, LITEST_TOUCHPAD, LITEST_ANY, &lh_transitions);
6238
6239 litest_add_for_device(huion_static_btn_tool_pen, LITEST_HUION_TABLET);
6240 litest_add_for_device(huion_static_btn_tool_pen_no_timeout_during_usage, LITEST_HUION_TABLET);
6241 litest_add_ranged_for_device(huion_static_btn_tool_pen_disable_quirk_on_prox_out, LITEST_HUION_TABLET, &with_timeout);
6242
6243 litest_add_for_device(tablet_smoothing, LITEST_WACOM_HID4800_PEN);
6244 }
6245