VirtualButton system

pull/20/head
cosmonaut 2022-07-12 16:09:23 -07:00
parent 3543f074f4
commit d07a722fb1
16 changed files with 443 additions and 209 deletions

View File

@ -1,15 +1,38 @@
using System;
using MoonWorks.Math;
using SDL2;
namespace MoonWorks.Input namespace MoonWorks.Input
{ {
public class Axis public class Axis
{ {
IntPtr GamepadHandle;
SDL.SDL_GameControllerAxis SDL_Axis;
public AxisCode Code { get; private set; }
/// <summary> /// <summary>
/// An axis value between -1 and 1. /// An axis value between -1 and 1.
/// </summary> /// </summary>
public float Value { get; private set; } public float Value { get; private set; }
internal void Update(float value) public Axis(
IntPtr gamepadHandle,
AxisCode code,
SDL.SDL_GameControllerAxis sdlAxis
) {
GamepadHandle = gamepadHandle;
SDL_Axis = sdlAxis;
Code = code;
}
internal void Update()
{ {
Value = value; Value = MathHelper.Normalize(
SDL.SDL_GameControllerGetAxis(GamepadHandle, SDL_Axis),
short.MinValue, short.MaxValue,
-1, 1
);
} }
} }
} }

View File

@ -0,0 +1,14 @@
namespace MoonWorks.Input
{
public enum AxisButtonCode
{
LeftX_Left,
LeftX_Right,
LeftY_Up,
LeftY_Down,
RightX_Left,
RightX_Right,
RightY_Up,
RightY_Down
}
}

View File

