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