Skip to content

Extend native Switch2Kit controller support to desktop platforms - #3

Merged
jmonster merged 12 commits into
mainfrom
feature/switch2kit-desktop-platforms
Sep 19, 2026
Merged

jmonster merged 12 commits into
mainfrom
feature/switch2kit-desktop-platforms

Conversation

@jmonster

@jmonster jmonster commented Sep 18, 2026 •

Copy link
Copy Markdown
Owner

Scope and reviewed revisions

This maintained Cemu fork embeds Switch2Kit in its existing SDL3 input backend on macOS, Linux and Windows. It does not require a separate dashboard, network bridge, system SDL override or virtual-controller driver. Upstream Cemu downloads do not contain this integration.

Current head: e3b579269caa3122cdab3b0dbf8e0c79da882049.
Tree: b620ba96891ccba3027d33907e715f8155a0fd1b.
dependencies/Switch2Kit: 3d3ce3a605733c47db061af687168ad5914cbf0c, matching maintained Dolphin. All SDK production/build/test fixes are in this reviewed immutable revision. SDK cemu-project#75's direct child 13abafe changes only README/platform-guide navigation, so it is deliberately not a new engine dependency.

Product and distribution repairs

  • Native BlueZ/WinRT transports feed the shared session/protocol engine and SDL adapter. Enabled desktop builds preserve a single main-event-loop SDL owner and terminal shutdown. Disabled builds do not acquire a Swift dependency or higher deployment target.
  • Windows linking now gives the statically linked Switch2KitSDL3 adapter the same Debug/Release MSVC CRT property as CemuInput. The hash-verified failing application archive showed /MD versus Cemu's /MT mismatch (LNK2038 and imported llround). The fix does not alter the separate Swift DLL runtime or bypass compiler/linker checks.
  • The shared Windows launch supervisor no longer writes PowerShell's read-only HOME variable. Native supervisor regressions verify private environment/profile setup, missing-notice rejection and refusal to overwrite unexpected packaged settings; a console fixture cannot pass GUI qualification.
  • The final SDK pin permits a fresh Windows advertisement after a connection retires during an existing scan. Stable identity, monotonically new tokens, stale-callback fences, bounded queues and explicit-stop policy remain. This does not add Dolphin's automatic startup/reconnection policy to Cemu.
  • Windows bounded file access retains strict UTF-8 handling, non-inheritable regular-file handles, bounded reads, namespace rejection and unchanged output on failure. Motion profiles remain measured and device-matching, not synthetic gameplay calibration.

Recommended GameCube/Pro mappings, independent GameCube analog trigger axes/digital clicks, model-appropriate rumble, saved physical assignments, guarded custom mapping backup/rollback and explicit disconnect remain. Joy-Con halves are complementary separate SDL sources assigned to one player; they are not a system virtual pair. After restarting Cemu, use Find again.

Editorial cleanup and executable regressions

test_desktop_lifecycle.py no longer freezes English CMake diagnostic fragments. It checks actual configure success/failure and whether the SDK was evaluated across macOS/Linux/Windows, missing-SDL, missing-SDK, deployment and disabled cases. Rewording a diagnostic without changing a guard now leaves the tests passing.

A new executable configure regression includes the complete production input CMake file and checks matching static host/adapter CRTs in both Debug and Release, plus no adapter target when disabled. It fails in both enabled configurations against the old production code and passes with the repair. It complements, not replaces, native Windows compilation/linking.

All final local retained tests passed: production mapping/identity/notification/lifecycle/backup/rollback with Clang sanitizers, bounded-file tests, nine wiring checks and all three lifecycle/CMake/CRT test methods. Required protocol/ABI, calibration, cancellation, signing, licensing and runtime dependency coverage remain. No suite, product safety check or native application failure is suppressed to obtain green CI.

Final-head native checks

These runs test e3b5792, not the preceding pin-only revision:

Application checks are running/queued and must complete before readiness. Translation/source jobs are not controller compatibility tests. SDK cemu-project#75 separately passes both native Windows Swift toolchains, 108 package tests, real C/SDL consumers, all extracted consumers and missing-DLL negative controls; that is not a substitute for these maintained Cemu application checks.

Desktop workflows archive before qualification, extract into new directories, isolate user profiles and library paths, inspect loaded controller/Swift module origins, observe a GUI, request normal close and relaunch. The exact tested archive is uploaded only after success. Unexpected user settings in staging are rejected; only the disposable extracted profile is seeded. No real user data is erased.

User route, remaining qualification and merge order

README.md and docs/Switch2Kit.md lead with macOS 15+ arm64/x86_64 and experimental Ubuntu 24.04 x86_64/Windows 11 x64 application downloads, exact extraction/executable paths, runtime prerequisites, source commands and Find/Sync/player selection. They cover emulated controller types, trigger differences, mapping checks, rumble, measured motion and complementary Joy-Con setup. Artifacts require GitHub sign-in, expire, and are development builds rather than production-signed/notarized releases.

