Skip to content

feat: configurable controller shortcuts with a first-run setup - #116

Merged
lippdev merged 4 commits into
mainfrom
feat/custom-controller-shortcuts
Sep 30, 2026
Merged

lippdev merged 4 commits into
mainfrom
feat/custom-controller-shortcuts

Conversation

@lippdev

@lippdev lippdev commented Sep 30, 2026

Copy link
Copy Markdown
Owner

What

Controller shortcuts become user-chosen: open Console Mode from the tray, the session menu, and back to the PC. None is on until the user picks it; the first run of this version shows a setup dialog (after the tour, or when the window is first opened from the tray). Existing installs start with nothing set too: the old Home / Start + Select settings are dropped.

  • ControllerShortcuts (pure, tested): allowed buttons (Home, Select, Start, A, B, X, Y, what every pad reports), naming per pad, and conflicts (same combo, or one containing the other). A lone face button is refused; only Home may stand alone.
  • ShortcutCapture records a combo from live readings (hold and let go) and ignores the press that opened the capture.
  • ShortcutPicker is the control used in Settings and in the setup dialog; while capturing no shortcut fires and the pad doesn't navigate.
  • Hint toast and "or hold ... to go back" use the chosen shortcut; the toast is skipped when the menu has none.

Verification

Built locally (0 errors); dotnet test passes (185, 30 new). The capture with a real pad is not automated: checklist in docs/TESTING.md (new section 0). Checked in the app with the mouse (set, remove, conflicts, persistence); a physical pad and a PlayStation pad were not exercised.

Stacked on #115.

🤖 Generated with Claude Code

The controller shortcuts were fixed: hold Home to open from the tray, Select +
Y for the session menu and Start + Select to go back to the PC. Now the user
picks each one, and none is on until they choose.

- ControllerShortcuts holds the pure rules: which buttons a shortcut may use
  (Home, Select, Start, A, B, X, Y: the ones every pad reports, XInput and
  Sony HID alike), what a combo is called per pad, and which two shortcuts
  collide (the same combo, or one containing the other). A single face button
  is refused because it would fire in any game; only Home may stand alone.
- ShortcutCapture records the combo from live pad readings: hold the buttons
  and let go. It only starts after a poll with nothing held, so the press that
  opened the capture is not recorded.
- ShortcutPicker is the control used in Settings and in the first-run dialog.
  While a capture runs no shortcut fires and the pad does not navigate.
- The first run of this version shows the setup once (after the tour, or when
  the window is first opened from the tray). Existing installs start with
  nothing set too, because the old Home/Start + Select settings are dropped.
- The session hint toast and the "or hold ... to go back" line use the
  shortcut that was chosen, and the toast is skipped when the menu has none.

The console rows toggle the suggested combo, since capturing needs the desktop
Settings. Docs: README pair and a new section in docs/TESTING.md.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Important

A shortcut can be captured from multiple controllers even though XInput only fires it when one controller holds the entire combination.

Reviewed changes This review covers configurable controller shortcut capture, persistence, onboarding, and integration with the tray and session UI.

  • Shortcut configuration Adds three saved shortcut slots, capture and conflict validation, and suggested combinations.
  • First-run setup Prompts desktop users to configure or skip shortcuts after the tour or when opening from the tray.
  • Shortcut behavior and UI Connects shortcuts to app launch, the session menu, and restore, and updates Settings, console hints, localization, and hardware test guidance.

Pullfrog  | Fix all ➔ | Fix 👍s ➔ | View workflow run | Using GPT Luna | 𝕏

Comment thread src/ConsoleMode/Services/ControllerHoldWatcher.cs Outdated
@lippdev
lippdev changed the base branch from fix/ignore-defective-hid-pads to main September 30, 2026 21:34

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Important

The new HID trust tracking can quarantine healthy controllers when another controller of the same model reports invalid input.

Reviewed changes Re-reviewed the commits since the prior Pullfrog review, focusing on per-device shortcut capture and the synchronized HID controller-trust changes.

  • Scoped shortcut capture to one controller Separated device states during capture and made shortcut triggering check each controller independently, addressing the prior finding.
  • Added HID input quarantine Incorporated consecutive invalid-reading detection and filtering of quarantined pads, alongside changes synchronized from main.

Pullfrog  | Fix all ➔ | Fix 👍s ➔ | View workflow run | Using GPT Luna | 𝕏


// A pad with impossible readings is ignored (see ControllerMapping.MaxSimultaneousHidButtons).
var pressedCount = buttons.Count(on => on);
NoisyStreaks.TryGetValue(name, out var streak);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

These trust maps use SafeName as the device key, but it contains only display name and vendor/product IDs. Two identical controllers therefore share their noise streak and quarantine state, so one defective pad can make its healthy sibling get ignored too.

Technical details
# HID trust state is shared by identical controllers

## Affected sites
- `src/ConsoleMode/Services/ControllerInput.cs:273-274` — `NoisyStreaks` and `DistrustedPads` are keyed by strings.
- `src/ConsoleMode/Services/ControllerInput.cs:281,303-308` — the shared display-name/vendor/product string is used as the key for both streak tracking and permanent quarantine.

## Required outcome
- Keep noisy streak and quarantine state isolated per physical HID device so one controller's invalid readings do not suppress another identical controller.

@lippdev
lippdev merged commit aa0e497 into main Sep 30, 2026
5 checks passed
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