Thumb-wheel tap is bindable but has nowhere to bind it in the GUI
- Dominant language
- Rust
- Stars
- 21k
- Forks
- 675
- Avg merge
- 2d 5h
- Merged PRs (30d)
- 172
Description
## Problem
`ButtonId::Thumbwheel` — the wheel's capacitive tap — is a real, dispatchable binding with no way to reach it from the GUI. The only way to set it is by hand:
```toml
[devices."receiver:aabbccdd:slot:1".bindings]
Thumbwheel = "AppExpose"
```
So the feature exists, works, is documented in `docs/CONFIGURATION.md`, and is undiscoverable.
## How we got here
#857 seeded the tap with `Action::None` because it was seeded with `AppExpose` and firing from incidental thumb contact (#340, #435, #477, #641). That was the right fix for the bug — an invisible control must not carry a live action — but it settles the tap at "inert and invisible" rather than "visible and yours to set". #340's proposal had a second half, exposing the tap as its own control, which did not land and is not tracked anywhere else.
## Constraint: there is one wheel slot, and we don't invent coordinates
Hotspots come from the device render's Logi metadata, mapped in `geometry.rs`:
```rust
"SLOT_NAME_THUMBWHEEL" => Some(MouseControlId::ThumbwheelRotation),
```
Logi ships exactly one thumb-wheel assignment, and `asset_hotspots_for_png` deliberately emits only what the metadata yields — we do not synthesise marker positions for controls the asset does not place (that rule came out of the primary-click markers, which looked permanently misaligned when guessed).
So "add a third hotspot next to Up and Down" is not the shape. `MouseControlId` already collapses `ThumbwheelScrollUp` / `ThumbwheelScrollDown` into the single `ThumbwheelRotation` target for exactly this reason.
## Proposed shape
Keep one wheel hotspot on the diagram; let its popover carry both controls:
- **Rotation** — the existing paired preset picker, unchanged.
- **Tap** — an action picker, defaulting to "Do Nothing".
Worth deciding as part of this: the tap picker should probably say that assigning it takes the wheel off native scrolling. Any non-default thumb-wheel binding arms the `0x2150` divert, after which OpenLogi re-synthesises horizontal scroll rather than the firmware producing it. That is already true for a rotation rebind; binding a tap makes it true for people who only wanted a tap.
Devices whose wheel reports `supports_single_tap: false` (MX Master 4, for one — confirmed on hardware in #857) can never deliver the tap. The capability is read at arm time today and only logged; the picker should be hidden or disabled for those wheels rather than offering a control that silently does nothing.
## Scope
- [ ] `MouseControlId` / `hotspots.rs`: a target for the tap that shares the wheel's hotspot
- [ ] `picker.rs` / `view.rs`: the second row in the wheel popover
- [ ] Gate on the wheel's single-tap capability (needs plumbing — `supports_single_tap` is read in `arm_controls_into` and dropped)
- [ ] Locale strings across all 21 `crates/openlogi-ui/locales/*.yml` (`"Thumb Wheel"` already exists as the `ButtonId::Thumbwheel` label; a tap row likely wants its own string)
- [ ] `README.md`: "Capture and remap the middle, mode-shift, and thumbwheel buttons" currently overstates the thumb-wheel tap, which is TOML-only until this ships
Follow-up to #340.
Contributor guide
No contributing guide indexed for this repository
Research direction
Start with geometry.rs and hotspots.rs to understand how the existing wheel hotspot is represented, then trace picker.rs, view.rs, and arm_controls_into for the popover and single-tap capability. Implement the shared hotspot with rotation and tap controls, gate tap assignment for unsupported wheels, update all 21 locale files and README.md, and verify that the existing rotation picker 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
- 55/100