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