@ -1,7 +1,7 @@
namespace MoonWorks.Input namespace MoonWorks.Input
{ {
// Enum values are equivalent to the SDL GameControllerButton value. // Enum values are equivalent to the SDL GameControllerButton value.
public enum ButtonCode public enum GamepadButtonCode
{ {
A, A,
B, B,

View File

@ -1,59 +0,0 @@
namespace MoonWorks.Input
{
// Blittable identifier that can be used for button state lookups.
public struct ButtonIdentifier : System.IEquatable<ButtonIdentifier>
{
public DeviceKind DeviceKind { get; }
public int Index { get; } // 1-4 for gamepads, 0 otherwise
public int Code { get; }
public ButtonIdentifier(Gamepad gamepad, ButtonCode buttonCode)
{
DeviceKind = DeviceKind.Gamepad;
Index = gamepad.Index;
Code = (int) buttonCode;
}
public ButtonIdentifier(KeyCode keyCode)
{
DeviceKind = DeviceKind.Keyboard;
Index = 0;
Code = (int) keyCode;
}
public ButtonIdentifier(MouseButtonCode mouseCode)
{
DeviceKind = DeviceKind.Mouse;
Index = 0;
Code = (int) mouseCode;
}
public override int GetHashCode()
{
return System.HashCode.Combine(DeviceKind, Index, Code);
}
public override bool Equals(object obj)
{
return obj is ButtonIdentifier identifier && Equals(identifier);
}
public bool Equals(ButtonIdentifier identifier)
{
return
DeviceKind == identifier.DeviceKind &&
Index == identifier.Index &&
Code == identifier.Code;
}
public static bool operator ==(ButtonIdentifier a, ButtonIdentifier b)
{
return a.Equals(b);
}
public static bool operator !=(ButtonIdentifier a, ButtonIdentifier b)
{
return !(a == b);
}
}
}

View File

@ -9,7 +9,7 @@
public bool IsDown => ButtonStatus == ButtonStatus.Pressed || ButtonStatus == ButtonStatus.Held; public bool IsDown => ButtonStatus == ButtonStatus.Pressed || ButtonStatus == ButtonStatus.Held;
public bool IsReleased => ButtonStatus == ButtonStatus.Released; public bool IsReleased => ButtonStatus == ButtonStatus.Released;
public ButtonState(ButtonStatus buttonStatus) internal ButtonState(ButtonStatus buttonStatus)
{ {
ButtonStatus = buttonStatus; ButtonStatus = buttonStatus;
} }

View File

@ -10,39 +10,57 @@ namespace MoonWorks.Input
internal IntPtr Handle; internal IntPtr Handle;
internal int Index; internal int Index;
public Button A { get; } = new Button(); public GamepadButton A { get; }
public Button B { get; } = new Button(); public GamepadButton B { get; }
public Button X { get; } = new Button(); public GamepadButton X { get; }
public Button Y { get; } = new Button(); public GamepadButton Y { get; }
public Button Back { get; } = new Button(); public GamepadButton Back { get; }
public Button Guide { get; } = new Button(); public GamepadButton Guide { get; }
public Button Start { get; } = new Button(); public GamepadButton Start { get; }
public Button LeftStick { get; } = new Button(); public GamepadButton LeftStick { get; }
public Button RightStick { get; } = new Button(); public GamepadButton RightStick { get; }
public Button LeftShoulder { get; } = new Button(); public GamepadButton LeftShoulder { get; }
public Button RightShoulder { get; } = new Button(); public GamepadButton RightShoulder { get; }
public Button DpadUp { get; } = new Button(); public GamepadButton DpadUp { get; }
public Button DpadDown { get; } = new Button(); public GamepadButton DpadDown { get; }
public Button DpadLeft { get; } = new Button(); public GamepadButton DpadLeft { get; }
public Button DpadRight { get; } = new Button(); public GamepadButton DpadRight { get; }
public Axis LeftX { get; } = new Axis(); public Axis LeftX { get; }
public Axis LeftY { get; } = new Axis(); public Axis LeftY { get; }
public Axis RightX { get; } = new Axis(); public Axis RightX { get; }
public Axis RightY { get; } = new Axis(); public Axis RightY { get; }
public Trigger TriggerLeft { get; } = new Trigger(); public AxisButton LeftXLeft { get; }
public Trigger TriggerRight { get; } = new Trigger(); public AxisButton LeftXRight { get; }
public AxisButton LeftYUp { get; }
public AxisButton LeftYDown { get; }
public AxisButton RightXLeft { get; }
public AxisButton RightXRight { get; }
public AxisButton RightYUp { get; }
public AxisButton RightYDown { get; }
public Trigger TriggerLeft { get; }
public Trigger TriggerRight { get; }
public TriggerButton TriggerLeftButton { get; }
public TriggerButton TriggerRightButton { get; }
public bool IsDummy => Handle == IntPtr.Zero; public bool IsDummy => Handle == IntPtr.Zero;
public bool AnyPressed { get; private set; } public bool AnyPressed { get; private set; }
public ButtonCode AnyPressedButtonCode { get; private set; } public VirtualButton AnyPressedButton { get; private set; }
private Dictionary<SDL.SDL_GameControllerButton, Button> EnumToButton; private Dictionary<SDL.SDL_GameControllerButton, GamepadButton> EnumToButton;
private Dictionary<SDL.SDL_GameControllerAxis, Axis> EnumToAxis; private Dictionary<SDL.SDL_GameControllerAxis, Axis> EnumToAxis;
private Dictionary<SDL.SDL_GameControllerAxis, Trigger> EnumToTrigger; private Dictionary<SDL.SDL_GameControllerAxis, Trigger> EnumToTrigger;
private Dictionary<AxisButtonCode, AxisButton> AxisButtonCodeToAxisButton;
private Dictionary<TriggerCode, TriggerButton> TriggerCodeToTriggerButton;
private VirtualButton[] VirtualButtons;
internal Gamepad(IntPtr handle, int index) internal Gamepad(IntPtr handle, int index)
{ {
Handle = handle; Handle = handle;
@ -50,7 +68,48 @@ namespace MoonWorks.Input
AnyPressed = false; AnyPressed = false;
EnumToButton = new Dictionary<SDL.SDL_GameControllerButton, Button> A = new GamepadButton(handle, GamepadButtonCode.A, SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_A);
B = new GamepadButton(handle, GamepadButtonCode.B, SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_B);
X = new GamepadButton(handle, GamepadButtonCode.X, SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_X);
Y = new GamepadButton(handle, GamepadButtonCode.Y, SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_Y);
Back = new GamepadButton(handle, GamepadButtonCode.Back, SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_BACK);
Guide = new GamepadButton(handle, GamepadButtonCode.Guide, SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_GUIDE);
Start = new GamepadButton(handle, GamepadButtonCode.Start, SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_START);
LeftStick = new GamepadButton(handle, GamepadButtonCode.LeftStick, SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_LEFTSTICK);
RightStick = new GamepadButton(handle, GamepadButtonCode.RightStick, SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_RIGHTSTICK);
LeftShoulder = new GamepadButton(handle, GamepadButtonCode.LeftShoulder, SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_LEFTSHOULDER);
RightShoulder = new GamepadButton(handle, GamepadButtonCode.RightShoulder, SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_RIGHTSHOULDER);
DpadUp = new GamepadButton(handle, GamepadButtonCode.DpadUp, SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_DPAD_UP);
DpadDown = new GamepadButton(handle, GamepadButtonCode.DpadDown, SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_DPAD_DOWN);
DpadLeft = new GamepadButton(handle, GamepadButtonCode.DpadLeft, SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_DPAD_LEFT);
DpadRight = new GamepadButton(handle, GamepadButtonCode.DpadRight, SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_DPAD_RIGHT);
LeftX = new Axis(handle, AxisCode.LeftX, SDL.SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_LEFTX);
LeftY = new Axis(handle, AxisCode.LeftY, SDL.SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_LEFTY);
RightX = new Axis(handle, AxisCode.RightX, SDL.SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_RIGHTX);
RightY = new Axis(handle, AxisCode.RightY, SDL.SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_RIGHTY);
LeftXLeft = new AxisButton(LeftX, false);
LeftXRight = new AxisButton(LeftX, true);
LeftYUp = new AxisButton(LeftY, false);
LeftYDown = new AxisButton(LeftY, true);
RightXLeft = new AxisButton(RightX, false);
RightXRight = new AxisButton(RightX, true);
RightYUp = new AxisButton(RightY, false);
RightYDown = new AxisButton(RightY, true);
TriggerLeft = new Trigger(handle, TriggerCode.Left, SDL.SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_TRIGGERLEFT);
TriggerRight = new Trigger(handle, TriggerCode.Right, SDL.SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_TRIGGERRIGHT);
TriggerLeftButton = new TriggerButton(TriggerLeft);
TriggerRightButton = new TriggerButton(TriggerRight);
EnumToButton = new Dictionary<SDL.SDL_GameControllerButton, GamepadButton>
{ {
{ SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_A, A }, { SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_A, A },
{ SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_B, B }, { SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_B, B },
@ -82,6 +141,47 @@ namespace MoonWorks.Input
{ SDL.SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_TRIGGERLEFT, TriggerLeft }, { SDL.SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_TRIGGERLEFT, TriggerLeft },
{ SDL.SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_TRIGGERRIGHT, TriggerRight } { SDL.SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_TRIGGERRIGHT, TriggerRight }
}; };
AxisButtonCodeToAxisButton = new Dictionary<AxisButtonCode, AxisButton>
{
{ AxisButtonCode.LeftX_Left, LeftXLeft },
{ AxisButtonCode.LeftX_Right, LeftXRight },
{ AxisButtonCode.LeftY_Down, LeftYDown },
{ AxisButtonCode.LeftY_Up, LeftYUp },
{ AxisButtonCode.RightX_Left, RightXLeft },
{ AxisButtonCode.RightX_Right, RightXRight },
{ AxisButtonCode.RightY_Up, RightYUp },
{ AxisButtonCode.RightY_Down, RightYDown }
};
VirtualButtons = new VirtualButton[]
{
A,
B,
X,
Y,
Back,
Guide,
Start,
LeftStick,
RightStick,
LeftShoulder,
RightShoulder,
DpadUp,
DpadDown,
DpadLeft,
DpadRight,
LeftXLeft,
LeftXRight,
LeftYUp,
LeftYDown,
RightXLeft,
RightXRight,
RightYUp,
RightYDown,
TriggerLeftButton,
TriggerRightButton
};
} }
internal void Update() internal void Update()
@ -90,31 +190,42 @@ namespace MoonWorks.Input
if (!IsDummy) if (!IsDummy)
{ {
foreach (var (sdlEnum, button) in EnumToButton) foreach (var button in EnumToButton.Values)
{ {
var pressed = CheckPressed(sdlEnum); button.Update();
button.Update(pressed); }
foreach (var axis in EnumToAxis.Values)
{
axis.Update();
}
foreach (var trigger in EnumToTrigger.Values)
{
trigger.Update();
}
LeftXLeft.Update();
LeftXRight.Update();
LeftYUp.Update();
LeftYDown.Update();
RightXLeft.Update();
RightXRight.Update();
RightYUp.Update();
RightYDown.Update();
TriggerLeftButton.Update();
TriggerRightButton.Update();
foreach (var button in VirtualButtons)
{
if (button.IsPressed) if (button.IsPressed)
{ {
AnyPressed = true; AnyPressed = true;
AnyPressedButtonCode = (ButtonCode) sdlEnum; AnyPressedButton = button;
break;
} }
} }
foreach (var (sdlEnum, axis) in EnumToAxis)
{
var sdlAxisValue = SDL.SDL_GameControllerGetAxis(Handle, sdlEnum);
var axisValue = MathHelper.Normalize(sdlAxisValue, short.MinValue, short.MaxValue, -1, 1);
axis.Update(axisValue);
}
foreach (var (sdlEnum, trigger) in EnumToTrigger)
{
var sdlAxisValue = SDL.SDL_GameControllerGetAxis(Handle, sdlEnum);
var axisValue = MathHelper.Normalize(sdlAxisValue, 0, short.MaxValue, 0, 1);
trigger.Update(axisValue);
}
} }
} }
@ -131,44 +242,19 @@ namespace MoonWorks.Input
) == 0; ) == 0;
} }
/// <summary> public GamepadButton Button(GamepadButtonCode buttonCode)
/// True if the button is pressed or held.
/// </summary>
public bool IsDown(ButtonCode buttonCode)
{ {
return EnumToButton[(SDL.SDL_GameControllerButton) buttonCode].IsDown; return EnumToButton[(SDL.SDL_GameControllerButton) buttonCode];
} }
/// <summary> public AxisButton Button(AxisButtonCode axisButtonCode)
/// True if the button was pressed this exact frame.
/// </summary>
public bool IsPressed(ButtonCode buttonCode)
{ {
return EnumToButton[(SDL.SDL_GameControllerButton) buttonCode].IsPressed; return AxisButtonCodeToAxisButton[axisButtonCode];
} }
/// <summary> public TriggerButton Button(TriggerCode triggerCode)
/// True if the button has been continuously held for more than one frame.
/// </summary>
public bool IsHeld(ButtonCode buttonCode)
{ {
return EnumToButton[(SDL.SDL_GameControllerButton) buttonCode].IsHeld; return TriggerCodeToTriggerButton[triggerCode];
}
/// <summary>
/// True if the button is not pressed.
/// </summary>
public bool IsReleased(ButtonCode buttonCode)
{
return EnumToButton[(SDL.SDL_GameControllerButton) buttonCode].IsReleased;
}
/// <summary>
/// Obtains the button state given a ButtonCode.
/// </summary>
public ButtonState ButtonState(ButtonCode buttonCode)
{
return EnumToButton[(SDL.SDL_GameControllerButton) buttonCode].State;
} }
/// <summary> /// <summary>

