• 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 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 
65 enum 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 
73 static inline const char *
debounce_state_to_str(enum debounce_state state)74 debounce_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 
92 static inline const char*
debounce_event_to_str(enum debounce_event event)93 debounce_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 
105 static inline void
log_debounce_bug(struct fallback_dispatch * fallback,enum debounce_event event)106 log_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 
115 static inline void
debounce_set_state(struct fallback_dispatch * fallback,enum debounce_state new_state)116 debounce_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 
125 static inline void
debounce_set_timer(struct fallback_dispatch * fallback,uint64_t time)126 debounce_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 
135 static inline void
debounce_set_timer_short(struct fallback_dispatch * fallback,uint64_t time)136 debounce_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 
145 static inline void
debounce_cancel_timer(struct fallback_dispatch * fallback)146 debounce_cancel_timer(struct fallback_dispatch *fallback)
147 {
148 	libinput_timer_cancel(&fallback->debounce.timer);
149 }
150 
151 static inline void
debounce_cancel_timer_short(struct fallback_dispatch * fallback)152 debounce_cancel_timer_short(struct fallback_dispatch *fallback)
153 {
154 	libinput_timer_cancel(&fallback->debounce.timer_short);
155 }
156 
157 static inline void
debounce_enable_spurious(struct fallback_dispatch * fallback)158 debounce_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 
171 static void
debounce_notify_button(struct fallback_dispatch * fallback,enum libinput_button_state state)172 debounce_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 
184 static void
debounce_is_up_handle_event(struct fallback_dispatch * fallback,enum debounce_event event,uint64_t time)185 debounce_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 
205 static void
debounce_is_down_handle_event(struct fallback_dispatch * fallback,enum debounce_event event,uint64_t time)206 debounce_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 
233 static void
debounce_is_down_waiting_handle_event(struct fallback_dispatch * fallback,enum debounce_event event,uint64_t time)234 debounce_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 
259 static void
debounce_is_up_delaying_handle_event(struct fallback_dispatch * fallback,enum debounce_event event,uint64_t time)260 debounce_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 
280 static void
debounce_is_up_delaying_spurious_handle_event(struct fallback_dispatch * fallback,enum debounce_event event,uint64_t time)281 debounce_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 
306 static void
debounce_is_up_detecting_spurious_handle_event(struct fallback_dispatch * fallback,enum debounce_event event,uint64_t time)307 debounce_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 
333 static void
debounce_is_down_detecting_spurious_handle_event(struct fallback_dispatch * fallback,enum debounce_event event,uint64_t time)334 debounce_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 
361 static void
debounce_is_up_waiting_handle_event(struct fallback_dispatch * fallback,enum debounce_event event,uint64_t time)362 debounce_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 
383 static void
debounce_is_down_delaying_handle_event(struct fallback_dispatch * fallback,enum debounce_event event,uint64_t time)384 debounce_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 
406 static void
debounce_disabled_handle_event(struct fallback_dispatch * fallback,enum debounce_event event,uint64_t time)407 debounce_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 
431 static void
debounce_handle_event(struct fallback_dispatch * fallback,enum debounce_event event,uint64_t time)432 debounce_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 
483 void
fallback_debounce_handle_state(struct fallback_dispatch * dispatch,uint64_t time)484 fallback_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 
552 static void
debounce_timeout(uint64_t now,void * data)553 debounce_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 
562 static void
debounce_timeout_short(uint64_t now,void * data)563 debounce_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 
572 void
fallback_init_debounce(struct fallback_dispatch * dispatch)573 fallback_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