• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 currently unhandled.
61 */
62 
63 enum debounce_event {
64 	DEBOUNCE_EVENT_PRESS = 50,
65 	DEBOUNCE_EVENT_RELEASE,
66 	DEBOUNCE_EVENT_TIMEOUT,
67 	DEBOUNCE_EVENT_TIMEOUT_SHORT,
68 	DEBOUNCE_EVENT_OTHERBUTTON,
69 };
70 
71 static inline const char *
debounce_state_to_str(enum debounce_state state)72 debounce_state_to_str(enum debounce_state state)
73 {
74 	switch(state) {
75 	CASE_RETURN_STRING(DEBOUNCE_STATE_IS_UP);
76 	CASE_RETURN_STRING(DEBOUNCE_STATE_IS_DOWN);
77 	CASE_RETURN_STRING(DEBOUNCE_STATE_IS_DOWN_WAITING);
78 	CASE_RETURN_STRING(DEBOUNCE_STATE_IS_UP_DELAYING);
79 	CASE_RETURN_STRING(DEBOUNCE_STATE_IS_UP_DELAYING_SPURIOUS);
80 	CASE_RETURN_STRING(DEBOUNCE_STATE_IS_UP_DETECTING_SPURIOUS);
81 	CASE_RETURN_STRING(DEBOUNCE_STATE_IS_DOWN_DETECTING_SPURIOUS);
82 	CASE_RETURN_STRING(DEBOUNCE_STATE_IS_UP_WAITING);
83 	CASE_RETURN_STRING(DEBOUNCE_STATE_IS_DOWN_DELAYING);
84 	CASE_RETURN_STRING(DEBOUNCE_STATE_DISABLED);
85 	}
86 
87 	return NULL;
88 }
89 
90 static inline const char*
debounce_event_to_str(enum debounce_event event)91 debounce_event_to_str(enum debounce_event event)
92 {
93 	switch(event) {
94 	CASE_RETURN_STRING(DEBOUNCE_EVENT_PRESS);
95 	CASE_RETURN_STRING(DEBOUNCE_EVENT_RELEASE);
96 	CASE_RETURN_STRING(DEBOUNCE_EVENT_TIMEOUT);
97 	CASE_RETURN_STRING(DEBOUNCE_EVENT_TIMEOUT_SHORT);
98 	CASE_RETURN_STRING(DEBOUNCE_EVENT_OTHERBUTTON);
99 	}
100 	return NULL;
101 }
102 
103 static inline void
log_debounce_bug(struct fallback_dispatch * fallback,enum debounce_event event)104 log_debounce_bug(struct fallback_dispatch *fallback, enum debounce_event event)
105 {
106 	evdev_log_bug_libinput(fallback->device,
107 			       "invalid debounce event %s in state %s\n",
108 			       debounce_event_to_str(event),
109 			       debounce_state_to_str(fallback->debounce.state));
110 
111 }
112 
113 static inline void
debounce_set_state(struct fallback_dispatch * fallback,enum debounce_state new_state)114 debounce_set_state(struct fallback_dispatch *fallback,
115 		   enum debounce_state new_state)
116 {
117 	assert(new_state >= DEBOUNCE_STATE_IS_UP &&
118 	       new_state <= DEBOUNCE_STATE_IS_DOWN_DELAYING);
119 
120 	fallback->debounce.state = new_state;
121 }
122 
123 static inline void
debounce_set_timer(struct fallback_dispatch * fallback,uint64_t time)124 debounce_set_timer(struct fallback_dispatch *fallback,
125 		   uint64_t time)
126 {
127 	const int DEBOUNCE_TIMEOUT_BOUNCE = ms2us(25);
128 
129 	libinput_timer_set(&fallback->debounce.timer,
130 			   time + DEBOUNCE_TIMEOUT_BOUNCE);
131 }
132 
133 static inline void
debounce_set_timer_short(struct fallback_dispatch * fallback,uint64_t time)134 debounce_set_timer_short(struct fallback_dispatch *fallback,
135 			 uint64_t time)
136 {
137 	const int DEBOUNCE_TIMEOUT_SPURIOUS = ms2us(12);
138 
139 	libinput_timer_set(&fallback->debounce.timer_short,
140 			   time + DEBOUNCE_TIMEOUT_SPURIOUS);
141 }
142 
143 static inline void
debounce_cancel_timer(struct fallback_dispatch * fallback)144 debounce_cancel_timer(struct fallback_dispatch *fallback)
145 {
146 	libinput_timer_cancel(&fallback->debounce.timer);
147 }
148 
149 static inline void
debounce_cancel_timer_short(struct fallback_dispatch * fallback)150 debounce_cancel_timer_short(struct fallback_dispatch *fallback)
151 {
152 	libinput_timer_cancel(&fallback->debounce.timer_short);
153 }
154 
155 static inline void
debounce_enable_spurious(struct fallback_dispatch * fallback)156 debounce_enable_spurious(struct fallback_dispatch *fallback)
157 {
158 	if (fallback->debounce.spurious_enabled)
159 		evdev_log_bug_libinput(fallback->device,
160 				       "tried to enable spurious debouncing twice\n");
161 
162 	fallback->debounce.spurious_enabled = true;
163 	evdev_log_info(fallback->device,
164 		       "Enabling spurious button debouncing, "
165 		       "see %sbutton-debouncing.html for details\n",
166 		       HTTP_DOC_LINK);
167 }
168 
169 static void
debounce_notify_button(struct fallback_dispatch * fallback,enum libinput_button_state state)170 debounce_notify_button(struct fallback_dispatch *fallback,
171 		       enum libinput_button_state state)
172 {
173 	struct evdev_device *device = fallback->device;
174 	unsigned int code = fallback->debounce.button_code;
175 	uint64_t time = fallback->debounce.button_time;
176 
177 	code = evdev_to_left_handed(device, code);
178 
179 	evdev_pointer_notify_physical_button(device, time, code, state);
180 }
181 
182 static void
debounce_is_up_handle_event(struct fallback_dispatch * fallback,enum debounce_event event,uint64_t time)183 debounce_is_up_handle_event(struct fallback_dispatch *fallback, enum debounce_event event, uint64_t time)
184 {
185 	switch (event) {
186 	case DEBOUNCE_EVENT_PRESS:
187 		fallback->debounce.button_time = time;
188 		debounce_set_timer(fallback, time);
189 		debounce_set_state(fallback, DEBOUNCE_STATE_IS_DOWN_WAITING);
190 		debounce_notify_button(fallback,
191 				       LIBINPUT_BUTTON_STATE_PRESSED);
192 		break;
193 	case DEBOUNCE_EVENT_RELEASE:
194 	case DEBOUNCE_EVENT_TIMEOUT:
195 	case DEBOUNCE_EVENT_TIMEOUT_SHORT:
196 		log_debounce_bug(fallback, event);
197 		break;
198 	case DEBOUNCE_EVENT_OTHERBUTTON:
199 		break;
200 	}
201 }
202 
203 static void
debounce_is_down_handle_event(struct fallback_dispatch * fallback,enum debounce_event event,uint64_t time)204 debounce_is_down_handle_event(struct fallback_dispatch *fallback, enum debounce_event event, uint64_t time)
205 {
206 	switch (event) {
207 	case DEBOUNCE_EVENT_PRESS:
208 		log_debounce_bug(fallback, event);
209 		break;
210 	case DEBOUNCE_EVENT_RELEASE:
211 		fallback->debounce.button_time = time;
212 		debounce_set_timer(fallback, time);
213 		debounce_set_timer_short(fallback, time);
214 		if (fallback->debounce.spurious_enabled) {
215 			debounce_set_state(fallback, DEBOUNCE_STATE_IS_UP_DELAYING_SPURIOUS);
216 		} else {
217 			debounce_set_state(fallback, DEBOUNCE_STATE_IS_UP_DETECTING_SPURIOUS);
218 			debounce_notify_button(fallback,
219 					       LIBINPUT_BUTTON_STATE_RELEASED);
220 		}
221 		break;
222 	case DEBOUNCE_EVENT_TIMEOUT:
223 	case DEBOUNCE_EVENT_TIMEOUT_SHORT:
224 		log_debounce_bug(fallback, event);
225 		break;
226 	case DEBOUNCE_EVENT_OTHERBUTTON:
227 		break;
228 	}
229 }
230 
231 static void
debounce_is_down_waiting_handle_event(struct fallback_dispatch * fallback,enum debounce_event event,uint64_t time)232 debounce_is_down_waiting_handle_event(struct fallback_dispatch *fallback, enum debounce_event event, uint64_t time)
233 {
234 	switch (event) {
235 	case DEBOUNCE_EVENT_PRESS:
236 		log_debounce_bug(fallback, event);
237 		break;
238 	case DEBOUNCE_EVENT_RELEASE:
239 		debounce_set_state(fallback, DEBOUNCE_STATE_IS_UP_DELAYING);
240 		/* Note: In the debouncing RPR case, we use the last
241 		 * release's time stamp */
242 		fallback->debounce.button_time = time;
243 		break;
244 	case DEBOUNCE_EVENT_TIMEOUT:
245 		debounce_set_state(fallback, DEBOUNCE_STATE_IS_DOWN);
246 		break;
247 	case DEBOUNCE_EVENT_TIMEOUT_SHORT:
248 		log_debounce_bug(fallback, event);
249 		break;
250 	case DEBOUNCE_EVENT_OTHERBUTTON:
251 		debounce_set_state(fallback, DEBOUNCE_STATE_IS_DOWN);
252 		break;
253 	}
254 }
255 
256 static void
debounce_is_up_delaying_handle_event(struct fallback_dispatch * fallback,enum debounce_event event,uint64_t time)257 debounce_is_up_delaying_handle_event(struct fallback_dispatch *fallback, enum debounce_event event, uint64_t time)
258 {
259 	switch (event) {
260 	case DEBOUNCE_EVENT_PRESS:
261 		debounce_set_state(fallback, DEBOUNCE_STATE_IS_DOWN_WAITING);
262 		break;
263 	case DEBOUNCE_EVENT_RELEASE:
264 	case DEBOUNCE_EVENT_TIMEOUT_SHORT:
265 		log_debounce_bug(fallback, event);
266 		break;
267 	case DEBOUNCE_EVENT_TIMEOUT:
268 	case DEBOUNCE_EVENT_OTHERBUTTON:
269 		debounce_set_state(fallback, DEBOUNCE_STATE_IS_UP);
270 		debounce_notify_button(fallback,
271 				       LIBINPUT_BUTTON_STATE_RELEASED);
272 		break;
273 	}
274 }
275 
276 static void
debounce_is_up_delaying_spurious_handle_event(struct fallback_dispatch * fallback,enum debounce_event event,uint64_t time)277 debounce_is_up_delaying_spurious_handle_event(struct fallback_dispatch *fallback, enum debounce_event event, uint64_t time)
278 {
279 	switch (event) {
280 	case DEBOUNCE_EVENT_PRESS:
281 		debounce_set_state(fallback, DEBOUNCE_STATE_IS_DOWN);
282 		debounce_cancel_timer(fallback);
283 		debounce_cancel_timer_short(fallback);
284 		break;
285 	case DEBOUNCE_EVENT_RELEASE:
286 	case DEBOUNCE_EVENT_TIMEOUT:
287 		log_debounce_bug(fallback, event);
288 		break;
289 	case DEBOUNCE_EVENT_TIMEOUT_SHORT:
290 		debounce_set_state(fallback, DEBOUNCE_STATE_IS_UP_WAITING);
291 		debounce_notify_button(fallback,
292 				       LIBINPUT_BUTTON_STATE_RELEASED);
293 		break;
294 	case DEBOUNCE_EVENT_OTHERBUTTON:
295 		debounce_set_state(fallback, DEBOUNCE_STATE_IS_UP);
296 		debounce_notify_button(fallback,
297 				       LIBINPUT_BUTTON_STATE_RELEASED);
298 		break;
299 	}
300 }
301 
302 static void
debounce_is_up_detecting_spurious_handle_event(struct fallback_dispatch * fallback,enum debounce_event event,uint64_t time)303 debounce_is_up_detecting_spurious_handle_event(struct fallback_dispatch *fallback, enum debounce_event event, uint64_t time)
304 {
305 	switch (event) {
306 	case DEBOUNCE_EVENT_PRESS:
307 		/* Note: in a bouncing PRP case, we use the last press
308 		 * event time */
309 		fallback->debounce.button_time = time;
310 		debounce_set_state(fallback, DEBOUNCE_STATE_IS_DOWN_DETECTING_SPURIOUS);
311 		break;
312 	case DEBOUNCE_EVENT_RELEASE:
313 		log_debounce_bug(fallback, event);
314 		break;
315 	case DEBOUNCE_EVENT_TIMEOUT:
316 		debounce_set_state(fallback, DEBOUNCE_STATE_IS_UP);
317 		break;
318 	case DEBOUNCE_EVENT_TIMEOUT_SHORT:
319 		debounce_set_state(fallback, DEBOUNCE_STATE_IS_UP_WAITING);
320 		break;
321 	case DEBOUNCE_EVENT_OTHERBUTTON:
322 		debounce_set_state(fallback, DEBOUNCE_STATE_IS_UP);
323 		break;
324 	}
325 }
326 
327 static void
debounce_is_down_detecting_spurious_handle_event(struct fallback_dispatch * fallback,enum debounce_event event,uint64_t time)328 debounce_is_down_detecting_spurious_handle_event(struct fallback_dispatch *fallback, enum debounce_event event, uint64_t time)
329 {
330 	switch (event) {
331 	case DEBOUNCE_EVENT_PRESS:
332 		log_debounce_bug(fallback, event);
333 		break;
334 	case DEBOUNCE_EVENT_RELEASE:
335 		debounce_set_state(fallback, DEBOUNCE_STATE_IS_UP_DETECTING_SPURIOUS);
336 		break;
337 	case DEBOUNCE_EVENT_TIMEOUT_SHORT:
338 		debounce_cancel_timer(fallback);
339 		debounce_set_state(fallback, DEBOUNCE_STATE_IS_DOWN);
340 		debounce_enable_spurious(fallback);
341 		debounce_notify_button(fallback,
342 				       LIBINPUT_BUTTON_STATE_PRESSED);
343 		break;
344 	case DEBOUNCE_EVENT_TIMEOUT:
345 	case DEBOUNCE_EVENT_OTHERBUTTON:
346 		debounce_set_state(fallback, DEBOUNCE_STATE_IS_DOWN);
347 		debounce_notify_button(fallback,
348 				       LIBINPUT_BUTTON_STATE_PRESSED);
349 		break;
350 	}
351 }
352 
353 static void
debounce_is_up_waiting_handle_event(struct fallback_dispatch * fallback,enum debounce_event event,uint64_t time)354 debounce_is_up_waiting_handle_event(struct fallback_dispatch *fallback, enum debounce_event event, uint64_t time)
355 {
356 	switch (event) {
357 	case DEBOUNCE_EVENT_PRESS:
358 		/* Note: in a debouncing PRP case, we use the last press'
359 		 * time */
360 		fallback->debounce.button_time = time;
361 		debounce_set_state(fallback, DEBOUNCE_STATE_IS_DOWN_DELAYING);
362 		break;
363 	case DEBOUNCE_EVENT_RELEASE:
364 	case DEBOUNCE_EVENT_TIMEOUT_SHORT:
365 		log_debounce_bug(fallback, event);
366 		break;
367 	case DEBOUNCE_EVENT_TIMEOUT:
368 	case DEBOUNCE_EVENT_OTHERBUTTON:
369 		debounce_set_state(fallback, DEBOUNCE_STATE_IS_UP);
370 		break;
371 	}
372 }
373 
374 static void
debounce_is_down_delaying_handle_event(struct fallback_dispatch * fallback,enum debounce_event event,uint64_t time)375 debounce_is_down_delaying_handle_event(struct fallback_dispatch *fallback, enum debounce_event event, uint64_t time)
376 {
377 	switch (event) {
378 	case DEBOUNCE_EVENT_PRESS:
379 		log_debounce_bug(fallback, event);
380 		break;
381 	case DEBOUNCE_EVENT_RELEASE:
382 		debounce_set_state(fallback, DEBOUNCE_STATE_IS_UP_WAITING);
383 		break;
384 	case DEBOUNCE_EVENT_TIMEOUT_SHORT:
385 		log_debounce_bug(fallback, event);
386 		break;
387 	case DEBOUNCE_EVENT_TIMEOUT:
388 	case DEBOUNCE_EVENT_OTHERBUTTON:
389 		debounce_set_state(fallback, DEBOUNCE_STATE_IS_DOWN);
390 		debounce_notify_button(fallback,
391 				       LIBINPUT_BUTTON_STATE_PRESSED);
392 		break;
393 	}
394 }
395 
396 static void
debounce_disabled_handle_event(struct fallback_dispatch * fallback,enum debounce_event event,uint64_t time)397 debounce_disabled_handle_event(struct fallback_dispatch *fallback,
398 			enum debounce_event event,
399 			uint64_t time)
400 {
401 	switch (event) {
402 	case DEBOUNCE_EVENT_PRESS:
403 		fallback->debounce.button_time = time;
404 		debounce_notify_button(fallback,
405 				       LIBINPUT_BUTTON_STATE_PRESSED);
406 		break;
407 	case DEBOUNCE_EVENT_RELEASE:
408 		fallback->debounce.button_time = time;
409 		debounce_notify_button(fallback,
410 				       LIBINPUT_BUTTON_STATE_RELEASED);
411 		break;
412 	case DEBOUNCE_EVENT_TIMEOUT_SHORT:
413 	case DEBOUNCE_EVENT_TIMEOUT:
414 		log_debounce_bug(fallback, event);
415 		break;
416 	case DEBOUNCE_EVENT_OTHERBUTTON:
417 		break;
418 	}
419 }
420 
421 static void
debounce_handle_event(struct fallback_dispatch * fallback,enum debounce_event event,uint64_t time)422 debounce_handle_event(struct fallback_dispatch *fallback,
423 		      enum debounce_event event,
424 		      uint64_t time)
425 {
426 	enum debounce_state current = fallback->debounce.state;
427 
428 	if (event == DEBOUNCE_EVENT_OTHERBUTTON) {
429 		debounce_cancel_timer(fallback);
430 		debounce_cancel_timer_short(fallback);
431 	}
432 
433 	switch(current) {
434 	case DEBOUNCE_STATE_IS_UP:
435 		debounce_is_up_handle_event(fallback, event, time);
436 		break;
437 	case DEBOUNCE_STATE_IS_DOWN:
438 		debounce_is_down_handle_event(fallback, event, time);
439 		break;
440 	case DEBOUNCE_STATE_IS_DOWN_WAITING:
441 		debounce_is_down_waiting_handle_event(fallback, event, time);
442 		break;
443 	case DEBOUNCE_STATE_IS_UP_DELAYING:
444 		debounce_is_up_delaying_handle_event(fallback, event, time);
445 		break;
446 	case DEBOUNCE_STATE_IS_UP_DELAYING_SPURIOUS:
447 		debounce_is_up_delaying_spurious_handle_event(fallback, event, time);
448 		break;
449 	case DEBOUNCE_STATE_IS_UP_DETECTING_SPURIOUS:
450 		debounce_is_up_detecting_spurious_handle_event(fallback, event, time);
451 		break;
452 	case DEBOUNCE_STATE_IS_DOWN_DETECTING_SPURIOUS:
453 		debounce_is_down_detecting_spurious_handle_event(fallback, event, time);
454 		break;
455 	case DEBOUNCE_STATE_IS_UP_WAITING:
456 		debounce_is_up_waiting_handle_event(fallback, event, time);
457 		break;
458 	case DEBOUNCE_STATE_IS_DOWN_DELAYING:
459 		debounce_is_down_delaying_handle_event(fallback, event, time);
460 		break;
461 	case DEBOUNCE_STATE_DISABLED:
462 		debounce_disabled_handle_event(fallback, event, time);
463 		break;
464 	}
465 
466 	evdev_log_debug(fallback->device,
467 			"debounce state: %s → %s → %s\n",
468 			debounce_state_to_str(current),
469 			debounce_event_to_str(event),
470 			debounce_state_to_str(fallback->debounce.state));
471 }
472 
473 void
fallback_debounce_handle_state(struct fallback_dispatch * dispatch,uint64_t time)474 fallback_debounce_handle_state(struct fallback_dispatch *dispatch,
475 			       uint64_t time)
476 {
477 	unsigned int changed[16] = {0}; /* event codes of changed buttons */
478 	size_t nchanged = 0;
479 	bool flushed = false;
480 
481 	for (unsigned int code = 0; code <= KEY_MAX; code++) {
482 		if (get_key_type(code) != KEY_TYPE_BUTTON)
483 			continue;
484 
485 		if (hw_key_has_changed(dispatch, code))
486 			changed[nchanged++] = code;
487 
488 		/* If you manage to press more than 16 buttons in the same
489 		 * frame, we just quietly ignore the rest of them */
490 		if (nchanged == ARRAY_LENGTH(changed))
491 			break;
492 	}
493 
494 	/* If we have more than one button this frame or a different button,
495 	 * flush the state machine with otherbutton */
496 	if (nchanged > 1 ||
497 	    changed[0] != dispatch->debounce.button_code) {
498 		debounce_handle_event(dispatch,
499 				      DEBOUNCE_EVENT_OTHERBUTTON,
500 				      time);
501 		flushed = true;
502 	}
503 
504 	/* The state machine has some pre-conditions:
505 	 * - the IS_DOWN and IS_UP states are neutral entry states without
506 	 *   any timeouts
507 	 * - a OTHERBUTTON event always flushes the state to IS_DOWN or
508 	 *   IS_UP
509 	 */
510 
511 	for (size_t i = 0; i < nchanged; i++) {
512 		bool is_down = hw_is_key_down(dispatch, changed[i]);
513 
514 		if (flushed &&
515 		    dispatch->debounce.state != DEBOUNCE_STATE_DISABLED) {
516 			debounce_set_state(dispatch,
517 					   !is_down ?
518 						   DEBOUNCE_STATE_IS_DOWN :
519 						   DEBOUNCE_STATE_IS_UP);
520 			flushed = false;
521 		}
522 
523 		dispatch->debounce.button_code = changed[i];
524 		debounce_handle_event(dispatch,
525 				      is_down ?
526 					      DEBOUNCE_EVENT_PRESS :
527 					      DEBOUNCE_EVENT_RELEASE,
528 				      time);
529 
530 		/* if we have more than one event, we flush the state
531 		 * machine immediately after the event itself */
532 		if (nchanged > 1) {
533 			debounce_handle_event(dispatch,
534 					      DEBOUNCE_EVENT_OTHERBUTTON,
535 					      time);
536 			flushed = true;
537 		}
538 
539 	}
540 }
541 
542 static void
debounce_timeout(uint64_t now,void * data)543 debounce_timeout(uint64_t now, void *data)
544 {
545 	struct evdev_device *device = data;
546 	struct fallback_dispatch *dispatch =
547 		fallback_dispatch(device->dispatch);
548 
549 	debounce_handle_event(dispatch, DEBOUNCE_EVENT_TIMEOUT, now);
550 }
551 
552 static void
debounce_timeout_short(uint64_t now,void * data)553 debounce_timeout_short(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_SHORT, now);
560 }
561 
562 void
fallback_init_debounce(struct fallback_dispatch * dispatch)563 fallback_init_debounce(struct fallback_dispatch *dispatch)
564 {
565 	struct evdev_device *device = dispatch->device;
566 	char timer_name[64];
567 
568 	if (evdev_device_has_model_quirk(device, QUIRK_MODEL_BOUNCING_KEYS)) {
569 		dispatch->debounce.state = DEBOUNCE_STATE_DISABLED;
570 		return;
571 	}
572 
573 	dispatch->debounce.state = DEBOUNCE_STATE_IS_UP;
574 
575 	snprintf(timer_name,
576 		 sizeof(timer_name),
577 		 "%s debounce short",
578 		 evdev_device_get_sysname(device));
579 	libinput_timer_init(&dispatch->debounce.timer_short,
580 			    evdev_libinput_context(device),
581 			    timer_name,
582 			    debounce_timeout_short,
583 			    device);
584 
585 	snprintf(timer_name,
586 		 sizeof(timer_name),
587 		 "%s debounce",
588 		 evdev_device_get_sysname(device));
589 	libinput_timer_init(&dispatch->debounce.timer,
590 			    evdev_libinput_context(device),
591 			    timer_name,
592 			    debounce_timeout,
593 			    device);
594 }
595