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)
};
}