Skip to content

Rework swipe-gesture recognition and speed up HID++ device detection#184

Open
laziukdavid wants to merge 1 commit into
TomBadash:masterfrom
laziukdavid:mxm4-improvements
Open

Rework swipe-gesture recognition and speed up HID++ device detection#184
laziukdavid wants to merge 1 commit into
TomBadash:masterfrom
laziukdavid:mxm4-improvements

Conversation

@laziukdavid
Copy link
Copy Markdown

@laziukdavid laziukdavid commented May 19, 2026

Summary

This PR adds two core reliability/performance reworks, plus a few smaller
improvements, all developed and tested against an MX Master 4 (Logi Bolt
receiver, receiver PID 0xC548).

Core changes

Swipe-gesture recognizer rewrite

The old gesture-button swipe logic summed every movement delta into one running
total, fired when it crossed gesture_threshold, then blocked input for a
fixed cooldown. That dropped inputs (the cooldown swallowed the start of the
next swipe), produced false positives (slow drift summed past threshold; the
return stroke between two swipes fired the opposite direction), and made
back-to-back repeats impossible.

  • New core/gesture_recognizer.py — a pure, thread-safe GestureRecognizer
    that segments motion into strokes instead of integrating one global sum.
    A stroke commits a swipe on threshold travel along one axis within a commit
    window and within an off-axis ratio; a peak detector fires every fresh flick
    while return strokes only re-arm it; a pause clears the lock. No cooldown.
  • Shared by the macOS, Windows and Linux hooks — removes the triplicated
    _accumulate_gesture_delta / _detect_gesture_event code.
  • Click-jolt rejection (minimum movement-report count) and quick-flick capture
    fix phantom swipes on a tap and missed swipes during a fast flick.
  • Config schema v9 → v10: retires gesture_deadzone / gesture_timeout_ms
    / gesture_cooldown_ms; adds gesture_commit_window_ms, gesture_settle_ms,
    gesture_cross_ratio. Obsolete keys in existing configs are left ignored.
  • The raw gesture_threshold px slider is replaced with a discrete 5-level
    Sensitivity dropdown (stored key/units unchanged).

HID++ detection speed

Cold-start connection on a setup with several Logitech receivers was ~46s,
almost entirely spent probing the wrong devices before reaching the mouse.

  • Receiver-aware device-index scan order
  • Persistent device cache (device_cache.json) so a relaunch / reconnect goes
    straight to the last-good device
  • Dead-slot early-out — stop probing a slot once its control-count read fails
  • 600ms discovery probe timeout applied across the whole discovery phase
    (operational requests keep the 2s timeout)
  • Candidate dedup — a multi-interface device (e.g. a webcam exposing vendor
    usage pages) is opened once, not once per interface

Additional changes

  • Screenshot action — new screenshot action: Cmd+Shift+4 on macOS,
    Win+Shift+S on Windows.
  • Application Log panelcore/log_setup.py ring-buffer log handler with
    listener fan-out; appLog property on the QML backend; a new
    "Application Log" section in the Debug Events panel showing captured console
    output alongside the existing mouse-events log.
  • macOS Accessibility auto-recovery — first launch after granting
    Accessibility used to leave the app dead until a manual quit/reopen. Now: a
    non-modal prompt with a deep link to the Accessibility pane, a 1s grant poll,
    and a clean re-exec once the grant lands.
  • macOS buildbuild_macos_app.sh redirects build artifacts off network
    volumes to local disk (codesign rejects the resource-fork metadata SMB/AFP
    shares attach); auto-detects a non-local repo volume, overridable with
    MOUSER_BUILD_DIR. New install_macos_app.sh, a documented build +
    install-to-/Applications wrapper.

Testing

  • Full suite green: python3 -m pytest tests/ → 555 passed, 1 skipped
  • New tests: test_gesture_recognizer.py (21), plus additions to
    test_hid_gesture.py, test_config.py, test_log_setup.py,
    test_backend.py, test_macos_app_shell.py, test_key_simulator.py
  • Several features are verified by tests but not yet hardware-verified across
    every platform — feedback welcome.

🤖 Generated with Claude Code

@laziukdavid laziukdavid changed the title Add MX Master 4 support: HID++ detection, gesture recognizer, UI & build fixes Rework swipe-gesture recognition and speed up HID++ device detection May 19, 2026
…ild fixes

A multi-feature set developed and tested against a Logitech MX Master 4
(via a Logi Bolt receiver). Summary by area:

HID++ detection speed
- Receiver-aware device-index scan order, persistent device cache
  (device_cache.json), dead-slot early-out, 600ms discovery probe timeout
  applied across the whole discovery phase, and candidate dedup so a
  multi-interface device is probed once. Cuts cold-start connection from
  ~46s of wrong-device probing.

Gesture swipe recognizer
- New core/gesture_recognizer.py: a pure, thread-safe, stroke-segmenting
  GestureRecognizer replacing the old global-sum + fixed-cooldown logic
  (which dropped inputs, fired the opposite direction on return strokes,
  and could not do back-to-back repeats). Shared by the macOS, Windows and
  Linux hooks, removing the triplicated accumulate/detect code.
- Config schema v9 -> v10: retires gesture_deadzone / gesture_timeout_ms /
  gesture_cooldown_ms; adds gesture_commit_window_ms, gesture_settle_ms,
  gesture_cross_ratio. Obsolete keys in existing configs are left ignored.
- Click-jolt rejection (min sample count) and quick-flick capture.

Sensitivity selector
- Replaces the raw gesture_threshold px slider with a discrete 5-level
  Sensitivity dropdown. Stored key/units unchanged.

Screenshot action
- New screenshot action: Cmd+Shift+4 on macOS, Win+Shift+S on Windows.

Application Log panel
- core/log_setup.py ring-buffer log handler with listener fan-out; appLog
  property on the QML backend; a new Application Log section in the
  Debug Events panel showing captured console output.

macOS Accessibility auto-recovery
- Non-modal permission prompt with a deep link to the Accessibility pane,
  a 1s grant poll, and a clean re-exec once the grant lands -- no manual
  quit/reopen after granting Accessibility on first launch.

macOS build
- build_macos_app.sh redirects all build artifacts off network volumes to
  local disk (codesign rejects the resource-fork metadata SMB/AFP shares
  attach); auto-detects a non-local repo volume, overridable via
  MOUSER_BUILD_DIR.
- New install_macos_app.sh: a documented build + install-to-/Applications
  wrapper around build_macos_app.sh.

Tests: full suite green -- 555 passed, 1 skipped.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@laziukdavid laziukdavid marked this pull request as ready for review May 19, 2026 02:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant