New input pipeline: sources feed an InputRouter (VRio.Core.Input) that calls the same VRioDevice press/release/axis entry points the mouse canvas uses, so routed input is indistinguishable on the wire. - Bindings live in %APPDATA%\vRIO\bindings.txt (plain text, commented defaults written on first run; Reload/Edit buttons in the new Input group). Keys and pad buttons press any RIO address, momentary or toggle; axes bind in normalized units of each axis realistic travel window with deflect (spring-back), rate (position holds), deadzone, and invert options - RioAxisRange supplies the wire signs. - Router suppresses key auto-repeat, edge-detects pad buttons, and hold-counts per address so overlapping sources press once and release last; axes only write when the composed value changes, so mouse drags keep working while sources idle. - Xbox pad via a zero-dependency XInput P/Invoke poller (xinput1_4, fallback xinput9_1_0), throttled rescan while disconnected. - MainForm intercepts bound keys in ProcessCmdKey so arrows/space reach the panel instead of moving focus; keys release on focus loss; center-axes and host ResetRequest reset the rate integrators. - Canvas highlights router-held addresses like clicks. - Defaults: arrows=stick, W/S=throttle, Q/E=pedals, numpad=internal keypad, IJKL/Space=hat+main; pad left stick/triggers/right stick = stick/pedals/throttle-rate, ABXY/dpad/shoulders = named buttons. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
77 lines
2.0 KiB
C#
77 lines
2.0 KiB
C#
namespace VRio.Core.Input;
|
||
|
||
/// <summary>
|
||
/// Gamepad button flags, bit-for-bit the XInput <c>wButtons</c> mask so the
|
||
/// App-side poller can cast the native value straight through.
|
||
/// </summary>
|
||
[Flags]
|
||
public enum PadButtons : ushort
|
||
{
|
||
None = 0,
|
||
DPadUp = 0x0001,
|
||
DPadDown = 0x0002,
|
||
DPadLeft = 0x0004,
|
||
DPadRight = 0x0008,
|
||
Start = 0x0010,
|
||
Back = 0x0020,
|
||
LeftThumb = 0x0040,
|
||
RightThumb = 0x0080,
|
||
LeftShoulder = 0x0100,
|
||
RightShoulder = 0x0200,
|
||
A = 0x1000,
|
||
B = 0x2000,
|
||
X = 0x4000,
|
||
Y = 0x8000,
|
||
}
|
||
|
||
/// <summary>A gamepad analog control usable as a binding source.</summary>
|
||
public enum PadAxis
|
||
{
|
||
LeftStickX,
|
||
LeftStickY,
|
||
RightStickX,
|
||
RightStickY,
|
||
LeftTrigger,
|
||
RightTrigger,
|
||
}
|
||
|
||
/// <summary>
|
||
/// One normalized gamepad snapshot: sticks −1..+1 (up/right positive),
|
||
/// triggers 0..1. The default value is "pad at rest / no pad connected".
|
||
/// </summary>
|
||
public readonly struct PadState
|
||
{
|
||
public PadState(PadButtons buttons,
|
||
float leftStickX, float leftStickY, float rightStickX, float rightStickY,
|
||
float leftTrigger, float rightTrigger)
|
||
{
|
||
Buttons = buttons;
|
||
LeftStickX = leftStickX;
|
||
LeftStickY = leftStickY;
|
||
RightStickX = rightStickX;
|
||
RightStickY = rightStickY;
|
||
LeftTrigger = leftTrigger;
|
||
RightTrigger = rightTrigger;
|
||
}
|
||
|
||
public PadButtons Buttons { get; }
|
||
public float LeftStickX { get; }
|
||
public float LeftStickY { get; }
|
||
public float RightStickX { get; }
|
||
public float RightStickY { get; }
|
||
public float LeftTrigger { get; }
|
||
public float RightTrigger { get; }
|
||
|
||
/// <summary>Value of one analog control.</summary>
|
||
public float Axis(PadAxis axis) => axis switch
|
||
{
|
||
PadAxis.LeftStickX => LeftStickX,
|
||
PadAxis.LeftStickY => LeftStickY,
|
||
PadAxis.RightStickX => RightStickX,
|
||
PadAxis.RightStickY => RightStickY,
|
||
PadAxis.LeftTrigger => LeftTrigger,
|
||
PadAxis.RightTrigger => RightTrigger,
|
||
_ => 0f,
|
||
};
|
||
}
|