Skip to content

feat: add mouse buttons 6–9 as pickable actions#335

Open
MichaelDanCurtis wants to merge 6 commits into
AprilNEA:masterfrom
MichaelDanCurtis:feat/mouse-buttons-6-9
Open

feat: add mouse buttons 6–9 as pickable actions#335
MichaelDanCurtis wants to merge 6 commits into
AprilNEA:masterfrom
MichaelDanCurtis:feat/mouse-buttons-6-9

Conversation

@MichaelDanCurtis

@MichaelDanCurtis MichaelDanCurtis commented Jun 30, 2026

Copy link
Copy Markdown

Summary

Adds four pickable actions — MouseButton6MouseButton9 — that synthesize
mouse buttons 6–9, for apps/games/CAD that bind buttons beyond the standard
five. Mirrors the existing MouseBack/MouseForward pattern.

Why: the Action vocabulary capped output at "button 5". Users wanting a
physical 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

Layer Change
openlogi-core/src/binding.rs +4 Action variants; wired into label() ("Button 6"…), category() (Category::Mouse), and catalog()
openlogi-inject/src/inject.rs macOS → post_other_button(5..=8); Linux → evdev BTN_FORWARD/BACK/TASK/0; Windows → log-and-skip
openlogi-gui/src/mouse_model/picker.rs icon arms (compiler-forced — exhaustive match, no wildcard)
openlogi-gui/locales/*.yml (×20) "Button 6""Button 9" translation keys, each locale's own "button" word

Purely additive — no schema_version bump, no migration. New unit variants
serialize as bare TOML strings ("MouseButton6"), consistent with existing
extra-button actions.

Platform coverage

  • macOS — full (existing post_other_button already takes any number)
  • Linux — full (evdev BTN_* family)
  • Windows — log-and-skip. SendInput's mouse path carries flags for
    buttons 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 new
    extra_mouse_button_labels and extended category_mouse_variants;
    all_catalog_variants_roundtrip_toml now exercises the 4 new variants
  • cargo test -p openlogi-inject — 1 pass
  • cargo test -p openlogi-agent-core — 33 pass (consumes the Action
    enum; confirms no downstream missing-match arms)
  • cargo build -p openlogi-gui (macOS) — succeeds after installing the
    Metal Toolchain; the picker's exhaustive match compiles, proving all
    four variants are covered
  • Ran the dev-built GUI on real hardware against an MX Master 3S over
    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) — succeeds
  • Linux/Windows cargo check --target — no cross-targets installed
    locally; 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_NUMBER field, so the risk is low — but
flagging it rather than claiming full end-to-end verification.

Notes

  • Naming: variants MouseButton6MouseButton9, labels "Button 6"
    "Button 9". Unlike Back/Forward these have no universal semantic meaning.
  • Spec & plan live in docs/superpowers/specs/2026-06-29-mouse-buttons-6-9-design.md
    and docs/superpowers/plans/2026-06-29-mouse-buttons-6-9.md (in the last two
    commits on this branch). Happy to rebase them out if you'd prefer code-only.

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-apps

greptile-apps Bot commented Jun 30, 2026

Copy link
Copy Markdown

Greptile Summary

This PR adds pickable actions for mouse buttons 6 through 9. The main changes are:

  • New Action variants, labels, categories, catalog entries, and tests.
  • Picker icon handling for the new mouse actions.
  • macOS, Linux, and Windows injection handling for the new actions.
  • Locale keys for the new button labels.
  • Design and implementation notes for the feature.

Confidence Score: 5/5

This looks safe to merge.

  • No blocking issues found in the changed code since the previous review.

Important Files Changed

Filename Overview
crates/openlogi-core/src/binding.rs Adds the new mouse button actions to the core action model and tests.
crates/openlogi-inject/src/inject.rs Adds per-platform injection behavior for mouse buttons 6 through 9.
crates/openlogi-gui/src/mouse_model/picker.rs Adds picker icon coverage for the new mouse button actions.
crates/openlogi-gui/locales/*.yml Adds localized label keys for the new button actions.

Reviews (2): Last reviewed commit: "feat(gui): add Button 6-9 translation ke..." | Re-trigger Greptile

Comment on lines +80 to +83
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),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 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.

Fix in Codex Fix in Claude Code

Comment on lines +80 to +83
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),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 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.

Fix in Codex Fix in Claude Code

@MichaelDanCurtis

Copy link
Copy Markdown
Author

Closing for now — withdrawing until the feature is fully built and tested locally. Sorry for the noise.

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