Conversation
8 tasks
…fier Adds the SdlGamepadSpecifier enum variant, schema component, protocol YAML (two 0-65535 vibrate features, low/high motors), and the regenerated device config (v5.43). Structural inspiration: chiefautism's abandoned PR #860.
Stateful two-motor handler mirroring the XInput protocol: every vibrate command carries the full motor state as two u16 LE values on Tx, so each write is a complete command with no batching step.
Cross-platform (Windows/macOS/Linux) gamepad rumble via SDL3, statically built from source. One process-lifetime thread owns the SDL context and multiplexes all gamepads addressed by SDL3 instance ID; discovery is on-demand enumeration and removal is connected-state polling - the thread never pumps SDL events. Rumble is armed finitely (60s) and refreshed before expiry so one-shot commands hold indefinitely. Includes the Phase 0 threading spike example (headless init + no-pump enumeration on a spawned thread). Joins the workspace as both a member and default member so plain cargo build compiles it on all three OSes. Structural inspiration: chiefautism's abandoned PR #860.
Registered in the v1-v4 embedded/json lists. v0 is excluded with a comment: SingleMotorVibrateCmd broadcasts one speed to all motors and cannot express the per-motor addressing this case verifies. Test harness gains an sdl-gamepad specifier branch (Tx-only endpoints) alongside the BLE default.
Registers the SDL gamepad communication manager on all platforms (no OS gate, unlike XInput) and logs a warning on Windows when both gamepad managers are enabled, since the same physical controller may then appear as two devices. Flag plumbing, default-false options, and the registration decision are unit-tested.
Non-default feature (SDL3 source build is too heavy for default library consumers): enabling it registers the SDL gamepad manager, cross-platform with no OS gate. Manager registration is refactored into a named-returns helper asserted by a feature-gated test.
On all three OS matrix entries: run the in-process client tests with --features sdl-gamepad-manager, assert via cargo tree that sdl3 is absent from default features and present with the feature, and run the SDL3 headless threading spike example (automated half of the Phase 0 gate; CI runners have no controllers, so an empty gamepad set passes).
…devices SDL3 on macOS routes wired gamepads to GCController (MFI) by default: the hidapi device drivers decline wired pads (DevSrvsID paths) while MFI is enabled, and GCController discovery only fires via Cocoa runloop notifications - which a headless, no-video process never spins. Result: zero gamepads ever discovered, even on the main thread with event pumping. Verified against SDL 3.4.14 source (SDL_PLATFORM_MACOS && SDL_JOYSTICK_MFI guard in SDL_hidapi_xboxone.c) and on hardware: with SDL_JOYSTICK_MFI=0 the wired Xbox One S enumerates via hidapi and set_rumble succeeds. iOS keeps the MFI default (GCController is the only backend there). The spike example mirrors the factory's platform policy. Windows discovery failure remains under investigation (likely analogous WGI behavior; needs an on-hardware SDL_LOGGING=3 run).
On-hardware diagnosis (wired Xbox One S, USB): with the MFI=0 hidapi policy, wired pads enumerate but rumble silently fails - Apple exposes only read-only shortened HID reports for them, and the working path (GCController/CoreHaptics) requires a main-thread runloop this architecture deliberately does not host. SDL2 has the same Apple-side guard, so a version switch would not help. Per operator decision, v1 is Bluetooth-only on macOS: scan probes each candidate's SDL connection state and skips Wired pads with a logged explanation pointing users at Bluetooth pairing. Verified on hardware: SDL reports the wired pad as connection Wired. Bluetooth pads and all of Windows/Linux are unaffected. The spike example now enables verbose SDL logging and prints each pad's connection state, so a single run is a complete diagnostic - this is the tool for the still-open Windows zero-device diagnosis (likely the analogous XGIP/WGI claiming dance).
On-hardware validation (Bluetooth DualSense, macOS) showed rumble stops after a few seconds despite the 60s arm - some controllers do not honor long durations. Re-sending the current non-zero command every second keeps the effect alive; the long finite arm stays as a safety net if a keepalive is missed. Same refresh_decision machinery, tighter interval.
SDL gamepads expose two, three, or four logical rumble output channels (main low/high, trigger left/right) depending on hardware capabilities. The existing configuration system hardcodes the two-channel main layout and cannot reconcile a cached user definition against a different base definition, so trigger channels could never be advertised. - Add a layout/constant module to the device config crate sharing the SDL base identifiers, protocol variants, selector keys, and the visible-index to logical-channel-slot mapping for the three layouts. - Add a neutral DeviceDefinitionSelection value (selected base key plus canonical hardware name) and an optional carrier on Hardware, so connectors can declare which base definition they selected without SDL dependencies leaking into buttplug_server or identity fields. - Add DeviceConfigurationManager::device_definition_with_selection, which resolves the selected base explicitly, reconciles cached user definitions (preserving user UUID, index, display name, allow/deny, message gap, and surviving-channel customizations; refreshing the canonical name and base id), and errors on invalid selections instead of silently falling back. - Register the four-channel and trigger-only base configurations with fixed UUIDs and channel descriptions alongside the default two- channel base in the SDL protocol YAML.
SDL gamepads report main rumble and trigger rumble as independent capabilities. Discovery now probes both (pure property reads, no motor activation) and pads with neither capability are not published; failed probes and capability changes are rechecked on later scans and on the actual leased open. The macOS wired-pad exclusion is unchanged. The protocol-to-hardware transport carries the complete four-slot desired state (low, high, left trigger, right trigger as u16 LE, 8 bytes) in one command. The protocol handler derives its visible-index to logical-slot mapping from the final definition's protocol variant, never from feature count. The ownership thread dispatches only pairs the pad reports as supported - including zero, stop, and keepalive calls - tracks last-applied state per pair, refreshes each active pair before expiry, and on any pair failure best-effort zeroes both supported pairs, removes the lease, and delivers removal so no successfully applied half keeps running untracked. Adds a test-only Shutdown command routed through the production loop teardown with a joinable spawn seam, plus deterministic coverage for the capability matrix, probe retries, fresh connect snapshots, name fallbacks (including whitespace-only names), per-pair lifecycle and keepalive, partial-pair failure cleanup, stale-generation isolation, hardware packet validation, and supported-pair dispatch.
Integration harness: test devices can carry an explicit SDL base selection that flows through the production definition-selection path, so fixtures exercise real capability-driven layout selection rather than prebuilt definitions. Fixtures cover main-only, main+trigger, and trigger-only layouts with eight-byte packet assertions, plus a disabled-channel scenario proving filtered features keep their logical channel slots and receive no commands. Named regressions assert harness metadata propagation, v4 advertised feature order and descriptions straight from the client device, v3 advertisement, and per-channel command routing. Diagnostics: the sdl3_thread_spike example prints both capability booleans alongside name and connection state; it remains purely non-actuating. Docs: the crate README documents the three layouts, capability-based per-connection selection, skip-and-retry policy for output-less devices, naming fallback, connection-scoped identity, settings reconciliation (including that removed channels lose customizations), internal eight-byte framing, simple trigger rumble versus adaptive resistance, and a manual hardware release checklist. A sdl_docs_contract_check test pins the documented contract to the implementation.
The shutdown tests waited on the SDL thread join through spawn_blocking inside a tokio timeout, which bounds the wait but cannot cancel the blocking task: a hung thread would still wedge the test runtime after the timeout fired, defeating the bounded-completion guarantee the seam is meant to prove. Poll is_finished on the async timer with a deadline instead, joining only after the thread has actually exited.
Merge origin/dev's protocol additions (luvmazer, sexverse-v6, joyhub updates) with the sdl-gamepad definitions in the generated config.
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.
Implement support for SDL3, removing the xinput and hid managers at the same time (as SDL3 will handle those)