Commit Graph
20 Commits
Author SHA1 Message Date
CydandClaude Fable 5 02abfa8a14 Phase 8D: root README.txt + postinstall.bat cleans the C:\games root
The universal archive gains a root README.txt aimed at standalone
installers (which entry point to run, supported OSes, offline prereqs).
postinstall.bat (the TeslaConsole hook) deletes install.bat and that
README as its final step so cabinet deploys leave C:\games clean;
install.bat keeps the README as the standalone machine's docs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 20:27:41 -05:00
CydandClaude Fable 5 a9de26eff6 Phase 8: final decisions — editor everywhere, universal archive, dual installers
- Mapping editor ships in all instances, XP included (wallpaper maker
  stays modern-only with SkiaSharp).
- One dist zip deploys on both XP and Win10/11: app (net48 x64) +
  app-xp (net40 x86) + vendor prereqs incl. offline .NET 4.0/KB2468871
  redistributables and RioGamepadXP.sys.
- Two entry points: postinstall.bat (TeslaConsole/launcher, unattended)
  and install.bat (freestanding, adds shortcuts). OS-detected via ver;
  pure cmd on the XP path.

All Phase 8 open decisions are now resolved; ready to implement 8A.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 20:22:20 -05:00
CydandClaude Fable 5 6ad1abc919 Phase 8 decision: no vJoy — XP gets RioGamepadXP.sys, our own HID minidriver
vJoy/PPJoy are unmaintained, so third-party virtual joysticks are out.
The XP joystick becomes a thin WDM HID minidriver (vhidmini shape,
WDK 7.1.0, x86, no signing required on XP) exposing the same Public.h
IOCTL + 25-byte report contract as the modern RioGamepad.sys, so
HidFeederJoystickSink drives both. Precedent: FASA's tasgame.sys was an
XP HID minidriver. Staged: XP app ships keyboard/lamps/plasma first,
driver as milestone 2. Win10/11 chain unchanged (ViGEm preferred).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 20:14:23 -05:00
CydandClaude Fable 5 ae7a5d21ee Phase 8 decision: Xbox 360 pad (ViGEm) stays preferred on Win10/11
vJoy is fallback-only on modern Windows and the primary backend on XP.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 20:12:06 -05:00
CydandClaude Fable 5 39d79e1fb1 Plan Phase 8: Windows XP compatibility (net40/x86 + vJoy dual-target)
One codebase, two flavors: Win10/11 stays net48/x64 with ViGEm/RioGamepad
and remains the authoring platform; XP SP3 gets a net40/x86 runtime with
vJoy (full 96-button fidelity), pre-rendered wallpapers (PNG converted to
BMP at apply), Newtonsoft JSON shared by both flavors, Bcl.Async + small
compat shims, and a .bat-only installer. Grounded in a source audit:
about 20 Span/Memory uses in the 9600-baud serial path, 6 modern Task
calls, 1 HashCode.Combine, System.Text.Json in two stores.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 19:55:38 -05:00
CydandClaude Fable 5 2ac3188528 Fix pedal gauges frozen under ZR mix: feed L/R from pre-mix pedal readouts
The editor's L/R gauges read Rx/Ry, but EnableZR (on in real profiles)
folds the pedals into Rz and pins Rx/Ry to center, so the bars never
moved with the physical pedals. AxisCalibrator now exposes
LeftPedalOutput/RightPedalOutput (the calibrated pre-mix positions) and
RioRuntime.AxesUpdated carries an AxisReadout (the six virtual axes +
both pedals); the strip draws L/R from the pedal readouts, Z/Rz/X/Y
from the axes. With ZR off the readouts equal Rx/Ry, so nothing
changes there. Verified by screenshot: Rx/Ry centered while L=75% and
R=25% render correctly.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 10:22:05 -05:00
CydandClaude Fable 5 e60d551f39 Phase 7: live encoder gauges in the profile editor
RioRuntime raises AxesUpdated with the calibrated AxisOutputs after every
analog reply (independent of the joystick sink, so the gauges work while
editor input routing is suppressed). The editor strip now renders the
values live: Z and the L/R pedals (Rx/Ry) fill bottom-up, Rz deflects
from a center tick, and the X/Y box tracks the stick as a dot over a
crosshair. Fraction/deflection math is pure in Core.Editing.AxisGauges
(clamped, unit-tested); the canvas repaints only the strip and only on
change. Verified by offline form screenshots against injected values.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 09:37:29 -05:00
CydandClaude Fable 5 d1a938dd43 Phase 7: region box editor in the wallpaper maker
"Edit cell boxes" mode: the selected cell grows resize handles on the
preview -- drag to move/resize with live outline tracking and a re-render
on drop, or type exact X/Y/W/H in the new geometry fields. Plain clicks
still select and cycle stacked cells (click-vs-drag resolved by a movement
threshold on mouse-up). The move/resize math is pure and unit-tested
(OverlayRegionEdit: corner/edge/move handle hit-testing with tolerance,
min-size clamped resizing that pins the opposite edge). "Save template"
persists the shared cell geometry back to the regions.json; "Reload
template" re-reads it to discard unsaved box edits. Cursor feedback per
handle; template save/reload disabled when no template path was supplied.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 01:14:36 -05:00
CydandClaude Fable 5 0623891f74 Phase 7: wallpaper maker (live preview, click-to-edit labels, .data import)
The interactive replacement for the legacy Sheet -> GIMP/Script-Fu pipeline:
WallpaperMakerForm (tray -> "Wallpaper maker") renders the profile wallpaper
live via SkiaOverlayRenderer, outlines all 119 template cells, and lets any
cell -- including the heading/banner cells the button editor cannot reach --
be clicked and retitled with debounced re-render. Clicks on stacked cells
cycle through the regions at that pixel (OverlayHitTester, unit-tested);
stacking is legitimate chroma-split display encoding. Imports a legacy .data
sheet row (with a game picker for multi-row sheets), exports the PNG, and can
apply the desktop wallpaper immediately to the same per-profile path the
runtime uses. Prompts for and remembers AppConfig.OverlayTemplatePath on
first use. PLAN.md: record this + the completed Phase 6 deploy package.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 00:54:54 -05:00
CydandClaude Opus 4.8 b275892451 Remove auto-start: launcher owns the app lifecycle
The TeslaConsole launcher starts and stops RIOJoy, so the app no longer
registers any auto-start entry:
- install-rio.ps1: drop the HKLM ...\Run registration and the post-install
  launch (and the -NoLaunch param).
