1a46c0ec8Sopenharmony_ci/*
2a46c0ec8Sopenharmony_ci * Copyright © 2010 Intel Corporation
3a46c0ec8Sopenharmony_ci * Copyright © 2013 Jonas Ådahl
4a46c0ec8Sopenharmony_ci * Copyright © 2013-2017 Red Hat, Inc.
5a46c0ec8Sopenharmony_ci * Copyright © 2017 James Ye <jye836@gmail.com>
6a46c0ec8Sopenharmony_ci *
7a46c0ec8Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
8a46c0ec8Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
9a46c0ec8Sopenharmony_ci * to deal in the Software without restriction, including without limitation
10a46c0ec8Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11a46c0ec8Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
12a46c0ec8Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
13a46c0ec8Sopenharmony_ci *
14a46c0ec8Sopenharmony_ci * The above copyright notice and this permission notice (including the next
15a46c0ec8Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
16a46c0ec8Sopenharmony_ci * Software.
17a46c0ec8Sopenharmony_ci *
18a46c0ec8Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19a46c0ec8Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20a46c0ec8Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
21a46c0ec8Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22a46c0ec8Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23a46c0ec8Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24a46c0ec8Sopenharmony_ci * DEALINGS IN THE SOFTWARE.
25a46c0ec8Sopenharmony_ci */
26a46c0ec8Sopenharmony_ci
27a46c0ec8Sopenharmony_ci#include "config.h"
28a46c0ec8Sopenharmony_ci
29a46c0ec8Sopenharmony_ci#include <mtdev-plumbing.h>
30a46c0ec8Sopenharmony_ci
31a46c0ec8Sopenharmony_ci#include "evdev-fallback.h"
32a46c0ec8Sopenharmony_ci#include "util-input-event.h"
33a46c0ec8Sopenharmony_ci
34a46c0ec8Sopenharmony_cistatic void
35a46c0ec8Sopenharmony_cifallback_keyboard_notify_key(struct fallback_dispatch *dispatch,
36a46c0ec8Sopenharmony_ci			     struct evdev_device *device,
37a46c0ec8Sopenharmony_ci			     uint64_t time,
38a46c0ec8Sopenharmony_ci			     int key,
39a46c0ec8Sopenharmony_ci			     enum libinput_key_state state)
40a46c0ec8Sopenharmony_ci{
41a46c0ec8Sopenharmony_ci	int down_count;
42a46c0ec8Sopenharmony_ci
43a46c0ec8Sopenharmony_ci	down_count = evdev_update_key_down_count(device, key, state);
44a46c0ec8Sopenharmony_ci
45a46c0ec8Sopenharmony_ci	if ((state == LIBINPUT_KEY_STATE_PRESSED && down_count == 1) ||
46a46c0ec8Sopenharmony_ci	    (state == LIBINPUT_KEY_STATE_RELEASED && down_count == 0))
47a46c0ec8Sopenharmony_ci		keyboard_notify_key(&device->base, time, key, state);
48a46c0ec8Sopenharmony_ci}
49a46c0ec8Sopenharmony_ci
50a46c0ec8Sopenharmony_cistatic void
51a46c0ec8Sopenharmony_cifallback_lid_notify_toggle(struct fallback_dispatch *dispatch,
52a46c0ec8Sopenharmony_ci			   struct evdev_device *device,
53a46c0ec8Sopenharmony_ci			   uint64_t time)
54a46c0ec8Sopenharmony_ci{
55a46c0ec8Sopenharmony_ci	if (dispatch->lid.is_closed ^ dispatch->lid.is_closed_client_state) {
56a46c0ec8Sopenharmony_ci		switch_notify_toggle(&device->base,
57a46c0ec8Sopenharmony_ci				     time,
58a46c0ec8Sopenharmony_ci				     LIBINPUT_SWITCH_LID,
59a46c0ec8Sopenharmony_ci				     dispatch->lid.is_closed);
60a46c0ec8Sopenharmony_ci		dispatch->lid.is_closed_client_state = dispatch->lid.is_closed;
61a46c0ec8Sopenharmony_ci	}
62a46c0ec8Sopenharmony_ci}
63a46c0ec8Sopenharmony_ci
64a46c0ec8Sopenharmony_civoid
65a46c0ec8Sopenharmony_cifallback_notify_physical_button(struct fallback_dispatch *dispatch,
66a46c0ec8Sopenharmony_ci				struct evdev_device *device,
67a46c0ec8Sopenharmony_ci				uint64_t time,
68a46c0ec8Sopenharmony_ci				int button,
69a46c0ec8Sopenharmony_ci				enum libinput_button_state state)
70a46c0ec8Sopenharmony_ci{
71a46c0ec8Sopenharmony_ci	evdev_pointer_notify_physical_button(device, time, button, state);
72a46c0ec8Sopenharmony_ci}
73a46c0ec8Sopenharmony_ci
74a46c0ec8Sopenharmony_cistatic enum libinput_switch_state
75a46c0ec8Sopenharmony_cifallback_interface_get_switch_state(struct evdev_dispatch *evdev_dispatch,
76a46c0ec8Sopenharmony_ci				    enum libinput_switch sw)
77a46c0ec8Sopenharmony_ci{
78a46c0ec8Sopenharmony_ci	struct fallback_dispatch *dispatch = fallback_dispatch(evdev_dispatch);
79a46c0ec8Sopenharmony_ci
80a46c0ec8Sopenharmony_ci	switch (sw) {
81a46c0ec8Sopenharmony_ci	case LIBINPUT_SWITCH_TABLET_MODE:
82a46c0ec8Sopenharmony_ci		break;
83a46c0ec8Sopenharmony_ci	default:
84a46c0ec8Sopenharmony_ci		/* Internal function only, so we can abort here */
85a46c0ec8Sopenharmony_ci		abort();
86a46c0ec8Sopenharmony_ci	}
87a46c0ec8Sopenharmony_ci
88a46c0ec8Sopenharmony_ci	return dispatch->tablet_mode.sw.state ?
89a46c0ec8Sopenharmony_ci			LIBINPUT_SWITCH_STATE_ON :
90a46c0ec8Sopenharmony_ci			LIBINPUT_SWITCH_STATE_OFF;
91a46c0ec8Sopenharmony_ci}
92a46c0ec8Sopenharmony_ci
93a46c0ec8Sopenharmony_cistatic inline bool
94a46c0ec8Sopenharmony_cipost_button_scroll(struct evdev_device *device,
95a46c0ec8Sopenharmony_ci		   struct device_float_coords raw,
96a46c0ec8Sopenharmony_ci		   uint64_t time)
97a46c0ec8Sopenharmony_ci{
98a46c0ec8Sopenharmony_ci	if (device->scroll.method != LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN)
99a46c0ec8Sopenharmony_ci		return false;
100a46c0ec8Sopenharmony_ci
101a46c0ec8Sopenharmony_ci	switch(device->scroll.button_scroll_state) {
102a46c0ec8Sopenharmony_ci	case BUTTONSCROLL_IDLE:
103a46c0ec8Sopenharmony_ci		return false;
104a46c0ec8Sopenharmony_ci	case BUTTONSCROLL_BUTTON_DOWN:
105a46c0ec8Sopenharmony_ci		/* if the button is down but scroll is not active, we're within the
106a46c0ec8Sopenharmony_ci		   timeout where we swallow motion events but don't post
107a46c0ec8Sopenharmony_ci		   scroll buttons */
108a46c0ec8Sopenharmony_ci		evdev_log_debug(device, "btnscroll: discarding\n");
109a46c0ec8Sopenharmony_ci		return true;
110a46c0ec8Sopenharmony_ci	case BUTTONSCROLL_READY:
111a46c0ec8Sopenharmony_ci		device->scroll.button_scroll_state = BUTTONSCROLL_SCROLLING;
112a46c0ec8Sopenharmony_ci		_fallthrough_;
113a46c0ec8Sopenharmony_ci	case BUTTONSCROLL_SCROLLING:
114a46c0ec8Sopenharmony_ci		{
115a46c0ec8Sopenharmony_ci		const struct normalized_coords normalized =
116a46c0ec8Sopenharmony_ci				filter_dispatch_scroll(device->pointer.filter,
117a46c0ec8Sopenharmony_ci						       &raw,
118a46c0ec8Sopenharmony_ci						       device,
119a46c0ec8Sopenharmony_ci						       time);
120a46c0ec8Sopenharmony_ci		evdev_post_scroll(device, time,
121a46c0ec8Sopenharmony_ci				  LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS,
122a46c0ec8Sopenharmony_ci				  &normalized);
123a46c0ec8Sopenharmony_ci		}
124a46c0ec8Sopenharmony_ci		return true;
125a46c0ec8Sopenharmony_ci	}
126a46c0ec8Sopenharmony_ci
127a46c0ec8Sopenharmony_ci	assert(!"invalid scroll button state");
128a46c0ec8Sopenharmony_ci}
129a46c0ec8Sopenharmony_ci
130a46c0ec8Sopenharmony_cistatic inline bool
131a46c0ec8Sopenharmony_cifallback_filter_defuzz_touch(struct fallback_dispatch *dispatch,
132a46c0ec8Sopenharmony_ci			     struct evdev_device *device,
133a46c0ec8Sopenharmony_ci			     struct mt_slot *slot)
134a46c0ec8Sopenharmony_ci{
135a46c0ec8Sopenharmony_ci	struct device_coords point;
136a46c0ec8Sopenharmony_ci
137a46c0ec8Sopenharmony_ci	if (!dispatch->mt.want_hysteresis)
138a46c0ec8Sopenharmony_ci		return false;
139a46c0ec8Sopenharmony_ci
140a46c0ec8Sopenharmony_ci	point = evdev_hysteresis(&slot->point,
141a46c0ec8Sopenharmony_ci				 &slot->hysteresis_center,
142a46c0ec8Sopenharmony_ci				 &dispatch->mt.hysteresis_margin);
143a46c0ec8Sopenharmony_ci	slot->point = point;
144a46c0ec8Sopenharmony_ci
145a46c0ec8Sopenharmony_ci	if (point.x == slot->hysteresis_center.x &&
146a46c0ec8Sopenharmony_ci	    point.y == slot->hysteresis_center.y)
147a46c0ec8Sopenharmony_ci		return true;
148a46c0ec8Sopenharmony_ci
149a46c0ec8Sopenharmony_ci	slot->hysteresis_center = point;
150a46c0ec8Sopenharmony_ci
151a46c0ec8Sopenharmony_ci	return false;
152a46c0ec8Sopenharmony_ci}
153a46c0ec8Sopenharmony_ci
154a46c0ec8Sopenharmony_cistatic inline struct device_float_coords
155a46c0ec8Sopenharmony_cifallback_rotate_relative(struct fallback_dispatch *dispatch,
156a46c0ec8Sopenharmony_ci			 struct evdev_device *device)
157a46c0ec8Sopenharmony_ci{
158a46c0ec8Sopenharmony_ci	struct device_float_coords rel = { dispatch->rel.x, dispatch->rel.y };
159a46c0ec8Sopenharmony_ci
160a46c0ec8Sopenharmony_ci	if (!device->base.config.rotation)
161a46c0ec8Sopenharmony_ci		return rel;
162a46c0ec8Sopenharmony_ci
163a46c0ec8Sopenharmony_ci	matrix_mult_vec_double(&dispatch->rotation.matrix, &rel.x, &rel.y);
164a46c0ec8Sopenharmony_ci
165a46c0ec8Sopenharmony_ci	return rel;
166a46c0ec8Sopenharmony_ci}
167a46c0ec8Sopenharmony_ci
168a46c0ec8Sopenharmony_cistatic void
169a46c0ec8Sopenharmony_cifallback_flush_relative_motion(struct fallback_dispatch *dispatch,
170a46c0ec8Sopenharmony_ci			       struct evdev_device *device,
171a46c0ec8Sopenharmony_ci			       uint64_t time)
172a46c0ec8Sopenharmony_ci{
173a46c0ec8Sopenharmony_ci	struct libinput_device *base = &device->base;
174a46c0ec8Sopenharmony_ci	struct normalized_coords accel;
175a46c0ec8Sopenharmony_ci
176a46c0ec8Sopenharmony_ci	if (!(device->seat_caps & EVDEV_DEVICE_POINTER))
177a46c0ec8Sopenharmony_ci		return;
178a46c0ec8Sopenharmony_ci
179a46c0ec8Sopenharmony_ci	struct device_float_coords raw = fallback_rotate_relative(dispatch, device);
180a46c0ec8Sopenharmony_ci
181a46c0ec8Sopenharmony_ci	dispatch->rel.x = 0;
182a46c0ec8Sopenharmony_ci	dispatch->rel.y = 0;
183a46c0ec8Sopenharmony_ci
184a46c0ec8Sopenharmony_ci	/* Use unaccelerated deltas for pointing stick scroll */
185a46c0ec8Sopenharmony_ci	if (post_button_scroll(device, raw, time))
186a46c0ec8Sopenharmony_ci		return;
187a46c0ec8Sopenharmony_ci
188a46c0ec8Sopenharmony_ci	if (device->pointer.filter) {
189a46c0ec8Sopenharmony_ci		/* Apply pointer acceleration. */
190a46c0ec8Sopenharmony_ci		accel = filter_dispatch(device->pointer.filter,
191a46c0ec8Sopenharmony_ci					&raw,
192a46c0ec8Sopenharmony_ci					device,
193a46c0ec8Sopenharmony_ci					time);
194a46c0ec8Sopenharmony_ci	} else {
195a46c0ec8Sopenharmony_ci		evdev_log_bug_libinput(device,
196a46c0ec8Sopenharmony_ci				       "accel filter missing\n");
197a46c0ec8Sopenharmony_ci		accel.x = accel.y = 0;
198a46c0ec8Sopenharmony_ci	}
199a46c0ec8Sopenharmony_ci
200a46c0ec8Sopenharmony_ci	if (normalized_is_zero(accel))
201a46c0ec8Sopenharmony_ci		return;
202a46c0ec8Sopenharmony_ci
203a46c0ec8Sopenharmony_ci	pointer_notify_motion(base, time, &accel, &raw);
204a46c0ec8Sopenharmony_ci}
205a46c0ec8Sopenharmony_ci
206a46c0ec8Sopenharmony_cistatic void
207a46c0ec8Sopenharmony_cifallback_flush_absolute_motion(struct fallback_dispatch *dispatch,
208a46c0ec8Sopenharmony_ci			       struct evdev_device *device,
209a46c0ec8Sopenharmony_ci			       uint64_t time)
210a46c0ec8Sopenharmony_ci{
211a46c0ec8Sopenharmony_ci	struct libinput_device *base = &device->base;
212a46c0ec8Sopenharmony_ci	struct device_coords point;
213a46c0ec8Sopenharmony_ci
214a46c0ec8Sopenharmony_ci	if (!(device->seat_caps & EVDEV_DEVICE_POINTER))
215a46c0ec8Sopenharmony_ci		return;
216a46c0ec8Sopenharmony_ci
217a46c0ec8Sopenharmony_ci	point = dispatch->abs.point;
218a46c0ec8Sopenharmony_ci	evdev_transform_absolute(device, &point);
219a46c0ec8Sopenharmony_ci
220a46c0ec8Sopenharmony_ci	pointer_notify_motion_absolute(base, time, &point);
221a46c0ec8Sopenharmony_ci}
222a46c0ec8Sopenharmony_ci
223a46c0ec8Sopenharmony_cistatic bool
224a46c0ec8Sopenharmony_cifallback_flush_mt_down(struct fallback_dispatch *dispatch,
225a46c0ec8Sopenharmony_ci		       struct evdev_device *device,
226a46c0ec8Sopenharmony_ci		       int slot_idx,
227a46c0ec8Sopenharmony_ci		       uint64_t time)
228a46c0ec8Sopenharmony_ci{
229a46c0ec8Sopenharmony_ci	struct libinput_device *base = &device->base;
230a46c0ec8Sopenharmony_ci	struct libinput_seat *seat = base->seat;
231a46c0ec8Sopenharmony_ci	struct device_coords point;
232a46c0ec8Sopenharmony_ci	struct mt_slot *slot;
233a46c0ec8Sopenharmony_ci	int seat_slot;
234a46c0ec8Sopenharmony_ci
235a46c0ec8Sopenharmony_ci	if (!(device->seat_caps & EVDEV_DEVICE_TOUCH))
236a46c0ec8Sopenharmony_ci		return false;
237a46c0ec8Sopenharmony_ci
238a46c0ec8Sopenharmony_ci	slot = &dispatch->mt.slots[slot_idx];
239a46c0ec8Sopenharmony_ci	if (slot->seat_slot != -1) {
240a46c0ec8Sopenharmony_ci		evdev_log_bug_kernel(device,
241a46c0ec8Sopenharmony_ci				     "driver sent multiple touch down for the same slot");
242a46c0ec8Sopenharmony_ci		return false;
243a46c0ec8Sopenharmony_ci	}
244a46c0ec8Sopenharmony_ci
245a46c0ec8Sopenharmony_ci	seat_slot = ffs(~seat->slot_map) - 1;
246a46c0ec8Sopenharmony_ci	slot->seat_slot = seat_slot;
247a46c0ec8Sopenharmony_ci
248a46c0ec8Sopenharmony_ci	if (seat_slot == -1)
249a46c0ec8Sopenharmony_ci		return false;
250a46c0ec8Sopenharmony_ci
251a46c0ec8Sopenharmony_ci	seat->slot_map |= bit(seat_slot);
252a46c0ec8Sopenharmony_ci	point = slot->point;
253a46c0ec8Sopenharmony_ci	slot->hysteresis_center = point;
254a46c0ec8Sopenharmony_ci	evdev_transform_absolute(device, &point);
255a46c0ec8Sopenharmony_ci
256a46c0ec8Sopenharmony_ci	touch_notify_touch_down(base, time, slot_idx, seat_slot,
257a46c0ec8Sopenharmony_ci				&point);
258a46c0ec8Sopenharmony_ci
259a46c0ec8Sopenharmony_ci	return true;
260a46c0ec8Sopenharmony_ci}
261a46c0ec8Sopenharmony_ci
262a46c0ec8Sopenharmony_cistatic bool
263a46c0ec8Sopenharmony_cifallback_flush_mt_motion(struct fallback_dispatch *dispatch,
264a46c0ec8Sopenharmony_ci			 struct evdev_device *device,
265a46c0ec8Sopenharmony_ci			 int slot_idx,
266a46c0ec8Sopenharmony_ci			 uint64_t time)
267a46c0ec8Sopenharmony_ci{
268a46c0ec8Sopenharmony_ci	struct libinput_device *base = &device->base;
269a46c0ec8Sopenharmony_ci	struct device_coords point;
270a46c0ec8Sopenharmony_ci	struct mt_slot *slot;
271a46c0ec8Sopenharmony_ci	int seat_slot;
272a46c0ec8Sopenharmony_ci
273a46c0ec8Sopenharmony_ci	if (!(device->seat_caps & EVDEV_DEVICE_TOUCH))
274a46c0ec8Sopenharmony_ci		return false;
275a46c0ec8Sopenharmony_ci
276a46c0ec8Sopenharmony_ci	slot = &dispatch->mt.slots[slot_idx];
277a46c0ec8Sopenharmony_ci	seat_slot = slot->seat_slot;
278a46c0ec8Sopenharmony_ci	point = slot->point;
279a46c0ec8Sopenharmony_ci
280a46c0ec8Sopenharmony_ci	if (seat_slot == -1)
281a46c0ec8Sopenharmony_ci		return false;
282a46c0ec8Sopenharmony_ci
283a46c0ec8Sopenharmony_ci	if (fallback_filter_defuzz_touch(dispatch, device, slot))
284a46c0ec8Sopenharmony_ci		return false;
285a46c0ec8Sopenharmony_ci
286a46c0ec8Sopenharmony_ci	evdev_transform_absolute(device, &point);
287a46c0ec8Sopenharmony_ci	touch_notify_touch_motion(base, time, slot_idx, seat_slot,
288a46c0ec8Sopenharmony_ci				  &point);
289a46c0ec8Sopenharmony_ci
290a46c0ec8Sopenharmony_ci	return true;
291a46c0ec8Sopenharmony_ci}
292a46c0ec8Sopenharmony_ci
293a46c0ec8Sopenharmony_cistatic bool
294a46c0ec8Sopenharmony_cifallback_flush_mt_up(struct fallback_dispatch *dispatch,
295a46c0ec8Sopenharmony_ci		     struct evdev_device *device,
296a46c0ec8Sopenharmony_ci		     int slot_idx,
297a46c0ec8Sopenharmony_ci		     uint64_t time)
298a46c0ec8Sopenharmony_ci{
299a46c0ec8Sopenharmony_ci	struct libinput_device *base = &device->base;
300a46c0ec8Sopenharmony_ci	struct libinput_seat *seat = base->seat;
301a46c0ec8Sopenharmony_ci	struct mt_slot *slot;
302a46c0ec8Sopenharmony_ci	int seat_slot;
303a46c0ec8Sopenharmony_ci
304a46c0ec8Sopenharmony_ci	if (!(device->seat_caps & EVDEV_DEVICE_TOUCH))
305a46c0ec8Sopenharmony_ci		return false;
306a46c0ec8Sopenharmony_ci
307a46c0ec8Sopenharmony_ci	slot = &dispatch->mt.slots[slot_idx];
308a46c0ec8Sopenharmony_ci	seat_slot = slot->seat_slot;
309a46c0ec8Sopenharmony_ci	slot->seat_slot = -1;
310a46c0ec8Sopenharmony_ci
311a46c0ec8Sopenharmony_ci	if (seat_slot == -1)
312a46c0ec8Sopenharmony_ci		return false;
313a46c0ec8Sopenharmony_ci
314a46c0ec8Sopenharmony_ci	seat->slot_map &= ~bit(seat_slot);
315a46c0ec8Sopenharmony_ci
316a46c0ec8Sopenharmony_ci	touch_notify_touch_up(base, time, slot_idx, seat_slot);
317a46c0ec8Sopenharmony_ci
318a46c0ec8Sopenharmony_ci	return true;
319a46c0ec8Sopenharmony_ci}
320a46c0ec8Sopenharmony_ci
321a46c0ec8Sopenharmony_cistatic bool
322a46c0ec8Sopenharmony_cifallback_flush_mt_cancel(struct fallback_dispatch *dispatch,
323a46c0ec8Sopenharmony_ci			 struct evdev_device *device,
324a46c0ec8Sopenharmony_ci			 int slot_idx,
325a46c0ec8Sopenharmony_ci			 uint64_t time)
326a46c0ec8Sopenharmony_ci{
327a46c0ec8Sopenharmony_ci	struct libinput_device *base = &device->base;
328a46c0ec8Sopenharmony_ci	struct libinput_seat *seat = base->seat;
329a46c0ec8Sopenharmony_ci	struct mt_slot *slot;
330a46c0ec8Sopenharmony_ci	int seat_slot;
331a46c0ec8Sopenharmony_ci
332a46c0ec8Sopenharmony_ci	if (!(device->seat_caps & EVDEV_DEVICE_TOUCH))
333a46c0ec8Sopenharmony_ci		return false;
334a46c0ec8Sopenharmony_ci
335a46c0ec8Sopenharmony_ci	slot = &dispatch->mt.slots[slot_idx];
336a46c0ec8Sopenharmony_ci	seat_slot = slot->seat_slot;
337a46c0ec8Sopenharmony_ci	slot->seat_slot = -1;
338a46c0ec8Sopenharmony_ci
339a46c0ec8Sopenharmony_ci	if (seat_slot == -1)
340a46c0ec8Sopenharmony_ci		return false;
341a46c0ec8Sopenharmony_ci
342a46c0ec8Sopenharmony_ci	seat->slot_map &= ~bit(seat_slot);
343a46c0ec8Sopenharmony_ci
344a46c0ec8Sopenharmony_ci	touch_notify_touch_cancel(base, time, slot_idx, seat_slot);
345a46c0ec8Sopenharmony_ci
346a46c0ec8Sopenharmony_ci	return true;
347a46c0ec8Sopenharmony_ci}
348a46c0ec8Sopenharmony_ci
349a46c0ec8Sopenharmony_cistatic bool
350a46c0ec8Sopenharmony_cifallback_flush_st_down(struct fallback_dispatch *dispatch,
351a46c0ec8Sopenharmony_ci		       struct evdev_device *device,
352a46c0ec8Sopenharmony_ci		       uint64_t time)
353a46c0ec8Sopenharmony_ci{
354a46c0ec8Sopenharmony_ci	struct libinput_device *base = &device->base;
355a46c0ec8Sopenharmony_ci	struct libinput_seat *seat = base->seat;
356a46c0ec8Sopenharmony_ci	struct device_coords point;
357a46c0ec8Sopenharmony_ci	int seat_slot;
358a46c0ec8Sopenharmony_ci
359a46c0ec8Sopenharmony_ci	if (!(device->seat_caps & EVDEV_DEVICE_TOUCH))
360a46c0ec8Sopenharmony_ci		return false;
361a46c0ec8Sopenharmony_ci
362a46c0ec8Sopenharmony_ci	if (dispatch->abs.seat_slot != -1) {
363a46c0ec8Sopenharmony_ci		evdev_log_bug_kernel(device,
364a46c0ec8Sopenharmony_ci				     "driver sent multiple touch down for the same slot");
365a46c0ec8Sopenharmony_ci		return false;
366a46c0ec8Sopenharmony_ci	}
367a46c0ec8Sopenharmony_ci
368a46c0ec8Sopenharmony_ci	seat_slot = ffs(~seat->slot_map) - 1;
369a46c0ec8Sopenharmony_ci	dispatch->abs.seat_slot = seat_slot;
370a46c0ec8Sopenharmony_ci
371a46c0ec8Sopenharmony_ci	if (seat_slot == -1)
372a46c0ec8Sopenharmony_ci		return false;
373a46c0ec8Sopenharmony_ci
374a46c0ec8Sopenharmony_ci	seat->slot_map |= bit(seat_slot);
375a46c0ec8Sopenharmony_ci
376a46c0ec8Sopenharmony_ci	point = dispatch->abs.point;
377a46c0ec8Sopenharmony_ci	evdev_transform_absolute(device, &point);
378a46c0ec8Sopenharmony_ci
379a46c0ec8Sopenharmony_ci	touch_notify_touch_down(base, time, -1, seat_slot, &point);
380a46c0ec8Sopenharmony_ci
381a46c0ec8Sopenharmony_ci	return true;
382a46c0ec8Sopenharmony_ci}
383a46c0ec8Sopenharmony_ci
384a46c0ec8Sopenharmony_cistatic bool
385a46c0ec8Sopenharmony_cifallback_flush_st_motion(struct fallback_dispatch *dispatch,
386a46c0ec8Sopenharmony_ci			 struct evdev_device *device,
387a46c0ec8Sopenharmony_ci			 uint64_t time)
388a46c0ec8Sopenharmony_ci{
389a46c0ec8Sopenharmony_ci	struct libinput_device *base = &device->base;
390a46c0ec8Sopenharmony_ci	struct device_coords point;
391a46c0ec8Sopenharmony_ci	int seat_slot;
392a46c0ec8Sopenharmony_ci
393a46c0ec8Sopenharmony_ci	point = dispatch->abs.point;
394a46c0ec8Sopenharmony_ci	evdev_transform_absolute(device, &point);
395a46c0ec8Sopenharmony_ci
396a46c0ec8Sopenharmony_ci	seat_slot = dispatch->abs.seat_slot;
397a46c0ec8Sopenharmony_ci
398a46c0ec8Sopenharmony_ci	if (seat_slot == -1)
399a46c0ec8Sopenharmony_ci		return false;
400a46c0ec8Sopenharmony_ci
401a46c0ec8Sopenharmony_ci	touch_notify_touch_motion(base, time, -1, seat_slot, &point);
402a46c0ec8Sopenharmony_ci
403a46c0ec8Sopenharmony_ci	return true;
404a46c0ec8Sopenharmony_ci}
405a46c0ec8Sopenharmony_ci
406a46c0ec8Sopenharmony_cistatic bool
407a46c0ec8Sopenharmony_cifallback_flush_st_up(struct fallback_dispatch *dispatch,
408a46c0ec8Sopenharmony_ci		     struct evdev_device *device,
409a46c0ec8Sopenharmony_ci		     uint64_t time)
410a46c0ec8Sopenharmony_ci{
411a46c0ec8Sopenharmony_ci	struct libinput_device *base = &device->base;
412a46c0ec8Sopenharmony_ci	struct libinput_seat *seat = base->seat;
413a46c0ec8Sopenharmony_ci	int seat_slot;
414a46c0ec8Sopenharmony_ci
415a46c0ec8Sopenharmony_ci	if (!(device->seat_caps & EVDEV_DEVICE_TOUCH))
416a46c0ec8Sopenharmony_ci		return false;
417a46c0ec8Sopenharmony_ci
418a46c0ec8Sopenharmony_ci	seat_slot = dispatch->abs.seat_slot;
419a46c0ec8Sopenharmony_ci	dispatch->abs.seat_slot = -1;
420a46c0ec8Sopenharmony_ci
421a46c0ec8Sopenharmony_ci	if (seat_slot == -1)
422a46c0ec8Sopenharmony_ci		return false;
423a46c0ec8Sopenharmony_ci
424a46c0ec8Sopenharmony_ci	seat->slot_map &= ~bit(seat_slot);
425a46c0ec8Sopenharmony_ci
426a46c0ec8Sopenharmony_ci	touch_notify_touch_up(base, time, -1, seat_slot);
427a46c0ec8Sopenharmony_ci
428a46c0ec8Sopenharmony_ci	return true;
429a46c0ec8Sopenharmony_ci}
430a46c0ec8Sopenharmony_ci
431a46c0ec8Sopenharmony_cistatic bool
432a46c0ec8Sopenharmony_cifallback_flush_st_cancel(struct fallback_dispatch *dispatch,
433a46c0ec8Sopenharmony_ci			 struct evdev_device *device,
434a46c0ec8Sopenharmony_ci			 uint64_t time)
435a46c0ec8Sopenharmony_ci{
436a46c0ec8Sopenharmony_ci	struct libinput_device *base = &device->base;
437a46c0ec8Sopenharmony_ci	struct libinput_seat *seat = base->seat;
438a46c0ec8Sopenharmony_ci	int seat_slot;
439a46c0ec8Sopenharmony_ci
440a46c0ec8Sopenharmony_ci	if (!(device->seat_caps & EVDEV_DEVICE_TOUCH))
441a46c0ec8Sopenharmony_ci		return false;
442a46c0ec8Sopenharmony_ci
443a46c0ec8Sopenharmony_ci	seat_slot = dispatch->abs.seat_slot;
444a46c0ec8Sopenharmony_ci	dispatch->abs.seat_slot = -1;
445a46c0ec8Sopenharmony_ci
446a46c0ec8Sopenharmony_ci	if (seat_slot == -1)
447a46c0ec8Sopenharmony_ci		return false;
448a46c0ec8Sopenharmony_ci
449a46c0ec8Sopenharmony_ci	seat->slot_map &= ~bit(seat_slot);
450a46c0ec8Sopenharmony_ci
451a46c0ec8Sopenharmony_ci	touch_notify_touch_cancel(base, time, -1, seat_slot);
452a46c0ec8Sopenharmony_ci
453a46c0ec8Sopenharmony_ci	return true;
454a46c0ec8Sopenharmony_ci}
455a46c0ec8Sopenharmony_ci
456a46c0ec8Sopenharmony_cistatic void
457a46c0ec8Sopenharmony_cifallback_process_touch_button(struct fallback_dispatch *dispatch,
458a46c0ec8Sopenharmony_ci			      struct evdev_device *device,
459a46c0ec8Sopenharmony_ci			      uint64_t time, int value)
460a46c0ec8Sopenharmony_ci{
461a46c0ec8Sopenharmony_ci	dispatch->pending_event |= (value) ?
462a46c0ec8Sopenharmony_ci				 EVDEV_ABSOLUTE_TOUCH_DOWN :
463a46c0ec8Sopenharmony_ci				 EVDEV_ABSOLUTE_TOUCH_UP;
464a46c0ec8Sopenharmony_ci}
465a46c0ec8Sopenharmony_ci
466a46c0ec8Sopenharmony_cistatic inline void
467a46c0ec8Sopenharmony_cifallback_process_key(struct fallback_dispatch *dispatch,
468a46c0ec8Sopenharmony_ci		     struct evdev_device *device,
469a46c0ec8Sopenharmony_ci		     struct input_event *e, uint64_t time)
470a46c0ec8Sopenharmony_ci{
471a46c0ec8Sopenharmony_ci	enum key_type type;
472a46c0ec8Sopenharmony_ci
473a46c0ec8Sopenharmony_ci	/* ignore kernel key repeat */
474a46c0ec8Sopenharmony_ci	if (e->value == 2)
475a46c0ec8Sopenharmony_ci		return;
476a46c0ec8Sopenharmony_ci
477a46c0ec8Sopenharmony_ci	if (e->code == BTN_TOUCH) {
478a46c0ec8Sopenharmony_ci		if (!device->is_mt)
479a46c0ec8Sopenharmony_ci			fallback_process_touch_button(dispatch,
480a46c0ec8Sopenharmony_ci						      device,
481a46c0ec8Sopenharmony_ci						      time,
482a46c0ec8Sopenharmony_ci						      e->value);
483a46c0ec8Sopenharmony_ci		return;
484a46c0ec8Sopenharmony_ci	}
485a46c0ec8Sopenharmony_ci
486a46c0ec8Sopenharmony_ci	type = get_key_type(e->code);
487a46c0ec8Sopenharmony_ci
488a46c0ec8Sopenharmony_ci	/* Ignore key release events from the kernel for keys that libinput
489a46c0ec8Sopenharmony_ci	 * never got a pressed event for or key presses for keys that we
490a46c0ec8Sopenharmony_ci	 * think are still down */
491a46c0ec8Sopenharmony_ci	switch (type) {
492a46c0ec8Sopenharmony_ci	case KEY_TYPE_NONE:
493a46c0ec8Sopenharmony_ci		break;
494a46c0ec8Sopenharmony_ci	case KEY_TYPE_KEY:
495a46c0ec8Sopenharmony_ci	case KEY_TYPE_BUTTON:
496a46c0ec8Sopenharmony_ci		if ((e->value && hw_is_key_down(dispatch, e->code)) ||
497a46c0ec8Sopenharmony_ci		    (e->value == 0 && !hw_is_key_down(dispatch, e->code)))
498a46c0ec8Sopenharmony_ci			return;
499a46c0ec8Sopenharmony_ci
500a46c0ec8Sopenharmony_ci		dispatch->pending_event |= EVDEV_KEY;
501a46c0ec8Sopenharmony_ci		break;
502a46c0ec8Sopenharmony_ci	}
503a46c0ec8Sopenharmony_ci
504a46c0ec8Sopenharmony_ci	hw_set_key_down(dispatch, e->code, e->value);
505a46c0ec8Sopenharmony_ci
506a46c0ec8Sopenharmony_ci	switch (type) {
507a46c0ec8Sopenharmony_ci	case KEY_TYPE_NONE:
508a46c0ec8Sopenharmony_ci		break;
509a46c0ec8Sopenharmony_ci	case KEY_TYPE_KEY:
510a46c0ec8Sopenharmony_ci		fallback_keyboard_notify_key(
511a46c0ec8Sopenharmony_ci			     dispatch,
512a46c0ec8Sopenharmony_ci			     device,
513a46c0ec8Sopenharmony_ci			     time,
514a46c0ec8Sopenharmony_ci			     e->code,
515a46c0ec8Sopenharmony_ci			     e->value ? LIBINPUT_KEY_STATE_PRESSED :
516a46c0ec8Sopenharmony_ci					LIBINPUT_KEY_STATE_RELEASED);
517a46c0ec8Sopenharmony_ci		break;
518a46c0ec8Sopenharmony_ci	case KEY_TYPE_BUTTON:
519a46c0ec8Sopenharmony_ci		break;
520a46c0ec8Sopenharmony_ci	}
521a46c0ec8Sopenharmony_ci}
522a46c0ec8Sopenharmony_ci
523a46c0ec8Sopenharmony_cistatic void
524a46c0ec8Sopenharmony_cifallback_process_touch(struct fallback_dispatch *dispatch,
525a46c0ec8Sopenharmony_ci		       struct evdev_device *device,
526a46c0ec8Sopenharmony_ci		       struct input_event *e,
527a46c0ec8Sopenharmony_ci		       uint64_t time)
528a46c0ec8Sopenharmony_ci{
529a46c0ec8Sopenharmony_ci	struct mt_slot *slot = &dispatch->mt.slots[dispatch->mt.slot];
530a46c0ec8Sopenharmony_ci
531a46c0ec8Sopenharmony_ci	if (e->code == ABS_MT_SLOT) {
532a46c0ec8Sopenharmony_ci		if ((size_t)e->value >= dispatch->mt.slots_len) {
533a46c0ec8Sopenharmony_ci			evdev_log_bug_libinput(device,
534a46c0ec8Sopenharmony_ci					 "exceeded slot count (%d of max %zd)\n",
535a46c0ec8Sopenharmony_ci					 e->value,
536a46c0ec8Sopenharmony_ci					 dispatch->mt.slots_len);
537a46c0ec8Sopenharmony_ci			e->value = dispatch->mt.slots_len - 1;
538a46c0ec8Sopenharmony_ci		}
539a46c0ec8Sopenharmony_ci		dispatch->mt.slot = e->value;
540a46c0ec8Sopenharmony_ci		return;
541a46c0ec8Sopenharmony_ci	}
542a46c0ec8Sopenharmony_ci
543a46c0ec8Sopenharmony_ci	switch (e->code) {
544a46c0ec8Sopenharmony_ci	case ABS_MT_TRACKING_ID:
545a46c0ec8Sopenharmony_ci		if (e->value >= 0) {
546a46c0ec8Sopenharmony_ci			dispatch->pending_event |= EVDEV_ABSOLUTE_MT;
547a46c0ec8Sopenharmony_ci			slot->state = SLOT_STATE_BEGIN;
548a46c0ec8Sopenharmony_ci			if (dispatch->mt.has_palm) {
549a46c0ec8Sopenharmony_ci				int v;
550a46c0ec8Sopenharmony_ci				v = libevdev_get_slot_value(device->evdev,
551a46c0ec8Sopenharmony_ci							    dispatch->mt.slot,
552a46c0ec8Sopenharmony_ci							    ABS_MT_TOOL_TYPE);
553a46c0ec8Sopenharmony_ci				switch (v) {
554a46c0ec8Sopenharmony_ci				case MT_TOOL_PALM:
555a46c0ec8Sopenharmony_ci					/* new touch, no cancel needed */
556a46c0ec8Sopenharmony_ci					slot->palm_state = PALM_WAS_PALM;
557a46c0ec8Sopenharmony_ci					break;
558a46c0ec8Sopenharmony_ci				default:
559a46c0ec8Sopenharmony_ci					slot->palm_state = PALM_NONE;
560a46c0ec8Sopenharmony_ci					break;
561a46c0ec8Sopenharmony_ci				}
562a46c0ec8Sopenharmony_ci			} else {
563a46c0ec8Sopenharmony_ci				slot->palm_state = PALM_NONE;
564a46c0ec8Sopenharmony_ci			}
565a46c0ec8Sopenharmony_ci		} else {
566a46c0ec8Sopenharmony_ci			dispatch->pending_event |= EVDEV_ABSOLUTE_MT;
567a46c0ec8Sopenharmony_ci			slot->state = SLOT_STATE_END;
568a46c0ec8Sopenharmony_ci		}
569a46c0ec8Sopenharmony_ci		slot->dirty = true;
570a46c0ec8Sopenharmony_ci		break;
571a46c0ec8Sopenharmony_ci	case ABS_MT_POSITION_X:
572a46c0ec8Sopenharmony_ci		evdev_device_check_abs_axis_range(device, e->code, e->value);
573a46c0ec8Sopenharmony_ci		dispatch->mt.slots[dispatch->mt.slot].point.x = e->value;
574a46c0ec8Sopenharmony_ci		dispatch->pending_event |= EVDEV_ABSOLUTE_MT;
575a46c0ec8Sopenharmony_ci		slot->dirty = true;
576a46c0ec8Sopenharmony_ci		break;
577a46c0ec8Sopenharmony_ci	case ABS_MT_POSITION_Y:
578a46c0ec8Sopenharmony_ci		evdev_device_check_abs_axis_range(device, e->code, e->value);
579a46c0ec8Sopenharmony_ci		dispatch->mt.slots[dispatch->mt.slot].point.y = e->value;
580a46c0ec8Sopenharmony_ci		dispatch->pending_event |= EVDEV_ABSOLUTE_MT;
581a46c0ec8Sopenharmony_ci		slot->dirty = true;
582a46c0ec8Sopenharmony_ci		break;
583a46c0ec8Sopenharmony_ci	case ABS_MT_TOOL_TYPE:
584a46c0ec8Sopenharmony_ci		/* The transitions matter - we (may) need to send a touch
585a46c0ec8Sopenharmony_ci		 * cancel event if we just switched to a palm touch. And the
586a46c0ec8Sopenharmony_ci		 * kernel may switch back to finger but we keep the touch as
587a46c0ec8Sopenharmony_ci		 * palm - but then we need to reset correctly on a new touch
588a46c0ec8Sopenharmony_ci		 * sequence.
589a46c0ec8Sopenharmony_ci		 */
590a46c0ec8Sopenharmony_ci		switch (e->value) {
591a46c0ec8Sopenharmony_ci		case MT_TOOL_PALM:
592a46c0ec8Sopenharmony_ci			if (slot->palm_state == PALM_NONE)
593a46c0ec8Sopenharmony_ci				slot->palm_state = PALM_NEW;
594a46c0ec8Sopenharmony_ci			break;
595a46c0ec8Sopenharmony_ci		default:
596a46c0ec8Sopenharmony_ci			if (slot->palm_state == PALM_IS_PALM)
597a46c0ec8Sopenharmony_ci				slot->palm_state = PALM_WAS_PALM;
598a46c0ec8Sopenharmony_ci			break;
599a46c0ec8Sopenharmony_ci		}
600a46c0ec8Sopenharmony_ci		dispatch->pending_event |= EVDEV_ABSOLUTE_MT;
601a46c0ec8Sopenharmony_ci		slot->dirty = true;
602a46c0ec8Sopenharmony_ci		break;
603a46c0ec8Sopenharmony_ci	}
604a46c0ec8Sopenharmony_ci}
605a46c0ec8Sopenharmony_ci
606a46c0ec8Sopenharmony_cistatic inline void
607a46c0ec8Sopenharmony_cifallback_process_absolute_motion(struct fallback_dispatch *dispatch,
608a46c0ec8Sopenharmony_ci				 struct evdev_device *device,
609a46c0ec8Sopenharmony_ci				 struct input_event *e)
610a46c0ec8Sopenharmony_ci{
611a46c0ec8Sopenharmony_ci	switch (e->code) {
612a46c0ec8Sopenharmony_ci	case ABS_X:
613a46c0ec8Sopenharmony_ci		evdev_device_check_abs_axis_range(device, e->code, e->value);
614a46c0ec8Sopenharmony_ci		dispatch->abs.point.x = e->value;
615a46c0ec8Sopenharmony_ci		dispatch->pending_event |= EVDEV_ABSOLUTE_MOTION;
616a46c0ec8Sopenharmony_ci		break;
617a46c0ec8Sopenharmony_ci	case ABS_Y:
618a46c0ec8Sopenharmony_ci		evdev_device_check_abs_axis_range(device, e->code, e->value);
619a46c0ec8Sopenharmony_ci		dispatch->abs.point.y = e->value;
620a46c0ec8Sopenharmony_ci		dispatch->pending_event |= EVDEV_ABSOLUTE_MOTION;
621a46c0ec8Sopenharmony_ci		break;
622a46c0ec8Sopenharmony_ci	}
623a46c0ec8Sopenharmony_ci}
624a46c0ec8Sopenharmony_ci
625a46c0ec8Sopenharmony_cistatic void
626a46c0ec8Sopenharmony_cifallback_lid_keyboard_event(uint64_t time,
627a46c0ec8Sopenharmony_ci			    struct libinput_event *event,
628a46c0ec8Sopenharmony_ci			    void *data)
629a46c0ec8Sopenharmony_ci{
630a46c0ec8Sopenharmony_ci	struct fallback_dispatch *dispatch = fallback_dispatch(data);
631a46c0ec8Sopenharmony_ci
632a46c0ec8Sopenharmony_ci	if (!dispatch->lid.is_closed)
633a46c0ec8Sopenharmony_ci		return;
634a46c0ec8Sopenharmony_ci
635a46c0ec8Sopenharmony_ci	if (event->type != LIBINPUT_EVENT_KEYBOARD_KEY)
636a46c0ec8Sopenharmony_ci		return;
637a46c0ec8Sopenharmony_ci
638a46c0ec8Sopenharmony_ci	if (dispatch->lid.reliability == RELIABILITY_WRITE_OPEN) {
639a46c0ec8Sopenharmony_ci		int fd = libevdev_get_fd(dispatch->device->evdev);
640a46c0ec8Sopenharmony_ci		int rc;
641a46c0ec8Sopenharmony_ci		struct input_event ev[2];
642a46c0ec8Sopenharmony_ci
643a46c0ec8Sopenharmony_ci		ev[0] = input_event_init(0, EV_SW, SW_LID, 0);
644a46c0ec8Sopenharmony_ci		ev[1] = input_event_init(0, EV_SYN, SYN_REPORT, 0);
645a46c0ec8Sopenharmony_ci
646a46c0ec8Sopenharmony_ci		rc = write(fd, ev, sizeof(ev));
647a46c0ec8Sopenharmony_ci
648a46c0ec8Sopenharmony_ci		if (rc < 0)
649a46c0ec8Sopenharmony_ci			evdev_log_error(dispatch->device,
650a46c0ec8Sopenharmony_ci					"failed to write SW_LID state (%s)",
651a46c0ec8Sopenharmony_ci					strerror(errno));
652a46c0ec8Sopenharmony_ci
653a46c0ec8Sopenharmony_ci		/* In case write() fails, we sync the lid state manually
654a46c0ec8Sopenharmony_ci		 * regardless. */
655a46c0ec8Sopenharmony_ci	}
656a46c0ec8Sopenharmony_ci
657a46c0ec8Sopenharmony_ci	/* Posting the event here means we preempt the keyboard events that
658a46c0ec8Sopenharmony_ci	 * caused us to wake up, so the lid event is always passed on before
659a46c0ec8Sopenharmony_ci	 * the key event.
660a46c0ec8Sopenharmony_ci	 */
661a46c0ec8Sopenharmony_ci	dispatch->lid.is_closed = false;
662a46c0ec8Sopenharmony_ci	fallback_lid_notify_toggle(dispatch, dispatch->device, time);
663a46c0ec8Sopenharmony_ci}
664a46c0ec8Sopenharmony_ci
665a46c0ec8Sopenharmony_cistatic void
666a46c0ec8Sopenharmony_cifallback_lid_toggle_keyboard_listener(struct fallback_dispatch *dispatch,
667a46c0ec8Sopenharmony_ci				      struct evdev_paired_keyboard *kbd,
668a46c0ec8Sopenharmony_ci				      bool is_closed)
669a46c0ec8Sopenharmony_ci{
670a46c0ec8Sopenharmony_ci	assert(kbd->device);
671a46c0ec8Sopenharmony_ci
672a46c0ec8Sopenharmony_ci	libinput_device_remove_event_listener(&kbd->listener);
673a46c0ec8Sopenharmony_ci
674a46c0ec8Sopenharmony_ci	if (is_closed) {
675a46c0ec8Sopenharmony_ci		libinput_device_add_event_listener(
676a46c0ec8Sopenharmony_ci					&kbd->device->base,
677a46c0ec8Sopenharmony_ci					&kbd->listener,
678a46c0ec8Sopenharmony_ci					fallback_lid_keyboard_event,
679a46c0ec8Sopenharmony_ci					dispatch);
680a46c0ec8Sopenharmony_ci	} else {
681a46c0ec8Sopenharmony_ci		libinput_device_init_event_listener(&kbd->listener);
682a46c0ec8Sopenharmony_ci	}
683a46c0ec8Sopenharmony_ci}
684a46c0ec8Sopenharmony_ci
685a46c0ec8Sopenharmony_cistatic void
686a46c0ec8Sopenharmony_cifallback_lid_toggle_keyboard_listeners(struct fallback_dispatch *dispatch,
687a46c0ec8Sopenharmony_ci				       bool is_closed)
688a46c0ec8Sopenharmony_ci{
689a46c0ec8Sopenharmony_ci	struct evdev_paired_keyboard *kbd;
690a46c0ec8Sopenharmony_ci
691a46c0ec8Sopenharmony_ci	list_for_each(kbd, &dispatch->lid.paired_keyboard_list, link) {
692a46c0ec8Sopenharmony_ci		if (!kbd->device)
693a46c0ec8Sopenharmony_ci			continue;
694a46c0ec8Sopenharmony_ci
695a46c0ec8Sopenharmony_ci		fallback_lid_toggle_keyboard_listener(dispatch,
696a46c0ec8Sopenharmony_ci						      kbd,
697a46c0ec8Sopenharmony_ci						      is_closed);
698a46c0ec8Sopenharmony_ci	}
699a46c0ec8Sopenharmony_ci}
700a46c0ec8Sopenharmony_ci
701a46c0ec8Sopenharmony_cistatic inline void
702a46c0ec8Sopenharmony_cifallback_process_switch(struct fallback_dispatch *dispatch,
703a46c0ec8Sopenharmony_ci			struct evdev_device *device,
704a46c0ec8Sopenharmony_ci			struct input_event *e,
705a46c0ec8Sopenharmony_ci			uint64_t time)
706a46c0ec8Sopenharmony_ci{
707a46c0ec8Sopenharmony_ci	enum libinput_switch_state state;
708a46c0ec8Sopenharmony_ci	bool is_closed;
709a46c0ec8Sopenharmony_ci
710a46c0ec8Sopenharmony_ci	/* TODO: this should to move to handle_state */
711a46c0ec8Sopenharmony_ci
712a46c0ec8Sopenharmony_ci	switch (e->code) {
713a46c0ec8Sopenharmony_ci	case SW_LID:
714a46c0ec8Sopenharmony_ci		is_closed = !!e->value;
715a46c0ec8Sopenharmony_ci
716a46c0ec8Sopenharmony_ci		fallback_lid_toggle_keyboard_listeners(dispatch, is_closed);
717a46c0ec8Sopenharmony_ci
718a46c0ec8Sopenharmony_ci		if (dispatch->lid.is_closed == is_closed)
719a46c0ec8Sopenharmony_ci			return;
720a46c0ec8Sopenharmony_ci
721a46c0ec8Sopenharmony_ci		dispatch->lid.is_closed = is_closed;
722a46c0ec8Sopenharmony_ci		fallback_lid_notify_toggle(dispatch, device, time);
723a46c0ec8Sopenharmony_ci		break;
724a46c0ec8Sopenharmony_ci	case SW_TABLET_MODE:
725a46c0ec8Sopenharmony_ci		if (dispatch->tablet_mode.sw.state == e->value)
726a46c0ec8Sopenharmony_ci			return;
727a46c0ec8Sopenharmony_ci
728a46c0ec8Sopenharmony_ci		dispatch->tablet_mode.sw.state = e->value;
729a46c0ec8Sopenharmony_ci		if (e->value)
730a46c0ec8Sopenharmony_ci			state = LIBINPUT_SWITCH_STATE_ON;
731a46c0ec8Sopenharmony_ci		else
732a46c0ec8Sopenharmony_ci			state = LIBINPUT_SWITCH_STATE_OFF;
733a46c0ec8Sopenharmony_ci		switch_notify_toggle(&device->base,
734a46c0ec8Sopenharmony_ci				     time,
735a46c0ec8Sopenharmony_ci				     LIBINPUT_SWITCH_TABLET_MODE,
736a46c0ec8Sopenharmony_ci				     state);
737a46c0ec8Sopenharmony_ci		break;
738a46c0ec8Sopenharmony_ci	}
739a46c0ec8Sopenharmony_ci}
740a46c0ec8Sopenharmony_ci
741a46c0ec8Sopenharmony_cistatic inline bool
742a46c0ec8Sopenharmony_cifallback_reject_relative(struct evdev_device *device,
743a46c0ec8Sopenharmony_ci			 const struct input_event *e,
744a46c0ec8Sopenharmony_ci			 uint64_t time)
745a46c0ec8Sopenharmony_ci{
746a46c0ec8Sopenharmony_ci	if ((e->code == REL_X || e->code == REL_Y) &&
747a46c0ec8Sopenharmony_ci	    (device->seat_caps & EVDEV_DEVICE_POINTER) == 0) {
748a46c0ec8Sopenharmony_ci		evdev_log_bug_libinput_ratelimit(device,
749a46c0ec8Sopenharmony_ci						 &device->nonpointer_rel_limit,
750a46c0ec8Sopenharmony_ci						 "REL_X/Y from a non-pointer device\n");
751a46c0ec8Sopenharmony_ci		return true;
752a46c0ec8Sopenharmony_ci	}
753a46c0ec8Sopenharmony_ci
754a46c0ec8Sopenharmony_ci	return false;
755a46c0ec8Sopenharmony_ci}
756a46c0ec8Sopenharmony_ci
757a46c0ec8Sopenharmony_cistatic inline void
758a46c0ec8Sopenharmony_cifallback_process_relative(struct fallback_dispatch *dispatch,
759a46c0ec8Sopenharmony_ci			  struct evdev_device *device,
760a46c0ec8Sopenharmony_ci			  struct input_event *e, uint64_t time)
761a46c0ec8Sopenharmony_ci{
762a46c0ec8Sopenharmony_ci	if (fallback_reject_relative(device, e, time))
763a46c0ec8Sopenharmony_ci		return;
764a46c0ec8Sopenharmony_ci
765a46c0ec8Sopenharmony_ci	switch (e->code) {
766a46c0ec8Sopenharmony_ci	case REL_X:
767a46c0ec8Sopenharmony_ci		dispatch->rel.x += e->value;
768a46c0ec8Sopenharmony_ci		dispatch->pending_event |= EVDEV_RELATIVE_MOTION;
769a46c0ec8Sopenharmony_ci		break;
770a46c0ec8Sopenharmony_ci	case REL_Y:
771a46c0ec8Sopenharmony_ci		dispatch->rel.y += e->value;
772a46c0ec8Sopenharmony_ci		dispatch->pending_event |= EVDEV_RELATIVE_MOTION;
773a46c0ec8Sopenharmony_ci		break;
774a46c0ec8Sopenharmony_ci	}
775a46c0ec8Sopenharmony_ci
776a46c0ec8Sopenharmony_ci	fallback_wheel_process_relative(dispatch, device, e, time);
777a46c0ec8Sopenharmony_ci}
778a46c0ec8Sopenharmony_ci
779a46c0ec8Sopenharmony_cistatic inline void
780a46c0ec8Sopenharmony_cifallback_process_absolute(struct fallback_dispatch *dispatch,
781a46c0ec8Sopenharmony_ci			  struct evdev_device *device,
782a46c0ec8Sopenharmony_ci			  struct input_event *e,
783a46c0ec8Sopenharmony_ci			  uint64_t time)
784a46c0ec8Sopenharmony_ci{
785a46c0ec8Sopenharmony_ci	if (device->is_mt) {
786a46c0ec8Sopenharmony_ci		fallback_process_touch(dispatch, device, e, time);
787a46c0ec8Sopenharmony_ci	} else {
788a46c0ec8Sopenharmony_ci		fallback_process_absolute_motion(dispatch, device, e);
789a46c0ec8Sopenharmony_ci	}
790a46c0ec8Sopenharmony_ci}
791a46c0ec8Sopenharmony_ci
792a46c0ec8Sopenharmony_cistatic inline bool
793a46c0ec8Sopenharmony_cifallback_any_button_down(struct fallback_dispatch *dispatch,
794a46c0ec8Sopenharmony_ci		      struct evdev_device *device)
795a46c0ec8Sopenharmony_ci{
796a46c0ec8Sopenharmony_ci	unsigned int button;
797a46c0ec8Sopenharmony_ci
798a46c0ec8Sopenharmony_ci	for (button = BTN_LEFT; button < BTN_JOYSTICK; button++) {
799a46c0ec8Sopenharmony_ci		if (libevdev_has_event_code(device->evdev, EV_KEY, button) &&
800a46c0ec8Sopenharmony_ci		    hw_is_key_down(dispatch, button))
801a46c0ec8Sopenharmony_ci			return true;
802a46c0ec8Sopenharmony_ci	}
803a46c0ec8Sopenharmony_ci	return false;
804a46c0ec8Sopenharmony_ci}
805a46c0ec8Sopenharmony_ci
806a46c0ec8Sopenharmony_cistatic inline bool
807a46c0ec8Sopenharmony_cifallback_arbitrate_touch(struct fallback_dispatch *dispatch,
808a46c0ec8Sopenharmony_ci			 struct mt_slot *slot)
809a46c0ec8Sopenharmony_ci{
810a46c0ec8Sopenharmony_ci	bool discard = false;
811a46c0ec8Sopenharmony_ci	struct device_coords point = slot->point;
812a46c0ec8Sopenharmony_ci	evdev_transform_absolute(dispatch->device, &point);
813a46c0ec8Sopenharmony_ci
814a46c0ec8Sopenharmony_ci	if (dispatch->arbitration.state == ARBITRATION_IGNORE_RECT &&
815a46c0ec8Sopenharmony_ci	    point_in_rect(&point, &dispatch->arbitration.rect)) {
816a46c0ec8Sopenharmony_ci		slot->palm_state = PALM_IS_PALM;
817a46c0ec8Sopenharmony_ci		discard = true;
818a46c0ec8Sopenharmony_ci	}
819a46c0ec8Sopenharmony_ci
820a46c0ec8Sopenharmony_ci	return discard;
821a46c0ec8Sopenharmony_ci}
822a46c0ec8Sopenharmony_ci
823a46c0ec8Sopenharmony_cistatic inline bool
824a46c0ec8Sopenharmony_cifallback_flush_mt_events(struct fallback_dispatch *dispatch,
825a46c0ec8Sopenharmony_ci			 struct evdev_device *device,
826a46c0ec8Sopenharmony_ci			 uint64_t time)
827a46c0ec8Sopenharmony_ci{
828a46c0ec8Sopenharmony_ci	bool sent = false;
829a46c0ec8Sopenharmony_ci
830a46c0ec8Sopenharmony_ci	for (size_t i = 0; i < dispatch->mt.slots_len; i++) {
831a46c0ec8Sopenharmony_ci		struct mt_slot *slot = &dispatch->mt.slots[i];
832a46c0ec8Sopenharmony_ci
833a46c0ec8Sopenharmony_ci		if (!slot->dirty)
834a46c0ec8Sopenharmony_ci			continue;
835a46c0ec8Sopenharmony_ci
836a46c0ec8Sopenharmony_ci		slot->dirty = false;
837a46c0ec8Sopenharmony_ci
838a46c0ec8Sopenharmony_ci		/* Any palm state other than PALM_NEW means we've either
839a46c0ec8Sopenharmony_ci		 * already cancelled the touch or the touch was never
840a46c0ec8Sopenharmony_ci		 * a finger anyway and we didn't send the begin.
841a46c0ec8Sopenharmony_ci		 */
842a46c0ec8Sopenharmony_ci		if (slot->palm_state == PALM_NEW) {
843a46c0ec8Sopenharmony_ci			if (slot->state != SLOT_STATE_BEGIN)
844a46c0ec8Sopenharmony_ci				sent = fallback_flush_mt_cancel(dispatch,
845a46c0ec8Sopenharmony_ci								device,
846a46c0ec8Sopenharmony_ci								i,
847a46c0ec8Sopenharmony_ci								time);
848a46c0ec8Sopenharmony_ci			slot->palm_state = PALM_IS_PALM;
849a46c0ec8Sopenharmony_ci		} else if (slot->palm_state == PALM_NONE) {
850a46c0ec8Sopenharmony_ci			switch (slot->state) {
851a46c0ec8Sopenharmony_ci			case SLOT_STATE_BEGIN:
852a46c0ec8Sopenharmony_ci				if (!fallback_arbitrate_touch(dispatch,
853a46c0ec8Sopenharmony_ci							     slot)) {
854a46c0ec8Sopenharmony_ci					sent = fallback_flush_mt_down(dispatch,
855a46c0ec8Sopenharmony_ci								      device,
856a46c0ec8Sopenharmony_ci								      i,
857a46c0ec8Sopenharmony_ci								      time);
858a46c0ec8Sopenharmony_ci				}
859a46c0ec8Sopenharmony_ci				break;
860a46c0ec8Sopenharmony_ci			case SLOT_STATE_UPDATE:
861a46c0ec8Sopenharmony_ci				sent = fallback_flush_mt_motion(dispatch,
862a46c0ec8Sopenharmony_ci								device,
863a46c0ec8Sopenharmony_ci								i,
864a46c0ec8Sopenharmony_ci								time);
865a46c0ec8Sopenharmony_ci				break;
866a46c0ec8Sopenharmony_ci			case SLOT_STATE_END:
867a46c0ec8Sopenharmony_ci				sent = fallback_flush_mt_up(dispatch,
868a46c0ec8Sopenharmony_ci							    device,
869a46c0ec8Sopenharmony_ci							    i,
870a46c0ec8Sopenharmony_ci							    time);
871a46c0ec8Sopenharmony_ci				break;
872a46c0ec8Sopenharmony_ci			case SLOT_STATE_NONE:
873a46c0ec8Sopenharmony_ci				break;
874a46c0ec8Sopenharmony_ci			}
875a46c0ec8Sopenharmony_ci		}
876a46c0ec8Sopenharmony_ci
877a46c0ec8Sopenharmony_ci		/* State machine continues independent of the palm state */
878a46c0ec8Sopenharmony_ci		switch (slot->state) {
879a46c0ec8Sopenharmony_ci		case SLOT_STATE_BEGIN:
880a46c0ec8Sopenharmony_ci			slot->state = SLOT_STATE_UPDATE;
881a46c0ec8Sopenharmony_ci			break;
882a46c0ec8Sopenharmony_ci		case SLOT_STATE_UPDATE:
883a46c0ec8Sopenharmony_ci			break;
884a46c0ec8Sopenharmony_ci		case SLOT_STATE_END:
885a46c0ec8Sopenharmony_ci			slot->state = SLOT_STATE_NONE;
886a46c0ec8Sopenharmony_ci			break;
887a46c0ec8Sopenharmony_ci		case SLOT_STATE_NONE:
888a46c0ec8Sopenharmony_ci			/* touch arbitration may swallow the begin,
889a46c0ec8Sopenharmony_ci			 * so we may get updates for a touch still
890a46c0ec8Sopenharmony_ci			 * in NONE state */
891a46c0ec8Sopenharmony_ci			break;
892a46c0ec8Sopenharmony_ci		}
893a46c0ec8Sopenharmony_ci	}
894a46c0ec8Sopenharmony_ci
895a46c0ec8Sopenharmony_ci	return sent;
896a46c0ec8Sopenharmony_ci}
897a46c0ec8Sopenharmony_ci
898a46c0ec8Sopenharmony_cistatic void
899a46c0ec8Sopenharmony_cifallback_handle_state(struct fallback_dispatch *dispatch,
900a46c0ec8Sopenharmony_ci		      struct evdev_device *device,
901a46c0ec8Sopenharmony_ci		      uint64_t time)
902a46c0ec8Sopenharmony_ci{
903a46c0ec8Sopenharmony_ci	bool need_touch_frame = false;
904a46c0ec8Sopenharmony_ci
905a46c0ec8Sopenharmony_ci	/* Relative motion */
906a46c0ec8Sopenharmony_ci	if (dispatch->pending_event & EVDEV_RELATIVE_MOTION)
907a46c0ec8Sopenharmony_ci		fallback_flush_relative_motion(dispatch, device, time);
908a46c0ec8Sopenharmony_ci
909a46c0ec8Sopenharmony_ci	/* Single touch or absolute pointer devices */
910a46c0ec8Sopenharmony_ci	if (dispatch->pending_event & EVDEV_ABSOLUTE_TOUCH_DOWN) {
911a46c0ec8Sopenharmony_ci		if (fallback_flush_st_down(dispatch, device, time))
912a46c0ec8Sopenharmony_ci			need_touch_frame = true;
913a46c0ec8Sopenharmony_ci	} else if (dispatch->pending_event & EVDEV_ABSOLUTE_MOTION) {
914a46c0ec8Sopenharmony_ci		if (device->seat_caps & EVDEV_DEVICE_TOUCH) {
915a46c0ec8Sopenharmony_ci			if (fallback_flush_st_motion(dispatch,
916a46c0ec8Sopenharmony_ci						     device,
917a46c0ec8Sopenharmony_ci						     time))
918a46c0ec8Sopenharmony_ci				need_touch_frame = true;
919a46c0ec8Sopenharmony_ci		} else if (device->seat_caps & EVDEV_DEVICE_POINTER) {
920a46c0ec8Sopenharmony_ci			fallback_flush_absolute_motion(dispatch,
921a46c0ec8Sopenharmony_ci						       device,
922a46c0ec8Sopenharmony_ci						       time);
923a46c0ec8Sopenharmony_ci		}
924a46c0ec8Sopenharmony_ci	}
925a46c0ec8Sopenharmony_ci
926a46c0ec8Sopenharmony_ci	if (dispatch->pending_event & EVDEV_ABSOLUTE_TOUCH_UP) {
927a46c0ec8Sopenharmony_ci		if (fallback_flush_st_up(dispatch, device, time))
928a46c0ec8Sopenharmony_ci			need_touch_frame = true;
929a46c0ec8Sopenharmony_ci	}
930a46c0ec8Sopenharmony_ci
931a46c0ec8Sopenharmony_ci	/* Multitouch devices */
932a46c0ec8Sopenharmony_ci	if (dispatch->pending_event & EVDEV_ABSOLUTE_MT)
933a46c0ec8Sopenharmony_ci		need_touch_frame = fallback_flush_mt_events(dispatch,
934a46c0ec8Sopenharmony_ci							    device,
935a46c0ec8Sopenharmony_ci							    time);
936a46c0ec8Sopenharmony_ci
937a46c0ec8Sopenharmony_ci	if (need_touch_frame)
938a46c0ec8Sopenharmony_ci		touch_notify_frame(&device->base, time);
939a46c0ec8Sopenharmony_ci
940a46c0ec8Sopenharmony_ci	fallback_wheel_handle_state(dispatch, device, time);
941a46c0ec8Sopenharmony_ci
942a46c0ec8Sopenharmony_ci	/* Buttons and keys */
943a46c0ec8Sopenharmony_ci	if (dispatch->pending_event & EVDEV_KEY) {
944a46c0ec8Sopenharmony_ci		bool want_debounce = false;
945a46c0ec8Sopenharmony_ci		for (unsigned int code = 0; code <= KEY_MAX; code++) {
946a46c0ec8Sopenharmony_ci			if (!hw_key_has_changed(dispatch, code))
947a46c0ec8Sopenharmony_ci				continue;
948a46c0ec8Sopenharmony_ci
949a46c0ec8Sopenharmony_ci			if (get_key_type(code) == KEY_TYPE_BUTTON) {
950a46c0ec8Sopenharmony_ci				want_debounce = true;
951a46c0ec8Sopenharmony_ci				break;
952a46c0ec8Sopenharmony_ci			}
953a46c0ec8Sopenharmony_ci		}
954a46c0ec8Sopenharmony_ci
955a46c0ec8Sopenharmony_ci		if (want_debounce)
956a46c0ec8Sopenharmony_ci			fallback_debounce_handle_state(dispatch, time);
957a46c0ec8Sopenharmony_ci
958a46c0ec8Sopenharmony_ci		hw_key_update_last_state(dispatch);
959a46c0ec8Sopenharmony_ci	}
960a46c0ec8Sopenharmony_ci
961a46c0ec8Sopenharmony_ci	dispatch->pending_event = EVDEV_NONE;
962a46c0ec8Sopenharmony_ci}
963a46c0ec8Sopenharmony_ci
964a46c0ec8Sopenharmony_cistatic void
965a46c0ec8Sopenharmony_cifallback_interface_process(struct evdev_dispatch *evdev_dispatch,
966a46c0ec8Sopenharmony_ci			   struct evdev_device *device,
967a46c0ec8Sopenharmony_ci			   struct input_event *event,
968a46c0ec8Sopenharmony_ci			   uint64_t time)
969a46c0ec8Sopenharmony_ci{
970a46c0ec8Sopenharmony_ci	struct fallback_dispatch *dispatch = fallback_dispatch(evdev_dispatch);
971a46c0ec8Sopenharmony_ci	static bool warned = false;
972a46c0ec8Sopenharmony_ci
973a46c0ec8Sopenharmony_ci	if (dispatch->arbitration.in_arbitration) {
974a46c0ec8Sopenharmony_ci		if (!warned) {
975a46c0ec8Sopenharmony_ci			evdev_log_debug(device, "dropping events due to touch arbitration\n");
976a46c0ec8Sopenharmony_ci			warned = true;
977a46c0ec8Sopenharmony_ci		}
978a46c0ec8Sopenharmony_ci		return;
979a46c0ec8Sopenharmony_ci	}
980a46c0ec8Sopenharmony_ci
981a46c0ec8Sopenharmony_ci	warned = false;
982a46c0ec8Sopenharmony_ci
983a46c0ec8Sopenharmony_ci	switch (event->type) {
984a46c0ec8Sopenharmony_ci	case EV_REL:
985a46c0ec8Sopenharmony_ci		fallback_process_relative(dispatch, device, event, time);
986a46c0ec8Sopenharmony_ci		break;
987a46c0ec8Sopenharmony_ci	case EV_ABS:
988a46c0ec8Sopenharmony_ci		fallback_process_absolute(dispatch, device, event, time);
989a46c0ec8Sopenharmony_ci		break;
990a46c0ec8Sopenharmony_ci	case EV_KEY:
991a46c0ec8Sopenharmony_ci		fallback_process_key(dispatch, device, event, time);
992a46c0ec8Sopenharmony_ci		break;
993a46c0ec8Sopenharmony_ci	case EV_SW:
994a46c0ec8Sopenharmony_ci		fallback_process_switch(dispatch, device, event, time);
995a46c0ec8Sopenharmony_ci		break;
996a46c0ec8Sopenharmony_ci	case EV_SYN:
997a46c0ec8Sopenharmony_ci		fallback_handle_state(dispatch, device, time);
998a46c0ec8Sopenharmony_ci		break;
999a46c0ec8Sopenharmony_ci	}
1000a46c0ec8Sopenharmony_ci}
1001a46c0ec8Sopenharmony_ci
1002a46c0ec8Sopenharmony_cistatic void
1003a46c0ec8Sopenharmony_cicancel_touches(struct fallback_dispatch *dispatch,
1004a46c0ec8Sopenharmony_ci	       struct evdev_device *device,
1005a46c0ec8Sopenharmony_ci	       const struct device_coord_rect *rect,
1006a46c0ec8Sopenharmony_ci	       uint64_t time)
1007a46c0ec8Sopenharmony_ci{
1008a46c0ec8Sopenharmony_ci	unsigned int idx;
1009a46c0ec8Sopenharmony_ci	bool need_frame = false;
1010a46c0ec8Sopenharmony_ci	struct device_coords point;
1011a46c0ec8Sopenharmony_ci
1012a46c0ec8Sopenharmony_ci	point = dispatch->abs.point;
1013a46c0ec8Sopenharmony_ci	evdev_transform_absolute(device, &point);
1014a46c0ec8Sopenharmony_ci	if (!rect || point_in_rect(&point, rect))
1015a46c0ec8Sopenharmony_ci		need_frame = fallback_flush_st_cancel(dispatch,
1016a46c0ec8Sopenharmony_ci						      device,
1017a46c0ec8Sopenharmony_ci						      time);
1018a46c0ec8Sopenharmony_ci
1019a46c0ec8Sopenharmony_ci	for (idx = 0; idx < dispatch->mt.slots_len; idx++) {
1020a46c0ec8Sopenharmony_ci		struct mt_slot *slot = &dispatch->mt.slots[idx];
1021a46c0ec8Sopenharmony_ci		point = slot->point;
1022a46c0ec8Sopenharmony_ci		evdev_transform_absolute(device, &point);
1023a46c0ec8Sopenharmony_ci
1024a46c0ec8Sopenharmony_ci		if (slot->seat_slot == -1)
1025a46c0ec8Sopenharmony_ci			continue;
1026a46c0ec8Sopenharmony_ci
1027a46c0ec8Sopenharmony_ci		if ((!rect || point_in_rect(&point, rect)) &&
1028a46c0ec8Sopenharmony_ci		    fallback_flush_mt_cancel(dispatch, device, idx, time))
1029a46c0ec8Sopenharmony_ci			need_frame = true;
1030a46c0ec8Sopenharmony_ci	}
1031a46c0ec8Sopenharmony_ci
1032a46c0ec8Sopenharmony_ci	if (need_frame)
1033a46c0ec8Sopenharmony_ci		touch_notify_frame(&device->base, time);
1034a46c0ec8Sopenharmony_ci}
1035a46c0ec8Sopenharmony_ci
1036a46c0ec8Sopenharmony_cistatic void
1037a46c0ec8Sopenharmony_cirelease_pressed_keys(struct fallback_dispatch *dispatch,
1038a46c0ec8Sopenharmony_ci		     struct evdev_device *device,
1039a46c0ec8Sopenharmony_ci		     uint64_t time)
1040a46c0ec8Sopenharmony_ci{
1041a46c0ec8Sopenharmony_ci	int code;
1042a46c0ec8Sopenharmony_ci
1043a46c0ec8Sopenharmony_ci	for (code = 0; code < KEY_CNT; code++) {
1044a46c0ec8Sopenharmony_ci		int count = get_key_down_count(device, code);
1045a46c0ec8Sopenharmony_ci
1046a46c0ec8Sopenharmony_ci		if (count == 0)
1047a46c0ec8Sopenharmony_ci			continue;
1048a46c0ec8Sopenharmony_ci
1049a46c0ec8Sopenharmony_ci		if (count > 1) {
1050a46c0ec8Sopenharmony_ci			evdev_log_bug_libinput(device,
1051a46c0ec8Sopenharmony_ci					       "key %d is down %d times.\n",
1052a46c0ec8Sopenharmony_ci					       code,
1053a46c0ec8Sopenharmony_ci					       count);
1054a46c0ec8Sopenharmony_ci		}
1055a46c0ec8Sopenharmony_ci
1056a46c0ec8Sopenharmony_ci		switch (get_key_type(code)) {
1057a46c0ec8Sopenharmony_ci		case KEY_TYPE_NONE:
1058a46c0ec8Sopenharmony_ci			break;
1059a46c0ec8Sopenharmony_ci		case KEY_TYPE_KEY:
1060a46c0ec8Sopenharmony_ci			fallback_keyboard_notify_key(
1061a46c0ec8Sopenharmony_ci				dispatch,
1062a46c0ec8Sopenharmony_ci				device,
1063a46c0ec8Sopenharmony_ci				time,
1064a46c0ec8Sopenharmony_ci				code,
1065a46c0ec8Sopenharmony_ci				LIBINPUT_KEY_STATE_RELEASED);
1066a46c0ec8Sopenharmony_ci			break;
1067a46c0ec8Sopenharmony_ci		case KEY_TYPE_BUTTON:
1068a46c0ec8Sopenharmony_ci			/* Note: the left-handed configuration is nonzero for
1069a46c0ec8Sopenharmony_ci			 * the mapped button (not the physical button), in
1070a46c0ec8Sopenharmony_ci			 * get_key_down_count(). We must not map this to left-handed
1071a46c0ec8Sopenharmony_ci			 * again, see #881.
1072a46c0ec8Sopenharmony_ci			 */
1073a46c0ec8Sopenharmony_ci			evdev_pointer_notify_button(
1074a46c0ec8Sopenharmony_ci				device,
1075a46c0ec8Sopenharmony_ci				time,
1076a46c0ec8Sopenharmony_ci				code,
1077a46c0ec8Sopenharmony_ci				LIBINPUT_BUTTON_STATE_RELEASED);
1078a46c0ec8Sopenharmony_ci			break;
1079a46c0ec8Sopenharmony_ci		}
1080a46c0ec8Sopenharmony_ci
1081a46c0ec8Sopenharmony_ci		count = get_key_down_count(device, code);
1082a46c0ec8Sopenharmony_ci		if (count != 0) {
1083a46c0ec8Sopenharmony_ci			evdev_log_bug_libinput(device,
1084a46c0ec8Sopenharmony_ci					       "releasing key %d failed.\n",
1085a46c0ec8Sopenharmony_ci					       code);
1086a46c0ec8Sopenharmony_ci			break;
1087a46c0ec8Sopenharmony_ci		}
1088a46c0ec8Sopenharmony_ci	}
1089a46c0ec8Sopenharmony_ci}
1090a46c0ec8Sopenharmony_ci
1091a46c0ec8Sopenharmony_cistatic void
1092a46c0ec8Sopenharmony_cifallback_return_to_neutral_state(struct fallback_dispatch *dispatch,
1093a46c0ec8Sopenharmony_ci				 struct evdev_device *device)
1094a46c0ec8Sopenharmony_ci{
1095a46c0ec8Sopenharmony_ci	struct libinput *libinput = evdev_libinput_context(device);
1096a46c0ec8Sopenharmony_ci	uint64_t time;
1097a46c0ec8Sopenharmony_ci
1098a46c0ec8Sopenharmony_ci	if ((time = libinput_now(libinput)) == 0)
1099a46c0ec8Sopenharmony_ci		return;
1100a46c0ec8Sopenharmony_ci
1101a46c0ec8Sopenharmony_ci	cancel_touches(dispatch, device, NULL, time);
1102a46c0ec8Sopenharmony_ci	release_pressed_keys(dispatch, device, time);
1103a46c0ec8Sopenharmony_ci	memset(dispatch->hw_key_mask, 0, sizeof(dispatch->hw_key_mask));
1104a46c0ec8Sopenharmony_ci	memset(dispatch->hw_key_mask, 0, sizeof(dispatch->last_hw_key_mask));
1105a46c0ec8Sopenharmony_ci}
1106a46c0ec8Sopenharmony_ci
1107a46c0ec8Sopenharmony_cistatic void
1108a46c0ec8Sopenharmony_cifallback_interface_suspend(struct evdev_dispatch *evdev_dispatch,
1109a46c0ec8Sopenharmony_ci			   struct evdev_device *device)
1110a46c0ec8Sopenharmony_ci{
1111a46c0ec8Sopenharmony_ci	struct fallback_dispatch *dispatch = fallback_dispatch(evdev_dispatch);
1112a46c0ec8Sopenharmony_ci
1113a46c0ec8Sopenharmony_ci	fallback_return_to_neutral_state(dispatch, device);
1114a46c0ec8Sopenharmony_ci}
1115a46c0ec8Sopenharmony_ci
1116a46c0ec8Sopenharmony_cistatic void
1117a46c0ec8Sopenharmony_cifallback_interface_remove(struct evdev_dispatch *evdev_dispatch)
1118a46c0ec8Sopenharmony_ci{
1119a46c0ec8Sopenharmony_ci	struct fallback_dispatch *dispatch = fallback_dispatch(evdev_dispatch);
1120a46c0ec8Sopenharmony_ci	struct evdev_paired_keyboard *kbd;
1121a46c0ec8Sopenharmony_ci
1122a46c0ec8Sopenharmony_ci	libinput_timer_cancel(&dispatch->wheel.scroll_timer);
1123a46c0ec8Sopenharmony_ci	libinput_timer_cancel(&dispatch->debounce.timer);
1124a46c0ec8Sopenharmony_ci	libinput_timer_cancel(&dispatch->debounce.timer_short);
1125a46c0ec8Sopenharmony_ci	libinput_timer_cancel(&dispatch->arbitration.arbitration_timer);
1126a46c0ec8Sopenharmony_ci
1127a46c0ec8Sopenharmony_ci	libinput_device_remove_event_listener(&dispatch->tablet_mode.other.listener);
1128a46c0ec8Sopenharmony_ci
1129a46c0ec8Sopenharmony_ci	list_for_each_safe(kbd,
1130a46c0ec8Sopenharmony_ci			   &dispatch->lid.paired_keyboard_list,
1131a46c0ec8Sopenharmony_ci			   link) {
1132a46c0ec8Sopenharmony_ci		evdev_paired_keyboard_destroy(kbd);
1133a46c0ec8Sopenharmony_ci	}
1134a46c0ec8Sopenharmony_ci}
1135a46c0ec8Sopenharmony_ci
1136a46c0ec8Sopenharmony_cistatic void
1137a46c0ec8Sopenharmony_cifallback_interface_sync_initial_state(struct evdev_device *device,
1138a46c0ec8Sopenharmony_ci				      struct evdev_dispatch *evdev_dispatch)
1139a46c0ec8Sopenharmony_ci{
1140a46c0ec8Sopenharmony_ci	struct fallback_dispatch *dispatch = fallback_dispatch(evdev_dispatch);
1141a46c0ec8Sopenharmony_ci	uint64_t time = libinput_now(evdev_libinput_context(device));
1142a46c0ec8Sopenharmony_ci
1143a46c0ec8Sopenharmony_ci	if (device->tags & EVDEV_TAG_LID_SWITCH) {
1144a46c0ec8Sopenharmony_ci		struct libevdev *evdev = device->evdev;
1145a46c0ec8Sopenharmony_ci
1146a46c0ec8Sopenharmony_ci		dispatch->lid.is_closed = libevdev_get_event_value(evdev,
1147a46c0ec8Sopenharmony_ci								   EV_SW,
1148a46c0ec8Sopenharmony_ci								   SW_LID);
1149a46c0ec8Sopenharmony_ci		dispatch->lid.is_closed_client_state = false;
1150a46c0ec8Sopenharmony_ci
1151a46c0ec8Sopenharmony_ci		/* For the initial state sync, we depend on whether the lid switch
1152a46c0ec8Sopenharmony_ci		 * is reliable. If we know it's reliable, we sync as expected.
1153a46c0ec8Sopenharmony_ci		 * If we're not sure, we ignore the initial state and only sync on
1154a46c0ec8Sopenharmony_ci		 * the first future lid close event. Laptops with a broken switch
1155a46c0ec8Sopenharmony_ci		 * that always have the switch in 'on' state thus don't mess up our
1156a46c0ec8Sopenharmony_ci		 * touchpad.
1157a46c0ec8Sopenharmony_ci		 */
1158a46c0ec8Sopenharmony_ci		if (dispatch->lid.is_closed &&
1159a46c0ec8Sopenharmony_ci		    dispatch->lid.reliability == RELIABILITY_RELIABLE) {
1160a46c0ec8Sopenharmony_ci			fallback_lid_notify_toggle(dispatch, device, time);
1161a46c0ec8Sopenharmony_ci		}
1162a46c0ec8Sopenharmony_ci	}
1163a46c0ec8Sopenharmony_ci
1164a46c0ec8Sopenharmony_ci	if (dispatch->tablet_mode.sw.state) {
1165a46c0ec8Sopenharmony_ci		switch_notify_toggle(&device->base,
1166a46c0ec8Sopenharmony_ci				     time,
1167a46c0ec8Sopenharmony_ci				     LIBINPUT_SWITCH_TABLET_MODE,
1168a46c0ec8Sopenharmony_ci				     LIBINPUT_SWITCH_STATE_ON);
1169a46c0ec8Sopenharmony_ci	}
1170a46c0ec8Sopenharmony_ci}
1171a46c0ec8Sopenharmony_ci
1172a46c0ec8Sopenharmony_cistatic void
1173a46c0ec8Sopenharmony_cifallback_interface_update_rect(struct evdev_dispatch *evdev_dispatch,
1174a46c0ec8Sopenharmony_ci			       struct evdev_device *device,
1175a46c0ec8Sopenharmony_ci				const struct phys_rect *phys_rect,
1176a46c0ec8Sopenharmony_ci				uint64_t time)
1177a46c0ec8Sopenharmony_ci{
1178a46c0ec8Sopenharmony_ci	struct fallback_dispatch *dispatch = fallback_dispatch(evdev_dispatch);
1179a46c0ec8Sopenharmony_ci	struct device_coord_rect rect;
1180a46c0ec8Sopenharmony_ci
1181a46c0ec8Sopenharmony_ci	assert(phys_rect);
1182a46c0ec8Sopenharmony_ci
1183a46c0ec8Sopenharmony_ci	/* Existing touches do not change, we just update the rect and only
1184a46c0ec8Sopenharmony_ci	 * new touches in these areas will be ignored. If you want to paint
1185a46c0ec8Sopenharmony_ci	 * over your finger, be my guest. */
1186a46c0ec8Sopenharmony_ci	rect = evdev_phys_rect_to_units(device, phys_rect);
1187a46c0ec8Sopenharmony_ci	dispatch->arbitration.rect = rect;
1188a46c0ec8Sopenharmony_ci}
1189a46c0ec8Sopenharmony_ci
1190a46c0ec8Sopenharmony_cistatic void
1191a46c0ec8Sopenharmony_cifallback_interface_toggle_touch(struct evdev_dispatch *evdev_dispatch,
1192a46c0ec8Sopenharmony_ci				struct evdev_device *device,
1193a46c0ec8Sopenharmony_ci				enum evdev_arbitration_state which,
1194a46c0ec8Sopenharmony_ci				const struct phys_rect *phys_rect,
1195a46c0ec8Sopenharmony_ci				uint64_t time)
1196a46c0ec8Sopenharmony_ci{
1197a46c0ec8Sopenharmony_ci	struct fallback_dispatch *dispatch = fallback_dispatch(evdev_dispatch);
1198a46c0ec8Sopenharmony_ci	struct device_coord_rect rect = {0};
1199a46c0ec8Sopenharmony_ci	const char *state = NULL;
1200a46c0ec8Sopenharmony_ci
1201a46c0ec8Sopenharmony_ci	if (which == dispatch->arbitration.state)
1202a46c0ec8Sopenharmony_ci		return;
1203a46c0ec8Sopenharmony_ci
1204a46c0ec8Sopenharmony_ci	switch (which) {
1205a46c0ec8Sopenharmony_ci	case ARBITRATION_NOT_ACTIVE:
1206a46c0ec8Sopenharmony_ci		/* if in-kernel arbitration is in use and there is a touch
1207a46c0ec8Sopenharmony_ci		 * and a pen in proximity, lifting the pen out of proximity
1208a46c0ec8Sopenharmony_ci		 * causes a touch begin for the touch. On a hand-lift the
1209a46c0ec8Sopenharmony_ci		 * proximity out precedes the touch up by a few ms, so we
1210a46c0ec8Sopenharmony_ci		 * get what looks like a tap. Fix this by delaying
1211a46c0ec8Sopenharmony_ci		 * arbitration by just a little bit so that any touch in
1212a46c0ec8Sopenharmony_ci		 * event is caught as palm touch. */
1213a46c0ec8Sopenharmony_ci		libinput_timer_set(&dispatch->arbitration.arbitration_timer,
1214a46c0ec8Sopenharmony_ci				   time + ms2us(90));
1215a46c0ec8Sopenharmony_ci		state = "not-active";
1216a46c0ec8Sopenharmony_ci		break;
1217a46c0ec8Sopenharmony_ci	case ARBITRATION_IGNORE_RECT:
1218a46c0ec8Sopenharmony_ci		assert(phys_rect);
1219a46c0ec8Sopenharmony_ci		rect = evdev_phys_rect_to_units(device, phys_rect);
1220a46c0ec8Sopenharmony_ci		cancel_touches(dispatch, device, &rect, time);
1221a46c0ec8Sopenharmony_ci		dispatch->arbitration.rect = rect;
1222a46c0ec8Sopenharmony_ci		state = "ignore-rect";
1223a46c0ec8Sopenharmony_ci		break;
1224a46c0ec8Sopenharmony_ci	case ARBITRATION_IGNORE_ALL:
1225a46c0ec8Sopenharmony_ci		libinput_timer_cancel(&dispatch->arbitration.arbitration_timer);
1226a46c0ec8Sopenharmony_ci		fallback_return_to_neutral_state(dispatch, device);
1227a46c0ec8Sopenharmony_ci		dispatch->arbitration.in_arbitration = true;
1228a46c0ec8Sopenharmony_ci		state = "ignore-all";
1229a46c0ec8Sopenharmony_ci		break;
1230a46c0ec8Sopenharmony_ci	}
1231a46c0ec8Sopenharmony_ci
1232a46c0ec8Sopenharmony_ci	evdev_log_debug(device, "Touch arbitration state now %s\n", state);
1233a46c0ec8Sopenharmony_ci
1234a46c0ec8Sopenharmony_ci	dispatch->arbitration.state = which;
1235a46c0ec8Sopenharmony_ci}
1236a46c0ec8Sopenharmony_ci
1237a46c0ec8Sopenharmony_cistatic void
1238a46c0ec8Sopenharmony_cifallback_interface_destroy(struct evdev_dispatch *evdev_dispatch)
1239a46c0ec8Sopenharmony_ci{
1240a46c0ec8Sopenharmony_ci	struct fallback_dispatch *dispatch = fallback_dispatch(evdev_dispatch);
1241a46c0ec8Sopenharmony_ci
1242a46c0ec8Sopenharmony_ci	libinput_timer_destroy(&dispatch->wheel.scroll_timer);
1243a46c0ec8Sopenharmony_ci	libinput_timer_destroy(&dispatch->arbitration.arbitration_timer);
1244a46c0ec8Sopenharmony_ci	libinput_timer_destroy(&dispatch->debounce.timer);
1245a46c0ec8Sopenharmony_ci	libinput_timer_destroy(&dispatch->debounce.timer_short);
1246a46c0ec8Sopenharmony_ci
1247a46c0ec8Sopenharmony_ci	free(dispatch->mt.slots);
1248a46c0ec8Sopenharmony_ci	free(dispatch);
1249a46c0ec8Sopenharmony_ci}
1250a46c0ec8Sopenharmony_ci
1251a46c0ec8Sopenharmony_cistatic void
1252a46c0ec8Sopenharmony_cifallback_lid_pair_keyboard(struct evdev_device *lid_switch,
1253a46c0ec8Sopenharmony_ci			   struct evdev_device *keyboard)
1254a46c0ec8Sopenharmony_ci{
1255a46c0ec8Sopenharmony_ci	struct fallback_dispatch *dispatch =
1256a46c0ec8Sopenharmony_ci		fallback_dispatch(lid_switch->dispatch);
1257a46c0ec8Sopenharmony_ci	struct evdev_paired_keyboard *kbd;
1258a46c0ec8Sopenharmony_ci	size_t count = 0;
1259a46c0ec8Sopenharmony_ci
1260a46c0ec8Sopenharmony_ci	if ((keyboard->tags & EVDEV_TAG_KEYBOARD) == 0 ||
1261a46c0ec8Sopenharmony_ci	    (lid_switch->tags & EVDEV_TAG_LID_SWITCH) == 0)
1262a46c0ec8Sopenharmony_ci		return;
1263a46c0ec8Sopenharmony_ci
1264a46c0ec8Sopenharmony_ci	if ((keyboard->tags & EVDEV_TAG_INTERNAL_KEYBOARD) == 0)
1265a46c0ec8Sopenharmony_ci		return;
1266a46c0ec8Sopenharmony_ci
1267a46c0ec8Sopenharmony_ci	list_for_each(kbd, &dispatch->lid.paired_keyboard_list, link) {
1268a46c0ec8Sopenharmony_ci		count++;
1269a46c0ec8Sopenharmony_ci		if (count > 3) {
1270a46c0ec8Sopenharmony_ci			evdev_log_info(lid_switch,
1271a46c0ec8Sopenharmony_ci				       "lid: too many internal keyboards\n");
1272a46c0ec8Sopenharmony_ci			break;
1273a46c0ec8Sopenharmony_ci		}
1274a46c0ec8Sopenharmony_ci	}
1275a46c0ec8Sopenharmony_ci
1276a46c0ec8Sopenharmony_ci	kbd = zalloc(sizeof(*kbd));
1277a46c0ec8Sopenharmony_ci	kbd->device = keyboard;
1278a46c0ec8Sopenharmony_ci	libinput_device_init_event_listener(&kbd->listener);
1279a46c0ec8Sopenharmony_ci	list_insert(&dispatch->lid.paired_keyboard_list, &kbd->link);
1280a46c0ec8Sopenharmony_ci	evdev_log_debug(lid_switch,
1281a46c0ec8Sopenharmony_ci			"lid: keyboard paired with %s<->%s\n",
1282a46c0ec8Sopenharmony_ci			lid_switch->devname,
1283a46c0ec8Sopenharmony_ci			keyboard->devname);
1284a46c0ec8Sopenharmony_ci
1285a46c0ec8Sopenharmony_ci	/* We need to init the event listener now only if the
1286a46c0ec8Sopenharmony_ci	 * reported state is closed. */
1287a46c0ec8Sopenharmony_ci	if (dispatch->lid.is_closed)
1288a46c0ec8Sopenharmony_ci		fallback_lid_toggle_keyboard_listener(dispatch,
1289a46c0ec8Sopenharmony_ci						      kbd,
1290a46c0ec8Sopenharmony_ci						      dispatch->lid.is_closed);
1291a46c0ec8Sopenharmony_ci}
1292a46c0ec8Sopenharmony_ci
1293a46c0ec8Sopenharmony_cistatic void
1294a46c0ec8Sopenharmony_cifallback_resume(struct fallback_dispatch *dispatch,
1295a46c0ec8Sopenharmony_ci		struct evdev_device *device)
1296a46c0ec8Sopenharmony_ci{
1297a46c0ec8Sopenharmony_ci	if (dispatch->base.sendevents.current_mode ==
1298a46c0ec8Sopenharmony_ci	    LIBINPUT_CONFIG_SEND_EVENTS_DISABLED)
1299a46c0ec8Sopenharmony_ci		return;
1300a46c0ec8Sopenharmony_ci
1301a46c0ec8Sopenharmony_ci	evdev_device_resume(device);
1302a46c0ec8Sopenharmony_ci}
1303a46c0ec8Sopenharmony_ci
1304a46c0ec8Sopenharmony_cistatic void
1305a46c0ec8Sopenharmony_cifallback_suspend(struct fallback_dispatch *dispatch,
1306a46c0ec8Sopenharmony_ci		 struct evdev_device *device)
1307a46c0ec8Sopenharmony_ci{
1308a46c0ec8Sopenharmony_ci	evdev_device_suspend(device);
1309a46c0ec8Sopenharmony_ci}
1310a46c0ec8Sopenharmony_ci
1311a46c0ec8Sopenharmony_cistatic void
1312a46c0ec8Sopenharmony_cifallback_tablet_mode_switch_event(uint64_t time,
1313a46c0ec8Sopenharmony_ci				  struct libinput_event *event,
1314a46c0ec8Sopenharmony_ci				  void *data)
1315a46c0ec8Sopenharmony_ci{
1316a46c0ec8Sopenharmony_ci	struct fallback_dispatch *dispatch = data;
1317a46c0ec8Sopenharmony_ci	struct evdev_device *device = dispatch->device;
1318a46c0ec8Sopenharmony_ci	struct libinput_event_switch *swev;
1319a46c0ec8Sopenharmony_ci
1320a46c0ec8Sopenharmony_ci	if (libinput_event_get_type(event) != LIBINPUT_EVENT_SWITCH_TOGGLE)
1321a46c0ec8Sopenharmony_ci		return;
1322a46c0ec8Sopenharmony_ci
1323a46c0ec8Sopenharmony_ci	swev = libinput_event_get_switch_event(event);
1324a46c0ec8Sopenharmony_ci	if (libinput_event_switch_get_switch(swev) !=
1325a46c0ec8Sopenharmony_ci	    LIBINPUT_SWITCH_TABLET_MODE)
1326a46c0ec8Sopenharmony_ci		return;
1327a46c0ec8Sopenharmony_ci
1328a46c0ec8Sopenharmony_ci	switch (libinput_event_switch_get_switch_state(swev)) {
1329a46c0ec8Sopenharmony_ci	case LIBINPUT_SWITCH_STATE_OFF:
1330a46c0ec8Sopenharmony_ci		fallback_resume(dispatch, device);
1331a46c0ec8Sopenharmony_ci		evdev_log_debug(device, "tablet-mode: resuming device\n");
1332a46c0ec8Sopenharmony_ci		break;
1333a46c0ec8Sopenharmony_ci	case LIBINPUT_SWITCH_STATE_ON:
1334a46c0ec8Sopenharmony_ci		fallback_suspend(dispatch, device);
1335a46c0ec8Sopenharmony_ci		evdev_log_debug(device, "tablet-mode: suspending device\n");
1336a46c0ec8Sopenharmony_ci		break;
1337a46c0ec8Sopenharmony_ci	}
1338a46c0ec8Sopenharmony_ci}
1339a46c0ec8Sopenharmony_ci
1340a46c0ec8Sopenharmony_cistatic void
1341a46c0ec8Sopenharmony_cifallback_pair_tablet_mode(struct evdev_device *keyboard,
1342a46c0ec8Sopenharmony_ci			  struct evdev_device *tablet_mode_switch)
1343a46c0ec8Sopenharmony_ci{
1344a46c0ec8Sopenharmony_ci	struct fallback_dispatch *dispatch =
1345a46c0ec8Sopenharmony_ci		fallback_dispatch(keyboard->dispatch);
1346a46c0ec8Sopenharmony_ci
1347a46c0ec8Sopenharmony_ci	if ((keyboard->tags & EVDEV_TAG_EXTERNAL_KEYBOARD))
1348a46c0ec8Sopenharmony_ci		return;
1349a46c0ec8Sopenharmony_ci
1350a46c0ec8Sopenharmony_ci	if ((keyboard->tags & EVDEV_TAG_TRACKPOINT)) {
1351a46c0ec8Sopenharmony_ci		if (keyboard->tags & EVDEV_TAG_EXTERNAL_MOUSE)
1352a46c0ec8Sopenharmony_ci			return;
1353a46c0ec8Sopenharmony_ci	/* This filters out all internal keyboard-like devices (Video
1354a46c0ec8Sopenharmony_ci	 * Switch) */
1355a46c0ec8Sopenharmony_ci	} else if ((keyboard->tags & EVDEV_TAG_INTERNAL_KEYBOARD) == 0) {
1356a46c0ec8Sopenharmony_ci		return;
1357a46c0ec8Sopenharmony_ci	}
1358a46c0ec8Sopenharmony_ci
1359a46c0ec8Sopenharmony_ci	if (evdev_device_has_model_quirk(keyboard,
1360a46c0ec8Sopenharmony_ci					 QUIRK_MODEL_TABLET_MODE_NO_SUSPEND))
1361a46c0ec8Sopenharmony_ci		return;
1362a46c0ec8Sopenharmony_ci
1363a46c0ec8Sopenharmony_ci	if ((tablet_mode_switch->tags & EVDEV_TAG_TABLET_MODE_SWITCH) == 0)
1364a46c0ec8Sopenharmony_ci		return;
1365a46c0ec8Sopenharmony_ci
1366a46c0ec8Sopenharmony_ci	if (dispatch->tablet_mode.other.sw_device)
1367a46c0ec8Sopenharmony_ci		return;
1368a46c0ec8Sopenharmony_ci
1369a46c0ec8Sopenharmony_ci	evdev_log_debug(keyboard,
1370a46c0ec8Sopenharmony_ci			"tablet-mode: paired %s<->%s\n",
1371a46c0ec8Sopenharmony_ci			keyboard->devname,
1372a46c0ec8Sopenharmony_ci			tablet_mode_switch->devname);
1373a46c0ec8Sopenharmony_ci
1374a46c0ec8Sopenharmony_ci	libinput_device_add_event_listener(&tablet_mode_switch->base,
1375a46c0ec8Sopenharmony_ci				&dispatch->tablet_mode.other.listener,
1376a46c0ec8Sopenharmony_ci				fallback_tablet_mode_switch_event,
1377a46c0ec8Sopenharmony_ci				dispatch);
1378a46c0ec8Sopenharmony_ci	dispatch->tablet_mode.other.sw_device = tablet_mode_switch;
1379a46c0ec8Sopenharmony_ci
1380a46c0ec8Sopenharmony_ci	if (evdev_device_switch_get_state(tablet_mode_switch,
1381a46c0ec8Sopenharmony_ci					  LIBINPUT_SWITCH_TABLET_MODE)
1382a46c0ec8Sopenharmony_ci		    == LIBINPUT_SWITCH_STATE_ON) {
1383a46c0ec8Sopenharmony_ci		evdev_log_debug(keyboard, "tablet-mode: suspending device\n");
1384a46c0ec8Sopenharmony_ci		fallback_suspend(dispatch, keyboard);
1385a46c0ec8Sopenharmony_ci	}
1386a46c0ec8Sopenharmony_ci}
1387a46c0ec8Sopenharmony_ci
1388a46c0ec8Sopenharmony_cistatic void
1389a46c0ec8Sopenharmony_cifallback_interface_device_added(struct evdev_device *device,
1390a46c0ec8Sopenharmony_ci				struct evdev_device *added_device)
1391a46c0ec8Sopenharmony_ci{
1392a46c0ec8Sopenharmony_ci	fallback_lid_pair_keyboard(device, added_device);
1393a46c0ec8Sopenharmony_ci	fallback_pair_tablet_mode(device, added_device);
1394a46c0ec8Sopenharmony_ci}
1395a46c0ec8Sopenharmony_ci
1396a46c0ec8Sopenharmony_cistatic void
1397a46c0ec8Sopenharmony_cifallback_interface_device_removed(struct evdev_device *device,
1398a46c0ec8Sopenharmony_ci				  struct evdev_device *removed_device)
1399a46c0ec8Sopenharmony_ci{
1400a46c0ec8Sopenharmony_ci	struct fallback_dispatch *dispatch =
1401a46c0ec8Sopenharmony_ci			fallback_dispatch(device->dispatch);
1402a46c0ec8Sopenharmony_ci	struct evdev_paired_keyboard *kbd;
1403a46c0ec8Sopenharmony_ci
1404a46c0ec8Sopenharmony_ci	list_for_each_safe(kbd,
1405a46c0ec8Sopenharmony_ci			   &dispatch->lid.paired_keyboard_list,
1406a46c0ec8Sopenharmony_ci			   link) {
1407a46c0ec8Sopenharmony_ci		if (!kbd->device)
1408a46c0ec8Sopenharmony_ci			continue;
1409a46c0ec8Sopenharmony_ci
1410a46c0ec8Sopenharmony_ci		if (kbd->device != removed_device)
1411a46c0ec8Sopenharmony_ci			continue;
1412a46c0ec8Sopenharmony_ci
1413a46c0ec8Sopenharmony_ci		evdev_paired_keyboard_destroy(kbd);
1414a46c0ec8Sopenharmony_ci	}
1415a46c0ec8Sopenharmony_ci
1416a46c0ec8Sopenharmony_ci	if (removed_device == dispatch->tablet_mode.other.sw_device) {
1417a46c0ec8Sopenharmony_ci		libinput_device_remove_event_listener(
1418a46c0ec8Sopenharmony_ci				&dispatch->tablet_mode.other.listener);
1419a46c0ec8Sopenharmony_ci		libinput_device_init_event_listener(
1420a46c0ec8Sopenharmony_ci				&dispatch->tablet_mode.other.listener);
1421a46c0ec8Sopenharmony_ci		dispatch->tablet_mode.other.sw_device = NULL;
1422a46c0ec8Sopenharmony_ci	}
1423a46c0ec8Sopenharmony_ci}
1424a46c0ec8Sopenharmony_ci
1425a46c0ec8Sopenharmony_cistruct evdev_dispatch_interface fallback_interface = {
1426a46c0ec8Sopenharmony_ci	.process = fallback_interface_process,
1427a46c0ec8Sopenharmony_ci	.suspend = fallback_interface_suspend,
1428a46c0ec8Sopenharmony_ci	.remove = fallback_interface_remove,
1429a46c0ec8Sopenharmony_ci	.destroy = fallback_interface_destroy,
1430a46c0ec8Sopenharmony_ci	.device_added = fallback_interface_device_added,
1431a46c0ec8Sopenharmony_ci	.device_removed = fallback_interface_device_removed,
1432a46c0ec8Sopenharmony_ci	.device_suspended = fallback_interface_device_removed, /* treat as remove */
1433a46c0ec8Sopenharmony_ci	.device_resumed = fallback_interface_device_added,   /* treat as add */
1434a46c0ec8Sopenharmony_ci	.post_added = fallback_interface_sync_initial_state,
1435a46c0ec8Sopenharmony_ci	.touch_arbitration_toggle = fallback_interface_toggle_touch,
1436a46c0ec8Sopenharmony_ci	.touch_arbitration_update_rect = fallback_interface_update_rect,
1437a46c0ec8Sopenharmony_ci	.get_switch_state = fallback_interface_get_switch_state,
1438a46c0ec8Sopenharmony_ci};
1439a46c0ec8Sopenharmony_ci
1440a46c0ec8Sopenharmony_cistatic void
1441a46c0ec8Sopenharmony_cifallback_change_to_left_handed(struct evdev_device *device)
1442a46c0ec8Sopenharmony_ci{
1443a46c0ec8Sopenharmony_ci	struct fallback_dispatch *dispatch = fallback_dispatch(device->dispatch);
1444a46c0ec8Sopenharmony_ci
1445a46c0ec8Sopenharmony_ci	if (device->left_handed.want_enabled == device->left_handed.enabled)
1446a46c0ec8Sopenharmony_ci		return;
1447a46c0ec8Sopenharmony_ci
1448a46c0ec8Sopenharmony_ci	if (fallback_any_button_down(dispatch, device))
1449a46c0ec8Sopenharmony_ci		return;
1450a46c0ec8Sopenharmony_ci
1451a46c0ec8Sopenharmony_ci	device->left_handed.enabled = device->left_handed.want_enabled;
1452a46c0ec8Sopenharmony_ci}
1453a46c0ec8Sopenharmony_ci
1454a46c0ec8Sopenharmony_cistatic void
1455a46c0ec8Sopenharmony_cifallback_change_scroll_method(struct evdev_device *device)
1456a46c0ec8Sopenharmony_ci{
1457a46c0ec8Sopenharmony_ci	struct fallback_dispatch *dispatch = fallback_dispatch(device->dispatch);
1458a46c0ec8Sopenharmony_ci
1459a46c0ec8Sopenharmony_ci	if (device->scroll.want_method == device->scroll.method &&
1460a46c0ec8Sopenharmony_ci	    device->scroll.want_button == device->scroll.button &&
1461a46c0ec8Sopenharmony_ci	    device->scroll.want_lock_enabled == device->scroll.lock_enabled)
1462a46c0ec8Sopenharmony_ci		return;
1463a46c0ec8Sopenharmony_ci
1464a46c0ec8Sopenharmony_ci	if (fallback_any_button_down(dispatch, device))
1465a46c0ec8Sopenharmony_ci		return;
1466a46c0ec8Sopenharmony_ci
1467a46c0ec8Sopenharmony_ci	device->scroll.method = device->scroll.want_method;
1468a46c0ec8Sopenharmony_ci	device->scroll.button = device->scroll.want_button;
1469a46c0ec8Sopenharmony_ci	device->scroll.lock_enabled = device->scroll.want_lock_enabled;
1470a46c0ec8Sopenharmony_ci	evdev_set_button_scroll_lock_enabled(device, device->scroll.lock_enabled);
1471a46c0ec8Sopenharmony_ci}
1472a46c0ec8Sopenharmony_ci
1473a46c0ec8Sopenharmony_cistatic int
1474a46c0ec8Sopenharmony_cifallback_rotation_config_is_available(struct libinput_device *device)
1475a46c0ec8Sopenharmony_ci{
1476a46c0ec8Sopenharmony_ci	/* This function only gets called when we support rotation */
1477a46c0ec8Sopenharmony_ci	return 1;
1478a46c0ec8Sopenharmony_ci}
1479a46c0ec8Sopenharmony_ci
1480a46c0ec8Sopenharmony_cistatic enum libinput_config_status
1481a46c0ec8Sopenharmony_cifallback_rotation_config_set_angle(struct libinput_device *libinput_device,
1482a46c0ec8Sopenharmony_ci				unsigned int degrees_cw)
1483a46c0ec8Sopenharmony_ci{
1484a46c0ec8Sopenharmony_ci	struct evdev_device *device = evdev_device(libinput_device);
1485a46c0ec8Sopenharmony_ci	struct fallback_dispatch *dispatch = fallback_dispatch(device->dispatch);
1486a46c0ec8Sopenharmony_ci
1487a46c0ec8Sopenharmony_ci	dispatch->rotation.angle = degrees_cw;
1488a46c0ec8Sopenharmony_ci	matrix_init_rotate(&dispatch->rotation.matrix, degrees_cw);
1489a46c0ec8Sopenharmony_ci
1490a46c0ec8Sopenharmony_ci	return LIBINPUT_CONFIG_STATUS_SUCCESS;
1491a46c0ec8Sopenharmony_ci}
1492a46c0ec8Sopenharmony_ci
1493a46c0ec8Sopenharmony_cistatic unsigned int
1494a46c0ec8Sopenharmony_cifallback_rotation_config_get_angle(struct libinput_device *libinput_device)
1495a46c0ec8Sopenharmony_ci{
1496a46c0ec8Sopenharmony_ci	struct evdev_device *device = evdev_device(libinput_device);
1497a46c0ec8Sopenharmony_ci	struct fallback_dispatch *dispatch = fallback_dispatch(device->dispatch);
1498a46c0ec8Sopenharmony_ci
1499a46c0ec8Sopenharmony_ci	return dispatch->rotation.angle;
1500a46c0ec8Sopenharmony_ci}
1501a46c0ec8Sopenharmony_ci
1502a46c0ec8Sopenharmony_cistatic unsigned int
1503a46c0ec8Sopenharmony_cifallback_rotation_config_get_default_angle(struct libinput_device *device)
1504a46c0ec8Sopenharmony_ci{
1505a46c0ec8Sopenharmony_ci	return 0;
1506a46c0ec8Sopenharmony_ci}
1507a46c0ec8Sopenharmony_ci
1508a46c0ec8Sopenharmony_cistatic void
1509a46c0ec8Sopenharmony_cifallback_init_rotation(struct fallback_dispatch *dispatch,
1510a46c0ec8Sopenharmony_ci		       struct evdev_device *device)
1511a46c0ec8Sopenharmony_ci{
1512a46c0ec8Sopenharmony_ci	if (device->tags & EVDEV_TAG_TRACKPOINT)
1513a46c0ec8Sopenharmony_ci		return;
1514a46c0ec8Sopenharmony_ci
1515a46c0ec8Sopenharmony_ci	dispatch->rotation.config.is_available = fallback_rotation_config_is_available;
1516a46c0ec8Sopenharmony_ci	dispatch->rotation.config.set_angle = fallback_rotation_config_set_angle;
1517a46c0ec8Sopenharmony_ci	dispatch->rotation.config.get_angle = fallback_rotation_config_get_angle;
1518a46c0ec8Sopenharmony_ci	dispatch->rotation.config.get_default_angle = fallback_rotation_config_get_default_angle;
1519a46c0ec8Sopenharmony_ci	matrix_init_identity(&dispatch->rotation.matrix);
1520a46c0ec8Sopenharmony_ci	device->base.config.rotation = &dispatch->rotation.config;
1521a46c0ec8Sopenharmony_ci}
1522a46c0ec8Sopenharmony_ci
1523a46c0ec8Sopenharmony_cistatic inline int
1524a46c0ec8Sopenharmony_cifallback_dispatch_init_slots(struct fallback_dispatch *dispatch,
1525a46c0ec8Sopenharmony_ci			     struct evdev_device *device)
1526a46c0ec8Sopenharmony_ci{
1527a46c0ec8Sopenharmony_ci	struct libevdev *evdev = device->evdev;
1528a46c0ec8Sopenharmony_ci	struct mt_slot *slots;
1529a46c0ec8Sopenharmony_ci	int num_slots;
1530a46c0ec8Sopenharmony_ci	int active_slot;
1531a46c0ec8Sopenharmony_ci	int slot;
1532a46c0ec8Sopenharmony_ci
1533a46c0ec8Sopenharmony_ci	if (evdev_is_fake_mt_device(device) ||
1534a46c0ec8Sopenharmony_ci	    !libevdev_has_event_code(evdev, EV_ABS, ABS_MT_POSITION_X) ||
1535a46c0ec8Sopenharmony_ci	    !libevdev_has_event_code(evdev, EV_ABS, ABS_MT_POSITION_Y))
1536a46c0ec8Sopenharmony_ci		 return 0;
1537a46c0ec8Sopenharmony_ci
1538a46c0ec8Sopenharmony_ci	/* We only handle the slotted Protocol B in libinput.
1539a46c0ec8Sopenharmony_ci	   Devices with ABS_MT_POSITION_* but not ABS_MT_SLOT
1540a46c0ec8Sopenharmony_ci	   require mtdev for conversion. */
1541a46c0ec8Sopenharmony_ci	if (evdev_need_mtdev(device)) {
1542a46c0ec8Sopenharmony_ci		device->mtdev = mtdev_new_open(device->fd);
1543a46c0ec8Sopenharmony_ci		if (!device->mtdev)
1544a46c0ec8Sopenharmony_ci			return -1;
1545a46c0ec8Sopenharmony_ci
1546a46c0ec8Sopenharmony_ci		/* pick 10 slots as default for type A
1547a46c0ec8Sopenharmony_ci		   devices. */
1548a46c0ec8Sopenharmony_ci		num_slots = 10;
1549a46c0ec8Sopenharmony_ci		active_slot = device->mtdev->caps.slot.value;
1550a46c0ec8Sopenharmony_ci	} else {
1551a46c0ec8Sopenharmony_ci		num_slots = libevdev_get_num_slots(device->evdev);
1552a46c0ec8Sopenharmony_ci		active_slot = libevdev_get_current_slot(evdev);
1553a46c0ec8Sopenharmony_ci	}
1554a46c0ec8Sopenharmony_ci
1555a46c0ec8Sopenharmony_ci	slots = zalloc(num_slots * sizeof(struct mt_slot));
1556a46c0ec8Sopenharmony_ci
1557a46c0ec8Sopenharmony_ci	for (slot = 0; slot < num_slots; ++slot) {
1558a46c0ec8Sopenharmony_ci		slots[slot].seat_slot = -1;
1559a46c0ec8Sopenharmony_ci
1560a46c0ec8Sopenharmony_ci		if (evdev_need_mtdev(device))
1561a46c0ec8Sopenharmony_ci			continue;
1562a46c0ec8Sopenharmony_ci
1563a46c0ec8Sopenharmony_ci		slots[slot].point.x = libevdev_get_slot_value(evdev,
1564a46c0ec8Sopenharmony_ci							      slot,
1565a46c0ec8Sopenharmony_ci							      ABS_MT_POSITION_X);
1566a46c0ec8Sopenharmony_ci		slots[slot].point.y = libevdev_get_slot_value(evdev,
1567a46c0ec8Sopenharmony_ci							      slot,
1568a46c0ec8Sopenharmony_ci							      ABS_MT_POSITION_Y);
1569a46c0ec8Sopenharmony_ci	}
1570a46c0ec8Sopenharmony_ci	dispatch->mt.slots = slots;
1571a46c0ec8Sopenharmony_ci	dispatch->mt.slots_len = num_slots;
1572a46c0ec8Sopenharmony_ci	dispatch->mt.slot = active_slot;
1573a46c0ec8Sopenharmony_ci	dispatch->mt.has_palm = libevdev_has_event_code(evdev,
1574a46c0ec8Sopenharmony_ci							EV_ABS,
1575a46c0ec8Sopenharmony_ci							ABS_MT_TOOL_TYPE);
1576a46c0ec8Sopenharmony_ci
1577a46c0ec8Sopenharmony_ci	if (device->abs.absinfo_x->fuzz || device->abs.absinfo_y->fuzz) {
1578a46c0ec8Sopenharmony_ci		dispatch->mt.want_hysteresis = true;
1579a46c0ec8Sopenharmony_ci		dispatch->mt.hysteresis_margin.x = device->abs.absinfo_x->fuzz/2;
1580a46c0ec8Sopenharmony_ci		dispatch->mt.hysteresis_margin.y = device->abs.absinfo_y->fuzz/2;
1581a46c0ec8Sopenharmony_ci	}
1582a46c0ec8Sopenharmony_ci
1583a46c0ec8Sopenharmony_ci	return 0;
1584a46c0ec8Sopenharmony_ci}
1585a46c0ec8Sopenharmony_ci
1586a46c0ec8Sopenharmony_cistatic inline void
1587a46c0ec8Sopenharmony_cifallback_dispatch_init_rel(struct fallback_dispatch *dispatch,
1588a46c0ec8Sopenharmony_ci			   struct evdev_device *device)
1589a46c0ec8Sopenharmony_ci{
1590a46c0ec8Sopenharmony_ci	dispatch->rel.x = 0;
1591a46c0ec8Sopenharmony_ci	dispatch->rel.y = 0;
1592a46c0ec8Sopenharmony_ci}
1593a46c0ec8Sopenharmony_ci
1594a46c0ec8Sopenharmony_cistatic inline void
1595a46c0ec8Sopenharmony_cifallback_dispatch_init_abs(struct fallback_dispatch *dispatch,
1596a46c0ec8Sopenharmony_ci			   struct evdev_device *device)
1597a46c0ec8Sopenharmony_ci{
1598a46c0ec8Sopenharmony_ci	if (!libevdev_has_event_code(device->evdev, EV_ABS, ABS_X))
1599a46c0ec8Sopenharmony_ci		return;
1600a46c0ec8Sopenharmony_ci
1601a46c0ec8Sopenharmony_ci	dispatch->abs.point.x = device->abs.absinfo_x->value;
1602a46c0ec8Sopenharmony_ci	dispatch->abs.point.y = device->abs.absinfo_y->value;
1603a46c0ec8Sopenharmony_ci	dispatch->abs.seat_slot = -1;
1604a46c0ec8Sopenharmony_ci
1605a46c0ec8Sopenharmony_ci	evdev_device_init_abs_range_warnings(device);
1606a46c0ec8Sopenharmony_ci}
1607a46c0ec8Sopenharmony_ci
1608a46c0ec8Sopenharmony_cistatic inline void
1609a46c0ec8Sopenharmony_cifallback_dispatch_init_switch(struct fallback_dispatch *dispatch,
1610a46c0ec8Sopenharmony_ci			      struct evdev_device *device)
1611a46c0ec8Sopenharmony_ci{
1612a46c0ec8Sopenharmony_ci	int val;
1613a46c0ec8Sopenharmony_ci
1614a46c0ec8Sopenharmony_ci	list_init(&dispatch->lid.paired_keyboard_list);
1615a46c0ec8Sopenharmony_ci
1616a46c0ec8Sopenharmony_ci	if (device->tags & EVDEV_TAG_LID_SWITCH) {
1617a46c0ec8Sopenharmony_ci		dispatch->lid.reliability = evdev_read_switch_reliability_prop(device);
1618a46c0ec8Sopenharmony_ci		dispatch->lid.is_closed = false;
1619a46c0ec8Sopenharmony_ci	}
1620a46c0ec8Sopenharmony_ci
1621a46c0ec8Sopenharmony_ci	if (device->tags & EVDEV_TAG_TABLET_MODE_SWITCH) {
1622a46c0ec8Sopenharmony_ci		val = libevdev_get_event_value(device->evdev,
1623a46c0ec8Sopenharmony_ci					       EV_SW,
1624a46c0ec8Sopenharmony_ci					       SW_TABLET_MODE);
1625a46c0ec8Sopenharmony_ci		dispatch->tablet_mode.sw.state = val;
1626a46c0ec8Sopenharmony_ci	}
1627a46c0ec8Sopenharmony_ci
1628a46c0ec8Sopenharmony_ci	libinput_device_init_event_listener(&dispatch->tablet_mode.other.listener);
1629a46c0ec8Sopenharmony_ci}
1630a46c0ec8Sopenharmony_ci
1631a46c0ec8Sopenharmony_cistatic void
1632a46c0ec8Sopenharmony_cifallback_arbitration_timeout(uint64_t now, void *data)
1633a46c0ec8Sopenharmony_ci{
1634a46c0ec8Sopenharmony_ci	struct fallback_dispatch *dispatch = data;
1635a46c0ec8Sopenharmony_ci
1636a46c0ec8Sopenharmony_ci	if (dispatch->arbitration.in_arbitration)
1637a46c0ec8Sopenharmony_ci		dispatch->arbitration.in_arbitration = false;
1638a46c0ec8Sopenharmony_ci
1639a46c0ec8Sopenharmony_ci	evdev_log_debug(dispatch->device, "touch arbitration timeout\n");
1640a46c0ec8Sopenharmony_ci}
1641a46c0ec8Sopenharmony_ci
1642a46c0ec8Sopenharmony_cistatic void
1643a46c0ec8Sopenharmony_cifallback_init_arbitration(struct fallback_dispatch *dispatch,
1644a46c0ec8Sopenharmony_ci			  struct evdev_device *device)
1645a46c0ec8Sopenharmony_ci{
1646a46c0ec8Sopenharmony_ci	char timer_name[64];
1647a46c0ec8Sopenharmony_ci
1648a46c0ec8Sopenharmony_ci	snprintf(timer_name,
1649a46c0ec8Sopenharmony_ci		 sizeof(timer_name),
1650a46c0ec8Sopenharmony_ci		  "%s arbitration",
1651a46c0ec8Sopenharmony_ci		  evdev_device_get_sysname(device));
1652a46c0ec8Sopenharmony_ci	libinput_timer_init(&dispatch->arbitration.arbitration_timer,
1653a46c0ec8Sopenharmony_ci			    evdev_libinput_context(device),
1654a46c0ec8Sopenharmony_ci			    timer_name,
1655a46c0ec8Sopenharmony_ci			    fallback_arbitration_timeout,
1656a46c0ec8Sopenharmony_ci			    dispatch);
1657a46c0ec8Sopenharmony_ci	dispatch->arbitration.in_arbitration = false;
1658a46c0ec8Sopenharmony_ci}
1659a46c0ec8Sopenharmony_ci
1660a46c0ec8Sopenharmony_cistruct evdev_dispatch *
1661a46c0ec8Sopenharmony_cifallback_dispatch_create(struct libinput_device *libinput_device)
1662a46c0ec8Sopenharmony_ci{
1663a46c0ec8Sopenharmony_ci	struct evdev_device *device = evdev_device(libinput_device);
1664a46c0ec8Sopenharmony_ci	struct fallback_dispatch *dispatch;
1665a46c0ec8Sopenharmony_ci
1666a46c0ec8Sopenharmony_ci	dispatch = zalloc(sizeof *dispatch);
1667a46c0ec8Sopenharmony_ci	dispatch->device = evdev_device(libinput_device);
1668a46c0ec8Sopenharmony_ci	dispatch->base.dispatch_type = DISPATCH_FALLBACK;
1669a46c0ec8Sopenharmony_ci	dispatch->base.interface = &fallback_interface;
1670a46c0ec8Sopenharmony_ci	dispatch->pending_event = EVDEV_NONE;
1671a46c0ec8Sopenharmony_ci	list_init(&dispatch->lid.paired_keyboard_list);
1672a46c0ec8Sopenharmony_ci
1673a46c0ec8Sopenharmony_ci	fallback_dispatch_init_rel(dispatch, device);
1674a46c0ec8Sopenharmony_ci	fallback_dispatch_init_abs(dispatch, device);
1675a46c0ec8Sopenharmony_ci	if (fallback_dispatch_init_slots(dispatch, device) == -1) {
1676a46c0ec8Sopenharmony_ci		free(dispatch);
1677a46c0ec8Sopenharmony_ci		return NULL;
1678a46c0ec8Sopenharmony_ci	}
1679a46c0ec8Sopenharmony_ci
1680a46c0ec8Sopenharmony_ci	fallback_dispatch_init_switch(dispatch, device);
1681a46c0ec8Sopenharmony_ci
1682a46c0ec8Sopenharmony_ci	if (device->left_handed.want_enabled)
1683a46c0ec8Sopenharmony_ci		evdev_init_left_handed(device,
1684a46c0ec8Sopenharmony_ci				       fallback_change_to_left_handed);
1685a46c0ec8Sopenharmony_ci
1686a46c0ec8Sopenharmony_ci	if (device->scroll.want_button)
1687a46c0ec8Sopenharmony_ci		evdev_init_button_scroll(device,
1688a46c0ec8Sopenharmony_ci					 fallback_change_scroll_method);
1689a46c0ec8Sopenharmony_ci
1690a46c0ec8Sopenharmony_ci	if (device->scroll.natural_scrolling_enabled)
1691a46c0ec8Sopenharmony_ci		evdev_init_natural_scroll(device);
1692a46c0ec8Sopenharmony_ci
1693a46c0ec8Sopenharmony_ci	evdev_init_calibration(device, &dispatch->calibration);
1694a46c0ec8Sopenharmony_ci	evdev_init_sendevents(device, &dispatch->base);
1695a46c0ec8Sopenharmony_ci	fallback_init_rotation(dispatch, device);
1696a46c0ec8Sopenharmony_ci
1697a46c0ec8Sopenharmony_ci	/* BTN_MIDDLE is set on mice even when it's not present. So
1698a46c0ec8Sopenharmony_ci	 * we can only use the absence of BTN_MIDDLE to mean something, i.e.
1699a46c0ec8Sopenharmony_ci	 * we enable it by default on anything that only has L&R.
1700a46c0ec8Sopenharmony_ci	 * If we have L&R and no middle, we don't expose it as config
1701a46c0ec8Sopenharmony_ci	 * option */
1702a46c0ec8Sopenharmony_ci	if (libevdev_has_event_code(device->evdev, EV_KEY, BTN_LEFT) &&
1703a46c0ec8Sopenharmony_ci	    libevdev_has_event_code(device->evdev, EV_KEY, BTN_RIGHT)) {
1704a46c0ec8Sopenharmony_ci		bool has_middle = libevdev_has_event_code(device->evdev,
1705a46c0ec8Sopenharmony_ci							  EV_KEY,
1706a46c0ec8Sopenharmony_ci							  BTN_MIDDLE);
1707a46c0ec8Sopenharmony_ci		bool want_config = has_middle;
1708a46c0ec8Sopenharmony_ci		bool enable_by_default = !has_middle;
1709a46c0ec8Sopenharmony_ci
1710a46c0ec8Sopenharmony_ci		evdev_init_middlebutton(device,
1711a46c0ec8Sopenharmony_ci					enable_by_default,
1712a46c0ec8Sopenharmony_ci					want_config);
1713a46c0ec8Sopenharmony_ci	}
1714a46c0ec8Sopenharmony_ci
1715a46c0ec8Sopenharmony_ci	fallback_init_wheel(dispatch, device);
1716a46c0ec8Sopenharmony_ci	fallback_init_debounce(dispatch);
1717a46c0ec8Sopenharmony_ci	fallback_init_arbitration(dispatch, device);
1718a46c0ec8Sopenharmony_ci
1719a46c0ec8Sopenharmony_ci	return &dispatch->base;
1720a46c0ec8Sopenharmony_ci}
1721