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>
60 lines
1.8 KiB
C#
60 lines
1.8 KiB
C#
using RioJoy.Core.Mapping;
|
|
using Xunit;
|
|
|
|
namespace RioJoy.Core.Tests.Mapping;
|
|
|
|
public class RioMapEntryTests
|
|
{
|
|
[Fact]
|
|
public void Keyboard_NoRoutingFlags_DecodesModifiersAndValue()
|
|
{
|
|
// 0x8749 = hasLamp + alt + ctrl + shift, VK 0x49 ('I')
|
|
var e = new RioMapEntry(0x8749);
|
|
Assert.Equal(RioRouteKind.Keyboard, e.Kind);
|
|
Assert.True(e.HasLamp);
|
|
Assert.True(e.Alt);
|
|
Assert.True(e.Ctrl);
|
|
Assert.True(e.Shift);
|
|
Assert.False(e.Extended);
|
|
Assert.Equal(0x49, e.Value);
|
|
}
|
|
|
|
[Fact]
|
|
public void Extended_FlagDecodes()
|
|
{
|
|
// 0x88BE = hasLamp + extended, VK 0xBE
|
|
var e = new RioMapEntry(0x88BE);
|
|
Assert.Equal(RioRouteKind.Keyboard, e.Kind);
|
|
Assert.True(e.HasLamp);
|
|
Assert.True(e.Extended);
|
|
Assert.Equal(0xBE, e.Value);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(0x1009, RioRouteKind.Joystick)] // joy flag
|
|
[InlineData(0x2003, RioRouteKind.Hat)] // hat flag
|
|
[InlineData(0x4002, RioRouteKind.Mouse)] // mouse flag
|
|
[InlineData(0x7005, RioRouteKind.RioCommand)] // joy+hat+mouse → command
|
|
[InlineData(0x0041, RioRouteKind.Keyboard)] // none → keyboard
|
|
public void Kind_FollowsPrecedence(ushort raw, RioRouteKind expected)
|
|
{
|
|
Assert.Equal(expected, new RioMapEntry(raw).Kind);
|
|
}
|
|
|
|
[Fact]
|
|
public void Joystick_BeatsHatAndMouse_WhenMultipleSet()
|
|
{
|
|
// joy + hat set (but not mouse) → joystick wins
|
|
Assert.Equal(RioRouteKind.Joystick, new RioMapEntry(0x3001).Kind);
|
|
// hat + mouse set (but not joy) → hat wins
|
|
Assert.Equal(RioRouteKind.Hat, new RioMapEntry(0x6001).Kind);
|
|
}
|
|
|
|
[Fact]
|
|
public void Unmapped_IsZero()
|
|
{
|
|
Assert.True(new RioMapEntry(0).IsUnmapped);
|
|
Assert.False(new RioMapEntry(0x0041).IsUnmapped);
|
|
}
|
|
}
|