Skip to content

shake gesture never triggers on devices with kernel key autorepeat (EV_REP) #16

Description

@PlinioL

On Linux, MouseInterceptor treats any BTN_LEFT event whose value is not 1 as a button release. The kernel emits BTN_LEFT with value == 2 (autorepeat) on input devices that advertise EV_REP. Every autorepeat event therefore clears mLeftButtonClicked and calls mShakeDetector.reset(), which makes the shake gesture impossible to complete on those devices.

Environment
Zorin OS (Ubuntu based), X11 session
Tokri v2026.03.01, Flatpak bundle
Logitech MX Master 3 over Bluetooth
User in the input group, Flatpak granted --device=all
Root cause

src/linuxmouseinterceptor.cpp:

cpp
if (event.type == EV_KEY){
if (event.code == BTN_LEFT){
if (event.value == 1){
mLeftButtonClicked = true;
} else { // value == 2 (autorepeat) lands here
mLeftButtonClicked = false;
mShakeDetector.reset();
}
}
}

evdev defines three values for EV_KEY: 0 release, 1 press, 2 autorepeat. The else branch swallows 2.

The MX Master 3 registers a keyboard interface alongside the pointer (Handlers=sysrq kbd mouse1 event14) and has EV_REP set:

I: Bus=0005 Vendor=046d Product=b023 Version=0015
N: Name="Logitech Wireless Mouse MX Master 3"
H: Handlers=sysrq kbd mouse1 event14
B: EV=100017 <-- bit 0x14 (EV_REP) is set
Evidence

evtest capture during a single continuous drag, button never physically released:

Event: time 1785528143.641209, type 1 (EV_KEY), code 272 (BTN_LEFT), value 1
Event: time 1785528143.895010, type 1 (EV_KEY), code 272 (BTN_LEFT), value 2
Event: time 1785528143.928954, type 1 (EV_KEY), code 272 (BTN_LEFT), value 2
Event: time 1785528143.963005, type 1 (EV_KEY), code 272 (BTN_LEFT), value 2
Event: time 1785528143.996953, type 1 (EV_KEY), code 272 (BTN_LEFT), value 2
...

First repeat arrives 254 ms after the press (kernel REP_DELAY), then every 33 ms (REP_PERIOD). Value distribution over the whole capture:

  2 x value 0
  2 x value 1
208 x value 2

HorizontalShakeDetector needs 3 direction flips with at most 200 ms between qualifying events. Since the detector is reset every 33 ms, the flip counter can never reach 3 — regardless of how the user performs the gesture. The motion data itself was well within range (hundreds of REL_X events with 8 <= |dx| <= 100, none above 100).

Proposed fix
cpp
if (event.code == BTN_LEFT){
if (event.value == 1 || event.value == 2){ // press or autorepeat
mLeftButtonClicked = true;
} else {
mLeftButtonClicked = false;
mShakeDetector.reset();
}
}

Optionally ignore value == 2 entirely, since it carries no state change.

Notes
Windows and macOS interceptors are unaffected; they do not go through evdev.
Workaround for users: disable autorepeat on the device with EVIOCSREP set to {0, 0}. This has to be reapplied on every reconnect.
Devices without EV_REP (most plain mice) never hit this path, which is probably why it went unnoticed.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions