Skip to content

Learn gamepad buttons 1 to 8 as switch keys - #1223

Merged
enaboapps merged 4 commits into
mainfrom
feat/1222-gamepad-buttons
Oct 28, 2026
Merged

enaboapps merged 4 commits into
mainfrom
feat/1222-gamepad-buttons

Conversation

@enaboapps

@enaboapps enaboapps commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

Closes #1222

What

Switch interfaces in gamepad mode and game controllers now work as switches. Buttons 1 to 8 on any connected controller are switch keys named Gamepad1 to Gamepad8, shown as Gamepad 1 to Gamepad 8, learned from the Switches page like keys and usable for every press and hold action.

  • Windows: the capture worker registers the HID joystick and gamepad usages with Raw Input (RIDEV_INPUTSINK), so presses arrive while another app is in front, and reads button state with HidP_GetUsages. Button edges ride the existing edge queue at virtual-key codes Windows leaves unassigned (0x97 to 0x9E); the keyboard hook ignores that range so a stray keyboard code can never pose as a button. Controllers are recorded on arrival and at startup so unplugging one is never mistaken for a keyboard removal. Buttons are never suppressed, a held button blocks re-enabling until released, a removed controller releases its buttons, and controller registration is best effort so keyboard capture never depends on it.
  • macOS: an IOHIDManager scheduled on the existing capture run loop, matching the same usages and only button elements. GameController's background flag is not used (it broke silently in macOS 15.4). A button held while capture was off blocks re-enabling, like a key.
  • Settings: the switch settings file stays schema 1 (the key is a string). The synced settings schema moves from 5 to 6 with a no-op upgrade. Consequence to note in the release notes: once any computer on 1.3.0 saves, a Switchify PC 1.2.x on the same account shows "update to keep syncing" instead of silently rejecting a profile with a gamepad key.
  • Docs and help: Add a switch, Troubleshooting, the in-app "Switch not recognized" advice and the interface demonstration now say gamepad mode is fine and mouse-click mode is the one that cannot be learned.

Out of scope, as in the issue: sticks, triggers, the D-pad, Xbox layout names, buttons 9 and up, and telling two controllers apart.

Validation

  • npm run prediction-model, npm run lint, npm test (312 passed), npm run build
  • cargo fmt --check, cargo clippy --all-targets -D warnings on Windows and cross-checked for aarch64-apple-darwin, cargo test (849 passed)
  • site: npm run build
  • New tests: key naming and display names, per-device button merging, Raw Input edge handling in learning and active modes, keyboard removal while a button is held, the keyboard hook rejecting the controller code range, a held button blocking startup, switch settings validation, and the version 5 to 6 sync upgrade with gamepad keys.
  • Two independent review rounds; every actionable finding is fixed in the second and third commits.

Not yet done, needs hardware: a controller or switch box in gamepad mode on Windows and on a Mac, learned while another app is in front. The Xbox Adaptive Controller should be checked over USB and Bluetooth since its two transports expose different descriptors, and a composite box such as the Pretorian USB Switch should be checked on a Mac in case Input Monitoring is required. Known limits accepted for now: a button held across a worker restart on Windows is not known until its next report, and a controller that splits its buttons across several HID report IDs would need per-report tracking.

🤖 Generated with Claude Code

Switch interfaces in gamepad mode (Joycable, Pretorian USB Switch, Crick
USB Switch Box, Ultimate Switchbox) and game controllers such as the Xbox
Adaptive Controller present as HID game controllers and send numbered
buttons. Buttons 1 to 8 on any connected controller are now switch keys
named Gamepad1 to Gamepad8, learned and used like keyboard keys.

Windows registers the joystick and gamepad usages with Raw Input in the
capture worker, so presses arrive in the background, and reads button
state through the HID parser. macOS reads the same reports through
IOHIDManager on the capture run loop; the GameController framework's
background flag is not relied on. Buttons are never suppressed, a held
button blocks re-enabling until released, and a removed controller
releases its buttons. The synced settings schema moves to 6 so an older
Switchify PC asks for an update instead of refusing the switches.

Closes #1222

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@enaboapps enaboapps added this to the v1.3.0 milestone Oct 28, 2026
@vercel

vercel Bot commented Oct 28, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
site Ready Ready Preview Oct 28, 2026 9:37am UTC

Request Review

…n macOS

Windows now records controllers on arrival and at startup, so unplugging
one that never reported is a controller removal and cannot send keyboard
capture into recovery. The button usage list is sized from the device.
macOS counts a button held while capture was off as held on begin, like
a key. Held-key messages use the badge wording "Gamepad 1". The docs
qualify the Xbox Adaptive Controller as checked on Windows.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The keyboard hook rejects virtual-key codes in the controller range, so
a keyboard reporting an unassigned code can never be learned or
suppressed as a button. The shutdown-wait message names held buttons
the way the badges do.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A keyboard reporting an unassigned code in the controller range leaves
no observation, so it can never read as a lost hook.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@enaboapps
enaboapps marked this pull request as ready for review October 28, 2026 09:37
@enaboapps
enaboapps merged commit 3a8b314 into main Oct 28, 2026
10 checks passed
@enaboapps
enaboapps deleted the feat/1222-gamepad-buttons branch October 28, 2026 10:11

This branch was successfully deployed

1 active deployment
Preview — 4fa40f07 Deployed Oct 28, 2026 by vercel[bot]
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.

Learn gamepad buttons 1 to 8 from switch interfaces in gamepad mode

2 participants