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