xref: /third_party/libinput/test/test-totem.c (revision a46c0ec8)
1/*
2 * Copyright © 2018 Red Hat, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 */
23
24#include <config.h>
25
26#include <check.h>
27#include <errno.h>
28#include <fcntl.h>
29#include <libinput.h>
30#include <unistd.h>
31#include <stdbool.h>
32#include <stdarg.h>
33
34#include "libinput-util.h"
35#include "evdev-tablet.h"
36#include "litest.h"
37#include "util-input-event.h"
38
39START_TEST(totem_type)
40{
41	struct litest_device *dev = litest_current_device();
42	struct libinput *li = dev->libinput;
43	struct libinput_event *event;
44	struct libinput_event_tablet_tool *t;
45	struct libinput_tablet_tool *tool;
46
47	litest_drain_events(li);
48
49	litest_tablet_proximity_in(dev, 50, 50, NULL);
50	libinput_dispatch(li);
51
52	event = libinput_get_event(li);
53	t = litest_is_tablet_event(event,
54				   LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
55	tool = libinput_event_tablet_tool_get_tool(t);
56
57	ck_assert_int_eq(libinput_tablet_tool_get_type(tool),
58			 LIBINPUT_TABLET_TOOL_TYPE_TOTEM);
59	libinput_event_destroy(event);
60}
61END_TEST
62
63START_TEST(totem_axes)
64{
65	struct litest_device *dev = litest_current_device();
66	struct libinput *li = dev->libinput;
67	struct libinput_event *event;
68	struct libinput_event_tablet_tool *t;
69	struct libinput_tablet_tool *tool;
70
71	litest_drain_events(li);
72
73	litest_tablet_proximity_in(dev, 50, 50, NULL);
74	libinput_dispatch(li);
75
76	event = libinput_get_event(li);
77	t = litest_is_tablet_event(event,
78				   LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
79	tool = libinput_event_tablet_tool_get_tool(t);
80
81	ck_assert(libinput_tablet_tool_has_rotation(tool));
82	ck_assert(libinput_tablet_tool_has_size(tool));
83	ck_assert(libinput_tablet_tool_has_button(tool, BTN_0));
84
85	libinput_event_destroy(event);
86}
87END_TEST
88
89START_TEST(totem_proximity_in_out)
90{
91	struct litest_device *dev = litest_current_device();
92	struct libinput *li = dev->libinput;
93	struct libinput_event *event;
94	struct libinput_event_tablet_tool *t;
95
96	litest_drain_events(li);
97
98	litest_tablet_proximity_in(dev, 50, 50, NULL);
99	libinput_dispatch(li);
100
101	event = libinput_get_event(li);
102	t = litest_is_tablet_event(event,
103				   LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
104	ck_assert_int_eq(libinput_event_tablet_tool_get_proximity_state(t),
105			 LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN);
106	libinput_event_destroy(event);
107
108	event = libinput_get_event(li);
109	t = litest_is_tablet_event(event,
110				   LIBINPUT_EVENT_TABLET_TOOL_TIP);
111	ck_assert_int_eq(libinput_event_tablet_tool_get_tip_state(t),
112			 LIBINPUT_TABLET_TOOL_TIP_DOWN);
113	libinput_event_destroy(event);
114
115	litest_assert_empty_queue(li);
116	litest_tablet_proximity_out(dev);
117	libinput_dispatch(li);
118
119	event = libinput_get_event(li);
120	t = litest_is_tablet_event(event,
121				   LIBINPUT_EVENT_TABLET_TOOL_TIP);
122	ck_assert_int_eq(libinput_event_tablet_tool_get_tip_state(t),
123			 LIBINPUT_TABLET_TOOL_TIP_UP);
124	libinput_event_destroy(event);
125
126	event = libinput_get_event(li);
127	t = litest_is_tablet_event(event,
128				   LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
129	ck_assert_int_eq(libinput_event_tablet_tool_get_proximity_state(t),
130			 LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT);
131	libinput_event_destroy(event);
132}
133END_TEST
134
135START_TEST(totem_proximity_in_on_init)
136{
137	struct litest_device *dev = litest_current_device();
138	struct libinput *li;
139	struct libinput_event *event;
140	struct libinput_event_tablet_tool *t;
141	const char *devnode;
142	double x, y;
143	double w, h;
144	const struct input_absinfo *abs;
145
146	abs = libevdev_get_abs_info(dev->evdev, ABS_MT_POSITION_X);
147	w = absinfo_range(abs)/abs->resolution;
148	abs = libevdev_get_abs_info(dev->evdev, ABS_MT_POSITION_Y);
149	h = absinfo_range(abs)/abs->resolution;
150
151	litest_tablet_proximity_in(dev, 50, 50, NULL);
152
153	/* for simplicity, we create a new litest context */
154	devnode = libevdev_uinput_get_devnode(dev->uinput);
155	li = litest_create_context();
156	libinput_path_add_device(li, devnode);
157	libinput_dispatch(li);
158
159	litest_wait_for_event_of_type(li,
160				      LIBINPUT_EVENT_DEVICE_ADDED,
161				      -1);
162	event = libinput_get_event(li);
163	libinput_event_destroy(event);
164
165	event = libinput_get_event(li);
166	t = litest_is_tablet_event(event,
167				   LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
168	ck_assert_int_eq(libinput_event_tablet_tool_get_proximity_state(t),
169			 LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN);
170	x = libinput_event_tablet_tool_get_x(t);
171	y = libinput_event_tablet_tool_get_y(t);
172
173	ck_assert_double_gt(x, w/2 - 1);
174	ck_assert_double_lt(x, w/2 + 1);
175	ck_assert_double_gt(y, h/2 - 1);
176	ck_assert_double_lt(y, h/2 + 1);
177
178	libinput_event_destroy(event);
179
180	event = libinput_get_event(li);
181	t = litest_is_tablet_event(event,
182				   LIBINPUT_EVENT_TABLET_TOOL_TIP);
183	ck_assert_int_eq(libinput_event_tablet_tool_get_tip_state(t),
184			 LIBINPUT_TABLET_TOOL_TIP_DOWN);
185	x = libinput_event_tablet_tool_get_x(t);
186	y = libinput_event_tablet_tool_get_y(t);
187
188	ck_assert_double_gt(x, w/2 - 1);
189	ck_assert_double_lt(x, w/2 + 1);
190	ck_assert_double_gt(y, h/2 - 1);
191	ck_assert_double_lt(y, h/2 + 1);
192
193	libinput_event_destroy(event);
194
195	litest_assert_empty_queue(li);
196
197	litest_destroy_context(li);
198}
199END_TEST
200
201START_TEST(totem_proximity_out_on_suspend)
202{
203	struct litest_device *dev = litest_current_device();
204	struct libinput *li;
205	struct libinput_event *event;
206	struct libinput_event_tablet_tool *t;
207	const char *devnode;
208
209	/* for simplicity, we create a new litest context */
210	devnode = libevdev_uinput_get_devnode(dev->uinput);
211	li = litest_create_context();
212	libinput_path_add_device(li, devnode);
213
214	litest_tablet_proximity_in(dev, 50, 50, NULL);
215	litest_drain_events(li);
216
217	libinput_suspend(li);
218
219	libinput_dispatch(li);
220	event = libinput_get_event(li);
221	t = litest_is_tablet_event(event,
222				   LIBINPUT_EVENT_TABLET_TOOL_TIP);
223	ck_assert_int_eq(libinput_event_tablet_tool_get_tip_state(t),
224			 LIBINPUT_TABLET_TOOL_TIP_UP);
225	libinput_event_destroy(event);
226
227	event = libinput_get_event(li);
228	t = litest_is_tablet_event(event,
229				   LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
230	ck_assert_int_eq(libinput_event_tablet_tool_get_proximity_state(t),
231			 LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT);
232	libinput_event_destroy(event);
233
234	litest_assert_only_typed_events(li, LIBINPUT_EVENT_DEVICE_REMOVED);
235	litest_destroy_context(li);
236}
237END_TEST
238
239START_TEST(totem_motion)
240{
241	struct litest_device *dev = litest_current_device();
242	struct libinput *li = dev->libinput;
243	struct libinput_event *event;
244	double x = 50, y = 50;
245	double current_x, current_y, old_x, old_y;
246
247	litest_tablet_proximity_in(dev, x, y, NULL);
248	litest_drain_events(li);
249
250	for (int i = 0; i < 30; i++, x++, y--) {
251		struct libinput_event_tablet_tool *t;
252
253		litest_tablet_motion(dev, x + 1, y + 1, NULL);
254		libinput_dispatch(li);
255
256		event = libinput_get_event(li);
257		t = litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_AXIS);
258
259		ck_assert(libinput_event_tablet_tool_x_has_changed(t));
260		ck_assert(libinput_event_tablet_tool_y_has_changed(t));
261
262		current_x = libinput_event_tablet_tool_get_x(t);
263		current_y = libinput_event_tablet_tool_get_y(t);
264		if (i != 0) {
265			ck_assert_double_gt(current_x, old_x);
266			ck_assert_double_lt(current_y, old_y);
267		}
268		old_x = current_x;
269		old_y = current_y;
270
271		libinput_event_destroy(event);
272	}
273}
274END_TEST
275
276START_TEST(totem_rotation)
277{
278	struct litest_device *dev = litest_current_device();
279	struct libinput *li = dev->libinput;
280	struct libinput_event *event;
281	double r, old_r;
282	struct axis_replacement axes[] = {
283		{ ABS_MT_ORIENTATION, 50 }, /* mid-point is 0 */
284		{ -1, -1 }
285	};
286
287	litest_tablet_proximity_in(dev, 50, 50, axes);
288	litest_drain_events(li);
289
290	old_r = 360;
291
292	for (int i = 1; i < 30; i++) {
293		struct libinput_event_tablet_tool *t;
294
295
296		litest_axis_set_value(axes, ABS_MT_ORIENTATION, 50 + i);
297		litest_tablet_motion(dev, 50, 50, axes);
298		libinput_dispatch(li);
299
300		event = libinput_get_event(li);
301		t = litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_AXIS);
302
303		ck_assert(!libinput_event_tablet_tool_x_has_changed(t));
304		ck_assert(!libinput_event_tablet_tool_y_has_changed(t));
305		ck_assert(libinput_event_tablet_tool_rotation_has_changed(t));
306
307		r = libinput_event_tablet_tool_get_rotation(t);
308		ck_assert_double_lt(r, old_r);
309		old_r = r;
310
311		libinput_event_destroy(event);
312	}
313
314	old_r = 0;
315
316	for (int i = 1; i < 30; i++) {
317		struct libinput_event_tablet_tool *t;
318
319
320		litest_axis_set_value(axes, ABS_MT_ORIENTATION, 50 - i);
321		litest_tablet_motion(dev, 50, 50, axes);
322		libinput_dispatch(li);
323
324		event = libinput_get_event(li);
325		t = litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_AXIS);
326
327		ck_assert(!libinput_event_tablet_tool_x_has_changed(t));
328		ck_assert(!libinput_event_tablet_tool_y_has_changed(t));
329		ck_assert(libinput_event_tablet_tool_rotation_has_changed(t));
330
331		r = libinput_event_tablet_tool_get_rotation(t);
332		ck_assert_double_gt(r, old_r);
333		old_r = r;
334
335		libinput_event_destroy(event);
336	}
337}
338END_TEST
339
340START_TEST(totem_size)
341{
342	struct litest_device *dev = litest_current_device();
343	struct libinput *li = dev->libinput;
344	struct libinput_event *event;
345	struct libinput_event_tablet_tool *t;
346	double smin, smaj;
347
348	litest_drain_events(li);
349
350	litest_tablet_proximity_in(dev, 50, 50, NULL);
351	libinput_dispatch(li);
352
353	event = libinput_get_event(li);
354	t = litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
355	ck_assert(libinput_event_tablet_tool_size_major_has_changed(t));
356	ck_assert(libinput_event_tablet_tool_size_minor_has_changed(t));
357	smaj = libinput_event_tablet_tool_get_size_major(t);
358	smin = libinput_event_tablet_tool_get_size_minor(t);
359	libinput_event_destroy(event);
360
361	ck_assert_double_eq(smaj, 71.8);
362	ck_assert_double_eq(smin, 71.8);
363
364	litest_drain_events(li);
365}
366END_TEST
367
368START_TEST(totem_button)
369{
370	struct litest_device *dev = litest_current_device();
371	struct libinput *li = dev->libinput;
372	struct libinput_event *event;
373	struct libinput_event_tablet_tool *t;
374
375	litest_tablet_proximity_in(dev, 30, 40, NULL);
376	litest_drain_events(li);
377
378	litest_button_click(dev, BTN_0, true);
379	libinput_dispatch(li);
380	event = libinput_get_event(li);
381	t = litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_BUTTON);
382	ck_assert_int_eq(libinput_event_tablet_tool_get_button(t), BTN_0);
383	ck_assert_int_eq(libinput_event_tablet_tool_get_button_state(t),
384			 LIBINPUT_BUTTON_STATE_PRESSED);
385	ck_assert_int_eq(libinput_event_tablet_tool_get_tip_state(t),
386			 LIBINPUT_TABLET_TOOL_TIP_DOWN);
387	libinput_event_destroy(event);
388
389	litest_button_click(dev, BTN_0, false);
390	libinput_dispatch(li);
391
392	event = libinput_get_event(li);
393	t = litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_BUTTON);
394	ck_assert_int_eq(libinput_event_tablet_tool_get_button(t), BTN_0);
395	ck_assert_int_eq(libinput_event_tablet_tool_get_button_state(t),
396			 LIBINPUT_BUTTON_STATE_RELEASED);
397	ck_assert_int_eq(libinput_event_tablet_tool_get_tip_state(t),
398			 LIBINPUT_TABLET_TOOL_TIP_DOWN);
399	libinput_event_destroy(event);
400}
401END_TEST
402
403START_TEST(totem_button_down_on_init)
404{
405	struct litest_device *dev = litest_current_device();
406	struct libinput *li;
407	struct libinput_event *event;
408	struct libinput_event_tablet_tool *t;
409	const char *devnode;
410
411	litest_tablet_proximity_in(dev, 50, 50, NULL);
412	litest_button_click(dev, BTN_0, true);
413
414	/* for simplicity, we create a new litest context */
415	devnode = libevdev_uinput_get_devnode(dev->uinput);
416	li = litest_create_context();
417	libinput_path_add_device(li, devnode);
418	libinput_dispatch(li);
419
420	litest_wait_for_event_of_type(li,
421				      LIBINPUT_EVENT_DEVICE_ADDED,
422				      -1);
423	event = libinput_get_event(li);
424	libinput_event_destroy(event);
425
426	event = libinput_get_event(li);
427	t = litest_is_tablet_event(event,
428				   LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
429	ck_assert_int_eq(libinput_event_tablet_tool_get_proximity_state(t),
430			 LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN);
431
432	libinput_event_destroy(event);
433
434	event = libinput_get_event(li);
435	t = litest_is_tablet_event(event,
436				   LIBINPUT_EVENT_TABLET_TOOL_TIP);
437	ck_assert_int_eq(libinput_event_tablet_tool_get_tip_state(t),
438			 LIBINPUT_TABLET_TOOL_TIP_DOWN);
439
440	libinput_event_destroy(event);
441
442	/* The button is down on init but we don't expect an event */
443	litest_assert_empty_queue(li);
444
445	litest_button_click(dev, BTN_0, false);
446	libinput_dispatch(li);
447	litest_assert_empty_queue(li);
448
449	/* but buttons after this should be sent */
450	litest_button_click(dev, BTN_0, true);
451	libinput_dispatch(li);
452	litest_assert_tablet_button_event(li, BTN_0, LIBINPUT_BUTTON_STATE_PRESSED);
453	litest_button_click(dev, BTN_0, false);
454	libinput_dispatch(li);
455	litest_assert_tablet_button_event(li, BTN_0, LIBINPUT_BUTTON_STATE_RELEASED);
456
457	litest_destroy_context(li);
458}
459END_TEST
460
461START_TEST(totem_button_up_on_delete)
462{
463	struct libinput *li = litest_create_context();
464	struct litest_device *dev = litest_add_device(li, LITEST_DELL_CANVAS_TOTEM);
465	struct libevdev *evdev = libevdev_new();
466
467	litest_tablet_proximity_in(dev, 10, 10, NULL);
468	litest_drain_events(li);
469
470	litest_button_click(dev, BTN_0, true);
471	litest_drain_events(li);
472
473	litest_delete_device(dev);
474	libinput_dispatch(li);
475
476	litest_assert_tablet_button_event(li,
477					  BTN_0,
478					  LIBINPUT_BUTTON_STATE_RELEASED);
479
480	litest_assert_tablet_tip_event(li, LIBINPUT_TABLET_TOOL_TIP_UP);
481	litest_assert_tablet_proximity_event(li,
482					     LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT);
483	libevdev_free(evdev);
484	litest_destroy_context(li);
485}
486END_TEST
487
488START_TEST(totem_arbitration_below)
489{
490	struct litest_device *totem = litest_current_device();
491	struct litest_device *touch;
492	struct libinput *li = totem->libinput;
493
494	touch = litest_add_device(li, LITEST_DELL_CANVAS_TOTEM_TOUCH);
495	litest_drain_events(li);
496
497	/* touches below the totem, cancelled once the totem is down */
498	litest_touch_down(touch, 0, 50, 50);
499	libinput_dispatch(li);
500	litest_assert_touch_down_frame(li);
501	litest_touch_move_to(touch, 0, 50, 50, 50, 70, 10);
502	libinput_dispatch(li);
503	while (libinput_next_event_type(li)) {
504		litest_assert_touch_motion_frame(li);
505	}
506
507	litest_tablet_proximity_in(totem, 50, 70, NULL);
508	libinput_dispatch(li);
509
510	litest_assert_tablet_proximity_event(li, LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN);
511	litest_assert_tablet_tip_event(li, LIBINPUT_TABLET_TOOL_TIP_DOWN);
512	litest_assert_touch_cancel(li);
513
514	litest_touch_move_to(touch, 0, 50, 70, 20, 50, 10);
515	litest_assert_empty_queue(li);
516
517	litest_tablet_motion(totem, 20, 50, NULL);
518	litest_assert_only_typed_events(li, LIBINPUT_EVENT_TABLET_TOOL_AXIS);
519
520	litest_touch_up(touch, 0);
521	litest_assert_empty_queue(li);
522
523	litest_delete_device(touch);
524}
525END_TEST
526
527START_TEST(totem_arbitration_during)
528{
529	struct litest_device *totem = litest_current_device();
530	struct litest_device *touch;
531	struct libinput *li = totem->libinput;
532
533	touch = litest_add_device(li, LITEST_DELL_CANVAS_TOTEM_TOUCH);
534	litest_drain_events(li);
535
536	litest_tablet_proximity_in(totem, 50, 50, NULL);
537	libinput_dispatch(li);
538
539	litest_drain_events(li);
540
541	for (int i = 0; i < 3; i++) {
542		litest_touch_down(touch, 0, 51, 51);
543		litest_touch_move_to(touch, 0, 51, 50, 90, 80, 10);
544		litest_touch_up(touch, 0);
545
546		litest_assert_empty_queue(li);
547	}
548
549	litest_delete_device(touch);
550}
551END_TEST
552
553START_TEST(totem_arbitration_outside_rect)
554{
555	struct litest_device *totem = litest_current_device();
556	struct litest_device *touch;
557	struct libinput *li = totem->libinput;
558
559	touch = litest_add_device(li, LITEST_DELL_CANVAS_TOTEM_TOUCH);
560	litest_drain_events(li);
561
562	litest_tablet_proximity_in(totem, 50, 50, NULL);
563	libinput_dispatch(li);
564
565	litest_drain_events(li);
566
567	for (int i = 0; i < 3; i++) {
568		litest_touch_down(touch, 0, 81, 51);
569		litest_touch_move_to(touch, 0, 81, 50, 90, 80, 10);
570		litest_touch_up(touch, 0);
571		libinput_dispatch(li);
572
573		litest_assert_touch_sequence(li);
574	}
575
576	/* moving onto the totem is fine */
577	litest_touch_down(touch, 0, 81, 51);
578	litest_touch_move_to(touch, 0, 81, 50, 50, 50, 10);
579	litest_touch_up(touch, 0);
580	libinput_dispatch(li);
581
582	litest_assert_touch_sequence(li);
583
584	litest_delete_device(touch);
585}
586END_TEST
587
588TEST_COLLECTION(totem)
589{
590	litest_add(totem_type, LITEST_TOTEM, LITEST_ANY);
591	litest_add(totem_axes, LITEST_TOTEM, LITEST_ANY);
592	litest_add(totem_proximity_in_out, LITEST_TOTEM, LITEST_ANY);
593	litest_add(totem_proximity_in_on_init, LITEST_TOTEM, LITEST_ANY);
594	litest_add(totem_proximity_out_on_suspend, LITEST_TOTEM, LITEST_ANY);
595
596	litest_add(totem_motion, LITEST_TOTEM, LITEST_ANY);
597	litest_add(totem_rotation, LITEST_TOTEM, LITEST_ANY);
598	litest_add(totem_size, LITEST_TOTEM, LITEST_ANY);
599	litest_add(totem_button, LITEST_TOTEM, LITEST_ANY);
600	litest_add(totem_button_down_on_init, LITEST_TOTEM, LITEST_ANY);
601	litest_add_no_device(totem_button_up_on_delete);
602
603	litest_add(totem_arbitration_below, LITEST_TOTEM, LITEST_ANY);
604	litest_add(totem_arbitration_during, LITEST_TOTEM, LITEST_ANY);
605	litest_add(totem_arbitration_outside_rect, LITEST_TOTEM, LITEST_ANY);
606}
607