Skip to content

Steering Wheel Emulator v0.2.8

Latest

Choose a tag to compare

@camborambo camborambo released this 11 Oct 01:36
· 2 commits to main since this release

Fixed

  • Fanatec DD1 OEM / HID FFB: PC Comp path aligned with the working Desktop fork — DI default-value axis/effect names, five OEM axes (no orphan Handbrake), HID report descriptor 5×16-bit + reserved byte matching the 17-byte report (removed mismatched Dial that advertised 6 axes while reports stayed 5). Physical VID_0EB7&PID_0006 FAW OEM restored on Start/Stop. Fanatec bind UI no longer offers the virtual Handbrake axis (unknown Dial OEM/joy.cpl); Telemetry arcade Handbrake bind unchanged.

Added

  • Status bar Debug Tools menu: Start/Stop Debug, Export log…, and Capture Fanatec OEM… (physical Fanatec Joystick OEM registry + DI axis names for Dial/handbrake research). Capture needs no Debug session; also embedded under fanatec-oem-capture\ in full Export log zips.
  • Docs: Fanatec bind list has no Handbrake Dial (no OEM hardware capture yet); Forza mainly needs virtual Fanatec identity for steering + FFB — buttons/handbrake bind from physical devices.

Changed

  • Main window UI capped at 60 Hz (Timeline.DesiredFrameRate) so high-refresh monitors do not multiply WPF paint cost on weaker PCs. Live meters slow to ~10 Hz when the window is inactive/minimized, with a light adaptive backoff under load; unchanged Text/ProgressBar values are skipped.
  • Removed Settings → Debug Test (and all sub-options). Runtime always uses the known-good release FFB/input path. Fanatec PC Comp + Fanatec physical dual-handle stays in the core path. Soft steering catch-up / Invert FFB remain on Force Feedback → Advanced Settings. Legacy settings.json keys still load but are forced off.
  • Docs / Emulated-device tooltip: Forza Horizon → Fanatec DD1, then in Forza pick any Fanatec profile and custom-bind; keep Logitech G920 for Heat / Unbound.
  • Product rename → Steering Wheel Emulator: UI brand, SteeringWheelEmulator.exe / zip / install folder, %AppData% / %ProgramData% / LocalAppData under SteeringWheelEmulator (one-time migrate from G920Emulator, then remove old trees when safe). GitHub repo → camborambo/SteeringWheelEmulator. C# projects/namespaces → SteeringWheelEmulator.* (SteeringWheelEmulator.sln). emuffb COM CLSID, SHM Local\G920Emulator.FfbTorque.v7, and virtual G920/Fanatec HID InstanceIDs unchanged. SimHub External Sim → Steering Wheel Emulator (simulated); plugin → SteeringWheelEmulator.SimHubPlugin.dll (Register removes legacy G920Emulator.SimHubPlugin).

Added

  • Emulated device toolbar: Logitech G920 (default) or Fanatec DD1 (0EB7:0004). Games see that virtual identity; your physical Fanatec/Simucube/etc. stays the FFB output (and can still be bound). Change only while Stopped. Gear R defaults to 12 for PC Comp.
  • Per-profile HidHide snapshot: Save on an input profile captures the current hide list (best-effort). Switching profiles (or Start when Settings HidHide is Off but the profile has a snapshot) restores that list. Settings Hide-all / Hide-bound Start paths unchanged.
  • Output feel optional Device pace, Interpolate (full-path INT-like blend, not idle-only), and Gap fill — each slider adds its effect when > 0 (defaults off). Offline replay: tools/IdleSmoothReplay.
  • Debug session logs FFB_TUNE lines to steeringwheel-emulator-bridge-health.log when effect gains / output feel are applied (values + shared-memory readback) so exports can prove slider changes reached emuffb.
  • Telemetry Max gears in the Gearing card (1–10): UDP MaxGears → SimHub CarSettings_MaxGears, shows that many gear ratio / top-speed rows (paddles can use 7–10 for speed sim; H-shifter still 1–6). Gear tops use the Blocklayer formula MPH = (tire × ShiftAt) / (336 × gear × diff) for all gears including 7–10; absolute speed ceiling raised to 1600 km/h so tall overdrive is not clipped through AbsoluteRpmMax. After updating, Remove registration → restart SimHub → Register with SimHub again if the packet layout changed.
  • Telemetry Arcade buttons → Sequential shifter (opt-in): bind Gear up / Gear down / Gear reset on the input profile for sequential/paddle boxes that do not map to H-pattern gears. Pattern is R → 1 → Max gears; Reset jumps to 1. When enabled, H-pattern and bumper-paddle gear inference are ignored.
  • Custom bindings after Gear 6: Binding Wizard with Bind Button + optional Bind FN popups, plus a Toggle checkbox (hold vs latch). If FN is bound, the button requires that key held. Remove with X.
  • Axis→button on standard Assign and custom Binding Wizard: capturing an axis for a button target converts automatically (Activate on Axis threshold + live meter). Checkbox label is Invert.
  • Axis range (start/end) for axis→axis bindings: dual-handle slider remaps the usable throw. Separate from Activate on Axis (single % for axis→button).
  • Tabbed Settings modal (General / Overlays / HidHide) from the gear button; tray menu is Restore / Settings… / Exit.
  • HidHide apply modes: Off (default), Hide all (except emulator), Hide bound devices only, plus Save & restore on Stop (same snapshot behavior as before).