View File

@ -15,7 +15,7 @@ namespace MoonWorks.Input
public static event Action<char> TextInput; public static event Action<char> TextInput;
public bool AnyPressed { get; private set; } public bool AnyPressed { get; private set; }
public ButtonIdentifier AnyPressedButton { get; private set; } public VirtualButton AnyPressedButton { get; private set; }
internal Inputs() internal Inputs()
{ {
@ -49,7 +49,7 @@ namespace MoonWorks.Input
if (Keyboard.AnyPressed) if (Keyboard.AnyPressed)
{ {
AnyPressed = true; AnyPressed = true;
AnyPressedButton = new ButtonIdentifier(Keyboard.AnyPressedKeyCode); AnyPressedButton = Keyboard.AnyPressedButton;
} }
Mouse.Update(); Mouse.Update();
@ -57,7 +57,7 @@ namespace MoonWorks.Input
if (Mouse.AnyPressed) if (Mouse.AnyPressed)
{ {
AnyPressed = true; AnyPressed = true;
AnyPressedButton = new ButtonIdentifier(Mouse.AnyPressedButtonCode); AnyPressedButton = Mouse.AnyPressedButton;
} }
foreach (var gamepad in gamepads) foreach (var gamepad in gamepads)
@ -67,7 +67,7 @@ namespace MoonWorks.Input
if (gamepad.AnyPressed) if (gamepad.AnyPressed)
{ {
AnyPressed = true; AnyPressed = true;
AnyPressedButton = new ButtonIdentifier(gamepad, gamepad.AnyPressedButtonCode); AnyPressedButton = gamepad.AnyPressedButton;
} }
} }
} }
@ -82,31 +82,6 @@ namespace MoonWorks.Input
return gamepads[slot]; return gamepads[slot];
} }
public ButtonState ButtonState(ButtonIdentifier identifier)
{
if (identifier.DeviceKind == DeviceKind.Gamepad)
{
var gamepad = GetGamepad(identifier.Index);
return gamepad.ButtonState((ButtonCode) identifier.Code);
}
else if (identifier.DeviceKind == DeviceKind.Keyboard)
{
return Keyboard.ButtonState((KeyCode) identifier.Code);
}
else if (identifier.DeviceKind == DeviceKind.Mouse)
{
return Mouse.ButtonState((MouseButtonCode) identifier.Code);
}
else if (identifier.DeviceKind == DeviceKind.None)
{
return new ButtonState(ButtonStatus.Released);
}
else
{
throw new System.ArgumentException("Invalid button identifier!");
}
}
internal static void OnTextInput(char c) internal static void OnTextInput(char c)
{ {
if (TextInput != null) if (TextInput != null)

View File

@ -8,9 +8,11 @@ namespace MoonWorks.Input
public class Keyboard public class Keyboard
{ {
public bool AnyPressed { get; private set; } public bool AnyPressed { get; private set; }
public KeyCode AnyPressedKeyCode { get; private set; } public KeyboardButton AnyPressedButton { get; private set; }
private Button[] Keys { get; } public IntPtr State { get; private set; }
private KeyboardButton[] Keys { get; }
private int numKeys; private int numKeys;
private static readonly char[] TextInputCharacters = new char[] private static readonly char[] TextInputCharacters = new char[]
@ -39,10 +41,10 @@ namespace MoonWorks.Input
{ {
SDL.SDL_GetKeyboardState(out numKeys); SDL.SDL_GetKeyboardState(out numKeys);
Keys = new Button[numKeys]; Keys = new KeyboardButton[numKeys];
foreach (KeyCode keycode in Enum.GetValues(typeof(KeyCode))) foreach (KeyCode keycode in Enum.GetValues(typeof(KeyCode)))
{ {
Keys[(int) keycode] = new Button(); Keys[(int) keycode] = new KeyboardButton(this, keycode);
} }
} }
@ -50,14 +52,14 @@ namespace MoonWorks.Input
{ {
AnyPressed = false; AnyPressed = false;
IntPtr keyboardState = SDL.SDL_GetKeyboardState(out _); State = SDL.SDL_GetKeyboardState(out _);
foreach (int keycode in Enum.GetValues(typeof(KeyCode))) foreach (int keycode in Enum.GetValues(typeof(KeyCode)))
{ {
var keyDown = Conversions.ByteToBool(Marshal.ReadByte(keyboardState, keycode)); var button = Keys[keycode];
Keys[keycode].Update(keyDown); button.Update();
if (keyDown) if (button.IsPressed)
{ {
if (TextInputBindings.TryGetValue((KeyCode) keycode, out var textIndex)) if (TextInputBindings.TryGetValue((KeyCode) keycode, out var textIndex))
{ {
@ -67,12 +69,9 @@ namespace MoonWorks.Input
{ {
Inputs.OnTextInput(TextInputCharacters[6]); Inputs.OnTextInput(TextInputCharacters[6]);
} }
}
if (Keys[keycode].IsPressed)
{
AnyPressed = true; AnyPressed = true;
AnyPressedKeyCode = (KeyCode) keycode; AnyPressedButton = button;
} }
} }
} }
@ -97,7 +96,7 @@ namespace MoonWorks.Input
return Keys[(int) keycode].IsReleased; return Keys[(int) keycode].IsReleased;
} }
public Button Button(KeyCode keycode) public KeyboardButton Button(KeyCode keycode)
{ {
return Keys[(int) keycode]; return Keys[(int) keycode];
} }

View File

@ -5,9 +5,9 @@ namespace MoonWorks.Input
{ {
public class Mouse public class Mouse
{ {
public Button LeftButton { get; } = new Button(); public MouseButton LeftButton { get; }
public Button MiddleButton { get; } = new Button(); public MouseButton MiddleButton { get; }
public Button RightButton { get; } = new Button(); public MouseButton RightButton { get; }
public int X { get; private set; } public int X { get; private set; }
public int Y { get; private set; } public int Y { get; private set; }
@ -17,7 +17,9 @@ namespace MoonWorks.Input
public int Wheel { get; internal set; } public int Wheel { get; internal set; }
public bool AnyPressed { get; private set; } public bool AnyPressed { get; private set; }
public MouseButtonCode AnyPressedButtonCode { get; private set; } public MouseButton AnyPressedButton { get; private set; }
public uint ButtonMask { get; private set; }
private bool relativeMode; private bool relativeMode;
public bool RelativeMode public bool RelativeMode
@ -34,31 +36,37 @@ namespace MoonWorks.Input
} }
} }
private readonly Dictionary<MouseButtonCode, Button> CodeToButton; private readonly Dictionary<MouseButtonCode, MouseButton> CodeToButton;
private readonly Dictionary<uint, MouseButtonCode> MaskToButtonCode;
private IEnumerable<MouseButton> Buttons
{
get
{
yield return LeftButton;
yield return MiddleButton;
yield return RightButton;
}
}
public Mouse() public Mouse()
{ {
CodeToButton = new Dictionary<MouseButtonCode, Button> LeftButton = new MouseButton(this, MouseButtonCode.Left, SDL.SDL_BUTTON_LMASK);
MiddleButton = new MouseButton(this, MouseButtonCode.Middle, SDL.SDL_BUTTON_MMASK);
RightButton = new MouseButton(this, MouseButtonCode.Right, SDL.SDL_BUTTON_RMASK);
CodeToButton = new Dictionary<MouseButtonCode, MouseButton>
{ {
{ MouseButtonCode.Left, LeftButton }, { MouseButtonCode.Left, LeftButton },
{ MouseButtonCode.Right, RightButton }, { MouseButtonCode.Right, RightButton },
{ MouseButtonCode.Middle, MiddleButton } { MouseButtonCode.Middle, MiddleButton }
}; };
MaskToButtonCode = new Dictionary<uint, MouseButtonCode>
{
{ SDL.SDL_BUTTON_LMASK, MouseButtonCode.Left },
{ SDL.SDL_BUTTON_MMASK, MouseButtonCode.Middle },
{ SDL.SDL_BUTTON_RMASK, MouseButtonCode.Right }
};
} }
internal void Update() internal void Update()
{ {
AnyPressed = false; AnyPressed = false;
var buttonMask = SDL.SDL_GetMouseState(out var x, out var y); ButtonMask = SDL.SDL_GetMouseState(out var x, out var y);
var _ = SDL.SDL_GetRelativeMouseState(out var deltaX, out var deltaY); var _ = SDL.SDL_GetRelativeMouseState(out var deltaX, out var deltaY);
X = x; X = x;
@ -66,16 +74,18 @@ namespace MoonWorks.Input
DeltaX = deltaX; DeltaX = deltaX;
DeltaY = deltaY; DeltaY = deltaY;
foreach (var (mask, buttonCode) in MaskToButtonCode) LeftButton.Update();
MiddleButton.Update();
RightButton.Update();
foreach (var button in Buttons)
{ {
var pressed = IsPressed(buttonMask, mask); button.Update();
var button = CodeToButton[buttonCode];
button.Update(pressed);
if (button.IsPressed) if (button.IsPressed)
{ {
AnyPressed = true; AnyPressed = true;
AnyPressedButtonCode = buttonCode; AnyPressedButton = button;
} }
} }
} }
@ -84,10 +94,5 @@ namespace MoonWorks.Input
{ {
return CodeToButton[buttonCode].State; return CodeToButton[buttonCode].State;
} }
private bool IsPressed(uint buttonMask, uint buttonFlag)
{
return (buttonMask & buttonFlag) != 0;
}
} }
} }

