AprilNEA / AprilNEA/OpenLogi

Feature: allow consecutive swipes during a single gesture button hold

Open
#969 3 comments 4 reactions 0 assignees View on GitHub
platform: all type: feature
Dominant language
Rust
Stars
21k
Forks
675
Avg merge
2d 5h
Merged PRs (30d)
172

Description

## Problem

Currently `SwipeAccumulator` commits a direction exactly once per hold: after a swipe fires, the `fired` latch blocks all further travel until the button is released and pressed again. This means switching workspaces (or any repeated directional action) requires a full release-and-repress cycle for each step.

Logitech Options+ allows holding the gesture button and swiping multiple times in one continuous press — e.g. swiping right repeatedly to jump several desktops, or up/down to cycle through several workspaces.

I ran into this myself on an MX Master 4 (Bolt receiver, Linux/niri) and implemented the fix locally so I could move between workspaces without releasing the gesture button each time. I did not open an issue back then, but coming across [this comment](https://github.com/AprilNEA/OpenLogi/pull/719#issuecomment-5404225694) from another user describing the exact same workflow gap made me realise it is worth reporting.

## Proposed behaviour

After a swipe commits, reset the accumulator (`dx`/`dy` → 0) so the next swipe can fire within the same hold — without releasing the button. A short cooldown (~100–120 ms) after each commit prevents residual hand momentum from immediately re-crossing the threshold and firing a duplicate. The release at the end of the hold must not trigger a `Click` if any swipe fired during it.

This should be opt-in rather than replacing the default behaviour outright — some users may prefer the current one-swipe-per-hold model (e.g. to avoid accidental repeated triggers). A config toggle (e.g. `multi_swipe = true` under the gesture bindings section) and a corresponding checkbox in the GUI settings would let each user choose.

## Implementation notes

- `SwipeAccumulator` in `crates/openlogi-core/src/binding/swipe.rs`: replace the `fired: bool` latch with `ever_fired: bool` (tracks whether *any* swipe fired this hold, used by `end()` to suppress click) and reset `dx`/`dy` to 0 after each commit.
- A `cooldown_until: Option` field gates `accumulate()`: during the cooldown window, incoming samples are discarded entirely (hand is still settling).
- `GESTURE_SWIPE_COOLDOWN` constant (~120 ms) alongside the existing `GESTURE_HOLD_FOR_SWIPE`.
- Config: a per-device `multi_swipe` boolean (default `false`), plumbed through to the capture session.
- GUI: a toggle in the gesture bindings settings panel.

Contributor guide

No contributing guide indexed for this repository

Research direction

Start with SwipeAccumulator and the existing GESTURE_HOLD_FOR_SWIPE constant in crates/openlogi-core/src/binding/swipe.rs, then trace gesture bindings into the capture session. Find the per-device config and gesture bindings settings panel to follow the multi_swipe value through core and GUI. Done means consecutive swipes work during one hold, cooldown prevents duplicate triggers, release suppresses Click after any swipe, and the default remains unchanged.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
desktop
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
66/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.