- Tray: remove the "Start with Windows" menu item and delete AutoStartManager
  (HKCU ...\Run writer).
- AppConfig: drop the now-inert AutoStart field (+ test).
- Docs (PLAN.md, README-DEPLOY.txt) updated to reflect launcher-managed start/stop.

uninstall-rio.ps1 still clears any leftover Run entry from older auto-starting
builds. Solution builds; 241 tests pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 14:36:32 -05:00
CydandClaude Opus 4.8 270abfc5ad Docs: reflect net48; convert tools projects to net48
Documentation now describes the .NET Framework 4.8 stack (was .NET 8):
- README build prerequisites + framework-dependent/no-runtime-install note,
  test count 136 -> 241.
- PLAN.md architecture diagram, stack decision (with PolySharp/shims note),
  suite total 136 -> 241.
- deploy/README-DEPLOY.txt: app is net48 framework-dependent (4.8 is in-box on
  Win10/11), and build prerequisites.

Also migrate the three tools (RioJoySmokeTest, RioSerialMonitor, XcfRegionExtract)
to net48 so they keep building against the now-net48 RioJoy.Core (a net8 project
cannot reference a net48 one). Added PolySharp + System.Memory/System.Text.Json
shims and replaced net-core-only APIs (string.Contains/IndexOf with comparison,
Array.Fill, generic Enum.IsDefined, int.TryParse(span)). All three build clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 13:11:25 -05:00
CydandClaude Opus 4.8 094637b0a4 Editor: rework to the original Win32 RIO control-panel layout
Reworked the profile/mapping editor to mirror the original unfinished Win32
RIO driver's control-panel design (docs/Win32RIO, by FASA / Michel Lowrance)
instead of the flat config-sheet grid. The wallpaper region positions are a
VGA chroma-split display artifact, not the cockpit's logical shape.

- RioJoy.Core.Editing.CockpitPanel: the functional layout — five MFD clusters,
  four board columns (Throttle/Secondary/Screen/Joystick-Hat), an encoder-gauge
  strip, and the two later-added 4x4 keypads (Internal/External). Places every
  address 0x00-0x47 / 0x50-0x6F exactly once (unit-tested).
