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>
52 lines
1.9 KiB
C#
52 lines
1.9 KiB
C#
namespace RioJoy.Core.Mapping;
|
||
|
||
/// <summary>
|
||
/// Translates raw RIO events into an <c>iRIO</c> table address. The 72 digital
|
||
/// buttons map to <c>0x00–0x47</c> directly; keypad 0 is offset by <c>0x50</c>
|
||
/// and keypad 1 by <c>0x60</c> (port of <c>KeypadEvent</c>, riovjoy2.cpp#L1185);
|
||
/// see docs/PROTOCOL.md §5.
|
||
/// </summary>
|
||
public static class RioAddress
|
||
{
|
||
/// <summary>Number of digital button inputs (addresses 0x00–0x47).</summary>
|
||
public const int ButtonCount = 72;
|
||
|
||
/// <summary>Address offset added to keypad-0 key indices.</summary>
|
||
public const int Keypad0Base = 0x50;
|
||
|
||
/// <summary>Address offset added to keypad-1 key indices.</summary>
|
||
public const int Keypad1Base = 0x60;
|
||
|
||
/// <summary>Highest valid address (keypad 1, index 0x0F).</summary>
|
||
public const int MaxAddress = Keypad1Base + 0x0F; // 0x6F
|
||
|
||
/// <summary>Size of the <c>iRIO</c> table (addresses 0x00..0x6F inclusive).</summary>
|
||
public const int TableSize = MaxAddress + 1; // 112
|
||
|
||
/// <summary>Address for a digital button event (<paramref name="index"/> 0x00–0x47).</summary>
|
||
public static int FromButton(byte index)
|
||
{
|
||
if (index >= ButtonCount)
|
||
throw new ArgumentOutOfRangeException(
|
||
nameof(index), $"Button index must be 0..{ButtonCount - 1}.");
|
||
return index;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Address for a keypad key event: <paramref name="pad"/> 0 or 1,
|
||
/// <paramref name="index"/> 0x00–0x0F. Mirrors the legacy offsets (+0x50 / +0x60).
|
||
/// </summary>
|
||
public static int FromKeypad(byte pad, byte index)
|
||
{
|
||
if (index > 0x0F)
|
||
throw new ArgumentOutOfRangeException(nameof(index), "Keypad index must be 0..0x0F.");
|
||
|
||
return pad switch
|
||
{
|
||
0 => Keypad0Base + index,
|
||
1 => Keypad1Base + index,
|
||
_ => throw new ArgumentOutOfRangeException(nameof(pad), "Keypad must be 0 or 1."),
|
||
};
|
||
}
|
||
}
|