1a46c0ec8Sopenharmony_ci/*
2a46c0ec8Sopenharmony_ci * Copyright © 2013 Red Hat, Inc.
3a46c0ec8Sopenharmony_ci * Copyright © 2013 Marcin Slusarz <marcin.slusarz@gmail.com>
4a46c0ec8Sopenharmony_ci *
5a46c0ec8Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
6a46c0ec8Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
7a46c0ec8Sopenharmony_ci * to deal in the Software without restriction, including without limitation
8a46c0ec8Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9a46c0ec8Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
10a46c0ec8Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
11a46c0ec8Sopenharmony_ci *
12a46c0ec8Sopenharmony_ci * The above copyright notice and this permission notice (including the next
13a46c0ec8Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
14a46c0ec8Sopenharmony_ci * Software.
15a46c0ec8Sopenharmony_ci *
16a46c0ec8Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17a46c0ec8Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18a46c0ec8Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19a46c0ec8Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20a46c0ec8Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21a46c0ec8Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22a46c0ec8Sopenharmony_ci * DEALINGS IN THE SOFTWARE.
23a46c0ec8Sopenharmony_ci */
24a46c0ec8Sopenharmony_ci
25a46c0ec8Sopenharmony_ci#include "config.h"
26a46c0ec8Sopenharmony_ci
27a46c0ec8Sopenharmony_ci#include <check.h>
28a46c0ec8Sopenharmony_ci#include <dirent.h>
29a46c0ec8Sopenharmony_ci#include <errno.h>
30a46c0ec8Sopenharmony_ci#include <libgen.h>
31a46c0ec8Sopenharmony_ci#include <fcntl.h>
32a46c0ec8Sopenharmony_ci#include <fnmatch.h>
33a46c0ec8Sopenharmony_ci#include <getopt.h>
34a46c0ec8Sopenharmony_ci#include <poll.h>
35a46c0ec8Sopenharmony_ci#include <signal.h>
36a46c0ec8Sopenharmony_ci#include <stdint.h>
37a46c0ec8Sopenharmony_ci#include <stdio.h>
38a46c0ec8Sopenharmony_ci#include <stdlib.h>
39a46c0ec8Sopenharmony_ci#include <stdarg.h>
40a46c0ec8Sopenharmony_ci#include <time.h>
41a46c0ec8Sopenharmony_ci#include <unistd.h>
42a46c0ec8Sopenharmony_ci#include "linux/input.h"
43a46c0ec8Sopenharmony_ci#include <sys/ptrace.h>
44a46c0ec8Sopenharmony_ci#include <sys/resource.h>
45a46c0ec8Sopenharmony_ci#include <sys/timerfd.h>
46a46c0ec8Sopenharmony_ci#include <sys/wait.h>
47a46c0ec8Sopenharmony_ci#include <sys/stat.h>
48a46c0ec8Sopenharmony_ci#include <sys/types.h>
49a46c0ec8Sopenharmony_ci#include <sys/sysinfo.h>
50a46c0ec8Sopenharmony_ci#include <libudev.h>
51a46c0ec8Sopenharmony_ci#if HAVE_LIBSYSTEMD
52a46c0ec8Sopenharmony_ci#include <systemd/sd-bus.h>
53a46c0ec8Sopenharmony_ci#endif
54a46c0ec8Sopenharmony_ci#ifdef __FreeBSD__
55a46c0ec8Sopenharmony_ci#include <termios.h>
56a46c0ec8Sopenharmony_ci#endif
57a46c0ec8Sopenharmony_ci
58a46c0ec8Sopenharmony_ci#include <valgrind/valgrind.h>
59a46c0ec8Sopenharmony_ci
60a46c0ec8Sopenharmony_ci#include "litest.h"
61a46c0ec8Sopenharmony_ci#include "litest-int.h"
62a46c0ec8Sopenharmony_ci#include "libinput-util.h"
63a46c0ec8Sopenharmony_ci#include "quirks.h"
64a46c0ec8Sopenharmony_ci#include "builddir.h"
65a46c0ec8Sopenharmony_ci
66a46c0ec8Sopenharmony_ci#include <linux/kd.h>
67a46c0ec8Sopenharmony_ci
68a46c0ec8Sopenharmony_ci#define evbit(t, c) ((t) << 16U | (c & 0xffff))
69a46c0ec8Sopenharmony_ci
70a46c0ec8Sopenharmony_ci#define UDEV_RULES_D "/run/udev/rules.d"
71a46c0ec8Sopenharmony_ci#define UDEV_FUZZ_OVERRIDE_RULE_FILE UDEV_RULES_D \
72a46c0ec8Sopenharmony_ci	"/91-litest-fuzz-override-REMOVEME-XXXXXX.rules"
73a46c0ec8Sopenharmony_ci#define UDEV_TEST_DEVICE_RULE_FILE UDEV_RULES_D \
74a46c0ec8Sopenharmony_ci	"/91-litest-test-device-REMOVEME-XXXXXXX.rules"
75a46c0ec8Sopenharmony_ci#define UDEV_DEVICE_GROUPS_FILE UDEV_RULES_D \
76a46c0ec8Sopenharmony_ci	"/80-libinput-device-groups-litest-XXXXXX.rules"
77a46c0ec8Sopenharmony_ci
78a46c0ec8Sopenharmony_cistatic int jobs;
79a46c0ec8Sopenharmony_cistatic bool in_debugger = false;
80a46c0ec8Sopenharmony_cistatic bool verbose = false;
81a46c0ec8Sopenharmony_cistatic bool run_deviceless = false;
82a46c0ec8Sopenharmony_cistatic bool use_system_rules_quirks = false;
83a46c0ec8Sopenharmony_cistatic const char *filter_test = NULL;
84a46c0ec8Sopenharmony_cistatic const char *filter_device = NULL;
85a46c0ec8Sopenharmony_cistatic const char *filter_group = NULL;
86a46c0ec8Sopenharmony_cistatic const char *xml_prefix = NULL;
87a46c0ec8Sopenharmony_cistatic struct quirks_context *quirks_context;
88a46c0ec8Sopenharmony_ci
89a46c0ec8Sopenharmony_cistruct created_file {
90a46c0ec8Sopenharmony_ci	struct list link;
91a46c0ec8Sopenharmony_ci	char *path;
92a46c0ec8Sopenharmony_ci};
93a46c0ec8Sopenharmony_ci
94a46c0ec8Sopenharmony_cistatic struct list created_files_list; /* list of all files to remove at the end
95a46c0ec8Sopenharmony_ci					  of the test run */
96a46c0ec8Sopenharmony_ci
97a46c0ec8Sopenharmony_cistatic void litest_init_udev_rules(struct list *created_files_list);
98a46c0ec8Sopenharmony_cistatic void litest_remove_udev_rules(struct list *created_files_list);
99a46c0ec8Sopenharmony_ci
100a46c0ec8Sopenharmony_cienum quirks_setup_mode {
101a46c0ec8Sopenharmony_ci	QUIRKS_SETUP_USE_SRCDIR,
102a46c0ec8Sopenharmony_ci	QUIRKS_SETUP_ONLY_DEVICE,
103a46c0ec8Sopenharmony_ci	QUIRKS_SETUP_FULL,
104a46c0ec8Sopenharmony_ci};
105a46c0ec8Sopenharmony_cistatic void litest_setup_quirks(struct list *created_files_list,
106a46c0ec8Sopenharmony_ci				enum quirks_setup_mode mode);
107a46c0ec8Sopenharmony_ci
108a46c0ec8Sopenharmony_ci/* defined for the litest selftest */
109a46c0ec8Sopenharmony_ci#ifndef LITEST_DISABLE_BACKTRACE_LOGGING
110a46c0ec8Sopenharmony_ci#define litest_log(...) fprintf(stderr, __VA_ARGS__)
111a46c0ec8Sopenharmony_ci#define litest_vlog(format_, args_) vfprintf(stderr, format_, args_)
112a46c0ec8Sopenharmony_ci#else
113a46c0ec8Sopenharmony_ci#define litest_log(...) { /* __VA_ARGS__ */ }
114a46c0ec8Sopenharmony_ci#define litest_vlog(...) { /* __VA_ARGS__ */ }
115a46c0ec8Sopenharmony_ci#endif
116a46c0ec8Sopenharmony_ci
117a46c0ec8Sopenharmony_cistatic void
118a46c0ec8Sopenharmony_cilitest_backtrace(void)
119a46c0ec8Sopenharmony_ci{
120a46c0ec8Sopenharmony_ci#if HAVE_GSTACK
121a46c0ec8Sopenharmony_ci	pid_t parent, child;
122a46c0ec8Sopenharmony_ci	int pipefd[2];
123a46c0ec8Sopenharmony_ci
124a46c0ec8Sopenharmony_ci	if (RUNNING_ON_VALGRIND) {
125a46c0ec8Sopenharmony_ci		litest_log("  Using valgrind, omitting backtrace\n");
126a46c0ec8Sopenharmony_ci		return;
127a46c0ec8Sopenharmony_ci	}
128a46c0ec8Sopenharmony_ci
129a46c0ec8Sopenharmony_ci	if (pipe(pipefd) == -1)
130a46c0ec8Sopenharmony_ci		return;
131a46c0ec8Sopenharmony_ci
132a46c0ec8Sopenharmony_ci	parent = getpid();
133a46c0ec8Sopenharmony_ci	child = fork();
134a46c0ec8Sopenharmony_ci
135a46c0ec8Sopenharmony_ci	if (child == 0) {
136a46c0ec8Sopenharmony_ci		char pid[8];
137a46c0ec8Sopenharmony_ci
138a46c0ec8Sopenharmony_ci		close(pipefd[0]);
139a46c0ec8Sopenharmony_ci		dup2(pipefd[1], STDOUT_FILENO);
140a46c0ec8Sopenharmony_ci
141a46c0ec8Sopenharmony_ci		sprintf(pid, "%d", parent);
142a46c0ec8Sopenharmony_ci
143a46c0ec8Sopenharmony_ci		execlp("gstack", "gstack", pid, NULL);
144a46c0ec8Sopenharmony_ci		exit(errno);
145a46c0ec8Sopenharmony_ci	}
146a46c0ec8Sopenharmony_ci
147a46c0ec8Sopenharmony_ci	/* parent */
148a46c0ec8Sopenharmony_ci	char buf[1024];
149a46c0ec8Sopenharmony_ci	int status, nread;
150a46c0ec8Sopenharmony_ci
151a46c0ec8Sopenharmony_ci	close(pipefd[1]);
152a46c0ec8Sopenharmony_ci	waitpid(child, &status, 0);
153a46c0ec8Sopenharmony_ci
154a46c0ec8Sopenharmony_ci	status = WEXITSTATUS(status);
155a46c0ec8Sopenharmony_ci	if (status != 0) {
156a46c0ec8Sopenharmony_ci		litest_log("ERROR: gstack failed, no backtrace available: %s\n",
157a46c0ec8Sopenharmony_ci			   strerror(status));
158a46c0ec8Sopenharmony_ci	} else {
159a46c0ec8Sopenharmony_ci		litest_log("\nBacktrace:\n");
160a46c0ec8Sopenharmony_ci		while ((nread = read(pipefd[0], buf, sizeof(buf) - 1)) > 0) {
161a46c0ec8Sopenharmony_ci			buf[nread] = '\0';
162a46c0ec8Sopenharmony_ci			litest_log("%s", buf);
163a46c0ec8Sopenharmony_ci		}
164a46c0ec8Sopenharmony_ci		litest_log("\n");
165a46c0ec8Sopenharmony_ci	}
166a46c0ec8Sopenharmony_ci	close(pipefd[0]);
167a46c0ec8Sopenharmony_ci#endif
168a46c0ec8Sopenharmony_ci}
169a46c0ec8Sopenharmony_ci
170a46c0ec8Sopenharmony_ciLIBINPUT_ATTRIBUTE_PRINTF(5, 6)
171a46c0ec8Sopenharmony_ci__attribute__((noreturn))
172a46c0ec8Sopenharmony_civoid
173a46c0ec8Sopenharmony_cilitest_fail_condition(const char *file,
174a46c0ec8Sopenharmony_ci		      int line,
175a46c0ec8Sopenharmony_ci		      const char *func,
176a46c0ec8Sopenharmony_ci		      const char *condition,
177a46c0ec8Sopenharmony_ci		      const char *message,
178a46c0ec8Sopenharmony_ci		      ...)
179a46c0ec8Sopenharmony_ci{
180a46c0ec8Sopenharmony_ci	litest_log("FAILED: %s\n", condition);
181a46c0ec8Sopenharmony_ci
182a46c0ec8Sopenharmony_ci	if (message) {
183a46c0ec8Sopenharmony_ci		va_list args;
184a46c0ec8Sopenharmony_ci		va_start(args, message);
185a46c0ec8Sopenharmony_ci		litest_vlog(message, args);
186a46c0ec8Sopenharmony_ci		va_end(args);
187a46c0ec8Sopenharmony_ci	}
188a46c0ec8Sopenharmony_ci
189a46c0ec8Sopenharmony_ci	litest_log("in %s() (%s:%d)\n", func, file, line);
190a46c0ec8Sopenharmony_ci	litest_backtrace();
191a46c0ec8Sopenharmony_ci	abort();
192a46c0ec8Sopenharmony_ci}
193a46c0ec8Sopenharmony_ci
194a46c0ec8Sopenharmony_ci__attribute__((noreturn))
195a46c0ec8Sopenharmony_civoid
196a46c0ec8Sopenharmony_cilitest_fail_comparison_int(const char *file,
197a46c0ec8Sopenharmony_ci			   int line,
198a46c0ec8Sopenharmony_ci			   const char *func,
199a46c0ec8Sopenharmony_ci			   const char *operator,
200a46c0ec8Sopenharmony_ci			   int a,
201a46c0ec8Sopenharmony_ci			   int b,
202a46c0ec8Sopenharmony_ci			   const char *astr,
203a46c0ec8Sopenharmony_ci			   const char *bstr)
204a46c0ec8Sopenharmony_ci{
205a46c0ec8Sopenharmony_ci	litest_log("FAILED COMPARISON: %s %s %s\n", astr, operator, bstr);
206a46c0ec8Sopenharmony_ci	litest_log("Resolved to: %d %s %d\n", a, operator, b);
207a46c0ec8Sopenharmony_ci	litest_log("in %s() (%s:%d)\n", func, file, line);
208a46c0ec8Sopenharmony_ci	litest_backtrace();
209a46c0ec8Sopenharmony_ci	abort();
210a46c0ec8Sopenharmony_ci}
211a46c0ec8Sopenharmony_ci
212a46c0ec8Sopenharmony_ci__attribute__((noreturn))
213a46c0ec8Sopenharmony_civoid
214a46c0ec8Sopenharmony_cilitest_fail_comparison_double(const char *file,
215a46c0ec8Sopenharmony_ci			      int line,
216a46c0ec8Sopenharmony_ci			      const char *func,
217a46c0ec8Sopenharmony_ci			      const char *operator,
218a46c0ec8Sopenharmony_ci			      double a,
219a46c0ec8Sopenharmony_ci			      double b,
220a46c0ec8Sopenharmony_ci			      const char *astr,
221a46c0ec8Sopenharmony_ci			      const char *bstr)
222a46c0ec8Sopenharmony_ci{
223a46c0ec8Sopenharmony_ci	litest_log("FAILED COMPARISON: %s %s %s\n", astr, operator, bstr);
224a46c0ec8Sopenharmony_ci	litest_log("Resolved to: %.3f %s %.3f\n", a, operator, b);
225a46c0ec8Sopenharmony_ci	litest_log("in %s() (%s:%d)\n", func, file, line);
226a46c0ec8Sopenharmony_ci	litest_backtrace();
227a46c0ec8Sopenharmony_ci	abort();
228a46c0ec8Sopenharmony_ci}
229a46c0ec8Sopenharmony_ci
230a46c0ec8Sopenharmony_ci__attribute__((noreturn))
231a46c0ec8Sopenharmony_civoid
232a46c0ec8Sopenharmony_cilitest_fail_comparison_ptr(const char *file,
233a46c0ec8Sopenharmony_ci			   int line,
234a46c0ec8Sopenharmony_ci			   const char *func,
235a46c0ec8Sopenharmony_ci			   const char *comparison)
236a46c0ec8Sopenharmony_ci{
237a46c0ec8Sopenharmony_ci	litest_log("FAILED COMPARISON: %s\n", comparison);
238a46c0ec8Sopenharmony_ci	litest_log("in %s() (%s:%d)\n", func, file, line);
239a46c0ec8Sopenharmony_ci	litest_backtrace();
240a46c0ec8Sopenharmony_ci	abort();
241a46c0ec8Sopenharmony_ci}
242a46c0ec8Sopenharmony_ci
243a46c0ec8Sopenharmony_cistruct test {
244a46c0ec8Sopenharmony_ci	struct list node;
245a46c0ec8Sopenharmony_ci	char *name;
246a46c0ec8Sopenharmony_ci	char *devname;
247a46c0ec8Sopenharmony_ci	const void *func;
248a46c0ec8Sopenharmony_ci	void *setup;
249a46c0ec8Sopenharmony_ci	void *teardown;
250a46c0ec8Sopenharmony_ci
251a46c0ec8Sopenharmony_ci	struct range range;
252a46c0ec8Sopenharmony_ci	bool deviceless;
253a46c0ec8Sopenharmony_ci};
254a46c0ec8Sopenharmony_ci
255a46c0ec8Sopenharmony_cistruct suite {
256a46c0ec8Sopenharmony_ci	struct list node;
257a46c0ec8Sopenharmony_ci	struct list tests;
258a46c0ec8Sopenharmony_ci	char *name;
259a46c0ec8Sopenharmony_ci};
260a46c0ec8Sopenharmony_ci
261a46c0ec8Sopenharmony_cistatic struct litest_device *current_device;
262a46c0ec8Sopenharmony_ci
263a46c0ec8Sopenharmony_cistruct litest_device *litest_current_device(void)
264a46c0ec8Sopenharmony_ci{
265a46c0ec8Sopenharmony_ci	return current_device;
266a46c0ec8Sopenharmony_ci}
267a46c0ec8Sopenharmony_ci
268a46c0ec8Sopenharmony_cistatic void
269a46c0ec8Sopenharmony_cigrab_device(struct litest_device *device, bool mode)
270a46c0ec8Sopenharmony_ci{
271a46c0ec8Sopenharmony_ci	struct libinput *li = libinput_device_get_context(device->libinput_device);
272a46c0ec8Sopenharmony_ci	struct litest_context *ctx = libinput_get_user_data(li);
273a46c0ec8Sopenharmony_ci	struct udev_device *udev_device;
274a46c0ec8Sopenharmony_ci	const char *devnode;
275a46c0ec8Sopenharmony_ci	struct path *p;
276a46c0ec8Sopenharmony_ci
277a46c0ec8Sopenharmony_ci	udev_device = libinput_device_get_udev_device(device->libinput_device);
278a46c0ec8Sopenharmony_ci	litest_assert_ptr_notnull(udev_device);
279a46c0ec8Sopenharmony_ci
280a46c0ec8Sopenharmony_ci	devnode = udev_device_get_devnode(udev_device);
281a46c0ec8Sopenharmony_ci
282a46c0ec8Sopenharmony_ci	/* Note: in some tests we create multiple devices for the same path.
283a46c0ec8Sopenharmony_ci	 * This will only grab the first device in the list but we're using
284a46c0ec8Sopenharmony_ci	 * list_insert() so the first device is the latest that was
285a46c0ec8Sopenharmony_ci	 * initialized, so we should be good.
286a46c0ec8Sopenharmony_ci	 */
287a46c0ec8Sopenharmony_ci	list_for_each(p, &ctx->paths, link) {
288a46c0ec8Sopenharmony_ci		if (streq(p->path, devnode)) {
289a46c0ec8Sopenharmony_ci			int rc = ioctl(p->fd, EVIOCGRAB, (void*)mode ? 1 : 0);
290a46c0ec8Sopenharmony_ci			ck_assert_int_gt(rc, -1);
291a46c0ec8Sopenharmony_ci			udev_device_unref(udev_device);
292a46c0ec8Sopenharmony_ci			return;
293a46c0ec8Sopenharmony_ci		}
294a46c0ec8Sopenharmony_ci	}
295a46c0ec8Sopenharmony_ci	litest_abort_msg("Failed to find device %s to %sgrab\n",
296a46c0ec8Sopenharmony_ci			 devnode, mode ? "" : "un");
297a46c0ec8Sopenharmony_ci}
298a46c0ec8Sopenharmony_ci
299a46c0ec8Sopenharmony_civoid
300a46c0ec8Sopenharmony_cilitest_grab_device(struct litest_device *device)
301a46c0ec8Sopenharmony_ci{
302a46c0ec8Sopenharmony_ci	grab_device(device, true);
303a46c0ec8Sopenharmony_ci}
304a46c0ec8Sopenharmony_ci
305a46c0ec8Sopenharmony_civoid
306a46c0ec8Sopenharmony_cilitest_ungrab_device(struct litest_device *device)
307a46c0ec8Sopenharmony_ci{
308a46c0ec8Sopenharmony_ci	grab_device(device, false);
309a46c0ec8Sopenharmony_ci}
310a46c0ec8Sopenharmony_ci
311a46c0ec8Sopenharmony_civoid litest_set_current_device(struct litest_device *device)
312a46c0ec8Sopenharmony_ci{
313a46c0ec8Sopenharmony_ci	current_device = device;
314a46c0ec8Sopenharmony_ci}
315a46c0ec8Sopenharmony_ci
316a46c0ec8Sopenharmony_civoid litest_generic_device_teardown(void)
317a46c0ec8Sopenharmony_ci{
318a46c0ec8Sopenharmony_ci	litest_delete_device(current_device);
319a46c0ec8Sopenharmony_ci	current_device = NULL;
320a46c0ec8Sopenharmony_ci}
321a46c0ec8Sopenharmony_ci
322a46c0ec8Sopenharmony_cistatic struct list devices;
323a46c0ec8Sopenharmony_ci
324a46c0ec8Sopenharmony_cistatic struct list all_tests;
325a46c0ec8Sopenharmony_ci
326a46c0ec8Sopenharmony_cistatic inline void
327a46c0ec8Sopenharmony_cilitest_system(const char *command)
328a46c0ec8Sopenharmony_ci{
329a46c0ec8Sopenharmony_ci	int ret;
330a46c0ec8Sopenharmony_ci
331a46c0ec8Sopenharmony_ci	ret = system(command);
332a46c0ec8Sopenharmony_ci
333a46c0ec8Sopenharmony_ci	if (ret == -1) {
334a46c0ec8Sopenharmony_ci		litest_abort_msg("Failed to execute: %s", command);
335a46c0ec8Sopenharmony_ci	} else if (WIFEXITED(ret)) {
336a46c0ec8Sopenharmony_ci		if (WEXITSTATUS(ret))
337a46c0ec8Sopenharmony_ci			litest_abort_msg("'%s' failed with %d",
338a46c0ec8Sopenharmony_ci					 command,
339a46c0ec8Sopenharmony_ci					 WEXITSTATUS(ret));
340a46c0ec8Sopenharmony_ci	} else if (WIFSIGNALED(ret)) {
341a46c0ec8Sopenharmony_ci		litest_abort_msg("'%s' terminated with signal %d",
342a46c0ec8Sopenharmony_ci				 command,
343a46c0ec8Sopenharmony_ci				 WTERMSIG(ret));
344a46c0ec8Sopenharmony_ci	}
345a46c0ec8Sopenharmony_ci}
346a46c0ec8Sopenharmony_ci
347a46c0ec8Sopenharmony_cistatic void
348a46c0ec8Sopenharmony_cilitest_reload_udev_rules(void)
349a46c0ec8Sopenharmony_ci{
350a46c0ec8Sopenharmony_ci	litest_system("udevadm control --reload-rules");
351a46c0ec8Sopenharmony_ci}
352a46c0ec8Sopenharmony_ci
353a46c0ec8Sopenharmony_cistatic void
354a46c0ec8Sopenharmony_cilitest_add_tcase_for_device(struct suite *suite,
355a46c0ec8Sopenharmony_ci			    const char *funcname,
356a46c0ec8Sopenharmony_ci			    const void *func,
357a46c0ec8Sopenharmony_ci			    const struct litest_test_device *dev,
358a46c0ec8Sopenharmony_ci			    const struct range *range)
359a46c0ec8Sopenharmony_ci{
360a46c0ec8Sopenharmony_ci	struct test *t;
361a46c0ec8Sopenharmony_ci
362a46c0ec8Sopenharmony_ci	t = zalloc(sizeof(*t));
363a46c0ec8Sopenharmony_ci	t->name = safe_strdup(funcname);
364a46c0ec8Sopenharmony_ci	t->devname = safe_strdup(dev->shortname);
365a46c0ec8Sopenharmony_ci	t->func = func;
366a46c0ec8Sopenharmony_ci	t->setup = dev->setup;
367a46c0ec8Sopenharmony_ci	t->teardown = dev->teardown ?
368a46c0ec8Sopenharmony_ci			dev->teardown : litest_generic_device_teardown;
369a46c0ec8Sopenharmony_ci	if (range)
370a46c0ec8Sopenharmony_ci		t->range = *range;
371a46c0ec8Sopenharmony_ci
372a46c0ec8Sopenharmony_ci	list_insert(&suite->tests, &t->node);
373a46c0ec8Sopenharmony_ci}
374a46c0ec8Sopenharmony_ci
375a46c0ec8Sopenharmony_cistatic void
376a46c0ec8Sopenharmony_cilitest_add_tcase_no_device(struct suite *suite,
377a46c0ec8Sopenharmony_ci			   const void *func,
378a46c0ec8Sopenharmony_ci			   const char *funcname,
379a46c0ec8Sopenharmony_ci			   const struct range *range)
380a46c0ec8Sopenharmony_ci{
381a46c0ec8Sopenharmony_ci	struct test *t;
382a46c0ec8Sopenharmony_ci	const char *test_name = funcname;
383a46c0ec8Sopenharmony_ci
384a46c0ec8Sopenharmony_ci	if (filter_device &&
385a46c0ec8Sopenharmony_ci	    strstr(test_name, filter_device) == NULL &&
386a46c0ec8Sopenharmony_ci	    fnmatch(filter_device, test_name, 0) != 0)
387a46c0ec8Sopenharmony_ci		return;
388a46c0ec8Sopenharmony_ci
389a46c0ec8Sopenharmony_ci	t = zalloc(sizeof(*t));
390a46c0ec8Sopenharmony_ci	t->name = safe_strdup(test_name);
391a46c0ec8Sopenharmony_ci	t->devname = safe_strdup("no device");
392a46c0ec8Sopenharmony_ci	t->func = func;
393a46c0ec8Sopenharmony_ci	if (range)
394a46c0ec8Sopenharmony_ci		t->range = *range;
395a46c0ec8Sopenharmony_ci	t->setup = NULL;
396a46c0ec8Sopenharmony_ci	t->teardown = NULL;
397a46c0ec8Sopenharmony_ci
398a46c0ec8Sopenharmony_ci	list_insert(&suite->tests, &t->node);
399a46c0ec8Sopenharmony_ci}
400a46c0ec8Sopenharmony_ci
401a46c0ec8Sopenharmony_cistatic void
402a46c0ec8Sopenharmony_cilitest_add_tcase_deviceless(struct suite *suite,
403a46c0ec8Sopenharmony_ci			    const void *func,
404a46c0ec8Sopenharmony_ci			    const char *funcname,
405a46c0ec8Sopenharmony_ci			    const struct range *range)
406a46c0ec8Sopenharmony_ci{
407a46c0ec8Sopenharmony_ci	struct test *t;
408a46c0ec8Sopenharmony_ci	const char *test_name = funcname;
409a46c0ec8Sopenharmony_ci
410a46c0ec8Sopenharmony_ci	if (filter_device &&
411a46c0ec8Sopenharmony_ci	    strstr(test_name, filter_device) == NULL &&
412a46c0ec8Sopenharmony_ci	    fnmatch(filter_device, test_name, 0) != 0)
413a46c0ec8Sopenharmony_ci		return;
414a46c0ec8Sopenharmony_ci
415a46c0ec8Sopenharmony_ci	t = zalloc(sizeof(*t));
416a46c0ec8Sopenharmony_ci	t->deviceless = true;
417a46c0ec8Sopenharmony_ci	t->name = safe_strdup(test_name);
418a46c0ec8Sopenharmony_ci	t->devname = safe_strdup("deviceless");
419a46c0ec8Sopenharmony_ci	t->func = func;
420a46c0ec8Sopenharmony_ci	if (range)
421a46c0ec8Sopenharmony_ci		t->range = *range;
422a46c0ec8Sopenharmony_ci	t->setup = NULL;
423a46c0ec8Sopenharmony_ci	t->teardown = NULL;
424a46c0ec8Sopenharmony_ci
425a46c0ec8Sopenharmony_ci	list_insert(&suite->tests, &t->node);
426a46c0ec8Sopenharmony_ci}
427a46c0ec8Sopenharmony_ci
428a46c0ec8Sopenharmony_cistatic struct suite *
429a46c0ec8Sopenharmony_ciget_suite(const char *name)
430a46c0ec8Sopenharmony_ci{
431a46c0ec8Sopenharmony_ci	struct suite *s;
432a46c0ec8Sopenharmony_ci
433a46c0ec8Sopenharmony_ci	list_for_each(s, &all_tests, node) {
434a46c0ec8Sopenharmony_ci		if (streq(s->name, name))
435a46c0ec8Sopenharmony_ci			return s;
436a46c0ec8Sopenharmony_ci	}
437a46c0ec8Sopenharmony_ci
438a46c0ec8Sopenharmony_ci	s = zalloc(sizeof(*s));
439a46c0ec8Sopenharmony_ci	s->name = safe_strdup(name);
440a46c0ec8Sopenharmony_ci
441a46c0ec8Sopenharmony_ci	list_init(&s->tests);
442a46c0ec8Sopenharmony_ci	list_insert(&all_tests, &s->node);
443a46c0ec8Sopenharmony_ci
444a46c0ec8Sopenharmony_ci	return s;
445a46c0ec8Sopenharmony_ci}
446a46c0ec8Sopenharmony_ci
447a46c0ec8Sopenharmony_cistatic void
448a46c0ec8Sopenharmony_cicreate_suite_name(const char *filename, char suitename[64])
449a46c0ec8Sopenharmony_ci{
450a46c0ec8Sopenharmony_ci	char *trunk = trunkname(filename);
451a46c0ec8Sopenharmony_ci	char *p = trunk;
452a46c0ec8Sopenharmony_ci
453a46c0ec8Sopenharmony_ci	/* strip the test- prefix */
454a46c0ec8Sopenharmony_ci	if (strstartswith(trunk, "test-"))
455a46c0ec8Sopenharmony_ci		p += 5;
456a46c0ec8Sopenharmony_ci
457a46c0ec8Sopenharmony_ci	snprintf(suitename, 64, "%s", p);
458a46c0ec8Sopenharmony_ci	free(trunk);
459a46c0ec8Sopenharmony_ci}
460a46c0ec8Sopenharmony_ci
461a46c0ec8Sopenharmony_cistatic void
462a46c0ec8Sopenharmony_cilitest_add_tcase(const char *filename,
463a46c0ec8Sopenharmony_ci		 const char *funcname,
464a46c0ec8Sopenharmony_ci		 const void *func,
465a46c0ec8Sopenharmony_ci		 int64_t required,
466a46c0ec8Sopenharmony_ci		 int64_t excluded,
467a46c0ec8Sopenharmony_ci		 const struct range *range)
468a46c0ec8Sopenharmony_ci{
469a46c0ec8Sopenharmony_ci	char suite_name[65];
470a46c0ec8Sopenharmony_ci	struct suite *suite;
471a46c0ec8Sopenharmony_ci	bool added = false;
472a46c0ec8Sopenharmony_ci
473a46c0ec8Sopenharmony_ci	litest_assert(required >= LITEST_DEVICELESS);
474a46c0ec8Sopenharmony_ci	litest_assert(excluded >= LITEST_DEVICELESS);
475a46c0ec8Sopenharmony_ci
476a46c0ec8Sopenharmony_ci	if (filter_test &&
477a46c0ec8Sopenharmony_ci	    strstr(funcname, filter_test) == NULL &&
478a46c0ec8Sopenharmony_ci	    fnmatch(filter_test, funcname, 0) != 0)
479a46c0ec8Sopenharmony_ci		return;
480a46c0ec8Sopenharmony_ci
481a46c0ec8Sopenharmony_ci	create_suite_name(filename, suite_name);
482a46c0ec8Sopenharmony_ci
483a46c0ec8Sopenharmony_ci	if (filter_group && fnmatch(filter_group, suite_name, 0) != 0)
484a46c0ec8Sopenharmony_ci		return;
485a46c0ec8Sopenharmony_ci
486a46c0ec8Sopenharmony_ci	suite = get_suite(suite_name);
487a46c0ec8Sopenharmony_ci
488a46c0ec8Sopenharmony_ci	if (required == LITEST_DEVICELESS &&
489a46c0ec8Sopenharmony_ci	    excluded == LITEST_DEVICELESS) {
490a46c0ec8Sopenharmony_ci		litest_add_tcase_deviceless(suite, func, funcname, range);
491a46c0ec8Sopenharmony_ci		added = true;
492a46c0ec8Sopenharmony_ci	} else if (required == LITEST_DISABLE_DEVICE &&
493a46c0ec8Sopenharmony_ci	    excluded == LITEST_DISABLE_DEVICE) {
494a46c0ec8Sopenharmony_ci		litest_add_tcase_no_device(suite, func, funcname, range);
495a46c0ec8Sopenharmony_ci		added = true;
496a46c0ec8Sopenharmony_ci	} else if (required != LITEST_ANY || excluded != LITEST_ANY) {
497a46c0ec8Sopenharmony_ci		struct litest_test_device *dev;
498a46c0ec8Sopenharmony_ci
499a46c0ec8Sopenharmony_ci		list_for_each(dev, &devices, node) {
500a46c0ec8Sopenharmony_ci			if (dev->features & LITEST_IGNORED)
501a46c0ec8Sopenharmony_ci				continue;
502a46c0ec8Sopenharmony_ci
503a46c0ec8Sopenharmony_ci			if (filter_device &&
504a46c0ec8Sopenharmony_ci			    strstr(dev->shortname, filter_device) == NULL &&
505a46c0ec8Sopenharmony_ci			    fnmatch(filter_device, dev->shortname, 0) != 0)
506a46c0ec8Sopenharmony_ci				continue;
507a46c0ec8Sopenharmony_ci			if ((dev->features & required) != required ||
508a46c0ec8Sopenharmony_ci			    (dev->features & excluded) != 0)
509a46c0ec8Sopenharmony_ci				continue;
510a46c0ec8Sopenharmony_ci
511a46c0ec8Sopenharmony_ci			litest_add_tcase_for_device(suite,
512a46c0ec8Sopenharmony_ci						    funcname,
513a46c0ec8Sopenharmony_ci						    func,
514a46c0ec8Sopenharmony_ci						    dev,
515a46c0ec8Sopenharmony_ci						    range);
516a46c0ec8Sopenharmony_ci			added = true;
517a46c0ec8Sopenharmony_ci		}
518a46c0ec8Sopenharmony_ci	} else {
519a46c0ec8Sopenharmony_ci		struct litest_test_device *dev;
520a46c0ec8Sopenharmony_ci
521a46c0ec8Sopenharmony_ci		list_for_each(dev, &devices, node) {
522a46c0ec8Sopenharmony_ci			if (dev->features & LITEST_IGNORED)
523a46c0ec8Sopenharmony_ci				continue;
524a46c0ec8Sopenharmony_ci
525a46c0ec8Sopenharmony_ci			if (filter_device &&
526a46c0ec8Sopenharmony_ci			    strstr(dev->shortname, filter_device) == NULL &&
527a46c0ec8Sopenharmony_ci			    fnmatch(filter_device, dev->shortname, 0) != 0)
528a46c0ec8Sopenharmony_ci				continue;
529a46c0ec8Sopenharmony_ci
530a46c0ec8Sopenharmony_ci			litest_add_tcase_for_device(suite,
531a46c0ec8Sopenharmony_ci						    funcname,
532a46c0ec8Sopenharmony_ci						    func,
533a46c0ec8Sopenharmony_ci						    dev,
534a46c0ec8Sopenharmony_ci						    range);
535a46c0ec8Sopenharmony_ci			added = true;
536a46c0ec8Sopenharmony_ci		}
537a46c0ec8Sopenharmony_ci	}
538a46c0ec8Sopenharmony_ci
539a46c0ec8Sopenharmony_ci	if (!added &&
540a46c0ec8Sopenharmony_ci	    filter_test == NULL &&
541a46c0ec8Sopenharmony_ci	    filter_device == NULL &&
542a46c0ec8Sopenharmony_ci	    filter_group == NULL) {
543a46c0ec8Sopenharmony_ci		fprintf(stderr, "Test '%s' does not match any devices. Aborting.\n", funcname);
544a46c0ec8Sopenharmony_ci		abort();
545a46c0ec8Sopenharmony_ci	}
546a46c0ec8Sopenharmony_ci}
547a46c0ec8Sopenharmony_ci
548a46c0ec8Sopenharmony_civoid
549a46c0ec8Sopenharmony_ci_litest_add_no_device(const char *name, const char *funcname, const void *func)
550a46c0ec8Sopenharmony_ci{
551a46c0ec8Sopenharmony_ci	_litest_add(name, funcname, func, LITEST_DISABLE_DEVICE, LITEST_DISABLE_DEVICE);
552a46c0ec8Sopenharmony_ci}
553a46c0ec8Sopenharmony_ci
554a46c0ec8Sopenharmony_civoid
555a46c0ec8Sopenharmony_ci_litest_add_ranged_no_device(const char *name,
556a46c0ec8Sopenharmony_ci			     const char *funcname,
557a46c0ec8Sopenharmony_ci			     const void *func,
558a46c0ec8Sopenharmony_ci			     const struct range *range)
559a46c0ec8Sopenharmony_ci{
560a46c0ec8Sopenharmony_ci	_litest_add_ranged(name,
561a46c0ec8Sopenharmony_ci			   funcname,
562a46c0ec8Sopenharmony_ci			   func,
563a46c0ec8Sopenharmony_ci			   LITEST_DISABLE_DEVICE,
564a46c0ec8Sopenharmony_ci			   LITEST_DISABLE_DEVICE,
565a46c0ec8Sopenharmony_ci			   range);
566a46c0ec8Sopenharmony_ci}
567a46c0ec8Sopenharmony_ci
568a46c0ec8Sopenharmony_civoid
569a46c0ec8Sopenharmony_ci_litest_add_deviceless(const char *name,
570a46c0ec8Sopenharmony_ci		       const char *funcname,
571a46c0ec8Sopenharmony_ci		       const void *func)
572a46c0ec8Sopenharmony_ci{
573a46c0ec8Sopenharmony_ci	_litest_add_ranged(name,
574a46c0ec8Sopenharmony_ci			   funcname,
575a46c0ec8Sopenharmony_ci			   func,
576a46c0ec8Sopenharmony_ci			   LITEST_DEVICELESS,
577a46c0ec8Sopenharmony_ci			   LITEST_DEVICELESS,
578a46c0ec8Sopenharmony_ci			   NULL);
579a46c0ec8Sopenharmony_ci}
580a46c0ec8Sopenharmony_ci
581a46c0ec8Sopenharmony_civoid
582a46c0ec8Sopenharmony_ci_litest_add(const char *name,
583a46c0ec8Sopenharmony_ci	    const char *funcname,
584a46c0ec8Sopenharmony_ci	    const void *func,
585a46c0ec8Sopenharmony_ci	    int64_t required,
586a46c0ec8Sopenharmony_ci	    int64_t excluded)
587a46c0ec8Sopenharmony_ci{
588a46c0ec8Sopenharmony_ci	_litest_add_ranged(name,
589a46c0ec8Sopenharmony_ci			   funcname,
590a46c0ec8Sopenharmony_ci			   func,
591a46c0ec8Sopenharmony_ci			   required,
592a46c0ec8Sopenharmony_ci			   excluded,
593a46c0ec8Sopenharmony_ci			   NULL);
594a46c0ec8Sopenharmony_ci}
595a46c0ec8Sopenharmony_ci
596a46c0ec8Sopenharmony_civoid
597a46c0ec8Sopenharmony_ci_litest_add_ranged(const char *name,
598a46c0ec8Sopenharmony_ci		   const char *funcname,
599a46c0ec8Sopenharmony_ci		   const void *func,
600a46c0ec8Sopenharmony_ci		   int64_t required,
601a46c0ec8Sopenharmony_ci		   int64_t excluded,
602a46c0ec8Sopenharmony_ci		   const struct range *range)
603a46c0ec8Sopenharmony_ci{
604a46c0ec8Sopenharmony_ci	litest_add_tcase(name, funcname, func, required, excluded, range);
605a46c0ec8Sopenharmony_ci}
606a46c0ec8Sopenharmony_ci
607a46c0ec8Sopenharmony_civoid
608a46c0ec8Sopenharmony_ci_litest_add_for_device(const char *name,
609a46c0ec8Sopenharmony_ci		       const char *funcname,
610a46c0ec8Sopenharmony_ci		       const void *func,
611a46c0ec8Sopenharmony_ci		       enum litest_device_type type)
612a46c0ec8Sopenharmony_ci{
613a46c0ec8Sopenharmony_ci	_litest_add_ranged_for_device(name, funcname, func, type, NULL);
614a46c0ec8Sopenharmony_ci}
615a46c0ec8Sopenharmony_ci
616a46c0ec8Sopenharmony_civoid
617a46c0ec8Sopenharmony_ci_litest_add_ranged_for_device(const char *filename,
618a46c0ec8Sopenharmony_ci			      const char *funcname,
619a46c0ec8Sopenharmony_ci			      const void *func,
620a46c0ec8Sopenharmony_ci			      enum litest_device_type type,
621a46c0ec8Sopenharmony_ci			      const struct range *range)
622a46c0ec8Sopenharmony_ci{
623a46c0ec8Sopenharmony_ci	struct suite *s;
624a46c0ec8Sopenharmony_ci	struct litest_test_device *dev;
625a46c0ec8Sopenharmony_ci	bool device_filtered = false;
626a46c0ec8Sopenharmony_ci	char suite_name[64];
627a46c0ec8Sopenharmony_ci
628a46c0ec8Sopenharmony_ci	litest_assert(type < LITEST_NO_DEVICE);
629a46c0ec8Sopenharmony_ci
630a46c0ec8Sopenharmony_ci	if (filter_test &&
631a46c0ec8Sopenharmony_ci	    strstr(funcname, filter_test) == NULL &&
632a46c0ec8Sopenharmony_ci	    fnmatch(filter_test, funcname, 0) != 0)
633a46c0ec8Sopenharmony_ci		return;
634a46c0ec8Sopenharmony_ci
635a46c0ec8Sopenharmony_ci	create_suite_name(filename, suite_name);
636a46c0ec8Sopenharmony_ci	if (filter_group && fnmatch(filter_group, suite_name, 0) != 0)
637a46c0ec8Sopenharmony_ci		return;
638a46c0ec8Sopenharmony_ci
639a46c0ec8Sopenharmony_ci	s = get_suite(suite_name);
640a46c0ec8Sopenharmony_ci	list_for_each(dev, &devices, node) {
641a46c0ec8Sopenharmony_ci		if (filter_device &&
642a46c0ec8Sopenharmony_ci		    strstr(dev->shortname, filter_device) == NULL &&
643a46c0ec8Sopenharmony_ci		    fnmatch(filter_device, dev->shortname, 0) != 0) {
644a46c0ec8Sopenharmony_ci			device_filtered = true;
645a46c0ec8Sopenharmony_ci			continue;
646a46c0ec8Sopenharmony_ci		}
647a46c0ec8Sopenharmony_ci
648a46c0ec8Sopenharmony_ci		if (dev->type == type) {
649a46c0ec8Sopenharmony_ci			litest_add_tcase_for_device(s,
650a46c0ec8Sopenharmony_ci						    funcname,
651a46c0ec8Sopenharmony_ci						    func,
652a46c0ec8Sopenharmony_ci						    dev,
653a46c0ec8Sopenharmony_ci						    range);
654a46c0ec8Sopenharmony_ci			return;
655a46c0ec8Sopenharmony_ci		}
656a46c0ec8Sopenharmony_ci	}
657a46c0ec8Sopenharmony_ci
658a46c0ec8Sopenharmony_ci	/* only abort if no filter was set, that's a bug */
659a46c0ec8Sopenharmony_ci	if (!device_filtered)
660a46c0ec8Sopenharmony_ci		litest_abort_msg("Invalid test device type\n");
661a46c0ec8Sopenharmony_ci}
662a46c0ec8Sopenharmony_ci
663a46c0ec8Sopenharmony_ciLIBINPUT_ATTRIBUTE_PRINTF(3, 0)
664a46c0ec8Sopenharmony_cistatic void
665a46c0ec8Sopenharmony_cilitest_log_handler(struct libinput *libinput,
666a46c0ec8Sopenharmony_ci		   enum libinput_log_priority pri,
667a46c0ec8Sopenharmony_ci		   const char *format,
668a46c0ec8Sopenharmony_ci		   va_list args)
669a46c0ec8Sopenharmony_ci{
670a46c0ec8Sopenharmony_ci	static int is_tty = -1;
671a46c0ec8Sopenharmony_ci	const char *priority = NULL;
672a46c0ec8Sopenharmony_ci	const char *color;
673a46c0ec8Sopenharmony_ci
674a46c0ec8Sopenharmony_ci	if (is_tty == -1)
675a46c0ec8Sopenharmony_ci		is_tty = isatty(STDERR_FILENO);
676a46c0ec8Sopenharmony_ci
677a46c0ec8Sopenharmony_ci	switch(pri) {
678a46c0ec8Sopenharmony_ci	case LIBINPUT_LOG_PRIORITY_INFO:
679a46c0ec8Sopenharmony_ci		priority =  "info ";
680a46c0ec8Sopenharmony_ci		color = ANSI_HIGHLIGHT;
681a46c0ec8Sopenharmony_ci		break;
682a46c0ec8Sopenharmony_ci	case LIBINPUT_LOG_PRIORITY_ERROR:
683a46c0ec8Sopenharmony_ci		priority = "error";
684a46c0ec8Sopenharmony_ci		color = ANSI_BRIGHT_RED;
685a46c0ec8Sopenharmony_ci		break;
686a46c0ec8Sopenharmony_ci	case LIBINPUT_LOG_PRIORITY_DEBUG:
687a46c0ec8Sopenharmony_ci		priority = "debug";
688a46c0ec8Sopenharmony_ci		color = ANSI_NORMAL;
689a46c0ec8Sopenharmony_ci		break;
690a46c0ec8Sopenharmony_ci	default:
691a46c0ec8Sopenharmony_ci		  abort();
692a46c0ec8Sopenharmony_ci	}
693a46c0ec8Sopenharmony_ci
694a46c0ec8Sopenharmony_ci	if (!is_tty)
695a46c0ec8Sopenharmony_ci		color = "";
696a46c0ec8Sopenharmony_ci	else if (strstr(format, "tap:"))
697a46c0ec8Sopenharmony_ci		color = ANSI_BLUE;
698a46c0ec8Sopenharmony_ci	else if (strstr(format, "thumb state:"))
699a46c0ec8Sopenharmony_ci		color = ANSI_YELLOW;
700a46c0ec8Sopenharmony_ci	else if (strstr(format, "button state:"))
701a46c0ec8Sopenharmony_ci		color = ANSI_MAGENTA;
702a46c0ec8Sopenharmony_ci	else if (strstr(format, "touch-size:") ||
703a46c0ec8Sopenharmony_ci		 strstr(format, "pressure:"))
704a46c0ec8Sopenharmony_ci		color = ANSI_GREEN;
705a46c0ec8Sopenharmony_ci	else if (strstr(format, "palm:") ||
706a46c0ec8Sopenharmony_ci		 strstr(format, "thumb:"))
707a46c0ec8Sopenharmony_ci		color = ANSI_CYAN;
708a46c0ec8Sopenharmony_ci	else if (strstr(format, "edge-scroll:"))
709a46c0ec8Sopenharmony_ci		color = ANSI_BRIGHT_GREEN;
710a46c0ec8Sopenharmony_ci
711a46c0ec8Sopenharmony_ci	fprintf(stderr, "%slitest %s ", color, priority);
712a46c0ec8Sopenharmony_ci	vfprintf(stderr, format, args);
713a46c0ec8Sopenharmony_ci	if (is_tty)
714a46c0ec8Sopenharmony_ci		fprintf(stderr, ANSI_NORMAL);
715a46c0ec8Sopenharmony_ci
716a46c0ec8Sopenharmony_ci	if (strstr(format, "client bug: ") ||
717a46c0ec8Sopenharmony_ci	    strstr(format, "libinput bug: ")) {
718a46c0ec8Sopenharmony_ci		/* valgrind is too slow and some of our offsets are too
719a46c0ec8Sopenharmony_ci		 * short, don't abort if during a valgrind run we get a
720a46c0ec8Sopenharmony_ci		 * negative offset */
721a46c0ec8Sopenharmony_ci		if ((RUNNING_ON_VALGRIND && in_debugger) ||
722a46c0ec8Sopenharmony_ci		    !strstr(format, "scheduled expiry is in the past")) {
723a46c0ec8Sopenharmony_ci			/* noop */
724a46c0ec8Sopenharmony_ci		} else if (!strstr(format, "event processing lagging behind")) {
725a46c0ec8Sopenharmony_ci			/* noop */
726a46c0ec8Sopenharmony_ci		} else {
727a46c0ec8Sopenharmony_ci			litest_abort_msg("libinput bug triggered, aborting.\n");
728a46c0ec8Sopenharmony_ci		}
729a46c0ec8Sopenharmony_ci	}
730a46c0ec8Sopenharmony_ci
731a46c0ec8Sopenharmony_ci	if (strstr(format, "Touch jump detected and discarded")) {
732a46c0ec8Sopenharmony_ci		litest_abort_msg("libinput touch jump triggered, aborting.\n");
733a46c0ec8Sopenharmony_ci	}
734a46c0ec8Sopenharmony_ci}
735a46c0ec8Sopenharmony_ci
736a46c0ec8Sopenharmony_cistatic void
737a46c0ec8Sopenharmony_cilitest_init_device_udev_rules(struct litest_test_device *dev, FILE *f)
738a46c0ec8Sopenharmony_ci{
739a46c0ec8Sopenharmony_ci	const struct key_value_str *kv;
740a46c0ec8Sopenharmony_ci	static int count;
741a46c0ec8Sopenharmony_ci	bool need_keyboard_builtin = false;
742a46c0ec8Sopenharmony_ci
743a46c0ec8Sopenharmony_ci	if (dev->udev_properties[0].key == NULL)
744a46c0ec8Sopenharmony_ci		return;
745a46c0ec8Sopenharmony_ci
746a46c0ec8Sopenharmony_ci	count++;
747a46c0ec8Sopenharmony_ci
748a46c0ec8Sopenharmony_ci	fprintf(f, "# %s\n", dev->shortname);
749a46c0ec8Sopenharmony_ci	fprintf(f, "ACTION==\"remove\", GOTO=\"rule%d_end\"\n", count);
750a46c0ec8Sopenharmony_ci	fprintf(f, "KERNEL!=\"event*\", GOTO=\"rule%d_end\"\n", count);
751a46c0ec8Sopenharmony_ci
752a46c0ec8Sopenharmony_ci	fprintf(f, "ATTRS{name}==\"litest %s*\"", dev->name);
753a46c0ec8Sopenharmony_ci
754a46c0ec8Sopenharmony_ci	kv = dev->udev_properties;
755a46c0ec8Sopenharmony_ci	while (kv->key) {
756a46c0ec8Sopenharmony_ci		fprintf(f, ", \\\n\tENV{%s}=\"%s\"", kv->key, kv->value);
757a46c0ec8Sopenharmony_ci		if (strneq(kv->key, "EVDEV_ABS_", 10))
758a46c0ec8Sopenharmony_ci			need_keyboard_builtin = true;
759a46c0ec8Sopenharmony_ci		kv++;
760a46c0ec8Sopenharmony_ci	}
761a46c0ec8Sopenharmony_ci	fprintf(f, "\n");
762a46c0ec8Sopenharmony_ci
763a46c0ec8Sopenharmony_ci	/* Special case: the udev keyboard builtin is only run for hwdb
764a46c0ec8Sopenharmony_ci	 * matches but we don't set any up in litest. So instead scan the
765a46c0ec8Sopenharmony_ci	 * device's udev properties for any EVDEV_ABS properties and where
766a46c0ec8Sopenharmony_ci	 * they exist, force a (re-)run of the keyboard builtin to set up
767a46c0ec8Sopenharmony_ci	 * the evdev device correctly.
768a46c0ec8Sopenharmony_ci	 * This needs to be done as separate rule apparently, otherwise the
769a46c0ec8Sopenharmony_ci	 * ENV variables aren't set yet by the time the builtin runs.
770a46c0ec8Sopenharmony_ci	 */
771a46c0ec8Sopenharmony_ci	if (need_keyboard_builtin) {
772a46c0ec8Sopenharmony_ci		fprintf(f, ""
773a46c0ec8Sopenharmony_ci			"ATTRS{name}==\"litest %s*\","
774a46c0ec8Sopenharmony_ci			" IMPORT{builtin}=\"keyboard\"\n",
775a46c0ec8Sopenharmony_ci			dev->name);
776a46c0ec8Sopenharmony_ci	}
777a46c0ec8Sopenharmony_ci
778a46c0ec8Sopenharmony_ci	fprintf(f, "LABEL=\"rule%d_end\"\n\n", count);;
779a46c0ec8Sopenharmony_ci}
780a46c0ec8Sopenharmony_ci
781a46c0ec8Sopenharmony_cistatic void
782a46c0ec8Sopenharmony_cilitest_init_all_device_udev_rules(struct list *created_files)
783a46c0ec8Sopenharmony_ci{
784a46c0ec8Sopenharmony_ci	struct created_file *file = zalloc(sizeof(*file));
785a46c0ec8Sopenharmony_ci	struct litest_test_device *dev;
786a46c0ec8Sopenharmony_ci	char *path = NULL;
787a46c0ec8Sopenharmony_ci	FILE *f;
788a46c0ec8Sopenharmony_ci	int rc;
789a46c0ec8Sopenharmony_ci	int fd;
790a46c0ec8Sopenharmony_ci
791a46c0ec8Sopenharmony_ci	rc = xasprintf(&path,
792a46c0ec8Sopenharmony_ci		      "%s/99-litest-XXXXXX.rules",
793a46c0ec8Sopenharmony_ci		      UDEV_RULES_D);
794a46c0ec8Sopenharmony_ci	litest_assert_int_gt(rc, 0);
795a46c0ec8Sopenharmony_ci
796a46c0ec8Sopenharmony_ci	fd = mkstemps(path, 6);
797a46c0ec8Sopenharmony_ci	litest_assert_int_ne(fd, -1);
798a46c0ec8Sopenharmony_ci	f = fdopen(fd, "w");
799a46c0ec8Sopenharmony_ci	litest_assert_notnull(f);
800a46c0ec8Sopenharmony_ci
801a46c0ec8Sopenharmony_ci	list_for_each(dev, &devices, node)
802a46c0ec8Sopenharmony_ci		litest_init_device_udev_rules(dev, f);
803a46c0ec8Sopenharmony_ci
804a46c0ec8Sopenharmony_ci	fclose(f);
805a46c0ec8Sopenharmony_ci
806a46c0ec8Sopenharmony_ci	file->path = path;
807a46c0ec8Sopenharmony_ci	list_insert(created_files, &file->link);
808a46c0ec8Sopenharmony_ci}
809a46c0ec8Sopenharmony_ci
810a46c0ec8Sopenharmony_cistatic int
811a46c0ec8Sopenharmony_ciopen_restricted(const char *path, int flags, void *userdata)
812a46c0ec8Sopenharmony_ci{
813a46c0ec8Sopenharmony_ci	const char prefix[] = "/dev/input/event";
814a46c0ec8Sopenharmony_ci	struct litest_context *ctx = userdata;
815a46c0ec8Sopenharmony_ci	struct path *p;
816a46c0ec8Sopenharmony_ci	int fd;
817a46c0ec8Sopenharmony_ci
818a46c0ec8Sopenharmony_ci	litest_assert_ptr_notnull(ctx);
819a46c0ec8Sopenharmony_ci
820a46c0ec8Sopenharmony_ci	fd = open(path, flags);
821a46c0ec8Sopenharmony_ci	if (fd < 0)
822a46c0ec8Sopenharmony_ci		return -errno;
823a46c0ec8Sopenharmony_ci
824a46c0ec8Sopenharmony_ci	if (strneq(path, prefix, strlen(prefix))) {
825a46c0ec8Sopenharmony_ci		p = zalloc(sizeof *p);
826a46c0ec8Sopenharmony_ci		p->path = safe_strdup(path);
827a46c0ec8Sopenharmony_ci		p->fd = fd;
828a46c0ec8Sopenharmony_ci		/* We specifically insert here so that the most-recently
829a46c0ec8Sopenharmony_ci		 * opened path is the first one in the list. This helps when
830a46c0ec8Sopenharmony_ci		 * we have multiple test devices with the same device path,
831a46c0ec8Sopenharmony_ci		 * the fd of the most recent device is the first one to get
832a46c0ec8Sopenharmony_ci		 * grabbed
833a46c0ec8Sopenharmony_ci		 */
834a46c0ec8Sopenharmony_ci		list_insert(&ctx->paths, &p->link);
835a46c0ec8Sopenharmony_ci	}
836a46c0ec8Sopenharmony_ci
837a46c0ec8Sopenharmony_ci	return fd;
838a46c0ec8Sopenharmony_ci}
839a46c0ec8Sopenharmony_ci
840a46c0ec8Sopenharmony_cistatic void
841a46c0ec8Sopenharmony_ciclose_restricted(int fd, void *userdata)
842a46c0ec8Sopenharmony_ci{
843a46c0ec8Sopenharmony_ci	struct litest_context *ctx = userdata;
844a46c0ec8Sopenharmony_ci	struct path *p;
845a46c0ec8Sopenharmony_ci
846a46c0ec8Sopenharmony_ci	list_for_each_safe(p, &ctx->paths, link) {
847a46c0ec8Sopenharmony_ci		if (p->fd != fd)
848a46c0ec8Sopenharmony_ci			continue;
849a46c0ec8Sopenharmony_ci		list_remove(&p->link);
850a46c0ec8Sopenharmony_ci		free(p->path);
851a46c0ec8Sopenharmony_ci		free(p);
852a46c0ec8Sopenharmony_ci	}
853a46c0ec8Sopenharmony_ci
854a46c0ec8Sopenharmony_ci	close(fd);
855a46c0ec8Sopenharmony_ci}
856a46c0ec8Sopenharmony_ci
857a46c0ec8Sopenharmony_cistatic struct libinput_interface interface = {
858a46c0ec8Sopenharmony_ci	.open_restricted = open_restricted,
859a46c0ec8Sopenharmony_ci	.close_restricted = close_restricted,
860a46c0ec8Sopenharmony_ci};
861a46c0ec8Sopenharmony_ci
862a46c0ec8Sopenharmony_cistatic void
863a46c0ec8Sopenharmony_cilitest_signal(int sig)
864a46c0ec8Sopenharmony_ci{
865a46c0ec8Sopenharmony_ci	struct created_file *f;
866a46c0ec8Sopenharmony_ci
867a46c0ec8Sopenharmony_ci	list_for_each_safe(f, &created_files_list, link) {
868a46c0ec8Sopenharmony_ci		list_remove(&f->link);
869a46c0ec8Sopenharmony_ci		unlink(f->path);
870a46c0ec8Sopenharmony_ci		rmdir(f->path);
871a46c0ec8Sopenharmony_ci		/* in the sighandler, we can't free */
872a46c0ec8Sopenharmony_ci	}
873a46c0ec8Sopenharmony_ci
874a46c0ec8Sopenharmony_ci	if (fork() == 0) {
875a46c0ec8Sopenharmony_ci		/* child, we can run system() */
876a46c0ec8Sopenharmony_ci		litest_reload_udev_rules();
877a46c0ec8Sopenharmony_ci		exit(0);
878a46c0ec8Sopenharmony_ci	}
879a46c0ec8Sopenharmony_ci
880a46c0ec8Sopenharmony_ci	exit(1);
881a46c0ec8Sopenharmony_ci}
882a46c0ec8Sopenharmony_ci
883a46c0ec8Sopenharmony_cistatic inline void
884a46c0ec8Sopenharmony_cilitest_setup_sighandler(int sig)
885a46c0ec8Sopenharmony_ci{
886a46c0ec8Sopenharmony_ci	struct sigaction act, oact;
887a46c0ec8Sopenharmony_ci	int rc;
888a46c0ec8Sopenharmony_ci
889a46c0ec8Sopenharmony_ci	sigemptyset(&act.sa_mask);
890a46c0ec8Sopenharmony_ci	sigaddset(&act.sa_mask, sig);
891a46c0ec8Sopenharmony_ci	act.sa_flags = 0;
892a46c0ec8Sopenharmony_ci	act.sa_handler = litest_signal;
893a46c0ec8Sopenharmony_ci	rc = sigaction(sig, &act, &oact);
894a46c0ec8Sopenharmony_ci	litest_assert_int_ne(rc, -1);
895a46c0ec8Sopenharmony_ci}
896a46c0ec8Sopenharmony_ci
897a46c0ec8Sopenharmony_cistatic void
898a46c0ec8Sopenharmony_cilitest_free_test_list(struct list *tests)
899a46c0ec8Sopenharmony_ci{
900a46c0ec8Sopenharmony_ci	struct suite *s;
901a46c0ec8Sopenharmony_ci
902a46c0ec8Sopenharmony_ci	list_for_each_safe(s, tests, node) {
903a46c0ec8Sopenharmony_ci		struct test *t;
904a46c0ec8Sopenharmony_ci
905a46c0ec8Sopenharmony_ci		list_for_each_safe(t, &s->tests, node) {
906a46c0ec8Sopenharmony_ci			free(t->name);
907a46c0ec8Sopenharmony_ci			free(t->devname);
908a46c0ec8Sopenharmony_ci			list_remove(&t->node);
909a46c0ec8Sopenharmony_ci			free(t);
910a46c0ec8Sopenharmony_ci		}
911a46c0ec8Sopenharmony_ci
912a46c0ec8Sopenharmony_ci		list_remove(&s->node);
913a46c0ec8Sopenharmony_ci		free(s->name);
914a46c0ec8Sopenharmony_ci		free(s);
915a46c0ec8Sopenharmony_ci	}
916a46c0ec8Sopenharmony_ci}
917a46c0ec8Sopenharmony_ci
918a46c0ec8Sopenharmony_ciLIBINPUT_ATTRIBUTE_PRINTF(3, 0)
919a46c0ec8Sopenharmony_cistatic inline void
920a46c0ec8Sopenharmony_ciquirk_log_handler(struct libinput *unused,
921a46c0ec8Sopenharmony_ci		  enum libinput_log_priority priority,
922a46c0ec8Sopenharmony_ci		  const char *format,
923a46c0ec8Sopenharmony_ci		  va_list args)
924a46c0ec8Sopenharmony_ci{
925a46c0ec8Sopenharmony_ci	if (priority < LIBINPUT_LOG_PRIORITY_ERROR)
926a46c0ec8Sopenharmony_ci		return;
927a46c0ec8Sopenharmony_ci
928a46c0ec8Sopenharmony_ci	vfprintf(stderr, format, args);
929a46c0ec8Sopenharmony_ci}
930a46c0ec8Sopenharmony_ci
931a46c0ec8Sopenharmony_cistatic void
932a46c0ec8Sopenharmony_cilitest_export_xml(SRunner *sr, const char *xml_prefix)
933a46c0ec8Sopenharmony_ci{
934a46c0ec8Sopenharmony_ci	TestResult **results;
935a46c0ec8Sopenharmony_ci	int nresults, nfailed;
936a46c0ec8Sopenharmony_ci	char *filename;
937a46c0ec8Sopenharmony_ci	int fd;
938a46c0ec8Sopenharmony_ci
939a46c0ec8Sopenharmony_ci	/* This is the minimum-effort implementation here because its only
940a46c0ec8Sopenharmony_ci	 * real purpose is to make test logs look pretty in the gitlab CI.
941a46c0ec8Sopenharmony_ci	 *
942a46c0ec8Sopenharmony_ci	 * Which means:
943a46c0ec8Sopenharmony_ci	 * - there's no filename validation, if you supply a filename that
944a46c0ec8Sopenharmony_ci	 *   mkstemps doesn't like, things go boom.
945a46c0ec8Sopenharmony_ci	 * - every fork writes out a separate junit.xml file. gitlab is better
946a46c0ec8Sopenharmony_ci	 *   at collecting lots of files than I am at writing code to collect
947a46c0ec8Sopenharmony_ci	 *   this across forks to write out only one file.
948a46c0ec8Sopenharmony_ci	 * - most of the content is pretty useless because libcheck only gives
949a46c0ec8Sopenharmony_ci	 *   us minimal information. the libcheck XML file has more info like
950a46c0ec8Sopenharmony_ci	 *   the duration of each test but it's more complicated to extract
951a46c0ec8Sopenharmony_ci	 *   and we don't need it for now.
952a46c0ec8Sopenharmony_ci	 */
953a46c0ec8Sopenharmony_ci	filename = safe_strdup(xml_prefix);
954a46c0ec8Sopenharmony_ci	fd = mkstemps(filename, 4);
955a46c0ec8Sopenharmony_ci
956a46c0ec8Sopenharmony_ci	results = srunner_results(sr);
957a46c0ec8Sopenharmony_ci	nresults = srunner_ntests_run(sr);
958a46c0ec8Sopenharmony_ci	nfailed = srunner_ntests_failed(sr);
959a46c0ec8Sopenharmony_ci
960a46c0ec8Sopenharmony_ci	dprintf(fd, "<?xml version=\"1.0\"?>\n");
961a46c0ec8Sopenharmony_ci	dprintf(fd, "<testsuites id=\"%s\" tests=\"%d\" failures=\"%d\">\n",
962a46c0ec8Sopenharmony_ci		filename,
963a46c0ec8Sopenharmony_ci		nresults,
964a46c0ec8Sopenharmony_ci		nfailed);
965a46c0ec8Sopenharmony_ci	dprintf(fd, "  <testsuite>\n");
966a46c0ec8Sopenharmony_ci	for (int i = 0; i < nresults; i++) {
967a46c0ec8Sopenharmony_ci		TestResult *r = results[i];
968a46c0ec8Sopenharmony_ci
969a46c0ec8Sopenharmony_ci		dprintf(fd, "    <testcase id=\"%s\" name=\"%s\" %s>\n",
970a46c0ec8Sopenharmony_ci			tr_tcname(r),
971a46c0ec8Sopenharmony_ci			tr_tcname(r),
972a46c0ec8Sopenharmony_ci			tr_rtype(r) == CK_PASS ? "/" : "");
973a46c0ec8Sopenharmony_ci		if (tr_rtype(r) != CK_PASS) {
974a46c0ec8Sopenharmony_ci			dprintf(fd, "      <failure message=\"%s:%d\">\n",
975a46c0ec8Sopenharmony_ci				tr_lfile(r),
976a46c0ec8Sopenharmony_ci				tr_lno(r));
977a46c0ec8Sopenharmony_ci			dprintf(fd, "        %s:%d\n", tr_lfile(r), tr_lno(r));
978a46c0ec8Sopenharmony_ci			dprintf(fd, "        %s\n", tr_tcname(r));
979a46c0ec8Sopenharmony_ci			dprintf(fd, "\n");
980a46c0ec8Sopenharmony_ci			dprintf(fd, "        %s\n", tr_msg(r));
981a46c0ec8Sopenharmony_ci			dprintf(fd, "      </failure>\n");
982a46c0ec8Sopenharmony_ci			dprintf(fd, "    </testcase>\n");
983a46c0ec8Sopenharmony_ci		}
984a46c0ec8Sopenharmony_ci	}
985a46c0ec8Sopenharmony_ci	dprintf(fd, "  </testsuite>\n");
986a46c0ec8Sopenharmony_ci	dprintf(fd, "</testsuites>\n");
987a46c0ec8Sopenharmony_ci
988a46c0ec8Sopenharmony_ci	free(results);
989a46c0ec8Sopenharmony_ci	close(fd);
990a46c0ec8Sopenharmony_ci	free(filename);
991a46c0ec8Sopenharmony_ci}
992a46c0ec8Sopenharmony_ci
993a46c0ec8Sopenharmony_cistatic int
994a46c0ec8Sopenharmony_cilitest_run_suite(struct list *tests, int which, int max, int error_fd)
995a46c0ec8Sopenharmony_ci{
996a46c0ec8Sopenharmony_ci	int failed = 0;
997a46c0ec8Sopenharmony_ci	SRunner *sr = NULL;
998a46c0ec8Sopenharmony_ci	struct suite *s;
999a46c0ec8Sopenharmony_ci	struct test *t;
1000a46c0ec8Sopenharmony_ci	int count = -1;
1001a46c0ec8Sopenharmony_ci	struct name {
1002a46c0ec8Sopenharmony_ci		struct list node;
1003a46c0ec8Sopenharmony_ci		char *name;
1004a46c0ec8Sopenharmony_ci	};
1005a46c0ec8Sopenharmony_ci	struct name *n;
1006a46c0ec8Sopenharmony_ci	struct list testnames;
1007a46c0ec8Sopenharmony_ci	const char *data_path;
1008a46c0ec8Sopenharmony_ci
1009a46c0ec8Sopenharmony_ci	data_path = getenv("LIBINPUT_QUIRKS_DIR");
1010a46c0ec8Sopenharmony_ci	if (!data_path)
1011a46c0ec8Sopenharmony_ci		data_path = LIBINPUT_QUIRKS_DIR;
1012a46c0ec8Sopenharmony_ci
1013a46c0ec8Sopenharmony_ci	quirks_context = quirks_init_subsystem(data_path,
1014a46c0ec8Sopenharmony_ci					       NULL,
1015a46c0ec8Sopenharmony_ci					       quirk_log_handler,
1016a46c0ec8Sopenharmony_ci					       NULL,
1017a46c0ec8Sopenharmony_ci					       QLOG_LIBINPUT_LOGGING);
1018a46c0ec8Sopenharmony_ci
1019a46c0ec8Sopenharmony_ci	/* Check just takes the suite/test name pointers but doesn't strdup
1020a46c0ec8Sopenharmony_ci	 * them - we have to keep them around */
1021a46c0ec8Sopenharmony_ci	list_init(&testnames);
1022a46c0ec8Sopenharmony_ci
1023a46c0ec8Sopenharmony_ci	/* For each test, create one test suite with one test case, then
1024a46c0ec8Sopenharmony_ci	   add it to the test runner. The only benefit suites give us in
1025a46c0ec8Sopenharmony_ci	   check is that we can filter them, but our test runner has a
1026a46c0ec8Sopenharmony_ci	   --filter-group anyway. */
1027a46c0ec8Sopenharmony_ci	list_for_each(s, tests, node) {
1028a46c0ec8Sopenharmony_ci		list_for_each(t, &s->tests, node) {
1029a46c0ec8Sopenharmony_ci			Suite *suite;
1030a46c0ec8Sopenharmony_ci			TCase *tc;
1031a46c0ec8Sopenharmony_ci			char *sname, *tname;
1032a46c0ec8Sopenharmony_ci
1033a46c0ec8Sopenharmony_ci			/* We run deviceless tests as part of the normal
1034a46c0ec8Sopenharmony_ci			 * test suite runner, just in case. Filtering
1035a46c0ec8Sopenharmony_ci			 * all the other ones out just for the case where
1036a46c0ec8Sopenharmony_ci			 * we can't run the full runner.
1037a46c0ec8Sopenharmony_ci			 */
1038a46c0ec8Sopenharmony_ci			if (run_deviceless && !t->deviceless)
1039a46c0ec8Sopenharmony_ci				continue;
1040a46c0ec8Sopenharmony_ci
1041a46c0ec8Sopenharmony_ci			count = (count + 1) % max;
1042a46c0ec8Sopenharmony_ci			if (max != 1 && (count % max) != which)
1043a46c0ec8Sopenharmony_ci				continue;
1044a46c0ec8Sopenharmony_ci
1045a46c0ec8Sopenharmony_ci			xasprintf(&sname,
1046a46c0ec8Sopenharmony_ci				  "%s:%s:%s",
1047a46c0ec8Sopenharmony_ci				  s->name,
1048a46c0ec8Sopenharmony_ci				  t->name,
1049a46c0ec8Sopenharmony_ci				  t->devname);
1050a46c0ec8Sopenharmony_ci			litest_assert_ptr_notnull(sname);
1051a46c0ec8Sopenharmony_ci			n = zalloc(sizeof(*n));
1052a46c0ec8Sopenharmony_ci			n->name = sname;
1053a46c0ec8Sopenharmony_ci			list_insert(&testnames, &n->node);
1054a46c0ec8Sopenharmony_ci
1055a46c0ec8Sopenharmony_ci			xasprintf(&tname,
1056a46c0ec8Sopenharmony_ci				  "%s:%s",
1057a46c0ec8Sopenharmony_ci				  t->name,
1058a46c0ec8Sopenharmony_ci				  t->devname);
1059a46c0ec8Sopenharmony_ci			litest_assert_ptr_notnull(tname);
1060a46c0ec8Sopenharmony_ci			n = zalloc(sizeof(*n));
1061a46c0ec8Sopenharmony_ci			n->name = tname;
1062a46c0ec8Sopenharmony_ci			list_insert(&testnames, &n->node);
1063a46c0ec8Sopenharmony_ci
1064a46c0ec8Sopenharmony_ci			tc = tcase_create(tname);
1065a46c0ec8Sopenharmony_ci			tcase_add_checked_fixture(tc,
1066a46c0ec8Sopenharmony_ci						  t->setup,
1067a46c0ec8Sopenharmony_ci						  t->teardown);
1068a46c0ec8Sopenharmony_ci			if (t->range.upper != t->range.lower)
1069a46c0ec8Sopenharmony_ci				tcase_add_loop_test(tc,
1070a46c0ec8Sopenharmony_ci						    t->func,
1071a46c0ec8Sopenharmony_ci						    t->range.lower,
1072a46c0ec8Sopenharmony_ci						    t->range.upper);
1073a46c0ec8Sopenharmony_ci			else
1074a46c0ec8Sopenharmony_ci				tcase_add_test(tc, t->func);
1075a46c0ec8Sopenharmony_ci
1076a46c0ec8Sopenharmony_ci			suite = suite_create(sname);
1077a46c0ec8Sopenharmony_ci			suite_add_tcase(suite, tc);
1078a46c0ec8Sopenharmony_ci
1079a46c0ec8Sopenharmony_ci			if (!sr)
1080a46c0ec8Sopenharmony_ci				sr = srunner_create(suite);
1081a46c0ec8Sopenharmony_ci			else
1082a46c0ec8Sopenharmony_ci				srunner_add_suite(sr, suite);
1083a46c0ec8Sopenharmony_ci		}
1084a46c0ec8Sopenharmony_ci	}
1085a46c0ec8Sopenharmony_ci
1086a46c0ec8Sopenharmony_ci	if (!sr)
1087a46c0ec8Sopenharmony_ci		goto out;
1088a46c0ec8Sopenharmony_ci
1089a46c0ec8Sopenharmony_ci	srunner_run_all(sr, CK_ENV);
1090a46c0ec8Sopenharmony_ci	if (xml_prefix)
1091a46c0ec8Sopenharmony_ci		litest_export_xml(sr, xml_prefix);
1092a46c0ec8Sopenharmony_ci
1093a46c0ec8Sopenharmony_ci
1094a46c0ec8Sopenharmony_ci	failed = srunner_ntests_failed(sr);
1095a46c0ec8Sopenharmony_ci	if (failed) {
1096a46c0ec8Sopenharmony_ci		TestResult **trs;
1097a46c0ec8Sopenharmony_ci
1098a46c0ec8Sopenharmony_ci		trs = srunner_failures(sr);
1099a46c0ec8Sopenharmony_ci		for (int i = 0; i < failed; i++) {
1100a46c0ec8Sopenharmony_ci			char tname[256];
1101a46c0ec8Sopenharmony_ci			char *c = tname;
1102a46c0ec8Sopenharmony_ci
1103a46c0ec8Sopenharmony_ci			/* tr_tcname is in the form "suite:testcase", let's
1104a46c0ec8Sopenharmony_ci			 * convert this to "suite(testcase)" to make
1105a46c0ec8Sopenharmony_ci			 * double-click selection in the terminal a bit
1106a46c0ec8Sopenharmony_ci			 * easier. */
1107a46c0ec8Sopenharmony_ci			snprintf(tname, sizeof(tname), "%s)", tr_tcname(trs[i]));
1108a46c0ec8Sopenharmony_ci			if ((c = index(c, ':')))
1109a46c0ec8Sopenharmony_ci				*c = '(';
1110a46c0ec8Sopenharmony_ci
1111a46c0ec8Sopenharmony_ci			dprintf(error_fd,
1112a46c0ec8Sopenharmony_ci				":: Failure: %s:%d: %s\n",
1113a46c0ec8Sopenharmony_ci				tr_lfile(trs[i]),
1114a46c0ec8Sopenharmony_ci				tr_lno(trs[i]),
1115a46c0ec8Sopenharmony_ci				tname);
1116a46c0ec8Sopenharmony_ci		}
1117a46c0ec8Sopenharmony_ci		free(trs);
1118a46c0ec8Sopenharmony_ci	}
1119a46c0ec8Sopenharmony_ci	srunner_free(sr);
1120a46c0ec8Sopenharmony_ciout:
1121a46c0ec8Sopenharmony_ci	list_for_each_safe(n, &testnames, node) {
1122a46c0ec8Sopenharmony_ci		free(n->name);
1123a46c0ec8Sopenharmony_ci		free(n);
1124a46c0ec8Sopenharmony_ci	}
1125a46c0ec8Sopenharmony_ci
1126a46c0ec8Sopenharmony_ci	quirks_context_unref(quirks_context);
1127a46c0ec8Sopenharmony_ci
1128a46c0ec8Sopenharmony_ci	return failed;
1129a46c0ec8Sopenharmony_ci}
1130a46c0ec8Sopenharmony_ci
1131a46c0ec8Sopenharmony_cistatic int
1132a46c0ec8Sopenharmony_cilitest_fork_subtests(struct list *tests, int max_forks)
1133a46c0ec8Sopenharmony_ci{
1134a46c0ec8Sopenharmony_ci	int failed = 0;
1135a46c0ec8Sopenharmony_ci	int status;
1136a46c0ec8Sopenharmony_ci	pid_t pid;
1137a46c0ec8Sopenharmony_ci	int f;
1138a46c0ec8Sopenharmony_ci	int pipes[max_forks];
1139a46c0ec8Sopenharmony_ci
1140a46c0ec8Sopenharmony_ci	for (f = 0; f < max_forks; f++) {
1141a46c0ec8Sopenharmony_ci		int rc;
1142a46c0ec8Sopenharmony_ci		int pipefd[2];
1143a46c0ec8Sopenharmony_ci
1144a46c0ec8Sopenharmony_ci		rc = pipe2(pipefd, O_NONBLOCK);
1145a46c0ec8Sopenharmony_ci		assert(rc != -1);
1146a46c0ec8Sopenharmony_ci
1147a46c0ec8Sopenharmony_ci		pid = fork();
1148a46c0ec8Sopenharmony_ci		if (pid == 0) {
1149a46c0ec8Sopenharmony_ci			close(pipefd[0]);
1150a46c0ec8Sopenharmony_ci			failed = litest_run_suite(tests,
1151a46c0ec8Sopenharmony_ci						  f,
1152a46c0ec8Sopenharmony_ci						  max_forks,
1153a46c0ec8Sopenharmony_ci						  pipefd[1]);
1154a46c0ec8Sopenharmony_ci
1155a46c0ec8Sopenharmony_ci			litest_free_test_list(&all_tests);
1156a46c0ec8Sopenharmony_ci			exit(failed);
1157a46c0ec8Sopenharmony_ci			/* child always exits here */
1158a46c0ec8Sopenharmony_ci		} else {
1159a46c0ec8Sopenharmony_ci			pipes[f] = pipefd[0];
1160a46c0ec8Sopenharmony_ci			close(pipefd[1]);
1161a46c0ec8Sopenharmony_ci		}
1162a46c0ec8Sopenharmony_ci	}
1163a46c0ec8Sopenharmony_ci
1164a46c0ec8Sopenharmony_ci	/* parent process only */
1165a46c0ec8Sopenharmony_ci	while (wait(&status) != -1 && errno != ECHILD) {
1166a46c0ec8Sopenharmony_ci		if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
1167a46c0ec8Sopenharmony_ci			failed = 1;
1168a46c0ec8Sopenharmony_ci	}
1169a46c0ec8Sopenharmony_ci
1170a46c0ec8Sopenharmony_ci	for (f = 0; f < max_forks; f++) {
1171a46c0ec8Sopenharmony_ci		char buf[1024] = {0};
1172a46c0ec8Sopenharmony_ci		int rc;
1173a46c0ec8Sopenharmony_ci
1174a46c0ec8Sopenharmony_ci		while ((rc = read(pipes[f], buf, sizeof(buf) - 1)) > 0) {
1175a46c0ec8Sopenharmony_ci			buf[rc] = '\0';
1176a46c0ec8Sopenharmony_ci			fprintf(stderr, "%s", buf);
1177a46c0ec8Sopenharmony_ci		}
1178a46c0ec8Sopenharmony_ci
1179a46c0ec8Sopenharmony_ci		close(pipes[f]);
1180a46c0ec8Sopenharmony_ci	}
1181a46c0ec8Sopenharmony_ci
1182a46c0ec8Sopenharmony_ci	return failed;
1183a46c0ec8Sopenharmony_ci}
1184a46c0ec8Sopenharmony_ci
1185a46c0ec8Sopenharmony_cistatic inline int
1186a46c0ec8Sopenharmony_ciinhibit(void)
1187a46c0ec8Sopenharmony_ci{
1188a46c0ec8Sopenharmony_ci	int lock_fd = -1;
1189a46c0ec8Sopenharmony_ci#if HAVE_LIBSYSTEMD
1190a46c0ec8Sopenharmony_ci	sd_bus_error error = SD_BUS_ERROR_NULL;
1191a46c0ec8Sopenharmony_ci	sd_bus_message *m = NULL;
1192a46c0ec8Sopenharmony_ci	sd_bus *bus = NULL;
1193a46c0ec8Sopenharmony_ci	int rc;
1194a46c0ec8Sopenharmony_ci
1195a46c0ec8Sopenharmony_ci	if (run_deviceless)
1196a46c0ec8Sopenharmony_ci		return -1;
1197a46c0ec8Sopenharmony_ci
1198a46c0ec8Sopenharmony_ci	rc = sd_bus_open_system(&bus);
1199a46c0ec8Sopenharmony_ci	if (rc != 0) {
1200a46c0ec8Sopenharmony_ci		fprintf(stderr, "Warning: inhibit failed: %s\n", strerror(-rc));
1201a46c0ec8Sopenharmony_ci		goto out;
1202a46c0ec8Sopenharmony_ci	}
1203a46c0ec8Sopenharmony_ci
1204a46c0ec8Sopenharmony_ci	rc = sd_bus_call_method(bus,
1205a46c0ec8Sopenharmony_ci				"org.freedesktop.login1",
1206a46c0ec8Sopenharmony_ci				"/org/freedesktop/login1",
1207a46c0ec8Sopenharmony_ci				"org.freedesktop.login1.Manager",
1208a46c0ec8Sopenharmony_ci				"Inhibit",
1209a46c0ec8Sopenharmony_ci				&error,
1210a46c0ec8Sopenharmony_ci				&m,
1211a46c0ec8Sopenharmony_ci				"ssss",
1212a46c0ec8Sopenharmony_ci				"sleep:shutdown:handle-lid-switch:handle-power-key:handle-suspend-key:handle-hibernate-key",
1213a46c0ec8Sopenharmony_ci				"libinput test-suite runner",
1214a46c0ec8Sopenharmony_ci				"testing in progress",
1215a46c0ec8Sopenharmony_ci				"block");
1216a46c0ec8Sopenharmony_ci	if (rc < 0) {
1217a46c0ec8Sopenharmony_ci		fprintf(stderr, "Warning: inhibit failed: %s\n", error.message);
1218a46c0ec8Sopenharmony_ci		goto out;
1219a46c0ec8Sopenharmony_ci	}
1220a46c0ec8Sopenharmony_ci
1221a46c0ec8Sopenharmony_ci	rc = sd_bus_message_read(m, "h", &lock_fd);
1222a46c0ec8Sopenharmony_ci	if (rc < 0) {
1223a46c0ec8Sopenharmony_ci		fprintf(stderr, "Warning: inhibit failed: %s\n", strerror(-rc));
1224a46c0ec8Sopenharmony_ci		goto out;
1225a46c0ec8Sopenharmony_ci	}
1226a46c0ec8Sopenharmony_ci
1227a46c0ec8Sopenharmony_ci	lock_fd = dup(lock_fd);
1228a46c0ec8Sopenharmony_ciout:
1229a46c0ec8Sopenharmony_ci	sd_bus_error_free(&error);
1230a46c0ec8Sopenharmony_ci	sd_bus_message_unref(m);
1231a46c0ec8Sopenharmony_ci	sd_bus_close(bus);
1232a46c0ec8Sopenharmony_ci	sd_bus_unref(bus);
1233a46c0ec8Sopenharmony_ci#endif
1234a46c0ec8Sopenharmony_ci	return lock_fd;
1235a46c0ec8Sopenharmony_ci}
1236a46c0ec8Sopenharmony_ci
1237a46c0ec8Sopenharmony_cistatic inline int
1238a46c0ec8Sopenharmony_cilitest_run(int argc, char **argv)
1239a46c0ec8Sopenharmony_ci{
1240a46c0ec8Sopenharmony_ci	int failed = 0;
1241a46c0ec8Sopenharmony_ci	int inhibit_lock_fd;
1242a46c0ec8Sopenharmony_ci
1243a46c0ec8Sopenharmony_ci	list_init(&created_files_list);
1244a46c0ec8Sopenharmony_ci
1245a46c0ec8Sopenharmony_ci	if (list_empty(&all_tests)) {
1246a46c0ec8Sopenharmony_ci		fprintf(stderr,
1247a46c0ec8Sopenharmony_ci			"Error: filters are too strict, no tests to run.\n");
1248a46c0ec8Sopenharmony_ci		return 1;
1249a46c0ec8Sopenharmony_ci	}
1250a46c0ec8Sopenharmony_ci
1251a46c0ec8Sopenharmony_ci	if (getenv("LITEST_VERBOSE"))
1252a46c0ec8Sopenharmony_ci		verbose = true;
1253a46c0ec8Sopenharmony_ci
1254a46c0ec8Sopenharmony_ci	if (run_deviceless) {
1255a46c0ec8Sopenharmony_ci		litest_setup_quirks(&created_files_list,
1256a46c0ec8Sopenharmony_ci				    QUIRKS_SETUP_USE_SRCDIR);
1257a46c0ec8Sopenharmony_ci	} else {
1258a46c0ec8Sopenharmony_ci		enum quirks_setup_mode mode;
1259a46c0ec8Sopenharmony_ci		litest_init_udev_rules(&created_files_list);
1260a46c0ec8Sopenharmony_ci
1261a46c0ec8Sopenharmony_ci
1262a46c0ec8Sopenharmony_ci		mode = use_system_rules_quirks ?
1263a46c0ec8Sopenharmony_ci				QUIRKS_SETUP_ONLY_DEVICE :
1264a46c0ec8Sopenharmony_ci				QUIRKS_SETUP_FULL;
1265a46c0ec8Sopenharmony_ci		litest_setup_quirks(&created_files_list, mode);
1266a46c0ec8Sopenharmony_ci	}
1267a46c0ec8Sopenharmony_ci
1268a46c0ec8Sopenharmony_ci	litest_setup_sighandler(SIGINT);
1269a46c0ec8Sopenharmony_ci
1270a46c0ec8Sopenharmony_ci	inhibit_lock_fd = inhibit();
1271a46c0ec8Sopenharmony_ci
1272a46c0ec8Sopenharmony_ci	if (jobs == 1)
1273a46c0ec8Sopenharmony_ci		failed = litest_run_suite(&all_tests, 1, 1, STDERR_FILENO);
1274a46c0ec8Sopenharmony_ci	else
1275a46c0ec8Sopenharmony_ci		failed = litest_fork_subtests(&all_tests, jobs);
1276a46c0ec8Sopenharmony_ci
1277a46c0ec8Sopenharmony_ci	close(inhibit_lock_fd);
1278a46c0ec8Sopenharmony_ci
1279a46c0ec8Sopenharmony_ci	litest_free_test_list(&all_tests);
1280a46c0ec8Sopenharmony_ci
1281a46c0ec8Sopenharmony_ci	litest_remove_udev_rules(&created_files_list);
1282a46c0ec8Sopenharmony_ci
1283a46c0ec8Sopenharmony_ci	return failed;
1284a46c0ec8Sopenharmony_ci}
1285a46c0ec8Sopenharmony_ci
1286a46c0ec8Sopenharmony_cistatic struct input_absinfo *
1287a46c0ec8Sopenharmony_cimerge_absinfo(const struct input_absinfo *orig,
1288a46c0ec8Sopenharmony_ci	      const struct input_absinfo *override)
1289a46c0ec8Sopenharmony_ci{
1290a46c0ec8Sopenharmony_ci	struct input_absinfo *abs;
1291a46c0ec8Sopenharmony_ci	unsigned int nelem, i;
1292a46c0ec8Sopenharmony_ci	size_t sz = ABS_MAX + 1;
1293a46c0ec8Sopenharmony_ci
1294a46c0ec8Sopenharmony_ci	if (!orig)
1295a46c0ec8Sopenharmony_ci		return NULL;
1296a46c0ec8Sopenharmony_ci
1297a46c0ec8Sopenharmony_ci	abs = zalloc(sz * sizeof(*abs));
1298a46c0ec8Sopenharmony_ci	litest_assert_ptr_notnull(abs);
1299a46c0ec8Sopenharmony_ci
1300a46c0ec8Sopenharmony_ci	nelem = 0;
1301a46c0ec8Sopenharmony_ci	while (orig[nelem].value != -1) {
1302a46c0ec8Sopenharmony_ci		abs[nelem] = orig[nelem];
1303a46c0ec8Sopenharmony_ci		nelem++;
1304a46c0ec8Sopenharmony_ci		litest_assert_int_lt(nelem, sz);
1305a46c0ec8Sopenharmony_ci	}
1306a46c0ec8Sopenharmony_ci
1307a46c0ec8Sopenharmony_ci	/* just append, if the same axis is present twice, libevdev will
1308a46c0ec8Sopenharmony_ci	   only use the last value anyway */
1309a46c0ec8Sopenharmony_ci	i = 0;
1310a46c0ec8Sopenharmony_ci	while (override && override[i].value != -1) {
1311a46c0ec8Sopenharmony_ci		abs[nelem++] = override[i++];
1312a46c0ec8Sopenharmony_ci		litest_assert_int_lt(nelem, sz);
1313a46c0ec8Sopenharmony_ci	}
1314a46c0ec8Sopenharmony_ci
1315a46c0ec8Sopenharmony_ci	litest_assert_int_lt(nelem, sz);
1316a46c0ec8Sopenharmony_ci	abs[nelem].value = -1;
1317a46c0ec8Sopenharmony_ci
1318a46c0ec8Sopenharmony_ci	return abs;
1319a46c0ec8Sopenharmony_ci}
1320a46c0ec8Sopenharmony_ci
1321a46c0ec8Sopenharmony_cistatic int*
1322a46c0ec8Sopenharmony_cimerge_events(const int *orig, const int *override)
1323a46c0ec8Sopenharmony_ci{
1324a46c0ec8Sopenharmony_ci	int *events;
1325a46c0ec8Sopenharmony_ci	unsigned int nelem, i;
1326a46c0ec8Sopenharmony_ci	size_t sz = KEY_MAX * 3;
1327a46c0ec8Sopenharmony_ci
1328a46c0ec8Sopenharmony_ci	if (!orig)
1329a46c0ec8Sopenharmony_ci		return NULL;
1330a46c0ec8Sopenharmony_ci
1331a46c0ec8Sopenharmony_ci	events = zalloc(sz * sizeof(int));
1332a46c0ec8Sopenharmony_ci	litest_assert_ptr_notnull(events);
1333a46c0ec8Sopenharmony_ci
1334a46c0ec8Sopenharmony_ci	nelem = 0;
1335a46c0ec8Sopenharmony_ci	while (orig[nelem] != -1) {
1336a46c0ec8Sopenharmony_ci		events[nelem] = orig[nelem];
1337a46c0ec8Sopenharmony_ci		nelem++;
1338a46c0ec8Sopenharmony_ci		litest_assert_int_lt(nelem, sz);
1339a46c0ec8Sopenharmony_ci	}
1340a46c0ec8Sopenharmony_ci
1341a46c0ec8Sopenharmony_ci	/* just append, if the same axis is present twice, libevdev will
1342a46c0ec8Sopenharmony_ci	 * ignore the double definition anyway */
1343a46c0ec8Sopenharmony_ci	i = 0;
1344a46c0ec8Sopenharmony_ci	while (override && override[i] != -1) {
1345a46c0ec8Sopenharmony_ci		events[nelem++] = override[i++];
1346a46c0ec8Sopenharmony_ci		litest_assert_int_le(nelem, sz);
1347a46c0ec8Sopenharmony_ci	}
1348a46c0ec8Sopenharmony_ci
1349a46c0ec8Sopenharmony_ci	litest_assert_int_lt(nelem, sz);
1350a46c0ec8Sopenharmony_ci	events[nelem] = -1;
1351a46c0ec8Sopenharmony_ci
1352a46c0ec8Sopenharmony_ci	return events;
1353a46c0ec8Sopenharmony_ci}
1354a46c0ec8Sopenharmony_ci
1355a46c0ec8Sopenharmony_cistatic inline struct created_file *
1356a46c0ec8Sopenharmony_cilitest_copy_file(const char *dest, const char *src, const char *header, bool is_file)
1357a46c0ec8Sopenharmony_ci{
1358a46c0ec8Sopenharmony_ci	int in, out, length;
1359a46c0ec8Sopenharmony_ci	struct created_file *file;
1360a46c0ec8Sopenharmony_ci
1361a46c0ec8Sopenharmony_ci	file = zalloc(sizeof(*file));
1362a46c0ec8Sopenharmony_ci	file->path = safe_strdup(dest);
1363a46c0ec8Sopenharmony_ci
1364a46c0ec8Sopenharmony_ci	if (strstr(dest, "XXXXXX")) {
1365a46c0ec8Sopenharmony_ci		int suffixlen;
1366a46c0ec8Sopenharmony_ci
1367a46c0ec8Sopenharmony_ci		suffixlen = file->path +
1368a46c0ec8Sopenharmony_ci				strlen(file->path) -
1369a46c0ec8Sopenharmony_ci				rindex(file->path, '.');
1370a46c0ec8Sopenharmony_ci		out = mkstemps(file->path, suffixlen);
1371a46c0ec8Sopenharmony_ci	} else {
1372a46c0ec8Sopenharmony_ci		out = open(file->path, O_CREAT|O_WRONLY, 0644);
1373a46c0ec8Sopenharmony_ci	}
1374a46c0ec8Sopenharmony_ci	if (out == -1)
1375a46c0ec8Sopenharmony_ci		litest_abort_msg("Failed to write to file %s (%s)\n",
1376a46c0ec8Sopenharmony_ci				 file->path,
1377a46c0ec8Sopenharmony_ci				 strerror(errno));
1378a46c0ec8Sopenharmony_ci	litest_assert_int_ne(chmod(file->path, 0644), -1);
1379a46c0ec8Sopenharmony_ci
1380a46c0ec8Sopenharmony_ci	if (header) {
1381a46c0ec8Sopenharmony_ci		length = strlen(header);
1382a46c0ec8Sopenharmony_ci		litest_assert_int_eq(write(out, header, length), length);
1383a46c0ec8Sopenharmony_ci	}
1384a46c0ec8Sopenharmony_ci
1385a46c0ec8Sopenharmony_ci	if (is_file) {
1386a46c0ec8Sopenharmony_ci		in = open(src, O_RDONLY);
1387a46c0ec8Sopenharmony_ci		if (in == -1)
1388a46c0ec8Sopenharmony_ci			litest_abort_msg("Failed to open file %s (%s)\n",
1389a46c0ec8Sopenharmony_ci					 src,
1390a46c0ec8Sopenharmony_ci					 strerror(errno));
1391a46c0ec8Sopenharmony_ci		/* lazy, just check for error and empty file copy */
1392a46c0ec8Sopenharmony_ci		litest_assert_int_gt(litest_send_file(out, in), 0);
1393a46c0ec8Sopenharmony_ci		close(in);
1394a46c0ec8Sopenharmony_ci	} else {
1395a46c0ec8Sopenharmony_ci		size_t written = write(out, src, strlen(src));
1396a46c0ec8Sopenharmony_ci		litest_assert_int_eq(written, strlen(src));
1397a46c0ec8Sopenharmony_ci
1398a46c0ec8Sopenharmony_ci	}
1399a46c0ec8Sopenharmony_ci	close(out);
1400a46c0ec8Sopenharmony_ci
1401a46c0ec8Sopenharmony_ci	return file;
1402a46c0ec8Sopenharmony_ci}
1403a46c0ec8Sopenharmony_ci
1404a46c0ec8Sopenharmony_cistatic inline void
1405a46c0ec8Sopenharmony_cilitest_install_model_quirks(struct list *created_files_list)
1406a46c0ec8Sopenharmony_ci{
1407a46c0ec8Sopenharmony_ci	const char *warning =
1408a46c0ec8Sopenharmony_ci			 "#################################################################\n"
1409a46c0ec8Sopenharmony_ci			 "# WARNING: REMOVE THIS FILE\n"
1410a46c0ec8Sopenharmony_ci			 "# This is a run-time file for the libinput test suite and\n"
1411a46c0ec8Sopenharmony_ci			 "# should be removed on exit. If the test-suite is not currently \n"
1412a46c0ec8Sopenharmony_ci			 "# running, remove this file\n"
1413a46c0ec8Sopenharmony_ci			 "#################################################################\n\n";
1414a46c0ec8Sopenharmony_ci	struct created_file *file;
1415a46c0ec8Sopenharmony_ci	const char *test_device_udev_rule = "KERNELS==\"*input*\", "
1416a46c0ec8Sopenharmony_ci					    "ATTRS{name}==\"litest *\", "
1417a46c0ec8Sopenharmony_ci					    "ENV{LIBINPUT_TEST_DEVICE}=\"1\"";
1418a46c0ec8Sopenharmony_ci
1419a46c0ec8Sopenharmony_ci	file = litest_copy_file(UDEV_TEST_DEVICE_RULE_FILE,
1420a46c0ec8Sopenharmony_ci				test_device_udev_rule,
1421a46c0ec8Sopenharmony_ci				warning,
1422a46c0ec8Sopenharmony_ci				false);
1423a46c0ec8Sopenharmony_ci	list_insert(created_files_list, &file->link);
1424a46c0ec8Sopenharmony_ci
1425a46c0ec8Sopenharmony_ci	/* Only install the litest device rule when we're running as system
1426a46c0ec8Sopenharmony_ci	 * test suite, we expect the others to be in place already */
1427a46c0ec8Sopenharmony_ci	if (use_system_rules_quirks)
1428a46c0ec8Sopenharmony_ci		return;
1429a46c0ec8Sopenharmony_ci
1430a46c0ec8Sopenharmony_ci	file = litest_copy_file(UDEV_DEVICE_GROUPS_FILE,
1431a46c0ec8Sopenharmony_ci				LIBINPUT_DEVICE_GROUPS_RULES_FILE,
1432a46c0ec8Sopenharmony_ci				warning,
1433a46c0ec8Sopenharmony_ci				true);
1434a46c0ec8Sopenharmony_ci	list_insert(created_files_list, &file->link);
1435a46c0ec8Sopenharmony_ci
1436a46c0ec8Sopenharmony_ci	file = litest_copy_file(UDEV_FUZZ_OVERRIDE_RULE_FILE,
1437a46c0ec8Sopenharmony_ci				LIBINPUT_FUZZ_OVERRIDE_UDEV_RULES_FILE,
1438a46c0ec8Sopenharmony_ci				warning,
1439a46c0ec8Sopenharmony_ci				true);
1440a46c0ec8Sopenharmony_ci	list_insert(created_files_list, &file->link);
1441a46c0ec8Sopenharmony_ci}
1442a46c0ec8Sopenharmony_ci
1443a46c0ec8Sopenharmony_cistatic char *
1444a46c0ec8Sopenharmony_cilitest_init_device_quirk_file(const char *data_dir,
1445a46c0ec8Sopenharmony_ci			      struct litest_test_device *dev)
1446a46c0ec8Sopenharmony_ci{
1447a46c0ec8Sopenharmony_ci	int fd;
1448a46c0ec8Sopenharmony_ci	FILE *f;
1449a46c0ec8Sopenharmony_ci	char path[PATH_MAX];
1450a46c0ec8Sopenharmony_ci	static int count;
1451a46c0ec8Sopenharmony_ci
1452a46c0ec8Sopenharmony_ci	if (!dev->quirk_file)
1453a46c0ec8Sopenharmony_ci		return NULL;
1454a46c0ec8Sopenharmony_ci
1455a46c0ec8Sopenharmony_ci	snprintf(path, sizeof(path),
1456a46c0ec8Sopenharmony_ci		 "%s/99-%03d-%s.quirks",
1457a46c0ec8Sopenharmony_ci		 data_dir,
1458a46c0ec8Sopenharmony_ci		 ++count,
1459a46c0ec8Sopenharmony_ci		 dev->shortname);
1460a46c0ec8Sopenharmony_ci	fd = open(path, O_CREAT|O_WRONLY, 0644);
1461a46c0ec8Sopenharmony_ci	litest_assert_int_ne(fd, -1);
1462a46c0ec8Sopenharmony_ci	f = fdopen(fd, "w");
1463a46c0ec8Sopenharmony_ci	litest_assert_notnull(f);
1464a46c0ec8Sopenharmony_ci	litest_assert_int_ge(fputs(dev->quirk_file, f), 0);
1465a46c0ec8Sopenharmony_ci	fclose(f);
1466a46c0ec8Sopenharmony_ci
1467a46c0ec8Sopenharmony_ci	return safe_strdup(path);
1468a46c0ec8Sopenharmony_ci}
1469a46c0ec8Sopenharmony_ci
1470a46c0ec8Sopenharmony_cistatic int is_quirks_file(const struct dirent *dir) {
1471a46c0ec8Sopenharmony_ci	return strendswith(dir->d_name, ".quirks");
1472a46c0ec8Sopenharmony_ci}
1473a46c0ec8Sopenharmony_ci
1474a46c0ec8Sopenharmony_ci/**
1475a46c0ec8Sopenharmony_ci * Install the quirks from the quirks/ source directory.
1476a46c0ec8Sopenharmony_ci */
1477a46c0ec8Sopenharmony_cistatic void
1478a46c0ec8Sopenharmony_cilitest_install_source_quirks(struct list *created_files_list,
1479a46c0ec8Sopenharmony_ci			     const char *dirname)
1480a46c0ec8Sopenharmony_ci{
1481a46c0ec8Sopenharmony_ci	struct dirent **namelist;
1482a46c0ec8Sopenharmony_ci	int ndev;
1483a46c0ec8Sopenharmony_ci
1484a46c0ec8Sopenharmony_ci	ndev = scandir(LIBINPUT_QUIRKS_SRCDIR,
1485a46c0ec8Sopenharmony_ci		       &namelist,
1486a46c0ec8Sopenharmony_ci		       is_quirks_file,
1487a46c0ec8Sopenharmony_ci		       versionsort);
1488a46c0ec8Sopenharmony_ci	litest_assert_int_ge(ndev, 0);
1489a46c0ec8Sopenharmony_ci
1490a46c0ec8Sopenharmony_ci	for (int idx = 0; idx < ndev; idx++) {
1491a46c0ec8Sopenharmony_ci		struct created_file *file;
1492a46c0ec8Sopenharmony_ci		char *filename;
1493a46c0ec8Sopenharmony_ci		char dest[PATH_MAX];
1494a46c0ec8Sopenharmony_ci		char src[PATH_MAX];
1495a46c0ec8Sopenharmony_ci
1496a46c0ec8Sopenharmony_ci		filename = namelist[idx]->d_name;
1497a46c0ec8Sopenharmony_ci		snprintf(src, sizeof(src), "%s/%s",
1498a46c0ec8Sopenharmony_ci			 LIBINPUT_QUIRKS_SRCDIR, filename);
1499a46c0ec8Sopenharmony_ci		snprintf(dest, sizeof(dest), "%s/%s", dirname, filename);
1500a46c0ec8Sopenharmony_ci		file = litest_copy_file(dest, src, NULL, true);
1501a46c0ec8Sopenharmony_ci		list_append(created_files_list, &file->link);
1502a46c0ec8Sopenharmony_ci		free(namelist[idx]);
1503a46c0ec8Sopenharmony_ci	}
1504a46c0ec8Sopenharmony_ci	free(namelist);
1505a46c0ec8Sopenharmony_ci}
1506a46c0ec8Sopenharmony_ci
1507a46c0ec8Sopenharmony_ci/**
1508a46c0ec8Sopenharmony_ci * Install the quirks from the various litest test devices
1509a46c0ec8Sopenharmony_ci */
1510a46c0ec8Sopenharmony_cistatic void
1511a46c0ec8Sopenharmony_cilitest_install_device_quirks(struct list *created_files_list,
1512a46c0ec8Sopenharmony_ci			     const char *dirname)
1513a46c0ec8Sopenharmony_ci{
1514a46c0ec8Sopenharmony_ci	struct litest_test_device *dev;
1515a46c0ec8Sopenharmony_ci
1516a46c0ec8Sopenharmony_ci	list_for_each(dev, &devices, node) {
1517a46c0ec8Sopenharmony_ci		char *path;
1518a46c0ec8Sopenharmony_ci
1519a46c0ec8Sopenharmony_ci		path = litest_init_device_quirk_file(dirname, dev);
1520a46c0ec8Sopenharmony_ci		if (path) {
1521a46c0ec8Sopenharmony_ci			struct created_file *file = zalloc(sizeof(*file));
1522a46c0ec8Sopenharmony_ci			file->path = path;
1523a46c0ec8Sopenharmony_ci			list_insert(created_files_list, &file->link);
1524a46c0ec8Sopenharmony_ci		}
1525a46c0ec8Sopenharmony_ci	}
1526a46c0ec8Sopenharmony_ci}
1527a46c0ec8Sopenharmony_ci
1528a46c0ec8Sopenharmony_cistatic void
1529a46c0ec8Sopenharmony_cilitest_setup_quirks(struct list *created_files_list,
1530a46c0ec8Sopenharmony_ci		    enum quirks_setup_mode mode)
1531a46c0ec8Sopenharmony_ci{
1532a46c0ec8Sopenharmony_ci	struct created_file *file = NULL;
1533a46c0ec8Sopenharmony_ci	const char *dirname;
1534a46c0ec8Sopenharmony_ci	char tmpdir[] = "/run/litest-XXXXXX";
1535a46c0ec8Sopenharmony_ci
1536a46c0ec8Sopenharmony_ci	switch (mode) {
1537a46c0ec8Sopenharmony_ci	case QUIRKS_SETUP_USE_SRCDIR:
1538a46c0ec8Sopenharmony_ci		dirname = LIBINPUT_QUIRKS_SRCDIR;
1539a46c0ec8Sopenharmony_ci		break;
1540a46c0ec8Sopenharmony_ci	case QUIRKS_SETUP_ONLY_DEVICE:
1541a46c0ec8Sopenharmony_ci		dirname = LIBINPUT_QUIRKS_DIR;
1542a46c0ec8Sopenharmony_ci		litest_install_device_quirks(created_files_list, dirname);
1543a46c0ec8Sopenharmony_ci		break;
1544a46c0ec8Sopenharmony_ci	case QUIRKS_SETUP_FULL:
1545a46c0ec8Sopenharmony_ci		litest_assert_notnull(mkdtemp(tmpdir));
1546a46c0ec8Sopenharmony_ci		litest_assert_int_ne(chmod(tmpdir, 0755), -1);
1547a46c0ec8Sopenharmony_ci		file = zalloc(sizeof *file);
1548a46c0ec8Sopenharmony_ci		file->path = safe_strdup(tmpdir);
1549a46c0ec8Sopenharmony_ci		dirname = tmpdir;
1550a46c0ec8Sopenharmony_ci
1551a46c0ec8Sopenharmony_ci		litest_install_source_quirks(created_files_list, dirname);
1552a46c0ec8Sopenharmony_ci		litest_install_device_quirks(created_files_list, dirname);
1553a46c0ec8Sopenharmony_ci		list_append(created_files_list, &file->link);
1554a46c0ec8Sopenharmony_ci		break;
1555a46c0ec8Sopenharmony_ci	}
1556a46c0ec8Sopenharmony_ci
1557a46c0ec8Sopenharmony_ci	setenv("LIBINPUT_QUIRKS_DIR", dirname, 1);
1558a46c0ec8Sopenharmony_ci}
1559a46c0ec8Sopenharmony_ci
1560a46c0ec8Sopenharmony_cistatic inline void
1561a46c0ec8Sopenharmony_cimkdir_p(const char *dir)
1562a46c0ec8Sopenharmony_ci{
1563a46c0ec8Sopenharmony_ci	char *path, *parent;
1564a46c0ec8Sopenharmony_ci	int rc;
1565a46c0ec8Sopenharmony_ci
1566a46c0ec8Sopenharmony_ci	if (streq(dir, "/"))
1567a46c0ec8Sopenharmony_ci		return;
1568a46c0ec8Sopenharmony_ci
1569a46c0ec8Sopenharmony_ci	path = safe_strdup(dir);
1570a46c0ec8Sopenharmony_ci	parent = dirname(path);
1571a46c0ec8Sopenharmony_ci
1572a46c0ec8Sopenharmony_ci	mkdir_p(parent);
1573a46c0ec8Sopenharmony_ci	rc = mkdir(dir, 0755);
1574a46c0ec8Sopenharmony_ci
1575a46c0ec8Sopenharmony_ci	if (rc == -1 && errno != EEXIST) {
1576a46c0ec8Sopenharmony_ci		litest_abort_msg("Failed to create directory %s (%s)\n",
1577a46c0ec8Sopenharmony_ci				 dir,
1578a46c0ec8Sopenharmony_ci				 strerror(errno));
1579a46c0ec8Sopenharmony_ci	}
1580a46c0ec8Sopenharmony_ci
1581a46c0ec8Sopenharmony_ci	free(path);
1582a46c0ec8Sopenharmony_ci}
1583a46c0ec8Sopenharmony_ci
1584a46c0ec8Sopenharmony_cistatic inline void
1585a46c0ec8Sopenharmony_cilitest_init_udev_rules(struct list *created_files)
1586a46c0ec8Sopenharmony_ci{
1587a46c0ec8Sopenharmony_ci	mkdir_p(UDEV_RULES_D);
1588a46c0ec8Sopenharmony_ci
1589a46c0ec8Sopenharmony_ci	litest_install_model_quirks(created_files);
1590a46c0ec8Sopenharmony_ci	litest_init_all_device_udev_rules(created_files);
1591a46c0ec8Sopenharmony_ci	litest_reload_udev_rules();
1592a46c0ec8Sopenharmony_ci}
1593a46c0ec8Sopenharmony_ci
1594a46c0ec8Sopenharmony_cistatic inline void
1595a46c0ec8Sopenharmony_cilitest_remove_udev_rules(struct list *created_files_list)
1596a46c0ec8Sopenharmony_ci{
1597a46c0ec8Sopenharmony_ci	struct created_file *f;
1598a46c0ec8Sopenharmony_ci	bool reload_udev;
1599a46c0ec8Sopenharmony_ci
1600a46c0ec8Sopenharmony_ci	reload_udev = !list_empty(created_files_list);
1601a46c0ec8Sopenharmony_ci
1602a46c0ec8Sopenharmony_ci	list_for_each_safe(f, created_files_list, link) {
1603a46c0ec8Sopenharmony_ci		list_remove(&f->link);
1604a46c0ec8Sopenharmony_ci		unlink(f->path);
1605a46c0ec8Sopenharmony_ci		rmdir(f->path);
1606a46c0ec8Sopenharmony_ci		free(f->path);
1607a46c0ec8Sopenharmony_ci		free(f);
1608a46c0ec8Sopenharmony_ci	}
1609a46c0ec8Sopenharmony_ci
1610a46c0ec8Sopenharmony_ci	if (reload_udev)
1611a46c0ec8Sopenharmony_ci		litest_reload_udev_rules();
1612a46c0ec8Sopenharmony_ci}
1613a46c0ec8Sopenharmony_ci
1614a46c0ec8Sopenharmony_ci/**
1615a46c0ec8Sopenharmony_ci * Creates a uinput device but does not add it to a libinput context
1616a46c0ec8Sopenharmony_ci */
1617a46c0ec8Sopenharmony_cistruct litest_device *
1618a46c0ec8Sopenharmony_cilitest_create(enum litest_device_type which,
1619a46c0ec8Sopenharmony_ci	      const char *name_override,
1620a46c0ec8Sopenharmony_ci	      struct input_id *id_override,
1621a46c0ec8Sopenharmony_ci	      const struct input_absinfo *abs_override,
1622a46c0ec8Sopenharmony_ci	      const int *events_override)
1623a46c0ec8Sopenharmony_ci{
1624a46c0ec8Sopenharmony_ci	struct litest_device *d = NULL;
1625a46c0ec8Sopenharmony_ci	struct litest_test_device *dev;
1626a46c0ec8Sopenharmony_ci	const char *name;
1627a46c0ec8Sopenharmony_ci	const struct input_id *id;
1628a46c0ec8Sopenharmony_ci	struct input_absinfo *abs;
1629a46c0ec8Sopenharmony_ci	int *events, *e;
1630a46c0ec8Sopenharmony_ci	const char *path;
1631a46c0ec8Sopenharmony_ci	int fd, rc;
1632a46c0ec8Sopenharmony_ci	bool found = false;
1633a46c0ec8Sopenharmony_ci	bool create_device = true;
1634a46c0ec8Sopenharmony_ci
1635a46c0ec8Sopenharmony_ci	list_for_each(dev, &devices, node) {
1636a46c0ec8Sopenharmony_ci		if (dev->type == which) {
1637a46c0ec8Sopenharmony_ci			found = true;
1638a46c0ec8Sopenharmony_ci			break;
1639a46c0ec8Sopenharmony_ci		}
1640a46c0ec8Sopenharmony_ci	}
1641a46c0ec8Sopenharmony_ci
1642a46c0ec8Sopenharmony_ci	if (!found)
1643a46c0ec8Sopenharmony_ci		ck_abort_msg("Invalid device type %d\n", which);
1644a46c0ec8Sopenharmony_ci
1645a46c0ec8Sopenharmony_ci	d = zalloc(sizeof(*d));
1646a46c0ec8Sopenharmony_ci	d->which = which;
1647a46c0ec8Sopenharmony_ci
1648a46c0ec8Sopenharmony_ci	/* device has custom create method */
1649a46c0ec8Sopenharmony_ci	if (dev->create) {
1650a46c0ec8Sopenharmony_ci		create_device = dev->create(d);
1651a46c0ec8Sopenharmony_ci		if (abs_override || events_override) {
1652a46c0ec8Sopenharmony_ci			litest_abort_msg("Custom create cannot be overridden");
1653a46c0ec8Sopenharmony_ci		}
1654a46c0ec8Sopenharmony_ci	}
1655a46c0ec8Sopenharmony_ci
1656a46c0ec8Sopenharmony_ci	abs = merge_absinfo(dev->absinfo, abs_override);
1657a46c0ec8Sopenharmony_ci	events = merge_events(dev->events, events_override);
1658a46c0ec8Sopenharmony_ci	name = name_override ? name_override : dev->name;
1659a46c0ec8Sopenharmony_ci	id = id_override ? id_override : dev->id;
1660a46c0ec8Sopenharmony_ci
1661a46c0ec8Sopenharmony_ci	if (create_device) {
1662a46c0ec8Sopenharmony_ci		d->uinput = litest_create_uinput_device_from_description(name,
1663a46c0ec8Sopenharmony_ci									 id,
1664a46c0ec8Sopenharmony_ci									 abs,
1665a46c0ec8Sopenharmony_ci									 events);
1666a46c0ec8Sopenharmony_ci		d->interface = dev->interface;
1667a46c0ec8Sopenharmony_ci
1668a46c0ec8Sopenharmony_ci		for (e = events; *e != -1; e += 2) {
1669a46c0ec8Sopenharmony_ci			unsigned int type = *e,
1670a46c0ec8Sopenharmony_ci				     code = *(e + 1);
1671a46c0ec8Sopenharmony_ci
1672a46c0ec8Sopenharmony_ci			if (type == INPUT_PROP_MAX &&
1673a46c0ec8Sopenharmony_ci			    code == INPUT_PROP_SEMI_MT) {
1674a46c0ec8Sopenharmony_ci				d->semi_mt.is_semi_mt = true;
1675a46c0ec8Sopenharmony_ci				break;
1676a46c0ec8Sopenharmony_ci			}
1677a46c0ec8Sopenharmony_ci		}
1678a46c0ec8Sopenharmony_ci	}
1679a46c0ec8Sopenharmony_ci
1680a46c0ec8Sopenharmony_ci	free(abs);
1681a46c0ec8Sopenharmony_ci	free(events);
1682a46c0ec8Sopenharmony_ci
1683a46c0ec8Sopenharmony_ci	path = libevdev_uinput_get_devnode(d->uinput);
1684a46c0ec8Sopenharmony_ci	litest_assert_ptr_notnull(path);
1685a46c0ec8Sopenharmony_ci	fd = open(path, O_RDWR|O_NONBLOCK);
1686a46c0ec8Sopenharmony_ci	litest_assert_int_ne(fd, -1);
1687a46c0ec8Sopenharmony_ci
1688a46c0ec8Sopenharmony_ci	rc = libevdev_new_from_fd(fd, &d->evdev);
1689a46c0ec8Sopenharmony_ci	litest_assert_int_eq(rc, 0);
1690a46c0ec8Sopenharmony_ci
1691a46c0ec8Sopenharmony_ci	return d;
1692a46c0ec8Sopenharmony_ci
1693a46c0ec8Sopenharmony_ci}
1694a46c0ec8Sopenharmony_ci
1695a46c0ec8Sopenharmony_cistruct libinput *
1696a46c0ec8Sopenharmony_cilitest_create_context(void)
1697a46c0ec8Sopenharmony_ci{
1698a46c0ec8Sopenharmony_ci	struct libinput *libinput;
1699a46c0ec8Sopenharmony_ci	struct litest_context *ctx;
1700a46c0ec8Sopenharmony_ci
1701a46c0ec8Sopenharmony_ci	ctx = zalloc(sizeof *ctx);
1702a46c0ec8Sopenharmony_ci	list_init(&ctx->paths);
1703a46c0ec8Sopenharmony_ci
1704a46c0ec8Sopenharmony_ci	libinput = libinput_path_create_context(&interface, ctx);
1705a46c0ec8Sopenharmony_ci	litest_assert_notnull(libinput);
1706a46c0ec8Sopenharmony_ci
1707a46c0ec8Sopenharmony_ci	libinput_log_set_handler(libinput, litest_log_handler);
1708a46c0ec8Sopenharmony_ci	if (verbose)
1709a46c0ec8Sopenharmony_ci		libinput_log_set_priority(libinput, LIBINPUT_LOG_PRIORITY_DEBUG);
1710a46c0ec8Sopenharmony_ci
1711a46c0ec8Sopenharmony_ci	return libinput;
1712a46c0ec8Sopenharmony_ci}
1713a46c0ec8Sopenharmony_ci
1714a46c0ec8Sopenharmony_civoid
1715a46c0ec8Sopenharmony_cilitest_destroy_context(struct libinput *li)
1716a46c0ec8Sopenharmony_ci{
1717a46c0ec8Sopenharmony_ci	struct path *p;
1718a46c0ec8Sopenharmony_ci	struct litest_context *ctx;
1719a46c0ec8Sopenharmony_ci
1720a46c0ec8Sopenharmony_ci
1721a46c0ec8Sopenharmony_ci	ctx = libinput_get_user_data(li);
1722a46c0ec8Sopenharmony_ci	litest_assert_ptr_notnull(ctx);
1723a46c0ec8Sopenharmony_ci	libinput_unref(li);
1724a46c0ec8Sopenharmony_ci
1725a46c0ec8Sopenharmony_ci	list_for_each_safe(p, &ctx->paths, link) {
1726a46c0ec8Sopenharmony_ci		litest_abort_msg("Device paths should be removed by now");
1727a46c0ec8Sopenharmony_ci	}
1728a46c0ec8Sopenharmony_ci	free(ctx);
1729a46c0ec8Sopenharmony_ci}
1730a46c0ec8Sopenharmony_ci
1731a46c0ec8Sopenharmony_civoid
1732a46c0ec8Sopenharmony_cilitest_disable_log_handler(struct libinput *libinput)
1733a46c0ec8Sopenharmony_ci{
1734a46c0ec8Sopenharmony_ci	libinput_log_set_handler(libinput, NULL);
1735a46c0ec8Sopenharmony_ci}
1736a46c0ec8Sopenharmony_ci
1737a46c0ec8Sopenharmony_civoid
1738a46c0ec8Sopenharmony_cilitest_restore_log_handler(struct libinput *libinput)
1739a46c0ec8Sopenharmony_ci{
1740a46c0ec8Sopenharmony_ci	libinput_log_set_handler(libinput, litest_log_handler);
1741a46c0ec8Sopenharmony_ci	if (verbose)
1742a46c0ec8Sopenharmony_ci		libinput_log_set_priority(libinput, LIBINPUT_LOG_PRIORITY_DEBUG);
1743a46c0ec8Sopenharmony_ci}
1744a46c0ec8Sopenharmony_ci
1745a46c0ec8Sopenharmony_ciLIBINPUT_ATTRIBUTE_PRINTF(3, 0)
1746a46c0ec8Sopenharmony_cistatic void
1747a46c0ec8Sopenharmony_cilitest_bug_log_handler(struct libinput *libinput,
1748a46c0ec8Sopenharmony_ci		       enum libinput_log_priority pri,
1749a46c0ec8Sopenharmony_ci		       const char *format,
1750a46c0ec8Sopenharmony_ci		       va_list args)
1751a46c0ec8Sopenharmony_ci{
1752a46c0ec8Sopenharmony_ci	if (strstr(format, "client bug: ") ||
1753a46c0ec8Sopenharmony_ci	    strstr(format, "libinput bug: ") ||
1754a46c0ec8Sopenharmony_ci	    strstr(format, "kernel bug: "))
1755a46c0ec8Sopenharmony_ci		return;
1756a46c0ec8Sopenharmony_ci
1757a46c0ec8Sopenharmony_ci	litest_abort_msg("Expected bug statement in log msg, aborting.\n");
1758a46c0ec8Sopenharmony_ci}
1759a46c0ec8Sopenharmony_ci
1760a46c0ec8Sopenharmony_civoid
1761a46c0ec8Sopenharmony_cilitest_set_log_handler_bug(struct libinput *libinput)
1762a46c0ec8Sopenharmony_ci{
1763a46c0ec8Sopenharmony_ci	libinput_log_set_handler(libinput, litest_bug_log_handler);
1764a46c0ec8Sopenharmony_ci}
1765a46c0ec8Sopenharmony_ci
1766a46c0ec8Sopenharmony_cistruct litest_device *
1767a46c0ec8Sopenharmony_cilitest_add_device_with_overrides(struct libinput *libinput,
1768a46c0ec8Sopenharmony_ci				 enum litest_device_type which,
1769a46c0ec8Sopenharmony_ci				 const char *name_override,
1770a46c0ec8Sopenharmony_ci				 struct input_id *id_override,
1771a46c0ec8Sopenharmony_ci				 const struct input_absinfo *abs_override,
1772a46c0ec8Sopenharmony_ci				 const int *events_override)
1773a46c0ec8Sopenharmony_ci{
1774a46c0ec8Sopenharmony_ci	struct udev_device *ud;
1775a46c0ec8Sopenharmony_ci	struct litest_device *d;
1776a46c0ec8Sopenharmony_ci	const char *path;
1777a46c0ec8Sopenharmony_ci
1778a46c0ec8Sopenharmony_ci	d = litest_create(which,
1779a46c0ec8Sopenharmony_ci			  name_override,
1780a46c0ec8Sopenharmony_ci			  id_override,
1781a46c0ec8Sopenharmony_ci			  abs_override,
1782a46c0ec8Sopenharmony_ci			  events_override);
1783a46c0ec8Sopenharmony_ci
1784a46c0ec8Sopenharmony_ci	path = libevdev_uinput_get_devnode(d->uinput);
1785a46c0ec8Sopenharmony_ci	litest_assert_ptr_notnull(path);
1786a46c0ec8Sopenharmony_ci
1787a46c0ec8Sopenharmony_ci	d->libinput = libinput;
1788a46c0ec8Sopenharmony_ci	d->libinput_device = libinput_path_add_device(d->libinput, path);
1789a46c0ec8Sopenharmony_ci	litest_assert_ptr_notnull(d->libinput_device);
1790a46c0ec8Sopenharmony_ci	ud = libinput_device_get_udev_device(d->libinput_device);
1791a46c0ec8Sopenharmony_ci	d->quirks = quirks_fetch_for_device(quirks_context, ud);
1792a46c0ec8Sopenharmony_ci	udev_device_unref(ud);
1793a46c0ec8Sopenharmony_ci
1794a46c0ec8Sopenharmony_ci	libinput_device_ref(d->libinput_device);
1795a46c0ec8Sopenharmony_ci
1796a46c0ec8Sopenharmony_ci	if (d->interface) {
1797a46c0ec8Sopenharmony_ci		unsigned int code;
1798a46c0ec8Sopenharmony_ci
1799a46c0ec8Sopenharmony_ci		code = ABS_X;
1800a46c0ec8Sopenharmony_ci		if (!libevdev_has_event_code(d->evdev, EV_ABS, code))
1801a46c0ec8Sopenharmony_ci			code = ABS_MT_POSITION_X;
1802a46c0ec8Sopenharmony_ci		if (libevdev_has_event_code(d->evdev, EV_ABS, code)) {
1803a46c0ec8Sopenharmony_ci			d->interface->min[ABS_X] = libevdev_get_abs_minimum(d->evdev, code);
1804a46c0ec8Sopenharmony_ci			d->interface->max[ABS_X] = libevdev_get_abs_maximum(d->evdev, code);
1805a46c0ec8Sopenharmony_ci		}
1806a46c0ec8Sopenharmony_ci
1807a46c0ec8Sopenharmony_ci		code = ABS_Y;
1808a46c0ec8Sopenharmony_ci		if (!libevdev_has_event_code(d->evdev, EV_ABS, code))
1809a46c0ec8Sopenharmony_ci			code = ABS_MT_POSITION_Y;
1810a46c0ec8Sopenharmony_ci		if (libevdev_has_event_code(d->evdev, EV_ABS, code)) {
1811a46c0ec8Sopenharmony_ci			d->interface->min[ABS_Y] = libevdev_get_abs_minimum(d->evdev, code);
1812a46c0ec8Sopenharmony_ci			d->interface->max[ABS_Y] = libevdev_get_abs_maximum(d->evdev, code);
1813a46c0ec8Sopenharmony_ci		}
1814a46c0ec8Sopenharmony_ci		d->interface->tool_type = BTN_TOOL_PEN;
1815a46c0ec8Sopenharmony_ci	}
1816a46c0ec8Sopenharmony_ci	return d;
1817a46c0ec8Sopenharmony_ci}
1818a46c0ec8Sopenharmony_ci
1819a46c0ec8Sopenharmony_cistruct litest_device *
1820a46c0ec8Sopenharmony_cilitest_add_device(struct libinput *libinput,
1821a46c0ec8Sopenharmony_ci		  enum litest_device_type which)
1822a46c0ec8Sopenharmony_ci{
1823a46c0ec8Sopenharmony_ci	return litest_add_device_with_overrides(libinput,
1824a46c0ec8Sopenharmony_ci						which,
1825a46c0ec8Sopenharmony_ci						NULL,
1826a46c0ec8Sopenharmony_ci						NULL,
1827a46c0ec8Sopenharmony_ci						NULL,
1828a46c0ec8Sopenharmony_ci						NULL);
1829a46c0ec8Sopenharmony_ci}
1830a46c0ec8Sopenharmony_ci
1831a46c0ec8Sopenharmony_cistruct litest_device *
1832a46c0ec8Sopenharmony_cilitest_create_device_with_overrides(enum litest_device_type which,
1833a46c0ec8Sopenharmony_ci				    const char *name_override,
1834a46c0ec8Sopenharmony_ci				    struct input_id *id_override,
1835a46c0ec8Sopenharmony_ci				    const struct input_absinfo *abs_override,
1836a46c0ec8Sopenharmony_ci				    const int *events_override)
1837a46c0ec8Sopenharmony_ci{
1838a46c0ec8Sopenharmony_ci	struct litest_device *dev =
1839a46c0ec8Sopenharmony_ci		litest_add_device_with_overrides(litest_create_context(),
1840a46c0ec8Sopenharmony_ci						 which,
1841a46c0ec8Sopenharmony_ci						 name_override,
1842a46c0ec8Sopenharmony_ci						 id_override,
1843a46c0ec8Sopenharmony_ci						 abs_override,
1844a46c0ec8Sopenharmony_ci						 events_override);
1845a46c0ec8Sopenharmony_ci	dev->owns_context = true;
1846a46c0ec8Sopenharmony_ci	return dev;
1847a46c0ec8Sopenharmony_ci}
1848a46c0ec8Sopenharmony_ci
1849a46c0ec8Sopenharmony_cistruct litest_device *
1850a46c0ec8Sopenharmony_cilitest_create_device(enum litest_device_type which)
1851a46c0ec8Sopenharmony_ci{
1852a46c0ec8Sopenharmony_ci	return litest_create_device_with_overrides(which, NULL, NULL, NULL, NULL);
1853a46c0ec8Sopenharmony_ci}
1854a46c0ec8Sopenharmony_ci
1855a46c0ec8Sopenharmony_cistatic struct udev_monitor *
1856a46c0ec8Sopenharmony_ciudev_setup_monitor(void)
1857a46c0ec8Sopenharmony_ci{
1858a46c0ec8Sopenharmony_ci	struct udev *udev;
1859a46c0ec8Sopenharmony_ci	struct udev_monitor *udev_monitor;
1860a46c0ec8Sopenharmony_ci	int rc;
1861a46c0ec8Sopenharmony_ci
1862a46c0ec8Sopenharmony_ci	udev = udev_new();
1863a46c0ec8Sopenharmony_ci	litest_assert_notnull(udev);
1864a46c0ec8Sopenharmony_ci	udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
1865a46c0ec8Sopenharmony_ci	litest_assert_notnull(udev_monitor);
1866a46c0ec8Sopenharmony_ci	udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "input",
1867a46c0ec8Sopenharmony_ci							NULL);
1868a46c0ec8Sopenharmony_ci
1869a46c0ec8Sopenharmony_ci
1870a46c0ec8Sopenharmony_ci	/* remove O_NONBLOCK */
1871a46c0ec8Sopenharmony_ci	rc = fcntl(udev_monitor_get_fd(udev_monitor), F_SETFL, 0);
1872a46c0ec8Sopenharmony_ci	litest_assert_int_ne(rc, -1);
1873a46c0ec8Sopenharmony_ci	litest_assert_int_eq(udev_monitor_enable_receiving(udev_monitor),
1874a46c0ec8Sopenharmony_ci			     0);
1875a46c0ec8Sopenharmony_ci	udev_unref(udev);
1876a46c0ec8Sopenharmony_ci
1877a46c0ec8Sopenharmony_ci	return udev_monitor;
1878a46c0ec8Sopenharmony_ci}
1879a46c0ec8Sopenharmony_ci
1880a46c0ec8Sopenharmony_cistatic struct udev_device *
1881a46c0ec8Sopenharmony_ciudev_wait_for_device_event(struct udev_monitor *udev_monitor,
1882a46c0ec8Sopenharmony_ci			   const char *udev_event,
1883a46c0ec8Sopenharmony_ci			   const char *syspath)
1884a46c0ec8Sopenharmony_ci{
1885a46c0ec8Sopenharmony_ci	struct udev_device *udev_device = NULL;
1886a46c0ec8Sopenharmony_ci
1887a46c0ec8Sopenharmony_ci	/* blocking, we don't want to continue until udev is ready */
1888a46c0ec8Sopenharmony_ci	while (1) {
1889a46c0ec8Sopenharmony_ci		const char *udev_syspath = NULL;
1890a46c0ec8Sopenharmony_ci		const char *udev_action;
1891a46c0ec8Sopenharmony_ci
1892a46c0ec8Sopenharmony_ci		udev_device = udev_monitor_receive_device(udev_monitor);
1893a46c0ec8Sopenharmony_ci		litest_assert_notnull(udev_device);
1894a46c0ec8Sopenharmony_ci		udev_action = udev_device_get_action(udev_device);
1895a46c0ec8Sopenharmony_ci		if (!udev_action || !streq(udev_action, udev_event)) {
1896a46c0ec8Sopenharmony_ci			udev_device_unref(udev_device);
1897a46c0ec8Sopenharmony_ci			continue;
1898a46c0ec8Sopenharmony_ci		}
1899a46c0ec8Sopenharmony_ci
1900a46c0ec8Sopenharmony_ci		udev_syspath = udev_device_get_syspath(udev_device);
1901a46c0ec8Sopenharmony_ci		if (udev_syspath && strstartswith(udev_syspath, syspath))
1902a46c0ec8Sopenharmony_ci			break;
1903a46c0ec8Sopenharmony_ci
1904a46c0ec8Sopenharmony_ci		udev_device_unref(udev_device);
1905a46c0ec8Sopenharmony_ci	}
1906a46c0ec8Sopenharmony_ci
1907a46c0ec8Sopenharmony_ci	return udev_device;
1908a46c0ec8Sopenharmony_ci}
1909a46c0ec8Sopenharmony_ci
1910a46c0ec8Sopenharmony_civoid
1911a46c0ec8Sopenharmony_cilitest_delete_device(struct litest_device *d)
1912a46c0ec8Sopenharmony_ci{
1913a46c0ec8Sopenharmony_ci
1914a46c0ec8Sopenharmony_ci	struct udev_monitor *udev_monitor;
1915a46c0ec8Sopenharmony_ci	struct udev_device *udev_device;
1916a46c0ec8Sopenharmony_ci	char path[PATH_MAX];
1917a46c0ec8Sopenharmony_ci
1918a46c0ec8Sopenharmony_ci	if (!d)
1919a46c0ec8Sopenharmony_ci		return;
1920a46c0ec8Sopenharmony_ci
1921a46c0ec8Sopenharmony_ci	udev_monitor = udev_setup_monitor();
1922a46c0ec8Sopenharmony_ci	snprintf(path, sizeof(path),
1923a46c0ec8Sopenharmony_ci		 "%s/event",
1924a46c0ec8Sopenharmony_ci		 libevdev_uinput_get_syspath(d->uinput));
1925a46c0ec8Sopenharmony_ci
1926a46c0ec8Sopenharmony_ci	litest_assert_int_eq(d->skip_ev_syn, 0);
1927a46c0ec8Sopenharmony_ci
1928a46c0ec8Sopenharmony_ci	quirks_unref(d->quirks);
1929a46c0ec8Sopenharmony_ci
1930a46c0ec8Sopenharmony_ci	if (d->libinput_device) {
1931a46c0ec8Sopenharmony_ci		libinput_path_remove_device(d->libinput_device);
1932a46c0ec8Sopenharmony_ci		libinput_device_unref(d->libinput_device);
1933a46c0ec8Sopenharmony_ci	}
1934a46c0ec8Sopenharmony_ci	if (d->owns_context) {
1935a46c0ec8Sopenharmony_ci		libinput_dispatch(d->libinput);
1936a46c0ec8Sopenharmony_ci		litest_destroy_context(d->libinput);
1937a46c0ec8Sopenharmony_ci	}
1938a46c0ec8Sopenharmony_ci	close(libevdev_get_fd(d->evdev));
1939a46c0ec8Sopenharmony_ci	libevdev_free(d->evdev);
1940a46c0ec8Sopenharmony_ci	libevdev_uinput_destroy(d->uinput);
1941a46c0ec8Sopenharmony_ci	free(d->private);
1942a46c0ec8Sopenharmony_ci	memset(d,0, sizeof(*d));
1943a46c0ec8Sopenharmony_ci	free(d);
1944a46c0ec8Sopenharmony_ci
1945a46c0ec8Sopenharmony_ci	udev_device = udev_wait_for_device_event(udev_monitor,
1946a46c0ec8Sopenharmony_ci						 "remove",
1947a46c0ec8Sopenharmony_ci						 path);
1948a46c0ec8Sopenharmony_ci	udev_device_unref(udev_device);
1949a46c0ec8Sopenharmony_ci	udev_monitor_unref(udev_monitor);
1950a46c0ec8Sopenharmony_ci}
1951a46c0ec8Sopenharmony_ci
1952a46c0ec8Sopenharmony_civoid
1953a46c0ec8Sopenharmony_cilitest_event(struct litest_device *d, unsigned int type,
1954a46c0ec8Sopenharmony_ci	     unsigned int code, int value)
1955a46c0ec8Sopenharmony_ci{
1956a46c0ec8Sopenharmony_ci	int ret;
1957a46c0ec8Sopenharmony_ci
1958a46c0ec8Sopenharmony_ci	if (!libevdev_has_event_code(d->evdev, type, code))
1959a46c0ec8Sopenharmony_ci		return;
1960a46c0ec8Sopenharmony_ci
1961a46c0ec8Sopenharmony_ci	if (d->skip_ev_syn && type == EV_SYN && code == SYN_REPORT)
1962a46c0ec8Sopenharmony_ci		return;
1963a46c0ec8Sopenharmony_ci
1964a46c0ec8Sopenharmony_ci	ret = libevdev_uinput_write_event(d->uinput, type, code, value);
1965a46c0ec8Sopenharmony_ci	litest_assert_int_eq(ret, 0);
1966a46c0ec8Sopenharmony_ci}
1967a46c0ec8Sopenharmony_ci
1968a46c0ec8Sopenharmony_cistatic bool
1969a46c0ec8Sopenharmony_ciaxis_replacement_value(struct litest_device *d,
1970a46c0ec8Sopenharmony_ci		       struct axis_replacement *axes,
1971a46c0ec8Sopenharmony_ci		       int32_t evcode,
1972a46c0ec8Sopenharmony_ci		       int32_t *value)
1973a46c0ec8Sopenharmony_ci{
1974a46c0ec8Sopenharmony_ci	struct axis_replacement *axis = axes;
1975a46c0ec8Sopenharmony_ci
1976a46c0ec8Sopenharmony_ci	if (!axes)
1977a46c0ec8Sopenharmony_ci		return false;
1978a46c0ec8Sopenharmony_ci
1979a46c0ec8Sopenharmony_ci	while (axis->evcode != -1) {
1980a46c0ec8Sopenharmony_ci		if (axis->evcode == evcode) {
1981a46c0ec8Sopenharmony_ci			switch (evcode) {
1982a46c0ec8Sopenharmony_ci			case ABS_MT_SLOT:
1983a46c0ec8Sopenharmony_ci			case ABS_MT_TRACKING_ID:
1984a46c0ec8Sopenharmony_ci			case ABS_MT_TOOL_TYPE:
1985a46c0ec8Sopenharmony_ci				*value = axis->value;
1986a46c0ec8Sopenharmony_ci				break;
1987a46c0ec8Sopenharmony_ci			default:
1988a46c0ec8Sopenharmony_ci				*value = litest_scale(d, evcode, axis->value);
1989a46c0ec8Sopenharmony_ci				break;
1990a46c0ec8Sopenharmony_ci			}
1991a46c0ec8Sopenharmony_ci			return true;
1992a46c0ec8Sopenharmony_ci		}
1993a46c0ec8Sopenharmony_ci		axis++;
1994a46c0ec8Sopenharmony_ci	}
1995a46c0ec8Sopenharmony_ci
1996a46c0ec8Sopenharmony_ci	return false;
1997a46c0ec8Sopenharmony_ci}
1998a46c0ec8Sopenharmony_ci
1999a46c0ec8Sopenharmony_ciint
2000a46c0ec8Sopenharmony_cilitest_auto_assign_value(struct litest_device *d,
2001a46c0ec8Sopenharmony_ci			 const struct input_event *ev,
2002a46c0ec8Sopenharmony_ci			 int slot, double x, double y,
2003a46c0ec8Sopenharmony_ci			 struct axis_replacement *axes,
2004a46c0ec8Sopenharmony_ci			 bool touching)
2005a46c0ec8Sopenharmony_ci{
2006a46c0ec8Sopenharmony_ci	static int tracking_id;
2007a46c0ec8Sopenharmony_ci	int value = ev->value;
2008a46c0ec8Sopenharmony_ci
2009a46c0ec8Sopenharmony_ci	if (value != LITEST_AUTO_ASSIGN || ev->type != EV_ABS)
2010a46c0ec8Sopenharmony_ci		return value;
2011a46c0ec8Sopenharmony_ci
2012a46c0ec8Sopenharmony_ci	switch (ev->code) {
2013a46c0ec8Sopenharmony_ci	case ABS_X:
2014a46c0ec8Sopenharmony_ci	case ABS_MT_POSITION_X:
2015a46c0ec8Sopenharmony_ci		value = litest_scale(d, ABS_X, x);
2016a46c0ec8Sopenharmony_ci		break;
2017a46c0ec8Sopenharmony_ci	case ABS_Y:
2018a46c0ec8Sopenharmony_ci	case ABS_MT_POSITION_Y:
2019a46c0ec8Sopenharmony_ci		value = litest_scale(d, ABS_Y, y);
2020a46c0ec8Sopenharmony_ci		break;
2021a46c0ec8Sopenharmony_ci	case ABS_MT_TRACKING_ID:
2022a46c0ec8Sopenharmony_ci		value = ++tracking_id;
2023a46c0ec8Sopenharmony_ci		break;
2024a46c0ec8Sopenharmony_ci	case ABS_MT_SLOT:
2025a46c0ec8Sopenharmony_ci		value = slot;
2026a46c0ec8Sopenharmony_ci		break;
2027a46c0ec8Sopenharmony_ci	case ABS_MT_DISTANCE:
2028a46c0ec8Sopenharmony_ci		value = touching ? 0 : 1;
2029a46c0ec8Sopenharmony_ci		break;
2030a46c0ec8Sopenharmony_ci	case ABS_MT_TOOL_TYPE:
2031a46c0ec8Sopenharmony_ci		if (!axis_replacement_value(d, axes, ev->code, &value))
2032a46c0ec8Sopenharmony_ci			value = MT_TOOL_FINGER;
2033a46c0ec8Sopenharmony_ci		break;
2034a46c0ec8Sopenharmony_ci	default:
2035a46c0ec8Sopenharmony_ci		if (!axis_replacement_value(d, axes, ev->code, &value) &&
2036a46c0ec8Sopenharmony_ci		    d->interface->get_axis_default) {
2037a46c0ec8Sopenharmony_ci			int error = d->interface->get_axis_default(d,
2038a46c0ec8Sopenharmony_ci								   ev->code,
2039a46c0ec8Sopenharmony_ci								   &value);
2040a46c0ec8Sopenharmony_ci			if (error) {
2041a46c0ec8Sopenharmony_ci				litest_abort_msg("Failed to get default axis value for %s (%d)\n",
2042a46c0ec8Sopenharmony_ci						 libevdev_event_code_get_name(EV_ABS, ev->code),
2043a46c0ec8Sopenharmony_ci						 ev->code);
2044a46c0ec8Sopenharmony_ci			}
2045a46c0ec8Sopenharmony_ci		}
2046a46c0ec8Sopenharmony_ci		break;
2047a46c0ec8Sopenharmony_ci	}
2048a46c0ec8Sopenharmony_ci
2049a46c0ec8Sopenharmony_ci	return value;
2050a46c0ec8Sopenharmony_ci}
2051a46c0ec8Sopenharmony_ci
2052a46c0ec8Sopenharmony_cistatic void
2053a46c0ec8Sopenharmony_cisend_btntool(struct litest_device *d, bool hover)
2054a46c0ec8Sopenharmony_ci{
2055a46c0ec8Sopenharmony_ci	litest_event(d, EV_KEY, BTN_TOUCH, d->ntouches_down != 0 && !hover);
2056a46c0ec8Sopenharmony_ci	litest_event(d, EV_KEY, BTN_TOOL_FINGER, d->ntouches_down == 1);
2057a46c0ec8Sopenharmony_ci	litest_event(d, EV_KEY, BTN_TOOL_DOUBLETAP, d->ntouches_down == 2);
2058a46c0ec8Sopenharmony_ci	litest_event(d, EV_KEY, BTN_TOOL_TRIPLETAP, d->ntouches_down == 3);
2059a46c0ec8Sopenharmony_ci	litest_event(d, EV_KEY, BTN_TOOL_QUADTAP, d->ntouches_down == 4);
2060a46c0ec8Sopenharmony_ci	litest_event(d, EV_KEY, BTN_TOOL_QUINTTAP, d->ntouches_down == 5);
2061a46c0ec8Sopenharmony_ci}
2062a46c0ec8Sopenharmony_ci
2063a46c0ec8Sopenharmony_cistatic void
2064a46c0ec8Sopenharmony_cislot_start(struct litest_device *d,
2065a46c0ec8Sopenharmony_ci	   unsigned int slot,
2066a46c0ec8Sopenharmony_ci	   double x,
2067a46c0ec8Sopenharmony_ci	   double y,
2068a46c0ec8Sopenharmony_ci	   struct axis_replacement *axes,
2069a46c0ec8Sopenharmony_ci	   bool touching,
2070a46c0ec8Sopenharmony_ci	   bool filter_abs_xy)
2071a46c0ec8Sopenharmony_ci{
2072a46c0ec8Sopenharmony_ci	struct input_event *ev;
2073a46c0ec8Sopenharmony_ci
2074a46c0ec8Sopenharmony_ci	litest_assert_int_ge(d->ntouches_down, 0);
2075a46c0ec8Sopenharmony_ci	d->ntouches_down++;
2076a46c0ec8Sopenharmony_ci
2077a46c0ec8Sopenharmony_ci	send_btntool(d, !touching);
2078a46c0ec8Sopenharmony_ci
2079a46c0ec8Sopenharmony_ci	/* If the test device overrides touch_down and says it didn't
2080a46c0ec8Sopenharmony_ci	 * handle the event, let's continue normally */
2081a46c0ec8Sopenharmony_ci	if (d->interface->touch_down &&
2082a46c0ec8Sopenharmony_ci	    d->interface->touch_down(d, slot, x, y))
2083a46c0ec8Sopenharmony_ci	    return;
2084a46c0ec8Sopenharmony_ci
2085a46c0ec8Sopenharmony_ci	for (ev = d->interface->touch_down_events;
2086a46c0ec8Sopenharmony_ci	     ev && (int16_t)ev->type != -1 && (int16_t)ev->code != -1;
2087a46c0ec8Sopenharmony_ci	     ev++) {
2088a46c0ec8Sopenharmony_ci		int value = litest_auto_assign_value(d,
2089a46c0ec8Sopenharmony_ci						     ev,
2090a46c0ec8Sopenharmony_ci						     slot,
2091a46c0ec8Sopenharmony_ci						     x,
2092a46c0ec8Sopenharmony_ci						     y,
2093a46c0ec8Sopenharmony_ci						     axes,
2094a46c0ec8Sopenharmony_ci						     touching);
2095a46c0ec8Sopenharmony_ci		if (value == LITEST_AUTO_ASSIGN)
2096a46c0ec8Sopenharmony_ci			continue;
2097a46c0ec8Sopenharmony_ci
2098a46c0ec8Sopenharmony_ci		if (filter_abs_xy && ev->type == EV_ABS &&
2099a46c0ec8Sopenharmony_ci		    (ev->code == ABS_X || ev->code == ABS_Y))
2100a46c0ec8Sopenharmony_ci			continue;
2101a46c0ec8Sopenharmony_ci
2102a46c0ec8Sopenharmony_ci		litest_event(d, ev->type, ev->code, value);
2103a46c0ec8Sopenharmony_ci	}
2104a46c0ec8Sopenharmony_ci}
2105a46c0ec8Sopenharmony_ci
2106a46c0ec8Sopenharmony_cistatic void
2107a46c0ec8Sopenharmony_cislot_move(struct litest_device *d,
2108a46c0ec8Sopenharmony_ci	  unsigned int slot,
2109a46c0ec8Sopenharmony_ci	  double x,
2110a46c0ec8Sopenharmony_ci	  double y,
2111a46c0ec8Sopenharmony_ci	  struct axis_replacement *axes,
2112a46c0ec8Sopenharmony_ci	  bool touching,
2113a46c0ec8Sopenharmony_ci	  bool filter_abs_xy)
2114a46c0ec8Sopenharmony_ci{
2115a46c0ec8Sopenharmony_ci	struct input_event *ev;
2116a46c0ec8Sopenharmony_ci
2117a46c0ec8Sopenharmony_ci	if (d->interface->touch_move &&
2118a46c0ec8Sopenharmony_ci	    d->interface->touch_move(d, slot, x, y))
2119a46c0ec8Sopenharmony_ci		return;
2120a46c0ec8Sopenharmony_ci
2121a46c0ec8Sopenharmony_ci	for (ev = d->interface->touch_move_events;
2122a46c0ec8Sopenharmony_ci	     ev && (int16_t)ev->type != -1 && (int16_t)ev->code != -1;
2123a46c0ec8Sopenharmony_ci	     ev++) {
2124a46c0ec8Sopenharmony_ci		int value = litest_auto_assign_value(d,
2125a46c0ec8Sopenharmony_ci						     ev,
2126a46c0ec8Sopenharmony_ci						     slot,
2127a46c0ec8Sopenharmony_ci						     x,
2128a46c0ec8Sopenharmony_ci						     y,
2129a46c0ec8Sopenharmony_ci						     axes,
2130a46c0ec8Sopenharmony_ci						     touching);
2131a46c0ec8Sopenharmony_ci		if (value == LITEST_AUTO_ASSIGN)
2132a46c0ec8Sopenharmony_ci			continue;
2133a46c0ec8Sopenharmony_ci
2134a46c0ec8Sopenharmony_ci		if (filter_abs_xy && ev->type == EV_ABS &&
2135a46c0ec8Sopenharmony_ci		    (ev->code == ABS_X || ev->code == ABS_Y))
2136a46c0ec8Sopenharmony_ci			continue;
2137a46c0ec8Sopenharmony_ci
2138a46c0ec8Sopenharmony_ci		litest_event(d, ev->type, ev->code, value);
2139a46c0ec8Sopenharmony_ci	}
2140a46c0ec8Sopenharmony_ci}
2141a46c0ec8Sopenharmony_ci
2142a46c0ec8Sopenharmony_cistatic void
2143a46c0ec8Sopenharmony_citouch_up(struct litest_device *d, unsigned int slot)
2144a46c0ec8Sopenharmony_ci{
2145a46c0ec8Sopenharmony_ci	struct input_event *ev;
2146a46c0ec8Sopenharmony_ci	struct input_event up[] = {
2147a46c0ec8Sopenharmony_ci		{ .type = EV_ABS, .code = ABS_MT_SLOT, .value = LITEST_AUTO_ASSIGN },
2148a46c0ec8Sopenharmony_ci		{ .type = EV_ABS, .code = ABS_MT_TRACKING_ID, .value = -1 },
2149a46c0ec8Sopenharmony_ci		{ .type = EV_ABS, .code = ABS_MT_PRESSURE, .value = 0 },
2150a46c0ec8Sopenharmony_ci		{ .type = EV_ABS, .code = ABS_MT_TOUCH_MAJOR, .value = 0 },
2151a46c0ec8Sopenharmony_ci		{ .type = EV_ABS, .code = ABS_MT_TOUCH_MINOR, .value = 0 },
2152a46c0ec8Sopenharmony_ci		{ .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
2153a46c0ec8Sopenharmony_ci		{ .type = -1, .code = -1 }
2154a46c0ec8Sopenharmony_ci	};
2155a46c0ec8Sopenharmony_ci
2156a46c0ec8Sopenharmony_ci	litest_assert_int_gt(d->ntouches_down, 0);
2157a46c0ec8Sopenharmony_ci	d->ntouches_down--;
2158a46c0ec8Sopenharmony_ci
2159a46c0ec8Sopenharmony_ci	send_btntool(d, false);
2160a46c0ec8Sopenharmony_ci
2161a46c0ec8Sopenharmony_ci	if (d->interface->touch_up &&
2162a46c0ec8Sopenharmony_ci	    d->interface->touch_up(d, slot)) {
2163a46c0ec8Sopenharmony_ci		return;
2164a46c0ec8Sopenharmony_ci	} else if (d->interface->touch_up_events) {
2165a46c0ec8Sopenharmony_ci		ev = d->interface->touch_up_events;
2166a46c0ec8Sopenharmony_ci	} else
2167a46c0ec8Sopenharmony_ci		ev = up;
2168a46c0ec8Sopenharmony_ci
2169a46c0ec8Sopenharmony_ci	for ( /* */;
2170a46c0ec8Sopenharmony_ci	     ev && (int16_t)ev->type != -1 && (int16_t)ev->code != -1;
2171a46c0ec8Sopenharmony_ci	     ev++) {
2172a46c0ec8Sopenharmony_ci		int value = litest_auto_assign_value(d,
2173a46c0ec8Sopenharmony_ci						     ev,
2174a46c0ec8Sopenharmony_ci						     slot,
2175a46c0ec8Sopenharmony_ci						     0,
2176a46c0ec8Sopenharmony_ci						     0,
2177a46c0ec8Sopenharmony_ci						     NULL,
2178a46c0ec8Sopenharmony_ci						     false);
2179a46c0ec8Sopenharmony_ci		litest_event(d, ev->type, ev->code, value);
2180a46c0ec8Sopenharmony_ci	}
2181a46c0ec8Sopenharmony_ci}
2182a46c0ec8Sopenharmony_ci
2183a46c0ec8Sopenharmony_cistatic void
2184a46c0ec8Sopenharmony_cilitest_slot_start(struct litest_device *d,
2185a46c0ec8Sopenharmony_ci		  unsigned int slot,
2186a46c0ec8Sopenharmony_ci		  double x,
2187a46c0ec8Sopenharmony_ci		  double y,
2188a46c0ec8Sopenharmony_ci		  struct axis_replacement *axes,
2189a46c0ec8Sopenharmony_ci		  bool touching)
2190a46c0ec8Sopenharmony_ci{
2191a46c0ec8Sopenharmony_ci	double t, l, r = 0, b = 0; /* top, left, right, bottom */
2192a46c0ec8Sopenharmony_ci	bool filter_abs_xy = false;
2193a46c0ec8Sopenharmony_ci
2194a46c0ec8Sopenharmony_ci	if (!d->semi_mt.is_semi_mt) {
2195a46c0ec8Sopenharmony_ci		slot_start(d, slot, x, y, axes, touching, filter_abs_xy);
2196a46c0ec8Sopenharmony_ci		return;
2197a46c0ec8Sopenharmony_ci	}
2198a46c0ec8Sopenharmony_ci
2199a46c0ec8Sopenharmony_ci	if (d->ntouches_down >= 2 || slot > 1)
2200a46c0ec8Sopenharmony_ci		return;
2201a46c0ec8Sopenharmony_ci
2202a46c0ec8Sopenharmony_ci	slot = d->ntouches_down;
2203a46c0ec8Sopenharmony_ci
2204a46c0ec8Sopenharmony_ci	if (d->ntouches_down == 0) {
2205a46c0ec8Sopenharmony_ci		l = x;
2206a46c0ec8Sopenharmony_ci		t = y;
2207a46c0ec8Sopenharmony_ci	} else {
2208a46c0ec8Sopenharmony_ci		int other = (slot + 1) % 2;
2209a46c0ec8Sopenharmony_ci		l = min(x, d->semi_mt.touches[other].x);
2210a46c0ec8Sopenharmony_ci		t = min(y, d->semi_mt.touches[other].y);
2211a46c0ec8Sopenharmony_ci		r = max(x, d->semi_mt.touches[other].x);
2212a46c0ec8Sopenharmony_ci		b = max(y, d->semi_mt.touches[other].y);
2213a46c0ec8Sopenharmony_ci	}
2214a46c0ec8Sopenharmony_ci
2215a46c0ec8Sopenharmony_ci	litest_push_event_frame(d);
2216a46c0ec8Sopenharmony_ci	if (d->ntouches_down == 0)
2217a46c0ec8Sopenharmony_ci		slot_start(d, 0, l, t, axes, touching, filter_abs_xy);
2218a46c0ec8Sopenharmony_ci	else
2219a46c0ec8Sopenharmony_ci		slot_move(d, 0, l, t, axes, touching, filter_abs_xy);
2220a46c0ec8Sopenharmony_ci
2221a46c0ec8Sopenharmony_ci	if (slot == 1) {
2222a46c0ec8Sopenharmony_ci		filter_abs_xy = true;
2223a46c0ec8Sopenharmony_ci		slot_start(d, 1, r, b, axes, touching, filter_abs_xy);
2224a46c0ec8Sopenharmony_ci	}
2225a46c0ec8Sopenharmony_ci
2226a46c0ec8Sopenharmony_ci	litest_pop_event_frame(d);
2227a46c0ec8Sopenharmony_ci
2228a46c0ec8Sopenharmony_ci	d->semi_mt.touches[slot].x = x;
2229a46c0ec8Sopenharmony_ci	d->semi_mt.touches[slot].y = y;
2230a46c0ec8Sopenharmony_ci}
2231a46c0ec8Sopenharmony_ci
2232a46c0ec8Sopenharmony_civoid
2233a46c0ec8Sopenharmony_cilitest_touch_sequence(struct litest_device *d,
2234a46c0ec8Sopenharmony_ci		      unsigned int slot,
2235a46c0ec8Sopenharmony_ci		      double x_from,
2236a46c0ec8Sopenharmony_ci		      double y_from,
2237a46c0ec8Sopenharmony_ci		      double x_to,
2238a46c0ec8Sopenharmony_ci		      double y_to,
2239a46c0ec8Sopenharmony_ci		      int steps)
2240a46c0ec8Sopenharmony_ci{
2241a46c0ec8Sopenharmony_ci	litest_touch_down(d, slot, x_from, y_from);
2242a46c0ec8Sopenharmony_ci	litest_touch_move_to(d, slot,
2243a46c0ec8Sopenharmony_ci			     x_from, y_from,
2244a46c0ec8Sopenharmony_ci			     x_to, y_to,
2245a46c0ec8Sopenharmony_ci			     steps);
2246a46c0ec8Sopenharmony_ci	litest_touch_up(d, slot);
2247a46c0ec8Sopenharmony_ci}
2248a46c0ec8Sopenharmony_ci
2249a46c0ec8Sopenharmony_civoid
2250a46c0ec8Sopenharmony_cilitest_touch_down(struct litest_device *d,
2251a46c0ec8Sopenharmony_ci		  unsigned int slot,
2252a46c0ec8Sopenharmony_ci		  double x,
2253a46c0ec8Sopenharmony_ci		  double y)
2254a46c0ec8Sopenharmony_ci{
2255a46c0ec8Sopenharmony_ci	litest_slot_start(d, slot, x, y, NULL, true);
2256a46c0ec8Sopenharmony_ci}
2257a46c0ec8Sopenharmony_ci
2258a46c0ec8Sopenharmony_civoid
2259a46c0ec8Sopenharmony_cilitest_touch_down_extended(struct litest_device *d,
2260a46c0ec8Sopenharmony_ci			   unsigned int slot,
2261a46c0ec8Sopenharmony_ci			   double x,
2262a46c0ec8Sopenharmony_ci			   double y,
2263a46c0ec8Sopenharmony_ci			   struct axis_replacement *axes)
2264a46c0ec8Sopenharmony_ci{
2265a46c0ec8Sopenharmony_ci	litest_slot_start(d, slot, x, y, axes, true);
2266a46c0ec8Sopenharmony_ci}
2267a46c0ec8Sopenharmony_ci
2268a46c0ec8Sopenharmony_cistatic void
2269a46c0ec8Sopenharmony_cilitest_slot_move(struct litest_device *d,
2270a46c0ec8Sopenharmony_ci		 unsigned int slot,
2271a46c0ec8Sopenharmony_ci		 double x,
2272a46c0ec8Sopenharmony_ci		 double y,
2273a46c0ec8Sopenharmony_ci		 struct axis_replacement *axes,
2274a46c0ec8Sopenharmony_ci		 bool touching)
2275a46c0ec8Sopenharmony_ci{
2276a46c0ec8Sopenharmony_ci	double t, l, r = 0, b = 0; /* top, left, right, bottom */
2277a46c0ec8Sopenharmony_ci	bool filter_abs_xy = false;
2278a46c0ec8Sopenharmony_ci
2279a46c0ec8Sopenharmony_ci	if (!d->semi_mt.is_semi_mt) {
2280a46c0ec8Sopenharmony_ci		slot_move(d, slot, x, y, axes, touching, filter_abs_xy);
2281a46c0ec8Sopenharmony_ci		return;
2282a46c0ec8Sopenharmony_ci	}
2283a46c0ec8Sopenharmony_ci
2284a46c0ec8Sopenharmony_ci	if (d->ntouches_down > 2 || slot > 1)
2285a46c0ec8Sopenharmony_ci		return;
2286a46c0ec8Sopenharmony_ci
2287a46c0ec8Sopenharmony_ci	if (d->ntouches_down == 1) {
2288a46c0ec8Sopenharmony_ci		l = x;
2289a46c0ec8Sopenharmony_ci		t = y;
2290a46c0ec8Sopenharmony_ci	} else {
2291a46c0ec8Sopenharmony_ci		int other = (slot + 1) % 2;
2292a46c0ec8Sopenharmony_ci		l = min(x, d->semi_mt.touches[other].x);
2293a46c0ec8Sopenharmony_ci		t = min(y, d->semi_mt.touches[other].y);
2294a46c0ec8Sopenharmony_ci		r = max(x, d->semi_mt.touches[other].x);
2295a46c0ec8Sopenharmony_ci		b = max(y, d->semi_mt.touches[other].y);
2296a46c0ec8Sopenharmony_ci	}
2297a46c0ec8Sopenharmony_ci
2298a46c0ec8Sopenharmony_ci	litest_push_event_frame(d);
2299a46c0ec8Sopenharmony_ci	slot_move(d, 0, l, t, axes, touching, filter_abs_xy);
2300a46c0ec8Sopenharmony_ci
2301a46c0ec8Sopenharmony_ci	if (d->ntouches_down == 2) {
2302a46c0ec8Sopenharmony_ci		filter_abs_xy = true;
2303a46c0ec8Sopenharmony_ci		slot_move(d, 1, r, b, axes, touching, filter_abs_xy);
2304a46c0ec8Sopenharmony_ci	}
2305a46c0ec8Sopenharmony_ci
2306a46c0ec8Sopenharmony_ci	litest_pop_event_frame(d);
2307a46c0ec8Sopenharmony_ci
2308a46c0ec8Sopenharmony_ci	d->semi_mt.touches[slot].x = x;
2309a46c0ec8Sopenharmony_ci	d->semi_mt.touches[slot].y = y;
2310a46c0ec8Sopenharmony_ci}
2311a46c0ec8Sopenharmony_ci
2312a46c0ec8Sopenharmony_civoid
2313a46c0ec8Sopenharmony_cilitest_touch_up(struct litest_device *d, unsigned int slot)
2314a46c0ec8Sopenharmony_ci{
2315a46c0ec8Sopenharmony_ci	if (!d->semi_mt.is_semi_mt) {
2316a46c0ec8Sopenharmony_ci		touch_up(d, slot);
2317a46c0ec8Sopenharmony_ci		return;
2318a46c0ec8Sopenharmony_ci	}
2319a46c0ec8Sopenharmony_ci
2320a46c0ec8Sopenharmony_ci	if (d->ntouches_down > 2 || slot > 1)
2321a46c0ec8Sopenharmony_ci		return;
2322a46c0ec8Sopenharmony_ci
2323a46c0ec8Sopenharmony_ci	litest_push_event_frame(d);
2324a46c0ec8Sopenharmony_ci	touch_up(d, d->ntouches_down - 1);
2325a46c0ec8Sopenharmony_ci
2326a46c0ec8Sopenharmony_ci	/* if we have one finger left, send x/y coords for that finger left.
2327a46c0ec8Sopenharmony_ci	   this is likely to happen with a real touchpad */
2328a46c0ec8Sopenharmony_ci	if (d->ntouches_down == 1) {
2329a46c0ec8Sopenharmony_ci		bool touching = true;
2330a46c0ec8Sopenharmony_ci		bool filter_abs_xy = false;
2331a46c0ec8Sopenharmony_ci
2332a46c0ec8Sopenharmony_ci		int other = (slot + 1) % 2;
2333a46c0ec8Sopenharmony_ci		slot_move(d,
2334a46c0ec8Sopenharmony_ci			  0,
2335a46c0ec8Sopenharmony_ci			  d->semi_mt.touches[other].x,
2336a46c0ec8Sopenharmony_ci			  d->semi_mt.touches[other].y,
2337a46c0ec8Sopenharmony_ci			  NULL,
2338a46c0ec8Sopenharmony_ci			  touching,
2339a46c0ec8Sopenharmony_ci			  filter_abs_xy);
2340a46c0ec8Sopenharmony_ci	}
2341a46c0ec8Sopenharmony_ci
2342a46c0ec8Sopenharmony_ci	litest_pop_event_frame(d);
2343a46c0ec8Sopenharmony_ci}
2344a46c0ec8Sopenharmony_ci
2345a46c0ec8Sopenharmony_civoid
2346a46c0ec8Sopenharmony_cilitest_touch_move(struct litest_device *d,
2347a46c0ec8Sopenharmony_ci		  unsigned int slot,
2348a46c0ec8Sopenharmony_ci		  double x,
2349a46c0ec8Sopenharmony_ci		  double y)
2350a46c0ec8Sopenharmony_ci{
2351a46c0ec8Sopenharmony_ci	litest_slot_move(d, slot, x, y, NULL, true);
2352a46c0ec8Sopenharmony_ci}
2353a46c0ec8Sopenharmony_ci
2354a46c0ec8Sopenharmony_civoid
2355a46c0ec8Sopenharmony_cilitest_touch_move_extended(struct litest_device *d,
2356a46c0ec8Sopenharmony_ci			   unsigned int slot,
2357a46c0ec8Sopenharmony_ci			   double x,
2358a46c0ec8Sopenharmony_ci			   double y,
2359a46c0ec8Sopenharmony_ci			   struct axis_replacement *axes)
2360a46c0ec8Sopenharmony_ci{
2361a46c0ec8Sopenharmony_ci	litest_slot_move(d, slot, x, y, axes, true);
2362a46c0ec8Sopenharmony_ci}
2363a46c0ec8Sopenharmony_ci
2364a46c0ec8Sopenharmony_civoid
2365a46c0ec8Sopenharmony_cilitest_touch_move_to(struct litest_device *d,
2366a46c0ec8Sopenharmony_ci		     unsigned int slot,
2367a46c0ec8Sopenharmony_ci		     double x_from, double y_from,
2368a46c0ec8Sopenharmony_ci		     double x_to, double y_to,
2369a46c0ec8Sopenharmony_ci		     int steps)
2370a46c0ec8Sopenharmony_ci{
2371a46c0ec8Sopenharmony_ci	litest_touch_move_to_extended(d, slot,
2372a46c0ec8Sopenharmony_ci				      x_from, y_from,
2373a46c0ec8Sopenharmony_ci				      x_to, y_to,
2374a46c0ec8Sopenharmony_ci				      NULL,
2375a46c0ec8Sopenharmony_ci				      steps);
2376a46c0ec8Sopenharmony_ci}
2377a46c0ec8Sopenharmony_ci
2378a46c0ec8Sopenharmony_civoid
2379a46c0ec8Sopenharmony_cilitest_touch_move_to_extended(struct litest_device *d,
2380a46c0ec8Sopenharmony_ci			      unsigned int slot,
2381a46c0ec8Sopenharmony_ci			      double x_from, double y_from,
2382a46c0ec8Sopenharmony_ci			      double x_to, double y_to,
2383a46c0ec8Sopenharmony_ci			      struct axis_replacement *axes,
2384a46c0ec8Sopenharmony_ci			      int steps)
2385a46c0ec8Sopenharmony_ci{
2386a46c0ec8Sopenharmony_ci	int sleep_ms = 10;
2387a46c0ec8Sopenharmony_ci
2388a46c0ec8Sopenharmony_ci	for (int i = 1; i < steps; i++) {
2389a46c0ec8Sopenharmony_ci		litest_touch_move_extended(d, slot,
2390a46c0ec8Sopenharmony_ci					   x_from + (x_to - x_from)/steps * i,
2391a46c0ec8Sopenharmony_ci					   y_from + (y_to - y_from)/steps * i,
2392a46c0ec8Sopenharmony_ci					   axes);
2393a46c0ec8Sopenharmony_ci		libinput_dispatch(d->libinput);
2394a46c0ec8Sopenharmony_ci		msleep(sleep_ms);
2395a46c0ec8Sopenharmony_ci		libinput_dispatch(d->libinput);
2396a46c0ec8Sopenharmony_ci	}
2397a46c0ec8Sopenharmony_ci	litest_touch_move_extended(d, slot, x_to, y_to, axes);
2398a46c0ec8Sopenharmony_ci}
2399a46c0ec8Sopenharmony_ci
2400a46c0ec8Sopenharmony_cistatic int
2401a46c0ec8Sopenharmony_ciauto_assign_tablet_value(struct litest_device *d,
2402a46c0ec8Sopenharmony_ci			 const struct input_event *ev,
2403a46c0ec8Sopenharmony_ci			 int x, int y,
2404a46c0ec8Sopenharmony_ci			 struct axis_replacement *axes)
2405a46c0ec8Sopenharmony_ci{
2406a46c0ec8Sopenharmony_ci	static int tracking_id;
2407a46c0ec8Sopenharmony_ci	int value = ev->value;
2408a46c0ec8Sopenharmony_ci
2409a46c0ec8Sopenharmony_ci	if (value != LITEST_AUTO_ASSIGN || ev->type != EV_ABS)
2410a46c0ec8Sopenharmony_ci		return value;
2411a46c0ec8Sopenharmony_ci
2412a46c0ec8Sopenharmony_ci	switch (ev->code) {
2413a46c0ec8Sopenharmony_ci	case ABS_MT_TRACKING_ID:
2414a46c0ec8Sopenharmony_ci		value = ++tracking_id;
2415a46c0ec8Sopenharmony_ci		break;
2416a46c0ec8Sopenharmony_ci	case ABS_X:
2417a46c0ec8Sopenharmony_ci	case ABS_MT_POSITION_X:
2418a46c0ec8Sopenharmony_ci		value = litest_scale(d, ABS_X, x);
2419a46c0ec8Sopenharmony_ci		break;
2420a46c0ec8Sopenharmony_ci	case ABS_Y:
2421a46c0ec8Sopenharmony_ci	case ABS_MT_POSITION_Y:
2422a46c0ec8Sopenharmony_ci		value = litest_scale(d, ABS_Y, y);
2423a46c0ec8Sopenharmony_ci		break;
2424a46c0ec8Sopenharmony_ci	default:
2425a46c0ec8Sopenharmony_ci		if (!axis_replacement_value(d, axes, ev->code, &value) &&
2426a46c0ec8Sopenharmony_ci		    d->interface->get_axis_default) {
2427a46c0ec8Sopenharmony_ci			int error = d->interface->get_axis_default(d, ev->code, &value);
2428a46c0ec8Sopenharmony_ci			if (error) {
2429a46c0ec8Sopenharmony_ci				litest_abort_msg("Failed to get default axis value for %s (%d)\n",
2430a46c0ec8Sopenharmony_ci						 libevdev_event_code_get_name(EV_ABS, ev->code),
2431a46c0ec8Sopenharmony_ci						 ev->code);
2432a46c0ec8Sopenharmony_ci			}
2433a46c0ec8Sopenharmony_ci		}
2434a46c0ec8Sopenharmony_ci		break;
2435a46c0ec8Sopenharmony_ci	}
2436a46c0ec8Sopenharmony_ci
2437a46c0ec8Sopenharmony_ci	return value;
2438a46c0ec8Sopenharmony_ci}
2439a46c0ec8Sopenharmony_ci
2440a46c0ec8Sopenharmony_cistatic int
2441a46c0ec8Sopenharmony_citablet_ignore_event(const struct input_event *ev, int value)
2442a46c0ec8Sopenharmony_ci{
2443a46c0ec8Sopenharmony_ci	return value == -1 && (ev->code == ABS_PRESSURE || ev->code == ABS_DISTANCE);
2444a46c0ec8Sopenharmony_ci}
2445a46c0ec8Sopenharmony_ci
2446a46c0ec8Sopenharmony_civoid
2447a46c0ec8Sopenharmony_cilitest_tablet_set_tool_type(struct litest_device *d, unsigned int code)
2448a46c0ec8Sopenharmony_ci{
2449a46c0ec8Sopenharmony_ci	switch (code) {
2450a46c0ec8Sopenharmony_ci	case BTN_TOOL_PEN:
2451a46c0ec8Sopenharmony_ci	case BTN_TOOL_RUBBER:
2452a46c0ec8Sopenharmony_ci	case BTN_TOOL_BRUSH:
2453a46c0ec8Sopenharmony_ci	case BTN_TOOL_PENCIL:
2454a46c0ec8Sopenharmony_ci	case BTN_TOOL_AIRBRUSH:
2455a46c0ec8Sopenharmony_ci	case BTN_TOOL_MOUSE:
2456a46c0ec8Sopenharmony_ci	case BTN_TOOL_LENS:
2457a46c0ec8Sopenharmony_ci		break;
2458a46c0ec8Sopenharmony_ci	default:
2459a46c0ec8Sopenharmony_ci		abort();
2460a46c0ec8Sopenharmony_ci	}
2461a46c0ec8Sopenharmony_ci
2462a46c0ec8Sopenharmony_ci	d->interface->tool_type = code;
2463a46c0ec8Sopenharmony_ci}
2464a46c0ec8Sopenharmony_ci
2465a46c0ec8Sopenharmony_cistatic void
2466a46c0ec8Sopenharmony_cilitest_tool_event(struct litest_device *d, int value)
2467a46c0ec8Sopenharmony_ci{
2468a46c0ec8Sopenharmony_ci	unsigned int tool = d->interface->tool_type;
2469a46c0ec8Sopenharmony_ci
2470a46c0ec8Sopenharmony_ci	litest_event(d, EV_KEY, tool, value);
2471a46c0ec8Sopenharmony_ci}
2472a46c0ec8Sopenharmony_ci
2473a46c0ec8Sopenharmony_civoid
2474a46c0ec8Sopenharmony_cilitest_tablet_proximity_in(struct litest_device *d,
2475a46c0ec8Sopenharmony_ci			   double x, double y,
2476a46c0ec8Sopenharmony_ci			   struct axis_replacement *axes)
2477a46c0ec8Sopenharmony_ci{
2478a46c0ec8Sopenharmony_ci	struct input_event *ev;
2479a46c0ec8Sopenharmony_ci
2480a46c0ec8Sopenharmony_ci	/* If the test device overrides proximity_in and says it didn't
2481a46c0ec8Sopenharmony_ci	 * handle the event, let's continue normally */
2482a46c0ec8Sopenharmony_ci	if (d->interface->tablet_proximity_in &&
2483a46c0ec8Sopenharmony_ci	    d->interface->tablet_proximity_in(d, d->interface->tool_type, &x, &y, axes))
2484a46c0ec8Sopenharmony_ci		return;
2485a46c0ec8Sopenharmony_ci
2486a46c0ec8Sopenharmony_ci	ev = d->interface->tablet_proximity_in_events;
2487a46c0ec8Sopenharmony_ci	while (ev && (int16_t)ev->type != -1 && (int16_t)ev->code != -1) {
2488a46c0ec8Sopenharmony_ci		int value;
2489a46c0ec8Sopenharmony_ci
2490a46c0ec8Sopenharmony_ci		switch (evbit(ev->type, ev->code)) {
2491a46c0ec8Sopenharmony_ci		case evbit(EV_KEY, LITEST_BTN_TOOL_AUTO):
2492a46c0ec8Sopenharmony_ci			litest_tool_event(d, ev->value);
2493a46c0ec8Sopenharmony_ci			break;
2494a46c0ec8Sopenharmony_ci		default:
2495a46c0ec8Sopenharmony_ci			value = auto_assign_tablet_value(d, ev, x, y, axes);
2496a46c0ec8Sopenharmony_ci			if (!tablet_ignore_event(ev, value))
2497a46c0ec8Sopenharmony_ci				litest_event(d, ev->type, ev->code, value);
2498a46c0ec8Sopenharmony_ci		}
2499a46c0ec8Sopenharmony_ci		ev++;
2500a46c0ec8Sopenharmony_ci	}
2501a46c0ec8Sopenharmony_ci}
2502a46c0ec8Sopenharmony_ci
2503a46c0ec8Sopenharmony_civoid
2504a46c0ec8Sopenharmony_cilitest_tablet_proximity_out(struct litest_device *d)
2505a46c0ec8Sopenharmony_ci{
2506a46c0ec8Sopenharmony_ci	struct input_event *ev;
2507a46c0ec8Sopenharmony_ci
2508a46c0ec8Sopenharmony_ci	/* If the test device overrides proximity_out and says it didn't
2509a46c0ec8Sopenharmony_ci	 * handle the event, let's continue normally */
2510a46c0ec8Sopenharmony_ci	if (d->interface->tablet_proximity_out &&
2511a46c0ec8Sopenharmony_ci	    d->interface->tablet_proximity_out(d, d->interface->tool_type))
2512a46c0ec8Sopenharmony_ci		return;
2513a46c0ec8Sopenharmony_ci
2514a46c0ec8Sopenharmony_ci	ev = d->interface->tablet_proximity_out_events;
2515a46c0ec8Sopenharmony_ci	while (ev && (int16_t)ev->type != -1 && (int16_t)ev->code != -1) {
2516a46c0ec8Sopenharmony_ci		int value;
2517a46c0ec8Sopenharmony_ci
2518a46c0ec8Sopenharmony_ci		switch (evbit(ev->type, ev->code)) {
2519a46c0ec8Sopenharmony_ci		case evbit(EV_KEY, LITEST_BTN_TOOL_AUTO):
2520a46c0ec8Sopenharmony_ci			litest_tool_event(d, ev->value);
2521a46c0ec8Sopenharmony_ci			break;
2522a46c0ec8Sopenharmony_ci		default:
2523a46c0ec8Sopenharmony_ci			value = auto_assign_tablet_value(d, ev, -1, -1, NULL);
2524a46c0ec8Sopenharmony_ci			if (!tablet_ignore_event(ev, value))
2525a46c0ec8Sopenharmony_ci				litest_event(d, ev->type, ev->code, value);
2526a46c0ec8Sopenharmony_ci			break;
2527a46c0ec8Sopenharmony_ci		}
2528a46c0ec8Sopenharmony_ci		ev++;
2529a46c0ec8Sopenharmony_ci	}
2530a46c0ec8Sopenharmony_ci}
2531a46c0ec8Sopenharmony_ci
2532a46c0ec8Sopenharmony_civoid
2533a46c0ec8Sopenharmony_cilitest_tablet_motion(struct litest_device *d,
2534a46c0ec8Sopenharmony_ci		     double x, double y,
2535a46c0ec8Sopenharmony_ci		     struct axis_replacement *axes)
2536a46c0ec8Sopenharmony_ci{
2537a46c0ec8Sopenharmony_ci	struct input_event *ev;
2538a46c0ec8Sopenharmony_ci
2539a46c0ec8Sopenharmony_ci	/* If the test device overrides proximity_out and says it didn't
2540a46c0ec8Sopenharmony_ci	 * handle the event, let's continue normally */
2541a46c0ec8Sopenharmony_ci	if (d->interface->tablet_motion &&
2542a46c0ec8Sopenharmony_ci	    d->interface->tablet_motion(d, &x, &y, axes))
2543a46c0ec8Sopenharmony_ci		return;
2544a46c0ec8Sopenharmony_ci
2545a46c0ec8Sopenharmony_ci	ev = d->interface->tablet_motion_events;
2546a46c0ec8Sopenharmony_ci	while (ev && (int16_t)ev->type != -1 && (int16_t)ev->code != -1) {
2547a46c0ec8Sopenharmony_ci		int value = auto_assign_tablet_value(d, ev, x, y, axes);
2548a46c0ec8Sopenharmony_ci		if (!tablet_ignore_event(ev, value))
2549a46c0ec8Sopenharmony_ci			litest_event(d, ev->type, ev->code, value);
2550a46c0ec8Sopenharmony_ci		ev++;
2551a46c0ec8Sopenharmony_ci	}
2552a46c0ec8Sopenharmony_ci}
2553a46c0ec8Sopenharmony_ci
2554a46c0ec8Sopenharmony_civoid
2555a46c0ec8Sopenharmony_cilitest_tablet_tip_down(struct litest_device *d,
2556a46c0ec8Sopenharmony_ci		       double x, double y,
2557a46c0ec8Sopenharmony_ci		       struct axis_replacement *axes)
2558a46c0ec8Sopenharmony_ci{
2559a46c0ec8Sopenharmony_ci	/* If the test device overrides tip_down and says it didn't
2560a46c0ec8Sopenharmony_ci	 * handle the event, let's continue normally */
2561a46c0ec8Sopenharmony_ci	if (d->interface->tablet_tip_down &&
2562a46c0ec8Sopenharmony_ci	    d->interface->tablet_tip_down(d, &x, &y, axes))
2563a46c0ec8Sopenharmony_ci		return;
2564a46c0ec8Sopenharmony_ci
2565a46c0ec8Sopenharmony_ci	litest_event(d, EV_KEY, BTN_TOUCH, 1);
2566a46c0ec8Sopenharmony_ci	litest_tablet_motion(d, x, y, axes);
2567a46c0ec8Sopenharmony_ci}
2568a46c0ec8Sopenharmony_ci
2569a46c0ec8Sopenharmony_civoid
2570a46c0ec8Sopenharmony_cilitest_tablet_tip_up(struct litest_device *d,
2571a46c0ec8Sopenharmony_ci		     double x, double y,
2572a46c0ec8Sopenharmony_ci		     struct axis_replacement *axes)
2573a46c0ec8Sopenharmony_ci{
2574a46c0ec8Sopenharmony_ci	/* If the test device overrides tip_down and says it didn't
2575a46c0ec8Sopenharmony_ci	 * handle the event, let's continue normally */
2576a46c0ec8Sopenharmony_ci	if (d->interface->tablet_tip_up &&
2577a46c0ec8Sopenharmony_ci	    d->interface->tablet_tip_up(d, &x, &y, axes))
2578a46c0ec8Sopenharmony_ci		return;
2579a46c0ec8Sopenharmony_ci
2580a46c0ec8Sopenharmony_ci	litest_event(d, EV_KEY, BTN_TOUCH, 0);
2581a46c0ec8Sopenharmony_ci	litest_tablet_motion(d, x, y, axes);
2582a46c0ec8Sopenharmony_ci}
2583a46c0ec8Sopenharmony_ci
2584a46c0ec8Sopenharmony_civoid
2585a46c0ec8Sopenharmony_cilitest_touch_move_two_touches(struct litest_device *d,
2586a46c0ec8Sopenharmony_ci			      double x0, double y0,
2587a46c0ec8Sopenharmony_ci			      double x1, double y1,
2588a46c0ec8Sopenharmony_ci			      double dx, double dy,
2589a46c0ec8Sopenharmony_ci			      int steps)
2590a46c0ec8Sopenharmony_ci{
2591a46c0ec8Sopenharmony_ci	int sleep_ms = 10;
2592a46c0ec8Sopenharmony_ci
2593a46c0ec8Sopenharmony_ci	for (int i = 1; i < steps; i++) {
2594a46c0ec8Sopenharmony_ci		litest_push_event_frame(d);
2595a46c0ec8Sopenharmony_ci		litest_touch_move(d, 0, x0 + dx / steps * i,
2596a46c0ec8Sopenharmony_ci					y0 + dy / steps * i);
2597a46c0ec8Sopenharmony_ci		litest_touch_move(d, 1, x1 + dx / steps * i,
2598a46c0ec8Sopenharmony_ci					y1 + dy / steps * i);
2599a46c0ec8Sopenharmony_ci		litest_pop_event_frame(d);
2600a46c0ec8Sopenharmony_ci		libinput_dispatch(d->libinput);
2601a46c0ec8Sopenharmony_ci		msleep(sleep_ms);
2602a46c0ec8Sopenharmony_ci		libinput_dispatch(d->libinput);
2603a46c0ec8Sopenharmony_ci	}
2604a46c0ec8Sopenharmony_ci	litest_push_event_frame(d);
2605a46c0ec8Sopenharmony_ci	litest_touch_move(d, 0, x0 + dx, y0 + dy);
2606a46c0ec8Sopenharmony_ci	litest_touch_move(d, 1, x1 + dx, y1 + dy);
2607a46c0ec8Sopenharmony_ci	litest_pop_event_frame(d);
2608a46c0ec8Sopenharmony_ci}
2609a46c0ec8Sopenharmony_ci
2610a46c0ec8Sopenharmony_civoid
2611a46c0ec8Sopenharmony_cilitest_touch_move_three_touches(struct litest_device *d,
2612a46c0ec8Sopenharmony_ci				double x0, double y0,
2613a46c0ec8Sopenharmony_ci				double x1, double y1,
2614a46c0ec8Sopenharmony_ci				double x2, double y2,
2615a46c0ec8Sopenharmony_ci				double dx, double dy,
2616a46c0ec8Sopenharmony_ci				int steps)
2617a46c0ec8Sopenharmony_ci{
2618a46c0ec8Sopenharmony_ci	int sleep_ms = 10;
2619a46c0ec8Sopenharmony_ci
2620a46c0ec8Sopenharmony_ci	for (int i = 1; i <= steps; i++) {
2621a46c0ec8Sopenharmony_ci		double step_x = dx / steps * i;
2622a46c0ec8Sopenharmony_ci		double step_y = dy / steps * i;
2623a46c0ec8Sopenharmony_ci
2624a46c0ec8Sopenharmony_ci		litest_push_event_frame(d);
2625a46c0ec8Sopenharmony_ci		litest_touch_move(d, 0, x0 + step_x, y0 + step_y);
2626a46c0ec8Sopenharmony_ci		litest_touch_move(d, 1, x1 + step_x, y1 + step_y);
2627a46c0ec8Sopenharmony_ci		litest_touch_move(d, 2, x2 + step_x, y2 + step_y);
2628a46c0ec8Sopenharmony_ci		litest_pop_event_frame(d);
2629a46c0ec8Sopenharmony_ci
2630a46c0ec8Sopenharmony_ci		libinput_dispatch(d->libinput);
2631a46c0ec8Sopenharmony_ci		msleep(sleep_ms);
2632a46c0ec8Sopenharmony_ci	}
2633a46c0ec8Sopenharmony_ci	libinput_dispatch(d->libinput);
2634a46c0ec8Sopenharmony_ci}
2635a46c0ec8Sopenharmony_ci
2636a46c0ec8Sopenharmony_civoid
2637a46c0ec8Sopenharmony_cilitest_hover_start(struct litest_device *d,
2638a46c0ec8Sopenharmony_ci		   unsigned int slot,
2639a46c0ec8Sopenharmony_ci		   double x,
2640a46c0ec8Sopenharmony_ci		   double y)
2641a46c0ec8Sopenharmony_ci{
2642a46c0ec8Sopenharmony_ci	struct axis_replacement axes[] = {
2643a46c0ec8Sopenharmony_ci		{ABS_MT_PRESSURE, 0 },
2644a46c0ec8Sopenharmony_ci		{ABS_PRESSURE, 0 },
2645a46c0ec8Sopenharmony_ci		{-1, -1 },
2646a46c0ec8Sopenharmony_ci	};
2647a46c0ec8Sopenharmony_ci
2648a46c0ec8Sopenharmony_ci	litest_slot_start(d, slot, x, y, axes, 0);
2649a46c0ec8Sopenharmony_ci}
2650a46c0ec8Sopenharmony_ci
2651a46c0ec8Sopenharmony_civoid
2652a46c0ec8Sopenharmony_cilitest_hover_end(struct litest_device *d, unsigned int slot)
2653a46c0ec8Sopenharmony_ci{
2654a46c0ec8Sopenharmony_ci	struct input_event *ev;
2655a46c0ec8Sopenharmony_ci	struct input_event up[] = {
2656a46c0ec8Sopenharmony_ci		{ .type = EV_ABS, .code = ABS_MT_SLOT, .value = LITEST_AUTO_ASSIGN },
2657a46c0ec8Sopenharmony_ci		{ .type = EV_ABS, .code = ABS_MT_DISTANCE, .value = 1 },
2658a46c0ec8Sopenharmony_ci		{ .type = EV_ABS, .code = ABS_MT_TRACKING_ID, .value = -1 },
2659a46c0ec8Sopenharmony_ci		{ .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
2660a46c0ec8Sopenharmony_ci		{ .type = -1, .code = -1 }
2661a46c0ec8Sopenharmony_ci	};
2662a46c0ec8Sopenharmony_ci
2663a46c0ec8Sopenharmony_ci	litest_assert_int_gt(d->ntouches_down, 0);
2664a46c0ec8Sopenharmony_ci	d->ntouches_down--;
2665a46c0ec8Sopenharmony_ci
2666a46c0ec8Sopenharmony_ci	send_btntool(d, true);
2667a46c0ec8Sopenharmony_ci
2668a46c0ec8Sopenharmony_ci	if (d->interface->touch_up) {
2669a46c0ec8Sopenharmony_ci		d->interface->touch_up(d, slot);
2670a46c0ec8Sopenharmony_ci		return;
2671a46c0ec8Sopenharmony_ci	} else if (d->interface->touch_up_events) {
2672a46c0ec8Sopenharmony_ci		ev = d->interface->touch_up_events;
2673a46c0ec8Sopenharmony_ci	} else
2674a46c0ec8Sopenharmony_ci		ev = up;
2675a46c0ec8Sopenharmony_ci
2676a46c0ec8Sopenharmony_ci	while (ev && (int16_t)ev->type != -1 && (int16_t)ev->code != -1) {
2677a46c0ec8Sopenharmony_ci		int value = litest_auto_assign_value(d, ev, slot, 0, 0, NULL, false);
2678a46c0ec8Sopenharmony_ci		litest_event(d, ev->type, ev->code, value);
2679a46c0ec8Sopenharmony_ci		ev++;
2680a46c0ec8Sopenharmony_ci	}
2681a46c0ec8Sopenharmony_ci}
2682a46c0ec8Sopenharmony_ci
2683a46c0ec8Sopenharmony_civoid
2684a46c0ec8Sopenharmony_cilitest_hover_move(struct litest_device *d, unsigned int slot,
2685a46c0ec8Sopenharmony_ci		  double x, double y)
2686a46c0ec8Sopenharmony_ci{
2687a46c0ec8Sopenharmony_ci	struct axis_replacement axes[] = {
2688a46c0ec8Sopenharmony_ci		{ABS_MT_PRESSURE, 0 },
2689a46c0ec8Sopenharmony_ci		{ABS_PRESSURE, 0 },
2690a46c0ec8Sopenharmony_ci		{-1, -1 },
2691a46c0ec8Sopenharmony_ci	};
2692a46c0ec8Sopenharmony_ci
2693a46c0ec8Sopenharmony_ci	litest_slot_move(d, slot, x, y, axes, false);
2694a46c0ec8Sopenharmony_ci}
2695a46c0ec8Sopenharmony_ci
2696a46c0ec8Sopenharmony_civoid
2697a46c0ec8Sopenharmony_cilitest_hover_move_to(struct litest_device *d,
2698a46c0ec8Sopenharmony_ci		     unsigned int slot,
2699a46c0ec8Sopenharmony_ci		     double x_from, double y_from,
2700a46c0ec8Sopenharmony_ci		     double x_to, double y_to,
2701a46c0ec8Sopenharmony_ci		     int steps)
2702a46c0ec8Sopenharmony_ci{
2703a46c0ec8Sopenharmony_ci	int sleep_ms = 10;
2704a46c0ec8Sopenharmony_ci
2705a46c0ec8Sopenharmony_ci	for (int i = 0; i < steps - 1; i++) {
2706a46c0ec8Sopenharmony_ci		litest_hover_move(d, slot,
2707a46c0ec8Sopenharmony_ci				  x_from + (x_to - x_from)/steps * i,
2708a46c0ec8Sopenharmony_ci				  y_from + (y_to - y_from)/steps * i);
2709a46c0ec8Sopenharmony_ci		libinput_dispatch(d->libinput);
2710a46c0ec8Sopenharmony_ci		msleep(sleep_ms);
2711a46c0ec8Sopenharmony_ci		libinput_dispatch(d->libinput);
2712a46c0ec8Sopenharmony_ci	}
2713a46c0ec8Sopenharmony_ci	litest_hover_move(d, slot, x_to, y_to);
2714a46c0ec8Sopenharmony_ci}
2715a46c0ec8Sopenharmony_ci
2716a46c0ec8Sopenharmony_civoid
2717a46c0ec8Sopenharmony_cilitest_hover_move_two_touches(struct litest_device *d,
2718a46c0ec8Sopenharmony_ci			      double x0, double y0,
2719a46c0ec8Sopenharmony_ci			      double x1, double y1,
2720a46c0ec8Sopenharmony_ci			      double dx, double dy,
2721a46c0ec8Sopenharmony_ci			      int steps)
2722a46c0ec8Sopenharmony_ci{
2723a46c0ec8Sopenharmony_ci	int sleep_ms = 10;
2724a46c0ec8Sopenharmony_ci
2725a46c0ec8Sopenharmony_ci	for (int i = 0; i < steps - 1; i++) {
2726a46c0ec8Sopenharmony_ci		litest_push_event_frame(d);
2727a46c0ec8Sopenharmony_ci		litest_hover_move(d, 0, x0 + dx / steps * i,
2728a46c0ec8Sopenharmony_ci					y0 + dy / steps * i);
2729a46c0ec8Sopenharmony_ci		litest_hover_move(d, 1, x1 + dx / steps * i,
2730a46c0ec8Sopenharmony_ci					y1 + dy / steps * i);
2731a46c0ec8Sopenharmony_ci		litest_pop_event_frame(d);
2732a46c0ec8Sopenharmony_ci		libinput_dispatch(d->libinput);
2733a46c0ec8Sopenharmony_ci		msleep(sleep_ms);
2734a46c0ec8Sopenharmony_ci		libinput_dispatch(d->libinput);
2735a46c0ec8Sopenharmony_ci	}
2736a46c0ec8Sopenharmony_ci	litest_push_event_frame(d);
2737a46c0ec8Sopenharmony_ci	litest_hover_move(d, 0, x0 + dx, y0 + dy);
2738a46c0ec8Sopenharmony_ci	litest_hover_move(d, 1, x1 + dx, y1 + dy);
2739a46c0ec8Sopenharmony_ci	litest_pop_event_frame(d);
2740a46c0ec8Sopenharmony_ci}
2741a46c0ec8Sopenharmony_ci
2742a46c0ec8Sopenharmony_civoid
2743a46c0ec8Sopenharmony_cilitest_button_click(struct litest_device *d,
2744a46c0ec8Sopenharmony_ci		    unsigned int button,
2745a46c0ec8Sopenharmony_ci		    bool is_press)
2746a46c0ec8Sopenharmony_ci{
2747a46c0ec8Sopenharmony_ci	struct input_event click[] = {
2748a46c0ec8Sopenharmony_ci		{ .type = EV_KEY, .code = button, .value = is_press ? 1 : 0 },
2749a46c0ec8Sopenharmony_ci		{ .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
2750a46c0ec8Sopenharmony_ci	};
2751a46c0ec8Sopenharmony_ci
2752a46c0ec8Sopenharmony_ci	ARRAY_FOR_EACH(click, ev)
2753a46c0ec8Sopenharmony_ci		litest_event(d, ev->type, ev->code, ev->value);
2754a46c0ec8Sopenharmony_ci}
2755a46c0ec8Sopenharmony_ci
2756a46c0ec8Sopenharmony_civoid
2757a46c0ec8Sopenharmony_cilitest_button_click_debounced(struct litest_device *d,
2758a46c0ec8Sopenharmony_ci			      struct libinput *li,
2759a46c0ec8Sopenharmony_ci			      unsigned int button,
2760a46c0ec8Sopenharmony_ci			      bool is_press)
2761a46c0ec8Sopenharmony_ci{
2762a46c0ec8Sopenharmony_ci	litest_button_click(d, button, is_press);
2763a46c0ec8Sopenharmony_ci
2764a46c0ec8Sopenharmony_ci	libinput_dispatch(li);
2765a46c0ec8Sopenharmony_ci	litest_timeout_debounce();
2766a46c0ec8Sopenharmony_ci	libinput_dispatch(li);
2767a46c0ec8Sopenharmony_ci}
2768a46c0ec8Sopenharmony_ci
2769a46c0ec8Sopenharmony_civoid
2770a46c0ec8Sopenharmony_cilitest_button_scroll(struct litest_device *dev,
2771a46c0ec8Sopenharmony_ci		     unsigned int button,
2772a46c0ec8Sopenharmony_ci		     double dx, double dy)
2773a46c0ec8Sopenharmony_ci{
2774a46c0ec8Sopenharmony_ci	struct libinput *li = dev->libinput;
2775a46c0ec8Sopenharmony_ci
2776a46c0ec8Sopenharmony_ci	litest_button_click_debounced(dev, li, button, 1);
2777a46c0ec8Sopenharmony_ci
2778a46c0ec8Sopenharmony_ci	libinput_dispatch(li);
2779a46c0ec8Sopenharmony_ci	litest_timeout_buttonscroll();
2780a46c0ec8Sopenharmony_ci	libinput_dispatch(li);
2781a46c0ec8Sopenharmony_ci
2782a46c0ec8Sopenharmony_ci	litest_event(dev, EV_REL, REL_X, dx);
2783a46c0ec8Sopenharmony_ci	litest_event(dev, EV_REL, REL_Y, dy);
2784a46c0ec8Sopenharmony_ci	litest_event(dev, EV_SYN, SYN_REPORT, 0);
2785a46c0ec8Sopenharmony_ci
2786a46c0ec8Sopenharmony_ci	litest_button_click_debounced(dev, li, button, 0);
2787a46c0ec8Sopenharmony_ci
2788a46c0ec8Sopenharmony_ci	libinput_dispatch(li);
2789a46c0ec8Sopenharmony_ci}
2790a46c0ec8Sopenharmony_ci
2791a46c0ec8Sopenharmony_civoid
2792a46c0ec8Sopenharmony_cilitest_button_scroll_locked(struct litest_device *dev,
2793a46c0ec8Sopenharmony_ci			    unsigned int button,
2794a46c0ec8Sopenharmony_ci			    double dx, double dy)
2795a46c0ec8Sopenharmony_ci{
2796a46c0ec8Sopenharmony_ci	struct libinput *li = dev->libinput;
2797a46c0ec8Sopenharmony_ci
2798a46c0ec8Sopenharmony_ci	litest_button_click_debounced(dev, li, button, 1);
2799a46c0ec8Sopenharmony_ci	litest_button_click_debounced(dev, li, button, 0);
2800a46c0ec8Sopenharmony_ci
2801a46c0ec8Sopenharmony_ci	libinput_dispatch(li);
2802a46c0ec8Sopenharmony_ci	litest_timeout_buttonscroll();
2803a46c0ec8Sopenharmony_ci	libinput_dispatch(li);
2804a46c0ec8Sopenharmony_ci
2805a46c0ec8Sopenharmony_ci	litest_event(dev, EV_REL, REL_X, dx);
2806a46c0ec8Sopenharmony_ci	litest_event(dev, EV_REL, REL_Y, dy);
2807a46c0ec8Sopenharmony_ci	litest_event(dev, EV_SYN, SYN_REPORT, 0);
2808a46c0ec8Sopenharmony_ci
2809a46c0ec8Sopenharmony_ci	libinput_dispatch(li);
2810a46c0ec8Sopenharmony_ci}
2811a46c0ec8Sopenharmony_ci
2812a46c0ec8Sopenharmony_civoid
2813a46c0ec8Sopenharmony_cilitest_keyboard_key(struct litest_device *d, unsigned int key, bool is_press)
2814a46c0ec8Sopenharmony_ci{
2815a46c0ec8Sopenharmony_ci	struct input_event click[] = {
2816a46c0ec8Sopenharmony_ci		{ .type = EV_KEY, .code = key, .value = is_press ? 1 : 0 },
2817a46c0ec8Sopenharmony_ci		{ .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
2818a46c0ec8Sopenharmony_ci	};
2819a46c0ec8Sopenharmony_ci
2820a46c0ec8Sopenharmony_ci	ARRAY_FOR_EACH(click, ev)
2821a46c0ec8Sopenharmony_ci		litest_event(d, ev->type, ev->code, ev->value);
2822a46c0ec8Sopenharmony_ci}
2823a46c0ec8Sopenharmony_ci
2824a46c0ec8Sopenharmony_civoid
2825a46c0ec8Sopenharmony_cilitest_switch_action(struct litest_device *dev,
2826a46c0ec8Sopenharmony_ci		     enum libinput_switch sw,
2827a46c0ec8Sopenharmony_ci		     enum libinput_switch_state state)
2828a46c0ec8Sopenharmony_ci{
2829a46c0ec8Sopenharmony_ci	unsigned int code;
2830a46c0ec8Sopenharmony_ci
2831a46c0ec8Sopenharmony_ci	switch (sw) {
2832a46c0ec8Sopenharmony_ci	case LIBINPUT_SWITCH_LID:
2833a46c0ec8Sopenharmony_ci		code = SW_LID;
2834a46c0ec8Sopenharmony_ci		break;
2835a46c0ec8Sopenharmony_ci	case LIBINPUT_SWITCH_TABLET_MODE:
2836a46c0ec8Sopenharmony_ci		code = SW_TABLET_MODE;
2837a46c0ec8Sopenharmony_ci		break;
2838a46c0ec8Sopenharmony_ci	default:
2839a46c0ec8Sopenharmony_ci		litest_abort_msg("Invalid switch %d", sw);
2840a46c0ec8Sopenharmony_ci		break;
2841a46c0ec8Sopenharmony_ci	}
2842a46c0ec8Sopenharmony_ci	litest_event(dev, EV_SW, code, state);
2843a46c0ec8Sopenharmony_ci	litest_event(dev, EV_SYN, SYN_REPORT, 0);
2844a46c0ec8Sopenharmony_ci}
2845a46c0ec8Sopenharmony_ci
2846a46c0ec8Sopenharmony_cistatic int
2847a46c0ec8Sopenharmony_cilitest_scale_axis(const struct litest_device *d,
2848a46c0ec8Sopenharmony_ci		  unsigned int axis,
2849a46c0ec8Sopenharmony_ci		  double val)
2850a46c0ec8Sopenharmony_ci{
2851a46c0ec8Sopenharmony_ci	const struct input_absinfo *abs;
2852a46c0ec8Sopenharmony_ci
2853a46c0ec8Sopenharmony_ci	litest_assert_double_ge(val, 0.0);
2854a46c0ec8Sopenharmony_ci	/* major/minor must be able to beyond 100% for large fingers */
2855a46c0ec8Sopenharmony_ci	if (axis != ABS_MT_TOUCH_MAJOR &&
2856a46c0ec8Sopenharmony_ci	    axis != ABS_MT_TOUCH_MINOR) {
2857a46c0ec8Sopenharmony_ci		litest_assert_double_le(val, 100.0);
2858a46c0ec8Sopenharmony_ci	}
2859a46c0ec8Sopenharmony_ci
2860a46c0ec8Sopenharmony_ci	abs = libevdev_get_abs_info(d->evdev, axis);
2861a46c0ec8Sopenharmony_ci	litest_assert_notnull(abs);
2862a46c0ec8Sopenharmony_ci
2863a46c0ec8Sopenharmony_ci	return (abs->maximum - abs->minimum) * val/100.0 + abs->minimum;
2864a46c0ec8Sopenharmony_ci}
2865a46c0ec8Sopenharmony_ci
2866a46c0ec8Sopenharmony_cistatic inline int
2867a46c0ec8Sopenharmony_cilitest_scale_range(int min, int max, double val)
2868a46c0ec8Sopenharmony_ci{
2869a46c0ec8Sopenharmony_ci	litest_assert_int_ge((int)val, 0);
2870a46c0ec8Sopenharmony_ci	litest_assert_int_le((int)val, 100);
2871a46c0ec8Sopenharmony_ci
2872a46c0ec8Sopenharmony_ci	return (max - min) * val/100.0 + min;
2873a46c0ec8Sopenharmony_ci}
2874a46c0ec8Sopenharmony_ci
2875a46c0ec8Sopenharmony_ciint
2876a46c0ec8Sopenharmony_cilitest_scale(const struct litest_device *d, unsigned int axis, double val)
2877a46c0ec8Sopenharmony_ci{
2878a46c0ec8Sopenharmony_ci	int min, max;
2879a46c0ec8Sopenharmony_ci
2880a46c0ec8Sopenharmony_ci	litest_assert_double_ge(val, 0.0);
2881a46c0ec8Sopenharmony_ci	/* major/minor must be able to beyond 100% for large fingers */
2882a46c0ec8Sopenharmony_ci	if (axis != ABS_MT_TOUCH_MAJOR &&
2883a46c0ec8Sopenharmony_ci	    axis != ABS_MT_TOUCH_MINOR)
2884a46c0ec8Sopenharmony_ci		litest_assert_double_le(val, 100.0);
2885a46c0ec8Sopenharmony_ci
2886a46c0ec8Sopenharmony_ci	if (axis <= ABS_Y) {
2887a46c0ec8Sopenharmony_ci		min = d->interface->min[axis];
2888a46c0ec8Sopenharmony_ci		max = d->interface->max[axis];
2889a46c0ec8Sopenharmony_ci
2890a46c0ec8Sopenharmony_ci		return litest_scale_range(min, max, val);
2891a46c0ec8Sopenharmony_ci	} else {
2892a46c0ec8Sopenharmony_ci		return litest_scale_axis(d, axis, val);
2893a46c0ec8Sopenharmony_ci	}
2894a46c0ec8Sopenharmony_ci}
2895a46c0ec8Sopenharmony_ci
2896a46c0ec8Sopenharmony_cistatic inline int
2897a46c0ec8Sopenharmony_ciauto_assign_pad_value(struct litest_device *dev,
2898a46c0ec8Sopenharmony_ci		      struct input_event *ev,
2899a46c0ec8Sopenharmony_ci		      double value)
2900a46c0ec8Sopenharmony_ci{
2901a46c0ec8Sopenharmony_ci	const struct input_absinfo *abs;
2902a46c0ec8Sopenharmony_ci
2903a46c0ec8Sopenharmony_ci	if (ev->value != LITEST_AUTO_ASSIGN ||
2904a46c0ec8Sopenharmony_ci	    ev->type != EV_ABS)
2905a46c0ec8Sopenharmony_ci		return value;
2906a46c0ec8Sopenharmony_ci
2907a46c0ec8Sopenharmony_ci	abs = libevdev_get_abs_info(dev->evdev, ev->code);
2908a46c0ec8Sopenharmony_ci	litest_assert_notnull(abs);
2909a46c0ec8Sopenharmony_ci
2910a46c0ec8Sopenharmony_ci	if (ev->code == ABS_RX || ev->code == ABS_RY) {
2911a46c0ec8Sopenharmony_ci		double min = abs->minimum != 0 ? log2(abs->minimum) : 0,
2912a46c0ec8Sopenharmony_ci		       max = abs->maximum != 0 ? log2(abs->maximum) : 0;
2913a46c0ec8Sopenharmony_ci
2914a46c0ec8Sopenharmony_ci		/* Value 0 is reserved for finger up, so a value of 0% is
2915a46c0ec8Sopenharmony_ci		 * actually 1 */
2916a46c0ec8Sopenharmony_ci		if (value == 0.0) {
2917a46c0ec8Sopenharmony_ci			return 1;
2918a46c0ec8Sopenharmony_ci		} else {
2919a46c0ec8Sopenharmony_ci			value = litest_scale_range(min, max, value);
2920a46c0ec8Sopenharmony_ci			return pow(2, value);
2921a46c0ec8Sopenharmony_ci		}
2922a46c0ec8Sopenharmony_ci	} else {
2923a46c0ec8Sopenharmony_ci		return litest_scale_range(abs->minimum, abs->maximum, value);
2924a46c0ec8Sopenharmony_ci	}
2925a46c0ec8Sopenharmony_ci}
2926a46c0ec8Sopenharmony_ci
2927a46c0ec8Sopenharmony_civoid
2928a46c0ec8Sopenharmony_cilitest_pad_ring_start(struct litest_device *d, double value)
2929a46c0ec8Sopenharmony_ci{
2930a46c0ec8Sopenharmony_ci	struct input_event *ev;
2931a46c0ec8Sopenharmony_ci
2932a46c0ec8Sopenharmony_ci	ev = d->interface->pad_ring_start_events;
2933a46c0ec8Sopenharmony_ci	while (ev && (int16_t)ev->type != -1 && (int16_t)ev->code != -1) {
2934a46c0ec8Sopenharmony_ci		value = auto_assign_pad_value(d, ev, value);
2935a46c0ec8Sopenharmony_ci		litest_event(d, ev->type, ev->code, value);
2936a46c0ec8Sopenharmony_ci		ev++;
2937a46c0ec8Sopenharmony_ci	}
2938a46c0ec8Sopenharmony_ci}
2939a46c0ec8Sopenharmony_ci
2940a46c0ec8Sopenharmony_civoid
2941a46c0ec8Sopenharmony_cilitest_pad_ring_change(struct litest_device *d, double value)
2942a46c0ec8Sopenharmony_ci{
2943a46c0ec8Sopenharmony_ci	struct input_event *ev;
2944a46c0ec8Sopenharmony_ci
2945a46c0ec8Sopenharmony_ci	ev = d->interface->pad_ring_change_events;
2946a46c0ec8Sopenharmony_ci	while (ev && (int16_t)ev->type != -1 && (int16_t)ev->code != -1) {
2947a46c0ec8Sopenharmony_ci		value = auto_assign_pad_value(d, ev, value);
2948a46c0ec8Sopenharmony_ci		litest_event(d, ev->type, ev->code, value);
2949a46c0ec8Sopenharmony_ci		ev++;
2950a46c0ec8Sopenharmony_ci	}
2951a46c0ec8Sopenharmony_ci}
2952a46c0ec8Sopenharmony_ci
2953a46c0ec8Sopenharmony_civoid
2954a46c0ec8Sopenharmony_cilitest_pad_ring_end(struct litest_device *d)
2955a46c0ec8Sopenharmony_ci{
2956a46c0ec8Sopenharmony_ci	struct input_event *ev;
2957a46c0ec8Sopenharmony_ci
2958a46c0ec8Sopenharmony_ci	ev = d->interface->pad_ring_end_events;
2959a46c0ec8Sopenharmony_ci	while (ev && (int16_t)ev->type != -1 && (int16_t)ev->code != -1) {
2960a46c0ec8Sopenharmony_ci		litest_event(d, ev->type, ev->code, ev->value);
2961a46c0ec8Sopenharmony_ci		ev++;
2962a46c0ec8Sopenharmony_ci	}
2963a46c0ec8Sopenharmony_ci}
2964a46c0ec8Sopenharmony_ci
2965a46c0ec8Sopenharmony_civoid
2966a46c0ec8Sopenharmony_cilitest_pad_strip_start(struct litest_device *d, double value)
2967a46c0ec8Sopenharmony_ci{
2968a46c0ec8Sopenharmony_ci	struct input_event *ev;
2969a46c0ec8Sopenharmony_ci
2970a46c0ec8Sopenharmony_ci	ev = d->interface->pad_strip_start_events;
2971a46c0ec8Sopenharmony_ci	while (ev && (int16_t)ev->type != -1 && (int16_t)ev->code != -1) {
2972a46c0ec8Sopenharmony_ci		value = auto_assign_pad_value(d, ev, value);
2973a46c0ec8Sopenharmony_ci		litest_event(d, ev->type, ev->code, value);
2974a46c0ec8Sopenharmony_ci		ev++;
2975a46c0ec8Sopenharmony_ci	}
2976a46c0ec8Sopenharmony_ci}
2977a46c0ec8Sopenharmony_ci
2978a46c0ec8Sopenharmony_civoid
2979a46c0ec8Sopenharmony_cilitest_pad_strip_change(struct litest_device *d, double value)
2980a46c0ec8Sopenharmony_ci{
2981a46c0ec8Sopenharmony_ci	struct input_event *ev;
2982a46c0ec8Sopenharmony_ci
2983a46c0ec8Sopenharmony_ci	ev = d->interface->pad_strip_change_events;
2984a46c0ec8Sopenharmony_ci	while (ev && (int16_t)ev->type != -1 && (int16_t)ev->code != -1) {
2985a46c0ec8Sopenharmony_ci		value = auto_assign_pad_value(d, ev, value);
2986a46c0ec8Sopenharmony_ci		litest_event(d, ev->type, ev->code, value);
2987a46c0ec8Sopenharmony_ci		ev++;
2988a46c0ec8Sopenharmony_ci	}
2989a46c0ec8Sopenharmony_ci}
2990a46c0ec8Sopenharmony_ci
2991a46c0ec8Sopenharmony_civoid
2992a46c0ec8Sopenharmony_cilitest_pad_strip_end(struct litest_device *d)
2993a46c0ec8Sopenharmony_ci{
2994a46c0ec8Sopenharmony_ci	struct input_event *ev;
2995a46c0ec8Sopenharmony_ci
2996a46c0ec8Sopenharmony_ci	ev = d->interface->pad_strip_end_events;
2997a46c0ec8Sopenharmony_ci	while (ev && (int16_t)ev->type != -1 && (int16_t)ev->code != -1) {
2998a46c0ec8Sopenharmony_ci		litest_event(d, ev->type, ev->code, ev->value);
2999a46c0ec8Sopenharmony_ci		ev++;
3000a46c0ec8Sopenharmony_ci	}
3001a46c0ec8Sopenharmony_ci}
3002a46c0ec8Sopenharmony_ci
3003a46c0ec8Sopenharmony_civoid
3004a46c0ec8Sopenharmony_cilitest_wait_for_event(struct libinput *li)
3005a46c0ec8Sopenharmony_ci{
3006a46c0ec8Sopenharmony_ci	return litest_wait_for_event_of_type(li, -1);
3007a46c0ec8Sopenharmony_ci}
3008a46c0ec8Sopenharmony_ci
3009a46c0ec8Sopenharmony_civoid
3010a46c0ec8Sopenharmony_cilitest_wait_for_event_of_type(struct libinput *li, ...)
3011a46c0ec8Sopenharmony_ci{
3012a46c0ec8Sopenharmony_ci	va_list args;
3013a46c0ec8Sopenharmony_ci	enum libinput_event_type types[32] = {LIBINPUT_EVENT_NONE};
3014a46c0ec8Sopenharmony_ci	size_t ntypes = 0;
3015a46c0ec8Sopenharmony_ci	enum libinput_event_type type;
3016a46c0ec8Sopenharmony_ci	struct pollfd fds;
3017a46c0ec8Sopenharmony_ci
3018a46c0ec8Sopenharmony_ci	va_start(args, li);
3019a46c0ec8Sopenharmony_ci	type = va_arg(args, int);
3020a46c0ec8Sopenharmony_ci	while ((int)type != -1) {
3021a46c0ec8Sopenharmony_ci		litest_assert_int_gt(type, 0U);
3022a46c0ec8Sopenharmony_ci		litest_assert_int_lt(ntypes, ARRAY_LENGTH(types));
3023a46c0ec8Sopenharmony_ci		types[ntypes++] = type;
3024a46c0ec8Sopenharmony_ci		type = va_arg(args, int);
3025a46c0ec8Sopenharmony_ci	}
3026a46c0ec8Sopenharmony_ci	va_end(args);
3027a46c0ec8Sopenharmony_ci
3028a46c0ec8Sopenharmony_ci	fds.fd = libinput_get_fd(li);
3029a46c0ec8Sopenharmony_ci	fds.events = POLLIN;
3030a46c0ec8Sopenharmony_ci	fds.revents = 0;
3031a46c0ec8Sopenharmony_ci
3032a46c0ec8Sopenharmony_ci	while (1) {
3033a46c0ec8Sopenharmony_ci		size_t i;
3034a46c0ec8Sopenharmony_ci		struct libinput_event *event;
3035a46c0ec8Sopenharmony_ci
3036a46c0ec8Sopenharmony_ci		while ((type = libinput_next_event_type(li)) == LIBINPUT_EVENT_NONE) {
3037a46c0ec8Sopenharmony_ci			int rc = poll(&fds, 1, 2000);
3038a46c0ec8Sopenharmony_ci			litest_assert_int_gt(rc, 0);
3039a46c0ec8Sopenharmony_ci			libinput_dispatch(li);
3040a46c0ec8Sopenharmony_ci		}
3041a46c0ec8Sopenharmony_ci
3042a46c0ec8Sopenharmony_ci		/* no event mask means wait for any event */
3043a46c0ec8Sopenharmony_ci		if (ntypes == 0)
3044a46c0ec8Sopenharmony_ci			return;
3045a46c0ec8Sopenharmony_ci
3046a46c0ec8Sopenharmony_ci		for (i = 0; i < ntypes; i++) {
3047a46c0ec8Sopenharmony_ci			if (type == types[i])
3048a46c0ec8Sopenharmony_ci				return;
3049a46c0ec8Sopenharmony_ci		}
3050a46c0ec8Sopenharmony_ci
3051a46c0ec8Sopenharmony_ci		event = libinput_get_event(li);
3052a46c0ec8Sopenharmony_ci		libinput_event_destroy(event);
3053a46c0ec8Sopenharmony_ci	}
3054a46c0ec8Sopenharmony_ci}
3055a46c0ec8Sopenharmony_ci
3056a46c0ec8Sopenharmony_civoid
3057a46c0ec8Sopenharmony_cilitest_drain_events(struct libinput *li)
3058a46c0ec8Sopenharmony_ci{
3059a46c0ec8Sopenharmony_ci	struct libinput_event *event;
3060a46c0ec8Sopenharmony_ci
3061a46c0ec8Sopenharmony_ci	libinput_dispatch(li);
3062a46c0ec8Sopenharmony_ci	while ((event = libinput_get_event(li))) {
3063a46c0ec8Sopenharmony_ci		libinput_event_destroy(event);
3064a46c0ec8Sopenharmony_ci		libinput_dispatch(li);
3065a46c0ec8Sopenharmony_ci	}
3066a46c0ec8Sopenharmony_ci}
3067a46c0ec8Sopenharmony_ci
3068a46c0ec8Sopenharmony_ci
3069a46c0ec8Sopenharmony_civoid
3070a46c0ec8Sopenharmony_cilitest_drain_events_of_type(struct libinput *li, ...)
3071a46c0ec8Sopenharmony_ci{
3072a46c0ec8Sopenharmony_ci	enum libinput_event_type type;
3073a46c0ec8Sopenharmony_ci	enum libinput_event_type types[32] = {LIBINPUT_EVENT_NONE};
3074a46c0ec8Sopenharmony_ci	size_t ntypes = 0;
3075a46c0ec8Sopenharmony_ci	va_list args;
3076a46c0ec8Sopenharmony_ci
3077a46c0ec8Sopenharmony_ci	va_start(args, li);
3078a46c0ec8Sopenharmony_ci	type = va_arg(args, int);
3079a46c0ec8Sopenharmony_ci	while ((int)type != -1) {
3080a46c0ec8Sopenharmony_ci		litest_assert_int_gt(type, 0U);
3081a46c0ec8Sopenharmony_ci		litest_assert_int_lt(ntypes, ARRAY_LENGTH(types));
3082a46c0ec8Sopenharmony_ci		types[ntypes++] = type;
3083a46c0ec8Sopenharmony_ci		type = va_arg(args, int);
3084a46c0ec8Sopenharmony_ci	}
3085a46c0ec8Sopenharmony_ci	va_end(args);
3086a46c0ec8Sopenharmony_ci
3087a46c0ec8Sopenharmony_ci	libinput_dispatch(li);
3088a46c0ec8Sopenharmony_ci	type = libinput_next_event_type(li);
3089a46c0ec8Sopenharmony_ci	while (type !=  LIBINPUT_EVENT_NONE) {
3090a46c0ec8Sopenharmony_ci		struct libinput_event *event;
3091a46c0ec8Sopenharmony_ci		bool found = false;
3092a46c0ec8Sopenharmony_ci
3093a46c0ec8Sopenharmony_ci		type = libinput_next_event_type(li);
3094a46c0ec8Sopenharmony_ci
3095a46c0ec8Sopenharmony_ci		for (size_t i = 0; i < ntypes; i++) {
3096a46c0ec8Sopenharmony_ci			if (type == types[i]) {
3097a46c0ec8Sopenharmony_ci				found = true;
3098a46c0ec8Sopenharmony_ci				break;
3099a46c0ec8Sopenharmony_ci			}
3100a46c0ec8Sopenharmony_ci		}
3101a46c0ec8Sopenharmony_ci		if (!found)
3102a46c0ec8Sopenharmony_ci			return;
3103a46c0ec8Sopenharmony_ci
3104a46c0ec8Sopenharmony_ci		event = libinput_get_event(li);
3105a46c0ec8Sopenharmony_ci		libinput_event_destroy(event);
3106a46c0ec8Sopenharmony_ci		libinput_dispatch(li);
3107a46c0ec8Sopenharmony_ci	}
3108a46c0ec8Sopenharmony_ci}
3109a46c0ec8Sopenharmony_ci
3110a46c0ec8Sopenharmony_cistatic const char *
3111a46c0ec8Sopenharmony_cilitest_event_type_str(enum libinput_event_type type)
3112a46c0ec8Sopenharmony_ci{
3113a46c0ec8Sopenharmony_ci	const char *str = NULL;
3114a46c0ec8Sopenharmony_ci
3115a46c0ec8Sopenharmony_ci	switch (type) {
3116a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_NONE:
3117a46c0ec8Sopenharmony_ci		abort();
3118a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_DEVICE_ADDED:
3119a46c0ec8Sopenharmony_ci		str = "ADDED";
3120a46c0ec8Sopenharmony_ci		break;
3121a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_DEVICE_REMOVED:
3122a46c0ec8Sopenharmony_ci		str = "REMOVED";
3123a46c0ec8Sopenharmony_ci		break;
3124a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_KEYBOARD_KEY:
3125a46c0ec8Sopenharmony_ci		str = "KEY";
3126a46c0ec8Sopenharmony_ci		break;
3127a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_POINTER_MOTION:
3128a46c0ec8Sopenharmony_ci		str = "MOTION";
3129a46c0ec8Sopenharmony_ci		break;
3130a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE:
3131a46c0ec8Sopenharmony_ci		str = "ABSOLUTE";
3132a46c0ec8Sopenharmony_ci		break;
3133a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_POINTER_BUTTON:
3134a46c0ec8Sopenharmony_ci		str = "BUTTON";
3135a46c0ec8Sopenharmony_ci		break;
3136a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_POINTER_AXIS:
3137a46c0ec8Sopenharmony_ci		str = "AXIS";
3138a46c0ec8Sopenharmony_ci		break;
3139a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_POINTER_SCROLL_WHEEL:
3140a46c0ec8Sopenharmony_ci		str = "SCROLL_WHEEL";
3141a46c0ec8Sopenharmony_ci		break;
3142a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_POINTER_SCROLL_FINGER:
3143a46c0ec8Sopenharmony_ci		str = "SCROLL_FINGER";
3144a46c0ec8Sopenharmony_ci		break;
3145a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_POINTER_SCROLL_CONTINUOUS:
3146a46c0ec8Sopenharmony_ci		str = "SCROLL_CONTINUOUS";
3147a46c0ec8Sopenharmony_ci		break;
3148a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_TOUCH_DOWN:
3149a46c0ec8Sopenharmony_ci		str = "TOUCH DOWN";
3150a46c0ec8Sopenharmony_ci		break;
3151a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_TOUCH_UP:
3152a46c0ec8Sopenharmony_ci		str = "TOUCH UP";
3153a46c0ec8Sopenharmony_ci		break;
3154a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_TOUCH_MOTION:
3155a46c0ec8Sopenharmony_ci		str = "TOUCH MOTION";
3156a46c0ec8Sopenharmony_ci		break;
3157a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_TOUCH_CANCEL:
3158a46c0ec8Sopenharmony_ci		str = "TOUCH CANCEL";
3159a46c0ec8Sopenharmony_ci		break;
3160a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_TOUCH_FRAME:
3161a46c0ec8Sopenharmony_ci		str = "TOUCH FRAME";
3162a46c0ec8Sopenharmony_ci		break;
3163a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN:
3164a46c0ec8Sopenharmony_ci		str = "GESTURE SWIPE BEGIN";
3165a46c0ec8Sopenharmony_ci		break;
3166a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE:
3167a46c0ec8Sopenharmony_ci		str = "GESTURE SWIPE UPDATE";
3168a46c0ec8Sopenharmony_ci		break;
3169a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_GESTURE_SWIPE_END:
3170a46c0ec8Sopenharmony_ci		str = "GESTURE SWIPE END";
3171a46c0ec8Sopenharmony_ci		break;
3172a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_GESTURE_PINCH_BEGIN:
3173a46c0ec8Sopenharmony_ci		str = "GESTURE PINCH BEGIN";
3174a46c0ec8Sopenharmony_ci		break;
3175a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_GESTURE_PINCH_UPDATE:
3176a46c0ec8Sopenharmony_ci		str = "GESTURE PINCH UPDATE";
3177a46c0ec8Sopenharmony_ci		break;
3178a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_GESTURE_PINCH_END:
3179a46c0ec8Sopenharmony_ci		str = "GESTURE PINCH END";
3180a46c0ec8Sopenharmony_ci		break;
3181a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_GESTURE_HOLD_BEGIN:
3182a46c0ec8Sopenharmony_ci		str = "GESTURE HOLD BEGIN";
3183a46c0ec8Sopenharmony_ci		break;
3184a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_GESTURE_HOLD_END:
3185a46c0ec8Sopenharmony_ci		str = "GESTURE HOLD END";
3186a46c0ec8Sopenharmony_ci		break;
3187a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_TABLET_TOOL_AXIS:
3188a46c0ec8Sopenharmony_ci		str = "TABLET TOOL AXIS";
3189a46c0ec8Sopenharmony_ci		break;
3190a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY:
3191a46c0ec8Sopenharmony_ci		str = "TABLET TOOL PROX";
3192a46c0ec8Sopenharmony_ci		break;
3193a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_TABLET_TOOL_TIP:
3194a46c0ec8Sopenharmony_ci		str = "TABLET TOOL TIP";
3195a46c0ec8Sopenharmony_ci		break;
3196a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_TABLET_TOOL_BUTTON:
3197a46c0ec8Sopenharmony_ci		str = "TABLET TOOL BUTTON";
3198a46c0ec8Sopenharmony_ci		break;
3199a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_TABLET_PAD_BUTTON:
3200a46c0ec8Sopenharmony_ci		str = "TABLET PAD BUTTON";
3201a46c0ec8Sopenharmony_ci		break;
3202a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_TABLET_PAD_RING:
3203a46c0ec8Sopenharmony_ci		str = "TABLET PAD RING";
3204a46c0ec8Sopenharmony_ci		break;
3205a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_TABLET_PAD_STRIP:
3206a46c0ec8Sopenharmony_ci		str = "TABLET PAD STRIP";
3207a46c0ec8Sopenharmony_ci		break;
3208a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_TABLET_PAD_KEY:
3209a46c0ec8Sopenharmony_ci		str = "TABLET PAD KEY";
3210a46c0ec8Sopenharmony_ci		break;
3211a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_SWITCH_TOGGLE:
3212a46c0ec8Sopenharmony_ci		str = "SWITCH TOGGLE";
3213a46c0ec8Sopenharmony_ci		break;
3214a46c0ec8Sopenharmony_ci	}
3215a46c0ec8Sopenharmony_ci	return str;
3216a46c0ec8Sopenharmony_ci}
3217a46c0ec8Sopenharmony_ci
3218a46c0ec8Sopenharmony_cistatic const char *
3219a46c0ec8Sopenharmony_cilitest_event_get_type_str(struct libinput_event *event)
3220a46c0ec8Sopenharmony_ci{
3221a46c0ec8Sopenharmony_ci	return litest_event_type_str(libinput_event_get_type(event));
3222a46c0ec8Sopenharmony_ci}
3223a46c0ec8Sopenharmony_ci
3224a46c0ec8Sopenharmony_cistatic void
3225a46c0ec8Sopenharmony_cilitest_print_event(struct libinput_event *event)
3226a46c0ec8Sopenharmony_ci{
3227a46c0ec8Sopenharmony_ci	struct libinput_event_pointer *p;
3228a46c0ec8Sopenharmony_ci	struct libinput_event_tablet_tool *t;
3229a46c0ec8Sopenharmony_ci	struct libinput_event_tablet_pad *pad;
3230a46c0ec8Sopenharmony_ci	struct libinput_device *dev;
3231a46c0ec8Sopenharmony_ci	enum libinput_event_type type;
3232a46c0ec8Sopenharmony_ci	double x, y;
3233a46c0ec8Sopenharmony_ci
3234a46c0ec8Sopenharmony_ci	dev = libinput_event_get_device(event);
3235a46c0ec8Sopenharmony_ci	type = libinput_event_get_type(event);
3236a46c0ec8Sopenharmony_ci
3237a46c0ec8Sopenharmony_ci	fprintf(stderr,
3238a46c0ec8Sopenharmony_ci		"device %s (%s) type %s ",
3239a46c0ec8Sopenharmony_ci		libinput_device_get_sysname(dev),
3240a46c0ec8Sopenharmony_ci		libinput_device_get_name(dev),
3241a46c0ec8Sopenharmony_ci		litest_event_get_type_str(event));
3242a46c0ec8Sopenharmony_ci	switch (type) {
3243a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_POINTER_MOTION:
3244a46c0ec8Sopenharmony_ci		p = libinput_event_get_pointer_event(event);
3245a46c0ec8Sopenharmony_ci		x = libinput_event_pointer_get_dx(p);
3246a46c0ec8Sopenharmony_ci		y = libinput_event_pointer_get_dy(p);
3247a46c0ec8Sopenharmony_ci		fprintf(stderr, "%.2f/%.2f", x, y);
3248a46c0ec8Sopenharmony_ci		break;
3249a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE:
3250a46c0ec8Sopenharmony_ci		p = libinput_event_get_pointer_event(event);
3251a46c0ec8Sopenharmony_ci		x = libinput_event_pointer_get_absolute_x(p);
3252a46c0ec8Sopenharmony_ci		y = libinput_event_pointer_get_absolute_y(p);
3253a46c0ec8Sopenharmony_ci		fprintf(stderr, "%.2f/%.2f", x, y);
3254a46c0ec8Sopenharmony_ci		break;
3255a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_POINTER_BUTTON:
3256a46c0ec8Sopenharmony_ci		p = libinput_event_get_pointer_event(event);
3257a46c0ec8Sopenharmony_ci		fprintf(stderr,
3258a46c0ec8Sopenharmony_ci			"button %d state %d",
3259a46c0ec8Sopenharmony_ci			libinput_event_pointer_get_button(p),
3260a46c0ec8Sopenharmony_ci			libinput_event_pointer_get_button_state(p));
3261a46c0ec8Sopenharmony_ci		break;
3262a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_POINTER_AXIS:
3263a46c0ec8Sopenharmony_ci		p = libinput_event_get_pointer_event(event);
3264a46c0ec8Sopenharmony_ci		x = 0.0;
3265a46c0ec8Sopenharmony_ci		y = 0.0;
3266a46c0ec8Sopenharmony_ci		if (libinput_event_pointer_has_axis(p,
3267a46c0ec8Sopenharmony_ci				LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL))
3268a46c0ec8Sopenharmony_ci			y = libinput_event_pointer_get_axis_value(p,
3269a46c0ec8Sopenharmony_ci				LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL);
3270a46c0ec8Sopenharmony_ci		if (libinput_event_pointer_has_axis(p,
3271a46c0ec8Sopenharmony_ci				LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL))
3272a46c0ec8Sopenharmony_ci			x = libinput_event_pointer_get_axis_value(p,
3273a46c0ec8Sopenharmony_ci				LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL);
3274a46c0ec8Sopenharmony_ci		fprintf(stderr, "vert %.2f horiz %.2f", y, x);
3275a46c0ec8Sopenharmony_ci		break;
3276a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY:
3277a46c0ec8Sopenharmony_ci		t = libinput_event_get_tablet_tool_event(event);
3278a46c0ec8Sopenharmony_ci		fprintf(stderr, "proximity %d",
3279a46c0ec8Sopenharmony_ci			libinput_event_tablet_tool_get_proximity_state(t));
3280a46c0ec8Sopenharmony_ci		break;
3281a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_TABLET_TOOL_TIP:
3282a46c0ec8Sopenharmony_ci		t = libinput_event_get_tablet_tool_event(event);
3283a46c0ec8Sopenharmony_ci		fprintf(stderr, "tip %d",
3284a46c0ec8Sopenharmony_ci			libinput_event_tablet_tool_get_tip_state(t));
3285a46c0ec8Sopenharmony_ci		break;
3286a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_TABLET_TOOL_BUTTON:
3287a46c0ec8Sopenharmony_ci		t = libinput_event_get_tablet_tool_event(event);
3288a46c0ec8Sopenharmony_ci		fprintf(stderr, "button %d state %d",
3289a46c0ec8Sopenharmony_ci			libinput_event_tablet_tool_get_button(t),
3290a46c0ec8Sopenharmony_ci			libinput_event_tablet_tool_get_button_state(t));
3291a46c0ec8Sopenharmony_ci		break;
3292a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_TABLET_PAD_BUTTON:
3293a46c0ec8Sopenharmony_ci		pad = libinput_event_get_tablet_pad_event(event);
3294a46c0ec8Sopenharmony_ci		fprintf(stderr, "button %d state %d",
3295a46c0ec8Sopenharmony_ci			libinput_event_tablet_pad_get_button_number(pad),
3296a46c0ec8Sopenharmony_ci			libinput_event_tablet_pad_get_button_state(pad));
3297a46c0ec8Sopenharmony_ci		break;
3298a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_TABLET_PAD_RING:
3299a46c0ec8Sopenharmony_ci		pad = libinput_event_get_tablet_pad_event(event);
3300a46c0ec8Sopenharmony_ci		fprintf(stderr, "ring %d position %.2f source %d",
3301a46c0ec8Sopenharmony_ci			libinput_event_tablet_pad_get_ring_number(pad),
3302a46c0ec8Sopenharmony_ci			libinput_event_tablet_pad_get_ring_position(pad),
3303a46c0ec8Sopenharmony_ci			libinput_event_tablet_pad_get_ring_source(pad));
3304a46c0ec8Sopenharmony_ci		break;
3305a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_TABLET_PAD_STRIP:
3306a46c0ec8Sopenharmony_ci		pad = libinput_event_get_tablet_pad_event(event);
3307a46c0ec8Sopenharmony_ci		fprintf(stderr, "strip %d position %.2f source %d",
3308a46c0ec8Sopenharmony_ci			libinput_event_tablet_pad_get_ring_number(pad),
3309a46c0ec8Sopenharmony_ci			libinput_event_tablet_pad_get_ring_position(pad),
3310a46c0ec8Sopenharmony_ci			libinput_event_tablet_pad_get_ring_source(pad));
3311a46c0ec8Sopenharmony_ci		break;
3312a46c0ec8Sopenharmony_ci	default:
3313a46c0ec8Sopenharmony_ci		break;
3314a46c0ec8Sopenharmony_ci	}
3315a46c0ec8Sopenharmony_ci
3316a46c0ec8Sopenharmony_ci	fprintf(stderr, "\n");
3317a46c0ec8Sopenharmony_ci}
3318a46c0ec8Sopenharmony_ci
3319a46c0ec8Sopenharmony_ci#define litest_assert_event_type_is_one_of(...) \
3320a46c0ec8Sopenharmony_ci    _litest_assert_event_type_is_one_of(__VA_ARGS__, -1)
3321a46c0ec8Sopenharmony_ci
3322a46c0ec8Sopenharmony_cistatic void
3323a46c0ec8Sopenharmony_ci_litest_assert_event_type_is_one_of(struct libinput_event *event, ...)
3324a46c0ec8Sopenharmony_ci{
3325a46c0ec8Sopenharmony_ci	va_list args;
3326a46c0ec8Sopenharmony_ci	enum libinput_event_type expected_type;
3327a46c0ec8Sopenharmony_ci	enum libinput_event_type actual_type = libinput_event_get_type(event);
3328a46c0ec8Sopenharmony_ci	bool match = false;
3329a46c0ec8Sopenharmony_ci
3330a46c0ec8Sopenharmony_ci	va_start(args, event);
3331a46c0ec8Sopenharmony_ci	expected_type = va_arg(args, int);
3332a46c0ec8Sopenharmony_ci	while ((int)expected_type != -1 && !match) {
3333a46c0ec8Sopenharmony_ci		match = (actual_type == expected_type);
3334a46c0ec8Sopenharmony_ci		expected_type = va_arg(args, int);
3335a46c0ec8Sopenharmony_ci	}
3336a46c0ec8Sopenharmony_ci	va_end(args);
3337a46c0ec8Sopenharmony_ci
3338a46c0ec8Sopenharmony_ci	if (match)
3339a46c0ec8Sopenharmony_ci		return;
3340a46c0ec8Sopenharmony_ci
3341a46c0ec8Sopenharmony_ci	fprintf(stderr,
3342a46c0ec8Sopenharmony_ci		"FAILED EVENT TYPE: %s: have %s (%d) but want ",
3343a46c0ec8Sopenharmony_ci		libinput_device_get_name(libinput_event_get_device(event)),
3344a46c0ec8Sopenharmony_ci		litest_event_get_type_str(event),
3345a46c0ec8Sopenharmony_ci		libinput_event_get_type(event));
3346a46c0ec8Sopenharmony_ci
3347a46c0ec8Sopenharmony_ci	va_start(args, event);
3348a46c0ec8Sopenharmony_ci	expected_type = va_arg(args, int);
3349a46c0ec8Sopenharmony_ci	while ((int)expected_type != -1) {
3350a46c0ec8Sopenharmony_ci		fprintf(stderr,
3351a46c0ec8Sopenharmony_ci			"%s (%d)",
3352a46c0ec8Sopenharmony_ci			litest_event_type_str(expected_type),
3353a46c0ec8Sopenharmony_ci			expected_type);
3354a46c0ec8Sopenharmony_ci		expected_type = va_arg(args, int);
3355a46c0ec8Sopenharmony_ci
3356a46c0ec8Sopenharmony_ci		if ((int)expected_type != -1)
3357a46c0ec8Sopenharmony_ci			fprintf(stderr, " || ");
3358a46c0ec8Sopenharmony_ci	}
3359a46c0ec8Sopenharmony_ci
3360a46c0ec8Sopenharmony_ci	fprintf(stderr, "\nWrong event is: ");
3361a46c0ec8Sopenharmony_ci	litest_print_event(event);
3362a46c0ec8Sopenharmony_ci	litest_backtrace();
3363a46c0ec8Sopenharmony_ci	abort();
3364a46c0ec8Sopenharmony_ci}
3365a46c0ec8Sopenharmony_ci
3366a46c0ec8Sopenharmony_civoid
3367a46c0ec8Sopenharmony_cilitest_assert_event_type(struct libinput_event *event,
3368a46c0ec8Sopenharmony_ci			 enum libinput_event_type want)
3369a46c0ec8Sopenharmony_ci{
3370a46c0ec8Sopenharmony_ci	litest_assert_event_type_is_one_of(event, want);
3371a46c0ec8Sopenharmony_ci}
3372a46c0ec8Sopenharmony_ci
3373a46c0ec8Sopenharmony_civoid
3374a46c0ec8Sopenharmony_cilitest_assert_empty_queue(struct libinput *li)
3375a46c0ec8Sopenharmony_ci{
3376a46c0ec8Sopenharmony_ci	bool empty_queue = true;
3377a46c0ec8Sopenharmony_ci	struct libinput_event *event;
3378a46c0ec8Sopenharmony_ci
3379a46c0ec8Sopenharmony_ci	libinput_dispatch(li);
3380a46c0ec8Sopenharmony_ci	while ((event = libinput_get_event(li))) {
3381a46c0ec8Sopenharmony_ci		empty_queue = false;
3382a46c0ec8Sopenharmony_ci		fprintf(stderr,
3383a46c0ec8Sopenharmony_ci			"Unexpected event: ");
3384a46c0ec8Sopenharmony_ci		litest_print_event(event);
3385a46c0ec8Sopenharmony_ci		libinput_event_destroy(event);
3386a46c0ec8Sopenharmony_ci		libinput_dispatch(li);
3387a46c0ec8Sopenharmony_ci	}
3388a46c0ec8Sopenharmony_ci
3389a46c0ec8Sopenharmony_ci	litest_assert(empty_queue);
3390a46c0ec8Sopenharmony_ci}
3391a46c0ec8Sopenharmony_ci
3392a46c0ec8Sopenharmony_cistatic struct libevdev_uinput *
3393a46c0ec8Sopenharmony_cilitest_create_uinput(const char *name,
3394a46c0ec8Sopenharmony_ci		     const struct input_id *id,
3395a46c0ec8Sopenharmony_ci		     const struct input_absinfo *abs_info,
3396a46c0ec8Sopenharmony_ci		     const int *events)
3397a46c0ec8Sopenharmony_ci{
3398a46c0ec8Sopenharmony_ci	struct libevdev_uinput *uinput;
3399a46c0ec8Sopenharmony_ci	struct libevdev *dev;
3400a46c0ec8Sopenharmony_ci	int type, code;
3401a46c0ec8Sopenharmony_ci	int rc, fd;
3402a46c0ec8Sopenharmony_ci	const struct input_absinfo *abs;
3403a46c0ec8Sopenharmony_ci	const struct input_absinfo default_abs = {
3404a46c0ec8Sopenharmony_ci		.value = 0,
3405a46c0ec8Sopenharmony_ci		.minimum = 0,
3406a46c0ec8Sopenharmony_ci		.maximum = 100,
3407a46c0ec8Sopenharmony_ci		.fuzz = 0,
3408a46c0ec8Sopenharmony_ci		.flat = 0,
3409a46c0ec8Sopenharmony_ci		.resolution = 100
3410a46c0ec8Sopenharmony_ci	};
3411a46c0ec8Sopenharmony_ci	char buf[512];
3412a46c0ec8Sopenharmony_ci	const char *devnode;
3413a46c0ec8Sopenharmony_ci
3414a46c0ec8Sopenharmony_ci	dev = libevdev_new();
3415a46c0ec8Sopenharmony_ci	litest_assert_ptr_notnull(dev);
3416a46c0ec8Sopenharmony_ci
3417a46c0ec8Sopenharmony_ci	snprintf(buf, sizeof(buf), "litest %s", name);
3418a46c0ec8Sopenharmony_ci	libevdev_set_name(dev, buf);
3419a46c0ec8Sopenharmony_ci	if (id) {
3420a46c0ec8Sopenharmony_ci		libevdev_set_id_bustype(dev, id->bustype);
3421a46c0ec8Sopenharmony_ci		libevdev_set_id_vendor(dev, id->vendor);
3422a46c0ec8Sopenharmony_ci		libevdev_set_id_product(dev, id->product);
3423a46c0ec8Sopenharmony_ci		libevdev_set_id_version(dev, id->version);
3424a46c0ec8Sopenharmony_ci	}
3425a46c0ec8Sopenharmony_ci
3426a46c0ec8Sopenharmony_ci	abs = abs_info;
3427a46c0ec8Sopenharmony_ci	while (abs && abs->value != -1) {
3428a46c0ec8Sopenharmony_ci		struct input_absinfo a = *abs;
3429a46c0ec8Sopenharmony_ci
3430a46c0ec8Sopenharmony_ci		/* abs_info->value is used for the code and may be outside
3431a46c0ec8Sopenharmony_ci		   of [min, max] */
3432a46c0ec8Sopenharmony_ci		a.value = abs->minimum;
3433a46c0ec8Sopenharmony_ci		rc = libevdev_enable_event_code(dev, EV_ABS, abs->value, &a);
3434a46c0ec8Sopenharmony_ci		litest_assert_int_eq(rc, 0);
3435a46c0ec8Sopenharmony_ci		abs++;
3436a46c0ec8Sopenharmony_ci	}
3437a46c0ec8Sopenharmony_ci
3438a46c0ec8Sopenharmony_ci	while (events &&
3439a46c0ec8Sopenharmony_ci	       (type = *events++) != -1 &&
3440a46c0ec8Sopenharmony_ci	       (code = *events++) != -1) {
3441a46c0ec8Sopenharmony_ci		if (type == INPUT_PROP_MAX) {
3442a46c0ec8Sopenharmony_ci			rc = libevdev_enable_property(dev, code);
3443a46c0ec8Sopenharmony_ci		} else {
3444a46c0ec8Sopenharmony_ci			rc = libevdev_enable_event_code(dev, type, code,
3445a46c0ec8Sopenharmony_ci							type == EV_ABS ? &default_abs : NULL);
3446a46c0ec8Sopenharmony_ci		}
3447a46c0ec8Sopenharmony_ci		litest_assert_int_eq(rc, 0);
3448a46c0ec8Sopenharmony_ci	}
3449a46c0ec8Sopenharmony_ci
3450a46c0ec8Sopenharmony_ci	rc = libevdev_uinput_create_from_device(dev,
3451a46c0ec8Sopenharmony_ci					        LIBEVDEV_UINPUT_OPEN_MANAGED,
3452a46c0ec8Sopenharmony_ci						&uinput);
3453a46c0ec8Sopenharmony_ci	/* workaround for a bug in libevdev pre-1.3
3454a46c0ec8Sopenharmony_ci	   http://cgit.freedesktop.org/libevdev/commit/?id=debe9b030c8069cdf78307888ef3b65830b25122 */
3455a46c0ec8Sopenharmony_ci	if (rc == -EBADF)
3456a46c0ec8Sopenharmony_ci		rc = -EACCES;
3457a46c0ec8Sopenharmony_ci	litest_assert_msg(rc == 0, "Failed to create uinput device: %s\n", strerror(-rc));
3458a46c0ec8Sopenharmony_ci
3459a46c0ec8Sopenharmony_ci	libevdev_free(dev);
3460a46c0ec8Sopenharmony_ci
3461a46c0ec8Sopenharmony_ci	devnode = libevdev_uinput_get_devnode(uinput);
3462a46c0ec8Sopenharmony_ci	litest_assert_notnull(devnode);
3463a46c0ec8Sopenharmony_ci	fd = open(devnode, O_RDONLY);
3464a46c0ec8Sopenharmony_ci	litest_assert_int_gt(fd, -1);
3465a46c0ec8Sopenharmony_ci	rc = libevdev_new_from_fd(fd, &dev);
3466a46c0ec8Sopenharmony_ci	litest_assert_int_eq(rc, 0);
3467a46c0ec8Sopenharmony_ci
3468a46c0ec8Sopenharmony_ci	/* uinput before kernel 4.5 + libevdev 1.5.0 does not support
3469a46c0ec8Sopenharmony_ci	 * setting the resolution, so we set it afterwards. This is of
3470a46c0ec8Sopenharmony_ci	 * course racy as hell but the way we _generally_ use this function
3471a46c0ec8Sopenharmony_ci	 * by the time libinput uses the device, we're finished here.
3472a46c0ec8Sopenharmony_ci	 *
3473a46c0ec8Sopenharmony_ci	 * If you have kernel 4.5 and libevdev 1.5.0 or later, this code
3474a46c0ec8Sopenharmony_ci	 * just keeps the room warm.
3475a46c0ec8Sopenharmony_ci	 */
3476a46c0ec8Sopenharmony_ci	abs = abs_info;
3477a46c0ec8Sopenharmony_ci	while (abs && abs->value != -1) {
3478a46c0ec8Sopenharmony_ci		if (abs->resolution != 0) {
3479a46c0ec8Sopenharmony_ci			if (libevdev_get_abs_resolution(dev, abs->value) ==
3480a46c0ec8Sopenharmony_ci			    abs->resolution)
3481a46c0ec8Sopenharmony_ci				break;
3482a46c0ec8Sopenharmony_ci
3483a46c0ec8Sopenharmony_ci			rc = libevdev_kernel_set_abs_info(dev,
3484a46c0ec8Sopenharmony_ci							  abs->value,
3485a46c0ec8Sopenharmony_ci							  abs);
3486a46c0ec8Sopenharmony_ci			litest_assert_int_eq(rc, 0);
3487a46c0ec8Sopenharmony_ci		}
3488a46c0ec8Sopenharmony_ci		abs++;
3489a46c0ec8Sopenharmony_ci	}
3490a46c0ec8Sopenharmony_ci	close(fd);
3491a46c0ec8Sopenharmony_ci	libevdev_free(dev);
3492a46c0ec8Sopenharmony_ci
3493a46c0ec8Sopenharmony_ci	return uinput;
3494a46c0ec8Sopenharmony_ci}
3495a46c0ec8Sopenharmony_ci
3496a46c0ec8Sopenharmony_cistruct libevdev_uinput *
3497a46c0ec8Sopenharmony_cilitest_create_uinput_device_from_description(const char *name,
3498a46c0ec8Sopenharmony_ci					     const struct input_id *id,
3499a46c0ec8Sopenharmony_ci					     const struct input_absinfo *abs_info,
3500a46c0ec8Sopenharmony_ci					     const int *events)
3501a46c0ec8Sopenharmony_ci{
3502a46c0ec8Sopenharmony_ci	struct libevdev_uinput *uinput;
3503a46c0ec8Sopenharmony_ci	const char *syspath;
3504a46c0ec8Sopenharmony_ci	char path[PATH_MAX];
3505a46c0ec8Sopenharmony_ci
3506a46c0ec8Sopenharmony_ci	struct udev_monitor *udev_monitor;
3507a46c0ec8Sopenharmony_ci	struct udev_device *udev_device;
3508a46c0ec8Sopenharmony_ci
3509a46c0ec8Sopenharmony_ci	udev_monitor = udev_setup_monitor();
3510a46c0ec8Sopenharmony_ci
3511a46c0ec8Sopenharmony_ci	uinput = litest_create_uinput(name, id, abs_info, events);
3512a46c0ec8Sopenharmony_ci
3513a46c0ec8Sopenharmony_ci	syspath = libevdev_uinput_get_syspath(uinput);
3514a46c0ec8Sopenharmony_ci	snprintf(path, sizeof(path), "%s/event", syspath);
3515a46c0ec8Sopenharmony_ci
3516a46c0ec8Sopenharmony_ci	udev_device = udev_wait_for_device_event(udev_monitor, "add", path);
3517a46c0ec8Sopenharmony_ci
3518a46c0ec8Sopenharmony_ci	litest_assert(udev_device_get_property_value(udev_device, "ID_INPUT"));
3519a46c0ec8Sopenharmony_ci
3520a46c0ec8Sopenharmony_ci	udev_device_unref(udev_device);
3521a46c0ec8Sopenharmony_ci	udev_monitor_unref(udev_monitor);
3522a46c0ec8Sopenharmony_ci
3523a46c0ec8Sopenharmony_ci	return uinput;
3524a46c0ec8Sopenharmony_ci}
3525a46c0ec8Sopenharmony_ci
3526a46c0ec8Sopenharmony_cistatic struct libevdev_uinput *
3527a46c0ec8Sopenharmony_cilitest_create_uinput_abs_device_v(const char *name,
3528a46c0ec8Sopenharmony_ci				  struct input_id *id,
3529a46c0ec8Sopenharmony_ci				  const struct input_absinfo *abs,
3530a46c0ec8Sopenharmony_ci				  va_list args)
3531a46c0ec8Sopenharmony_ci{
3532a46c0ec8Sopenharmony_ci	int events[KEY_MAX * 2 + 2]; /* increase this if not sufficient */
3533a46c0ec8Sopenharmony_ci	int *event = events;
3534a46c0ec8Sopenharmony_ci	int type, code;
3535a46c0ec8Sopenharmony_ci
3536a46c0ec8Sopenharmony_ci	while ((type = va_arg(args, int)) != -1 &&
3537a46c0ec8Sopenharmony_ci	       (code = va_arg(args, int)) != -1) {
3538a46c0ec8Sopenharmony_ci		*event++ = type;
3539a46c0ec8Sopenharmony_ci		*event++ = code;
3540a46c0ec8Sopenharmony_ci		litest_assert(event < &events[ARRAY_LENGTH(events) - 2]);
3541a46c0ec8Sopenharmony_ci	}
3542a46c0ec8Sopenharmony_ci
3543a46c0ec8Sopenharmony_ci	*event++ = -1;
3544a46c0ec8Sopenharmony_ci	*event++ = -1;
3545a46c0ec8Sopenharmony_ci
3546a46c0ec8Sopenharmony_ci	return litest_create_uinput_device_from_description(name, id,
3547a46c0ec8Sopenharmony_ci							    abs, events);
3548a46c0ec8Sopenharmony_ci}
3549a46c0ec8Sopenharmony_ci
3550a46c0ec8Sopenharmony_cistruct libevdev_uinput *
3551a46c0ec8Sopenharmony_cilitest_create_uinput_abs_device(const char *name,
3552a46c0ec8Sopenharmony_ci				struct input_id *id,
3553a46c0ec8Sopenharmony_ci				const struct input_absinfo *abs,
3554a46c0ec8Sopenharmony_ci				...)
3555a46c0ec8Sopenharmony_ci{
3556a46c0ec8Sopenharmony_ci	struct libevdev_uinput *uinput;
3557a46c0ec8Sopenharmony_ci	va_list args;
3558a46c0ec8Sopenharmony_ci
3559a46c0ec8Sopenharmony_ci	va_start(args, abs);
3560a46c0ec8Sopenharmony_ci	uinput = litest_create_uinput_abs_device_v(name, id, abs, args);
3561a46c0ec8Sopenharmony_ci	va_end(args);
3562a46c0ec8Sopenharmony_ci
3563a46c0ec8Sopenharmony_ci	return uinput;
3564a46c0ec8Sopenharmony_ci}
3565a46c0ec8Sopenharmony_ci
3566a46c0ec8Sopenharmony_cistruct libevdev_uinput *
3567a46c0ec8Sopenharmony_cilitest_create_uinput_device(const char *name, struct input_id *id, ...)
3568a46c0ec8Sopenharmony_ci{
3569a46c0ec8Sopenharmony_ci	struct libevdev_uinput *uinput;
3570a46c0ec8Sopenharmony_ci	va_list args;
3571a46c0ec8Sopenharmony_ci
3572a46c0ec8Sopenharmony_ci	va_start(args, id);
3573a46c0ec8Sopenharmony_ci	uinput = litest_create_uinput_abs_device_v(name, id, NULL, args);
3574a46c0ec8Sopenharmony_ci	va_end(args);
3575a46c0ec8Sopenharmony_ci
3576a46c0ec8Sopenharmony_ci	return uinput;
3577a46c0ec8Sopenharmony_ci}
3578a46c0ec8Sopenharmony_ci
3579a46c0ec8Sopenharmony_cistruct libinput_event_pointer*
3580a46c0ec8Sopenharmony_cilitest_is_button_event(struct libinput_event *event,
3581a46c0ec8Sopenharmony_ci		       unsigned int button,
3582a46c0ec8Sopenharmony_ci		       enum libinput_button_state state)
3583a46c0ec8Sopenharmony_ci{
3584a46c0ec8Sopenharmony_ci	struct libinput_event_pointer *ptrev;
3585a46c0ec8Sopenharmony_ci	enum libinput_event_type type = LIBINPUT_EVENT_POINTER_BUTTON;
3586a46c0ec8Sopenharmony_ci
3587a46c0ec8Sopenharmony_ci	litest_assert_ptr_notnull(event);
3588a46c0ec8Sopenharmony_ci	litest_assert_event_type(event, type);
3589a46c0ec8Sopenharmony_ci	ptrev = libinput_event_get_pointer_event(event);
3590a46c0ec8Sopenharmony_ci	litest_assert_int_eq(libinput_event_pointer_get_button(ptrev),
3591a46c0ec8Sopenharmony_ci			     button);
3592a46c0ec8Sopenharmony_ci	litest_assert_int_eq(libinput_event_pointer_get_button_state(ptrev),
3593a46c0ec8Sopenharmony_ci			     state);
3594a46c0ec8Sopenharmony_ci
3595a46c0ec8Sopenharmony_ci	return ptrev;
3596a46c0ec8Sopenharmony_ci}
3597a46c0ec8Sopenharmony_ci
3598a46c0ec8Sopenharmony_cistruct libinput_event_pointer *
3599a46c0ec8Sopenharmony_cilitest_is_axis_event(struct libinput_event *event,
3600a46c0ec8Sopenharmony_ci		     enum libinput_event_type axis_type,
3601a46c0ec8Sopenharmony_ci		     enum libinput_pointer_axis axis,
3602a46c0ec8Sopenharmony_ci		     enum libinput_pointer_axis_source source)
3603a46c0ec8Sopenharmony_ci{
3604a46c0ec8Sopenharmony_ci	struct libinput_event_pointer *ptrev;
3605a46c0ec8Sopenharmony_ci
3606a46c0ec8Sopenharmony_ci	litest_assert(axis_type == LIBINPUT_EVENT_POINTER_SCROLL_WHEEL ||
3607a46c0ec8Sopenharmony_ci		      axis_type == LIBINPUT_EVENT_POINTER_SCROLL_FINGER ||
3608a46c0ec8Sopenharmony_ci		      axis_type == LIBINPUT_EVENT_POINTER_SCROLL_CONTINUOUS);
3609a46c0ec8Sopenharmony_ci
3610a46c0ec8Sopenharmony_ci	litest_assert_ptr_notnull(event);
3611a46c0ec8Sopenharmony_ci	litest_assert_event_type_is_one_of(event,
3612a46c0ec8Sopenharmony_ci					   LIBINPUT_EVENT_POINTER_AXIS,
3613a46c0ec8Sopenharmony_ci					   axis_type);
3614a46c0ec8Sopenharmony_ci	ptrev = libinput_event_get_pointer_event(event);
3615a46c0ec8Sopenharmony_ci	litest_assert(libinput_event_pointer_has_axis(ptrev, axis));
3616a46c0ec8Sopenharmony_ci
3617a46c0ec8Sopenharmony_ci	if (source != 0)
3618a46c0ec8Sopenharmony_ci		litest_assert_int_eq(litest_event_pointer_get_axis_source(ptrev),
3619a46c0ec8Sopenharmony_ci				     source);
3620a46c0ec8Sopenharmony_ci
3621a46c0ec8Sopenharmony_ci	return ptrev;
3622a46c0ec8Sopenharmony_ci}
3623a46c0ec8Sopenharmony_ci
3624a46c0ec8Sopenharmony_cibool
3625a46c0ec8Sopenharmony_cilitest_is_high_res_axis_event(struct libinput_event *event)
3626a46c0ec8Sopenharmony_ci{
3627a46c0ec8Sopenharmony_ci	litest_assert_event_type_is_one_of(event,
3628a46c0ec8Sopenharmony_ci					   LIBINPUT_EVENT_POINTER_AXIS,
3629a46c0ec8Sopenharmony_ci					   LIBINPUT_EVENT_POINTER_SCROLL_WHEEL,
3630a46c0ec8Sopenharmony_ci					   LIBINPUT_EVENT_POINTER_SCROLL_FINGER,
3631a46c0ec8Sopenharmony_ci					   LIBINPUT_EVENT_POINTER_SCROLL_CONTINUOUS);
3632a46c0ec8Sopenharmony_ci
3633a46c0ec8Sopenharmony_ci	return (libinput_event_get_type(event) != LIBINPUT_EVENT_POINTER_AXIS);
3634a46c0ec8Sopenharmony_ci}
3635a46c0ec8Sopenharmony_ci
3636a46c0ec8Sopenharmony_cistruct libinput_event_pointer *
3637a46c0ec8Sopenharmony_cilitest_is_motion_event(struct libinput_event *event)
3638a46c0ec8Sopenharmony_ci{
3639a46c0ec8Sopenharmony_ci	struct libinput_event_pointer *ptrev;
3640a46c0ec8Sopenharmony_ci	enum libinput_event_type type = LIBINPUT_EVENT_POINTER_MOTION;
3641a46c0ec8Sopenharmony_ci	double x, y, ux, uy;
3642a46c0ec8Sopenharmony_ci
3643a46c0ec8Sopenharmony_ci	litest_assert_ptr_notnull(event);
3644a46c0ec8Sopenharmony_ci	litest_assert_event_type(event, type);
3645a46c0ec8Sopenharmony_ci	ptrev = libinput_event_get_pointer_event(event);
3646a46c0ec8Sopenharmony_ci
3647a46c0ec8Sopenharmony_ci	x = libinput_event_pointer_get_dx(ptrev);
3648a46c0ec8Sopenharmony_ci	y = libinput_event_pointer_get_dy(ptrev);
3649a46c0ec8Sopenharmony_ci	ux = libinput_event_pointer_get_dx_unaccelerated(ptrev);
3650a46c0ec8Sopenharmony_ci	uy = libinput_event_pointer_get_dy_unaccelerated(ptrev);
3651a46c0ec8Sopenharmony_ci
3652a46c0ec8Sopenharmony_ci	/* No 0 delta motion events */
3653a46c0ec8Sopenharmony_ci	litest_assert(x != 0.0 || y != 0.0 ||
3654a46c0ec8Sopenharmony_ci		      ux != 0.0 || uy != 0.0);
3655a46c0ec8Sopenharmony_ci
3656a46c0ec8Sopenharmony_ci	return ptrev;
3657a46c0ec8Sopenharmony_ci}
3658a46c0ec8Sopenharmony_ci
3659a46c0ec8Sopenharmony_civoid
3660a46c0ec8Sopenharmony_cilitest_assert_key_event(struct libinput *li, unsigned int key,
3661a46c0ec8Sopenharmony_ci			enum libinput_key_state state)
3662a46c0ec8Sopenharmony_ci{
3663a46c0ec8Sopenharmony_ci	struct libinput_event *event;
3664a46c0ec8Sopenharmony_ci
3665a46c0ec8Sopenharmony_ci	litest_wait_for_event(li);
3666a46c0ec8Sopenharmony_ci	event = libinput_get_event(li);
3667a46c0ec8Sopenharmony_ci
3668a46c0ec8Sopenharmony_ci	litest_is_keyboard_event(event, key, state);
3669a46c0ec8Sopenharmony_ci
3670a46c0ec8Sopenharmony_ci	libinput_event_destroy(event);
3671a46c0ec8Sopenharmony_ci}
3672a46c0ec8Sopenharmony_ci
3673a46c0ec8Sopenharmony_civoid
3674a46c0ec8Sopenharmony_cilitest_assert_button_event(struct libinput *li, unsigned int button,
3675a46c0ec8Sopenharmony_ci			   enum libinput_button_state state)
3676a46c0ec8Sopenharmony_ci{
3677a46c0ec8Sopenharmony_ci	struct libinput_event *event;
3678a46c0ec8Sopenharmony_ci
3679a46c0ec8Sopenharmony_ci	litest_wait_for_event(li);
3680a46c0ec8Sopenharmony_ci	event = libinput_get_event(li);
3681a46c0ec8Sopenharmony_ci
3682a46c0ec8Sopenharmony_ci	litest_is_button_event(event, button, state);
3683a46c0ec8Sopenharmony_ci
3684a46c0ec8Sopenharmony_ci	libinput_event_destroy(event);
3685a46c0ec8Sopenharmony_ci}
3686a46c0ec8Sopenharmony_ci
3687a46c0ec8Sopenharmony_cistruct libinput_event_touch *
3688a46c0ec8Sopenharmony_cilitest_is_touch_event(struct libinput_event *event,
3689a46c0ec8Sopenharmony_ci		      enum libinput_event_type type)
3690a46c0ec8Sopenharmony_ci{
3691a46c0ec8Sopenharmony_ci	struct libinput_event_touch *touch;
3692a46c0ec8Sopenharmony_ci
3693a46c0ec8Sopenharmony_ci	litest_assert_ptr_notnull(event);
3694a46c0ec8Sopenharmony_ci
3695a46c0ec8Sopenharmony_ci	if (type == 0)
3696a46c0ec8Sopenharmony_ci		type = libinput_event_get_type(event);
3697a46c0ec8Sopenharmony_ci
3698a46c0ec8Sopenharmony_ci	switch (type) {
3699a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_TOUCH_DOWN:
3700a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_TOUCH_UP:
3701a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_TOUCH_MOTION:
3702a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_TOUCH_FRAME:
3703a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_TOUCH_CANCEL:
3704a46c0ec8Sopenharmony_ci		litest_assert_event_type(event, type);
3705a46c0ec8Sopenharmony_ci		break;
3706a46c0ec8Sopenharmony_ci	default:
3707a46c0ec8Sopenharmony_ci		ck_abort_msg("%s: invalid touch type %d\n", __func__, type);
3708a46c0ec8Sopenharmony_ci	}
3709a46c0ec8Sopenharmony_ci
3710a46c0ec8Sopenharmony_ci	touch = libinput_event_get_touch_event(event);
3711a46c0ec8Sopenharmony_ci
3712a46c0ec8Sopenharmony_ci	return touch;
3713a46c0ec8Sopenharmony_ci}
3714a46c0ec8Sopenharmony_ci
3715a46c0ec8Sopenharmony_cistruct libinput_event_keyboard *
3716a46c0ec8Sopenharmony_cilitest_is_keyboard_event(struct libinput_event *event,
3717a46c0ec8Sopenharmony_ci			 unsigned int key,
3718a46c0ec8Sopenharmony_ci			 enum libinput_key_state state)
3719a46c0ec8Sopenharmony_ci{
3720a46c0ec8Sopenharmony_ci	struct libinput_event_keyboard *kevent;
3721a46c0ec8Sopenharmony_ci	enum libinput_event_type type = LIBINPUT_EVENT_KEYBOARD_KEY;
3722a46c0ec8Sopenharmony_ci
3723a46c0ec8Sopenharmony_ci	litest_assert_ptr_notnull(event);
3724a46c0ec8Sopenharmony_ci	litest_assert_event_type(event, type);
3725a46c0ec8Sopenharmony_ci
3726a46c0ec8Sopenharmony_ci	kevent = libinput_event_get_keyboard_event(event);
3727a46c0ec8Sopenharmony_ci	litest_assert_ptr_notnull(kevent);
3728a46c0ec8Sopenharmony_ci
3729a46c0ec8Sopenharmony_ci	litest_assert_int_eq(libinput_event_keyboard_get_key(kevent), key);
3730a46c0ec8Sopenharmony_ci	litest_assert_int_eq(libinput_event_keyboard_get_key_state(kevent),
3731a46c0ec8Sopenharmony_ci			     state);
3732a46c0ec8Sopenharmony_ci	return kevent;
3733a46c0ec8Sopenharmony_ci}
3734a46c0ec8Sopenharmony_ci
3735a46c0ec8Sopenharmony_cistruct libinput_event_gesture *
3736a46c0ec8Sopenharmony_cilitest_is_gesture_event(struct libinput_event *event,
3737a46c0ec8Sopenharmony_ci			enum libinput_event_type type,
3738a46c0ec8Sopenharmony_ci			int nfingers)
3739a46c0ec8Sopenharmony_ci{
3740a46c0ec8Sopenharmony_ci	struct libinput_event_gesture *gevent;
3741a46c0ec8Sopenharmony_ci
3742a46c0ec8Sopenharmony_ci	litest_assert_ptr_notnull(event);
3743a46c0ec8Sopenharmony_ci	litest_assert_event_type(event, type);
3744a46c0ec8Sopenharmony_ci
3745a46c0ec8Sopenharmony_ci	gevent = libinput_event_get_gesture_event(event);
3746a46c0ec8Sopenharmony_ci	litest_assert_ptr_notnull(gevent);
3747a46c0ec8Sopenharmony_ci
3748a46c0ec8Sopenharmony_ci	if (nfingers != -1)
3749a46c0ec8Sopenharmony_ci		litest_assert_int_eq(libinput_event_gesture_get_finger_count(gevent),
3750a46c0ec8Sopenharmony_ci				     nfingers);
3751a46c0ec8Sopenharmony_ci	return gevent;
3752a46c0ec8Sopenharmony_ci}
3753a46c0ec8Sopenharmony_ci
3754a46c0ec8Sopenharmony_civoid
3755a46c0ec8Sopenharmony_cilitest_assert_gesture_event(struct libinput *li,
3756a46c0ec8Sopenharmony_ci			    enum libinput_event_type type,
3757a46c0ec8Sopenharmony_ci			    int nfingers)
3758a46c0ec8Sopenharmony_ci{
3759a46c0ec8Sopenharmony_ci	struct libinput_event *event;
3760a46c0ec8Sopenharmony_ci
3761a46c0ec8Sopenharmony_ci	litest_wait_for_event(li);
3762a46c0ec8Sopenharmony_ci	event = libinput_get_event(li);
3763a46c0ec8Sopenharmony_ci
3764a46c0ec8Sopenharmony_ci	litest_is_gesture_event(event, type, nfingers);
3765a46c0ec8Sopenharmony_ci	libinput_event_destroy(event);
3766a46c0ec8Sopenharmony_ci}
3767a46c0ec8Sopenharmony_ci
3768a46c0ec8Sopenharmony_cistruct libinput_event_tablet_tool *
3769a46c0ec8Sopenharmony_cilitest_is_tablet_event(struct libinput_event *event,
3770a46c0ec8Sopenharmony_ci		       enum libinput_event_type type)
3771a46c0ec8Sopenharmony_ci{
3772a46c0ec8Sopenharmony_ci	struct libinput_event_tablet_tool *tevent;
3773a46c0ec8Sopenharmony_ci
3774a46c0ec8Sopenharmony_ci	litest_assert_ptr_notnull(event);
3775a46c0ec8Sopenharmony_ci	litest_assert_event_type(event, type);
3776a46c0ec8Sopenharmony_ci
3777a46c0ec8Sopenharmony_ci	tevent = libinput_event_get_tablet_tool_event(event);
3778a46c0ec8Sopenharmony_ci	litest_assert_ptr_notnull(tevent);
3779a46c0ec8Sopenharmony_ci
3780a46c0ec8Sopenharmony_ci	return tevent;
3781a46c0ec8Sopenharmony_ci}
3782a46c0ec8Sopenharmony_ci
3783a46c0ec8Sopenharmony_civoid
3784a46c0ec8Sopenharmony_cilitest_assert_tablet_button_event(struct libinput *li, unsigned int button,
3785a46c0ec8Sopenharmony_ci				  enum libinput_button_state state)
3786a46c0ec8Sopenharmony_ci{
3787a46c0ec8Sopenharmony_ci	struct libinput_event *event;
3788a46c0ec8Sopenharmony_ci	struct libinput_event_tablet_tool *tev;
3789a46c0ec8Sopenharmony_ci	enum libinput_event_type type = LIBINPUT_EVENT_TABLET_TOOL_BUTTON;
3790a46c0ec8Sopenharmony_ci
3791a46c0ec8Sopenharmony_ci	litest_wait_for_event(li);
3792a46c0ec8Sopenharmony_ci	event = libinput_get_event(li);
3793a46c0ec8Sopenharmony_ci
3794a46c0ec8Sopenharmony_ci	litest_assert_notnull(event);
3795a46c0ec8Sopenharmony_ci	litest_assert_event_type(event, type);
3796a46c0ec8Sopenharmony_ci	tev = libinput_event_get_tablet_tool_event(event);
3797a46c0ec8Sopenharmony_ci	litest_assert_int_eq(libinput_event_tablet_tool_get_button(tev),
3798a46c0ec8Sopenharmony_ci			     button);
3799a46c0ec8Sopenharmony_ci	litest_assert_int_eq(libinput_event_tablet_tool_get_button_state(tev),
3800a46c0ec8Sopenharmony_ci			     state);
3801a46c0ec8Sopenharmony_ci	libinput_event_destroy(event);
3802a46c0ec8Sopenharmony_ci}
3803a46c0ec8Sopenharmony_ci
3804a46c0ec8Sopenharmony_ci
3805a46c0ec8Sopenharmony_cistruct libinput_event_tablet_tool *
3806a46c0ec8Sopenharmony_cilitest_is_proximity_event(struct libinput_event *event,
3807a46c0ec8Sopenharmony_ci			  enum libinput_tablet_tool_proximity_state state)
3808a46c0ec8Sopenharmony_ci{
3809a46c0ec8Sopenharmony_ci	struct libinput_event_tablet_tool *tev;
3810a46c0ec8Sopenharmony_ci	enum libinput_event_type type = LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY;
3811a46c0ec8Sopenharmony_ci
3812a46c0ec8Sopenharmony_ci	litest_assert_notnull(event);
3813a46c0ec8Sopenharmony_ci	litest_assert_event_type(event, type);
3814a46c0ec8Sopenharmony_ci	tev = libinput_event_get_tablet_tool_event(event);
3815a46c0ec8Sopenharmony_ci	litest_assert_int_eq(libinput_event_tablet_tool_get_proximity_state(tev),
3816a46c0ec8Sopenharmony_ci			     state);
3817a46c0ec8Sopenharmony_ci	return tev;
3818a46c0ec8Sopenharmony_ci}
3819a46c0ec8Sopenharmony_ci
3820a46c0ec8Sopenharmony_cidouble
3821a46c0ec8Sopenharmony_cilitest_event_pointer_get_value(struct libinput_event_pointer *ptrev,
3822a46c0ec8Sopenharmony_ci			       enum libinput_pointer_axis axis)
3823a46c0ec8Sopenharmony_ci{
3824a46c0ec8Sopenharmony_ci	struct libinput_event *event;
3825a46c0ec8Sopenharmony_ci	enum libinput_event_type type;
3826a46c0ec8Sopenharmony_ci
3827a46c0ec8Sopenharmony_ci	event = libinput_event_pointer_get_base_event(ptrev);
3828a46c0ec8Sopenharmony_ci	type = libinput_event_get_type(event);
3829a46c0ec8Sopenharmony_ci
3830a46c0ec8Sopenharmony_ci	switch (type) {
3831a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_POINTER_AXIS:
3832a46c0ec8Sopenharmony_ci		return libinput_event_pointer_get_axis_value(ptrev, axis);
3833a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_POINTER_SCROLL_WHEEL:
3834a46c0ec8Sopenharmony_ci		return libinput_event_pointer_get_scroll_value_v120(ptrev, axis);
3835a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_POINTER_SCROLL_FINGER:
3836a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_POINTER_SCROLL_CONTINUOUS:
3837a46c0ec8Sopenharmony_ci		return libinput_event_pointer_get_scroll_value(ptrev, axis);
3838a46c0ec8Sopenharmony_ci	default:
3839a46c0ec8Sopenharmony_ci		abort();
3840a46c0ec8Sopenharmony_ci	}
3841a46c0ec8Sopenharmony_ci}
3842a46c0ec8Sopenharmony_ci
3843a46c0ec8Sopenharmony_cienum libinput_pointer_axis_source
3844a46c0ec8Sopenharmony_cilitest_event_pointer_get_axis_source(struct libinput_event_pointer *ptrev)
3845a46c0ec8Sopenharmony_ci{
3846a46c0ec8Sopenharmony_ci	struct libinput_event *event;
3847a46c0ec8Sopenharmony_ci	enum libinput_event_type type;
3848a46c0ec8Sopenharmony_ci
3849a46c0ec8Sopenharmony_ci	event = libinput_event_pointer_get_base_event(ptrev);
3850a46c0ec8Sopenharmony_ci	type = libinput_event_get_type(event);
3851a46c0ec8Sopenharmony_ci
3852a46c0ec8Sopenharmony_ci	if (type == LIBINPUT_EVENT_POINTER_AXIS)
3853a46c0ec8Sopenharmony_ci		return libinput_event_pointer_get_axis_source(ptrev);
3854a46c0ec8Sopenharmony_ci
3855a46c0ec8Sopenharmony_ci	switch (type) {
3856a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_POINTER_SCROLL_WHEEL:
3857a46c0ec8Sopenharmony_ci		return LIBINPUT_POINTER_AXIS_SOURCE_WHEEL;
3858a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_POINTER_SCROLL_FINGER:
3859a46c0ec8Sopenharmony_ci		return LIBINPUT_POINTER_AXIS_SOURCE_FINGER;
3860a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_POINTER_SCROLL_CONTINUOUS:
3861a46c0ec8Sopenharmony_ci		return LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS;
3862a46c0ec8Sopenharmony_ci	default:
3863a46c0ec8Sopenharmony_ci		abort();
3864a46c0ec8Sopenharmony_ci	}
3865a46c0ec8Sopenharmony_ci}
3866a46c0ec8Sopenharmony_ci
3867a46c0ec8Sopenharmony_civoid litest_assert_tablet_proximity_event(struct libinput *li,
3868a46c0ec8Sopenharmony_ci					  enum libinput_tablet_tool_proximity_state state)
3869a46c0ec8Sopenharmony_ci{
3870a46c0ec8Sopenharmony_ci	struct libinput_event *event;
3871a46c0ec8Sopenharmony_ci
3872a46c0ec8Sopenharmony_ci	litest_wait_for_event(li);
3873a46c0ec8Sopenharmony_ci	event = libinput_get_event(li);
3874a46c0ec8Sopenharmony_ci	litest_is_proximity_event(event, state);
3875a46c0ec8Sopenharmony_ci	libinput_event_destroy(event);
3876a46c0ec8Sopenharmony_ci}
3877a46c0ec8Sopenharmony_ci
3878a46c0ec8Sopenharmony_civoid litest_assert_tablet_tip_event(struct libinput *li,
3879a46c0ec8Sopenharmony_ci				    enum libinput_tablet_tool_tip_state state)
3880a46c0ec8Sopenharmony_ci{
3881a46c0ec8Sopenharmony_ci	struct libinput_event *event;
3882a46c0ec8Sopenharmony_ci	struct libinput_event_tablet_tool *tev;
3883a46c0ec8Sopenharmony_ci	enum libinput_event_type type = LIBINPUT_EVENT_TABLET_TOOL_TIP;
3884a46c0ec8Sopenharmony_ci
3885a46c0ec8Sopenharmony_ci	litest_wait_for_event(li);
3886a46c0ec8Sopenharmony_ci	event = libinput_get_event(li);
3887a46c0ec8Sopenharmony_ci
3888a46c0ec8Sopenharmony_ci	litest_assert_notnull(event);
3889a46c0ec8Sopenharmony_ci	litest_assert_event_type(event, type);
3890a46c0ec8Sopenharmony_ci	tev = libinput_event_get_tablet_tool_event(event);
3891a46c0ec8Sopenharmony_ci	litest_assert_int_eq(libinput_event_tablet_tool_get_tip_state(tev),
3892a46c0ec8Sopenharmony_ci			     state);
3893a46c0ec8Sopenharmony_ci	libinput_event_destroy(event);
3894a46c0ec8Sopenharmony_ci}
3895a46c0ec8Sopenharmony_ci
3896a46c0ec8Sopenharmony_cistruct libinput_event_tablet_pad *
3897a46c0ec8Sopenharmony_cilitest_is_pad_button_event(struct libinput_event *event,
3898a46c0ec8Sopenharmony_ci			   unsigned int button,
3899a46c0ec8Sopenharmony_ci			   enum libinput_button_state state)
3900a46c0ec8Sopenharmony_ci{
3901a46c0ec8Sopenharmony_ci	struct libinput_event_tablet_pad *p;
3902a46c0ec8Sopenharmony_ci	enum libinput_event_type type = LIBINPUT_EVENT_TABLET_PAD_BUTTON;
3903a46c0ec8Sopenharmony_ci
3904a46c0ec8Sopenharmony_ci	litest_assert_ptr_notnull(event);
3905a46c0ec8Sopenharmony_ci	litest_assert_event_type(event, type);
3906a46c0ec8Sopenharmony_ci
3907a46c0ec8Sopenharmony_ci	p = libinput_event_get_tablet_pad_event(event);
3908a46c0ec8Sopenharmony_ci	litest_assert_ptr_notnull(p);
3909a46c0ec8Sopenharmony_ci
3910a46c0ec8Sopenharmony_ci	litest_assert_int_eq(libinput_event_tablet_pad_get_button_number(p),
3911a46c0ec8Sopenharmony_ci			     button);
3912a46c0ec8Sopenharmony_ci	litest_assert_int_eq(libinput_event_tablet_pad_get_button_state(p),
3913a46c0ec8Sopenharmony_ci			     state);
3914a46c0ec8Sopenharmony_ci
3915a46c0ec8Sopenharmony_ci	return p;
3916a46c0ec8Sopenharmony_ci}
3917a46c0ec8Sopenharmony_ci
3918a46c0ec8Sopenharmony_cistruct libinput_event_tablet_pad *
3919a46c0ec8Sopenharmony_cilitest_is_pad_ring_event(struct libinput_event *event,
3920a46c0ec8Sopenharmony_ci			 unsigned int number,
3921a46c0ec8Sopenharmony_ci			 enum libinput_tablet_pad_ring_axis_source source)
3922a46c0ec8Sopenharmony_ci{
3923a46c0ec8Sopenharmony_ci	struct libinput_event_tablet_pad *p;
3924a46c0ec8Sopenharmony_ci	enum libinput_event_type type = LIBINPUT_EVENT_TABLET_PAD_RING;
3925a46c0ec8Sopenharmony_ci
3926a46c0ec8Sopenharmony_ci	litest_assert_ptr_notnull(event);
3927a46c0ec8Sopenharmony_ci	litest_assert_event_type(event, type);
3928a46c0ec8Sopenharmony_ci	p = libinput_event_get_tablet_pad_event(event);
3929a46c0ec8Sopenharmony_ci
3930a46c0ec8Sopenharmony_ci	litest_assert_int_eq(libinput_event_tablet_pad_get_ring_number(p),
3931a46c0ec8Sopenharmony_ci			     number);
3932a46c0ec8Sopenharmony_ci	litest_assert_int_eq(libinput_event_tablet_pad_get_ring_source(p),
3933a46c0ec8Sopenharmony_ci			     source);
3934a46c0ec8Sopenharmony_ci
3935a46c0ec8Sopenharmony_ci	return p;
3936a46c0ec8Sopenharmony_ci}
3937a46c0ec8Sopenharmony_ci
3938a46c0ec8Sopenharmony_cistruct libinput_event_tablet_pad *
3939a46c0ec8Sopenharmony_cilitest_is_pad_strip_event(struct libinput_event *event,
3940a46c0ec8Sopenharmony_ci			  unsigned int number,
3941a46c0ec8Sopenharmony_ci			  enum libinput_tablet_pad_strip_axis_source source)
3942a46c0ec8Sopenharmony_ci{
3943a46c0ec8Sopenharmony_ci	struct libinput_event_tablet_pad *p;
3944a46c0ec8Sopenharmony_ci	enum libinput_event_type type = LIBINPUT_EVENT_TABLET_PAD_STRIP;
3945a46c0ec8Sopenharmony_ci
3946a46c0ec8Sopenharmony_ci	litest_assert_ptr_notnull(event);
3947a46c0ec8Sopenharmony_ci	litest_assert_event_type(event, type);
3948a46c0ec8Sopenharmony_ci	p = libinput_event_get_tablet_pad_event(event);
3949a46c0ec8Sopenharmony_ci
3950a46c0ec8Sopenharmony_ci	litest_assert_int_eq(libinput_event_tablet_pad_get_strip_number(p),
3951a46c0ec8Sopenharmony_ci			     number);
3952a46c0ec8Sopenharmony_ci	litest_assert_int_eq(libinput_event_tablet_pad_get_strip_source(p),
3953a46c0ec8Sopenharmony_ci			     source);
3954a46c0ec8Sopenharmony_ci
3955a46c0ec8Sopenharmony_ci	return p;
3956a46c0ec8Sopenharmony_ci}
3957a46c0ec8Sopenharmony_ci
3958a46c0ec8Sopenharmony_cistruct libinput_event_tablet_pad *
3959a46c0ec8Sopenharmony_cilitest_is_pad_key_event(struct libinput_event *event,
3960a46c0ec8Sopenharmony_ci			unsigned int key,
3961a46c0ec8Sopenharmony_ci			enum libinput_key_state state)
3962a46c0ec8Sopenharmony_ci{
3963a46c0ec8Sopenharmony_ci	struct libinput_event_tablet_pad *p;
3964a46c0ec8Sopenharmony_ci	enum libinput_event_type type = LIBINPUT_EVENT_TABLET_PAD_KEY;
3965a46c0ec8Sopenharmony_ci
3966a46c0ec8Sopenharmony_ci	litest_assert(event != NULL);
3967a46c0ec8Sopenharmony_ci	litest_assert_event_type(event, type);
3968a46c0ec8Sopenharmony_ci
3969a46c0ec8Sopenharmony_ci	p = libinput_event_get_tablet_pad_event(event);
3970a46c0ec8Sopenharmony_ci	litest_assert(p != NULL);
3971a46c0ec8Sopenharmony_ci
3972a46c0ec8Sopenharmony_ci	litest_assert_int_eq(libinput_event_tablet_pad_get_key(p), key);
3973a46c0ec8Sopenharmony_ci	litest_assert_int_eq(libinput_event_tablet_pad_get_key_state(p),
3974a46c0ec8Sopenharmony_ci			     state);
3975a46c0ec8Sopenharmony_ci
3976a46c0ec8Sopenharmony_ci	return p;
3977a46c0ec8Sopenharmony_ci}
3978a46c0ec8Sopenharmony_ci
3979a46c0ec8Sopenharmony_cistruct libinput_event_switch *
3980a46c0ec8Sopenharmony_cilitest_is_switch_event(struct libinput_event *event,
3981a46c0ec8Sopenharmony_ci		       enum libinput_switch sw,
3982a46c0ec8Sopenharmony_ci		       enum libinput_switch_state state)
3983a46c0ec8Sopenharmony_ci{
3984a46c0ec8Sopenharmony_ci	struct libinput_event_switch *swev;
3985a46c0ec8Sopenharmony_ci	enum libinput_event_type type = LIBINPUT_EVENT_SWITCH_TOGGLE;
3986a46c0ec8Sopenharmony_ci
3987a46c0ec8Sopenharmony_ci	litest_assert_notnull(event);
3988a46c0ec8Sopenharmony_ci	litest_assert_event_type(event, type);
3989a46c0ec8Sopenharmony_ci	swev = libinput_event_get_switch_event(event);
3990a46c0ec8Sopenharmony_ci
3991a46c0ec8Sopenharmony_ci	litest_assert_int_eq(libinput_event_switch_get_switch(swev), sw);
3992a46c0ec8Sopenharmony_ci	litest_assert_int_eq(libinput_event_switch_get_switch_state(swev),
3993a46c0ec8Sopenharmony_ci			     state);
3994a46c0ec8Sopenharmony_ci
3995a46c0ec8Sopenharmony_ci	return swev;
3996a46c0ec8Sopenharmony_ci}
3997a46c0ec8Sopenharmony_ci
3998a46c0ec8Sopenharmony_civoid
3999a46c0ec8Sopenharmony_cilitest_assert_switch_event(struct libinput *li,
4000a46c0ec8Sopenharmony_ci			   enum libinput_switch sw,
4001a46c0ec8Sopenharmony_ci			   enum libinput_switch_state state)
4002a46c0ec8Sopenharmony_ci{
4003a46c0ec8Sopenharmony_ci	struct libinput_event *event;
4004a46c0ec8Sopenharmony_ci
4005a46c0ec8Sopenharmony_ci	litest_wait_for_event(li);
4006a46c0ec8Sopenharmony_ci	event = libinput_get_event(li);
4007a46c0ec8Sopenharmony_ci
4008a46c0ec8Sopenharmony_ci	litest_is_switch_event(event, sw, state);
4009a46c0ec8Sopenharmony_ci
4010a46c0ec8Sopenharmony_ci	libinput_event_destroy(event);
4011a46c0ec8Sopenharmony_ci}
4012a46c0ec8Sopenharmony_ci
4013a46c0ec8Sopenharmony_civoid
4014a46c0ec8Sopenharmony_cilitest_assert_pad_button_event(struct libinput *li,
4015a46c0ec8Sopenharmony_ci			       unsigned int button,
4016a46c0ec8Sopenharmony_ci			       enum libinput_button_state state)
4017a46c0ec8Sopenharmony_ci{
4018a46c0ec8Sopenharmony_ci	struct libinput_event *event;
4019a46c0ec8Sopenharmony_ci
4020a46c0ec8Sopenharmony_ci	litest_wait_for_event(li);
4021a46c0ec8Sopenharmony_ci	event = libinput_get_event(li);
4022a46c0ec8Sopenharmony_ci
4023a46c0ec8Sopenharmony_ci	litest_is_pad_button_event(event, button, state);
4024a46c0ec8Sopenharmony_ci	libinput_event_destroy(event);
4025a46c0ec8Sopenharmony_ci}
4026a46c0ec8Sopenharmony_ci
4027a46c0ec8Sopenharmony_civoid
4028a46c0ec8Sopenharmony_cilitest_assert_pad_key_event(struct libinput *li,
4029a46c0ec8Sopenharmony_ci			    unsigned int key,
4030a46c0ec8Sopenharmony_ci			    enum libinput_key_state state)
4031a46c0ec8Sopenharmony_ci{
4032a46c0ec8Sopenharmony_ci	struct libinput_event *event;
4033a46c0ec8Sopenharmony_ci
4034a46c0ec8Sopenharmony_ci	litest_wait_for_event(li);
4035a46c0ec8Sopenharmony_ci	event = libinput_get_event(li);
4036a46c0ec8Sopenharmony_ci
4037a46c0ec8Sopenharmony_ci	litest_is_pad_key_event(event, key, state);
4038a46c0ec8Sopenharmony_ci	libinput_event_destroy(event);
4039a46c0ec8Sopenharmony_ci}
4040a46c0ec8Sopenharmony_ci
4041a46c0ec8Sopenharmony_civoid
4042a46c0ec8Sopenharmony_cilitest_assert_scroll(struct libinput *li,
4043a46c0ec8Sopenharmony_ci		     enum libinput_event_type axis_type,
4044a46c0ec8Sopenharmony_ci		     enum libinput_pointer_axis axis,
4045a46c0ec8Sopenharmony_ci		     int minimum_movement)
4046a46c0ec8Sopenharmony_ci{
4047a46c0ec8Sopenharmony_ci	struct libinput_event *event;
4048a46c0ec8Sopenharmony_ci	struct libinput_event_pointer *ptrev;
4049a46c0ec8Sopenharmony_ci	bool last_hi_res_event_found, last_low_res_event_found;
4050a46c0ec8Sopenharmony_ci	int value;
4051a46c0ec8Sopenharmony_ci	int nevents = 0;
4052a46c0ec8Sopenharmony_ci
4053a46c0ec8Sopenharmony_ci	litest_assert(axis_type == LIBINPUT_EVENT_POINTER_SCROLL_WHEEL ||
4054a46c0ec8Sopenharmony_ci		      axis_type == LIBINPUT_EVENT_POINTER_SCROLL_FINGER ||
4055a46c0ec8Sopenharmony_ci		      axis_type == LIBINPUT_EVENT_POINTER_SCROLL_CONTINUOUS);
4056a46c0ec8Sopenharmony_ci
4057a46c0ec8Sopenharmony_ci	last_hi_res_event_found = false;
4058a46c0ec8Sopenharmony_ci	last_low_res_event_found = false;
4059a46c0ec8Sopenharmony_ci	event = libinput_get_event(li);
4060a46c0ec8Sopenharmony_ci	litest_assert_ptr_notnull(event);
4061a46c0ec8Sopenharmony_ci
4062a46c0ec8Sopenharmony_ci	while (event) {
4063a46c0ec8Sopenharmony_ci		int min = minimum_movement;
4064a46c0ec8Sopenharmony_ci
4065a46c0ec8Sopenharmony_ci		ptrev = litest_is_axis_event(event, axis_type, axis, 0);
4066a46c0ec8Sopenharmony_ci		nevents++;
4067a46c0ec8Sopenharmony_ci
4068a46c0ec8Sopenharmony_ci		/* Due to how the hysteresis works on touchpad
4069a46c0ec8Sopenharmony_ci		 * events, the first event is reduced by the
4070a46c0ec8Sopenharmony_ci		 * hysteresis margin that can cause the first event
4071a46c0ec8Sopenharmony_ci		 * go under the minimum we expect for all other
4072a46c0ec8Sopenharmony_ci		 * events */
4073a46c0ec8Sopenharmony_ci		if (nevents == 1)
4074a46c0ec8Sopenharmony_ci			min = minimum_movement/2;
4075a46c0ec8Sopenharmony_ci
4076a46c0ec8Sopenharmony_ci		value = litest_event_pointer_get_value(ptrev, axis);
4077a46c0ec8Sopenharmony_ci		if (litest_is_high_res_axis_event(event)) {
4078a46c0ec8Sopenharmony_ci			litest_assert(!last_hi_res_event_found);
4079a46c0ec8Sopenharmony_ci
4080a46c0ec8Sopenharmony_ci			if (axis_type == LIBINPUT_EVENT_POINTER_SCROLL_WHEEL)
4081a46c0ec8Sopenharmony_ci				min *= 120;
4082a46c0ec8Sopenharmony_ci
4083a46c0ec8Sopenharmony_ci			if (value == 0)
4084a46c0ec8Sopenharmony_ci				last_hi_res_event_found = true;
4085a46c0ec8Sopenharmony_ci		} else {
4086a46c0ec8Sopenharmony_ci			litest_assert(!last_low_res_event_found);
4087a46c0ec8Sopenharmony_ci
4088a46c0ec8Sopenharmony_ci			if (value == 0)
4089a46c0ec8Sopenharmony_ci				last_low_res_event_found = true;
4090a46c0ec8Sopenharmony_ci		}
4091a46c0ec8Sopenharmony_ci
4092a46c0ec8Sopenharmony_ci		if (value != 0) {
4093a46c0ec8Sopenharmony_ci			if (minimum_movement > 0)
4094a46c0ec8Sopenharmony_ci				litest_assert_int_ge(value, min);
4095a46c0ec8Sopenharmony_ci			else
4096a46c0ec8Sopenharmony_ci				litest_assert_int_le(value, min);
4097a46c0ec8Sopenharmony_ci		}
4098a46c0ec8Sopenharmony_ci
4099a46c0ec8Sopenharmony_ci		libinput_event_destroy(event);
4100a46c0ec8Sopenharmony_ci		event = libinput_get_event(li);
4101a46c0ec8Sopenharmony_ci	}
4102a46c0ec8Sopenharmony_ci
4103a46c0ec8Sopenharmony_ci	litest_assert(last_low_res_event_found);
4104a46c0ec8Sopenharmony_ci	litest_assert(last_hi_res_event_found);
4105a46c0ec8Sopenharmony_ci}
4106a46c0ec8Sopenharmony_ci
4107a46c0ec8Sopenharmony_civoid
4108a46c0ec8Sopenharmony_cilitest_assert_axis_end_sequence(struct libinput *li,
4109a46c0ec8Sopenharmony_ci				enum libinput_event_type axis_type,
4110a46c0ec8Sopenharmony_ci				enum libinput_pointer_axis axis,
4111a46c0ec8Sopenharmony_ci				enum libinput_pointer_axis_source source)
4112a46c0ec8Sopenharmony_ci{
4113a46c0ec8Sopenharmony_ci	struct libinput_event *event;
4114a46c0ec8Sopenharmony_ci	struct libinput_event_pointer *ptrev;
4115a46c0ec8Sopenharmony_ci	bool last_hi_res_event_found, last_low_res_event_found;
4116a46c0ec8Sopenharmony_ci	double val;
4117a46c0ec8Sopenharmony_ci	int i;
4118a46c0ec8Sopenharmony_ci
4119a46c0ec8Sopenharmony_ci	litest_assert(axis_type == LIBINPUT_EVENT_POINTER_SCROLL_WHEEL ||
4120a46c0ec8Sopenharmony_ci		      axis_type == LIBINPUT_EVENT_POINTER_SCROLL_FINGER ||
4121a46c0ec8Sopenharmony_ci		      axis_type == LIBINPUT_EVENT_POINTER_SCROLL_CONTINUOUS);
4122a46c0ec8Sopenharmony_ci
4123a46c0ec8Sopenharmony_ci	last_hi_res_event_found = false;
4124a46c0ec8Sopenharmony_ci	last_low_res_event_found = false;
4125a46c0ec8Sopenharmony_ci
4126a46c0ec8Sopenharmony_ci	/* both high and low scroll end events must be sent */
4127a46c0ec8Sopenharmony_ci	for (i = 0; i < 2; i++) {
4128a46c0ec8Sopenharmony_ci		event = libinput_get_event(li);
4129a46c0ec8Sopenharmony_ci		ptrev = litest_is_axis_event(event, axis_type, axis, source);
4130a46c0ec8Sopenharmony_ci		val = litest_event_pointer_get_value(ptrev, axis);
4131a46c0ec8Sopenharmony_ci		ck_assert(val == 0.0);
4132a46c0ec8Sopenharmony_ci
4133a46c0ec8Sopenharmony_ci		if (litest_is_high_res_axis_event(event)) {
4134a46c0ec8Sopenharmony_ci			litest_assert(!last_hi_res_event_found);
4135a46c0ec8Sopenharmony_ci			last_hi_res_event_found = true;
4136a46c0ec8Sopenharmony_ci		} else {
4137a46c0ec8Sopenharmony_ci			litest_assert(!last_low_res_event_found);
4138a46c0ec8Sopenharmony_ci			last_low_res_event_found = true;
4139a46c0ec8Sopenharmony_ci		}
4140a46c0ec8Sopenharmony_ci
4141a46c0ec8Sopenharmony_ci		libinput_event_destroy(event);
4142a46c0ec8Sopenharmony_ci	}
4143a46c0ec8Sopenharmony_ci
4144a46c0ec8Sopenharmony_ci	litest_assert(last_low_res_event_found);
4145a46c0ec8Sopenharmony_ci	litest_assert(last_hi_res_event_found);
4146a46c0ec8Sopenharmony_ci}
4147a46c0ec8Sopenharmony_ci
4148a46c0ec8Sopenharmony_civoid
4149a46c0ec8Sopenharmony_cilitest_assert_only_typed_events(struct libinput *li,
4150a46c0ec8Sopenharmony_ci				enum libinput_event_type type)
4151a46c0ec8Sopenharmony_ci{
4152a46c0ec8Sopenharmony_ci	struct libinput_event *event;
4153a46c0ec8Sopenharmony_ci
4154a46c0ec8Sopenharmony_ci	litest_assert(type != LIBINPUT_EVENT_NONE);
4155a46c0ec8Sopenharmony_ci
4156a46c0ec8Sopenharmony_ci	libinput_dispatch(li);
4157a46c0ec8Sopenharmony_ci	event = libinput_get_event(li);
4158a46c0ec8Sopenharmony_ci	litest_assert_notnull(event);
4159a46c0ec8Sopenharmony_ci
4160a46c0ec8Sopenharmony_ci	while (event) {
4161a46c0ec8Sopenharmony_ci		litest_assert_event_type(event, type);
4162a46c0ec8Sopenharmony_ci		libinput_event_destroy(event);
4163a46c0ec8Sopenharmony_ci		libinput_dispatch(li);
4164a46c0ec8Sopenharmony_ci		event = libinput_get_event(li);
4165a46c0ec8Sopenharmony_ci	}
4166a46c0ec8Sopenharmony_ci}
4167a46c0ec8Sopenharmony_ci
4168a46c0ec8Sopenharmony_civoid
4169a46c0ec8Sopenharmony_cilitest_assert_only_axis_events(struct libinput *li,
4170a46c0ec8Sopenharmony_ci			       enum libinput_event_type axis_type)
4171a46c0ec8Sopenharmony_ci{
4172a46c0ec8Sopenharmony_ci	struct libinput_event *event;
4173a46c0ec8Sopenharmony_ci
4174a46c0ec8Sopenharmony_ci	litest_assert(axis_type == LIBINPUT_EVENT_POINTER_SCROLL_WHEEL ||
4175a46c0ec8Sopenharmony_ci		      axis_type == LIBINPUT_EVENT_POINTER_SCROLL_FINGER ||
4176a46c0ec8Sopenharmony_ci		      axis_type == LIBINPUT_EVENT_POINTER_SCROLL_CONTINUOUS);
4177a46c0ec8Sopenharmony_ci
4178a46c0ec8Sopenharmony_ci	libinput_dispatch(li);
4179a46c0ec8Sopenharmony_ci	event = libinput_get_event(li);
4180a46c0ec8Sopenharmony_ci	litest_assert_notnull(event);
4181a46c0ec8Sopenharmony_ci
4182a46c0ec8Sopenharmony_ci	while (event) {
4183a46c0ec8Sopenharmony_ci		litest_assert_event_type_is_one_of(event,
4184a46c0ec8Sopenharmony_ci						   LIBINPUT_EVENT_POINTER_AXIS,
4185a46c0ec8Sopenharmony_ci						   axis_type);
4186a46c0ec8Sopenharmony_ci		libinput_event_destroy(event);
4187a46c0ec8Sopenharmony_ci		libinput_dispatch(li);
4188a46c0ec8Sopenharmony_ci		event = libinput_get_event(li);
4189a46c0ec8Sopenharmony_ci	}
4190a46c0ec8Sopenharmony_ci}
4191a46c0ec8Sopenharmony_ci
4192a46c0ec8Sopenharmony_civoid
4193a46c0ec8Sopenharmony_cilitest_assert_no_typed_events(struct libinput *li,
4194a46c0ec8Sopenharmony_ci			      enum libinput_event_type type)
4195a46c0ec8Sopenharmony_ci{
4196a46c0ec8Sopenharmony_ci	struct libinput_event *event;
4197a46c0ec8Sopenharmony_ci
4198a46c0ec8Sopenharmony_ci	litest_assert(type != LIBINPUT_EVENT_NONE);
4199a46c0ec8Sopenharmony_ci
4200a46c0ec8Sopenharmony_ci	libinput_dispatch(li);
4201a46c0ec8Sopenharmony_ci	event = libinput_get_event(li);
4202a46c0ec8Sopenharmony_ci
4203a46c0ec8Sopenharmony_ci	while (event) {
4204a46c0ec8Sopenharmony_ci		litest_assert_int_ne(libinput_event_get_type(event),
4205a46c0ec8Sopenharmony_ci                                     type);
4206a46c0ec8Sopenharmony_ci		libinput_event_destroy(event);
4207a46c0ec8Sopenharmony_ci		libinput_dispatch(li);
4208a46c0ec8Sopenharmony_ci		event = libinput_get_event(li);
4209a46c0ec8Sopenharmony_ci	}
4210a46c0ec8Sopenharmony_ci}
4211a46c0ec8Sopenharmony_ci
4212a46c0ec8Sopenharmony_civoid
4213a46c0ec8Sopenharmony_cilitest_assert_touch_sequence(struct libinput *li)
4214a46c0ec8Sopenharmony_ci{
4215a46c0ec8Sopenharmony_ci	struct libinput_event *event;
4216a46c0ec8Sopenharmony_ci	struct libinput_event_touch *tev;
4217a46c0ec8Sopenharmony_ci	int slot;
4218a46c0ec8Sopenharmony_ci
4219a46c0ec8Sopenharmony_ci	event = libinput_get_event(li);
4220a46c0ec8Sopenharmony_ci	tev = litest_is_touch_event(event, LIBINPUT_EVENT_TOUCH_DOWN);
4221a46c0ec8Sopenharmony_ci	slot = libinput_event_touch_get_slot(tev);
4222a46c0ec8Sopenharmony_ci	libinput_event_destroy(event);
4223a46c0ec8Sopenharmony_ci
4224a46c0ec8Sopenharmony_ci	event = libinput_get_event(li);
4225a46c0ec8Sopenharmony_ci	litest_is_touch_event(event, LIBINPUT_EVENT_TOUCH_FRAME);
4226a46c0ec8Sopenharmony_ci	libinput_event_destroy(event);
4227a46c0ec8Sopenharmony_ci
4228a46c0ec8Sopenharmony_ci	event = libinput_get_event(li);
4229a46c0ec8Sopenharmony_ci	do {
4230a46c0ec8Sopenharmony_ci		tev = litest_is_touch_event(event, LIBINPUT_EVENT_TOUCH_MOTION);
4231a46c0ec8Sopenharmony_ci		litest_assert_int_eq(slot, libinput_event_touch_get_slot(tev));
4232a46c0ec8Sopenharmony_ci		libinput_event_destroy(event);
4233a46c0ec8Sopenharmony_ci
4234a46c0ec8Sopenharmony_ci		event = libinput_get_event(li);
4235a46c0ec8Sopenharmony_ci		litest_is_touch_event(event, LIBINPUT_EVENT_TOUCH_FRAME);
4236a46c0ec8Sopenharmony_ci		libinput_event_destroy(event);
4237a46c0ec8Sopenharmony_ci
4238a46c0ec8Sopenharmony_ci		event = libinput_get_event(li);
4239a46c0ec8Sopenharmony_ci		litest_assert_notnull(event);
4240a46c0ec8Sopenharmony_ci	} while (libinput_event_get_type(event) != LIBINPUT_EVENT_TOUCH_UP);
4241a46c0ec8Sopenharmony_ci
4242a46c0ec8Sopenharmony_ci	tev = litest_is_touch_event(event, LIBINPUT_EVENT_TOUCH_UP);
4243a46c0ec8Sopenharmony_ci	litest_assert_int_eq(slot, libinput_event_touch_get_slot(tev));
4244a46c0ec8Sopenharmony_ci	libinput_event_destroy(event);
4245a46c0ec8Sopenharmony_ci	event = libinput_get_event(li);
4246a46c0ec8Sopenharmony_ci	litest_is_touch_event(event, LIBINPUT_EVENT_TOUCH_FRAME);
4247a46c0ec8Sopenharmony_ci	libinput_event_destroy(event);
4248a46c0ec8Sopenharmony_ci}
4249a46c0ec8Sopenharmony_ci
4250a46c0ec8Sopenharmony_civoid
4251a46c0ec8Sopenharmony_cilitest_assert_touch_motion_frame(struct libinput *li)
4252a46c0ec8Sopenharmony_ci{
4253a46c0ec8Sopenharmony_ci	struct libinput_event *event;
4254a46c0ec8Sopenharmony_ci
4255a46c0ec8Sopenharmony_ci	/* expect at least one, but maybe more */
4256a46c0ec8Sopenharmony_ci	event = libinput_get_event(li);
4257a46c0ec8Sopenharmony_ci	litest_is_touch_event(event, LIBINPUT_EVENT_TOUCH_MOTION);
4258a46c0ec8Sopenharmony_ci	libinput_event_destroy(event);
4259a46c0ec8Sopenharmony_ci
4260a46c0ec8Sopenharmony_ci	event = libinput_get_event(li);
4261a46c0ec8Sopenharmony_ci	litest_is_touch_event(event, LIBINPUT_EVENT_TOUCH_FRAME);
4262a46c0ec8Sopenharmony_ci	libinput_event_destroy(event);
4263a46c0ec8Sopenharmony_ci
4264a46c0ec8Sopenharmony_ci	event = libinput_get_event(li);
4265a46c0ec8Sopenharmony_ci	while (event) {
4266a46c0ec8Sopenharmony_ci		litest_is_touch_event(event, LIBINPUT_EVENT_TOUCH_MOTION);
4267a46c0ec8Sopenharmony_ci		libinput_event_destroy(event);
4268a46c0ec8Sopenharmony_ci
4269a46c0ec8Sopenharmony_ci		event = libinput_get_event(li);
4270a46c0ec8Sopenharmony_ci		litest_is_touch_event(event, LIBINPUT_EVENT_TOUCH_FRAME);
4271a46c0ec8Sopenharmony_ci		libinput_event_destroy(event);
4272a46c0ec8Sopenharmony_ci
4273a46c0ec8Sopenharmony_ci		event = libinput_get_event(li);
4274a46c0ec8Sopenharmony_ci	}
4275a46c0ec8Sopenharmony_ci}
4276a46c0ec8Sopenharmony_ci
4277a46c0ec8Sopenharmony_civoid
4278a46c0ec8Sopenharmony_cilitest_assert_touch_down_frame(struct libinput *li)
4279a46c0ec8Sopenharmony_ci{
4280a46c0ec8Sopenharmony_ci	struct libinput_event *event;
4281a46c0ec8Sopenharmony_ci
4282a46c0ec8Sopenharmony_ci	event = libinput_get_event(li);
4283a46c0ec8Sopenharmony_ci	litest_is_touch_event(event, LIBINPUT_EVENT_TOUCH_DOWN);
4284a46c0ec8Sopenharmony_ci	libinput_event_destroy(event);
4285a46c0ec8Sopenharmony_ci
4286a46c0ec8Sopenharmony_ci	event = libinput_get_event(li);
4287a46c0ec8Sopenharmony_ci	litest_is_touch_event(event, LIBINPUT_EVENT_TOUCH_FRAME);
4288a46c0ec8Sopenharmony_ci	libinput_event_destroy(event);
4289a46c0ec8Sopenharmony_ci}
4290a46c0ec8Sopenharmony_ci
4291a46c0ec8Sopenharmony_civoid
4292a46c0ec8Sopenharmony_cilitest_assert_touch_up_frame(struct libinput *li)
4293a46c0ec8Sopenharmony_ci{
4294a46c0ec8Sopenharmony_ci	struct libinput_event *event;
4295a46c0ec8Sopenharmony_ci
4296a46c0ec8Sopenharmony_ci	event = libinput_get_event(li);
4297a46c0ec8Sopenharmony_ci	litest_is_touch_event(event, LIBINPUT_EVENT_TOUCH_UP);
4298a46c0ec8Sopenharmony_ci	libinput_event_destroy(event);
4299a46c0ec8Sopenharmony_ci
4300a46c0ec8Sopenharmony_ci	event = libinput_get_event(li);
4301a46c0ec8Sopenharmony_ci	litest_is_touch_event(event, LIBINPUT_EVENT_TOUCH_FRAME);
4302a46c0ec8Sopenharmony_ci	libinput_event_destroy(event);
4303a46c0ec8Sopenharmony_ci}
4304a46c0ec8Sopenharmony_ci
4305a46c0ec8Sopenharmony_civoid
4306a46c0ec8Sopenharmony_cilitest_assert_touch_cancel(struct libinput *li)
4307a46c0ec8Sopenharmony_ci{
4308a46c0ec8Sopenharmony_ci	struct libinput_event *event;
4309a46c0ec8Sopenharmony_ci
4310a46c0ec8Sopenharmony_ci	event = libinput_get_event(li);
4311a46c0ec8Sopenharmony_ci	litest_is_touch_event(event, LIBINPUT_EVENT_TOUCH_CANCEL);
4312a46c0ec8Sopenharmony_ci	libinput_event_destroy(event);
4313a46c0ec8Sopenharmony_ci
4314a46c0ec8Sopenharmony_ci	event = libinput_get_event(li);
4315a46c0ec8Sopenharmony_ci	litest_is_touch_event(event, LIBINPUT_EVENT_TOUCH_FRAME);
4316a46c0ec8Sopenharmony_ci	libinput_event_destroy(event);
4317a46c0ec8Sopenharmony_ci}
4318a46c0ec8Sopenharmony_ci
4319a46c0ec8Sopenharmony_civoid
4320a46c0ec8Sopenharmony_cilitest_timeout_tap(void)
4321a46c0ec8Sopenharmony_ci{
4322a46c0ec8Sopenharmony_ci	msleep(300);
4323a46c0ec8Sopenharmony_ci}
4324a46c0ec8Sopenharmony_ci
4325a46c0ec8Sopenharmony_civoid
4326a46c0ec8Sopenharmony_cilitest_timeout_tapndrag(void)
4327a46c0ec8Sopenharmony_ci{
4328a46c0ec8Sopenharmony_ci	msleep(520);
4329a46c0ec8Sopenharmony_ci}
4330a46c0ec8Sopenharmony_ci
4331a46c0ec8Sopenharmony_civoid
4332a46c0ec8Sopenharmony_cilitest_timeout_debounce(void)
4333a46c0ec8Sopenharmony_ci{
4334a46c0ec8Sopenharmony_ci	msleep(30);
4335a46c0ec8Sopenharmony_ci}
4336a46c0ec8Sopenharmony_ci
4337a46c0ec8Sopenharmony_civoid
4338a46c0ec8Sopenharmony_cilitest_timeout_softbuttons(void)
4339a46c0ec8Sopenharmony_ci{
4340a46c0ec8Sopenharmony_ci	msleep(300);
4341a46c0ec8Sopenharmony_ci}
4342a46c0ec8Sopenharmony_ci
4343a46c0ec8Sopenharmony_civoid
4344a46c0ec8Sopenharmony_cilitest_timeout_buttonscroll(void)
4345a46c0ec8Sopenharmony_ci{
4346a46c0ec8Sopenharmony_ci	msleep(300);
4347a46c0ec8Sopenharmony_ci}
4348a46c0ec8Sopenharmony_ci
4349a46c0ec8Sopenharmony_civoid
4350a46c0ec8Sopenharmony_cilitest_timeout_finger_switch(void)
4351a46c0ec8Sopenharmony_ci{
4352a46c0ec8Sopenharmony_ci	msleep(120);
4353a46c0ec8Sopenharmony_ci}
4354a46c0ec8Sopenharmony_ci
4355a46c0ec8Sopenharmony_civoid
4356a46c0ec8Sopenharmony_cilitest_timeout_wheel_scroll(void)
4357a46c0ec8Sopenharmony_ci{
4358a46c0ec8Sopenharmony_ci	msleep(600);
4359a46c0ec8Sopenharmony_ci}
4360a46c0ec8Sopenharmony_ci
4361a46c0ec8Sopenharmony_civoid
4362a46c0ec8Sopenharmony_cilitest_timeout_edgescroll(void)
4363a46c0ec8Sopenharmony_ci{
4364a46c0ec8Sopenharmony_ci	msleep(300);
4365a46c0ec8Sopenharmony_ci}
4366a46c0ec8Sopenharmony_ci
4367a46c0ec8Sopenharmony_civoid
4368a46c0ec8Sopenharmony_cilitest_timeout_middlebutton(void)
4369a46c0ec8Sopenharmony_ci{
4370a46c0ec8Sopenharmony_ci	msleep(70);
4371a46c0ec8Sopenharmony_ci}
4372a46c0ec8Sopenharmony_ci
4373a46c0ec8Sopenharmony_civoid
4374a46c0ec8Sopenharmony_cilitest_timeout_dwt_short(void)
4375a46c0ec8Sopenharmony_ci{
4376a46c0ec8Sopenharmony_ci	msleep(220);
4377a46c0ec8Sopenharmony_ci}
4378a46c0ec8Sopenharmony_ci
4379a46c0ec8Sopenharmony_civoid
4380a46c0ec8Sopenharmony_cilitest_timeout_dwt_long(void)
4381a46c0ec8Sopenharmony_ci{
4382a46c0ec8Sopenharmony_ci	msleep(520);
4383a46c0ec8Sopenharmony_ci}
4384a46c0ec8Sopenharmony_ci
4385a46c0ec8Sopenharmony_civoid
4386a46c0ec8Sopenharmony_cilitest_timeout_gesture(void)
4387a46c0ec8Sopenharmony_ci{
4388a46c0ec8Sopenharmony_ci	msleep(120);
4389a46c0ec8Sopenharmony_ci}
4390a46c0ec8Sopenharmony_ci
4391a46c0ec8Sopenharmony_civoid
4392a46c0ec8Sopenharmony_cilitest_timeout_gesture_scroll(void)
4393a46c0ec8Sopenharmony_ci{
4394a46c0ec8Sopenharmony_ci	msleep(180);
4395a46c0ec8Sopenharmony_ci}
4396a46c0ec8Sopenharmony_ci
4397a46c0ec8Sopenharmony_civoid
4398a46c0ec8Sopenharmony_cilitest_timeout_gesture_hold(void)
4399a46c0ec8Sopenharmony_ci{
4400a46c0ec8Sopenharmony_ci	msleep(300);
4401a46c0ec8Sopenharmony_ci}
4402a46c0ec8Sopenharmony_ci
4403a46c0ec8Sopenharmony_civoid
4404a46c0ec8Sopenharmony_cilitest_timeout_gesture_quick_hold(void)
4405a46c0ec8Sopenharmony_ci{
4406a46c0ec8Sopenharmony_ci	msleep(60);
4407a46c0ec8Sopenharmony_ci}
4408a46c0ec8Sopenharmony_ci
4409a46c0ec8Sopenharmony_civoid
4410a46c0ec8Sopenharmony_cilitest_timeout_trackpoint(void)
4411a46c0ec8Sopenharmony_ci{
4412a46c0ec8Sopenharmony_ci	msleep(320);
4413a46c0ec8Sopenharmony_ci}
4414a46c0ec8Sopenharmony_ci
4415a46c0ec8Sopenharmony_civoid
4416a46c0ec8Sopenharmony_cilitest_timeout_tablet_proxout(void)
4417a46c0ec8Sopenharmony_ci{
4418a46c0ec8Sopenharmony_ci	msleep(170);
4419a46c0ec8Sopenharmony_ci}
4420a46c0ec8Sopenharmony_ci
4421a46c0ec8Sopenharmony_civoid
4422a46c0ec8Sopenharmony_cilitest_timeout_touch_arbitration(void)
4423a46c0ec8Sopenharmony_ci{
4424a46c0ec8Sopenharmony_ci	msleep(100);
4425a46c0ec8Sopenharmony_ci}
4426a46c0ec8Sopenharmony_ci
4427a46c0ec8Sopenharmony_civoid
4428a46c0ec8Sopenharmony_cilitest_timeout_hysteresis(void)
4429a46c0ec8Sopenharmony_ci{
4430a46c0ec8Sopenharmony_ci	msleep(90);
4431a46c0ec8Sopenharmony_ci}
4432a46c0ec8Sopenharmony_ci
4433a46c0ec8Sopenharmony_civoid
4434a46c0ec8Sopenharmony_cilitest_push_event_frame(struct litest_device *dev)
4435a46c0ec8Sopenharmony_ci{
4436a46c0ec8Sopenharmony_ci	litest_assert_int_ge(dev->skip_ev_syn, 0);
4437a46c0ec8Sopenharmony_ci	dev->skip_ev_syn++;
4438a46c0ec8Sopenharmony_ci}
4439a46c0ec8Sopenharmony_ci
4440a46c0ec8Sopenharmony_civoid
4441a46c0ec8Sopenharmony_cilitest_pop_event_frame(struct litest_device *dev)
4442a46c0ec8Sopenharmony_ci{
4443a46c0ec8Sopenharmony_ci	litest_assert_int_gt(dev->skip_ev_syn, 0);
4444a46c0ec8Sopenharmony_ci	dev->skip_ev_syn--;
4445a46c0ec8Sopenharmony_ci	if (dev->skip_ev_syn == 0)
4446a46c0ec8Sopenharmony_ci		litest_event(dev, EV_SYN, SYN_REPORT, 0);
4447a46c0ec8Sopenharmony_ci}
4448a46c0ec8Sopenharmony_ci
4449a46c0ec8Sopenharmony_civoid
4450a46c0ec8Sopenharmony_cilitest_filter_event(struct litest_device *dev,
4451a46c0ec8Sopenharmony_ci		    unsigned int type,
4452a46c0ec8Sopenharmony_ci		    unsigned int code)
4453a46c0ec8Sopenharmony_ci{
4454a46c0ec8Sopenharmony_ci	libevdev_disable_event_code(dev->evdev, type, code);
4455a46c0ec8Sopenharmony_ci}
4456a46c0ec8Sopenharmony_ci
4457a46c0ec8Sopenharmony_civoid
4458a46c0ec8Sopenharmony_cilitest_unfilter_event(struct litest_device *dev,
4459a46c0ec8Sopenharmony_ci		      unsigned int type,
4460a46c0ec8Sopenharmony_ci		      unsigned int code)
4461a46c0ec8Sopenharmony_ci{
4462a46c0ec8Sopenharmony_ci	/* would need an non-NULL argument for re-enabling, so simply abort
4463a46c0ec8Sopenharmony_ci	 * until we need to be more sophisticated */
4464a46c0ec8Sopenharmony_ci	litest_assert_int_ne(type, (unsigned int)EV_ABS);
4465a46c0ec8Sopenharmony_ci
4466a46c0ec8Sopenharmony_ci	libevdev_enable_event_code(dev->evdev, type, code, NULL);
4467a46c0ec8Sopenharmony_ci}
4468a46c0ec8Sopenharmony_ci
4469a46c0ec8Sopenharmony_cistatic void
4470a46c0ec8Sopenharmony_cisend_abs_xy(struct litest_device *d, double x, double y)
4471a46c0ec8Sopenharmony_ci{
4472a46c0ec8Sopenharmony_ci	struct input_event e;
4473a46c0ec8Sopenharmony_ci	int val;
4474a46c0ec8Sopenharmony_ci
4475a46c0ec8Sopenharmony_ci	e.type = EV_ABS;
4476a46c0ec8Sopenharmony_ci	e.code = ABS_X;
4477a46c0ec8Sopenharmony_ci	e.value = LITEST_AUTO_ASSIGN;
4478a46c0ec8Sopenharmony_ci	val = litest_auto_assign_value(d, &e, 0, x, y, NULL, true);
4479a46c0ec8Sopenharmony_ci	litest_event(d, EV_ABS, ABS_X, val);
4480a46c0ec8Sopenharmony_ci
4481a46c0ec8Sopenharmony_ci	e.code = ABS_Y;
4482a46c0ec8Sopenharmony_ci	val = litest_auto_assign_value(d, &e, 0, x, y, NULL, true);
4483a46c0ec8Sopenharmony_ci	litest_event(d, EV_ABS, ABS_Y, val);
4484a46c0ec8Sopenharmony_ci}
4485a46c0ec8Sopenharmony_ci
4486a46c0ec8Sopenharmony_cistatic void
4487a46c0ec8Sopenharmony_cisend_abs_mt_xy(struct litest_device *d, double x, double y)
4488a46c0ec8Sopenharmony_ci{
4489a46c0ec8Sopenharmony_ci	struct input_event e;
4490a46c0ec8Sopenharmony_ci	int val;
4491a46c0ec8Sopenharmony_ci
4492a46c0ec8Sopenharmony_ci	e.type = EV_ABS;
4493a46c0ec8Sopenharmony_ci	e.code = ABS_MT_POSITION_X;
4494a46c0ec8Sopenharmony_ci	e.value = LITEST_AUTO_ASSIGN;
4495a46c0ec8Sopenharmony_ci	val = litest_auto_assign_value(d, &e, 0, x, y, NULL, true);
4496a46c0ec8Sopenharmony_ci	litest_event(d, EV_ABS, ABS_MT_POSITION_X, val);
4497a46c0ec8Sopenharmony_ci
4498a46c0ec8Sopenharmony_ci	e.code = ABS_MT_POSITION_Y;
4499a46c0ec8Sopenharmony_ci	e.value = LITEST_AUTO_ASSIGN;
4500a46c0ec8Sopenharmony_ci	val = litest_auto_assign_value(d, &e, 0, x, y, NULL, true);
4501a46c0ec8Sopenharmony_ci	litest_event(d, EV_ABS, ABS_MT_POSITION_Y, val);
4502a46c0ec8Sopenharmony_ci}
4503a46c0ec8Sopenharmony_ci
4504a46c0ec8Sopenharmony_civoid
4505a46c0ec8Sopenharmony_cilitest_semi_mt_touch_down(struct litest_device *d,
4506a46c0ec8Sopenharmony_ci			  struct litest_semi_mt *semi_mt,
4507a46c0ec8Sopenharmony_ci			  unsigned int slot,
4508a46c0ec8Sopenharmony_ci			  double x, double y)
4509a46c0ec8Sopenharmony_ci{
4510a46c0ec8Sopenharmony_ci	double t, l, r = 0, b = 0; /* top, left, right, bottom */
4511a46c0ec8Sopenharmony_ci
4512a46c0ec8Sopenharmony_ci	if (d->ntouches_down > 2 || slot > 1)
4513a46c0ec8Sopenharmony_ci		return;
4514a46c0ec8Sopenharmony_ci
4515a46c0ec8Sopenharmony_ci	if (d->ntouches_down == 1) {
4516a46c0ec8Sopenharmony_ci		l = x;
4517a46c0ec8Sopenharmony_ci		t = y;
4518a46c0ec8Sopenharmony_ci	} else {
4519a46c0ec8Sopenharmony_ci		int other = (slot + 1) % 2;
4520a46c0ec8Sopenharmony_ci		l = min(x, semi_mt->touches[other].x);
4521a46c0ec8Sopenharmony_ci		t = min(y, semi_mt->touches[other].y);
4522a46c0ec8Sopenharmony_ci		r = max(x, semi_mt->touches[other].x);
4523a46c0ec8Sopenharmony_ci		b = max(y, semi_mt->touches[other].y);
4524a46c0ec8Sopenharmony_ci	}
4525a46c0ec8Sopenharmony_ci
4526a46c0ec8Sopenharmony_ci	send_abs_xy(d, l, t);
4527a46c0ec8Sopenharmony_ci
4528a46c0ec8Sopenharmony_ci	litest_event(d, EV_ABS, ABS_MT_SLOT, 0);
4529a46c0ec8Sopenharmony_ci
4530a46c0ec8Sopenharmony_ci	if (d->ntouches_down == 1)
4531a46c0ec8Sopenharmony_ci		litest_event(d, EV_ABS, ABS_MT_TRACKING_ID, ++semi_mt->tracking_id);
4532a46c0ec8Sopenharmony_ci
4533a46c0ec8Sopenharmony_ci	send_abs_mt_xy(d, l, t);
4534a46c0ec8Sopenharmony_ci
4535a46c0ec8Sopenharmony_ci	if (d->ntouches_down == 2) {
4536a46c0ec8Sopenharmony_ci		litest_event(d, EV_ABS, ABS_MT_SLOT, 1);
4537a46c0ec8Sopenharmony_ci		litest_event(d, EV_ABS, ABS_MT_TRACKING_ID, ++semi_mt->tracking_id);
4538a46c0ec8Sopenharmony_ci
4539a46c0ec8Sopenharmony_ci		send_abs_mt_xy(d, r, b);
4540a46c0ec8Sopenharmony_ci	}
4541a46c0ec8Sopenharmony_ci
4542a46c0ec8Sopenharmony_ci	litest_event(d, EV_SYN, SYN_REPORT, 0);
4543a46c0ec8Sopenharmony_ci
4544a46c0ec8Sopenharmony_ci	semi_mt->touches[slot].x = x;
4545a46c0ec8Sopenharmony_ci	semi_mt->touches[slot].y = y;
4546a46c0ec8Sopenharmony_ci}
4547a46c0ec8Sopenharmony_ci
4548a46c0ec8Sopenharmony_civoid
4549a46c0ec8Sopenharmony_cilitest_semi_mt_touch_move(struct litest_device *d,
4550a46c0ec8Sopenharmony_ci			  struct litest_semi_mt *semi_mt,
4551a46c0ec8Sopenharmony_ci			  unsigned int slot,
4552a46c0ec8Sopenharmony_ci			  double x, double y)
4553a46c0ec8Sopenharmony_ci{
4554a46c0ec8Sopenharmony_ci	double t, l, r = 0, b = 0; /* top, left, right, bottom */
4555a46c0ec8Sopenharmony_ci
4556a46c0ec8Sopenharmony_ci	if (d->ntouches_down > 2 || slot > 1)
4557a46c0ec8Sopenharmony_ci		return;
4558a46c0ec8Sopenharmony_ci
4559a46c0ec8Sopenharmony_ci	if (d->ntouches_down == 1) {
4560a46c0ec8Sopenharmony_ci		l = x;
4561a46c0ec8Sopenharmony_ci		t = y;
4562a46c0ec8Sopenharmony_ci	} else {
4563a46c0ec8Sopenharmony_ci		int other = (slot + 1) % 2;
4564a46c0ec8Sopenharmony_ci		l = min(x, semi_mt->touches[other].x);
4565a46c0ec8Sopenharmony_ci		t = min(y, semi_mt->touches[other].y);
4566a46c0ec8Sopenharmony_ci		r = max(x, semi_mt->touches[other].x);
4567a46c0ec8Sopenharmony_ci		b = max(y, semi_mt->touches[other].y);
4568a46c0ec8Sopenharmony_ci	}
4569a46c0ec8Sopenharmony_ci
4570a46c0ec8Sopenharmony_ci	send_abs_xy(d, l, t);
4571a46c0ec8Sopenharmony_ci
4572a46c0ec8Sopenharmony_ci	litest_event(d, EV_ABS, ABS_MT_SLOT, 0);
4573a46c0ec8Sopenharmony_ci	send_abs_mt_xy(d, l, t);
4574a46c0ec8Sopenharmony_ci
4575a46c0ec8Sopenharmony_ci	if (d->ntouches_down == 2) {
4576a46c0ec8Sopenharmony_ci		litest_event(d, EV_ABS, ABS_MT_SLOT, 1);
4577a46c0ec8Sopenharmony_ci		send_abs_mt_xy(d, r, b);
4578a46c0ec8Sopenharmony_ci	}
4579a46c0ec8Sopenharmony_ci
4580a46c0ec8Sopenharmony_ci	litest_event(d, EV_SYN, SYN_REPORT, 0);
4581a46c0ec8Sopenharmony_ci
4582a46c0ec8Sopenharmony_ci	semi_mt->touches[slot].x = x;
4583a46c0ec8Sopenharmony_ci	semi_mt->touches[slot].y = y;
4584a46c0ec8Sopenharmony_ci}
4585a46c0ec8Sopenharmony_ci
4586a46c0ec8Sopenharmony_civoid
4587a46c0ec8Sopenharmony_cilitest_semi_mt_touch_up(struct litest_device *d,
4588a46c0ec8Sopenharmony_ci			struct litest_semi_mt *semi_mt,
4589a46c0ec8Sopenharmony_ci			unsigned int slot)
4590a46c0ec8Sopenharmony_ci{
4591a46c0ec8Sopenharmony_ci	/* note: ntouches_down is decreased before we get here */
4592a46c0ec8Sopenharmony_ci	if (d->ntouches_down >= 2 || slot > 1)
4593a46c0ec8Sopenharmony_ci		return;
4594a46c0ec8Sopenharmony_ci
4595a46c0ec8Sopenharmony_ci	litest_event(d, EV_ABS, ABS_MT_SLOT, d->ntouches_down);
4596a46c0ec8Sopenharmony_ci	litest_event(d, EV_ABS, ABS_MT_TRACKING_ID, -1);
4597a46c0ec8Sopenharmony_ci
4598a46c0ec8Sopenharmony_ci	/* if we have one finger left, send x/y coords for that finger left.
4599a46c0ec8Sopenharmony_ci	   this is likely to happen with a real touchpad */
4600a46c0ec8Sopenharmony_ci	if (d->ntouches_down == 1) {
4601a46c0ec8Sopenharmony_ci		int other = (slot + 1) % 2;
4602a46c0ec8Sopenharmony_ci		send_abs_xy(d, semi_mt->touches[other].x, semi_mt->touches[other].y);
4603a46c0ec8Sopenharmony_ci		litest_event(d, EV_ABS, ABS_MT_SLOT, 0);
4604a46c0ec8Sopenharmony_ci		send_abs_mt_xy(d, semi_mt->touches[other].x, semi_mt->touches[other].y);
4605a46c0ec8Sopenharmony_ci	}
4606a46c0ec8Sopenharmony_ci
4607a46c0ec8Sopenharmony_ci	litest_event(d, EV_SYN, SYN_REPORT, 0);
4608a46c0ec8Sopenharmony_ci}
4609a46c0ec8Sopenharmony_ci
4610a46c0ec8Sopenharmony_cienum litest_mode {
4611a46c0ec8Sopenharmony_ci	LITEST_MODE_ERROR,
4612a46c0ec8Sopenharmony_ci	LITEST_MODE_TEST,
4613a46c0ec8Sopenharmony_ci	LITEST_MODE_LIST,
4614a46c0ec8Sopenharmony_ci};
4615a46c0ec8Sopenharmony_ci
4616a46c0ec8Sopenharmony_cistatic inline enum litest_mode
4617a46c0ec8Sopenharmony_cilitest_parse_argv(int argc, char **argv)
4618a46c0ec8Sopenharmony_ci{
4619a46c0ec8Sopenharmony_ci	enum {
4620a46c0ec8Sopenharmony_ci		OPT_FILTER_TEST,
4621a46c0ec8Sopenharmony_ci		OPT_FILTER_DEVICE,
4622a46c0ec8Sopenharmony_ci		OPT_FILTER_GROUP,
4623a46c0ec8Sopenharmony_ci		OPT_FILTER_DEVICELESS,
4624a46c0ec8Sopenharmony_ci		OPT_XML_PREFIX,
4625a46c0ec8Sopenharmony_ci		OPT_JOBS,
4626a46c0ec8Sopenharmony_ci		OPT_LIST,
4627a46c0ec8Sopenharmony_ci		OPT_VERBOSE,
4628a46c0ec8Sopenharmony_ci	};
4629a46c0ec8Sopenharmony_ci	static const struct option opts[] = {
4630a46c0ec8Sopenharmony_ci		{ "filter-test", 1, 0, OPT_FILTER_TEST },
4631a46c0ec8Sopenharmony_ci		{ "filter-device", 1, 0, OPT_FILTER_DEVICE },
4632a46c0ec8Sopenharmony_ci		{ "filter-group", 1, 0, OPT_FILTER_GROUP },
4633a46c0ec8Sopenharmony_ci		{ "filter-deviceless", 0, 0, OPT_FILTER_DEVICELESS },
4634a46c0ec8Sopenharmony_ci		{ "xml-output", 1, 0, OPT_XML_PREFIX },
4635a46c0ec8Sopenharmony_ci		{ "jobs", 1, 0, OPT_JOBS },
4636a46c0ec8Sopenharmony_ci		{ "list", 0, 0, OPT_LIST },
4637a46c0ec8Sopenharmony_ci		{ "verbose", 0, 0, OPT_VERBOSE },
4638a46c0ec8Sopenharmony_ci		{ "help", 0, 0, 'h'},
4639a46c0ec8Sopenharmony_ci		{ 0, 0, 0, 0}
4640a46c0ec8Sopenharmony_ci	};
4641a46c0ec8Sopenharmony_ci	enum {
4642a46c0ec8Sopenharmony_ci		JOBS_DEFAULT,
4643a46c0ec8Sopenharmony_ci		JOBS_SINGLE,
4644a46c0ec8Sopenharmony_ci		JOBS_CUSTOM
4645a46c0ec8Sopenharmony_ci	} want_jobs = JOBS_DEFAULT;
4646a46c0ec8Sopenharmony_ci	char *builddir;
4647a46c0ec8Sopenharmony_ci	char *jobs_env;
4648a46c0ec8Sopenharmony_ci
4649a46c0ec8Sopenharmony_ci	/* If we are not running from the builddir, we assume we're running
4650a46c0ec8Sopenharmony_ci	 * against the system as installed */
4651a46c0ec8Sopenharmony_ci	builddir = builddir_lookup();
4652a46c0ec8Sopenharmony_ci	if (!builddir)
4653a46c0ec8Sopenharmony_ci		use_system_rules_quirks = true;
4654a46c0ec8Sopenharmony_ci	free(builddir);
4655a46c0ec8Sopenharmony_ci
4656a46c0ec8Sopenharmony_ci	if (in_debugger)
4657a46c0ec8Sopenharmony_ci		want_jobs = JOBS_SINGLE;
4658a46c0ec8Sopenharmony_ci
4659a46c0ec8Sopenharmony_ci	if ((jobs_env = getenv("LITEST_JOBS"))) {
4660a46c0ec8Sopenharmony_ci		if (!safe_atoi(jobs_env, &jobs)) {
4661a46c0ec8Sopenharmony_ci			fprintf(stderr, "LITEST_JOBS environment variable must be positive integer\n");
4662a46c0ec8Sopenharmony_ci			exit(EXIT_FAILURE);
4663a46c0ec8Sopenharmony_ci		}
4664a46c0ec8Sopenharmony_ci	}
4665a46c0ec8Sopenharmony_ci
4666a46c0ec8Sopenharmony_ci	while(1) {
4667a46c0ec8Sopenharmony_ci		int c;
4668a46c0ec8Sopenharmony_ci		int option_index = 0;
4669a46c0ec8Sopenharmony_ci
4670a46c0ec8Sopenharmony_ci		c = getopt_long(argc, argv, "j:", opts, &option_index);
4671a46c0ec8Sopenharmony_ci		if (c == -1)
4672a46c0ec8Sopenharmony_ci			break;
4673a46c0ec8Sopenharmony_ci		switch(c) {
4674a46c0ec8Sopenharmony_ci		default:
4675a46c0ec8Sopenharmony_ci		case 'h':
4676a46c0ec8Sopenharmony_ci			printf("Usage: %s [--verbose] [--jobs] [--filter-...]\n"
4677a46c0ec8Sopenharmony_ci			       "\n"
4678a46c0ec8Sopenharmony_ci			       "Options:\n"
4679a46c0ec8Sopenharmony_ci			       "    --filter-test=.... \n"
4680a46c0ec8Sopenharmony_ci			       "          Glob to filter on test names\n"
4681a46c0ec8Sopenharmony_ci			       "    --filter-device=.... \n"
4682a46c0ec8Sopenharmony_ci			       "          Glob to filter on device names\n"
4683a46c0ec8Sopenharmony_ci			       "    --filter-group=.... \n"
4684a46c0ec8Sopenharmony_ci			       "          Glob to filter on test groups\n"
4685a46c0ec8Sopenharmony_ci			       "    --filter-deviceless=.... \n"
4686a46c0ec8Sopenharmony_ci			       "          Glob to filter on tests that do not create test devices\n"
4687a46c0ec8Sopenharmony_ci			       "    --xml-output=/path/to/file-XXXXXXX.xml\n"
4688a46c0ec8Sopenharmony_ci			       "          Write test output in libcheck's XML format\n"
4689a46c0ec8Sopenharmony_ci			       "          to the given files. The file must match the format\n"
4690a46c0ec8Sopenharmony_ci			       "          prefix-XXXXXX.xml and only the prefix is your choice.\n"
4691a46c0ec8Sopenharmony_ci			       "    --verbose\n"
4692a46c0ec8Sopenharmony_ci			       "          Enable verbose output\n"
4693a46c0ec8Sopenharmony_ci			       "    --jobs 8\n"
4694a46c0ec8Sopenharmony_ci			       "          Number of parallel test suites to run (default: 8).\n"
4695a46c0ec8Sopenharmony_ci			       "	  This overrides the LITEST_JOBS environment variable.\n"
4696a46c0ec8Sopenharmony_ci			       "    --list\n"
4697a46c0ec8Sopenharmony_ci			       "          List all tests\n"
4698a46c0ec8Sopenharmony_ci			       "\n"
4699a46c0ec8Sopenharmony_ci			       "See the libinput-test-suite(1) man page for details.\n",
4700a46c0ec8Sopenharmony_ci			       program_invocation_short_name);
4701a46c0ec8Sopenharmony_ci			exit(c != 'h');
4702a46c0ec8Sopenharmony_ci			break;
4703a46c0ec8Sopenharmony_ci		case OPT_FILTER_TEST:
4704a46c0ec8Sopenharmony_ci			filter_test = optarg;
4705a46c0ec8Sopenharmony_ci			if (want_jobs == JOBS_DEFAULT)
4706a46c0ec8Sopenharmony_ci				want_jobs = JOBS_SINGLE;
4707a46c0ec8Sopenharmony_ci			break;
4708a46c0ec8Sopenharmony_ci		case OPT_FILTER_DEVICE:
4709a46c0ec8Sopenharmony_ci			filter_device = optarg;
4710a46c0ec8Sopenharmony_ci			if (want_jobs == JOBS_DEFAULT)
4711a46c0ec8Sopenharmony_ci				want_jobs = JOBS_SINGLE;
4712a46c0ec8Sopenharmony_ci			break;
4713a46c0ec8Sopenharmony_ci		case OPT_FILTER_GROUP:
4714a46c0ec8Sopenharmony_ci			filter_group = optarg;
4715a46c0ec8Sopenharmony_ci			break;
4716a46c0ec8Sopenharmony_ci		case OPT_XML_PREFIX:
4717a46c0ec8Sopenharmony_ci			xml_prefix = optarg;
4718a46c0ec8Sopenharmony_ci			break;
4719a46c0ec8Sopenharmony_ci		case 'j':
4720a46c0ec8Sopenharmony_ci		case OPT_JOBS:
4721a46c0ec8Sopenharmony_ci			jobs = atoi(optarg);
4722a46c0ec8Sopenharmony_ci			want_jobs = JOBS_CUSTOM;
4723a46c0ec8Sopenharmony_ci			break;
4724a46c0ec8Sopenharmony_ci		case OPT_LIST:
4725a46c0ec8Sopenharmony_ci			return LITEST_MODE_LIST;
4726a46c0ec8Sopenharmony_ci		case OPT_VERBOSE:
4727a46c0ec8Sopenharmony_ci			verbose = true;
4728a46c0ec8Sopenharmony_ci			break;
4729a46c0ec8Sopenharmony_ci		case OPT_FILTER_DEVICELESS:
4730a46c0ec8Sopenharmony_ci			run_deviceless = true;
4731a46c0ec8Sopenharmony_ci			break;
4732a46c0ec8Sopenharmony_ci		}
4733a46c0ec8Sopenharmony_ci	}
4734a46c0ec8Sopenharmony_ci
4735a46c0ec8Sopenharmony_ci	if (want_jobs == JOBS_SINGLE)
4736a46c0ec8Sopenharmony_ci		jobs = 1;
4737a46c0ec8Sopenharmony_ci
4738a46c0ec8Sopenharmony_ci	return LITEST_MODE_TEST;
4739a46c0ec8Sopenharmony_ci}
4740a46c0ec8Sopenharmony_ci
4741a46c0ec8Sopenharmony_ci#ifndef LITEST_NO_MAIN
4742a46c0ec8Sopenharmony_cistatic bool
4743a46c0ec8Sopenharmony_ciis_debugger_attached(void)
4744a46c0ec8Sopenharmony_ci{
4745a46c0ec8Sopenharmony_ci	int status;
4746a46c0ec8Sopenharmony_ci	bool rc;
4747a46c0ec8Sopenharmony_ci	int pid = fork();
4748a46c0ec8Sopenharmony_ci
4749a46c0ec8Sopenharmony_ci	if (pid == -1)
4750a46c0ec8Sopenharmony_ci		return 0;
4751a46c0ec8Sopenharmony_ci
4752a46c0ec8Sopenharmony_ci	if (pid == 0) {
4753a46c0ec8Sopenharmony_ci		int ppid = getppid();
4754a46c0ec8Sopenharmony_ci		if (ptrace(PTRACE_ATTACH, ppid, NULL, 0) == 0) {
4755a46c0ec8Sopenharmony_ci			waitpid(ppid, NULL, 0);
4756a46c0ec8Sopenharmony_ci			ptrace(PTRACE_CONT, ppid, NULL, 0);
4757a46c0ec8Sopenharmony_ci			ptrace(PTRACE_DETACH, ppid, NULL, 0);
4758a46c0ec8Sopenharmony_ci			rc = false;
4759a46c0ec8Sopenharmony_ci		} else {
4760a46c0ec8Sopenharmony_ci			rc = true;
4761a46c0ec8Sopenharmony_ci		}
4762a46c0ec8Sopenharmony_ci		_exit(rc);
4763a46c0ec8Sopenharmony_ci	} else {
4764a46c0ec8Sopenharmony_ci		waitpid(pid, &status, 0);
4765a46c0ec8Sopenharmony_ci		rc = WEXITSTATUS(status);
4766a46c0ec8Sopenharmony_ci	}
4767a46c0ec8Sopenharmony_ci
4768a46c0ec8Sopenharmony_ci	return !!rc;
4769a46c0ec8Sopenharmony_ci}
4770a46c0ec8Sopenharmony_ci
4771a46c0ec8Sopenharmony_cistatic void
4772a46c0ec8Sopenharmony_cilitest_list_tests(struct list *tests)
4773a46c0ec8Sopenharmony_ci{
4774a46c0ec8Sopenharmony_ci	struct suite *s;
4775a46c0ec8Sopenharmony_ci	const char *last_test_name = NULL;
4776a46c0ec8Sopenharmony_ci
4777a46c0ec8Sopenharmony_ci	list_for_each(s, tests, node) {
4778a46c0ec8Sopenharmony_ci		struct test *t;
4779a46c0ec8Sopenharmony_ci		printf("%s:\n", s->name);
4780a46c0ec8Sopenharmony_ci		list_for_each(t, &s->tests, node) {
4781a46c0ec8Sopenharmony_ci			if (!last_test_name ||
4782a46c0ec8Sopenharmony_ci			    !streq(last_test_name, t->name))
4783a46c0ec8Sopenharmony_ci				printf("	%s:\n", t->name);
4784a46c0ec8Sopenharmony_ci
4785a46c0ec8Sopenharmony_ci			last_test_name = t->name;
4786a46c0ec8Sopenharmony_ci
4787a46c0ec8Sopenharmony_ci			printf("		%s\n", t->devname);
4788a46c0ec8Sopenharmony_ci		}
4789a46c0ec8Sopenharmony_ci	}
4790a46c0ec8Sopenharmony_ci}
4791a46c0ec8Sopenharmony_ci
4792a46c0ec8Sopenharmony_ciextern const struct test_device __start_test_section, __stop_test_section;
4793a46c0ec8Sopenharmony_ci
4794a46c0ec8Sopenharmony_cistatic void
4795a46c0ec8Sopenharmony_cilitest_init_test_devices(void)
4796a46c0ec8Sopenharmony_ci{
4797a46c0ec8Sopenharmony_ci	const struct test_device *t;
4798a46c0ec8Sopenharmony_ci
4799a46c0ec8Sopenharmony_ci	list_init(&devices);
4800a46c0ec8Sopenharmony_ci
4801a46c0ec8Sopenharmony_ci	for (t = &__start_test_section; t < &__stop_test_section; t++)
4802a46c0ec8Sopenharmony_ci		list_append(&devices, &t->device->node);
4803a46c0ec8Sopenharmony_ci}
4804a46c0ec8Sopenharmony_ci
4805a46c0ec8Sopenharmony_ciextern const struct test_collection __start_test_collection_section,
4806a46c0ec8Sopenharmony_ci				    __stop_test_collection_section;
4807a46c0ec8Sopenharmony_ci
4808a46c0ec8Sopenharmony_cistatic void
4809a46c0ec8Sopenharmony_cisetup_tests(void)
4810a46c0ec8Sopenharmony_ci{
4811a46c0ec8Sopenharmony_ci	const struct test_collection *c;
4812a46c0ec8Sopenharmony_ci
4813a46c0ec8Sopenharmony_ci	for (c = &__start_test_collection_section;
4814a46c0ec8Sopenharmony_ci	     c < &__stop_test_collection_section;
4815a46c0ec8Sopenharmony_ci	     c++) {
4816a46c0ec8Sopenharmony_ci		c->setup();
4817a46c0ec8Sopenharmony_ci	}
4818a46c0ec8Sopenharmony_ci}
4819a46c0ec8Sopenharmony_ci
4820a46c0ec8Sopenharmony_cistatic int
4821a46c0ec8Sopenharmony_cicheck_device_access(void)
4822a46c0ec8Sopenharmony_ci{
4823a46c0ec8Sopenharmony_ci	if (getuid() != 0) {
4824a46c0ec8Sopenharmony_ci		fprintf(stderr,
4825a46c0ec8Sopenharmony_ci			"%s must be run as root.\n",
4826a46c0ec8Sopenharmony_ci			program_invocation_short_name);
4827a46c0ec8Sopenharmony_ci		return 77;
4828a46c0ec8Sopenharmony_ci	}
4829a46c0ec8Sopenharmony_ci
4830a46c0ec8Sopenharmony_ci	if (access("/dev/uinput", F_OK) == -1 &&
4831a46c0ec8Sopenharmony_ci	    access("/dev/input/uinput", F_OK) == -1) {
4832a46c0ec8Sopenharmony_ci		fprintf(stderr,
4833a46c0ec8Sopenharmony_ci			"uinput device is missing, skipping tests.\n");
4834a46c0ec8Sopenharmony_ci		return 77;
4835a46c0ec8Sopenharmony_ci	}
4836a46c0ec8Sopenharmony_ci
4837a46c0ec8Sopenharmony_ci	return 0;
4838a46c0ec8Sopenharmony_ci}
4839a46c0ec8Sopenharmony_ci
4840a46c0ec8Sopenharmony_cistatic int
4841a46c0ec8Sopenharmony_cidisable_tty(void)
4842a46c0ec8Sopenharmony_ci{
4843a46c0ec8Sopenharmony_ci	int tty_mode = -1;
4844a46c0ec8Sopenharmony_ci
4845a46c0ec8Sopenharmony_ci	/* If we're running 'normally' on the VT, disable the keyboard to
4846a46c0ec8Sopenharmony_ci	 * avoid messing up our host. But if we're inside gdb or running
4847a46c0ec8Sopenharmony_ci	 * without forking, leave it as-is.
4848a46c0ec8Sopenharmony_ci	 */
4849a46c0ec8Sopenharmony_ci	if (!run_deviceless &&
4850a46c0ec8Sopenharmony_ci	    jobs > 1 &&
4851a46c0ec8Sopenharmony_ci	    !in_debugger &&
4852a46c0ec8Sopenharmony_ci	    getenv("CK_FORK") == NULL &&
4853a46c0ec8Sopenharmony_ci	    isatty(STDIN_FILENO) &&
4854a46c0ec8Sopenharmony_ci	    ioctl(STDIN_FILENO, KDGKBMODE, &tty_mode) == 0) {
4855a46c0ec8Sopenharmony_ci#ifdef __linux__
4856a46c0ec8Sopenharmony_ci		ioctl(STDIN_FILENO, KDSKBMODE, K_OFF);
4857a46c0ec8Sopenharmony_ci#elif __FreeBSD__
4858a46c0ec8Sopenharmony_ci		ioctl(STDIN_FILENO, KDSKBMODE, K_RAW);
4859a46c0ec8Sopenharmony_ci
4860a46c0ec8Sopenharmony_ci		/* Put the tty into raw mode */
4861a46c0ec8Sopenharmony_ci		struct termios tios;
4862a46c0ec8Sopenharmony_ci		if (tcgetattr(STDIN_FILENO, &tios))
4863a46c0ec8Sopenharmony_ci				fprintf(stderr, "Failed to get terminal attribute: %d - %s\n", errno, strerror(errno));
4864a46c0ec8Sopenharmony_ci		cfmakeraw(&tios);
4865a46c0ec8Sopenharmony_ci		if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &tios))
4866a46c0ec8Sopenharmony_ci				fprintf(stderr, "Failed to set terminal attribute: %d - %s\n", errno, strerror(errno));
4867a46c0ec8Sopenharmony_ci#endif
4868a46c0ec8Sopenharmony_ci	}
4869a46c0ec8Sopenharmony_ci
4870a46c0ec8Sopenharmony_ci	return tty_mode;
4871a46c0ec8Sopenharmony_ci}
4872a46c0ec8Sopenharmony_ci
4873a46c0ec8Sopenharmony_ciint
4874a46c0ec8Sopenharmony_cimain(int argc, char **argv)
4875a46c0ec8Sopenharmony_ci{
4876a46c0ec8Sopenharmony_ci	const struct rlimit corelimit = { 0, 0 };
4877a46c0ec8Sopenharmony_ci	enum litest_mode mode;
4878a46c0ec8Sopenharmony_ci	int tty_mode = -1;
4879a46c0ec8Sopenharmony_ci	int failed_tests;
4880a46c0ec8Sopenharmony_ci	int rc;
4881a46c0ec8Sopenharmony_ci	const char *meson_testthreads;
4882a46c0ec8Sopenharmony_ci
4883a46c0ec8Sopenharmony_ci	in_debugger = is_debugger_attached();
4884a46c0ec8Sopenharmony_ci	if (in_debugger || RUNNING_ON_VALGRIND)
4885a46c0ec8Sopenharmony_ci		setenv("CK_FORK", "no", 0);
4886a46c0ec8Sopenharmony_ci
4887a46c0ec8Sopenharmony_ci	if ((meson_testthreads = getenv("MESON_TESTTHREADS")) == NULL ||
4888a46c0ec8Sopenharmony_ci	     !safe_atoi(meson_testthreads, &jobs)) {
4889a46c0ec8Sopenharmony_ci		jobs = get_nprocs();
4890a46c0ec8Sopenharmony_ci		if (!RUNNING_ON_VALGRIND)
4891a46c0ec8Sopenharmony_ci			jobs *= 2;
4892a46c0ec8Sopenharmony_ci	}
4893a46c0ec8Sopenharmony_ci
4894a46c0ec8Sopenharmony_ci	mode = litest_parse_argv(argc, argv);
4895a46c0ec8Sopenharmony_ci	if (mode == LITEST_MODE_ERROR)
4896a46c0ec8Sopenharmony_ci		return EXIT_FAILURE;
4897a46c0ec8Sopenharmony_ci
4898a46c0ec8Sopenharmony_ci	litest_init_test_devices();
4899a46c0ec8Sopenharmony_ci	list_init(&all_tests);
4900a46c0ec8Sopenharmony_ci	setup_tests();
4901a46c0ec8Sopenharmony_ci	if (mode == LITEST_MODE_LIST) {
4902a46c0ec8Sopenharmony_ci		litest_list_tests(&all_tests);
4903a46c0ec8Sopenharmony_ci		return EXIT_SUCCESS;
4904a46c0ec8Sopenharmony_ci	}
4905a46c0ec8Sopenharmony_ci
4906a46c0ec8Sopenharmony_ci	if (!run_deviceless && (rc = check_device_access()) != 0)
4907a46c0ec8Sopenharmony_ci		return rc;
4908a46c0ec8Sopenharmony_ci
4909a46c0ec8Sopenharmony_ci	setenv("CK_DEFAULT_TIMEOUT", "30", 0);
4910a46c0ec8Sopenharmony_ci	setenv("LIBINPUT_RUNNING_TEST_SUITE", "1", 1);
4911a46c0ec8Sopenharmony_ci
4912a46c0ec8Sopenharmony_ci	if (setrlimit(RLIMIT_CORE, &corelimit) != 0)
4913a46c0ec8Sopenharmony_ci		perror("WARNING: Core dumps not disabled");
4914a46c0ec8Sopenharmony_ci
4915a46c0ec8Sopenharmony_ci	tty_mode = disable_tty();
4916a46c0ec8Sopenharmony_ci
4917a46c0ec8Sopenharmony_ci	failed_tests = litest_run(argc, argv);
4918a46c0ec8Sopenharmony_ci
4919a46c0ec8Sopenharmony_ci	if (tty_mode != -1) {
4920a46c0ec8Sopenharmony_ci		ioctl(STDIN_FILENO, KDSKBMODE, tty_mode);
4921a46c0ec8Sopenharmony_ci#ifdef __FreeBSD__
4922a46c0ec8Sopenharmony_ci		/* Put the tty into "sane" mode */
4923a46c0ec8Sopenharmony_ci		struct termios tios;
4924a46c0ec8Sopenharmony_ci		if (tcgetattr(STDIN_FILENO, &tios))
4925a46c0ec8Sopenharmony_ci				fprintf(stderr, "Failed to get terminal attribute: %d - %s\n", errno, strerror(errno));
4926a46c0ec8Sopenharmony_ci		cfmakesane(&tios);
4927a46c0ec8Sopenharmony_ci		if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &tios))
4928a46c0ec8Sopenharmony_ci				fprintf(stderr, "Failed to set terminal attribute: %d - %s\n", errno, strerror(errno));
4929a46c0ec8Sopenharmony_ci#endif
4930a46c0ec8Sopenharmony_ci	}
4931a46c0ec8Sopenharmony_ci
4932a46c0ec8Sopenharmony_ci	return min(failed_tests, 255);
4933a46c0ec8Sopenharmony_ci}
4934a46c0ec8Sopenharmony_ci#endif
4935