Skip to content

feat(gamepad): expose mice as opt-in virtual controllers - #1359

Open
humbertogontijo wants to merge 2 commits into
AprilNEA:masterfrom
humbertogontijo:feat/virtual-gamepad-hid
Open

humbertogontijo wants to merge 2 commits into
AprilNEA:masterfrom
humbertogontijo:feat/virtual-gamepad-hid

Conversation

@humbertogontijo

@humbertogontijo humbertogontijo commented Sep 11, 2026

Copy link
Copy Markdown

Summary

Browsers and many games only talk to the world through the Gamepad API / XInput-style controllers. A Logitech mouse already has remappable extras (Back/Forward, gesture button, haptic panel, thumb wheel) and often a haptic actuator (0x19b0), but none of that shows up as a standard gamepad — so a web page or game cannot:

  • read those extras as buttons / axes
  • send dual-rumble back to the device (Chrome gamepad.vibrationActuator, SDL rumble, etc.)

This PR adds an opt-in auxiliary virtual HID gamepad per mouse: the pointer and primary clicks stay native; mapped extras publish as a standard-layout pad that Gamepad API clients can see. When rumble = true and the device has haptics, host rumble is forwarded to HID++ waveforms so pages/games that vibrate a controller can drive the mouse panel instead of a silent no-op.

  • Opt-in per-device [devices.*.gamepad] (schema v8); pointer + L/R stay native.
  • New openlogi-gamepad crate with a VirtualGamepad trait: macOS IOHIDUserDevice, Linux uinput, Windows ViGEm stub (soft-fail until wired).
  • Agent diverts mapped extras into the pad and skips productivity actions for those controls. Host rumble → 0x19b0 when capable (macOS rumble callback deferred — SDK link gap).

Changes

  • openlogi-core: GamepadConfig / GamepadMap, schema 8, config example
  • openlogi-gamepad: new workspace crate
  • openlogi-agent-core / openlogi-agent: capture-plan divert, pad sync, dispatch short-circuit, rumble poller
  • Docs: docs/gamepad.md
  • Agent entitlements stub: crates/openlogi-agent/bundle/OpenLogiAgent.entitlementscom.apple.developer.hid.virtual.device is present but commented out so unsigned/dev builds are not killed by AMFI

Note for @AprilNEA — Virtual HID entitlement

macOS IOHIDUserDeviceCreate needs the restricted Apple entitlement com.apple.developer.hid.virtual.device on the agent helper (not the GUI). The stub is ready in OpenLogiAgent.entitlements; please leave it commented until your Apple signing identity / provisioning profile is approved for Virtual HID, then wire it into agent codesign the same way OpenLogi.entitlements is for the GUI. Without it, pad create fails open (controls keep native/productivity behaviour).

Testing

cargo test -p openlogi-core gamepad
cargo test -p openlogi-gamepad
cargo test -p openlogi-agent-core --lib
cargo clippy -p openlogi-core -p openlogi-gamepad -p openlogi-agent-core -p openlogi-agent --all-targets -- -D warnings

Not runtime-tested on hardware (macOS Virtual HID entitlement required for IOHIDUserDeviceCreate). To try: enable gamepad.enabled in TOML, reload, press a mapped button, check a Chrome Gamepad tester (and a page that calls vibrationActuator.playEffect if rumble is on).

@greptile-apps

greptile-apps Bot commented Sep 11, 2026

Copy link
Copy Markdown

RetriggerConfidence Score: 4/5

The PR is not yet safe to merge because enabling both gamepad mode and DPI gesture mode silently loses the virtual Select control.

Fix All in CodexFindings

  1. P1 DPI gamepad input disappears

Summary

This PR adds an opt-in virtual gamepad for supported mice, maps auxiliary controls to a standard controller layout, and integrates virtual-device lifecycle and optional haptic rumble forwarding into the agent.

  • Adds schema-v8 per-device gamepad configuration and documentation.
  • Adds Linux, macOS, and Windows virtual-gamepad backends.
  • Diverts gamepad-owned HID++ controls only while a virtual pad is live.
  • Adds neutralization, thumbwheel-axis decay, and rumble polling.
  • Changes since the previous review broaden DPI/ModeShift gesture capture, exposing one conflict with live gamepad ownership.
Diagram
%%{init: {'theme': 'neutral'}}%%
flowchart LR
    Config[Per-device gamepad config] --> Sync[Agent pad synchronization]
    Sync -->|creation succeeds| Pad[Live virtual gamepad]
    Sync -->|creation fails| Native[Native/productivity behavior]
    Pad --> Plan[Capture plan diverts mapped extras]
    Plan --> Events[HID++ input events]
    Events --> State[Gamepad state]
    State --> OS[Gamepad API / controller clients]
    OS --> Rumble[Host rumble]
    Rumble --> Haptics[Mouse HID++ haptics]
Loading

Reviews (3) · Last reviewed commit: "fix(gamepad): fail open when virtual pad..."

Comment thread crates/openlogi-agent-core/src/capture_plan.rs Outdated
Comment thread crates/openlogi-agent-core/src/gamepad.rs Outdated
Comment thread crates/openlogi-gamepad/src/linux.rs
Comment thread crates/openlogi-agent-core/src/gamepad.rs
Comment thread crates/openlogi-agent-core/src/capture_plan.rs
@davidbudnick davidbudnick added type: feature New feature request platform: all Cross-platform issue labels Sep 14, 2026
humbertogontijo and others added 2 commits September 17, 2026 13:25
Add a minimal auxiliary gamepad path: TOML opt-in, a VirtualGamepad trait
with macOS/Linux/Windows backends, and agent divert so mapped extras feed
an OS-visible standard HID pad while the pointer stays native.

Co-authored-by: Cursor <cursoragent@cursor.com>
Gate diversion on a live pad, pulse thumb-wheel axes back to neutral,
neutralize on session cancel, recreate pads when the product name
changes, and stop advertising unimplemented Linux FF_RUMBLE.

Co-authored-by: Cursor <cursoragent@cursor.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

platform: all Cross-platform issue type: feature New feature request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants