Invert Y on the wire, not in the router: the panel keeps tracking the stick
InputRouter.InvertJoystickY flipped the stored axis, so the X/Y dot and readout moved opposite the physical stick. The toggle now lives on VRioDevice and negates joystick Y only while building AnalogReply: local state keeps the physical direction for every source (pad, keys, panel drags) and only the host sees the flip. Negating a full -8192 deflection lands one past the 14-bit Max, so the reply clamps it to 8191. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -190,8 +190,8 @@ internal sealed class MainForm : Form
|
|||||||
if (!_kbInput.Checked)
|
if (!_kbInput.Checked)
|
||||||
_router.ReleaseAllKeys();
|
_router.ReleaseAllKeys();
|
||||||
};
|
};
|
||||||
_invertY.CheckedChanged += (_, _) => _router.InvertJoystickY = _invertY.Checked;
|
_invertY.CheckedChanged += (_, _) => _device.InvertJoystickY = _invertY.Checked;
|
||||||
_router.InvertJoystickY = _invertY.Checked; // the field initializer raises no event
|
_device.InvertJoystickY = _invertY.Checked; // the field initializer raises no event
|
||||||
_kbLights.CheckedChanged += (_, _) =>
|
_kbLights.CheckedChanged += (_, _) =>
|
||||||
{
|
{
|
||||||
_lampMirror.Enabled = _kbLights.Checked;
|
_lampMirror.Enabled = _kbLights.Checked;
|
||||||
|
|||||||
@@ -57,6 +57,13 @@ public sealed class VRioDevice
|
|||||||
/// <summary>Firmware version reported by VersionReply (real boards run 4.2).</summary>
|
/// <summary>Firmware version reported by VersionReply (real boards run 4.2).</summary>
|
||||||
public byte VersionMinor { get; set; } = 2;
|
public byte VersionMinor { get; set; } = 2;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Negate joystick Y in AnalogReply. Only the host sees the flip — local
|
||||||
|
/// state (<see cref="GetAxis"/>, the panel's dot and readout) keeps the
|
||||||
|
/// physical stick direction.
|
||||||
|
/// </summary>
|
||||||
|
public bool InvertJoystickY { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// When true, retry exhaustion leaves the analog reply path wedged (the
|
/// When true, retry exhaustion leaves the analog reply path wedged (the
|
||||||
/// v4.2 latch-leak bug) until a host ResetRequest clears it.
|
/// v4.2 latch-leak bug) until a host ResetRequest clears it.
|
||||||
@@ -274,6 +281,8 @@ public sealed class VRioDevice
|
|||||||
y = _axes[(int)RioAxis.JoystickY];
|
y = _axes[(int)RioAxis.JoystickY];
|
||||||
x = _axes[(int)RioAxis.JoystickX];
|
x = _axes[(int)RioAxis.JoystickX];
|
||||||
}
|
}
|
||||||
|
if (InvertJoystickY) // clamp: -Min (8192) is one past the 14-bit Max
|
||||||
|
y = (short)Math.Min(AnalogCodec.Max, -y);
|
||||||
Send(PacketBuilder.AnalogReply(t, l, r, y, x));
|
Send(PacketBuilder.AnalogReply(t, l, r, y, x));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|||||||
@@ -57,13 +57,6 @@ public sealed class InputRouter
|
|||||||
/// <summary>A routed address went down (true) or came back up (false) — for panel highlighting.</summary>
|
/// <summary>A routed address went down (true) or came back up (false) — for panel highlighting.</summary>
|
||||||
public event Action<int, bool>? AddressHeldChanged;
|
public event Action<int, bool>? AddressHeldChanged;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Flip the sign of the composed joystick Y before it reaches the device.
|
|
||||||
/// Applies to all routed sources (keys and pad) alike; panel drags write
|
|
||||||
/// the device directly and are unaffected.
|
|
||||||
/// </summary>
|
|
||||||
public bool InvertJoystickY { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The active bindings. Assigning releases everything currently held
|
/// The active bindings. Assigning releases everything currently held
|
||||||
/// (keys, toggles, pad buttons) so a reload never strands a pressed input.
|
/// (keys, toggles, pad buttons) so a reload never strands a pressed input.
|
||||||
@@ -223,8 +216,6 @@ public sealed class InputRouter
|
|||||||
if (b.Rate <= 0f)
|
if (b.Rate <= 0f)
|
||||||
total += Shape(_pad.Axis(b.Source), b);
|
total += Shape(_pad.Axis(b.Source), b);
|
||||||
}
|
}
|
||||||
if (InvertJoystickY && axis == RioAxis.JoystickY)
|
|
||||||
total = -total;
|
|
||||||
total = ClampNorm(axis, total);
|
total = ClampNorm(axis, total);
|
||||||
|
|
||||||
short raw = (short)Math.Round(total * RioAxisRange.Full(axis));
|
short raw = (short)Math.Round(total * RioAxisRange.Full(axis));
|
||||||
|
|||||||
@@ -191,26 +191,6 @@ public class InputRouterTests
|
|||||||
Assert.Equal(0, _device.GetAxis(RioAxis.JoystickY));
|
Assert.Equal(0, _device.GetAxis(RioAxis.JoystickY));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void InvertJoystickY_flips_the_composed_value_for_all_sources()
|
|
||||||
{
|
|
||||||
UseProfile("key Up axis JoystickY deflect 1\npadaxis LeftStickY axis JoystickY");
|
|
||||||
_router.InvertJoystickY = true;
|
|
||||||
|
|
||||||
_router.KeyDown("Up");
|
|
||||||
_router.Tick(0.016);
|
|
||||||
Assert.Equal(-RioAxisRange.JoystickExtent, _device.GetAxis(RioAxis.JoystickY));
|
|
||||||
_router.KeyUp("Up");
|
|
||||||
|
|
||||||
_router.SetPadState(new PadState(PadButtons.None, 0, 0.5f, 0, 0, 0, 0));
|
|
||||||
_router.Tick(0.016);
|
|
||||||
Assert.Equal(-RioAxisRange.JoystickExtent / 2, _device.GetAxis(RioAxis.JoystickY));
|
|
||||||
|
|
||||||
_router.InvertJoystickY = false; // toggling back re-sends the upright value
|
|
||||||
_router.Tick(0.016);
|
|
||||||
Assert.Equal(RioAxisRange.JoystickExtent / 2, _device.GetAxis(RioAxis.JoystickY));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Rate_key_walks_the_throttle_and_position_sticks()
|
public void Rate_key_walks_the_throttle_and_position_sticks()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -66,6 +66,27 @@ public class VRioDeviceTests
|
|||||||
Assert.Equal(1, device.AnalogRequests);
|
Assert.Equal(1, device.AnalogRequests);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void InvertJoystickY_flips_the_wire_but_not_local_state()
|
||||||
|
{
|
||||||
|
var device = new VRioDevice { InvertJoystickY = true };
|
||||||
|
var wire = new Wire(device);
|
||||||
|
device.SetAxis(RioAxis.JoystickY, 3000);
|
||||||
|
|
||||||
|
Send(device, PacketBuilder.Build(RioCommand.AnalogRequest));
|
||||||
|
|
||||||
|
byte[] p = Assert.Single(wire.Packets).Payload;
|
||||||
|
Assert.Equal(-3000, AnalogCodec.Combine(p[6], p[7]));
|
||||||
|
Assert.Equal(3000, device.GetAxis(RioAxis.JoystickY)); // the panel's view is unflipped
|
||||||
|
|
||||||
|
// Full negative deflection: -Min is one past Max, so it clamps rather than throws.
|
||||||
|
device.SetAxis(RioAxis.JoystickY, AnalogCodec.Min);
|
||||||
|
wire.Clear();
|
||||||
|
Send(device, PacketBuilder.Build(RioCommand.AnalogRequest));
|
||||||
|
p = Assert.Single(wire.Packets).Payload;
|
||||||
|
Assert.Equal(AnalogCodec.Max, AnalogCodec.Combine(p[6], p[7]));
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void VersionRequest_reports_configured_firmware()
|
public void VersionRequest_reports_configured_firmware()
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user