- Tray PanelView/PanelCanvas render the panel; ProfileEditorForm drives it.
  Buttons show label + assigned function (ButtonBinding.Describe -> CTL-N, JOY1,
  POV-U, Mse LB, RIO command names; unit-tested). Lamp shade is driven by the
  IsLit flag (not by whether a function is assigned); keypads are neutral blue
  with no Lit checkbox. Added an Unassign button next to Apply.
- Removed the superseded sheet-grid UI (SheetView/SheetCanvas); SheetLayout +
  config-sheet.csv stay as reference data.

docs/Win32RIO: the original driver (tasgame.sys, a 32-bit kernel HID minidriver
that opened the serial port, set baud/8N1/DTR, and spoke the *identical* RIO
protocol -- AnalogRequest/Reply, Button Pressed/Released, Check/Lamp/Reset/
Version -- validating our protocol port), oemsetup.inf, RemoteDriver.doc, and the
extracted control-panel / game-controllers mockups.

~236 xUnit tests green. PLAN.md updated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 19:48:14 -05:00
CydandClaude Opus 4.8 8d2d0b71aa Phase 7: cockpit overlay generator, region extraction, and profile editor
Overlay generator (pure, tested) — RioJoy.Core/Overlay:
- FontFitter ports the legacy calc-fontsize auto-fit search (validated against a
  brute-force oracle); OverlayLayoutEngine ports create-data-layer's fit + h/v
  justification and adds per-region 90 deg CCW rotation; OverlayTemplate/Region +
  OverlayTemplateStore hold cell geometry/colour/rotation (regions.json).
- GoobieDataImporter parses the legacy .data label sheet into label rows.
- src/RioJoy.Overlay: SkiaSharp rasterizer (SkiaTextMeasurer shared with the engine
  so measured layout == drawn output; SkiaOverlayRenderer -> PNG;
  ProfileWallpaperGenerator). Verified end-to-end on the real cockpit art
  (regions.json + riojoy.png + TEST.data) by OverlayRenderIntegrationTests.
- RioJoy.Tray/WallpaperApplier applies via SystemParametersInfo; RioCoordinator
  generates+applies on profile activation (opt-in via AppConfig.OverlayTemplatePath).

Region geometry — tools/XcfRegionExtract parses riojoy.xcf (a GIMP-format binary
reader, no GIMP needed) into the 119-cell regions.json: per-layer offsets/size/
font/colour, with 90 deg CCW rotation on a-00 + b-10..b-1F. Base image riojoy.png.
NOTE: the wallpaper positions are a VGA chroma-split display artifact (6 displays),
not the cockpit's logical layout.

Mapping editor (first cut) — RioJoy.Tray/Editor/ProfileEditorForm renders the
config sheet's logical grid (SheetLayout parses the sheet CSV export). The iRIO
word is edited via ButtonBinding <-> RioMapEntry.Create (no hex bit-twiddling), with
a context-sensitive picker: keyboard keys by name (KeyCatalog VK names), joystick
Button N, hat direction, mouse/RIO-command enum names; modifiers only for keyboard.
Opened from the tray ("Edit profile..."). The sheet-grid layout is a starting point
that needs rework from a better-formatted source.

~220 xUnit tests green. Docs (PLAN.md, README) updated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 17:13:48 -05:00
CydandClaude Opus 4.8 2deeb374ae Verify HID feeder end-to-end; add smoke-test tool; update docs
The RioGamepad driver now installs and enumerates, so the user-mode
feeder path is verifiable. Add tools/RioJoySmokeTest, a standalone
on-cabinet utility that drives the real HidFeederJoystickSink (open the
device, submit reports via IOCTL_RIO_SUBMIT_REPORT) and reads the gamepad
back through winmm joyGetPosEx, asserting axes (min/mid/max), buttons,
and the POV hat all surface to the OS. Verified: all checks pass against
the installed driver.

Update docs to match reality (PLAN.md predated the HidFeederJoystickSink
commit): Phase 1 is now test-signed/installed/verified with the VHF
LowerFilters requirement noted; the stale "NullJoystickSink placeholder"
remainders in Phases 3 and 5 are corrected to reflect the wired,
verified feeder. driver/README.md notes the end-to-end verification.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 23:56:16 -05:00
CydandClaude Opus 4.8 24cdf495e3 Phase 1: RioGamepad virtual HID driver (KMDF + VHF) + C# report packer
Author the custom virtual HID gamepad that replaces vJoy, and pin its wire
format on both sides. Builds clean to RioGamepad.sys against the EWDK
(KMDF 1.15 + VHF, x64, warnings-as-errors).

