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