using RioJoy.Core.Calibration; namespace RioJoy.Core.Output; /// /// A resolved axis write: which pad control to drive and the converted value. /// is in the thumb range (-32768..32767) for thumb /// targets, the trigger range (0..255) for trigger targets, and 0 for /// (nothing is written). /// public readonly struct ResolvedAxis { public PadTarget Target { get; } public int Value { get; } public ResolvedAxis(PadTarget target, int value) { Target = target; Value = value; } public override string ToString() => $"{Target}:{Value}"; } /// /// Pure route-resolution + value-conversion for the ViGEm sink — no ViGEm types, /// so the decision logic is unit-testable without the bus driver. /// translates the result into ViGEm calls. /// public static class AxisRouter { /// /// Resolve where the calibrated (0..32766, /// center 16383) of lands under /// , and convert it for that target. /// public static ResolvedAxis Resolve(AxisRoutingConfig config, JoyAxis axis, int value) { if (config is null) throw new ArgumentNullException(nameof(config)); AxisRoute route = config.RouteFor(axis); return route.Target switch { PadTarget.None => new ResolvedAxis(PadTarget.None, 0), PadTarget.LeftTrigger or PadTarget.RightTrigger => new ResolvedAxis(route.Target, ToTrigger(value)), _ => new ResolvedAxis( route.Target, route.Mode == AxisOutputMode.UnipolarPositive ? ToUnipolarThumb(value) : ToCenteredThumb(value)), }; } // RIO axis 0..32766 (centre 16383) -> Xbox thumb short -32768..32767 (legacy math). private static int ToCenteredThumb(int value) => Compat.Net48Math.Clamp((value - AxisOutputs.Center) * 2, (int)short.MinValue, short.MaxValue); // Unipolar RIO axis (rest = 0) -> upper thumb half: 0 -> center 0, 32766 -> max. private static int ToUnipolarThumb(int value) => Compat.Net48Math.Clamp(value, 0, (int)short.MaxValue); // RIO axis 0..32766 -> Xbox trigger byte 0..255 (legacy math). private static int ToTrigger(int value) => Compat.Net48Math.Clamp(value * 255 / AxisOutputs.Max, 0, 255); }