xref: /third_party/libinput/src/evdev-debounce.c (revision a46c0ec8)
1/*
2 * Copyright © 2017 Red Hat, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 */
23
24#include "config.h"
25
26#include "evdev-fallback.h"
27
28/* Debounce cases to handle
29     P ... button press
30     R ... button release
31     ---|  timeout duration
32
33     'normal' .... event sent when it happens
34     'filtered' .. event is not sent (but may be sent later)
35     'delayed' ... event is sent with wall-clock delay
36
37   1) P---| R		P normal, R normal
38   2) R---| P		R normal, P normal
39   3) P---R--| P	P normal, R filtered, delayed, P normal
40   4) R---P--| R	R normal, P filtered, delayed, R normal
41   4.1) P---| R--P--|	P normal, R filtered
42   5) P--R-P-| R	P normal, R filtered, P filtered, R normal
43   6) R--P-R-| P	R normal, P filtered, R filtered, P normal
44   7) P--R--|
45          ---P-|	P normal, R filtered, P filtered
46   8) R--P--|
47          ---R-|	R normal, P filtered, R filtered
48
49   1, 2 are the normal click cases without debouncing taking effect
50   3, 4 are fast clicks where the second event is delivered with a delay
51   5, 6 are contact bounces, fast
52   7, 8 are contact bounces, slow
53
54   4.1 is a special case with the same event sequence as 4 but we want to
55   filter the *release* event out, it's a button losing contact while being
56   held down.
57
58   7 and 8 are cases where the first event happens within the first timeout
59   but the second event is outside that timeout (but within the timeout of
60   the second event). These cases are handled by restarting the timer on every
61   event that could be part of a bouncing sequence, which makes these cases
62   indistinguishable from 5 and 6.
63*/
64
65enum debounce_event {
66	DEBOUNCE_EVENT_PRESS = 50,
67	DEBOUNCE_EVENT_RELEASE,
68	DEBOUNCE_EVENT_TIMEOUT,
69	DEBOUNCE_EVENT_TIMEOUT_SHORT,
70	DEBOUNCE_EVENT_OTHERBUTTON,
71};
72
73static inline const char *
74debounce_state_to_str(enum debounce_state state)
75{
76	switch(state) {
77	CASE_RETURN_STRING(DEBOUNCE_STATE_IS_UP);
78	CASE_RETURN_STRING(DEBOUNCE_STATE_IS_DOWN);
79	CASE_RETURN_STRING(DEBOUNCE_STATE_IS_DOWN_WAITING);
80	CASE_RETURN_STRING(DEBOUNCE_STATE_IS_UP_DELAYING);
81	CASE_RETURN_STRING(DEBOUNCE_STATE_IS_UP_DELAYING_SPURIOUS);
82	CASE_RETURN_STRING(DEBOUNCE_STATE_IS_UP_DETECTING_SPURIOUS);
83	CASE_RETURN_STRING(DEBOUNCE_STATE_IS_DOWN_DETECTING_SPURIOUS);
84	CASE_RETURN_STRING(DEBOUNCE_STATE_IS_UP_WAITING);
85	CASE_RETURN_STRING(DEBOUNCE_STATE_IS_DOWN_DELAYING);
86	CASE_RETURN_STRING(DEBOUNCE_STATE_DISABLED);
87	}
88
89	return NULL;
90}
91
92static inline const char*
93debounce_event_to_str(enum debounce_event event)
94{
95	switch(event) {
96	CASE_RETURN_STRING(DEBOUNCE_EVENT_PRESS);
97	CASE_RETURN_STRING(DEBOUNCE_EVENT_RELEASE);
98	CASE_RETURN_STRING(DEBOUNCE_EVENT_TIMEOUT);
99	CASE_RETURN_STRING(DEBOUNCE_EVENT_TIMEOUT_SHORT);
100	CASE_RETURN_STRING(DEBOUNCE_EVENT_OTHERBUTTON);
101	}
102	return NULL;
103}
104
105static inline void
106log_debounce_bug(struct fallback_dispatch *fallback, enum debounce_event event)
107{
108	evdev_log_bug_libinput(fallback->device,
109			       "invalid debounce event %s in state %s\n",
110			       debounce_event_to_str(event),
111			       debounce_state_to_str(fallback->debounce.state));
112
113}
114
115static inline void
116debounce_set_state(struct fallback_dispatch *fallback,
117		   enum debounce_state new_state)
118{
119	assert(new_state >= DEBOUNCE_STATE_IS_UP &&
120	       new_state <= DEBOUNCE_STATE_IS_DOWN_DELAYING);
121
122	fallback->debounce.state = new_state;
123}
124
125static inline void
126debounce_set_timer(struct fallback_dispatch *fallback,
127		   uint64_t time)
128{
129	const int DEBOUNCE_TIMEOUT_BOUNCE = ms2us(25);
130
131	libinput_timer_set(&fallback->debounce.timer,
132			   time + DEBOUNCE_TIMEOUT_BOUNCE);
133}
134
135static inline void
136debounce_set_timer_short(struct fallback_dispatch *fallback,
137			 uint64_t time)
138{
139	const int DEBOUNCE_TIMEOUT_SPURIOUS = ms2us(12);
140
141	libinput_timer_set(&fallback->debounce.timer_short,
142			   time + DEBOUNCE_TIMEOUT_SPURIOUS);
143}
144
145static inline void
146debounce_cancel_timer(struct fallback_dispatch *fallback)
147{
148	libinput_timer_cancel(&fallback->debounce.timer);
149}
150
151static inline void
152debounce_cancel_timer_short(struct fallback_dispatch *fallback)
153{
154	libinput_timer_cancel(&fallback->debounce.timer_short);
155}
156
157static inline void
158debounce_enable_spurious(struct fallback_dispatch *fallback)
159{
160	if (fallback->debounce.spurious_enabled)
161		evdev_log_bug_libinput(fallback->device,
162				       "tried to enable spurious debouncing twice\n");
163
164	fallback->debounce.spurious_enabled = true;
165	evdev_log_info(fallback->device,
166		       "Enabling spurious button debouncing, "
167		       "see %s/button-debouncing.html for details\n",
168		       HTTP_DOC_LINK);
169}
170
171static void
172debounce_notify_button(struct fallback_dispatch *fallback,
173		       enum libinput_button_state state)
174{
175	struct evdev_device *device = fallback->device;
176	unsigned int code = fallback->debounce.button_code;
177	uint64_t time = fallback->debounce.button_time;
178
179	code = evdev_to_left_handed(device, code);
180
181	fallback_notify_physical_button(fallback, device, time, code, state);
182}
183
184static void
185debounce_is_up_handle_event(struct fallback_dispatch *fallback, enum debounce_event event, uint64_t time)
186{
187	switch (event) {
188	case DEBOUNCE_EVENT_PRESS:
189		fallback->debounce.button_time = time;
190		debounce_set_timer(fallback, time);
191		debounce_set_state(fallback, DEBOUNCE_STATE_IS_DOWN_WAITING);
192		debounce_notify_button(fallback,
193				       LIBINPUT_BUTTON_STATE_PRESSED);
194		break;
195	case DEBOUNCE_EVENT_RELEASE:
196	case DEBOUNCE_EVENT_TIMEOUT:
197	case DEBOUNCE_EVENT_TIMEOUT_SHORT:
198		log_debounce_bug(fallback, event);
199		break;
200	case DEBOUNCE_EVENT_OTHERBUTTON:
201		break;
202	}
203}
204
205static void
206debounce_is_down_handle_event(struct fallback_dispatch *fallback, enum debounce_event event, uint64_t time)
207{
208	switch (event) {
209	case DEBOUNCE_EVENT_PRESS:
210		log_debounce_bug(fallback, event);
211		break;
212	case DEBOUNCE_EVENT_RELEASE:
213		fallback->debounce.button_time = time;
214		debounce_set_timer(fallback, time);
215		debounce_set_timer_short(fallback, time);
216		if (fallback->debounce.spurious_enabled) {
217			debounce_set_state(fallback, DEBOUNCE_STATE_IS_UP_DELAYING_SPURIOUS);
218		} else {
219			debounce_set_state(fallback, DEBOUNCE_STATE_IS_UP_DETECTING_SPURIOUS);
220			debounce_notify_button(fallback,
221					       LIBINPUT_BUTTON_STATE_RELEASED);
222		}
223		break;
224	case DEBOUNCE_EVENT_TIMEOUT:
225	case DEBOUNCE_EVENT_TIMEOUT_SHORT:
226		log_debounce_bug(fallback, event);
227		break;
228	case DEBOUNCE_EVENT_OTHERBUTTON:
229		break;
230	}
231}
232
233static void
234debounce_is_down_waiting_handle_event(struct fallback_dispatch *fallback, enum debounce_event event, uint64_t time)
235{
236	switch (event) {
237	case DEBOUNCE_EVENT_PRESS:
238		log_debounce_bug(fallback, event);
239		break;
240	case DEBOUNCE_EVENT_RELEASE:
241		debounce_set_timer(fallback, time);
242		debounce_set_state(fallback, DEBOUNCE_STATE_IS_UP_DELAYING);
243		/* Note: In the debouncing RPR case, we use the last
244		 * release's time stamp */
245		fallback->debounce.button_time = time;
246		break;
247	case DEBOUNCE_EVENT_TIMEOUT:
248		debounce_set_state(fallback, DEBOUNCE_STATE_IS_DOWN);
249		break;
250	case DEBOUNCE_EVENT_TIMEOUT_SHORT:
251		log_debounce_bug(fallback, event);
252		break;
253	case DEBOUNCE_EVENT_OTHERBUTTON:
254		debounce_set_state(fallback, DEBOUNCE_STATE_IS_DOWN);
255		break;
256	}
257}
258
259static void
260debounce_is_up_delaying_handle_event(struct fallback_dispatch *fallback, enum debounce_event event, uint64_t time)
261{
262	switch (event) {
263	case DEBOUNCE_EVENT_PRESS:
264		debounce_set_timer(fallback, time);
265		debounce_set_state(fallback, DEBOUNCE_STATE_IS_DOWN_WAITING);
266		break;
267	case DEBOUNCE_EVENT_RELEASE:
268	case DEBOUNCE_EVENT_TIMEOUT_SHORT:
269		log_debounce_bug(fallback, event);
270		break;
271	case DEBOUNCE_EVENT_TIMEOUT:
272	case DEBOUNCE_EVENT_OTHERBUTTON:
273		debounce_set_state(fallback, DEBOUNCE_STATE_IS_UP);
274		debounce_notify_button(fallback,
275				       LIBINPUT_BUTTON_STATE_RELEASED);
276		break;
277	}
278}
279
280static void
281debounce_is_up_delaying_spurious_handle_event(struct fallback_dispatch *fallback, enum debounce_event event, uint64_t time)
282{
283	switch (event) {
284	case DEBOUNCE_EVENT_PRESS:
285		debounce_set_state(fallback, DEBOUNCE_STATE_IS_DOWN);
286		debounce_cancel_timer(fallback);
287		debounce_cancel_timer_short(fallback);
288		break;
289	case DEBOUNCE_EVENT_RELEASE:
290	case DEBOUNCE_EVENT_TIMEOUT:
291		log_debounce_bug(fallback, event);
292		break;
293	case DEBOUNCE_EVENT_TIMEOUT_SHORT:
294		debounce_set_state(fallback, DEBOUNCE_STATE_IS_UP_WAITING);
295		debounce_notify_button(fallback,
296				       LIBINPUT_BUTTON_STATE_RELEASED);
297		break;
298	case DEBOUNCE_EVENT_OTHERBUTTON:
299		debounce_set_state(fallback, DEBOUNCE_STATE_IS_UP);
300		debounce_notify_button(fallback,
301				       LIBINPUT_BUTTON_STATE_RELEASED);
302		break;
303	}
304}
305
306static void
307debounce_is_up_detecting_spurious_handle_event(struct fallback_dispatch *fallback, enum debounce_event event, uint64_t time)
308{
309	switch (event) {
310	case DEBOUNCE_EVENT_PRESS:
311		debounce_set_timer(fallback, time);
312		debounce_set_timer_short(fallback, time);
313		/* Note: in a bouncing PRP case, we use the last press
314		 * event time */
315		fallback->debounce.button_time = time;
316		debounce_set_state(fallback, DEBOUNCE_STATE_IS_DOWN_DETECTING_SPURIOUS);
317		break;
318	case DEBOUNCE_EVENT_RELEASE:
319		log_debounce_bug(fallback, event);
320		break;
321	case DEBOUNCE_EVENT_TIMEOUT:
322		debounce_set_state(fallback, DEBOUNCE_STATE_IS_UP);
323		break;
324	case DEBOUNCE_EVENT_TIMEOUT_SHORT:
325		debounce_set_state(fallback, DEBOUNCE_STATE_IS_UP_WAITING);
326		break;
327	case DEBOUNCE_EVENT_OTHERBUTTON:
328		debounce_set_state(fallback, DEBOUNCE_STATE_IS_UP);
329		break;
330	}
331}
332
333static void
334debounce_is_down_detecting_spurious_handle_event(struct fallback_dispatch *fallback, enum debounce_event event, uint64_t time)
335{
336	switch (event) {
337	case DEBOUNCE_EVENT_PRESS:
338		log_debounce_bug(fallback, event);
339		break;
340	case DEBOUNCE_EVENT_RELEASE:
341		debounce_set_timer(fallback, time);
342		debounce_set_timer_short(fallback, time);
343		debounce_set_state(fallback, DEBOUNCE_STATE_IS_UP_DETECTING_SPURIOUS);
344		break;
345	case DEBOUNCE_EVENT_TIMEOUT_SHORT:
346		debounce_cancel_timer(fallback);
347		debounce_set_state(fallback, DEBOUNCE_STATE_IS_DOWN);
348		debounce_enable_spurious(fallback);
349		debounce_notify_button(fallback,
350				       LIBINPUT_BUTTON_STATE_PRESSED);
351		break;
352	case DEBOUNCE_EVENT_TIMEOUT:
353	case DEBOUNCE_EVENT_OTHERBUTTON:
354		debounce_set_state(fallback, DEBOUNCE_STATE_IS_DOWN);
355		debounce_notify_button(fallback,
356				       LIBINPUT_BUTTON_STATE_PRESSED);
357		break;
358	}
359}
360
361static void
362debounce_is_up_waiting_handle_event(struct fallback_dispatch *fallback, enum debounce_event event, uint64_t time)
363{
364	switch (event) {
365	case DEBOUNCE_EVENT_PRESS:
366		debounce_set_timer(fallback, time);
367		/* Note: in a debouncing PRP case, we use the last press'
368		 * time */
369		fallback->debounce.button_time = time;
370		debounce_set_state(fallback, DEBOUNCE_STATE_IS_DOWN_DELAYING);
371		break;
372	case DEBOUNCE_EVENT_RELEASE:
373	case DEBOUNCE_EVENT_TIMEOUT_SHORT:
374		log_debounce_bug(fallback, event);
375		break;
376	case DEBOUNCE_EVENT_TIMEOUT:
377	case DEBOUNCE_EVENT_OTHERBUTTON:
378		debounce_set_state(fallback, DEBOUNCE_STATE_IS_UP);
379		break;
380	}
381}
382
383static void
384debounce_is_down_delaying_handle_event(struct fallback_dispatch *fallback, enum debounce_event event, uint64_t time)
385{
386	switch (event) {
387	case DEBOUNCE_EVENT_PRESS:
388		log_debounce_bug(fallback, event);
389		break;
390	case DEBOUNCE_EVENT_RELEASE:
391		debounce_set_timer(fallback, time);
392		debounce_set_state(fallback, DEBOUNCE_STATE_IS_UP_WAITING);
393		break;
394	case DEBOUNCE_EVENT_TIMEOUT_SHORT:
395		log_debounce_bug(fallback, event);
396		break;
397	case DEBOUNCE_EVENT_TIMEOUT:
398	case DEBOUNCE_EVENT_OTHERBUTTON:
399		debounce_set_state(fallback, DEBOUNCE_STATE_IS_DOWN);
400		debounce_notify_button(fallback,
401				       LIBINPUT_BUTTON_STATE_PRESSED);
402		break;
403	}
404}
405
406static void
407debounce_disabled_handle_event(struct fallback_dispatch *fallback,
408			enum debounce_event event,
409			uint64_t time)
410{
411	switch (event) {
412	case DEBOUNCE_EVENT_PRESS:
413		fallback->debounce.button_time = time;
414		debounce_notify_button(fallback,
415				       LIBINPUT_BUTTON_STATE_PRESSED);
416		break;
417	case DEBOUNCE_EVENT_RELEASE:
418		fallback->debounce.button_time = time;
419		debounce_notify_button(fallback,
420				       LIBINPUT_BUTTON_STATE_RELEASED);
421		break;
422	case DEBOUNCE_EVENT_TIMEOUT_SHORT:
423	case DEBOUNCE_EVENT_TIMEOUT:
424		log_debounce_bug(fallback, event);
425		break;
426	case DEBOUNCE_EVENT_OTHERBUTTON:
427		break;
428	}
429}
430
431static void
432debounce_handle_event(struct fallback_dispatch *fallback,
433		      enum debounce_event event,
434		      uint64_t time)
435{
436	enum debounce_state current = fallback->debounce.state;
437
438	if (event == DEBOUNCE_EVENT_OTHERBUTTON) {
439		debounce_cancel_timer(fallback);
440		debounce_cancel_timer_short(fallback);
441	}
442
443	switch(current) {
444	case DEBOUNCE_STATE_IS_UP:
445		debounce_is_up_handle_event(fallback, event, time);
446		break;
447	case DEBOUNCE_STATE_IS_DOWN:
448		debounce_is_down_handle_event(fallback, event, time);
449		break;
450	case DEBOUNCE_STATE_IS_DOWN_WAITING:
451		debounce_is_down_waiting_handle_event(fallback, event, time);
452		break;
453	case DEBOUNCE_STATE_IS_UP_DELAYING:
454		debounce_is_up_delaying_handle_event(fallback, event, time);
455		break;
456	case DEBOUNCE_STATE_IS_UP_DELAYING_SPURIOUS:
457		debounce_is_up_delaying_spurious_handle_event(fallback, event, time);
458		break;
459	case DEBOUNCE_STATE_IS_UP_DETECTING_SPURIOUS:
460		debounce_is_up_detecting_spurious_handle_event(fallback, event, time);
461		break;
462	case DEBOUNCE_STATE_IS_DOWN_DETECTING_SPURIOUS:
463		debounce_is_down_detecting_spurious_handle_event(fallback, event, time);
464		break;
465	case DEBOUNCE_STATE_IS_UP_WAITING:
466		debounce_is_up_waiting_handle_event(fallback, event, time);
467		break;
468	case DEBOUNCE_STATE_IS_DOWN_DELAYING:
469		debounce_is_down_delaying_handle_event(fallback, event, time);
470		break;
471	case DEBOUNCE_STATE_DISABLED:
472		debounce_disabled_handle_event(fallback, event, time);
473		break;
474	}
475
476	evdev_log_debug(fallback->device,
477			"debounce state: %s → %s → %s\n",
478			debounce_state_to_str(current),
479			debounce_event_to_str(event),
480			debounce_state_to_str(fallback->debounce.state));
481}
482
483void
484fallback_debounce_handle_state(struct fallback_dispatch *dispatch,
485			       uint64_t time)
486{
487	unsigned int changed[16] = {0}; /* event codes of changed buttons */
488	size_t nchanged = 0;
489	bool flushed = false;
490
491	for (unsigned int code = 0; code <= KEY_MAX; code++) {
492		if (get_key_type(code) != KEY_TYPE_BUTTON)
493			continue;
494
495		if (hw_key_has_changed(dispatch, code))
496			changed[nchanged++] = code;
497
498		/* If you manage to press more than 16 buttons in the same
499		 * frame, we just quietly ignore the rest of them */
500		if (nchanged == ARRAY_LENGTH(changed))
501			break;
502	}
503
504	/* If we have more than one button this frame or a different button,
505	 * flush the state machine with otherbutton */
506	if (nchanged > 1 ||
507	    changed[0] != dispatch->debounce.button_code) {
508		debounce_handle_event(dispatch,
509				      DEBOUNCE_EVENT_OTHERBUTTON,
510				      time);
511		flushed = true;
512	}
513
514	/* The state machine has some pre-conditions:
515	 * - the IS_DOWN and IS_UP states are neutral entry states without
516	 *   any timeouts
517	 * - a OTHERBUTTON event always flushes the state to IS_DOWN or
518	 *   IS_UP
519	 */
520
521	for (size_t i = 0; i < nchanged; i++) {
522		bool is_down = hw_is_key_down(dispatch, changed[i]);
523
524		if (flushed &&
525		    dispatch->debounce.state != DEBOUNCE_STATE_DISABLED) {
526			debounce_set_state(dispatch,
527					   !is_down ?
528						   DEBOUNCE_STATE_IS_DOWN :
529						   DEBOUNCE_STATE_IS_UP);
530			flushed = false;
531		}
532
533		dispatch->debounce.button_code = changed[i];
534		debounce_handle_event(dispatch,
535				      is_down ?
536					      DEBOUNCE_EVENT_PRESS :
537					      DEBOUNCE_EVENT_RELEASE,
538				      time);
539
540		/* if we have more than one event, we flush the state
541		 * machine immediately after the event itself */
542		if (nchanged > 1) {
543			debounce_handle_event(dispatch,
544					      DEBOUNCE_EVENT_OTHERBUTTON,
545					      time);
546			flushed = true;
547		}
548
549	}
550}
551
552static void
553debounce_timeout(uint64_t now, void *data)
554{
555	struct evdev_device *device = data;
556	struct fallback_dispatch *dispatch =
557		fallback_dispatch(device->dispatch);
558
559	debounce_handle_event(dispatch, DEBOUNCE_EVENT_TIMEOUT, now);
560}
561
562static void
563debounce_timeout_short(uint64_t now, void *data)
564{
565	struct evdev_device *device = data;
566	struct fallback_dispatch *dispatch =
567		fallback_dispatch(device->dispatch);
568
569	debounce_handle_event(dispatch, DEBOUNCE_EVENT_TIMEOUT_SHORT, now);
570}
571
572void
573fallback_init_debounce(struct fallback_dispatch *dispatch)
574{
575	struct evdev_device *device = dispatch->device;
576	char timer_name[64];
577
578	if (evdev_device_has_model_quirk(device, QUIRK_MODEL_BOUNCING_KEYS)) {
579		dispatch->debounce.state = DEBOUNCE_STATE_DISABLED;
580		return;
581	}
582
583	dispatch->debounce.state = DEBOUNCE_STATE_IS_UP;
584
585	snprintf(timer_name,
586		 sizeof(timer_name),
587		 "%s debounce short",
588		 evdev_device_get_sysname(device));
589	libinput_timer_init(&dispatch->debounce.timer_short,
590			    evdev_libinput_context(device),
591			    timer_name,
592			    debounce_timeout_short,
593			    device);
594
595	snprintf(timer_name,
596		 sizeof(timer_name),
597		 "%s debounce",
598		 evdev_device_get_sysname(device));
599	libinput_timer_init(&dispatch->debounce.timer,
600			    evdev_libinput_context(device),
601			    timer_name,
602			    debounce_timeout,
603			    device);
604}
605