driver/RioGamepad/:
- ReportDescriptor.h: 6x16-bit axes (X,Y,Z,Rx,Ry,Rz), one 4-direction hat with
  null state, and 96 buttons — the legacy vJoy layout. 25-byte input report.
- Device.c/Driver.c: KMDF root-enumerated device that creates the VHF virtual HID
  device (VhfCreate in DeviceAdd, VhfStart in D0Entry, VhfDelete on cleanup) and
  exposes a device interface + IOCTL_RIO_SUBMIT_REPORT that forwards the caller's
  report bytes to VhfReadReportSubmit. Thin relay: no report logic in the kernel.
- Public.h: device-interface GUID, IOCTL, and the report byte layout shared with
  the C# client. RioGamepad.inf + build.cmd (EWDK build, catalog/sign disabled).

src/RioJoy.Core/Hid/RioHidReport.cs: packs AxisOutputs + hat + 96 buttons into
the exact 25-byte report (LE axes, hat nibble with 0x0F=centered, button bitmap).
13 new xUnit tests (136 total).

Remaining (deploy-side): test-sign + pnputil install + verify in joy.cpl, and
wire the real DeviceIoControl feeder sink (replacing NullJoystickSink). The
EWDK's in-build catalog task (DrvCat) can't load Microsoft.Kits.Logger on this
image, so the .cat is produced with inf2cat/signtool at install time instead.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 21:06:16 -05:00
CydandClaude Opus 4.8 1348040e1c Phase 5: tray app + profiles + runtime wiring
Wire the Core pieces into a runnable tray app with per-game profiles and the
three-state serial-yield auto-switch:

- Profiles/: RioProfile + AppConfig model; ConfigStore (System.Text.Json,
  round-tripped); RioIniImporter ports the legacy RIO.ini (button table, invert
  flags, plasma greeting); AutoSwitchResolver + AutoSwitchWatcher resolve the
  foreground executable into Yield (native game) / Activate (profile) / Idle, with
  native always winning and change-only notifications. IForegroundProcessProvider
  abstracts the OS.
- RioRuntime assembles a profile's live pipeline: serial ButtonPressed/Released +
  KeyPressed/Released → InputRouter (via RioAddress); AnalogReply → AxisCalibrator
  → the six joystick axes; RIO commands → calibration resets + version/check
  requests + lamp re-init. SerialLampSink sends lamp feedback over the link;
  NullJoystickSink is a placeholder until the Phase 1 HID feeder exists.
- RioJoy.Tray: NotifyIcon menu mirroring the legacy console menu (axis resets,
  version/status, raw-axes & poll-rate toggles, quit) + profile selection
  (auto vs. manual) + "start with Windows"; RioCoordinator owns the serial
  acquire/release tied to the watcher (native-game COM-port yield). OS adapters:
  ForegroundProcessProvider (Win32 foreground PID→exe) and AutoStartManager (HKCU
  Run key).
- tests: 18 new xUnit tests (123 total) for config round-trip, ini import,
  the three-state resolver + watcher, and RioRuntime end-to-end over the fake
  transport (button→joystick, keypad-offset→keyboard, analog→six axes).

The joystick output stays a no-op until the Phase 1 driver; on-cabinet
verification of the acquire/release lifecycle remains.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 15:36:58 -05:00
CydandClaude Opus 4.8 24a1b64519 Phase 4: axis calibration + plasma display (RioJoy.Core)
Port the analog calibration math and the plasma/VFD command set:

