using RioJoy.Core.Calibration; namespace RioJoy.Core.Output; /// /// Where a calibrated axis lands on the virtual Xbox 360 pad. Our own enum (no /// ViGEm types — these are shared config types, serialized into profiles and /// compiled for net40 too); translates to the /// ViGEm equivalents. = the axis is not emitted at all. /// public enum PadTarget { LeftThumbX, LeftThumbY, RightThumbX, RightThumbY, LeftTrigger, RightTrigger, None, } /// /// How a calibrated axis value (0..32766, center 16383) converts to a /// thumb-stick value. Meaningless for trigger targets (triggers always use the /// legacy value*255/32766 byte conversion). /// public enum AxisOutputMode { /// Legacy bipolar mapping: (value - 16383) * 2 → center 16383 = thumb 0. Centered, /// /// Unipolar mapping for axes whose calibrated rest is 0 (the ratcheted /// throttle): clamp(value, 0, 32767) → calibrated 0 = thumb center 0, /// 32766 = thumb max. Only the upper half of the thumb range is used. /// UnipolarPositive, } /// One axis route: which pad control it drives, and how the value converts. public sealed record AxisRoute { public PadTarget Target { get; init; } = PadTarget.None; public AxisOutputMode Mode { get; init; } = AxisOutputMode.Centered; } /// /// Per-profile routing of the six calibrated axes onto the ViGEm Xbox 360 pad /// (; null there = this /// default). The defaults reproduce the historical hardcoded sink routing /// exactly — X→LeftThumbX, Y→LeftThumbY, Rx→RightThumbX, Ry→RightThumbY, /// Z→LeftTrigger, Rz→RightTrigger, all — /// so existing profiles behave identically. Two axes routed to the same target /// are not arbitrated: the last SetAxis write wins. /// public sealed record AxisRoutingConfig { public AxisRoute X { get; init; } = new() { Target = PadTarget.LeftThumbX }; public AxisRoute Y { get; init; } = new() { Target = PadTarget.LeftThumbY }; public AxisRoute Z { get; init; } = new() { Target = PadTarget.LeftTrigger }; public AxisRoute Rx { get; init; } = new() { Target = PadTarget.RightThumbX }; public AxisRoute Ry { get; init; } = new() { Target = PadTarget.RightThumbY }; public AxisRoute Rz { get; init; } = new() { Target = PadTarget.RightTrigger }; /// The route for . public AxisRoute RouteFor(JoyAxis axis) => axis switch { JoyAxis.X => X, JoyAxis.Y => Y, JoyAxis.Z => Z, JoyAxis.Rx => Rx, JoyAxis.Ry => Ry, JoyAxis.Rz => Rz, _ => new AxisRoute(), // unknown axis → None (not emitted) }; }