Skip to content

Controller support without Steam (Seaglass #60) - #32

Merged
ApolloF merged 3 commits into
mainfrom
ApolloF/Controller-Input
Oct 17, 2026
Merged

ApolloF merged 3 commits into
mainfrom
ApolloF/Controller-Input

Conversation

@ApolloF

@ApolloF ApolloF commented Oct 17, 2026 •

Copy link
Copy Markdown
Owner

Brings Seaglass's own Xbox controller bridge (ApolloF/Seaglass#60, merge commit 4cd5cfe) into the Store Edition as a merge, so Seaglass's history stays an ancestor of main and the daily sync keeps working.

What comes in

  • SDL3 reads the real pad; a pure-Go ViGEmBus client plugs a virtual Xbox 360 pad (rumble passed back).
  • HidHide hides the real pad through its saved block list, with a ledger (hidden-controllers.json) cleared at game end, every start and quit, and from Unhide controller.
  • Settings → Set up downloads the official signed ViGEmBus/HidHide installers, checks pinned SHA-256 hashes and runs them with UAC.
  • Auto without ViGEmBus starts the game directly with a setup hint; Steam stays selectable in Settings and per game.
  • Tests, design doc (docs/design/controller-without-steam.md), CHANGELOG, ROADMAP, THIRD_PARTY_NOTICES, bindings.

Store Edition differences

  • Merge conflicts were all additive (imports in api*.ts, types.ts, Core fields, settings.normalize, update_test.go).

  • The edition already had platform.RunElevated (elevate.go) for the store's installers. Seaglass's new installer.go declared a second SHELLEXECUTEINFOW wrapper, so runElevated now calls RunElevated and maps a declined prompt to exit code 1602.

  • Also fixed a pre-existing, timing-dependent data race in Store code that CI's race detector caught on this PR: enrichState.refreshChart's goroutine now uses the client captured when it starts, so TestAnnotatorReadsCompletionAndReleaseDateWithoutFetching swapping c.enrich.client no longer races with it.

Store policy finding

Decision: keep Seaglass's download-and-run setup unchanged. The Store Edition is not distributed through the Microsoft Store: it ships as a signed NSIS installer on GitHub Releases with its own signed update feed (docs/store-edition.md, .github/workflows/build.yml). The "Store" in the name is the experimental game store, so Microsoft Store Policies don't apply to this build.

For the record, if it were ever listed in the Microsoft Store (version 7.20, updated 2026-09-14, https://learn.microsoft.com/en-us/windows/apps/publish/store-policies), the setup would have to change:

  • 10.1.5: in-app acquisition of add-ons explicitly excludes non-Microsoft drivers and NT services.
  • 10.2.4: dependency on non-Microsoft drivers is generally not allowed (case-by-case for WHCP-certified drivers, disclosed in Partner Center).
  • 10.2.3: no offering to install secondary software not developed by you, unless it enhances the product.
  • 10.2.5 / 10.2.9: in-app updates and Win32 installer rules also conflict with the edition's self-updater and store.

In that case "Set up" would have to link to the official ViGEmBus/HidHide pages and only detect the drivers. That would be a separate packaging, not this build.

Checks (local)

  • Check command go test ./internal/... && npm --prefix frontend run check && npm --prefix frontend test: passes. One run hit an unrelated Windows TempDir cleanup flake in TestAchievementsGetAndCache; the rerun was clean.

  • npm run check: 0 errors. Vitest: 202 tests passed.

  • go run ./tools/notices -check, wails3 build, go test ./... and go test -race ./internal/...: all pass.

  • Bindings regenerated with no diff.

  • Live WL_REAL_VIGEM=1 go test -run RealViGEm ./internal/vpad on ViGEmBus 1.21.442: passed. The first attempt timed out reading the state back through XInput; the second passed in 0.17 s.

  • CI build / windows: passes.

To test by hand

  • With a DualSense: an Xbox-only game in Auto starts with the virtual pad, and rumble works.
  • HidHide setup and hiding on a PC with HidHide; Unhide controller.
  • The Set up button's UAC flow.

…EmBus + HidHide) (#60)

* docs: design for controller support without Steam

* WIP: controller bridge without Steam (ViGEmBus + HidHide)

Built: internal/vpad, pad Bridge mode, launch route and controller step,
settings, UI, mock, bindings, docs. Checks pass locally (go test, -race,
npm check/test, notices).
Unfinished: wails3 build not run, mock UI not reviewed in both themes or at
narrow width, live ViGEm test not run, HidHide v1.5.230 lacks the session
block list (decision pending), main-session review of the diff, PR.

* Controller bridge: handle ViGEmBus results like ViGEmClient

Found with the live test on a real ViGEmBus 1.22: the bus ends a report
submit with other errors while the report still arrives, so only access
denied counts. Older buses without the wait-ready request still work,
and the rumble loop only ends on unplug or Close.

* Controller bridge: hide through HidHide's saved block list, Unhide in Settings

No HidHide release has the per-process list yet, so Seaglass uses the saved
block list. It notes what it adds in hidden-controllers.json first and takes
exactly those off at game end, start, quit and from Unhide controller. Auto
without ViGEmBus starts directly with the setup hint (no Steam fallback).
Brings Seaglass PR #60 (ViGEmBus virtual Xbox controller, HidHide hiding
with a crash-safe ledger, driver setup from Settings) into the Store Edition.

Conflicts were additive (imports, Core fields, settings normalize, tests).
platform.RunInstaller now elevates through the edition's existing
RunElevated instead of a second ShellExecuteEx wrapper.
TestAnnotatorReadsCompletionAndReleaseDateWithoutFetching swaps
c.enrich.client while the chart goroutine from the first StoreHome may
still read it; CI's race detector caught it on this PR.
@ApolloF
ApolloF merged commit 9aa1350 into main Oct 17, 2026
2 checks passed
@ApolloF
ApolloF deleted the ApolloF/Controller-Input branch October 17, 2026 13:51
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