Keep draft until final native application checks and review complete. No physical-controller/gameplay or pristine first-use qualification is claimed. Record model/firmware, OS, adapter/driver and tested revision for pairing/access retry, controls and independent trigger travel/clicks, rumble/stop, reversed multiplayer reconnect order, saved assignments, adapter loss, explicit disconnect, normal shutdown, measured motion and gameplay. Exercise both Joy-Con sources. Fixtures and seeded GUI test profiles do not replace this evidence.

SDK cemu-project#73 is already merged by an earlier action. Merge SDK cemu-project#75 next while keeping pinned 3d3ce3a reachable, then this PR and Dolphin #5 after final pinned application validation and review. A squash/rebase changing the selected SDK commit requires repinning and rerunning affected fork checks. No merge, auto-merge or production release is performed by this work.

…uilds

Advance the pinned SDK to the existing BlueZ backend. Keep macOS bundle and deployment requirements Apple-specific, add Linux install rules and a platform-aware build helper, and compile/install/relocate the complete Linux application in CI.
…ssions

Run native SDL initialization, pumping and shutdown on the GUI main thread on all enabled platforms, retaining the existing worker in backend-disabled non-macOS builds. This fixes Linux controller discovery never reaching the SDL adapter and keeps session state single-threaded.

Update the stale macOS-only source contract while retaining SDL, supported-host, macOS bundle/deployment and opt-in gates. Add production-preprocessor ownership tests for six platform/feature combinations and execute isolated CMake admission cases. Preserve policy diagnostics in the Linux CI artifact.

The new lifecycle regression fails on the previous Linux-enabled source; the full policy suite passes locally with Clang and GCC ASan/UBSan. Full application and hardware qualification remain separate.

jmonster commented Sep 18, 2026 •

Copy link
Copy Markdown
Owner Author

Follow-up to the failing check shown in the PR list: pushed the lifecycle/test fix in dfb8982e54f0f54b86a4c6e2d989b7d9131afd4b, then preserved the runner's external --sdk selection in ab4ac09627f460baf6c1b660c62731096e8244f3 (current head). No force-push or merge.

Reproduced CI failure: test_opt_in_bundle_and_target still required the old macOS-only option and guard although this branch admits Linux. The updated check retains default-off, SDL-required, supported-host and macOS bundle/deployment protections. Nine isolated CMake cases now exercise those production admission rules.

Functional fix: Linux's worker blocked in SDL_WaitEvent, while the only NativeSession().Pump() call was compiled inside the macOS-only main-loop handler. A successful build therefore did not establish working native controller input. Enabled native builds now use the existing GUI-main-thread SDL lifecycle on all platforms: initialize before input-manager creation, pump from the main-loop timer, stop the timer before input-manager shutdown, and shut down the native host before SDL. Backend-disabled Linux/Windows retain their worker. Session state remains single-threaded.

Verified locally:

  • The new ownership regression fails against the prior Linux-enabled and Windows-enabled source and passes after the fix. It preprocesses the production conditionals for six platform/feature combinations and checks matching declarations, exactly one SDL owner and shutdown ordering. This is NOT native Windows qualification.
  • The full C++ policy suite passes with Clang and GCC, C++20, warnings-as-errors, ASan and UBSan. All nine wiring checks and both new matrix-test groups pass.
  • The full suite also passes with the in-tree SDK moved away and only the explicitly selected external SDK available.
  • Uploaded Git blob hashes match the tested files. Linux policy logs are now retained in the diagnostics artifact with pipefail; no failed command is masked.

Fresh application CI has been triggered and must finish. The previous Linux run built successfully but failed at Execute controller policies; its relocation/launch step did not run. This fix does not add a Windows SDK backend or establish physical Bluetooth/gameplay acceptance. The PR remains draft and separate from autoconnect #4. When combining them, retain these lifecycle guards together with #4's consent/startup logic, tests and reviewed SDK pin.

Forward the existing policy runner's --sdk option to the new CMake admission tests. Verified the complete sanitizer suite with the in-tree SDK moved away and only the explicitly supplied external checkout available.

Copy link
Copy Markdown
Owner Author

Current-head validation update: the policies job now passes at ab4ac09627f460baf6c1b660c62731096e8244f3, including the corrected platform contract and new lifecycle/CMake matrix tests: https://github.com/jmonster/Cemu/actions/runs/35385671655/job/105731896242.

The fresh full Linux application workflow is https://github.com/jmonster/Cemu/actions/runs/35385671357; its result is still outstanding. Native macOS jobs remain queued. A passing policy job is not a claim that every build, installed-application launch, Windows backend or physical controller has been validated.

