- TargetFrameworks net48;net40. net48 keeps x64 + ViGEm + System.IO.Ports
package; net40 adds Microsoft.Bcl.Async + System.ValueTuple and uses the
in-box SerialPort.
- Compat/TaskCompat bridges Task.Run/Delay/WhenAny/WhenAll (TaskEx on
net40) and SemaphoreSlim.WaitAsync (net40 blocks briefly - trivial at
9600 baud).
- IReadOnlyList/IReadOnlyDictionary -> IList/IDictionary throughout
(net40 predates the IReadOnly* interfaces and the Bcl backport cannot
make arrays implement them).
- HashCode.Combine replaced with a manual combine (Bcl.HashCode has no
net40 build); Marshal.SizeOf<T> -> typeof form; ViGEmJoystickSink
gated #if !NET40. HidFeederJoystickSink stays on both flavors - it
will drive RioGamepadXP.sys on XP via the same contract.
Both TFMs build; 275 tests green on net48.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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>
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>
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>
- 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>