View File

@ -1,15 +1,38 @@
using System;
using MoonWorks.Math;
using SDL2;
namespace MoonWorks.Input namespace MoonWorks.Input
{ {
public class Trigger public class Trigger
{ {
public IntPtr GamepadHandle;
public SDL.SDL_GameControllerAxis SDL_Axis;
public TriggerCode Code { get; }
/// <summary> /// <summary>
/// A trigger value between 0 and 1. /// A trigger value between 0 and 1.
/// </summary> /// </summary>
public float Value { get; private set; } public float Value { get; private set; }
internal void Update(float value) public Trigger(
IntPtr gamepadHandle,
TriggerCode code,
SDL.SDL_GameControllerAxis sdlAxis
) {
GamepadHandle = gamepadHandle;
Code = code;
SDL_Axis = sdlAxis;
}
internal void Update()
{ {
Value = value; Value = MathHelper.Normalize(
SDL.SDL_GameControllerGetAxis(GamepadHandle, SDL_Axis),
0, short.MaxValue,
0, 1
);
} }
} }
} }

View File

@ -1,8 +1,8 @@
namespace MoonWorks.Input namespace MoonWorks.Input
{ {
public class Button public abstract class VirtualButton
{ {
public ButtonState State { get; private set; } public ButtonState State { get; protected set; }
/// <summary> /// <summary>
/// True if the button is pressed or held. /// True if the button is pressed or held.
@ -24,9 +24,11 @@ namespace MoonWorks.Input
/// </summary> /// </summary>
public bool IsReleased => State.IsReleased; public bool IsReleased => State.IsReleased;
internal void Update(bool isPressed) internal virtual void Update()
{ {
State = State.Update(isPressed); State = State.Update(CheckPressed());
} }
internal abstract bool CheckPressed();
} }
} }

