03ad2406b63f1b93fc43cd9a698bf598e4fa5735
6 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
f3986b8f82 |
feat(host/steam): shippable usbip/vhci_hcd virtual Deck + client leave-shortcuts
Steam Deck pass-through (design/steam-deck-passthrough-plan.md), code-complete + all CI checks green on Linux + adversarially reviewed; on-glass validation pending: - usbip/`vhci_hcd` virtual Deck transport (inject/linux/steam_usbip.rs) for non-SteamOS hosts (Bazzite/generic) — presents a real interface-2 USB Deck so Steam Input promotes it. In-process vhci attach (loopback OP_REQ_IMPORT handshake → sysfs attach) with a bounded `usbip`-CLI fallback; detach on drop. - Backed by a vendored, libusb-free trim of the `usbip` crate (crates/punktfunk-host/vendor/usbip-sim, MIT + NOTICE; host/cdc/hid + rusb/nusb removed; interrupt-IN paced by bInterval). - Selection ladder raw_gadget (SteamOS fast-path) → usbip (universal) → UHID, with PUNKTFUNK_STEAM_USBIP / PUNKTFUNK_USBIP_ATTACH knobs. - Shared Deck descriptors + the 0x83/0xAE feature contract + a Steam-accepted serial consolidated into steam_proto.rs; the raw_gadget backend reuses them. - Linux client leave-shortcuts: Ctrl+Alt+Shift+D + holding the escape chord (L1+R1+Start+Select) >=1.5s end the session (short press still exits fullscreen); the chord state resets across sessions. Also bundles in-progress work already staged in the tree: - host(kwin): xdg-output logical-geometry mapping so the KWin fake_input backend places absolute coordinates correctly under display scaling. - docs: design/README index entries + design/controller-only-mode.md. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
71e0cace77 |
feat(host/steam): M5 — fallback remap, motion rescale, degrade ladder
Keep the rich Steam inputs from silently dropping when the resolved backend
isn't the virtual hid-steam device, and fix a cross-device motion-scale bug.
- inject/proto/steam_remap.rs (new, pure + unit-tested):
* motion_wire_to_deck — the wire carries DualSense-convention units (20 LSB/
deg.s gyro, 10000 LSB/g accel — what every client capture emits), but the
Deck's hid-steam report wants 16 LSB/deg.s + 16384 LSB/g. The Deck backend
now rescales (gyro x16/20, accel x16384/10000): a real Deck<->Deck gyro/
accel correctness fix (the DualSense/DS4 backends consume the wire 1:1).
* fold_paddles + RemapConfig (PUNKTFUNK_STEAM_REMAP=paddles=drop|stickclicks|
shoulders, default drop) — the DualSense + DS4 managers fold a client's back
grips onto standard buttons rather than dropping them (those pads have no
back-button HID slot; the uinput Xbox pad already exposes them as Elite
paddles BTN_TRIGGER_HAPPY5-8).
- resolve_gamepad: a runtime degrade ladder — a UHID backend (DualSense / DS4 /
Steam Deck) on a host where /dev/uhid isn't writable now falls back to the
uinput Xbox 360 pad instead of a dead controller (the device-create would
just fail). Separate from pick_gamepad's compile-time platform check, so the
existing pick_gamepad tests are untouched.
- Delete the throwaway M0/M1 spike (src/bin/steam_uhid_spike.rs) — M2's
#[ignore]d backend test subsumes its validation, and removing it frees
steam_proto to reference steam_remap cleanly.
On-box backend test still green; workspace clippy/fmt/test green (incl. the new
steam_remap tests). Deferred as optional RemapConfig growth: gyro->mouse /
trackpad->stick synthesis on an Xbox target (no slot — documented drop today).
Not pushed.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
||
|
|
7cc2ed85cb |
feat(proto/steam): M3 — rich Steam wire (back buttons + 2nd trackpad)
Carry the rich Steam Controller / Steam Deck inputs end-to-end on the wire — strictly additive + forward-compatible (unknown kinds/bits drop on old peers). Core (punktfunk-core): - input.rs: BTN_PADDLE1..4 + BTN_MISC1 in Moonlight's buttonFlags2<<16 namespace (so the GameStream paddle path and native grips share one host injector map; Steam L4/L5/R4/R5 reuse the four Xbox-Elite paddle slots). - quic.rs: RichInput::TouchpadEx (kind 0x03 — surface 0/1/2, touch+click, signed coords, pressure; the second trackpad the single Touchpad can't express) and HidOutput::TrackpadHaptic (kind 0x04 — the SC voice-coil pulse). Round-tripped. - abi.rs: PUNKTFUNK_GAMEPAD_STEAMDECK=6 / _STEAMCONTROLLER=5, the paddle bits, RICH_TOUCHPAD_EX / HIDOUT_TRACKPAD_HAPTIC constants. from_hid packs TrackpadHaptic into the existing which + effect[0..6] — the legacy structs do NOT grow (guarded by new size_of==20/19 asserts); GamepadPref lockstep + paddle-bit lockstep asserts extended. include/punktfunk_core.h regenerated. Host (punktfunk-host): - steam_proto::from_gamepad maps the wire paddles -> the four Deck grips + QAM; apply_rich routes TouchpadEx left/right -> the matching pad. - every DualSense/DS4 manager (Linux + Windows) gained a TouchpadEx arm (surface 0/2 -> its one touchpad; surface 1 ignored) so the variant compiles everywhere and a Steam client streaming to a DS host keeps its right pad. - the xpad BUTTON_MAP finally consumes the GameStream paddle bits (BTN_TRIGGER_HAPPY5-8) — Sunshine/Moonlight paddle clients were silently no-op'd before (design §5.6). - Android feedback: drop TrackpadHaptic (no coils; rumble rides 0xCA). Validated on-box: the ignored backend test now drives the full wire path — from_gamepad (BTN_A + the L4 grip) + apply_rich (a left-pad TouchpadEx) reach the evdev as BTN_A + ABS_HAT0X=-8000. Wire round-trips + paddle/TouchpadEx mapping unit-tested. Workspace clippy/fmt/test green. Not pushed. Deferred to M4: the C-ABI PunktfunkRichInputEx + send_rich_input2 (only the Apple/embedder *send* path needs it; the host decodes TouchpadEx today). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
15b9287865 |
feat(host/steam): M1 — byte-exact Deck input serializer, on-box validated
Flesh out inject/proto/steam_proto.rs into the full Steam Deck HID contract, transcribed verbatim from the kernel steam_do_deck_input_event / steam_do_deck_sensors_event and validated field-for-field against kernel 7.0: - SteamState: the u64 button map (bytes 8..16), sticks/triggers/trackpads/IMU stored as raw little-endian report values; serialize_deck_state is a pure, byte-exact memcpy into the 64-byte unnumbered frame. - from_gamepad (XInput frame -> Deck buttons/sticks/triggers) + apply_rich (RichInput touchpad -> right pad, motion -> IMU). - parse_steam_output: the 0xEB ID_TRIGGER_RUMBLE_CMD feedback -> (low, high) for the universal rumble plane. - serial_reply fixed: prepend the report-id-0 byte the kernel strips (steam_recv_report does memcpy(data, buf+1, ...)); M0's reply lacked it, so the kernel fell back to the "XXXXXXXXXX" serial. - SteamModel (Deck now; classic Controller later), command/feature IDs. The spike is repurposed as the M1 validator: it pulses the b9.6 mode-switch to enter gamepad_mode (steam_do_deck_input_event early-returns under the default lizard_mode otherwise), then holds a known test pattern. Reading both evdevs via EVIOCGABS/EVIOCGKEY, every field matched: ABS_X/Y/RX/RY (incl. the kernel Y-negation), both triggers, the touched right-pad HAT1X/Y, the IMU accel/gyro (with ABS_Z/RZ negations), and the 6 expected buttons incl. the L4/R5 grips. 5 unit tests + workspace clippy/fmt/test green. Next: M2 (SteamControllerManager UHID backend + PadBackend wiring). Not pushed — pipeline not yet shippable. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
567b0d70e9 |
feat(host/steam): M0 — virtual hid-steam UHID device binds + parses (Linux)
Greenfield virtual Steam Deck controller, the Steam analogue of the shipped virtual DualSense. Proves the kernel hid-steam driver binds a /dev/uhid 28DE:1205 device, registers it as a real Steam Deck, and parses our input reports — the go/no-go gate for the full Steam Controller/Deck pipeline. - inject/proto/steam_proto.rs: keeper module — the vendor HID descriptor (one feature report, the sole thing steam_is_valve_interface() checks), the command/feature IDs, serialize_deck_state, and the serial GET_REPORT reply. Unit-tested. - src/bin/steam_uhid_spike.rs: throwaway M0 spike (Linux-only) — opens /dev/uhid, creates the device, services the handshake including UHID_SET_REPORT (which the DualSense backend omits and which hid-steam stalls ~5s/cmd without), and heartbeats a neutral report. - design/steam-controller-deck-support.md: full design + M0–M7 plan; the two walls (Steam Input capture ownership; virtual-Steam recognition) and the fidelity ceiling. Status: M0 GREEN. On-box (headless Ubuntu 26.04, kernel 7.0, no Steam): journalctl -k shows hid-steam binding the device (rebind off hid-generic), "Steam Controller connected", and the kernel creating BOTH a "Steam Deck" gamepad evdev and a "Steam Deck Motion Sensors" IMU evdev (INPUT_PROP_ACCELEROMETER). A layout-agnostic mash-probe drove 23 distinct BTN_* codes through hid-steam -> evdev, proving the input-report parse path. M1 line-checks the exact per-bit report layout against the lab kernel. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
fced221684 |
refactor(windows-host): confine platform code under windows/ + linux/ folders (Goal-1 stage 6)
Move 36 platform-specific files into per-module `windows/` and `linux/` subfolders (and the
shared HID codecs into `inject/proto/`):
capture/{windows,linux}/ encode/{windows,linux}/ inject/{windows,linux,proto}/
audio/{windows,linux}/ vdisplay/{windows,linux}/
src/windows/ (service, wgc_helper, win_adapter, win_display)
src/linux/ (dmabuf_fence, drm_sync, zerocopy/)
Done with `#[path]`, NOT a module rename: every file moves into its folder while the
`crate::*::*` module names stay FLAT, so all caller paths and every internal `super::`/`crate::`
reference are unchanged — only the parent `mod` decls gained `#[path = "..."]`. This is the
codebase's existing pattern (inject's gamepad_windows) and makes the move byte-identical in
behaviour with ZERO reference churn, far lower risk than collapsing to a single
`crate::capture::windows::` namespace (that deeper rename is an optional follow-on; this delivers
the cfg-sprawl folder confinement the stage is about). Done LAST, after the semantic stages, so
the path churn didn't fight them.
Verified: Linux cargo check + clippy (-D warnings) clean; my mod-decl changes fmt-clean (the 3
remaining fmt diffs are pre-existing local-rustfmt-version skew that moved with their files); all
36 `#[path]` targets exist; no internal `#[path]`/`include!`/file-child-mod in any moved file
(the inline `mod X {` blocks are self-contained). Box build to follow.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|