Pin the Windows-capable SDK, embed its DLL beside Cemu, add a PowerShell build-and-run helper and full Windows application CI with relocation and normal launch/quit/relaunch checks. Preserve the real opt-in test without prescribing CMake help text. Let an already-running Linux dependency build finish instead of discarding its cache on each commit.
Pin the SDK's Windows-compatible bounded file reader instead of including
POSIX-only unistd.h on MSVC. The SDK fix preserves POSIX behavior, UTF-8
paths, regular-file validation, byte/retry limits, and failure atomicity.

Add standalone tests against the production SDK header for binary data,
Unicode paths, missing/invalid/special files and size boundaries. Run them
with the Linux sanitizer suite and with MSVC in the Windows application
workflow. Keep all existing build, relocation and launch checks enabled.

Validated locally: Clang and GCC host-file tests with ASan/UBSan; existing
controller policy tests; 9 wiring tests; 2 desktop lifecycle tests.
Full native Windows application validation remains a CI check.
Advance only dependencies/Switch2Kit to immutable commit 06bc206047e9b5c9d3f07940e9a7ce29a7de366d, the same reviewed SDK selected for the maintained Dolphin integration. Both native Windows toolchains passed real C/SDL and extracted-package qualification at this revision, with packaged Swift runtime, isolated profiles, OS-only PATH and missing-DLL controls.

Review the preceding divergent 0d76136 host-file fix before replacing its pin. The selected SDK retains a Win32 UTF-8, regular-file, bounded reader with non-inheritable handles and unchanged outputs on error; it additionally rejects device namespaces and concurrent in-place writes. Cemu's production-header host-file regressions pass against this SDK under Linux Clang ASan/UBSan. Preserve the newly added Cemu MSVC and sanitizer regressions and all other host work.

The SDK also includes the complete runtime dependency closure, stale-copy protection and short deployment-copy locking. Fresh native Cemu builds and application/package checks remain required; SDK or local fixture passes are not physical-controller evidence. Merge the SDK with this commit retained/reachable first, or repin and revalidate after a squash/rebase.
…oller setup

Archive the actual installed/staged application before testing it, then delegate to the pinned SDK's extracted GUI supervisors on Linux and Windows. Check normal GUI startup, local controller/Swift runtime modules, normal quit and relaunch with isolated profiles and no compiler/developer PATH. Preserve JSON diagnostics on failure and upload the exact qualified archive only after success. Linux --version and a pre-archive Windows staging directory are no longer the launch gate.

Reject unexpected developer settings from the CI staging directory; seed only private extracted test settings, never erase a real user's configuration. Keep full native builds, Windows host-file regressions, sanitizer policy tests, SDK notices and other checks enabled.

Rewrite the initial README/controller guide for macOS, Ubuntu 24.04 x86-64 and experimental Windows x64: correct maintained-fork application artifacts, expiration/authentication, extraction/executable paths, runtime prerequisites, copyable source fallbacks, Find/Sync, physical/player selection, emulated type, mappings, rumble and subsequent launches. Preserve Joy-Con 2 complementary-source instructions, measured-motion calibration, saved identities and custom-mapping backups. Do not claim Cemu implements Dolphin's automatic reconnection, or that automated checks are physical hardware evidence.

Validation: all five uploaded blobs match the locally reviewed files. Existing Cemu mapping/identity/session/rollback policy tests and production host-file checks pass with Clang ASan/UBSan against SDK 06bc206; nine wiring and two executable desktop lifecycle/guard tests pass. YAML parses and local documentation links resolve. Fresh native application/GUI CI remains required for this final host revision. SDK pin and unrelated host code are unchanged.
The ef6fdfe Linux job built the complete controller-enabled application and passed controller policies, but the exact extracted GUI supervisor raced Openbox: wmctrl -m had succeeded before the client-list property existed, so the first wmctrl -lp failed before a window could be observed.

Select immutable Switch2Kit 5198ca5a5fb9e39657832951d8751ad1e9472a4c. Its supervisor waits for both identity and the possibly empty client list within the existing five-second bound, without swallowing later observer/runtime/GUI/shutdown errors. Seven portable readiness tests and a real isolated Xvfb/Openbox/Xlib reproduction pass. The native observer fixture is separate from this complete application and cannot satisfy its launch gate.

The SDK's product sources, Windows transport/runtime repair and controller policies are unchanged from the previously verified 06bc206 revision. The selected SDK adds only qualification code, tests and their Linux workflow. Preserve all host code, current documentation, extracted-archive gates and unrelated dependencies. Fresh final-pin native application validation remains required; do not rerun the old failing code or relabel --version as GUI acceptance.
…e repair

