1a46c0ec8Sopenharmony_ci/*
2a46c0ec8Sopenharmony_ci * Copyright © 2013-2015 Red Hat, Inc.
3a46c0ec8Sopenharmony_ci *
4a46c0ec8Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
5a46c0ec8Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
6a46c0ec8Sopenharmony_ci * to deal in the Software without restriction, including without limitation
7a46c0ec8Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8a46c0ec8Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
9a46c0ec8Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
10a46c0ec8Sopenharmony_ci *
11a46c0ec8Sopenharmony_ci * The above copyright notice and this permission notice (including the next
12a46c0ec8Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
13a46c0ec8Sopenharmony_ci * Software.
14a46c0ec8Sopenharmony_ci *
15a46c0ec8Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16a46c0ec8Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17a46c0ec8Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18a46c0ec8Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19a46c0ec8Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20a46c0ec8Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21a46c0ec8Sopenharmony_ci * DEALINGS IN THE SOFTWARE.
22a46c0ec8Sopenharmony_ci */
23a46c0ec8Sopenharmony_ci
24a46c0ec8Sopenharmony_ci#include "config.h"
25a46c0ec8Sopenharmony_ci
26a46c0ec8Sopenharmony_ci#include <assert.h>
27a46c0ec8Sopenharmony_ci#include <stdbool.h>
28a46c0ec8Sopenharmony_ci#include <stdio.h>
29a46c0ec8Sopenharmony_ci
30a46c0ec8Sopenharmony_ci#include "evdev-mt-touchpad.h"
31a46c0ec8Sopenharmony_ci
32a46c0ec8Sopenharmony_ci#define DEFAULT_TAP_TIMEOUT_PERIOD ms2us(180)
33a46c0ec8Sopenharmony_ci#define DEFAULT_DRAG_TIMEOUT_PERIOD_BASE ms2us(160)
34a46c0ec8Sopenharmony_ci#define DEFAULT_DRAG_TIMEOUT_PERIOD_PERFINGER ms2us(20)
35a46c0ec8Sopenharmony_ci#define DEFAULT_DRAGLOCK_TIMEOUT_PERIOD ms2us(300)
36a46c0ec8Sopenharmony_ci#define DEFAULT_TAP_MOVE_THRESHOLD 1.3 /* mm */
37a46c0ec8Sopenharmony_ci
38a46c0ec8Sopenharmony_cienum tap_event {
39a46c0ec8Sopenharmony_ci	TAP_EVENT_TOUCH = 12,
40a46c0ec8Sopenharmony_ci	TAP_EVENT_MOTION,
41a46c0ec8Sopenharmony_ci	TAP_EVENT_RELEASE,
42a46c0ec8Sopenharmony_ci	TAP_EVENT_BUTTON,
43a46c0ec8Sopenharmony_ci	TAP_EVENT_TIMEOUT,
44a46c0ec8Sopenharmony_ci	TAP_EVENT_THUMB,
45a46c0ec8Sopenharmony_ci	TAP_EVENT_PALM,
46a46c0ec8Sopenharmony_ci	TAP_EVENT_PALM_UP,
47a46c0ec8Sopenharmony_ci};
48a46c0ec8Sopenharmony_ci
49a46c0ec8Sopenharmony_ci/*****************************************
50a46c0ec8Sopenharmony_ci * DO NOT EDIT THIS FILE!
51a46c0ec8Sopenharmony_ci *
52a46c0ec8Sopenharmony_ci * Look at the state diagram in doc/touchpad-tap-state-machine.svg
53a46c0ec8Sopenharmony_ci * (generated with https://www.diagrams.net)
54a46c0ec8Sopenharmony_ci *
55a46c0ec8Sopenharmony_ci * Any changes in this file must be represented in the diagram.
56a46c0ec8Sopenharmony_ci */
57a46c0ec8Sopenharmony_ci
58a46c0ec8Sopenharmony_cistatic inline const char*
59a46c0ec8Sopenharmony_citap_state_to_str(enum tp_tap_state state)
60a46c0ec8Sopenharmony_ci{
61a46c0ec8Sopenharmony_ci	switch(state) {
62a46c0ec8Sopenharmony_ci	CASE_RETURN_STRING(TAP_STATE_IDLE);
63a46c0ec8Sopenharmony_ci	CASE_RETURN_STRING(TAP_STATE_HOLD);
64a46c0ec8Sopenharmony_ci	CASE_RETURN_STRING(TAP_STATE_TOUCH);
65a46c0ec8Sopenharmony_ci	CASE_RETURN_STRING(TAP_STATE_1FGTAP_TAPPED);
66a46c0ec8Sopenharmony_ci	CASE_RETURN_STRING(TAP_STATE_2FGTAP_TAPPED);
67a46c0ec8Sopenharmony_ci	CASE_RETURN_STRING(TAP_STATE_3FGTAP_TAPPED);
68a46c0ec8Sopenharmony_ci	CASE_RETURN_STRING(TAP_STATE_TOUCH_2);
69a46c0ec8Sopenharmony_ci	CASE_RETURN_STRING(TAP_STATE_TOUCH_2_HOLD);
70a46c0ec8Sopenharmony_ci	CASE_RETURN_STRING(TAP_STATE_TOUCH_2_RELEASE);
71a46c0ec8Sopenharmony_ci	CASE_RETURN_STRING(TAP_STATE_TOUCH_3);
72a46c0ec8Sopenharmony_ci	CASE_RETURN_STRING(TAP_STATE_TOUCH_3_HOLD);
73a46c0ec8Sopenharmony_ci	CASE_RETURN_STRING(TAP_STATE_TOUCH_3_RELEASE);
74a46c0ec8Sopenharmony_ci	CASE_RETURN_STRING(TAP_STATE_TOUCH_3_RELEASE_2);
75a46c0ec8Sopenharmony_ci	CASE_RETURN_STRING(TAP_STATE_1FGTAP_DRAGGING);
76a46c0ec8Sopenharmony_ci	CASE_RETURN_STRING(TAP_STATE_2FGTAP_DRAGGING);
77a46c0ec8Sopenharmony_ci	CASE_RETURN_STRING(TAP_STATE_3FGTAP_DRAGGING);
78a46c0ec8Sopenharmony_ci	CASE_RETURN_STRING(TAP_STATE_1FGTAP_DRAGGING_WAIT);
79a46c0ec8Sopenharmony_ci	CASE_RETURN_STRING(TAP_STATE_2FGTAP_DRAGGING_WAIT);
80a46c0ec8Sopenharmony_ci	CASE_RETURN_STRING(TAP_STATE_3FGTAP_DRAGGING_WAIT);
81a46c0ec8Sopenharmony_ci	CASE_RETURN_STRING(TAP_STATE_1FGTAP_DRAGGING_OR_DOUBLETAP);
82a46c0ec8Sopenharmony_ci	CASE_RETURN_STRING(TAP_STATE_2FGTAP_DRAGGING_OR_DOUBLETAP);
83a46c0ec8Sopenharmony_ci	CASE_RETURN_STRING(TAP_STATE_3FGTAP_DRAGGING_OR_DOUBLETAP);
84a46c0ec8Sopenharmony_ci	CASE_RETURN_STRING(TAP_STATE_1FGTAP_DRAGGING_OR_TAP);
85a46c0ec8Sopenharmony_ci	CASE_RETURN_STRING(TAP_STATE_2FGTAP_DRAGGING_OR_TAP);
86a46c0ec8Sopenharmony_ci	CASE_RETURN_STRING(TAP_STATE_3FGTAP_DRAGGING_OR_TAP);
87a46c0ec8Sopenharmony_ci	CASE_RETURN_STRING(TAP_STATE_1FGTAP_DRAGGING_2);
88a46c0ec8Sopenharmony_ci	CASE_RETURN_STRING(TAP_STATE_2FGTAP_DRAGGING_2);
89a46c0ec8Sopenharmony_ci	CASE_RETURN_STRING(TAP_STATE_3FGTAP_DRAGGING_2);
90a46c0ec8Sopenharmony_ci	CASE_RETURN_STRING(TAP_STATE_DEAD);
91a46c0ec8Sopenharmony_ci	}
92a46c0ec8Sopenharmony_ci	return NULL;
93a46c0ec8Sopenharmony_ci}
94a46c0ec8Sopenharmony_ci
95a46c0ec8Sopenharmony_cistatic inline const char*
96a46c0ec8Sopenharmony_citap_event_to_str(enum tap_event event)
97a46c0ec8Sopenharmony_ci{
98a46c0ec8Sopenharmony_ci	switch(event) {
99a46c0ec8Sopenharmony_ci	CASE_RETURN_STRING(TAP_EVENT_TOUCH);
100a46c0ec8Sopenharmony_ci	CASE_RETURN_STRING(TAP_EVENT_MOTION);
101a46c0ec8Sopenharmony_ci	CASE_RETURN_STRING(TAP_EVENT_RELEASE);
102a46c0ec8Sopenharmony_ci	CASE_RETURN_STRING(TAP_EVENT_TIMEOUT);
103a46c0ec8Sopenharmony_ci	CASE_RETURN_STRING(TAP_EVENT_BUTTON);
104a46c0ec8Sopenharmony_ci	CASE_RETURN_STRING(TAP_EVENT_THUMB);
105a46c0ec8Sopenharmony_ci	CASE_RETURN_STRING(TAP_EVENT_PALM);
106a46c0ec8Sopenharmony_ci	CASE_RETURN_STRING(TAP_EVENT_PALM_UP);
107a46c0ec8Sopenharmony_ci	}
108a46c0ec8Sopenharmony_ci	return NULL;
109a46c0ec8Sopenharmony_ci}
110a46c0ec8Sopenharmony_ci
111a46c0ec8Sopenharmony_cistatic inline void
112a46c0ec8Sopenharmony_cilog_tap_bug(struct tp_dispatch *tp, struct tp_touch *t, enum tap_event event)
113a46c0ec8Sopenharmony_ci{
114a46c0ec8Sopenharmony_ci	evdev_log_bug_libinput(tp->device,
115a46c0ec8Sopenharmony_ci			       "%d: invalid tap event %s in state %s\n",
116a46c0ec8Sopenharmony_ci			       t->index,
117a46c0ec8Sopenharmony_ci			       tap_event_to_str(event),
118a46c0ec8Sopenharmony_ci			       tap_state_to_str(tp->tap.state));
119a46c0ec8Sopenharmony_ci
120a46c0ec8Sopenharmony_ci}
121a46c0ec8Sopenharmony_ci
122a46c0ec8Sopenharmony_cistatic void
123a46c0ec8Sopenharmony_citp_tap_notify(struct tp_dispatch *tp,
124a46c0ec8Sopenharmony_ci	      uint64_t time,
125a46c0ec8Sopenharmony_ci	      int nfingers,
126a46c0ec8Sopenharmony_ci	      enum libinput_button_state state)
127a46c0ec8Sopenharmony_ci{
128a46c0ec8Sopenharmony_ci	int32_t button;
129a46c0ec8Sopenharmony_ci	int32_t button_map[2][3] = {
130a46c0ec8Sopenharmony_ci		{ BTN_LEFT, BTN_RIGHT, BTN_MIDDLE },
131a46c0ec8Sopenharmony_ci		{ BTN_LEFT, BTN_MIDDLE, BTN_RIGHT },
132a46c0ec8Sopenharmony_ci	};
133a46c0ec8Sopenharmony_ci
134a46c0ec8Sopenharmony_ci	assert(tp->tap.map < ARRAY_LENGTH(button_map));
135a46c0ec8Sopenharmony_ci
136a46c0ec8Sopenharmony_ci	if (nfingers < 1 || nfingers > 3)
137a46c0ec8Sopenharmony_ci		return;
138a46c0ec8Sopenharmony_ci
139a46c0ec8Sopenharmony_ci	button = button_map[tp->tap.map][nfingers - 1];
140a46c0ec8Sopenharmony_ci
141a46c0ec8Sopenharmony_ci	if (state == LIBINPUT_BUTTON_STATE_PRESSED)
142a46c0ec8Sopenharmony_ci		tp->tap.buttons_pressed |= bit(nfingers);
143a46c0ec8Sopenharmony_ci	else
144a46c0ec8Sopenharmony_ci		tp->tap.buttons_pressed &= ~bit(nfingers);
145a46c0ec8Sopenharmony_ci
146a46c0ec8Sopenharmony_ci	evdev_pointer_notify_button(tp->device,
147a46c0ec8Sopenharmony_ci				    time,
148a46c0ec8Sopenharmony_ci				    button,
149a46c0ec8Sopenharmony_ci				    state);
150a46c0ec8Sopenharmony_ci}
151a46c0ec8Sopenharmony_ci
152a46c0ec8Sopenharmony_cistatic void
153a46c0ec8Sopenharmony_citp_tap_set_timer(struct tp_dispatch *tp, uint64_t time)
154a46c0ec8Sopenharmony_ci{
155a46c0ec8Sopenharmony_ci	libinput_timer_set(&tp->tap.timer, time + DEFAULT_TAP_TIMEOUT_PERIOD);
156a46c0ec8Sopenharmony_ci}
157a46c0ec8Sopenharmony_ci
158a46c0ec8Sopenharmony_cistatic void
159a46c0ec8Sopenharmony_citp_tap_set_drag_timer(struct tp_dispatch *tp, uint64_t time,
160a46c0ec8Sopenharmony_ci		      int nfingers_tapped)
161a46c0ec8Sopenharmony_ci{
162a46c0ec8Sopenharmony_ci	libinput_timer_set(&tp->tap.timer,
163a46c0ec8Sopenharmony_ci			   time + DEFAULT_DRAG_TIMEOUT_PERIOD_BASE +
164a46c0ec8Sopenharmony_ci			   (nfingers_tapped *
165a46c0ec8Sopenharmony_ci			    DEFAULT_DRAG_TIMEOUT_PERIOD_PERFINGER));
166a46c0ec8Sopenharmony_ci}
167a46c0ec8Sopenharmony_ci
168a46c0ec8Sopenharmony_cistatic void
169a46c0ec8Sopenharmony_citp_tap_set_draglock_timer(struct tp_dispatch *tp, uint64_t time)
170a46c0ec8Sopenharmony_ci{
171a46c0ec8Sopenharmony_ci	libinput_timer_set(&tp->tap.timer,
172a46c0ec8Sopenharmony_ci			   time + DEFAULT_DRAGLOCK_TIMEOUT_PERIOD);
173a46c0ec8Sopenharmony_ci}
174a46c0ec8Sopenharmony_ci
175a46c0ec8Sopenharmony_cistatic void
176a46c0ec8Sopenharmony_citp_tap_clear_timer(struct tp_dispatch *tp)
177a46c0ec8Sopenharmony_ci{
178a46c0ec8Sopenharmony_ci	libinput_timer_cancel(&tp->tap.timer);
179a46c0ec8Sopenharmony_ci}
180a46c0ec8Sopenharmony_ci
181a46c0ec8Sopenharmony_cistatic void
182a46c0ec8Sopenharmony_citp_tap_move_to_dead(struct tp_dispatch *tp, struct tp_touch *t)
183a46c0ec8Sopenharmony_ci{
184a46c0ec8Sopenharmony_ci	tp->tap.state = TAP_STATE_DEAD;
185a46c0ec8Sopenharmony_ci	t->tap.state = TAP_TOUCH_STATE_DEAD;
186a46c0ec8Sopenharmony_ci	tp_tap_clear_timer(tp);
187a46c0ec8Sopenharmony_ci}
188a46c0ec8Sopenharmony_ci
189a46c0ec8Sopenharmony_cistatic void
190a46c0ec8Sopenharmony_citp_tap_idle_handle_event(struct tp_dispatch *tp,
191a46c0ec8Sopenharmony_ci			 struct tp_touch *t,
192a46c0ec8Sopenharmony_ci			 enum tap_event event, uint64_t time)
193a46c0ec8Sopenharmony_ci{
194a46c0ec8Sopenharmony_ci	switch (event) {
195a46c0ec8Sopenharmony_ci	case TAP_EVENT_TOUCH:
196a46c0ec8Sopenharmony_ci		tp->tap.state = TAP_STATE_TOUCH;
197a46c0ec8Sopenharmony_ci		tp->tap.saved_press_time = time;
198a46c0ec8Sopenharmony_ci		tp_tap_set_timer(tp, time);
199a46c0ec8Sopenharmony_ci		break;
200a46c0ec8Sopenharmony_ci	case TAP_EVENT_RELEASE:
201a46c0ec8Sopenharmony_ci		break;
202a46c0ec8Sopenharmony_ci	case TAP_EVENT_MOTION:
203a46c0ec8Sopenharmony_ci		log_tap_bug(tp, t, event);
204a46c0ec8Sopenharmony_ci		break;
205a46c0ec8Sopenharmony_ci	case TAP_EVENT_TIMEOUT:
206a46c0ec8Sopenharmony_ci		break;
207a46c0ec8Sopenharmony_ci	case TAP_EVENT_BUTTON:
208a46c0ec8Sopenharmony_ci		tp->tap.state = TAP_STATE_DEAD;
209a46c0ec8Sopenharmony_ci		break;
210a46c0ec8Sopenharmony_ci	case TAP_EVENT_THUMB:
211a46c0ec8Sopenharmony_ci		log_tap_bug(tp, t, event);
212a46c0ec8Sopenharmony_ci		break;
213a46c0ec8Sopenharmony_ci	case TAP_EVENT_PALM:
214a46c0ec8Sopenharmony_ci		tp->tap.state = TAP_STATE_IDLE;
215a46c0ec8Sopenharmony_ci		break;
216a46c0ec8Sopenharmony_ci	case TAP_EVENT_PALM_UP:
217a46c0ec8Sopenharmony_ci		break;
218a46c0ec8Sopenharmony_ci	}
219a46c0ec8Sopenharmony_ci}
220a46c0ec8Sopenharmony_ci
221a46c0ec8Sopenharmony_cistatic void
222a46c0ec8Sopenharmony_citp_tap_touch_handle_event(struct tp_dispatch *tp,
223a46c0ec8Sopenharmony_ci			  struct tp_touch *t,
224a46c0ec8Sopenharmony_ci			  enum tap_event event, uint64_t time)
225a46c0ec8Sopenharmony_ci{
226a46c0ec8Sopenharmony_ci
227a46c0ec8Sopenharmony_ci	switch (event) {
228a46c0ec8Sopenharmony_ci	case TAP_EVENT_TOUCH:
229a46c0ec8Sopenharmony_ci		tp->tap.state = TAP_STATE_TOUCH_2;
230a46c0ec8Sopenharmony_ci		tp->tap.saved_press_time = time;
231a46c0ec8Sopenharmony_ci		tp_tap_set_timer(tp, time);
232a46c0ec8Sopenharmony_ci		break;
233a46c0ec8Sopenharmony_ci	case TAP_EVENT_RELEASE:
234a46c0ec8Sopenharmony_ci		tp_tap_notify(tp,
235a46c0ec8Sopenharmony_ci			      tp->tap.saved_press_time,
236a46c0ec8Sopenharmony_ci			      1,
237a46c0ec8Sopenharmony_ci			      LIBINPUT_BUTTON_STATE_PRESSED);
238a46c0ec8Sopenharmony_ci		if (tp->tap.drag_enabled) {
239a46c0ec8Sopenharmony_ci			tp->tap.state = TAP_STATE_1FGTAP_TAPPED;
240a46c0ec8Sopenharmony_ci			tp->tap.saved_release_time = time;
241a46c0ec8Sopenharmony_ci			tp_tap_set_drag_timer(tp, time, 1);
242a46c0ec8Sopenharmony_ci		} else {
243a46c0ec8Sopenharmony_ci			tp_tap_notify(tp,
244a46c0ec8Sopenharmony_ci				      time,
245a46c0ec8Sopenharmony_ci				      1,
246a46c0ec8Sopenharmony_ci				      LIBINPUT_BUTTON_STATE_RELEASED);
247a46c0ec8Sopenharmony_ci			tp->tap.state = TAP_STATE_IDLE;
248a46c0ec8Sopenharmony_ci		}
249a46c0ec8Sopenharmony_ci		break;
250a46c0ec8Sopenharmony_ci	case TAP_EVENT_MOTION:
251a46c0ec8Sopenharmony_ci		tp_tap_move_to_dead(tp, t);
252a46c0ec8Sopenharmony_ci		break;
253a46c0ec8Sopenharmony_ci	case TAP_EVENT_TIMEOUT:
254a46c0ec8Sopenharmony_ci		tp->tap.state = TAP_STATE_HOLD;
255a46c0ec8Sopenharmony_ci		tp_tap_clear_timer(tp);
256a46c0ec8Sopenharmony_ci		tp_gesture_tap_timeout(tp, time);
257a46c0ec8Sopenharmony_ci		break;
258a46c0ec8Sopenharmony_ci	case TAP_EVENT_BUTTON:
259a46c0ec8Sopenharmony_ci		tp->tap.state = TAP_STATE_DEAD;
260a46c0ec8Sopenharmony_ci		break;
261a46c0ec8Sopenharmony_ci	case TAP_EVENT_THUMB:
262a46c0ec8Sopenharmony_ci		tp->tap.state = TAP_STATE_IDLE;
263a46c0ec8Sopenharmony_ci		t->tap.is_thumb = true;
264a46c0ec8Sopenharmony_ci		tp->tap.nfingers_down--;
265a46c0ec8Sopenharmony_ci		t->tap.state = TAP_TOUCH_STATE_DEAD;
266a46c0ec8Sopenharmony_ci		tp_tap_clear_timer(tp);
267a46c0ec8Sopenharmony_ci		break;
268a46c0ec8Sopenharmony_ci	case TAP_EVENT_PALM:
269a46c0ec8Sopenharmony_ci		tp->tap.state = TAP_STATE_IDLE;
270a46c0ec8Sopenharmony_ci		tp_tap_clear_timer(tp);
271a46c0ec8Sopenharmony_ci		break;
272a46c0ec8Sopenharmony_ci	case TAP_EVENT_PALM_UP:
273a46c0ec8Sopenharmony_ci		break;
274a46c0ec8Sopenharmony_ci	}
275a46c0ec8Sopenharmony_ci}
276a46c0ec8Sopenharmony_ci
277a46c0ec8Sopenharmony_cistatic void
278a46c0ec8Sopenharmony_citp_tap_hold_handle_event(struct tp_dispatch *tp,
279a46c0ec8Sopenharmony_ci			 struct tp_touch *t,
280a46c0ec8Sopenharmony_ci			 enum tap_event event, uint64_t time)
281a46c0ec8Sopenharmony_ci{
282a46c0ec8Sopenharmony_ci
283a46c0ec8Sopenharmony_ci	switch (event) {
284a46c0ec8Sopenharmony_ci	case TAP_EVENT_TOUCH:
285a46c0ec8Sopenharmony_ci		tp->tap.state = TAP_STATE_TOUCH_2;
286a46c0ec8Sopenharmony_ci		tp->tap.saved_press_time = time;
287a46c0ec8Sopenharmony_ci		tp_tap_set_timer(tp, time);
288a46c0ec8Sopenharmony_ci		break;
289a46c0ec8Sopenharmony_ci	case TAP_EVENT_RELEASE:
290a46c0ec8Sopenharmony_ci		tp->tap.state = TAP_STATE_IDLE;
291a46c0ec8Sopenharmony_ci		break;
292a46c0ec8Sopenharmony_ci	case TAP_EVENT_MOTION:
293a46c0ec8Sopenharmony_ci		tp_tap_move_to_dead(tp, t);
294a46c0ec8Sopenharmony_ci		break;
295a46c0ec8Sopenharmony_ci	case TAP_EVENT_TIMEOUT:
296a46c0ec8Sopenharmony_ci		break;
297a46c0ec8Sopenharmony_ci	case TAP_EVENT_BUTTON:
298a46c0ec8Sopenharmony_ci		tp->tap.state = TAP_STATE_DEAD;
299a46c0ec8Sopenharmony_ci		break;
300a46c0ec8Sopenharmony_ci	case TAP_EVENT_THUMB:
301a46c0ec8Sopenharmony_ci		tp->tap.state = TAP_STATE_IDLE;
302a46c0ec8Sopenharmony_ci		t->tap.is_thumb = true;
303a46c0ec8Sopenharmony_ci		tp->tap.nfingers_down--;
304a46c0ec8Sopenharmony_ci		t->tap.state = TAP_TOUCH_STATE_DEAD;
305a46c0ec8Sopenharmony_ci		break;
306a46c0ec8Sopenharmony_ci	case TAP_EVENT_PALM:
307a46c0ec8Sopenharmony_ci		tp->tap.state = TAP_STATE_IDLE;
308a46c0ec8Sopenharmony_ci		break;
309a46c0ec8Sopenharmony_ci	case TAP_EVENT_PALM_UP:
310a46c0ec8Sopenharmony_ci		break;
311a46c0ec8Sopenharmony_ci	}
312a46c0ec8Sopenharmony_ci}
313a46c0ec8Sopenharmony_ci
314a46c0ec8Sopenharmony_cistatic void
315a46c0ec8Sopenharmony_citp_tap_tapped_handle_event(struct tp_dispatch *tp,
316a46c0ec8Sopenharmony_ci			   struct tp_touch *t,
317a46c0ec8Sopenharmony_ci			   enum tap_event event, uint64_t time,
318a46c0ec8Sopenharmony_ci			   int nfingers_tapped)
319a46c0ec8Sopenharmony_ci{
320a46c0ec8Sopenharmony_ci	switch (event) {
321a46c0ec8Sopenharmony_ci	case TAP_EVENT_MOTION:
322a46c0ec8Sopenharmony_ci	case TAP_EVENT_RELEASE:
323a46c0ec8Sopenharmony_ci		log_tap_bug(tp, t, event);
324a46c0ec8Sopenharmony_ci		break;
325a46c0ec8Sopenharmony_ci	case TAP_EVENT_TOUCH: {
326a46c0ec8Sopenharmony_ci		enum tp_tap_state dest[3] = {
327a46c0ec8Sopenharmony_ci			TAP_STATE_1FGTAP_DRAGGING_OR_DOUBLETAP,
328a46c0ec8Sopenharmony_ci			TAP_STATE_2FGTAP_DRAGGING_OR_DOUBLETAP,
329a46c0ec8Sopenharmony_ci			TAP_STATE_3FGTAP_DRAGGING_OR_DOUBLETAP,
330a46c0ec8Sopenharmony_ci		};
331a46c0ec8Sopenharmony_ci		assert(nfingers_tapped >= 1 && nfingers_tapped <= 3);
332a46c0ec8Sopenharmony_ci		tp->tap.state = dest[nfingers_tapped - 1];
333a46c0ec8Sopenharmony_ci		tp->tap.saved_press_time = time;
334a46c0ec8Sopenharmony_ci		tp_tap_set_timer(tp, time);
335a46c0ec8Sopenharmony_ci		break;
336a46c0ec8Sopenharmony_ci	}
337a46c0ec8Sopenharmony_ci	case TAP_EVENT_TIMEOUT:
338a46c0ec8Sopenharmony_ci		tp->tap.state = TAP_STATE_IDLE;
339a46c0ec8Sopenharmony_ci		tp_tap_notify(tp,
340a46c0ec8Sopenharmony_ci			      tp->tap.saved_release_time,
341a46c0ec8Sopenharmony_ci			      nfingers_tapped,
342a46c0ec8Sopenharmony_ci			      LIBINPUT_BUTTON_STATE_RELEASED);
343a46c0ec8Sopenharmony_ci		break;
344a46c0ec8Sopenharmony_ci	case TAP_EVENT_BUTTON:
345a46c0ec8Sopenharmony_ci		tp->tap.state = TAP_STATE_DEAD;
346a46c0ec8Sopenharmony_ci		tp_tap_notify(tp,
347a46c0ec8Sopenharmony_ci			      tp->tap.saved_release_time,
348a46c0ec8Sopenharmony_ci			      nfingers_tapped,
349a46c0ec8Sopenharmony_ci			      LIBINPUT_BUTTON_STATE_RELEASED);
350a46c0ec8Sopenharmony_ci		break;
351a46c0ec8Sopenharmony_ci	case TAP_EVENT_THUMB:
352a46c0ec8Sopenharmony_ci		log_tap_bug(tp, t, event);
353a46c0ec8Sopenharmony_ci		break;
354a46c0ec8Sopenharmony_ci	case TAP_EVENT_PALM:
355a46c0ec8Sopenharmony_ci		log_tap_bug(tp, t, event);
356a46c0ec8Sopenharmony_ci		break;
357a46c0ec8Sopenharmony_ci	case TAP_EVENT_PALM_UP:
358a46c0ec8Sopenharmony_ci		break;
359a46c0ec8Sopenharmony_ci	}
360a46c0ec8Sopenharmony_ci}
361a46c0ec8Sopenharmony_ci
362a46c0ec8Sopenharmony_cistatic void
363a46c0ec8Sopenharmony_citp_tap_touch2_handle_event(struct tp_dispatch *tp,
364a46c0ec8Sopenharmony_ci			   struct tp_touch *t,
365a46c0ec8Sopenharmony_ci			   enum tap_event event, uint64_t time)
366a46c0ec8Sopenharmony_ci{
367a46c0ec8Sopenharmony_ci
368a46c0ec8Sopenharmony_ci	switch (event) {
369a46c0ec8Sopenharmony_ci	case TAP_EVENT_TOUCH:
370a46c0ec8Sopenharmony_ci		tp->tap.state = TAP_STATE_TOUCH_3;
371a46c0ec8Sopenharmony_ci		tp->tap.saved_press_time = time;
372a46c0ec8Sopenharmony_ci		tp_tap_set_timer(tp, time);
373a46c0ec8Sopenharmony_ci		break;
374a46c0ec8Sopenharmony_ci	case TAP_EVENT_RELEASE:
375a46c0ec8Sopenharmony_ci		tp->tap.state = TAP_STATE_TOUCH_2_RELEASE;
376a46c0ec8Sopenharmony_ci		tp->tap.saved_release_time = time;
377a46c0ec8Sopenharmony_ci		tp_tap_set_timer(tp, time);
378a46c0ec8Sopenharmony_ci		break;
379a46c0ec8Sopenharmony_ci	case TAP_EVENT_MOTION:
380a46c0ec8Sopenharmony_ci		tp_tap_move_to_dead(tp, t);
381a46c0ec8Sopenharmony_ci		break;
382a46c0ec8Sopenharmony_ci	case TAP_EVENT_TIMEOUT:
383a46c0ec8Sopenharmony_ci		tp->tap.state = TAP_STATE_TOUCH_2_HOLD;
384a46c0ec8Sopenharmony_ci		tp_gesture_tap_timeout(tp, time);
385a46c0ec8Sopenharmony_ci		break;
386a46c0ec8Sopenharmony_ci	case TAP_EVENT_BUTTON:
387a46c0ec8Sopenharmony_ci		tp->tap.state = TAP_STATE_DEAD;
388a46c0ec8Sopenharmony_ci		break;
389a46c0ec8Sopenharmony_ci	case TAP_EVENT_THUMB:
390a46c0ec8Sopenharmony_ci		break;
391a46c0ec8Sopenharmony_ci	case TAP_EVENT_PALM:
392a46c0ec8Sopenharmony_ci		tp->tap.state = TAP_STATE_TOUCH;
393a46c0ec8Sopenharmony_ci		break;
394a46c0ec8Sopenharmony_ci	case TAP_EVENT_PALM_UP:
395a46c0ec8Sopenharmony_ci		break;
396a46c0ec8Sopenharmony_ci	}
397a46c0ec8Sopenharmony_ci}
398a46c0ec8Sopenharmony_ci
399a46c0ec8Sopenharmony_cistatic void
400a46c0ec8Sopenharmony_citp_tap_touch2_hold_handle_event(struct tp_dispatch *tp,
401a46c0ec8Sopenharmony_ci				struct tp_touch *t,
402a46c0ec8Sopenharmony_ci				enum tap_event event, uint64_t time)
403a46c0ec8Sopenharmony_ci{
404a46c0ec8Sopenharmony_ci
405a46c0ec8Sopenharmony_ci	switch (event) {
406a46c0ec8Sopenharmony_ci	case TAP_EVENT_TOUCH:
407a46c0ec8Sopenharmony_ci		tp->tap.state = TAP_STATE_TOUCH_3;
408a46c0ec8Sopenharmony_ci		tp->tap.saved_press_time = time;
409a46c0ec8Sopenharmony_ci		tp_tap_set_timer(tp, time);
410a46c0ec8Sopenharmony_ci		break;
411a46c0ec8Sopenharmony_ci	case TAP_EVENT_RELEASE:
412a46c0ec8Sopenharmony_ci		tp->tap.state = TAP_STATE_HOLD;
413a46c0ec8Sopenharmony_ci		break;
414a46c0ec8Sopenharmony_ci	case TAP_EVENT_MOTION:
415a46c0ec8Sopenharmony_ci		tp_tap_move_to_dead(tp, t);
416a46c0ec8Sopenharmony_ci		break;
417a46c0ec8Sopenharmony_ci	case TAP_EVENT_TIMEOUT:
418a46c0ec8Sopenharmony_ci		tp->tap.state = TAP_STATE_TOUCH_2_HOLD;
419a46c0ec8Sopenharmony_ci		break;
420a46c0ec8Sopenharmony_ci	case TAP_EVENT_BUTTON:
421a46c0ec8Sopenharmony_ci		tp->tap.state = TAP_STATE_DEAD;
422a46c0ec8Sopenharmony_ci		break;
423a46c0ec8Sopenharmony_ci	case TAP_EVENT_THUMB:
424a46c0ec8Sopenharmony_ci		break;
425a46c0ec8Sopenharmony_ci	case TAP_EVENT_PALM:
426a46c0ec8Sopenharmony_ci		tp->tap.state = TAP_STATE_HOLD;
427a46c0ec8Sopenharmony_ci		break;
428a46c0ec8Sopenharmony_ci	case TAP_EVENT_PALM_UP:
429a46c0ec8Sopenharmony_ci		break;
430a46c0ec8Sopenharmony_ci	}
431a46c0ec8Sopenharmony_ci}
432a46c0ec8Sopenharmony_ci
433a46c0ec8Sopenharmony_cistatic void
434a46c0ec8Sopenharmony_citp_tap_touch2_release_handle_event(struct tp_dispatch *tp,
435a46c0ec8Sopenharmony_ci				   struct tp_touch *t,
436a46c0ec8Sopenharmony_ci				   enum tap_event event, uint64_t time)
437a46c0ec8Sopenharmony_ci{
438a46c0ec8Sopenharmony_ci
439a46c0ec8Sopenharmony_ci	switch (event) {
440a46c0ec8Sopenharmony_ci	case TAP_EVENT_TOUCH:
441a46c0ec8Sopenharmony_ci		tp->tap.state = TAP_STATE_TOUCH_2_HOLD;
442a46c0ec8Sopenharmony_ci		t->tap.state = TAP_TOUCH_STATE_DEAD;
443a46c0ec8Sopenharmony_ci		tp_tap_clear_timer(tp);
444a46c0ec8Sopenharmony_ci		break;
445a46c0ec8Sopenharmony_ci	case TAP_EVENT_RELEASE:
446a46c0ec8Sopenharmony_ci		tp_tap_notify(tp,
447a46c0ec8Sopenharmony_ci			      tp->tap.saved_press_time,
448a46c0ec8Sopenharmony_ci			      2,
449a46c0ec8Sopenharmony_ci			      LIBINPUT_BUTTON_STATE_PRESSED);
450a46c0ec8Sopenharmony_ci		if (tp->tap.drag_enabled) {
451a46c0ec8Sopenharmony_ci			tp->tap.state = TAP_STATE_2FGTAP_TAPPED;
452a46c0ec8Sopenharmony_ci			tp_tap_set_drag_timer(tp, time, 2);
453a46c0ec8Sopenharmony_ci		} else {
454a46c0ec8Sopenharmony_ci			tp_tap_notify(tp,
455a46c0ec8Sopenharmony_ci				      tp->tap.saved_release_time,
456a46c0ec8Sopenharmony_ci				      2,
457a46c0ec8Sopenharmony_ci				      LIBINPUT_BUTTON_STATE_RELEASED);
458a46c0ec8Sopenharmony_ci			tp->tap.state = TAP_STATE_IDLE;
459a46c0ec8Sopenharmony_ci		}
460a46c0ec8Sopenharmony_ci		break;
461a46c0ec8Sopenharmony_ci	case TAP_EVENT_MOTION:
462a46c0ec8Sopenharmony_ci		tp_tap_move_to_dead(tp, t);
463a46c0ec8Sopenharmony_ci		break;
464a46c0ec8Sopenharmony_ci	case TAP_EVENT_TIMEOUT:
465a46c0ec8Sopenharmony_ci		tp->tap.state = TAP_STATE_HOLD;
466a46c0ec8Sopenharmony_ci		break;
467a46c0ec8Sopenharmony_ci	case TAP_EVENT_BUTTON:
468a46c0ec8Sopenharmony_ci		tp->tap.state = TAP_STATE_DEAD;
469a46c0ec8Sopenharmony_ci		break;
470a46c0ec8Sopenharmony_ci	case TAP_EVENT_THUMB:
471a46c0ec8Sopenharmony_ci		break;
472a46c0ec8Sopenharmony_ci	case TAP_EVENT_PALM:
473a46c0ec8Sopenharmony_ci		/* There's only one saved press time and it's overwritten by
474a46c0ec8Sopenharmony_ci		 * the last touch down. So in the case of finger down, palm
475a46c0ec8Sopenharmony_ci		 * down, finger up, palm detected, we use the
476a46c0ec8Sopenharmony_ci		 * palm touch's press time here instead of the finger's press
477a46c0ec8Sopenharmony_ci		 * time. Let's wait and see if that's an issue.
478a46c0ec8Sopenharmony_ci		 */
479a46c0ec8Sopenharmony_ci		tp_tap_notify(tp,
480a46c0ec8Sopenharmony_ci			      tp->tap.saved_press_time,
481a46c0ec8Sopenharmony_ci			      1,
482a46c0ec8Sopenharmony_ci			      LIBINPUT_BUTTON_STATE_PRESSED);
483a46c0ec8Sopenharmony_ci		if (tp->tap.drag_enabled) {
484a46c0ec8Sopenharmony_ci			/* For a single-finger tap the timer delay is the same
485a46c0ec8Sopenharmony_ci			 * as for the release of the finger that became a palm,
486a46c0ec8Sopenharmony_ci			 * no reset necessary */
487a46c0ec8Sopenharmony_ci			tp->tap.state = TAP_STATE_1FGTAP_TAPPED;
488a46c0ec8Sopenharmony_ci		} else {
489a46c0ec8Sopenharmony_ci			tp_tap_notify(tp,
490a46c0ec8Sopenharmony_ci				      tp->tap.saved_release_time,
491a46c0ec8Sopenharmony_ci				      1,
492a46c0ec8Sopenharmony_ci				      LIBINPUT_BUTTON_STATE_RELEASED);
493a46c0ec8Sopenharmony_ci			tp->tap.state = TAP_STATE_IDLE;
494a46c0ec8Sopenharmony_ci		}
495a46c0ec8Sopenharmony_ci		break;
496a46c0ec8Sopenharmony_ci	case TAP_EVENT_PALM_UP:
497a46c0ec8Sopenharmony_ci		break;
498a46c0ec8Sopenharmony_ci	}
499a46c0ec8Sopenharmony_ci}
500a46c0ec8Sopenharmony_ci
501a46c0ec8Sopenharmony_cistatic void
502a46c0ec8Sopenharmony_citp_tap_touch3_handle_event(struct tp_dispatch *tp,
503a46c0ec8Sopenharmony_ci			   struct tp_touch *t,
504a46c0ec8Sopenharmony_ci			   enum tap_event event, uint64_t time)
505a46c0ec8Sopenharmony_ci{
506a46c0ec8Sopenharmony_ci
507a46c0ec8Sopenharmony_ci	switch (event) {
508a46c0ec8Sopenharmony_ci	case TAP_EVENT_TOUCH:
509a46c0ec8Sopenharmony_ci		tp->tap.state = TAP_STATE_DEAD;
510a46c0ec8Sopenharmony_ci		tp_tap_clear_timer(tp);
511a46c0ec8Sopenharmony_ci		break;
512a46c0ec8Sopenharmony_ci	case TAP_EVENT_MOTION:
513a46c0ec8Sopenharmony_ci		tp_tap_move_to_dead(tp, t);
514a46c0ec8Sopenharmony_ci		break;
515a46c0ec8Sopenharmony_ci	case TAP_EVENT_TIMEOUT:
516a46c0ec8Sopenharmony_ci		tp->tap.state = TAP_STATE_TOUCH_3_HOLD;
517a46c0ec8Sopenharmony_ci		tp_tap_clear_timer(tp);
518a46c0ec8Sopenharmony_ci		tp_gesture_tap_timeout(tp, time);
519a46c0ec8Sopenharmony_ci		break;
520a46c0ec8Sopenharmony_ci	case TAP_EVENT_RELEASE:
521a46c0ec8Sopenharmony_ci		tp->tap.state = TAP_STATE_TOUCH_3_RELEASE;
522a46c0ec8Sopenharmony_ci		tp->tap.saved_release_time = time;
523a46c0ec8Sopenharmony_ci		tp_tap_set_timer(tp, time);
524a46c0ec8Sopenharmony_ci		break;
525a46c0ec8Sopenharmony_ci	case TAP_EVENT_BUTTON:
526a46c0ec8Sopenharmony_ci		tp->tap.state = TAP_STATE_DEAD;
527a46c0ec8Sopenharmony_ci		break;
528a46c0ec8Sopenharmony_ci	case TAP_EVENT_THUMB:
529a46c0ec8Sopenharmony_ci		break;
530a46c0ec8Sopenharmony_ci	case TAP_EVENT_PALM:
531a46c0ec8Sopenharmony_ci		tp->tap.state = TAP_STATE_TOUCH_2;
532a46c0ec8Sopenharmony_ci		break;
533a46c0ec8Sopenharmony_ci	case TAP_EVENT_PALM_UP:
534a46c0ec8Sopenharmony_ci		break;
535a46c0ec8Sopenharmony_ci	}
536a46c0ec8Sopenharmony_ci}
537a46c0ec8Sopenharmony_ci
538a46c0ec8Sopenharmony_cistatic void
539a46c0ec8Sopenharmony_citp_tap_touch3_hold_handle_event(struct tp_dispatch *tp,
540a46c0ec8Sopenharmony_ci				struct tp_touch *t,
541a46c0ec8Sopenharmony_ci				enum tap_event event, uint64_t time)
542a46c0ec8Sopenharmony_ci{
543a46c0ec8Sopenharmony_ci
544a46c0ec8Sopenharmony_ci	switch (event) {
545a46c0ec8Sopenharmony_ci	case TAP_EVENT_TOUCH:
546a46c0ec8Sopenharmony_ci		tp->tap.state = TAP_STATE_DEAD;
547a46c0ec8Sopenharmony_ci		tp_tap_set_timer(tp, time);
548a46c0ec8Sopenharmony_ci		break;
549a46c0ec8Sopenharmony_ci	case TAP_EVENT_RELEASE:
550a46c0ec8Sopenharmony_ci		tp->tap.state = TAP_STATE_TOUCH_2_HOLD;
551a46c0ec8Sopenharmony_ci		break;
552a46c0ec8Sopenharmony_ci	case TAP_EVENT_MOTION:
553a46c0ec8Sopenharmony_ci		tp_tap_move_to_dead(tp, t);
554a46c0ec8Sopenharmony_ci		break;
555a46c0ec8Sopenharmony_ci	case TAP_EVENT_TIMEOUT:
556a46c0ec8Sopenharmony_ci		break;
557a46c0ec8Sopenharmony_ci	case TAP_EVENT_BUTTON:
558a46c0ec8Sopenharmony_ci		tp->tap.state = TAP_STATE_DEAD;
559a46c0ec8Sopenharmony_ci		break;
560a46c0ec8Sopenharmony_ci	case TAP_EVENT_THUMB:
561a46c0ec8Sopenharmony_ci		break;
562a46c0ec8Sopenharmony_ci	case TAP_EVENT_PALM:
563a46c0ec8Sopenharmony_ci		tp->tap.state = TAP_STATE_TOUCH_2_HOLD;
564a46c0ec8Sopenharmony_ci		break;
565a46c0ec8Sopenharmony_ci	case TAP_EVENT_PALM_UP:
566a46c0ec8Sopenharmony_ci		break;
567a46c0ec8Sopenharmony_ci	}
568a46c0ec8Sopenharmony_ci}
569a46c0ec8Sopenharmony_ci
570a46c0ec8Sopenharmony_cistatic void
571a46c0ec8Sopenharmony_citp_tap_touch3_release_handle_event(struct tp_dispatch *tp,
572a46c0ec8Sopenharmony_ci				   struct tp_touch *t,
573a46c0ec8Sopenharmony_ci				   enum tap_event event, uint64_t time)
574a46c0ec8Sopenharmony_ci{
575a46c0ec8Sopenharmony_ci
576a46c0ec8Sopenharmony_ci	switch (event) {
577a46c0ec8Sopenharmony_ci	case TAP_EVENT_TOUCH:
578a46c0ec8Sopenharmony_ci		tp_tap_notify(tp,
579a46c0ec8Sopenharmony_ci			      tp->tap.saved_press_time,
580a46c0ec8Sopenharmony_ci			      3,
581a46c0ec8Sopenharmony_ci			      LIBINPUT_BUTTON_STATE_PRESSED);
582a46c0ec8Sopenharmony_ci		tp_tap_notify(tp,
583a46c0ec8Sopenharmony_ci			      tp->tap.saved_release_time,
584a46c0ec8Sopenharmony_ci			      3,
585a46c0ec8Sopenharmony_ci			      LIBINPUT_BUTTON_STATE_RELEASED);
586a46c0ec8Sopenharmony_ci		tp->tap.state = TAP_STATE_TOUCH_3;
587a46c0ec8Sopenharmony_ci		tp->tap.saved_press_time = time;
588a46c0ec8Sopenharmony_ci		tp_tap_set_timer(tp, time);
589a46c0ec8Sopenharmony_ci		break;
590a46c0ec8Sopenharmony_ci	case TAP_EVENT_RELEASE:
591a46c0ec8Sopenharmony_ci		tp->tap.state = TAP_STATE_TOUCH_3_RELEASE_2;
592a46c0ec8Sopenharmony_ci		tp_tap_set_timer(tp, time);
593a46c0ec8Sopenharmony_ci		break;
594a46c0ec8Sopenharmony_ci	case TAP_EVENT_MOTION:
595a46c0ec8Sopenharmony_ci		tp_tap_notify(tp,
596a46c0ec8Sopenharmony_ci			      tp->tap.saved_press_time,
597a46c0ec8Sopenharmony_ci			      3,
598a46c0ec8Sopenharmony_ci			      LIBINPUT_BUTTON_STATE_PRESSED);
599a46c0ec8Sopenharmony_ci		tp_tap_notify(tp,
600a46c0ec8Sopenharmony_ci			      tp->tap.saved_release_time,
601a46c0ec8Sopenharmony_ci			      3,
602a46c0ec8Sopenharmony_ci			      LIBINPUT_BUTTON_STATE_RELEASED);
603a46c0ec8Sopenharmony_ci		tp_tap_move_to_dead(tp, t);
604a46c0ec8Sopenharmony_ci		break;
605a46c0ec8Sopenharmony_ci	case TAP_EVENT_TIMEOUT:
606a46c0ec8Sopenharmony_ci		tp_tap_notify(tp,
607a46c0ec8Sopenharmony_ci			      tp->tap.saved_press_time,
608a46c0ec8Sopenharmony_ci			      3,
609a46c0ec8Sopenharmony_ci			      LIBINPUT_BUTTON_STATE_PRESSED);
610a46c0ec8Sopenharmony_ci		tp_tap_notify(tp,
611a46c0ec8Sopenharmony_ci			      tp->tap.saved_release_time,
612a46c0ec8Sopenharmony_ci			      3,
613a46c0ec8Sopenharmony_ci			      LIBINPUT_BUTTON_STATE_RELEASED);
614a46c0ec8Sopenharmony_ci		tp->tap.state = TAP_STATE_TOUCH_2_HOLD;
615a46c0ec8Sopenharmony_ci		break;
616a46c0ec8Sopenharmony_ci	case TAP_EVENT_BUTTON:
617a46c0ec8Sopenharmony_ci		tp_tap_notify(tp,
618a46c0ec8Sopenharmony_ci			      tp->tap.saved_press_time,
619a46c0ec8Sopenharmony_ci			      3,
620a46c0ec8Sopenharmony_ci			      LIBINPUT_BUTTON_STATE_PRESSED);
621a46c0ec8Sopenharmony_ci		tp_tap_notify(tp,
622a46c0ec8Sopenharmony_ci			      tp->tap.saved_release_time,
623a46c0ec8Sopenharmony_ci			      3,
624a46c0ec8Sopenharmony_ci			      LIBINPUT_BUTTON_STATE_RELEASED);
625a46c0ec8Sopenharmony_ci		tp->tap.state = TAP_STATE_DEAD;
626a46c0ec8Sopenharmony_ci		break;
627a46c0ec8Sopenharmony_ci	case TAP_EVENT_THUMB:
628a46c0ec8Sopenharmony_ci		break;
629a46c0ec8Sopenharmony_ci	case TAP_EVENT_PALM:
630a46c0ec8Sopenharmony_ci		tp->tap.state = TAP_STATE_TOUCH_2_RELEASE;
631a46c0ec8Sopenharmony_ci		break;
632a46c0ec8Sopenharmony_ci	case TAP_EVENT_PALM_UP:
633a46c0ec8Sopenharmony_ci		break;
634a46c0ec8Sopenharmony_ci	}
635a46c0ec8Sopenharmony_ci}
636a46c0ec8Sopenharmony_ci
637a46c0ec8Sopenharmony_cistatic void
638a46c0ec8Sopenharmony_citp_tap_touch3_release2_handle_event(struct tp_dispatch *tp,
639a46c0ec8Sopenharmony_ci				    struct tp_touch *t,
640a46c0ec8Sopenharmony_ci				    enum tap_event event, uint64_t time)
641a46c0ec8Sopenharmony_ci{
642a46c0ec8Sopenharmony_ci
643a46c0ec8Sopenharmony_ci	switch (event) {
644a46c0ec8Sopenharmony_ci	case TAP_EVENT_TOUCH:
645a46c0ec8Sopenharmony_ci		tp_tap_notify(tp,
646a46c0ec8Sopenharmony_ci			      tp->tap.saved_press_time,
647a46c0ec8Sopenharmony_ci			      3,
648a46c0ec8Sopenharmony_ci			      LIBINPUT_BUTTON_STATE_PRESSED);
649a46c0ec8Sopenharmony_ci		tp_tap_notify(tp,
650a46c0ec8Sopenharmony_ci			      tp->tap.saved_release_time,
651a46c0ec8Sopenharmony_ci			      3,
652a46c0ec8Sopenharmony_ci			      LIBINPUT_BUTTON_STATE_RELEASED);
653a46c0ec8Sopenharmony_ci		tp->tap.state = TAP_STATE_TOUCH_2;
654a46c0ec8Sopenharmony_ci		tp->tap.saved_press_time = time;
655a46c0ec8Sopenharmony_ci		tp_tap_set_timer(tp, time);
656a46c0ec8Sopenharmony_ci		break;
657a46c0ec8Sopenharmony_ci	case TAP_EVENT_RELEASE:
658a46c0ec8Sopenharmony_ci		tp_tap_notify(tp,
659a46c0ec8Sopenharmony_ci			      tp->tap.saved_press_time,
660a46c0ec8Sopenharmony_ci			      3,
661a46c0ec8Sopenharmony_ci			      LIBINPUT_BUTTON_STATE_PRESSED);
662a46c0ec8Sopenharmony_ci		if (tp->tap.drag_enabled) {
663a46c0ec8Sopenharmony_ci			tp->tap.state = TAP_STATE_3FGTAP_TAPPED;
664a46c0ec8Sopenharmony_ci			tp_tap_set_drag_timer(tp, time, 3);
665a46c0ec8Sopenharmony_ci		} else {
666a46c0ec8Sopenharmony_ci			tp_tap_notify(tp,
667a46c0ec8Sopenharmony_ci				      tp->tap.saved_release_time,
668a46c0ec8Sopenharmony_ci				      3,
669a46c0ec8Sopenharmony_ci				      LIBINPUT_BUTTON_STATE_RELEASED);
670a46c0ec8Sopenharmony_ci			tp->tap.state = TAP_STATE_IDLE;
671a46c0ec8Sopenharmony_ci		}
672a46c0ec8Sopenharmony_ci		break;
673a46c0ec8Sopenharmony_ci	case TAP_EVENT_MOTION:
674a46c0ec8Sopenharmony_ci		tp_tap_notify(tp,
675a46c0ec8Sopenharmony_ci			      tp->tap.saved_press_time,
676a46c0ec8Sopenharmony_ci			      3,
677a46c0ec8Sopenharmony_ci			      LIBINPUT_BUTTON_STATE_PRESSED);
678a46c0ec8Sopenharmony_ci		tp_tap_notify(tp,
679a46c0ec8Sopenharmony_ci			      tp->tap.saved_release_time,
680a46c0ec8Sopenharmony_ci			      3,
681a46c0ec8Sopenharmony_ci			      LIBINPUT_BUTTON_STATE_RELEASED);
682a46c0ec8Sopenharmony_ci		tp_tap_move_to_dead(tp, t);
683a46c0ec8Sopenharmony_ci		break;
684a46c0ec8Sopenharmony_ci	case TAP_EVENT_TIMEOUT:
685a46c0ec8Sopenharmony_ci		tp_tap_notify(tp,
686a46c0ec8Sopenharmony_ci			      tp->tap.saved_press_time,
687a46c0ec8Sopenharmony_ci			      3,
688a46c0ec8Sopenharmony_ci			      LIBINPUT_BUTTON_STATE_PRESSED);
689a46c0ec8Sopenharmony_ci		tp_tap_notify(tp,
690a46c0ec8Sopenharmony_ci			      tp->tap.saved_release_time,
691a46c0ec8Sopenharmony_ci			      3,
692a46c0ec8Sopenharmony_ci			      LIBINPUT_BUTTON_STATE_RELEASED);
693a46c0ec8Sopenharmony_ci		tp->tap.state = TAP_STATE_HOLD;
694a46c0ec8Sopenharmony_ci		break;
695a46c0ec8Sopenharmony_ci	case TAP_EVENT_BUTTON:
696a46c0ec8Sopenharmony_ci		tp_tap_notify(tp,
697a46c0ec8Sopenharmony_ci			      tp->tap.saved_press_time,
698a46c0ec8Sopenharmony_ci			      3,
699a46c0ec8Sopenharmony_ci			      LIBINPUT_BUTTON_STATE_PRESSED);
700a46c0ec8Sopenharmony_ci		tp_tap_notify(tp,
701a46c0ec8Sopenharmony_ci			      tp->tap.saved_release_time,
702a46c0ec8Sopenharmony_ci			      3,
703a46c0ec8Sopenharmony_ci			      LIBINPUT_BUTTON_STATE_RELEASED);
704a46c0ec8Sopenharmony_ci		tp->tap.state = TAP_STATE_DEAD;
705a46c0ec8Sopenharmony_ci		break;
706a46c0ec8Sopenharmony_ci	case TAP_EVENT_THUMB:
707a46c0ec8Sopenharmony_ci		break;
708a46c0ec8Sopenharmony_ci	case TAP_EVENT_PALM:
709a46c0ec8Sopenharmony_ci		tp_tap_notify(tp,
710a46c0ec8Sopenharmony_ci			      tp->tap.saved_press_time,
711a46c0ec8Sopenharmony_ci			      2,
712a46c0ec8Sopenharmony_ci			      LIBINPUT_BUTTON_STATE_PRESSED);
713a46c0ec8Sopenharmony_ci		if (tp->tap.drag_enabled) {
714a46c0ec8Sopenharmony_ci			/* Resetting the timer to the appropriate delay
715a46c0ec8Sopenharmony_ci			 * for a two-finger tap would be ideal, but the
716a46c0ec8Sopenharmony_ci			 * timestamp of the last real finger release is lost,
717a46c0ec8Sopenharmony_ci			 * so the in-progress similar delay for release
718a46c0ec8Sopenharmony_ci			 * of the finger which became a palm instead
719a46c0ec8Sopenharmony_ci			 * will have to do */
720a46c0ec8Sopenharmony_ci			tp->tap.state = TAP_STATE_2FGTAP_TAPPED;
721a46c0ec8Sopenharmony_ci		} else {
722a46c0ec8Sopenharmony_ci			tp_tap_notify(tp,
723a46c0ec8Sopenharmony_ci				      tp->tap.saved_release_time,
724a46c0ec8Sopenharmony_ci				      2,
725a46c0ec8Sopenharmony_ci				      LIBINPUT_BUTTON_STATE_RELEASED);
726a46c0ec8Sopenharmony_ci			tp->tap.state = TAP_STATE_IDLE;
727a46c0ec8Sopenharmony_ci		}
728a46c0ec8Sopenharmony_ci		break;
729a46c0ec8Sopenharmony_ci	case TAP_EVENT_PALM_UP:
730a46c0ec8Sopenharmony_ci		break;
731a46c0ec8Sopenharmony_ci	}
732a46c0ec8Sopenharmony_ci}
733a46c0ec8Sopenharmony_ci
734a46c0ec8Sopenharmony_cistatic void
735a46c0ec8Sopenharmony_citp_tap_dragging_or_doubletap_handle_event(struct tp_dispatch *tp,
736a46c0ec8Sopenharmony_ci					  struct tp_touch *t,
737a46c0ec8Sopenharmony_ci					  enum tap_event event, uint64_t time,
738a46c0ec8Sopenharmony_ci					  int nfingers_tapped)
739a46c0ec8Sopenharmony_ci{
740a46c0ec8Sopenharmony_ci	switch (event) {
741a46c0ec8Sopenharmony_ci	case TAP_EVENT_TOUCH: {
742a46c0ec8Sopenharmony_ci		tp_tap_notify(tp,
743a46c0ec8Sopenharmony_ci			      tp->tap.saved_release_time,
744a46c0ec8Sopenharmony_ci			      nfingers_tapped,
745a46c0ec8Sopenharmony_ci			      LIBINPUT_BUTTON_STATE_RELEASED);
746a46c0ec8Sopenharmony_ci		tp->tap.state = TAP_STATE_TOUCH_2;
747a46c0ec8Sopenharmony_ci		tp->tap.saved_press_time = time;
748a46c0ec8Sopenharmony_ci		tp_tap_set_timer(tp, time);
749a46c0ec8Sopenharmony_ci		break;
750a46c0ec8Sopenharmony_ci	}
751a46c0ec8Sopenharmony_ci	case TAP_EVENT_RELEASE:
752a46c0ec8Sopenharmony_ci		tp->tap.state = TAP_STATE_1FGTAP_TAPPED;
753a46c0ec8Sopenharmony_ci		tp_tap_notify(tp,
754a46c0ec8Sopenharmony_ci			      tp->tap.saved_release_time,
755a46c0ec8Sopenharmony_ci			      nfingers_tapped,
756a46c0ec8Sopenharmony_ci			      LIBINPUT_BUTTON_STATE_RELEASED);
757a46c0ec8Sopenharmony_ci		tp_tap_notify(tp,
758a46c0ec8Sopenharmony_ci			      tp->tap.saved_press_time,
759a46c0ec8Sopenharmony_ci			      1,
760a46c0ec8Sopenharmony_ci			      LIBINPUT_BUTTON_STATE_PRESSED);
761a46c0ec8Sopenharmony_ci		tp->tap.saved_release_time = time;
762a46c0ec8Sopenharmony_ci		tp_tap_set_timer(tp, time);
763a46c0ec8Sopenharmony_ci		break;
764a46c0ec8Sopenharmony_ci	case TAP_EVENT_MOTION:
765a46c0ec8Sopenharmony_ci	case TAP_EVENT_TIMEOUT: {
766a46c0ec8Sopenharmony_ci		enum tp_tap_state dest[3] = {
767a46c0ec8Sopenharmony_ci			TAP_STATE_1FGTAP_DRAGGING,
768a46c0ec8Sopenharmony_ci			TAP_STATE_2FGTAP_DRAGGING,
769a46c0ec8Sopenharmony_ci			TAP_STATE_3FGTAP_DRAGGING,
770a46c0ec8Sopenharmony_ci		};
771a46c0ec8Sopenharmony_ci		assert(nfingers_tapped >= 1 && nfingers_tapped <= 3);
772a46c0ec8Sopenharmony_ci		tp->tap.state = dest[nfingers_tapped - 1];
773a46c0ec8Sopenharmony_ci		break;
774a46c0ec8Sopenharmony_ci	}
775a46c0ec8Sopenharmony_ci	case TAP_EVENT_BUTTON:
776a46c0ec8Sopenharmony_ci		tp->tap.state = TAP_STATE_DEAD;
777a46c0ec8Sopenharmony_ci		tp_tap_notify(tp,
778a46c0ec8Sopenharmony_ci			      tp->tap.saved_release_time,
779a46c0ec8Sopenharmony_ci			      nfingers_tapped,
780a46c0ec8Sopenharmony_ci			      LIBINPUT_BUTTON_STATE_RELEASED);
781a46c0ec8Sopenharmony_ci		break;
782a46c0ec8Sopenharmony_ci	case TAP_EVENT_THUMB:
783a46c0ec8Sopenharmony_ci		break;
784a46c0ec8Sopenharmony_ci	case TAP_EVENT_PALM: {
785a46c0ec8Sopenharmony_ci		enum tp_tap_state dest[3] = {
786a46c0ec8Sopenharmony_ci			TAP_STATE_1FGTAP_TAPPED,
787a46c0ec8Sopenharmony_ci			TAP_STATE_2FGTAP_TAPPED,
788a46c0ec8Sopenharmony_ci			TAP_STATE_3FGTAP_TAPPED,
789a46c0ec8Sopenharmony_ci		};
790a46c0ec8Sopenharmony_ci		assert(nfingers_tapped >= 1 && nfingers_tapped <= 3);
791a46c0ec8Sopenharmony_ci		tp->tap.state = dest[nfingers_tapped - 1];
792a46c0ec8Sopenharmony_ci		break;
793a46c0ec8Sopenharmony_ci	}
794a46c0ec8Sopenharmony_ci	case TAP_EVENT_PALM_UP:
795a46c0ec8Sopenharmony_ci		break;
796a46c0ec8Sopenharmony_ci	}
797a46c0ec8Sopenharmony_ci}
798a46c0ec8Sopenharmony_ci
799a46c0ec8Sopenharmony_cistatic void
800a46c0ec8Sopenharmony_citp_tap_dragging_handle_event(struct tp_dispatch *tp,
801a46c0ec8Sopenharmony_ci			     struct tp_touch *t,
802a46c0ec8Sopenharmony_ci			     enum tap_event event, uint64_t time,
803a46c0ec8Sopenharmony_ci			     int nfingers_tapped)
804a46c0ec8Sopenharmony_ci{
805a46c0ec8Sopenharmony_ci
806a46c0ec8Sopenharmony_ci	switch (event) {
807a46c0ec8Sopenharmony_ci	case TAP_EVENT_TOUCH: {
808a46c0ec8Sopenharmony_ci		enum tp_tap_state dest[3] = {
809a46c0ec8Sopenharmony_ci			TAP_STATE_1FGTAP_DRAGGING_2,
810a46c0ec8Sopenharmony_ci			TAP_STATE_2FGTAP_DRAGGING_2,
811a46c0ec8Sopenharmony_ci			TAP_STATE_3FGTAP_DRAGGING_2,
812a46c0ec8Sopenharmony_ci		};
813a46c0ec8Sopenharmony_ci		assert(nfingers_tapped >= 1 && nfingers_tapped <= 3);
814a46c0ec8Sopenharmony_ci		tp->tap.state = dest[nfingers_tapped - 1];
815a46c0ec8Sopenharmony_ci		break;
816a46c0ec8Sopenharmony_ci	}
817a46c0ec8Sopenharmony_ci	case TAP_EVENT_RELEASE:
818a46c0ec8Sopenharmony_ci		if (tp->tap.drag_lock_enabled) {
819a46c0ec8Sopenharmony_ci			enum tp_tap_state dest[3] = {
820a46c0ec8Sopenharmony_ci				TAP_STATE_1FGTAP_DRAGGING_WAIT,
821a46c0ec8Sopenharmony_ci				TAP_STATE_2FGTAP_DRAGGING_WAIT,
822a46c0ec8Sopenharmony_ci				TAP_STATE_3FGTAP_DRAGGING_WAIT,
823a46c0ec8Sopenharmony_ci			};
824a46c0ec8Sopenharmony_ci			assert(nfingers_tapped >= 1 && nfingers_tapped <= 3);
825a46c0ec8Sopenharmony_ci			tp->tap.state = dest[nfingers_tapped - 1];
826a46c0ec8Sopenharmony_ci			tp_tap_set_draglock_timer(tp, time);
827a46c0ec8Sopenharmony_ci		} else {
828a46c0ec8Sopenharmony_ci			tp_tap_notify(tp,
829a46c0ec8Sopenharmony_ci				      time,
830a46c0ec8Sopenharmony_ci				      nfingers_tapped,
831a46c0ec8Sopenharmony_ci				      LIBINPUT_BUTTON_STATE_RELEASED);
832a46c0ec8Sopenharmony_ci			tp->tap.state = TAP_STATE_IDLE;
833a46c0ec8Sopenharmony_ci		}
834a46c0ec8Sopenharmony_ci		break;
835a46c0ec8Sopenharmony_ci	case TAP_EVENT_MOTION:
836a46c0ec8Sopenharmony_ci	case TAP_EVENT_TIMEOUT:
837a46c0ec8Sopenharmony_ci		/* noop */
838a46c0ec8Sopenharmony_ci		break;
839a46c0ec8Sopenharmony_ci	case TAP_EVENT_BUTTON:
840a46c0ec8Sopenharmony_ci		tp->tap.state = TAP_STATE_DEAD;
841a46c0ec8Sopenharmony_ci		tp_tap_notify(tp,
842a46c0ec8Sopenharmony_ci			      time,
843a46c0ec8Sopenharmony_ci			      nfingers_tapped,
844a46c0ec8Sopenharmony_ci			      LIBINPUT_BUTTON_STATE_RELEASED);
845a46c0ec8Sopenharmony_ci		break;
846a46c0ec8Sopenharmony_ci	case TAP_EVENT_THUMB:
847a46c0ec8Sopenharmony_ci		break;
848a46c0ec8Sopenharmony_ci	case TAP_EVENT_PALM:
849a46c0ec8Sopenharmony_ci		tp_tap_notify(tp,
850a46c0ec8Sopenharmony_ci			      tp->tap.saved_release_time,
851a46c0ec8Sopenharmony_ci			      nfingers_tapped,
852a46c0ec8Sopenharmony_ci			      LIBINPUT_BUTTON_STATE_RELEASED);
853a46c0ec8Sopenharmony_ci		tp->tap.state = TAP_STATE_IDLE;
854a46c0ec8Sopenharmony_ci		break;
855a46c0ec8Sopenharmony_ci	case TAP_EVENT_PALM_UP:
856a46c0ec8Sopenharmony_ci		break;
857a46c0ec8Sopenharmony_ci	}
858a46c0ec8Sopenharmony_ci}
859a46c0ec8Sopenharmony_ci
860a46c0ec8Sopenharmony_cistatic void
861a46c0ec8Sopenharmony_citp_tap_dragging_wait_handle_event(struct tp_dispatch *tp,
862a46c0ec8Sopenharmony_ci				  struct tp_touch *t,
863a46c0ec8Sopenharmony_ci				  enum tap_event event, uint64_t time,
864a46c0ec8Sopenharmony_ci				  int nfingers_tapped)
865a46c0ec8Sopenharmony_ci{
866a46c0ec8Sopenharmony_ci
867a46c0ec8Sopenharmony_ci	switch (event) {
868a46c0ec8Sopenharmony_ci	case TAP_EVENT_TOUCH: {
869a46c0ec8Sopenharmony_ci		enum tp_tap_state dest[3] = {
870a46c0ec8Sopenharmony_ci			TAP_STATE_1FGTAP_DRAGGING_OR_TAP,
871a46c0ec8Sopenharmony_ci			TAP_STATE_2FGTAP_DRAGGING_OR_TAP,
872a46c0ec8Sopenharmony_ci			TAP_STATE_3FGTAP_DRAGGING_OR_TAP,
873a46c0ec8Sopenharmony_ci		};
874a46c0ec8Sopenharmony_ci		assert(nfingers_tapped >= 1 && nfingers_tapped <= 3);
875a46c0ec8Sopenharmony_ci		tp->tap.state = dest[nfingers_tapped - 1];
876a46c0ec8Sopenharmony_ci		tp_tap_set_timer(tp, time);
877a46c0ec8Sopenharmony_ci		break;
878a46c0ec8Sopenharmony_ci	}
879a46c0ec8Sopenharmony_ci	case TAP_EVENT_RELEASE:
880a46c0ec8Sopenharmony_ci	case TAP_EVENT_MOTION:
881a46c0ec8Sopenharmony_ci		log_tap_bug(tp, t, event);
882a46c0ec8Sopenharmony_ci		break;
883a46c0ec8Sopenharmony_ci	case TAP_EVENT_TIMEOUT:
884a46c0ec8Sopenharmony_ci		tp->tap.state = TAP_STATE_IDLE;
885a46c0ec8Sopenharmony_ci		tp_tap_notify(tp,
886a46c0ec8Sopenharmony_ci			      time,
887a46c0ec8Sopenharmony_ci			      nfingers_tapped,
888a46c0ec8Sopenharmony_ci			      LIBINPUT_BUTTON_STATE_RELEASED);
889a46c0ec8Sopenharmony_ci		break;
890a46c0ec8Sopenharmony_ci	case TAP_EVENT_BUTTON:
891a46c0ec8Sopenharmony_ci		tp->tap.state = TAP_STATE_DEAD;
892a46c0ec8Sopenharmony_ci		tp_tap_notify(tp,
893a46c0ec8Sopenharmony_ci			      time,
894a46c0ec8Sopenharmony_ci			      nfingers_tapped,
895a46c0ec8Sopenharmony_ci			      LIBINPUT_BUTTON_STATE_RELEASED);
896a46c0ec8Sopenharmony_ci		break;
897a46c0ec8Sopenharmony_ci	case TAP_EVENT_THUMB:
898a46c0ec8Sopenharmony_ci	case TAP_EVENT_PALM:
899a46c0ec8Sopenharmony_ci		log_tap_bug(tp, t, event);
900a46c0ec8Sopenharmony_ci		break;
901a46c0ec8Sopenharmony_ci	case TAP_EVENT_PALM_UP:
902a46c0ec8Sopenharmony_ci		break;
903a46c0ec8Sopenharmony_ci	}
904a46c0ec8Sopenharmony_ci}
905a46c0ec8Sopenharmony_ci
906a46c0ec8Sopenharmony_cistatic void
907a46c0ec8Sopenharmony_citp_tap_dragging_tap_handle_event(struct tp_dispatch *tp,
908a46c0ec8Sopenharmony_ci				 struct tp_touch *t,
909a46c0ec8Sopenharmony_ci				 enum tap_event event, uint64_t time,
910a46c0ec8Sopenharmony_ci				 int nfingers_tapped)
911a46c0ec8Sopenharmony_ci{
912a46c0ec8Sopenharmony_ci
913a46c0ec8Sopenharmony_ci	switch (event) {
914a46c0ec8Sopenharmony_ci	case TAP_EVENT_TOUCH: {
915a46c0ec8Sopenharmony_ci		tp_tap_notify(tp,
916a46c0ec8Sopenharmony_ci			      time,
917a46c0ec8Sopenharmony_ci			      nfingers_tapped,
918a46c0ec8Sopenharmony_ci			      LIBINPUT_BUTTON_STATE_RELEASED);
919a46c0ec8Sopenharmony_ci		tp_tap_clear_timer(tp);
920a46c0ec8Sopenharmony_ci		tp_tap_move_to_dead(tp, t);
921a46c0ec8Sopenharmony_ci		break;
922a46c0ec8Sopenharmony_ci	}
923a46c0ec8Sopenharmony_ci	case TAP_EVENT_RELEASE:
924a46c0ec8Sopenharmony_ci		tp->tap.state = TAP_STATE_IDLE;
925a46c0ec8Sopenharmony_ci		tp_tap_notify(tp,
926a46c0ec8Sopenharmony_ci			      time,
927a46c0ec8Sopenharmony_ci			      nfingers_tapped,
928a46c0ec8Sopenharmony_ci			      LIBINPUT_BUTTON_STATE_RELEASED);
929a46c0ec8Sopenharmony_ci		break;
930a46c0ec8Sopenharmony_ci	case TAP_EVENT_MOTION:
931a46c0ec8Sopenharmony_ci	case TAP_EVENT_TIMEOUT: {
932a46c0ec8Sopenharmony_ci		enum tp_tap_state dest[3] = {
933a46c0ec8Sopenharmony_ci			TAP_STATE_1FGTAP_DRAGGING,
934a46c0ec8Sopenharmony_ci			TAP_STATE_2FGTAP_DRAGGING,
935a46c0ec8Sopenharmony_ci			TAP_STATE_3FGTAP_DRAGGING,
936a46c0ec8Sopenharmony_ci		};
937a46c0ec8Sopenharmony_ci		assert(nfingers_tapped >= 1 && nfingers_tapped <= 3);
938a46c0ec8Sopenharmony_ci		tp->tap.state = dest[nfingers_tapped - 1];
939a46c0ec8Sopenharmony_ci		break;
940a46c0ec8Sopenharmony_ci	}
941a46c0ec8Sopenharmony_ci	case TAP_EVENT_BUTTON:
942a46c0ec8Sopenharmony_ci		tp->tap.state = TAP_STATE_DEAD;
943a46c0ec8Sopenharmony_ci		tp_tap_notify(tp,
944a46c0ec8Sopenharmony_ci			      time,
945a46c0ec8Sopenharmony_ci			      nfingers_tapped,
946a46c0ec8Sopenharmony_ci			      LIBINPUT_BUTTON_STATE_RELEASED);
947a46c0ec8Sopenharmony_ci		break;
948a46c0ec8Sopenharmony_ci	case TAP_EVENT_THUMB:
949a46c0ec8Sopenharmony_ci		break;
950a46c0ec8Sopenharmony_ci	case TAP_EVENT_PALM: {
951a46c0ec8Sopenharmony_ci		enum tp_tap_state dest[3] = {
952a46c0ec8Sopenharmony_ci			TAP_STATE_1FGTAP_DRAGGING_WAIT,
953a46c0ec8Sopenharmony_ci			TAP_STATE_2FGTAP_DRAGGING_WAIT,
954a46c0ec8Sopenharmony_ci			TAP_STATE_3FGTAP_DRAGGING_WAIT,
955a46c0ec8Sopenharmony_ci		};
956a46c0ec8Sopenharmony_ci		assert(nfingers_tapped >= 1 && nfingers_tapped <= 3);
957a46c0ec8Sopenharmony_ci		tp->tap.state = dest[nfingers_tapped - 1];
958a46c0ec8Sopenharmony_ci		break;
959a46c0ec8Sopenharmony_ci	}
960a46c0ec8Sopenharmony_ci	case TAP_EVENT_PALM_UP:
961a46c0ec8Sopenharmony_ci		break;
962a46c0ec8Sopenharmony_ci	}
963a46c0ec8Sopenharmony_ci}
964a46c0ec8Sopenharmony_ci
965a46c0ec8Sopenharmony_cistatic void
966a46c0ec8Sopenharmony_citp_tap_dragging2_handle_event(struct tp_dispatch *tp,
967a46c0ec8Sopenharmony_ci			      struct tp_touch *t,
968a46c0ec8Sopenharmony_ci			      enum tap_event event, uint64_t time,
969a46c0ec8Sopenharmony_ci			      int nfingers_tapped)
970a46c0ec8Sopenharmony_ci{
971a46c0ec8Sopenharmony_ci
972a46c0ec8Sopenharmony_ci	switch (event) {
973a46c0ec8Sopenharmony_ci	case TAP_EVENT_RELEASE: {
974a46c0ec8Sopenharmony_ci		enum tp_tap_state dest[3] = {
975a46c0ec8Sopenharmony_ci			TAP_STATE_1FGTAP_DRAGGING,
976a46c0ec8Sopenharmony_ci			TAP_STATE_2FGTAP_DRAGGING,
977a46c0ec8Sopenharmony_ci			TAP_STATE_3FGTAP_DRAGGING,
978a46c0ec8Sopenharmony_ci		};
979a46c0ec8Sopenharmony_ci		assert(nfingers_tapped >= 1 && nfingers_tapped <= 3);
980a46c0ec8Sopenharmony_ci		tp->tap.state = dest[nfingers_tapped - 1];
981a46c0ec8Sopenharmony_ci		break;
982a46c0ec8Sopenharmony_ci	}
983a46c0ec8Sopenharmony_ci	case TAP_EVENT_TOUCH:
984a46c0ec8Sopenharmony_ci		tp->tap.state = TAP_STATE_DEAD;
985a46c0ec8Sopenharmony_ci		tp_tap_notify(tp,
986a46c0ec8Sopenharmony_ci			      time,
987a46c0ec8Sopenharmony_ci			      nfingers_tapped,
988a46c0ec8Sopenharmony_ci			      LIBINPUT_BUTTON_STATE_RELEASED);
989a46c0ec8Sopenharmony_ci		break;
990a46c0ec8Sopenharmony_ci	case TAP_EVENT_MOTION:
991a46c0ec8Sopenharmony_ci	case TAP_EVENT_TIMEOUT:
992a46c0ec8Sopenharmony_ci		/* noop */
993a46c0ec8Sopenharmony_ci		break;
994a46c0ec8Sopenharmony_ci	case TAP_EVENT_BUTTON:
995a46c0ec8Sopenharmony_ci		tp->tap.state = TAP_STATE_DEAD;
996a46c0ec8Sopenharmony_ci		tp_tap_notify(tp,
997a46c0ec8Sopenharmony_ci			      time,
998a46c0ec8Sopenharmony_ci			      nfingers_tapped,
999a46c0ec8Sopenharmony_ci			      LIBINPUT_BUTTON_STATE_RELEASED);
1000a46c0ec8Sopenharmony_ci		break;
1001a46c0ec8Sopenharmony_ci	case TAP_EVENT_THUMB:
1002a46c0ec8Sopenharmony_ci		break;
1003a46c0ec8Sopenharmony_ci	case TAP_EVENT_PALM: {
1004a46c0ec8Sopenharmony_ci		enum tp_tap_state dest[3] = {
1005a46c0ec8Sopenharmony_ci			TAP_STATE_1FGTAP_DRAGGING,
1006a46c0ec8Sopenharmony_ci			TAP_STATE_2FGTAP_DRAGGING,
1007a46c0ec8Sopenharmony_ci			TAP_STATE_3FGTAP_DRAGGING,
1008a46c0ec8Sopenharmony_ci		};
1009a46c0ec8Sopenharmony_ci		assert(nfingers_tapped >= 1 && nfingers_tapped <= 3);
1010a46c0ec8Sopenharmony_ci		tp->tap.state = dest[nfingers_tapped - 1];
1011a46c0ec8Sopenharmony_ci		break;
1012a46c0ec8Sopenharmony_ci	}
1013a46c0ec8Sopenharmony_ci	case TAP_EVENT_PALM_UP:
1014a46c0ec8Sopenharmony_ci		break;
1015a46c0ec8Sopenharmony_ci	}
1016a46c0ec8Sopenharmony_ci}
1017a46c0ec8Sopenharmony_ci
1018a46c0ec8Sopenharmony_cistatic void
1019a46c0ec8Sopenharmony_citp_tap_dead_handle_event(struct tp_dispatch *tp,
1020a46c0ec8Sopenharmony_ci			 struct tp_touch *t,
1021a46c0ec8Sopenharmony_ci			 enum tap_event event,
1022a46c0ec8Sopenharmony_ci			 uint64_t time)
1023a46c0ec8Sopenharmony_ci{
1024a46c0ec8Sopenharmony_ci
1025a46c0ec8Sopenharmony_ci	switch (event) {
1026a46c0ec8Sopenharmony_ci	case TAP_EVENT_RELEASE:
1027a46c0ec8Sopenharmony_ci		if (tp->tap.nfingers_down == 0)
1028a46c0ec8Sopenharmony_ci			tp->tap.state = TAP_STATE_IDLE;
1029a46c0ec8Sopenharmony_ci		break;
1030a46c0ec8Sopenharmony_ci	case TAP_EVENT_TOUCH:
1031a46c0ec8Sopenharmony_ci	case TAP_EVENT_MOTION:
1032a46c0ec8Sopenharmony_ci	case TAP_EVENT_TIMEOUT:
1033a46c0ec8Sopenharmony_ci	case TAP_EVENT_BUTTON:
1034a46c0ec8Sopenharmony_ci		break;
1035a46c0ec8Sopenharmony_ci	case TAP_EVENT_THUMB:
1036a46c0ec8Sopenharmony_ci		break;
1037a46c0ec8Sopenharmony_ci	case TAP_EVENT_PALM:
1038a46c0ec8Sopenharmony_ci	case TAP_EVENT_PALM_UP:
1039a46c0ec8Sopenharmony_ci		if (tp->tap.nfingers_down == 0)
1040a46c0ec8Sopenharmony_ci			tp->tap.state = TAP_STATE_IDLE;
1041a46c0ec8Sopenharmony_ci		break;
1042a46c0ec8Sopenharmony_ci	}
1043a46c0ec8Sopenharmony_ci}
1044a46c0ec8Sopenharmony_ci
1045a46c0ec8Sopenharmony_cistatic void
1046a46c0ec8Sopenharmony_citp_tap_handle_event(struct tp_dispatch *tp,
1047a46c0ec8Sopenharmony_ci		    struct tp_touch *t,
1048a46c0ec8Sopenharmony_ci		    enum tap_event event,
1049a46c0ec8Sopenharmony_ci		    uint64_t time)
1050a46c0ec8Sopenharmony_ci{
1051a46c0ec8Sopenharmony_ci	enum tp_tap_state current;
1052a46c0ec8Sopenharmony_ci
1053a46c0ec8Sopenharmony_ci	current = tp->tap.state;
1054a46c0ec8Sopenharmony_ci
1055a46c0ec8Sopenharmony_ci	switch(tp->tap.state) {
1056a46c0ec8Sopenharmony_ci	case TAP_STATE_IDLE:
1057a46c0ec8Sopenharmony_ci		tp_tap_idle_handle_event(tp, t, event, time);
1058a46c0ec8Sopenharmony_ci		break;
1059a46c0ec8Sopenharmony_ci	case TAP_STATE_TOUCH:
1060a46c0ec8Sopenharmony_ci		tp_tap_touch_handle_event(tp, t, event, time);
1061a46c0ec8Sopenharmony_ci		break;
1062a46c0ec8Sopenharmony_ci	case TAP_STATE_HOLD:
1063a46c0ec8Sopenharmony_ci		tp_tap_hold_handle_event(tp, t, event, time);
1064a46c0ec8Sopenharmony_ci		break;
1065a46c0ec8Sopenharmony_ci	case TAP_STATE_1FGTAP_TAPPED:
1066a46c0ec8Sopenharmony_ci		tp_tap_tapped_handle_event(tp, t, event, time, 1);
1067a46c0ec8Sopenharmony_ci		break;
1068a46c0ec8Sopenharmony_ci	case TAP_STATE_2FGTAP_TAPPED:
1069a46c0ec8Sopenharmony_ci		tp_tap_tapped_handle_event(tp, t, event, time, 2);
1070a46c0ec8Sopenharmony_ci		break;
1071a46c0ec8Sopenharmony_ci	case TAP_STATE_3FGTAP_TAPPED:
1072a46c0ec8Sopenharmony_ci		tp_tap_tapped_handle_event(tp, t, event, time, 3);
1073a46c0ec8Sopenharmony_ci		break;
1074a46c0ec8Sopenharmony_ci	case TAP_STATE_TOUCH_2:
1075a46c0ec8Sopenharmony_ci		tp_tap_touch2_handle_event(tp, t, event, time);
1076a46c0ec8Sopenharmony_ci		break;
1077a46c0ec8Sopenharmony_ci	case TAP_STATE_TOUCH_2_HOLD:
1078a46c0ec8Sopenharmony_ci		tp_tap_touch2_hold_handle_event(tp, t, event, time);
1079a46c0ec8Sopenharmony_ci		break;
1080a46c0ec8Sopenharmony_ci	case TAP_STATE_TOUCH_2_RELEASE:
1081a46c0ec8Sopenharmony_ci		tp_tap_touch2_release_handle_event(tp, t, event, time);
1082a46c0ec8Sopenharmony_ci		break;
1083a46c0ec8Sopenharmony_ci	case TAP_STATE_TOUCH_3:
1084a46c0ec8Sopenharmony_ci		tp_tap_touch3_handle_event(tp, t, event, time);
1085a46c0ec8Sopenharmony_ci		break;
1086a46c0ec8Sopenharmony_ci	case TAP_STATE_TOUCH_3_HOLD:
1087a46c0ec8Sopenharmony_ci		tp_tap_touch3_hold_handle_event(tp, t, event, time);
1088a46c0ec8Sopenharmony_ci		break;
1089a46c0ec8Sopenharmony_ci	case TAP_STATE_TOUCH_3_RELEASE:
1090a46c0ec8Sopenharmony_ci		tp_tap_touch3_release_handle_event(tp, t, event, time);
1091a46c0ec8Sopenharmony_ci		break;
1092a46c0ec8Sopenharmony_ci	case TAP_STATE_TOUCH_3_RELEASE_2:
1093a46c0ec8Sopenharmony_ci		tp_tap_touch3_release2_handle_event(tp, t, event, time);
1094a46c0ec8Sopenharmony_ci		break;
1095a46c0ec8Sopenharmony_ci	case TAP_STATE_1FGTAP_DRAGGING_OR_DOUBLETAP:
1096a46c0ec8Sopenharmony_ci		tp_tap_dragging_or_doubletap_handle_event(tp, t, event, time,
1097a46c0ec8Sopenharmony_ci							  1);
1098a46c0ec8Sopenharmony_ci		break;
1099a46c0ec8Sopenharmony_ci	case TAP_STATE_2FGTAP_DRAGGING_OR_DOUBLETAP:
1100a46c0ec8Sopenharmony_ci		tp_tap_dragging_or_doubletap_handle_event(tp, t, event, time,
1101a46c0ec8Sopenharmony_ci							  2);
1102a46c0ec8Sopenharmony_ci		break;
1103a46c0ec8Sopenharmony_ci	case TAP_STATE_3FGTAP_DRAGGING_OR_DOUBLETAP:
1104a46c0ec8Sopenharmony_ci		tp_tap_dragging_or_doubletap_handle_event(tp, t, event, time,
1105a46c0ec8Sopenharmony_ci							  3);
1106a46c0ec8Sopenharmony_ci		break;
1107a46c0ec8Sopenharmony_ci	case TAP_STATE_1FGTAP_DRAGGING:
1108a46c0ec8Sopenharmony_ci		tp_tap_dragging_handle_event(tp, t, event, time, 1);
1109a46c0ec8Sopenharmony_ci		break;
1110a46c0ec8Sopenharmony_ci	case TAP_STATE_2FGTAP_DRAGGING:
1111a46c0ec8Sopenharmony_ci		tp_tap_dragging_handle_event(tp, t, event, time, 2);
1112a46c0ec8Sopenharmony_ci		break;
1113a46c0ec8Sopenharmony_ci	case TAP_STATE_3FGTAP_DRAGGING:
1114a46c0ec8Sopenharmony_ci		tp_tap_dragging_handle_event(tp, t, event, time, 3);
1115a46c0ec8Sopenharmony_ci		break;
1116a46c0ec8Sopenharmony_ci	case TAP_STATE_1FGTAP_DRAGGING_WAIT:
1117a46c0ec8Sopenharmony_ci		tp_tap_dragging_wait_handle_event(tp, t, event, time, 1);
1118a46c0ec8Sopenharmony_ci		break;
1119a46c0ec8Sopenharmony_ci	case TAP_STATE_2FGTAP_DRAGGING_WAIT:
1120a46c0ec8Sopenharmony_ci		tp_tap_dragging_wait_handle_event(tp, t, event, time, 2);
1121a46c0ec8Sopenharmony_ci		break;
1122a46c0ec8Sopenharmony_ci	case TAP_STATE_3FGTAP_DRAGGING_WAIT:
1123a46c0ec8Sopenharmony_ci		tp_tap_dragging_wait_handle_event(tp, t, event, time, 3);
1124a46c0ec8Sopenharmony_ci		break;
1125a46c0ec8Sopenharmony_ci	case TAP_STATE_1FGTAP_DRAGGING_OR_TAP:
1126a46c0ec8Sopenharmony_ci		tp_tap_dragging_tap_handle_event(tp, t, event, time, 1);
1127a46c0ec8Sopenharmony_ci		break;
1128a46c0ec8Sopenharmony_ci	case TAP_STATE_2FGTAP_DRAGGING_OR_TAP:
1129a46c0ec8Sopenharmony_ci		tp_tap_dragging_tap_handle_event(tp, t, event, time, 2);
1130a46c0ec8Sopenharmony_ci		break;
1131a46c0ec8Sopenharmony_ci	case TAP_STATE_3FGTAP_DRAGGING_OR_TAP:
1132a46c0ec8Sopenharmony_ci		tp_tap_dragging_tap_handle_event(tp, t, event, time, 3);
1133a46c0ec8Sopenharmony_ci		break;
1134a46c0ec8Sopenharmony_ci	case TAP_STATE_1FGTAP_DRAGGING_2:
1135a46c0ec8Sopenharmony_ci		tp_tap_dragging2_handle_event(tp, t, event, time, 1);
1136a46c0ec8Sopenharmony_ci		break;
1137a46c0ec8Sopenharmony_ci	case TAP_STATE_2FGTAP_DRAGGING_2:
1138a46c0ec8Sopenharmony_ci		tp_tap_dragging2_handle_event(tp, t, event, time, 2);
1139a46c0ec8Sopenharmony_ci		break;
1140a46c0ec8Sopenharmony_ci	case TAP_STATE_3FGTAP_DRAGGING_2:
1141a46c0ec8Sopenharmony_ci		tp_tap_dragging2_handle_event(tp, t, event, time, 3);
1142a46c0ec8Sopenharmony_ci		break;
1143a46c0ec8Sopenharmony_ci	case TAP_STATE_DEAD:
1144a46c0ec8Sopenharmony_ci		tp_tap_dead_handle_event(tp, t, event, time);
1145a46c0ec8Sopenharmony_ci		break;
1146a46c0ec8Sopenharmony_ci	}
1147a46c0ec8Sopenharmony_ci
1148a46c0ec8Sopenharmony_ci	if (tp->tap.state == TAP_STATE_IDLE || tp->tap.state == TAP_STATE_DEAD)
1149a46c0ec8Sopenharmony_ci		tp_tap_clear_timer(tp);
1150a46c0ec8Sopenharmony_ci
1151a46c0ec8Sopenharmony_ci	if (current != tp->tap.state)
1152a46c0ec8Sopenharmony_ci		evdev_log_debug(tp->device,
1153a46c0ec8Sopenharmony_ci			  "tap: touch %d (%s), tap state %s → %s → %s\n",
1154a46c0ec8Sopenharmony_ci			  t ? (int)t->index : -1,
1155a46c0ec8Sopenharmony_ci			  t ? touch_state_to_str(t->state) : "",
1156a46c0ec8Sopenharmony_ci			  tap_state_to_str(current),
1157a46c0ec8Sopenharmony_ci			  tap_event_to_str(event),
1158a46c0ec8Sopenharmony_ci			  tap_state_to_str(tp->tap.state));
1159a46c0ec8Sopenharmony_ci}
1160a46c0ec8Sopenharmony_ci
1161a46c0ec8Sopenharmony_cistatic bool
1162a46c0ec8Sopenharmony_citp_tap_exceeds_motion_threshold(struct tp_dispatch *tp,
1163a46c0ec8Sopenharmony_ci				struct tp_touch *t)
1164a46c0ec8Sopenharmony_ci{
1165a46c0ec8Sopenharmony_ci	struct phys_coords mm =
1166a46c0ec8Sopenharmony_ci		tp_phys_delta(tp, device_delta(t->point, t->tap.initial));
1167a46c0ec8Sopenharmony_ci
1168a46c0ec8Sopenharmony_ci	/* if we have more fingers down than slots, we know that synaptics
1169a46c0ec8Sopenharmony_ci	 * touchpads are likely to give us pointer jumps.
1170a46c0ec8Sopenharmony_ci	 * This triggers the movement threshold, making three-finger taps
1171a46c0ec8Sopenharmony_ci	 * less reliable (#101435)
1172a46c0ec8Sopenharmony_ci	 *
1173a46c0ec8Sopenharmony_ci	 * This uses the real nfingers_down, not the one for taps.
1174a46c0ec8Sopenharmony_ci	 */
1175a46c0ec8Sopenharmony_ci	if (tp->device->model_flags & EVDEV_MODEL_SYNAPTICS_SERIAL_TOUCHPAD &&
1176a46c0ec8Sopenharmony_ci	    (tp->nfingers_down > 2 || tp->old_nfingers_down > 2) &&
1177a46c0ec8Sopenharmony_ci	    (tp->nfingers_down > tp->num_slots ||
1178a46c0ec8Sopenharmony_ci	     tp->old_nfingers_down > tp->num_slots)) {
1179a46c0ec8Sopenharmony_ci		return false;
1180a46c0ec8Sopenharmony_ci	}
1181a46c0ec8Sopenharmony_ci
1182a46c0ec8Sopenharmony_ci	/* Semi-mt devices will give us large movements on finger release,
1183a46c0ec8Sopenharmony_ci	 * depending which touch is released. Make sure we ignore any
1184a46c0ec8Sopenharmony_ci	 * movement in the same frame as a finger change.
1185a46c0ec8Sopenharmony_ci	 */
1186a46c0ec8Sopenharmony_ci	if (tp->semi_mt && tp->nfingers_down != tp->old_nfingers_down)
1187a46c0ec8Sopenharmony_ci		return false;
1188a46c0ec8Sopenharmony_ci
1189a46c0ec8Sopenharmony_ci	return length_in_mm(mm) > DEFAULT_TAP_MOVE_THRESHOLD;
1190a46c0ec8Sopenharmony_ci}
1191a46c0ec8Sopenharmony_ci
1192a46c0ec8Sopenharmony_cistatic bool
1193a46c0ec8Sopenharmony_citp_tap_enabled(struct tp_dispatch *tp)
1194a46c0ec8Sopenharmony_ci{
1195a46c0ec8Sopenharmony_ci	return tp->tap.enabled && !tp->tap.suspended;
1196a46c0ec8Sopenharmony_ci}
1197a46c0ec8Sopenharmony_ci
1198a46c0ec8Sopenharmony_ciint
1199a46c0ec8Sopenharmony_citp_tap_handle_state(struct tp_dispatch *tp, uint64_t time)
1200a46c0ec8Sopenharmony_ci{
1201a46c0ec8Sopenharmony_ci	struct tp_touch *t;
1202a46c0ec8Sopenharmony_ci	int filter_motion = 0;
1203a46c0ec8Sopenharmony_ci
1204a46c0ec8Sopenharmony_ci	if (!tp_tap_enabled(tp))
1205a46c0ec8Sopenharmony_ci		return 0;
1206a46c0ec8Sopenharmony_ci
1207a46c0ec8Sopenharmony_ci	/* Handle queued button pressed events from clickpads. For touchpads
1208a46c0ec8Sopenharmony_ci	 * with separate physical buttons, ignore button pressed events so they
1209a46c0ec8Sopenharmony_ci	 * don't interfere with tapping. */
1210a46c0ec8Sopenharmony_ci	if (tp->buttons.is_clickpad && tp->queued & TOUCHPAD_EVENT_BUTTON_PRESS)
1211a46c0ec8Sopenharmony_ci		tp_tap_handle_event(tp, NULL, TAP_EVENT_BUTTON, time);
1212a46c0ec8Sopenharmony_ci
1213a46c0ec8Sopenharmony_ci	tp_for_each_touch(tp, t) {
1214a46c0ec8Sopenharmony_ci		if (!t->dirty || t->state == TOUCH_NONE)
1215a46c0ec8Sopenharmony_ci			continue;
1216a46c0ec8Sopenharmony_ci
1217a46c0ec8Sopenharmony_ci		if (tp->buttons.is_clickpad &&
1218a46c0ec8Sopenharmony_ci		    tp->queued & TOUCHPAD_EVENT_BUTTON_PRESS)
1219a46c0ec8Sopenharmony_ci			t->tap.state = TAP_TOUCH_STATE_DEAD;
1220a46c0ec8Sopenharmony_ci
1221a46c0ec8Sopenharmony_ci		/* If a touch was considered thumb for tapping once, we
1222a46c0ec8Sopenharmony_ci		 * ignore it for the rest of lifetime */
1223a46c0ec8Sopenharmony_ci		if (t->tap.is_thumb)
1224a46c0ec8Sopenharmony_ci			continue;
1225a46c0ec8Sopenharmony_ci
1226a46c0ec8Sopenharmony_ci		/* A palm tap needs to be properly released because we might
1227a46c0ec8Sopenharmony_ci		 * be who-knows-where in the state machine. Otherwise, we
1228a46c0ec8Sopenharmony_ci		 * ignore any event from it.
1229a46c0ec8Sopenharmony_ci		 */
1230a46c0ec8Sopenharmony_ci		if (t->tap.is_palm) {
1231a46c0ec8Sopenharmony_ci			if (t->state == TOUCH_END)
1232a46c0ec8Sopenharmony_ci				tp_tap_handle_event(tp,
1233a46c0ec8Sopenharmony_ci						    t,
1234a46c0ec8Sopenharmony_ci						    TAP_EVENT_PALM_UP,
1235a46c0ec8Sopenharmony_ci						    time);
1236a46c0ec8Sopenharmony_ci			continue;
1237a46c0ec8Sopenharmony_ci		}
1238a46c0ec8Sopenharmony_ci
1239a46c0ec8Sopenharmony_ci		if (t->state == TOUCH_HOVERING)
1240a46c0ec8Sopenharmony_ci			continue;
1241a46c0ec8Sopenharmony_ci
1242a46c0ec8Sopenharmony_ci		if (t->palm.state != PALM_NONE) {
1243a46c0ec8Sopenharmony_ci			assert(!t->tap.is_palm);
1244a46c0ec8Sopenharmony_ci			t->tap.is_palm = true;
1245a46c0ec8Sopenharmony_ci			t->tap.state = TAP_TOUCH_STATE_DEAD;
1246a46c0ec8Sopenharmony_ci			if (t->state != TOUCH_BEGIN) {
1247a46c0ec8Sopenharmony_ci				tp_tap_handle_event(tp, t, TAP_EVENT_PALM, time);
1248a46c0ec8Sopenharmony_ci				assert(tp->tap.nfingers_down > 0);
1249a46c0ec8Sopenharmony_ci				tp->tap.nfingers_down--;
1250a46c0ec8Sopenharmony_ci			}
1251a46c0ec8Sopenharmony_ci		} else if (t->state == TOUCH_BEGIN) {
1252a46c0ec8Sopenharmony_ci			/* The simple version: if a touch is a thumb on
1253a46c0ec8Sopenharmony_ci			 * begin we ignore it. All other thumb touches
1254a46c0ec8Sopenharmony_ci			 * follow the normal tap state for now */
1255a46c0ec8Sopenharmony_ci			if (tp_thumb_ignored_for_tap(tp, t)) {
1256a46c0ec8Sopenharmony_ci				t->tap.is_thumb = true;
1257a46c0ec8Sopenharmony_ci				continue;
1258a46c0ec8Sopenharmony_ci			}
1259a46c0ec8Sopenharmony_ci
1260a46c0ec8Sopenharmony_ci			t->tap.state = TAP_TOUCH_STATE_TOUCH;
1261a46c0ec8Sopenharmony_ci			t->tap.initial = t->point;
1262a46c0ec8Sopenharmony_ci			tp->tap.nfingers_down++;
1263a46c0ec8Sopenharmony_ci			tp_tap_handle_event(tp, t, TAP_EVENT_TOUCH, time);
1264a46c0ec8Sopenharmony_ci		} else if (t->state == TOUCH_END) {
1265a46c0ec8Sopenharmony_ci			if (t->was_down) {
1266a46c0ec8Sopenharmony_ci				assert(tp->tap.nfingers_down >= 1);
1267a46c0ec8Sopenharmony_ci				tp->tap.nfingers_down--;
1268a46c0ec8Sopenharmony_ci				tp_tap_handle_event(tp, t, TAP_EVENT_RELEASE, time);
1269a46c0ec8Sopenharmony_ci			}
1270a46c0ec8Sopenharmony_ci			t->tap.state = TAP_TOUCH_STATE_IDLE;
1271a46c0ec8Sopenharmony_ci		} else if (tp->tap.state != TAP_STATE_IDLE &&
1272a46c0ec8Sopenharmony_ci			   tp_thumb_ignored(tp, t)) {
1273a46c0ec8Sopenharmony_ci			tp_tap_handle_event(tp, t, TAP_EVENT_THUMB, time);
1274a46c0ec8Sopenharmony_ci		} else if (tp->tap.state != TAP_STATE_IDLE &&
1275a46c0ec8Sopenharmony_ci			   tp_tap_exceeds_motion_threshold(tp, t)) {
1276a46c0ec8Sopenharmony_ci			struct tp_touch *tmp;
1277a46c0ec8Sopenharmony_ci
1278a46c0ec8Sopenharmony_ci			/* Any touch exceeding the threshold turns all
1279a46c0ec8Sopenharmony_ci			 * touches into DEAD */
1280a46c0ec8Sopenharmony_ci			tp_for_each_touch(tp, tmp) {
1281a46c0ec8Sopenharmony_ci				if (tmp->tap.state == TAP_TOUCH_STATE_TOUCH)
1282a46c0ec8Sopenharmony_ci					tmp->tap.state = TAP_TOUCH_STATE_DEAD;
1283a46c0ec8Sopenharmony_ci			}
1284a46c0ec8Sopenharmony_ci
1285a46c0ec8Sopenharmony_ci			tp_tap_handle_event(tp, t, TAP_EVENT_MOTION, time);
1286a46c0ec8Sopenharmony_ci		}
1287a46c0ec8Sopenharmony_ci	}
1288a46c0ec8Sopenharmony_ci
1289a46c0ec8Sopenharmony_ci	/**
1290a46c0ec8Sopenharmony_ci	 * In any state where motion exceeding the move threshold would
1291a46c0ec8Sopenharmony_ci	 * move to the next state, filter that motion until we actually
1292a46c0ec8Sopenharmony_ci	 * exceed it. This prevents small motion events while we're waiting
1293a46c0ec8Sopenharmony_ci	 * on a decision if a tap is a tap.
1294a46c0ec8Sopenharmony_ci	 */
1295a46c0ec8Sopenharmony_ci	switch (tp->tap.state) {
1296a46c0ec8Sopenharmony_ci	case TAP_STATE_TOUCH:
1297a46c0ec8Sopenharmony_ci	case TAP_STATE_1FGTAP_TAPPED:
1298a46c0ec8Sopenharmony_ci	case TAP_STATE_2FGTAP_TAPPED:
1299a46c0ec8Sopenharmony_ci	case TAP_STATE_3FGTAP_TAPPED:
1300a46c0ec8Sopenharmony_ci	case TAP_STATE_1FGTAP_DRAGGING_OR_DOUBLETAP:
1301a46c0ec8Sopenharmony_ci	case TAP_STATE_2FGTAP_DRAGGING_OR_DOUBLETAP:
1302a46c0ec8Sopenharmony_ci	case TAP_STATE_3FGTAP_DRAGGING_OR_DOUBLETAP:
1303a46c0ec8Sopenharmony_ci	case TAP_STATE_1FGTAP_DRAGGING_OR_TAP:
1304a46c0ec8Sopenharmony_ci	case TAP_STATE_2FGTAP_DRAGGING_OR_TAP:
1305a46c0ec8Sopenharmony_ci	case TAP_STATE_3FGTAP_DRAGGING_OR_TAP:
1306a46c0ec8Sopenharmony_ci	case TAP_STATE_TOUCH_2:
1307a46c0ec8Sopenharmony_ci	case TAP_STATE_TOUCH_3:
1308a46c0ec8Sopenharmony_ci		filter_motion = 1;
1309a46c0ec8Sopenharmony_ci		break;
1310a46c0ec8Sopenharmony_ci
1311a46c0ec8Sopenharmony_ci	default:
1312a46c0ec8Sopenharmony_ci		break;
1313a46c0ec8Sopenharmony_ci
1314a46c0ec8Sopenharmony_ci	}
1315a46c0ec8Sopenharmony_ci
1316a46c0ec8Sopenharmony_ci	assert(tp->tap.nfingers_down <= tp->nfingers_down);
1317a46c0ec8Sopenharmony_ci	if (tp->nfingers_down == 0)
1318a46c0ec8Sopenharmony_ci		assert(tp->tap.nfingers_down == 0);
1319a46c0ec8Sopenharmony_ci
1320a46c0ec8Sopenharmony_ci	return filter_motion;
1321a46c0ec8Sopenharmony_ci}
1322a46c0ec8Sopenharmony_ci
1323a46c0ec8Sopenharmony_cistatic inline void
1324a46c0ec8Sopenharmony_citp_tap_update_map(struct tp_dispatch *tp)
1325a46c0ec8Sopenharmony_ci{
1326a46c0ec8Sopenharmony_ci	if (tp->tap.state != TAP_STATE_IDLE)
1327a46c0ec8Sopenharmony_ci		return;
1328a46c0ec8Sopenharmony_ci
1329a46c0ec8Sopenharmony_ci	if (tp->tap.map != tp->tap.want_map)
1330a46c0ec8Sopenharmony_ci		tp->tap.map = tp->tap.want_map;
1331a46c0ec8Sopenharmony_ci}
1332a46c0ec8Sopenharmony_ci
1333a46c0ec8Sopenharmony_civoid
1334a46c0ec8Sopenharmony_citp_tap_post_process_state(struct tp_dispatch *tp)
1335a46c0ec8Sopenharmony_ci{
1336a46c0ec8Sopenharmony_ci	tp_tap_update_map(tp);
1337a46c0ec8Sopenharmony_ci}
1338a46c0ec8Sopenharmony_ci
1339a46c0ec8Sopenharmony_cistatic void
1340a46c0ec8Sopenharmony_citp_tap_handle_timeout(uint64_t time, void *data)
1341a46c0ec8Sopenharmony_ci{
1342a46c0ec8Sopenharmony_ci	struct tp_dispatch *tp = data;
1343a46c0ec8Sopenharmony_ci	struct tp_touch *t;
1344a46c0ec8Sopenharmony_ci
1345a46c0ec8Sopenharmony_ci	tp_tap_handle_event(tp, NULL, TAP_EVENT_TIMEOUT, time);
1346a46c0ec8Sopenharmony_ci
1347a46c0ec8Sopenharmony_ci	tp_for_each_touch(tp, t) {
1348a46c0ec8Sopenharmony_ci		if (t->state == TOUCH_NONE ||
1349a46c0ec8Sopenharmony_ci		    t->tap.state == TAP_TOUCH_STATE_IDLE)
1350a46c0ec8Sopenharmony_ci			continue;
1351a46c0ec8Sopenharmony_ci
1352a46c0ec8Sopenharmony_ci		t->tap.state = TAP_TOUCH_STATE_DEAD;
1353a46c0ec8Sopenharmony_ci	}
1354a46c0ec8Sopenharmony_ci}
1355a46c0ec8Sopenharmony_ci
1356a46c0ec8Sopenharmony_cistatic void
1357a46c0ec8Sopenharmony_citp_tap_enabled_update(struct tp_dispatch *tp, bool suspended, bool enabled, uint64_t time)
1358a46c0ec8Sopenharmony_ci{
1359a46c0ec8Sopenharmony_ci	bool was_enabled = tp_tap_enabled(tp);
1360a46c0ec8Sopenharmony_ci
1361a46c0ec8Sopenharmony_ci	tp->tap.suspended = suspended;
1362a46c0ec8Sopenharmony_ci	tp->tap.enabled = enabled;
1363a46c0ec8Sopenharmony_ci
1364a46c0ec8Sopenharmony_ci	if (tp_tap_enabled(tp) == was_enabled)
1365a46c0ec8Sopenharmony_ci		return;
1366a46c0ec8Sopenharmony_ci
1367a46c0ec8Sopenharmony_ci	if (tp_tap_enabled(tp)) {
1368a46c0ec8Sopenharmony_ci		struct tp_touch *t;
1369a46c0ec8Sopenharmony_ci
1370a46c0ec8Sopenharmony_ci		/* On resume, all touches are considered palms */
1371a46c0ec8Sopenharmony_ci		tp_for_each_touch(tp, t) {
1372a46c0ec8Sopenharmony_ci			if (t->state == TOUCH_NONE)
1373a46c0ec8Sopenharmony_ci				continue;
1374a46c0ec8Sopenharmony_ci
1375a46c0ec8Sopenharmony_ci			t->tap.is_palm = true;
1376a46c0ec8Sopenharmony_ci			t->tap.state = TAP_TOUCH_STATE_DEAD;
1377a46c0ec8Sopenharmony_ci		}
1378a46c0ec8Sopenharmony_ci
1379a46c0ec8Sopenharmony_ci		tp->tap.state = TAP_STATE_IDLE;
1380a46c0ec8Sopenharmony_ci		tp->tap.nfingers_down = 0;
1381a46c0ec8Sopenharmony_ci	} else {
1382a46c0ec8Sopenharmony_ci		tp_release_all_taps(tp, time);
1383a46c0ec8Sopenharmony_ci	}
1384a46c0ec8Sopenharmony_ci}
1385a46c0ec8Sopenharmony_ci
1386a46c0ec8Sopenharmony_cistatic int
1387a46c0ec8Sopenharmony_citp_tap_config_count(struct libinput_device *device)
1388a46c0ec8Sopenharmony_ci{
1389a46c0ec8Sopenharmony_ci	struct evdev_dispatch *dispatch = evdev_device(device)->dispatch;
1390a46c0ec8Sopenharmony_ci	struct tp_dispatch *tp = tp_dispatch(dispatch);
1391a46c0ec8Sopenharmony_ci
1392a46c0ec8Sopenharmony_ci	return min(tp->ntouches, 3U); /* we only do up to 3 finger tap */
1393a46c0ec8Sopenharmony_ci}
1394a46c0ec8Sopenharmony_ci
1395a46c0ec8Sopenharmony_cistatic enum libinput_config_status
1396a46c0ec8Sopenharmony_citp_tap_config_set_enabled(struct libinput_device *device,
1397a46c0ec8Sopenharmony_ci			  enum libinput_config_tap_state enabled)
1398a46c0ec8Sopenharmony_ci{
1399a46c0ec8Sopenharmony_ci	struct evdev_dispatch *dispatch = evdev_device(device)->dispatch;
1400a46c0ec8Sopenharmony_ci	struct tp_dispatch *tp = tp_dispatch(dispatch);
1401a46c0ec8Sopenharmony_ci
1402a46c0ec8Sopenharmony_ci	tp_tap_enabled_update(tp, tp->tap.suspended,
1403a46c0ec8Sopenharmony_ci			      (enabled == LIBINPUT_CONFIG_TAP_ENABLED),
1404a46c0ec8Sopenharmony_ci			      libinput_now(device->seat->libinput));
1405a46c0ec8Sopenharmony_ci
1406a46c0ec8Sopenharmony_ci	return LIBINPUT_CONFIG_STATUS_SUCCESS;
1407a46c0ec8Sopenharmony_ci}
1408a46c0ec8Sopenharmony_ci
1409a46c0ec8Sopenharmony_cistatic enum libinput_config_tap_state
1410a46c0ec8Sopenharmony_citp_tap_config_is_enabled(struct libinput_device *device)
1411a46c0ec8Sopenharmony_ci{
1412a46c0ec8Sopenharmony_ci	struct evdev_dispatch *dispatch = evdev_device(device)->dispatch;
1413a46c0ec8Sopenharmony_ci	struct tp_dispatch *tp = tp_dispatch(dispatch);
1414a46c0ec8Sopenharmony_ci
1415a46c0ec8Sopenharmony_ci	return tp->tap.enabled ? LIBINPUT_CONFIG_TAP_ENABLED :
1416a46c0ec8Sopenharmony_ci				 LIBINPUT_CONFIG_TAP_DISABLED;
1417a46c0ec8Sopenharmony_ci}
1418a46c0ec8Sopenharmony_ci
1419a46c0ec8Sopenharmony_cistatic enum libinput_config_tap_state
1420a46c0ec8Sopenharmony_citp_tap_default(struct evdev_device *evdev)
1421a46c0ec8Sopenharmony_ci{
1422a46c0ec8Sopenharmony_ci	/**
1423a46c0ec8Sopenharmony_ci	 * If we don't have a left button we must have tapping enabled by
1424a46c0ec8Sopenharmony_ci	 * default.
1425a46c0ec8Sopenharmony_ci	 */
1426a46c0ec8Sopenharmony_ci	if (!libevdev_has_event_code(evdev->evdev, EV_KEY, BTN_LEFT))
1427a46c0ec8Sopenharmony_ci		return LIBINPUT_CONFIG_TAP_ENABLED;
1428a46c0ec8Sopenharmony_ci
1429a46c0ec8Sopenharmony_ci	/**
1430a46c0ec8Sopenharmony_ci	 * Tapping is disabled by default for two reasons:
1431a46c0ec8Sopenharmony_ci	 * * if you don't know that tapping is a thing (or enabled by
1432a46c0ec8Sopenharmony_ci	 *   default), you get spurious mouse events that make the desktop
1433a46c0ec8Sopenharmony_ci	 *   feel buggy.
1434a46c0ec8Sopenharmony_ci	 * * if you do know what tapping is and you want it, you
1435a46c0ec8Sopenharmony_ci	 *   usually know where to enable it, or at least you can search for
1436a46c0ec8Sopenharmony_ci	 *   it.
1437a46c0ec8Sopenharmony_ci	 */
1438a46c0ec8Sopenharmony_ci	return LIBINPUT_CONFIG_TAP_DISABLED;
1439a46c0ec8Sopenharmony_ci}
1440a46c0ec8Sopenharmony_ci
1441a46c0ec8Sopenharmony_cistatic enum libinput_config_tap_state
1442a46c0ec8Sopenharmony_citp_tap_config_get_default(struct libinput_device *device)
1443a46c0ec8Sopenharmony_ci{
1444a46c0ec8Sopenharmony_ci	struct evdev_device *evdev = evdev_device(device);
1445a46c0ec8Sopenharmony_ci
1446a46c0ec8Sopenharmony_ci	return tp_tap_default(evdev);
1447a46c0ec8Sopenharmony_ci}
1448a46c0ec8Sopenharmony_ci
1449a46c0ec8Sopenharmony_cistatic enum libinput_config_status
1450a46c0ec8Sopenharmony_citp_tap_config_set_map(struct libinput_device *device,
1451a46c0ec8Sopenharmony_ci		      enum libinput_config_tap_button_map map)
1452a46c0ec8Sopenharmony_ci{
1453a46c0ec8Sopenharmony_ci	struct evdev_dispatch *dispatch = evdev_device(device)->dispatch;
1454a46c0ec8Sopenharmony_ci	struct tp_dispatch *tp = tp_dispatch(dispatch);
1455a46c0ec8Sopenharmony_ci
1456a46c0ec8Sopenharmony_ci	tp->tap.want_map = map;
1457a46c0ec8Sopenharmony_ci
1458a46c0ec8Sopenharmony_ci	tp_tap_update_map(tp);
1459a46c0ec8Sopenharmony_ci
1460a46c0ec8Sopenharmony_ci	return LIBINPUT_CONFIG_STATUS_SUCCESS;
1461a46c0ec8Sopenharmony_ci}
1462a46c0ec8Sopenharmony_ci
1463a46c0ec8Sopenharmony_cistatic enum libinput_config_tap_button_map
1464a46c0ec8Sopenharmony_citp_tap_config_get_map(struct libinput_device *device)
1465a46c0ec8Sopenharmony_ci{
1466a46c0ec8Sopenharmony_ci	struct evdev_dispatch *dispatch = evdev_device(device)->dispatch;
1467a46c0ec8Sopenharmony_ci	struct tp_dispatch *tp = tp_dispatch(dispatch);
1468a46c0ec8Sopenharmony_ci
1469a46c0ec8Sopenharmony_ci	return tp->tap.want_map;
1470a46c0ec8Sopenharmony_ci}
1471a46c0ec8Sopenharmony_ci
1472a46c0ec8Sopenharmony_cistatic enum libinput_config_tap_button_map
1473a46c0ec8Sopenharmony_citp_tap_config_get_default_map(struct libinput_device *device)
1474a46c0ec8Sopenharmony_ci{
1475a46c0ec8Sopenharmony_ci	return LIBINPUT_CONFIG_TAP_MAP_LRM;
1476a46c0ec8Sopenharmony_ci}
1477a46c0ec8Sopenharmony_ci
1478a46c0ec8Sopenharmony_cistatic enum libinput_config_status
1479a46c0ec8Sopenharmony_citp_tap_config_set_drag_enabled(struct libinput_device *device,
1480a46c0ec8Sopenharmony_ci			       enum libinput_config_drag_state enabled)
1481a46c0ec8Sopenharmony_ci{
1482a46c0ec8Sopenharmony_ci	struct evdev_dispatch *dispatch = evdev_device(device)->dispatch;
1483a46c0ec8Sopenharmony_ci	struct tp_dispatch *tp = tp_dispatch(dispatch);
1484a46c0ec8Sopenharmony_ci
1485a46c0ec8Sopenharmony_ci	tp->tap.drag_enabled = enabled;
1486a46c0ec8Sopenharmony_ci
1487a46c0ec8Sopenharmony_ci	return LIBINPUT_CONFIG_STATUS_SUCCESS;
1488a46c0ec8Sopenharmony_ci}
1489a46c0ec8Sopenharmony_ci
1490a46c0ec8Sopenharmony_cistatic enum libinput_config_drag_state
1491a46c0ec8Sopenharmony_citp_tap_config_get_drag_enabled(struct libinput_device *device)
1492a46c0ec8Sopenharmony_ci{
1493a46c0ec8Sopenharmony_ci	struct evdev_dispatch *dispatch = evdev_device(device)->dispatch;
1494a46c0ec8Sopenharmony_ci	struct tp_dispatch *tp = tp_dispatch(dispatch);
1495a46c0ec8Sopenharmony_ci
1496a46c0ec8Sopenharmony_ci	return tp->tap.drag_enabled;
1497a46c0ec8Sopenharmony_ci}
1498a46c0ec8Sopenharmony_ci
1499a46c0ec8Sopenharmony_cistatic inline enum libinput_config_drag_state
1500a46c0ec8Sopenharmony_citp_drag_default(struct evdev_device *device)
1501a46c0ec8Sopenharmony_ci{
1502a46c0ec8Sopenharmony_ci	return LIBINPUT_CONFIG_DRAG_ENABLED;
1503a46c0ec8Sopenharmony_ci}
1504a46c0ec8Sopenharmony_ci
1505a46c0ec8Sopenharmony_cistatic enum libinput_config_drag_state
1506a46c0ec8Sopenharmony_citp_tap_config_get_default_drag_enabled(struct libinput_device *device)
1507a46c0ec8Sopenharmony_ci{
1508a46c0ec8Sopenharmony_ci	struct evdev_device *evdev = evdev_device(device);
1509a46c0ec8Sopenharmony_ci
1510a46c0ec8Sopenharmony_ci	return tp_drag_default(evdev);
1511a46c0ec8Sopenharmony_ci}
1512a46c0ec8Sopenharmony_ci
1513a46c0ec8Sopenharmony_cistatic enum libinput_config_status
1514a46c0ec8Sopenharmony_citp_tap_config_set_draglock_enabled(struct libinput_device *device,
1515a46c0ec8Sopenharmony_ci				   enum libinput_config_drag_lock_state enabled)
1516a46c0ec8Sopenharmony_ci{
1517a46c0ec8Sopenharmony_ci	struct evdev_dispatch *dispatch = evdev_device(device)->dispatch;
1518a46c0ec8Sopenharmony_ci	struct tp_dispatch *tp = tp_dispatch(dispatch);
1519a46c0ec8Sopenharmony_ci
1520a46c0ec8Sopenharmony_ci	tp->tap.drag_lock_enabled = enabled;
1521a46c0ec8Sopenharmony_ci
1522a46c0ec8Sopenharmony_ci	return LIBINPUT_CONFIG_STATUS_SUCCESS;
1523a46c0ec8Sopenharmony_ci}
1524a46c0ec8Sopenharmony_ci
1525a46c0ec8Sopenharmony_cistatic enum libinput_config_drag_lock_state
1526a46c0ec8Sopenharmony_citp_tap_config_get_draglock_enabled(struct libinput_device *device)
1527a46c0ec8Sopenharmony_ci{
1528a46c0ec8Sopenharmony_ci	struct evdev_dispatch *dispatch = evdev_device(device)->dispatch;
1529a46c0ec8Sopenharmony_ci	struct tp_dispatch *tp = tp_dispatch(dispatch);
1530a46c0ec8Sopenharmony_ci
1531a46c0ec8Sopenharmony_ci	return tp->tap.drag_lock_enabled;
1532a46c0ec8Sopenharmony_ci}
1533a46c0ec8Sopenharmony_ci
1534a46c0ec8Sopenharmony_cistatic inline enum libinput_config_drag_lock_state
1535a46c0ec8Sopenharmony_citp_drag_lock_default(struct evdev_device *device)
1536a46c0ec8Sopenharmony_ci{
1537a46c0ec8Sopenharmony_ci	return LIBINPUT_CONFIG_DRAG_LOCK_DISABLED;
1538a46c0ec8Sopenharmony_ci}
1539a46c0ec8Sopenharmony_ci
1540a46c0ec8Sopenharmony_cistatic enum libinput_config_drag_lock_state
1541a46c0ec8Sopenharmony_citp_tap_config_get_default_draglock_enabled(struct libinput_device *device)
1542a46c0ec8Sopenharmony_ci{
1543a46c0ec8Sopenharmony_ci	struct evdev_device *evdev = evdev_device(device);
1544a46c0ec8Sopenharmony_ci
1545a46c0ec8Sopenharmony_ci	return tp_drag_lock_default(evdev);
1546a46c0ec8Sopenharmony_ci}
1547a46c0ec8Sopenharmony_ci
1548a46c0ec8Sopenharmony_civoid
1549a46c0ec8Sopenharmony_citp_init_tap(struct tp_dispatch *tp)
1550a46c0ec8Sopenharmony_ci{
1551a46c0ec8Sopenharmony_ci	char timer_name[64];
1552a46c0ec8Sopenharmony_ci
1553a46c0ec8Sopenharmony_ci	tp->tap.config.count = tp_tap_config_count;
1554a46c0ec8Sopenharmony_ci	tp->tap.config.set_enabled = tp_tap_config_set_enabled;
1555a46c0ec8Sopenharmony_ci	tp->tap.config.get_enabled = tp_tap_config_is_enabled;
1556a46c0ec8Sopenharmony_ci	tp->tap.config.get_default = tp_tap_config_get_default;
1557a46c0ec8Sopenharmony_ci	tp->tap.config.set_map = tp_tap_config_set_map;
1558a46c0ec8Sopenharmony_ci	tp->tap.config.get_map = tp_tap_config_get_map;
1559a46c0ec8Sopenharmony_ci	tp->tap.config.get_default_map = tp_tap_config_get_default_map;
1560a46c0ec8Sopenharmony_ci	tp->tap.config.set_drag_enabled = tp_tap_config_set_drag_enabled;
1561a46c0ec8Sopenharmony_ci	tp->tap.config.get_drag_enabled = tp_tap_config_get_drag_enabled;
1562a46c0ec8Sopenharmony_ci	tp->tap.config.get_default_drag_enabled = tp_tap_config_get_default_drag_enabled;
1563a46c0ec8Sopenharmony_ci	tp->tap.config.set_draglock_enabled = tp_tap_config_set_draglock_enabled;
1564a46c0ec8Sopenharmony_ci	tp->tap.config.get_draglock_enabled = tp_tap_config_get_draglock_enabled;
1565a46c0ec8Sopenharmony_ci	tp->tap.config.get_default_draglock_enabled = tp_tap_config_get_default_draglock_enabled;
1566a46c0ec8Sopenharmony_ci	tp->device->base.config.tap = &tp->tap.config;
1567a46c0ec8Sopenharmony_ci
1568a46c0ec8Sopenharmony_ci	tp->tap.state = TAP_STATE_IDLE;
1569a46c0ec8Sopenharmony_ci	tp->tap.enabled = tp_tap_default(tp->device);
1570a46c0ec8Sopenharmony_ci	tp->tap.map = LIBINPUT_CONFIG_TAP_MAP_LRM;
1571a46c0ec8Sopenharmony_ci	tp->tap.want_map = tp->tap.map;
1572a46c0ec8Sopenharmony_ci	tp->tap.drag_enabled = tp_drag_default(tp->device);
1573a46c0ec8Sopenharmony_ci	tp->tap.drag_lock_enabled = tp_drag_lock_default(tp->device);
1574a46c0ec8Sopenharmony_ci
1575a46c0ec8Sopenharmony_ci	snprintf(timer_name,
1576a46c0ec8Sopenharmony_ci		 sizeof(timer_name),
1577a46c0ec8Sopenharmony_ci		 "%s tap",
1578a46c0ec8Sopenharmony_ci		 evdev_device_get_sysname(tp->device));
1579a46c0ec8Sopenharmony_ci	libinput_timer_init(&tp->tap.timer,
1580a46c0ec8Sopenharmony_ci			    tp_libinput_context(tp),
1581a46c0ec8Sopenharmony_ci			    timer_name,
1582a46c0ec8Sopenharmony_ci			    tp_tap_handle_timeout, tp);
1583a46c0ec8Sopenharmony_ci}
1584a46c0ec8Sopenharmony_ci
1585a46c0ec8Sopenharmony_civoid
1586a46c0ec8Sopenharmony_citp_remove_tap(struct tp_dispatch *tp)
1587a46c0ec8Sopenharmony_ci{
1588a46c0ec8Sopenharmony_ci	libinput_timer_cancel(&tp->tap.timer);
1589a46c0ec8Sopenharmony_ci}
1590a46c0ec8Sopenharmony_ci
1591a46c0ec8Sopenharmony_civoid
1592a46c0ec8Sopenharmony_citp_release_all_taps(struct tp_dispatch *tp, uint64_t now)
1593a46c0ec8Sopenharmony_ci{
1594a46c0ec8Sopenharmony_ci	struct tp_touch *t;
1595a46c0ec8Sopenharmony_ci	int i;
1596a46c0ec8Sopenharmony_ci
1597a46c0ec8Sopenharmony_ci	for (i = 1; i <= 3; i++) {
1598a46c0ec8Sopenharmony_ci		if (tp->tap.buttons_pressed & bit(i))
1599a46c0ec8Sopenharmony_ci			tp_tap_notify(tp, now, i, LIBINPUT_BUTTON_STATE_RELEASED);
1600a46c0ec8Sopenharmony_ci	}
1601a46c0ec8Sopenharmony_ci
1602a46c0ec8Sopenharmony_ci	/* To neutralize all current touches, we make them all palms */
1603a46c0ec8Sopenharmony_ci	tp_for_each_touch(tp, t) {
1604a46c0ec8Sopenharmony_ci		if (t->state == TOUCH_NONE)
1605a46c0ec8Sopenharmony_ci			continue;
1606a46c0ec8Sopenharmony_ci
1607a46c0ec8Sopenharmony_ci		if (t->tap.is_palm)
1608a46c0ec8Sopenharmony_ci			continue;
1609a46c0ec8Sopenharmony_ci
1610a46c0ec8Sopenharmony_ci		t->tap.is_palm = true;
1611a46c0ec8Sopenharmony_ci		t->tap.state = TAP_TOUCH_STATE_DEAD;
1612a46c0ec8Sopenharmony_ci	}
1613a46c0ec8Sopenharmony_ci
1614a46c0ec8Sopenharmony_ci	tp->tap.state = TAP_STATE_IDLE;
1615a46c0ec8Sopenharmony_ci	tp->tap.nfingers_down = 0;
1616a46c0ec8Sopenharmony_ci}
1617a46c0ec8Sopenharmony_ci
1618a46c0ec8Sopenharmony_civoid
1619a46c0ec8Sopenharmony_citp_tap_suspend(struct tp_dispatch *tp, uint64_t time)
1620a46c0ec8Sopenharmony_ci{
1621a46c0ec8Sopenharmony_ci	tp_tap_enabled_update(tp, true, tp->tap.enabled, time);
1622a46c0ec8Sopenharmony_ci}
1623a46c0ec8Sopenharmony_ci
1624a46c0ec8Sopenharmony_civoid
1625a46c0ec8Sopenharmony_citp_tap_resume(struct tp_dispatch *tp, uint64_t time)
1626a46c0ec8Sopenharmony_ci{
1627a46c0ec8Sopenharmony_ci	tp_tap_enabled_update(tp, false, tp->tap.enabled, time);
1628a46c0ec8Sopenharmony_ci}
1629a46c0ec8Sopenharmony_ci
1630a46c0ec8Sopenharmony_cibool
1631a46c0ec8Sopenharmony_citp_tap_dragging(const struct tp_dispatch *tp)
1632a46c0ec8Sopenharmony_ci{
1633a46c0ec8Sopenharmony_ci	switch (tp->tap.state) {
1634a46c0ec8Sopenharmony_ci	case TAP_STATE_1FGTAP_DRAGGING:
1635a46c0ec8Sopenharmony_ci	case TAP_STATE_2FGTAP_DRAGGING:
1636a46c0ec8Sopenharmony_ci	case TAP_STATE_3FGTAP_DRAGGING:
1637a46c0ec8Sopenharmony_ci	case TAP_STATE_1FGTAP_DRAGGING_2:
1638a46c0ec8Sopenharmony_ci	case TAP_STATE_2FGTAP_DRAGGING_2:
1639a46c0ec8Sopenharmony_ci	case TAP_STATE_3FGTAP_DRAGGING_2:
1640a46c0ec8Sopenharmony_ci	case TAP_STATE_1FGTAP_DRAGGING_WAIT:
1641a46c0ec8Sopenharmony_ci	case TAP_STATE_2FGTAP_DRAGGING_WAIT:
1642a46c0ec8Sopenharmony_ci	case TAP_STATE_3FGTAP_DRAGGING_WAIT:
1643a46c0ec8Sopenharmony_ci	case TAP_STATE_1FGTAP_DRAGGING_OR_TAP:
1644a46c0ec8Sopenharmony_ci	case TAP_STATE_2FGTAP_DRAGGING_OR_TAP:
1645a46c0ec8Sopenharmony_ci	case TAP_STATE_3FGTAP_DRAGGING_OR_TAP:
1646a46c0ec8Sopenharmony_ci		return true;
1647a46c0ec8Sopenharmony_ci	default:
1648a46c0ec8Sopenharmony_ci		return false;
1649a46c0ec8Sopenharmony_ci	}
1650a46c0ec8Sopenharmony_ci}
1651a46c0ec8Sopenharmony_ci
1652a46c0ec8Sopenharmony_cibool
1653a46c0ec8Sopenharmony_citp_tap_dragging_or_double_tapping(const struct tp_dispatch *tp)
1654a46c0ec8Sopenharmony_ci{
1655a46c0ec8Sopenharmony_ci	switch (tp->tap.state) {
1656a46c0ec8Sopenharmony_ci	case TAP_STATE_1FGTAP_DRAGGING_OR_DOUBLETAP:
1657a46c0ec8Sopenharmony_ci	case TAP_STATE_2FGTAP_DRAGGING_OR_DOUBLETAP:
1658a46c0ec8Sopenharmony_ci	case TAP_STATE_3FGTAP_DRAGGING_OR_DOUBLETAP:
1659a46c0ec8Sopenharmony_ci		return true;
1660a46c0ec8Sopenharmony_ci	default:
1661a46c0ec8Sopenharmony_ci		return false;
1662a46c0ec8Sopenharmony_ci	}
1663a46c0ec8Sopenharmony_ci}
1664