Retargets RioJoy.Core/Overlay/Tray + tests from net8.0-windows to net48 so
the app can be tested as a framework-dependent build (relies on the in-box
.NET Framework 4.8 on Windows 10/11). Builds clean; all 241 tests pass.
Polyfills (no behavior change):
- PolySharp source generator for init/records/Index/Range/required members.
- System.Memory, System.Text.Json, Microsoft.Bcl.HashCode,
System.Threading.Channels (tests) NuGet packages.
- Compat/Net48Polyfills.cs: GetValueOrDefault, KeyValuePair.Deconstruct,
Math.Clamp; tests/TestPolyfills.cs: Task.WaitAsync.
Source adjustments for APIs absent on net48:
- ArgumentNullException/ArgumentException.ThrowIf* inlined to manual guards.
- Convert.ToHexString, Encoding.Latin1, Environment.ProcessPath,
ApplicationConfiguration.Initialize, Enum.GetNames<T>/GetValues<T>,
string.StartsWith(char), string.Split(char, opts), TextBox.PlaceholderText,
PeriodicTimer, Memory-based Stream Read/WriteAsync, array range-slicing.
- Dropped [SupportedOSPlatform] hints (net48 is single-platform).
deploy/build-package.ps1: publish framework-dependent (no self-contained).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
deploy/ builds a single zip for TeslaConsole: the self-contained tray app and
the signed ViGEmBus installer under a riojoy\ folder, with postinstall.bat at the
root. postinstall elevates and runs riojoy\install-rio.ps1, which installs
ViGEmBus silently (if absent) and registers RIOJoy to start at logon — no cert
trust, test signing, Secure Boot change, or reboot.
Also guard against two instances fighting over the COM port (machine-wide +
per-user autostart both firing): a per-session named mutex makes a second launch
exit immediately. Built zips (dist/) and the bundled installer (deploy/vendor/)
are git-ignored.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace the test-signed RioGamepad driver as the default joystick output with a
ViGEmBus virtual Xbox 360 controller (Nefarius.ViGEm.Client) — properly signed,
so it installs with no test-signing / Secure Boot change / reboot.
The coordinator now selects ViGEm first, then the RioGamepad HID feeder, then a
no-op. The XInput layout caps joystick buttons at 11, so the editor's joystick
picker lists the named Xbox buttons (A, B, X, Y, LB, RB, Back, Start, L3, R3,
Guide); the hat maps to the D-pad and the six axes to the sticks + triggers.
Bind anything beyond 11 to the keyboard.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add a "Triggers:" field under the profile name that edits the profile's
MatchExecutables (comma-separated, .exe optional). On save, the listed
foreground executables auto-activate the profile in Auto mode — no more
hand-editing config.json.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Profile name field in the editor (rename, with empty/duplicate checks);
"Edit profile" becomes a submenu listing each profile plus "New profile…".
- "Send button output to the PC" toggle: editor sessions route keyboard/mouse
and joystick through gates (GatedInputSink/GatedJoystickSink) that stay closed
until the user opts in, so editing never injects input by default.
- Save profile now confirms ("Saved ✓"/"Save failed") — the write was silent.
- A lit button renders dim at idle and bright only when physically pressed, so
the press stays visible (three states: off / dim-lit / bright-held).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
While a profile is being edited, light every pressed button on the RIO
(RioRuntime.EchoAllLamps, enabled for editor sessions) regardless of mapping,
so a physical press always responds. On the panel, a held button now
brightens the cell in its own colour (red MFD / blue keypad / yellow board)
instead of a cyan outline.
Surface the RIO version/check replies (RioRuntime.VersionReceived/
CheckReceived) and show them grouped in a new "RIO reply" box below the
command buttons when "Request version & status" is clicked. Drop the two
diagnostic readout-toggle buttons (comms bring-up leftovers).
Verified against the partial RIO on COM1 (firmware 4.2; MFD + keypad light
and report; missing-board status shown).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Profile editor:
- Cockpit-style encoder gauges centered over the Upper Middle MFD: Z left,
X/Y right, and L/R/Rz arranged as a big "U".
- [JoyStick] section surfaced as a vertical "Axis" toggle column (6 inverts
+ ZR mix), written back to the profile's calibration.
- Tighten the panel layout (close gaps, trim empty border columns); colour the
Secondary/Screen columns yellow; rename the "Joystick / Hat" board to
"Joystick"; add an "Import .ini..." tray entry.
- "RIO commands (live)" button group (all RioCommandCodes) fired at the live RIO.
Serial-port handling:
- Start dormant; only take the COM port for a profiled game (auto-switch) or
while editing, so the native games can open the port without clashing.
- Editor sessions hold the port but route keyboard/mouse/joystick to no-op
sinks (NullInputSink), so button function can be checked without injecting
input; RioRuntime.ButtonActivity drives a live cyan press indicator and
lamp feedback still applies.
- AutoSwitchWatcher.Reset() re-syncs the watcher after an editor session.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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>
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>
Make the virtual gamepad deployable on owned cabinets and wire the real
user-mode feeder:
- driver/sign.ps1 (non-admin): create a self-signed code-signing cert, build the
catalog with inf2cat, and SHA-256-sign RioGamepad.sys + .cat (embed-sign the sys
before cataloguing so the .cat matches). Exports RIOJoyTest.cer. Verified
end-to-end against the EWDK (signability + catalog clean; both files signed).
- driver/install.ps1 (admin, two-phase): trust the cert (LocalMachine Root +
TrustedPublisher), stage the package (pnputil /add-driver), enable test signing;
after reboot, -CreateDevice runs devgen to create root\RioGamepad so PnP installs
it. uninstall.ps1 reverses it.
- RioJoy.Core.Output.HidFeederJoystickSink: opens the driver by
GUID_DEVINTERFACE_RIOGAMEPAD (SetupAPI), maintains a RioHidReport, and submits it
via DeviceIoControl(IOCTL_RIO_SUBMIT_REPORT) on each axis/button/hat change.
RioCoordinator now uses it when the driver is present and falls back to the no-op
sink otherwise (status shows "[no joystick driver]").
- gitignore the signing outputs (driver/package/, *.cat); driver/README.md gets the
full build → sign → install → joy.cpl workflow.
Remaining = the actual elevated install + reboot + joy.cpl verification on the
cabinet (admin steps), and on-hardware confirmation of the feeder.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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>
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>