- Calibration/: AxisCalibrator ports UpdateThrottle/UpdatePadal/UpdateJoystick
  (riovjoy2.cpp#L1504+) — throttle deadzone + ratchet field, pedal deadzones,
  joystick X/Y auto-ranging from observed min/max, rudder mixing (enableZR), and
  the per-axis invert flags. Stateful (start positions, last outputs, observed
  extremes) like the legacy globals, with the RIOcmd axis resets. Final outputs
  clamp to the documented 0..32766 range (also guards a legacy compounding quirk).
  AxisOutputs carries the six values; IJoystickSink gains SetAxis(JoyAxis,value)
  so calibrated axes reach the HID feeder.
- Plasma/: PlasmaCommands builds the CPlasma ESC sequences (clear/cursor/font/
  attr/box draw+fill/text) + GetFontSize + the PlasmaPosText auto-fit/centering;
  PlasmaDisplay writes them over the secondary COM transport.
- tests: 21 new xUnit tests (105 total) for throttle proportional/saturation/
  invert, pedal ZR mix vs. direct, joystick centering/direction/invert/reset, the
  output clamp, and plasma byte sequences/font sizes/auto-fit positioning.

Hardware verification of axis feel + plasma output remains; the game-specific
PlasmaScoreDraw layout is deferred to profile content (Phase 5/7).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 15:24:45 -05:00
CydandClaude Opus 4.8 cc64d241c9 Phase 3: input mapping + output routing (RioJoy.Core.Mapping)
Port the iRIO decode and Press_V2/Release_V2 routing into testable C#:

- Mapping/: RioMapEntry decodes the 16-bit map word (lamp/mouse/hat/joy/extended/
  alt/ctrl/shift flags + value) and resolves the routing Kind by the legacy
  precedence (joy+hat+mouse => RIO command; none => keyboard; else joy>hat>mouse).
  RioAddress translates button/keypad events to table addresses (+0x50/+0x60
  keypad offsets); RioInputMap is the 112-entry per-profile table replacing the
  hard-coded iRIO[].
- InputRouter ports Press_V2/Release_V2: modifier press/release ordering,
  scancode keys, joystick buttons, POV hat, mouse move/click (deltas corrected
  per PROTOCOL.md), RIO-command dispatch, and lamp feedback (bright on press, dim
  on release; RIO commands carry none). InitializeLamps() dims all lamp entries.
- Output is split behind sink interfaces (IInputSink/IJoystickSink/ILampSink/
  IRioCommandSink) so routing is pure + unit-tested; Output/SendInputSink is the
  real SendInput keyboard/mouse adapter (scancode injection).
- tests: 30 new xUnit tests (84 total) for entry decode, address translation,
  and router routing/precedence/lamp/modifier ordering via a recording sink.

The joystick sink's real adapter (HID feeder -> RioGamepad via DeviceIoControl)
is blocked on the Phase 1 driver; routing already targets IJoystickSink.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 15:10:06 -05:00
CydandClaude Opus 4.8 b3cb764f4d Phase 2: serial + RIO protocol core (RioJoy.Core) with unit tests
Port the RIO wire protocol from legacy/riovjoy2.cpp into testable C#:

- Protocol/: command + length table, 7-bit checksum, packet builder, and a
  streaming receive-side framing state machine (PacketParser) that mirrors the
  legacy ReadCommBlock framing/resync (high-bit-mid-packet abort). Typed RIO->PC
  decodes: AnalogReport (14-bit sign-extend), VersionInfo, CheckStatus; lamp-state
  composition.
- Serial/: RioSerialLink drives an async receive loop with ACK/NAK reply policy
  (legacy force-accept vs. opt-in VerifyInboundChecksum), the analog poll timer,
  and the >5s reset-recovery watchdog. IRioTransport abstracts the COM port; the
  SerialPort-backed transport does 9600 8N1 + DTR reset pulse, and acquire/release
  is just create/dispose (foundation for native-game serial yield).
- tests/RioJoy.Core.Tests: 54 xUnit tests covering checksum, framing/resync,
  builder round-trips, analog sign-extension + sentinel rejection, lamp combos,
  and the read loop driven against an in-memory fake transport.

Hardware verification (version/check/analog against a cabinet) remains; it can't
be done off-device.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 13:04:03 -05:00
CydandClaude Opus 4.8 39a3dab1fc Phase 0: scaffold modern RIOJoy solution + plan
Modernization of the legacy vJoy-based RIO cockpit interface for Win10/11,
removing the vJoy dependency in favor of a custom VHF/UMDF HID driver,
rewritten in C#/.NET 8 as a background tray app with per-game profiles.

- Reorganize: legacy C++ -> legacy/, cockpit art -> docs/reference/
- RioJoy.sln: src/RioJoy.Core (lib) + src/RioJoy.Tray (tray app), net8.0-windows x64
- driver/ placeholder for the RioGamepad WDK driver
- docs/PLAN.md (7-phase plan; profiles + serial-yield model)
- docs/PROTOCOL.md (RIO wire format + iRIO input-map reference)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 12:43:01 -05:00