You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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_TUNEdevicePace / 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.