View File

@ -0,0 +1,73 @@
namespace MoonWorks.Input
{
public class AxisButton : VirtualButton
{
public Axis Parent { get; }
public AxisButtonCode Code { get; }
private float threshold = 0.9f;
public float Threshold
{
get => threshold;
set => threshold = System.Math.Clamp(value, 0, 1);
}
private int Sign;
internal AxisButton(Axis parent, bool positive)
{
Parent = parent;
Sign = positive ? 1 : -1;
if (parent.Code == AxisCode.LeftX)
{
if (positive)
{
Code = AxisButtonCode.LeftX_Right;
}
else
{
Code = AxisButtonCode.LeftX_Left;
}
}
else if (parent.Code == AxisCode.LeftY)
{
if (positive)
{
Code = AxisButtonCode.LeftY_Up;
}
else
{
Code = AxisButtonCode.LeftY_Down;
}
}
else if (parent.Code == AxisCode.RightX)
{
if (positive)
{
Code = AxisButtonCode.RightX_Right;
}
else
{
Code = AxisButtonCode.RightX_Left;
}
}
else if (parent.Code == AxisCode.RightY)
{
if (positive)
{
Code = AxisButtonCode.RightY_Up;
}
else
{
Code = AxisButtonCode.RightY_Down;
}
}
}
internal override bool CheckPressed()
{
return Sign * Parent.Value >= threshold;
}
}
}