The hash-verified Windows diagnostic archive for 3b87d27 shows LNK2038: Switch2KitSDL3 was compiled with MD_DynamicRelease while Cemu uses MT_StaticRelease, followed by unresolved __imp_llround. Copy CemuInput's MSVC_RUNTIME_LIBRARY target property to the statically linked adapter for all configurations. Do not alter the Swift DLL runtime or disable the linker's ABI checks.

Pin immutable Switch2Kit 8a6ff6f7ed0763849e53a6bcf47c38cdd6e22ad7, which repairs the shared Windows package supervisor's read-only HOME collision and adds native preparation/failure regressions. The full application must still pass extracted relocation, runtime-origin, normal shutdown and relaunch checks.

Local CMake configuration probes reproduce the differing Debug/Release CRT properties before the change and matching static properties afterward. The disabled configuration adds no adapter or Swift invocation. Real native Windows linking and final-pin Linux/macOS validation remain required in CI.
Advance only dependencies/Switch2Kit to immutable 3d3ce3a605733c47db061af687168ad5914cbf0c, matching maintained Dolphin. The SDK removes a retired connection's scan-admission entry so fresh controller advertisements are not permanently suppressed during an existing discovery session. Stable identity, stale-token fences, bounded scanning, retry/consent and explicit stop remain intact.

The added adaptation regressions fail on the old implementation and pass with the repair. They neither stand in for native Windows/WinRT execution nor claim physical-controller evidence. Revalidate the complete native applications and exact extracted GUI/quit/relaunch packages on this pin.

Preserve 8069a92's static SDL adapter CRT alignment, all lifecycle/mapping/calibration/rollback tests and existing platform user guides. Cemu still does not adopt Dolphin's opt-in automatic startup/reconnection policy. No merge or release is performed.
…egression

Remove assertions that freeze English error-message fragments in the platform admission tests. Keep the actual CMake exit status and SDK-evaluation checks, with explicit expected success/admission booleans. Add Windows enabled, missing-SDL and disabled-without-SDK cases; macOS deployment, Linux dependency and unsupported-platform guards remain.

Add an executable configuration regression that includes the complete production src/input/CMakeLists.txt and evaluates the host and static adapter CRT properties in Debug and Release. Enabled targets must agree on the static CRT; disabled input configuration must not acquire the adapter. The real Windows workflow remains responsible for full native compile/link and extracted GUI qualification.

Local evidence: the new CRT regression fails twice against the original MD/MT-mismatched input target and passes after the production fix. Merely rewording the missing-SDK diagnostic causes the old test to fail but the revised outcome-based test to pass, with identical guard behavior. All three updated test methods pass. Temporarily varied source files were restored byte-for-byte before publication. Local new test blob: 76d6fbb.

The SDK remains the deliberately selected immutable 3d3ce3a605733c47db061af687168ad5914cbf0c, matching Dolphin. Subsequent SDK commit 13abafeb changes documentation links only. No production behavior, permission, runtime-dependency check, required notice or complete application CI gate is relaxed.
@jmonster
jmonster marked this pull request as ready for review September 19, 2026 21:56
@jmonster
jmonster merged commit 9614613 into main Sep 19, 2026
15 checks passed
@jmonster
jmonster deleted the feature/switch2kit-desktop-platforms branch September 19, 2026 21:56
jmonster added a commit that referenced this pull request Sep 19, 2026
Incorporate main 9614613 after PR #3 merged, preserving the original automatic-connection history. Resolve the SDK, provider/session, test-runner and documentation overlap without dropping either feature.

Pin Switch2Kit 1e6eac15fd4d4c93f15244eb66d79021c92d29fc: SDLHost automatic policy/start plus merged native desktop transport/runtime fixes. Update the exact-pin guard and user guide together. Keep main-thread SDL lifecycle on all enabled platforms, disabled-build behavior, static adapter CRT matching, bounded file access and all existing packaging/launch gates. Preserve saved-consent one-shot startup, authoritative Disconnect, live opt-out, sticky failures and the 64 KiB configuration output bound.

Validated the exact combined tree ac75e8d locally with Clang and GCC, C++20 warnings-as-errors, AddressSanitizer and UndefinedBehaviorSanitizer. Both complete runs pass mapping/identity/notification/rollback policies, bounded-file tests, nine wiring tests, automatic-connection and configuration/size regressions, six automatic wiring checks and three desktop lifecycle/CMake/CRT test methods. External SDK selection remains supported; the reconstructed SDK tree and commit match the published immutable revision.

The prior separate Cemu heads were CI-green, but those runs do not qualify this combined revision. Keep PR #4 draft until current SDK cemu-project#74 and full pinned Cemu native application/extracted GUI checks pass. No tests or safety checks are disabled. No physical-controller, gameplay, pristine first-use or production release qualification is claimed.
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