Changed

  • Renamed shared OEM EffectDriver g920ffb.dll → emuffb.dll (native/emuffb; %ProgramData%\SteeringWheelEmulator\emuffb\; %TEMP%\emuffb-effects.log). Same COM CLSID and SHM map name. On Start, legacy g920ffb cache / InprocServer32 paths migrate to emuffb.dll. Quit Steam once if it still holds the old DLL.
  • Docs: Forza device-profile findings — games author different FFB mixes per device class; virtual G920 gets sparse CF (grain on DDs) vs native Fanatec spring-led mix. Documented in docs/force-feedback.md, compatibility, architecture, user guide, README. PC Comp identity + shared emuffb covered in architecture / user guide / research notes.
  • Unified FFB core: unpaced physical CF apply is the default for all vendors (including Simucube / generic). Device pace and Interpolate are opt-in Output feel sliders only (defaults 0), not vendor-gated always-on.
  • Renamed Output feel CF pace → Device pace, Idle smooth → Interpolate, Gap hold → Gap fill (mix adjustments; JSON keys unchanged).
  • Interpolate / Gap fill apply as mix adjustments only (no idle rim-settle mute). Force Feedback tooltips describe effect only (no third-party product references).
  • Gap fill defaults to 0 (off) and shows/disables as off while Interpolate is off (was a misleading 80 ms default).
  • Output feel Device pace and Gap fill Bind buttons (− / + / Set as Default), matching Interpolate.
  • Telemetry Downshift settle (Speed dynamics): after a downshift, speed bleeds toward that gear’s max instead of snapping. Separate from Coast / Brake; 0 = off. (Restores the old Gear settle path that had been hard-pinned.)
  • FFB label clarity: Force deadzone (was Deadband; not Fanatec DEA), Slew rate (Simucube-style), DI chatter (was DI epsilon), Damper velocity / Damper deadzone (was Damp vel / Damp dead). Bind ids unchanged.
  • Damper velocity max capped at 200% (was 400%) to match Master / effect gains; legacy values above 200% clamp down.
  • FFB Raw / Default is always exact game mix (100% gains, no feel/shaping) and cannot be overwritten — Save with tweaks prompts Save As…; Default switches to Raw. Tuned presets are user-created only.
  • Renamed Output feel Soft start → Boot ease-in, now an on/off toggle: when on, mute forces for ~5 s when FFB first comes online so the base does not kick (was a ms fade slider). Moved under Force Feedback → Advanced Settings.
  • Renamed Force Feedback → Advanced mix → Advanced Settings.
  • Checkboxes use a toggle switch style app-wide (Settings, Force Feedback, bind dialogs); same on/off behavior.
  • Soft steering catch-up moved from Settings → Debug Test to Force Feedback → Advanced Settings (with Invert FFB). Saved with the FFB profile (default off).
  • Invert FFB moved under Force Feedback → Advanced Settings (with Invert Constant Force / damper scales).
  • Replaced Settings checkboxes Apply HidHide on Start / Restore my HidHide on Stop with the HidHide tab radios + restore checkbox (hidHideApplyMode in settings.json; legacy autoApplyHidHideConfigOnStart migrates).