View File

@ -0,0 +1,25 @@
using System;
using SDL2;
namespace MoonWorks.Input
{
public class GamepadButton : VirtualButton
{
IntPtr GamepadHandle;
SDL.SDL_GameControllerButton SDL_Button;
public GamepadButtonCode Code { get; private set; }
internal GamepadButton(IntPtr gamepadHandle, GamepadButtonCode code, SDL.SDL_GameControllerButton sdlButton)
{
GamepadHandle = gamepadHandle;
Code = code;
SDL_Button = sdlButton;
}
internal override bool CheckPressed()
{
return MoonWorks.Conversions.ByteToBool(SDL.SDL_GameControllerGetButton(GamepadHandle, SDL_Button));
}
}
}

View File

@ -0,0 +1,21 @@
using System.Runtime.InteropServices;
namespace MoonWorks.Input
{
public class KeyboardButton : VirtualButton
{
Keyboard Parent;
KeyCode KeyCode;
internal KeyboardButton(Keyboard parent, KeyCode keyCode)
{
Parent = parent;
KeyCode = keyCode;
}
internal override bool CheckPressed()
{
return Conversions.ByteToBool(Marshal.ReadByte(Parent.State, (int) KeyCode));
}
}
}

View File

@ -0,0 +1,22 @@
namespace MoonWorks.Input
{
public class MouseButton : VirtualButton
{
Mouse Parent;
uint ButtonMask;
public MouseButtonCode Code { get; private set; }
internal MouseButton(Mouse parent, MouseButtonCode code, uint buttonMask)
{
Parent = parent;
Code = code;
ButtonMask = buttonMask;
}
internal override bool CheckPressed()
{
return (Parent.ButtonMask & ButtonMask) != 0;
}
}
}

View File

@ -0,0 +1,25 @@
namespace MoonWorks.Input
{
public class TriggerButton : VirtualButton
{
public Trigger Parent { get; }
public TriggerCode Code => Parent.Code;
private float threshold = 0.7f;
public float Threshold
{
get => threshold;
set => threshold = System.Math.Clamp(value, 0, 1);
}
internal TriggerButton(Trigger parent)
{
Parent = parent;
}
internal override bool CheckPressed()
{
return Parent.Value >= Threshold;
}
}
}