feat: add mouse buttons 6–9 as pickable actions#335
Conversation
Add an approved design for emitting mouse buttons 6–9 as pickable actions. Approach A — four unit variants mirroring MouseBack/ MouseForward — surfaced through the existing data-driven action stack (catalog/category/picker/inject). macOS and Linux get full support; Windows is a documented log-and-skip gap (SendInput caps at button 5).
…g-and-skip) macOS: post_other_button(5..=8) via MOUSE_EVENT_BUTTON_NUMBER. Linux: evdev BTN_FORWARD/BACK/TASK/0. Windows: SendInput caps at button 5, so log-and-skip (documented gap, same pattern as macOS-only navigation actions).
Reuses the generic mouse.svg icon (same as MiddleClick). The picker's icon match is exhaustive with no wildcard, so this is compiler-forced: the build cannot succeed without it once the variants exist.
Each locale uses its own word for 'button' (derived from its existing 'Back (Button 4)' entry). For locales whose existing word includes a 'side' modifier (ja サイドボタン, ru боковая кнопка, zh-* 侧键/側鍵) the plain button/key word is used, since buttons 6-9 are not side buttons.
Greptile SummaryThis PR adds pickable actions for mouse buttons 6 through 9. The main changes are:
Confidence Score: 5/5This looks safe to merge.
Important Files Changed
Reviews (2): Last reviewed commit: "feat(gui): add Button 6-9 translation ke..." | Re-trigger Greptile |
| Action::MouseButton6 => linux::click(KeyCode::BTN_FORWARD), | ||
| Action::MouseButton7 => linux::click(KeyCode::BTN_BACK), | ||
| Action::MouseButton8 => linux::click(KeyCode::BTN_TASK), | ||
| Action::MouseButton9 => linux::click(KeyCode::BTN_0), |
There was a problem hiding this comment.
Linux Events Lack Capabilities
When these actions run on Linux, linux::click emits key codes that the virtual uinput device does not advertise in its key capabilities. The existing side-button path registers its codes because the kernel silently drops unregistered events, so MouseButton6 through MouseButton9 can be selected but produce no input on Linux.
| Action::MouseButton6 => linux::click(KeyCode::BTN_FORWARD), | ||
| Action::MouseButton7 => linux::click(KeyCode::BTN_BACK), | ||
| Action::MouseButton8 => linux::click(KeyCode::BTN_TASK), | ||
| Action::MouseButton9 => linux::click(KeyCode::BTN_0), |
There was a problem hiding this comment.
Linux Button Numbers Are Reordered
The new Linux mapping mixes semantic side-button codes with the positional BTN_0 range, so the emitted events do not line up with the user-facing button numbers. A Linux app that binds the numbered extra buttons can receive BTN_FORWARD, BTN_BACK, BTN_TASK, and then BTN_0 for Button 9, which makes Button 9 look like the first generic button instead of the ninth numbered button.
|
Closing for now — withdrawing until the feature is fully built and tested locally. Sorry for the noise. |
Summary
Adds four pickable actions —
MouseButton6–MouseButton9— that synthesizemouse buttons 6–9, for apps/games/CAD that bind buttons beyond the standard
five. Mirrors the existing
MouseBack/MouseForwardpattern.Why: the
Actionvocabulary capped output at "button 5". Users wanting aphysical button to emit button 6+ (Blender, MMO-mouse emulators, etc.) had no
path, even though the underlying injection layer already supported arbitrary
button numbers on macOS/Linux.
What changes
openlogi-core/src/binding.rsActionvariants; wired intolabel()("Button 6"…),category()(Category::Mouse), andcatalog()openlogi-inject/src/inject.rspost_other_button(5..=8); Linux → evdevBTN_FORWARD/BACK/TASK/0; Windows → log-and-skipopenlogi-gui/src/mouse_model/picker.rsmatch, no wildcard)openlogi-gui/locales/*.yml(×20)"Button 6"–"Button 9"translation keys, each locale's own "button" wordPurely additive — no
schema_versionbump, no migration. New unit variantsserialize as bare TOML strings (
"MouseButton6"), consistent with existingextra-button actions.
Platform coverage
post_other_buttonalready takes any number)BTN_*family)SendInput's mouse path carries flags forbuttons 1–5 only; there's no flag for 6+. Documented gap, matches the
existing "no platform equivalent → debug log + skip" pattern. Left out of
scope to fix here since Windows is a preview target.
Test plan — what was verified locally
cargo test -p openlogi-core— 84 pass, including newextra_mouse_button_labelsand extendedcategory_mouse_variants;all_catalog_variants_roundtrip_tomlnow exercises the 4 new variantscargo test -p openlogi-inject— 1 passcargo test -p openlogi-agent-core— 33 pass (consumes theActionenum; confirms no downstream missing-match arms)
cargo build -p openlogi-gui(macOS) — succeeds after installing theMetal Toolchain; the picker's exhaustive
matchcompiles, proving allfour variants are covered
Bluetooth-direct — confirmed Button 6/7/8/9 appear in the MOUSE section
of the action picker, with icons, after Forward (Button 5)
cargo build -p openlogi-inject(macOS) — succeedscargo check --target— no cross-targets installedlocally; relies on CI. evdev 0.13.2 confirmed to expose
BTN_FORWARD/BTN_BACK/BTN_TASK/BTN_0.Honest note on emission coverage
Button reception by a downstream app (e.g. Blender registering MB6) was not
end-to-end tested. The emission path reuses the already-shipping
post_other_button(proven for buttons 3/4) with a different integer argument(5–8) on the same
MOUSE_EVENT_BUTTON_NUMBERfield, so the risk is low — butflagging it rather than claiming full end-to-end verification.
Notes
MouseButton6–MouseButton9, labels"Button 6"–"Button 9". Unlike Back/Forward these have no universal semantic meaning.docs/superpowers/specs/2026-06-29-mouse-buttons-6-9-design.mdand
docs/superpowers/plans/2026-06-29-mouse-buttons-6-9.md(in the last twocommits on this branch). Happy to rebase them out if you'd prefer code-only.