fix: gate rumble/motion on the active path, not the model DB - #146
Merged
Conversation
emir-hasanbegovic
force-pushed
the
fix/standard-path-rumble-capability
branch
4 times, most recently
from
July 21, 2026 22:59
ab270d3 to
894a1a1
Compare
A Switch Pro over USB advertised rumble on Standard and Bluetooth (and left the input inspector's test buttons live) but only Direct actually rumbled. Two causes: 1. The capability layer ORed the framework actuator/sensor probe with the native model DB, so Direct-only capability leaked onto the framework paths. Resolve motion/rumble per path instead, mirroring MainViewModel's split: a Direct synthetic reads the parser DB, a framework pad reads the OS probe. CapabilityComposer is the single source of truth; the bindings VM reads it and the inspector disables and dims its rumble buttons when the path can't rumble. 2. The OS probe is itself a false positive for the Switch protocol: Android registers a framework vibrator it can't drive (Nintendo's proprietary HD-rumble, which only our Direct path speaks). Suppress the probe at its source for models the native DB maps to the SWITCH_PRO_USB parser (Pro, Joy-Con Grip, Online pads), so no framework path advertises dead rumble; Direct still works via the model DB. Also re-probe the vibrator in onInputDeviceChanged, symmetric with the existing late-gyro re-probe.
emir-hasanbegovic
force-pushed
the
fix/standard-path-rumble-capability
branch
from
July 21, 2026 23:41
894a1a1 to
5844713
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
A Switch Pro over USB advertised rumble on Standard and Bluetooth (and left the input inspector's rumble test buttons enabled), but only Direct actually rumbled.
Root causes
1. The capability layer ORed two path-specific signals.
CapabilityComposer.deviceControllerLayerandConfigureBindingsViewModelcomputed rumble asdevice.hasRumble || native.modelHasRumble(...). The framework probe is authoritative for Standard/Bluetooth; the model DB (parserHasRumble) only for Direct. ORing let the Direct-only capability leak onto the framework paths.2. The framework probe is itself a false positive for the Switch protocol.
vibratorManager.vibratorIdsis non-empty for a Switch Pro — Android registers a vibrator — but it can't drive Nintendo's proprietary HD-rumble, which only our Direct path speaks. So even after fixing (1),device.hasRumblestayedtrueand the framework paths still advertised rumble that never fires.Fix
MainViewModel's existing split): a Direct synthetic reads the parser DB, a framework pad reads the OS probe.CapabilityComposeris the single source of truth; the bindings VM reads it, and the inspector disables its rumble buttons when the path can't rumble.probeRumble) for models the native DB maps to theSWITCH_PRO_USBparser — the Pro, Joy-Con Charging Grip, and Online controllers, plus any future Switch-protocol device — via a newmodelFrameworkRumbleUnreliablelookup (mirrorsmodelHasRumble).device.hasRumbleis now truthful for every downstream surface (PathCard, composer, bindings, wizard, inspector); Direct still works through the model DB.onInputDeviceChanged, symmetric with the existing late-gyro re-probe.Net: rumble shows only where it fires — Direct for Switch-protocol pads; framework for Xbox/PlayStation where the OS actually drives it.
Why the parser, not the Nintendo vendor
Keying on
SWITCH_PRO_USB(the native model DB's parser field) targets the exact cause — the proprietary protocol — and covers the whole family without a hand-maintained VID:PID list that could drift from the DB.Tests
usb_parsers_test.cpp:parserFrameworkRumbleUnreliabletrue forSWITCH_PRO_USB, false for the Xbox/PlayStation families.CapabilityComposerTest: per-path matrix (framework trusts the probe / ignores the model DB; synthetic reads the model DB; end-to-endcapabilityForCandidatefor a Standard Switch Pro).Local CI — all green
clang-format · check_play_metadata · ktlintCheck · detekt · lint · testDebugUnitTest · nativeTest (168/168) · assembleDebug. Emulator
instrumentedjob runs in CI (no local device attached).🤖 Generated with Claude Code