From a1710d870c6ec99fd1246bde0656d63d4e267ad1 Mon Sep 17 00:00:00 2001 From: ThinkChaos Date: Mon, 25 Nov 2024 12:04:11 -0500 Subject: [PATCH] quirks: allow tweaking the debounce timeouts Add `AttrBouncingTimeoutMs` and `AttrBouncingTimeoutSpuriousMs` to allow quirks to change the debounce timeouts. The goal is to allow users to workaround defective hardware by increasing `AttrBouncingTimeoutMs` enough for what they observe. --- doc/user/button-debouncing.rst | 24 ++++++++++++++++++++++++ doc/user/device-quirks.rst | 19 +++++++++++++++++++ src/evdev-debounce.c | 32 ++++++++++++++++++++++++-------- src/evdev-fallback.h | 2 ++ src/quirks.c | 16 ++++++++++++++++ src/quirks.h | 2 ++ tools/shared.c | 2 ++ 7 files changed, 89 insertions(+), 8 deletions(-) diff --git a/doc/user/button-debouncing.rst b/doc/user/button-debouncing.rst index 47be1d2c..f3657013 100644 --- a/doc/user/button-debouncing.rst +++ b/doc/user/button-debouncing.rst @@ -54,3 +54,27 @@ correspond to the buttons 'pressed' and 'released' states, respectively. Some devices send events in bursts, erroneously triggering the button debouncing detection. Please :ref:`file a bug ` if that occurs for your device. + +------------------------------------------------------------------------------ +Configuration (via Quirks) +------------------------------------------------------------------------------ + +.. warning:: Quirks are an internal API, they come with no + backwards-compatibility guarantees or support for configuration. + Read the full :ref:`device-quirks` section before using. + Do NOT try to upstream your debouncing timeouts! + +It is possible to configure the timeouts used by both debouncing methods with +quirks. +Use ``libinput record`` to figure out the timing of bounced events. +Then increase the "bounce" timeout quirk to be larger than that, but smaller +than the fastest double click you can perform manually. + +Example quirk: :: + + [My Borked Mouse] + MatchUdevType=mouse + MatchBus=usb + MatchName=*MyBorkedMouse* + ModelBouncingKeys=1 + AttrBouncingTimeoutMs=100 diff --git a/doc/user/device-quirks.rst b/doc/user/device-quirks.rst index 8ae8af04..635354c6 100644 --- a/doc/user/device-quirks.rst +++ b/doc/user/device-quirks.rst @@ -142,9 +142,14 @@ ModelTabletModeSwitchUnreliable Indicates that this tablet mode switch's state cannot be relied upon. ModelTrackball Reserved for trackballs + +.. _device-quirks-ModelBouncingKeys: + ModelBouncingKeys Indicates that the device may send fake bouncing key events and timestamps can not be relied upon. + See also :ref:`device-quirks-AttrBouncingTimeoutMs` and + :ref:`device-quirks-AttrBouncingTimeoutSpuriousMs`. ModelSynapticsSerialTouchpad Reserved for touchpads made by Synaptics on the serial bus ModelPressurePad @@ -202,6 +207,20 @@ AttrTabletSmoothing=1|0 Enables (1) or disables (0) input smoothing for tablet devices. Smoothing is enabled by default, except on AES devices. +.. _device-quirks-AttrBouncingTimeoutMs: + +AttrBouncingTimeoutMs + Timeout (in milliseconds) for the "bounce" debouncing method. + See :ref:`button_debouncing` for details. + Only applies when :ref:`device-quirks-ModelBouncingKeys` is enabled. + +.. _device-quirks-AttrBouncingTimeoutSpuriousMs: + +AttrBouncingTimeoutSpuriousMs + Timeout (in milliseconds) for the "spurious" debouncing method. + See :ref:`button_debouncing` for details. + Only applies when :ref:`device-quirks-ModelBouncingKeys` is enabled. + .. _device-quirks-matches: ------------------------------------------------------------------------------ diff --git a/src/evdev-debounce.c b/src/evdev-debounce.c index 32ca0eb3..00c17a10 100644 --- a/src/evdev-debounce.c +++ b/src/evdev-debounce.c @@ -126,20 +126,16 @@ static inline void debounce_set_timer(struct fallback_dispatch *fallback, uint64_t time) { - const int DEBOUNCE_TIMEOUT_BOUNCE = ms2us(25); - libinput_timer_set(&fallback->debounce.timer, - time + DEBOUNCE_TIMEOUT_BOUNCE); + time + fallback->debounce.timeout_bounce); } static inline void debounce_set_timer_short(struct fallback_dispatch *fallback, uint64_t time) { - const int DEBOUNCE_TIMEOUT_SPURIOUS = ms2us(12); - libinput_timer_set(&fallback->debounce.timer_short, - time + DEBOUNCE_TIMEOUT_SPURIOUS); + time + fallback->debounce.timeout_spurious); } static inline void @@ -573,14 +569,28 @@ void fallback_init_debounce(struct fallback_dispatch *dispatch) { struct evdev_device *device = dispatch->device; + struct quirks_context *quirks = evdev_libinput_context(device)->quirks; + struct quirks *q = quirks_fetch_for_device(quirks, device->udev_device); + bool disabled = false; + bool has_spurious_quirk = false; + uint32_t timeout_ms = 25; + uint32_t timeout_spurious_ms = 12; char timer_name[64]; - if (evdev_device_has_model_quirk(device, QUIRK_MODEL_BOUNCING_KEYS)) { + quirks_get_bool(q, QUIRK_MODEL_BOUNCING_KEYS, &disabled); + if (disabled) { dispatch->debounce.state = DEBOUNCE_STATE_DISABLED; - return; + goto end; } + quirks_get_uint32(q, QUIRK_ATTR_BOUNCING_TIMEOUT_MS, &timeout_ms); + has_spurious_quirk = quirks_get_uint32(q, + QUIRK_ATTR_BOUNCING_TIMEOUT_SPURIOUS_MS, + &timeout_spurious_ms); + dispatch->debounce.state = DEBOUNCE_STATE_IS_UP; + dispatch->debounce.timeout_bounce = ms2us(timeout_ms); + dispatch->debounce.timeout_spurious = ms2us(timeout_spurious_ms); snprintf(timer_name, sizeof(timer_name), @@ -601,4 +611,10 @@ fallback_init_debounce(struct fallback_dispatch *dispatch) timer_name, debounce_timeout, device); + + if (has_spurious_quirk) + debounce_enable_spurious(dispatch); + +end: + quirks_unref(q); } diff --git a/src/evdev-fallback.h b/src/evdev-fallback.h index 519ae0a9..5026da28 100644 --- a/src/evdev-fallback.h +++ b/src/evdev-fallback.h @@ -145,6 +145,8 @@ struct fallback_dispatch { uint64_t button_time; struct libinput_timer timer; struct libinput_timer timer_short; + uint32_t timeout_bounce; + uint32_t timeout_spurious; enum debounce_state state; bool spurious_enabled; } debounce; diff --git a/src/quirks.c b/src/quirks.c index 2bb37b4f..15e12c43 100644 --- a/src/quirks.c +++ b/src/quirks.c @@ -292,6 +292,8 @@ quirk_get_name(enum quirk q) case QUIRK_ATTR_MSC_TIMESTAMP: return "AttrMscTimestamp"; case QUIRK_ATTR_EVENT_CODE: return "AttrEventCode"; case QUIRK_ATTR_INPUT_PROP: return "AttrInputProp"; + case QUIRK_ATTR_BOUNCING_TIMEOUT_MS: return "AttrBouncingTimeoutMs"; + case QUIRK_ATTR_BOUNCING_TIMEOUT_SPURIOUS_MS: return "AttrBouncingTimeoutSpuriousMs"; default: abort(); } @@ -878,6 +880,20 @@ parse_attr(struct quirks_context *ctx, p->value.tuples.ntuples = nprops; p->type = PT_TUPLES; + rc = true; + } else if (streq(key, quirk_get_name(QUIRK_ATTR_BOUNCING_TIMEOUT_MS))) { + p->id = QUIRK_ATTR_BOUNCING_TIMEOUT_MS; + if (!safe_atou(value, &v)) + goto out; + p->type = PT_UINT; + p->value.u = v; + rc = true; + } else if (streq(key, quirk_get_name(QUIRK_ATTR_BOUNCING_TIMEOUT_SPURIOUS_MS))) { + p->id = QUIRK_ATTR_BOUNCING_TIMEOUT_SPURIOUS_MS; + if (!safe_atou(value, &v)) + goto out; + p->type = PT_UINT; + p->value.u = v; rc = true; } else { qlog_error(ctx, "Unknown key %s in %s\n", key, s->name); diff --git a/src/quirks.h b/src/quirks.h index 340d0463..a6fcade3 100644 --- a/src/quirks.h +++ b/src/quirks.h @@ -109,6 +109,8 @@ enum quirk { QUIRK_ATTR_MSC_TIMESTAMP, QUIRK_ATTR_EVENT_CODE, QUIRK_ATTR_INPUT_PROP, + QUIRK_ATTR_BOUNCING_TIMEOUT_MS, + QUIRK_ATTR_BOUNCING_TIMEOUT_SPURIOUS_MS, _QUIRK_LAST_ATTR_QUIRK_, /* Guard: do not modify */ }; diff --git a/tools/shared.c b/tools/shared.c index 327005ed..1e5a3b8c 100644 --- a/tools/shared.c +++ b/tools/shared.c @@ -899,6 +899,8 @@ tools_list_device_quirks(struct quirks_context *ctx, case QUIRK_ATTR_PALM_PRESSURE_THRESHOLD: case QUIRK_ATTR_THUMB_PRESSURE_THRESHOLD: case QUIRK_ATTR_THUMB_SIZE_THRESHOLD: + case QUIRK_ATTR_BOUNCING_TIMEOUT_MS: + case QUIRK_ATTR_BOUNCING_TIMEOUT_SPURIOUS_MS: quirks_get_uint32(quirks, q, &v); snprintf(buf, sizeof(buf), "%s=%u", name, v); callback(userdata, buf);