Fixed

  • Forza / sparse-CF grain (optional): Output feel Device pace + Interpolate (full-path INT) + Gap fill can soften stepped OEM CF on DDs. Defaults off — unified unpaced core. Live push + SHM (FFB_TUNE devicePace / interpolate / gapFill). Apply-path EMA off. Advanced Settings Spring coeff / Friction coeff (0–200%).
  • Peak soft slider: 0 = off, slide up for more peak compression (was inverted: 100% = off, lower = stronger).
  • Spike cap: limit is a per-second |Δtorque| cap (like Slew), not a raw per-call clamp. Slider goes to 0 = off (was stuck at 5% minimum with “off” only at 100%). Legacy 100% migrates to 0. On the ~500 Hz OEM path, lowering the slider no longer turns into hard stair-steps that feel more rugged on DD bases.
  • HidHide Hide bound devices only: each Start syncs the hide list to the active profile — hides bound devices (match by DirectInput instance/product GUID and VID/PID) and unhides other gaming devices left hidden from a previous full-rig / Hide-all session. Wheel-only profiles no longer leave pedals/shifters cloaked after you switch profiles (or manually unhide them in HidHide Client).
  • Install folder still “in use” by Steam: never re-register emuffb.dll COM InprocServer32 to the install folder when the ProgramData cache copy fails; rewrite stale Desktop/install paths (HKCU/HKLM × 32/64-bit) to %ProgramData%\SteeringWheelEmulator\emuffb\; update the cache via temp+Replace. Diagnostics oem-registry.txt shows install vs ProgramData. If the folder was already locked from an older load, close Steam once after updating.
  • HOST_STALE / mid-session disconnect: virtual G920 uses interrupt-push WinUHid input (no ReadReport pull mode) so SubmitInputReport is not gated on a pending host read. Status + Debug log HOST_STALE / 2s heartbeats (hostReadAgeMs, notReadyDelta). No mid-session Col01 auto-recover for HOST_STALE or hard submit-fail (log + Stop/Start only; Settings opt-in later). Start/Stop orphan Col01 cleanup unchanged. Validated on Fanatec (idle + ~30 min live Unbound).
  • On bridge Start, disable Device Manager power-saving (“Allow the computer to turn off this device…”) for WinUHid / VHF nodes so Windows cannot sleep the virtual G920 while the app stays Running. Best-effort (needs elevation).
  • Telemetry synth, UDP send, and game-process probe run on a side thread (same idea as Simucube FFB apply). When Telemetry is off, the input loop skips that work entirely so SimHub I/O cannot stall virtual G920 reports.
  • Telemetry-on path no longer contends with HID/FFB on BridgeService’s main lock or double-reads OEM shared memory; process probe interval is 5s. (Freeze A/B: issue tracked with Telemetry enabled.)
  • Telemetry-on further lightened after Fanatec HOST_STALE (game stops reading Col01 while FFB continues): input thread enqueues at SendHz (not every ~2 ms), caches arcade-bind presence, and sheds samples when hostReadAge ≥ 250 ms.
  • Telemetry/OEM hot path: no per-frame CombinedTypeTorqueDi / effect-table string allocs (reuse buffers, throttle FFB diag text ~10 Hz), skip game-process probe while OEM is playing, avoid per-packet Engine-scale file writes and status-string rebuilds, ASCII gear packet fast-path, Telemetry UI meters only while that tab/overlay is visible.
  • Debug bridge-health log records steer/thr/brk, FFB cache age, and STALE_INPUT when the virtual report stops changing (Debug session only).
  • Debug bridge-health: hostReadAgeMs / notReady / HOST_STALE when mapped pedals move but the game stops reading the virtual G920 (distinguishes emulator soft-freeze from game DI/host stall).
  • Input profiles with unknown binding targets (e.g. saved by a newer build) no longer crash on launch: invalid rows are skipped and a Profile needs attention dialog asks you to rebind and Save.