fix(v2): ignore phantom/non-standard gamepads in nav polling#3852
Merged
Conversation
The v2 gamepad polling loop reads buttons and axes by hardcoded W3C standard-mapping indices, but only guarded against null pads. Firefox (and Zen) expose phantom or non-standard-mapping gamepads even with no real controller attached, whose analog controls drift across the press threshold. Index 4/5 (LB/RB) are bound to AppNav section cycling, so each oscillation re-fired cycleSection and looped the app through home/platforms/collections/search with no user input, making the UI unusable. Add an isUsablePad() guard requiring pad.connected and a "standard" mapping, applied in both the polling loop and detectPadPresence. Every button/axis read assumes the standard mapping, so a non-standard pad cannot be interpreted safely regardless. Fixes #3851 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Contributor
Greptile SummaryThis PR filters unusable gamepads from v2 navigation polling. The main changes are:
Confidence Score: 4/5The strict mapping filter can disable legitimate connected controllers and should be addressed before merging.
frontend/src/v2/composables/useGamepad/index.ts Important Files Changed
Prompt To Fix All With AIFix the following 1 code review issue. Work through them one at a time, proposing concise fixes.
---
### Issue 1 of 1
frontend/src/v2/composables/useGamepad/index.ts:114
**Connected Controllers Are Silently Ignored**
A legitimate controller can be connected while reporting an empty mapping, as occurs with some Switch Pro, Joy-Con, and 8BitDo browser/OS combinations. The new equality check rejects every such device before polling, so navigation stops working even when its buttons previously matched the expected indices; the controller-debug screen still shows the device, which makes this failure appear inconsistent.
Reviews (1): Last reviewed commit: "fix(v2): ignore phantom/non-standard gam..." | Re-trigger Greptile |
Requiring mapping === "standard" rejected legitimate controllers that report an empty mapping (some Switch Pro, Joy-Con, 8BitDo browser/OS combos) while still exposing the standard button indices, breaking navigation for them. There are only two mapping values, so the check dropped every empty-mapping device. Gate on pad.connected alone, which is the actual discriminator for the disconnected phantom entries that caused #3851. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.
Description
Explain the changes or enhancements you are proposing with this pull request.
Fixes #3851 — the v2 UI would enter an infinite loop cycling through the top-level pages (home → platforms → collections → search) right after login, making the app unusable. Reported in Firefox/Zen with no controller in use.
Root cause
The v2 gamepad polling loop (
frontend/src/v2/composables/useGamepad/index.ts) reads buttons and axes by hardcoded W3C standard-mapping indices, but only guarded againstnullpads (if (!pad) continue;). Firefox (and Zen) expose phantom or non-standard-mapping gamepads even when no real controller is attached, and their analog controls drift across the digital press threshold. Since buttons 4/5 (LB/RB) are bound to AppNav section cycling, eachfalse → trueoscillation re-firedcycleSection(), walking the router through the four sections cyclically with zero user input.detectPadPresence()also flipped the app into "pad" input modality for these phantom devices.The fix
Added an
isUsablePad()guard requiringpad.connected && pad.mapping === "standard", applied in both the polling loop anddetectPadPresence(). Every button/axis read assumes the standard mapping, so a non-standard pad cannot be interpreted safely regardless, and skipping it is the correct behavior. The controller-debug screen pollsnavigator.getGamepads()directly, so it still displays non-standard pads for inspection.AI assistance disclosure
This change was written with AI assistance (Claude Code): investigation of the root cause and the code change were AI-generated and human-reviewed.
Checklist
Please check all that apply.
Screenshots (if applicable)
N/A — input-guard fix. Reproduction video is in #3851.
🤖 Generated with Claude Code