Per-app overrides ignored for HID++ gesture sources (GestureButton / HapticPanel)
- Dominant language
- Rust
- Stars
- 21k
- Forks
- 675
- Avg merge
- 2d 5h
- Merged PRs (30d)
- 172
Description
**Summary**
`hidpp_gesture_maps_for()` ignores per-app overlays (`per_app_bindings`), so a per-app override of a dedicated HID++ gesture source (GestureButton / HapticPanel) never takes effect.
**Reproduction** (no app-specific setup required)
1. Device with a dedicated HID++ gesture source (e.g. MX Master series — GestureButton).
2. Add a per-app override for any app, e.g.:
```toml
[devices."direct:046d:b034:serial:…".per_app_bindings."com.example.MyApp"]
GestureButton = { RunShellCommand = "/usr/bin/true" }
# any Single action reproduces — RunShellCommand, KeyPress, etc.
```
3. Focus `com.example.MyApp` and press the GestureButton click.
4. Observe: the global seeded default still fires (on macOS: App Exposé / Mission Control for GestureButton Click), not the per-app action. Removing the per-app block or setting the same override globally works — only the per-app path is broken.
Minimal programmatic repro: `hidpp_gesture_maps_for(&cfg, Some(key), Some("com.example.MyApp"))` still contains `GestureButton` after `set_per_app_binding(key, "com.example.MyApp", GestureButton, Some(Action::RunShellCommand(…)))`.
**Expected**
Like OS-hook gesture buttons (`oshook_gestures_for` / `bindings_for`), a per-app `Single` override should drop that source from the app's gesture set — the capture plan then diverts it as a plain HID++ source so the press dispatches via `plan.bindings` with the per-app action. This is already documented for `oshook_gestures_for` and for the plain-divert fallback in `capture_plan.rs`.
**Actual**
- `plan_for_device(config, key, route, app, …)` receives `app: Option<&str>` and correctly passes it to `bindings_for(…, app)` and `oshook_gestures_for(…, app)`.
- But `hidpp_gesture_maps_for(config, key)` takes no `app_bundle` at all and resolves against `config.bindings_for(key)` (global only). The source therefore stays in gesture mode forever; `watchers/gesture.rs` resolves the Click via `plan.gesture_bindings[GestureButton][Click]` → seeded default.
**Evidence**
```
bindings_for(config, key, app) → effective_bindings(key, app) ✓
oshook_gestures_for(config, key, app) → effective_bindings(key, app) ✓
hidpp_gesture_maps_for(config, key) → bindings_for(key) ✗
```
`crates/openlogi-core/src/bindings.rs:57`, `crates/openlogi-agent-core/src/capture_plan.rs:70`
**Impact**
Any per-app action bound to a HID++ gesture source is unreachable (GestureButton-Click and any per-app override of the HapticPanel source). Workaround is none — only a global override works, which defeats per-app bindings.
**Proposed fix**
Thread `app_bundle: Option<&str>` through `hidpp_gesture_maps_for` → `effective_bindings(key, app_bundle)`, and call it with `app` from `plan_for_device`. A `Binding::Single` for that app then naturally drops the key from the per-app gesture map (existing `Single ⇒ None` arm), matching `oshook_gestures_for`'s documented contract.
**Environment**
OpenLogi `master` @ `2f459d7` (v0.7.10), macOS, MX Master series (any device with a HID++ gesture source).
Contributor guide
No contributing guide indexed for this repository
Research direction
Start in crates/openlogi-core/src/bindings.rs and crates/openlogi-agent-core/src/capture_plan.rs, tracing hidpp_gesture_maps_for from plan_for_device alongside oshook_gestures_for and bindings_for. Verify the programmatic reproduction with an app-specific Single binding; done means the HID++ source is removed from the app's gesture map and dispatches through plan.bindings with the per-app action.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- embedded-iot
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 76/100