Input API rework

main
cosmonaut 2022-03-18 11:46:44 -07:00
parent 3623e6b07c
commit 5050a9369d
10 changed files with 216 additions and 76 deletions

12
src/Input/Axis.cs Normal file
View File

@ -0,0 +1,12 @@
namespace MoonWorks.Input
{
public class Axis
{
public float Value { get; private set; }
internal void Update(float value)
{
Value = value;
}
}
}

11
src/Input/AxisCode.cs Normal file
View File

@ -0,0 +1,11 @@
namespace MoonWorks.Input
{
// Enum values are equivalent to SDL GameControllerAxis
public enum AxisCode
{
LeftX,
LeftY,
RightX,
RightY
}
}

17
src/Input/Button.cs Normal file
View File

@ -0,0 +1,17 @@
namespace MoonWorks.Input
{
public class Button
{
public ButtonState State { get; private set; }
public bool IsDown => State.IsDown;
public bool IsHeld => State.IsHeld;
public bool IsPressed => State.IsPressed;
public bool IsReleased => State.IsReleased;
internal void Update(bool isPressed)
{
State = State.Update(isPressed);
}
}
}

22
src/Input/ButtonCode.cs Normal file
View File

@ -0,0 +1,22 @@
namespace MoonWorks.Input
{
// Enum values are equivalent to the SDL GameControllerButton value.
public enum ButtonCode
{
A,
B,
X,
Y,
Back,
Guide,
Start,
LeftStick,
RightStick,
LeftShoulder,
RightShoulder,
DpadUp,
DpadDown,
DpadLeft,
DpadRight
}
}

View File

@ -2,7 +2,7 @@
{
public struct ButtonState
{
private ButtonStatus ButtonStatus { get; set; }
public ButtonStatus ButtonStatus { get; }
public bool IsPressed => ButtonStatus == ButtonStatus.Pressed;
public bool IsHeld => ButtonStatus == ButtonStatus.Held;

View File

@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using MoonWorks.Math;
using SDL2;
@ -8,32 +9,92 @@ namespace MoonWorks.Input
{
internal IntPtr Handle;
public ButtonState A { get; private set; } = new ButtonState();
public ButtonState B { get; private set; } = new ButtonState();
public ButtonState X { get; private set; } = new ButtonState();
public ButtonState Y { get; private set; } = new ButtonState();
public ButtonState Back { get; private set; } = new ButtonState();
public ButtonState Guide { get; private set; } = new ButtonState();
public ButtonState Start { get; private set; } = new ButtonState();
public ButtonState LeftStick { get; private set; } = new ButtonState();
public ButtonState RightStick { get; private set; } = new ButtonState();
public ButtonState LeftShoulder { get; private set; } = new ButtonState();
public ButtonState RightShoulder { get; private set; } = new ButtonState();
public ButtonState DpadUp { get; private set; } = new ButtonState();
public ButtonState DpadDown { get; private set; } = new ButtonState();
public ButtonState DpadLeft { get; private set; } = new ButtonState();
public ButtonState DpadRight { get; private set; } = new ButtonState();
public Button A { get; private set; } = new Button();
public Button B { get; private set; } = new Button();
public Button X { get; private set; } = new Button();
public Button Y { get; private set; } = new Button();
public Button Back { get; private set; } = new Button();
public Button Guide { get; private set; } = new Button();
public Button Start { get; private set; } = new Button();
public Button LeftStick { get; private set; } = new Button();
public Button RightStick { get; private set; } = new Button();
public Button LeftShoulder { get; private set; } = new Button();
public Button RightShoulder { get; private set; } = new Button();
public Button DpadUp { get; private set; } = new Button();
public Button DpadDown { get; private set; } = new Button();
public Button DpadLeft { get; private set; } = new Button();
public Button DpadRight { get; private set; } = new Button();
public float LeftX { get; private set; }
public float LeftY { get; private set; }
public float RightX { get; private set; }
public float RightY { get; private set; }
public float TriggerLeft { get; private set; }
public float TriggerRight { get; private set; }
public Axis LeftX { get; private set; }
public Axis LeftY { get; private set; }
public Axis RightX { get; private set; }
public Axis RightY { get; private set; }
public Trigger TriggerLeft { get; private set; }
public Trigger TriggerRight { get; private set; }
private Dictionary<SDL.SDL_GameControllerButton, Button> EnumToButton;
private Dictionary<SDL.SDL_GameControllerAxis, Axis> EnumToAxis;
private Dictionary<SDL.SDL_GameControllerAxis, Trigger> EnumToTrigger;
internal Gamepad(IntPtr handle)
{
Handle = handle;
EnumToButton = new Dictionary<SDL.SDL_GameControllerButton, Button>
{
{ SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_A, A },
{ SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_B, B },
{ SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_X, X },
{ SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_Y, Y },
{ SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_BACK, Back },
{ SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_GUIDE, Guide },
{ SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_START, Start },
{ SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_LEFTSTICK, LeftStick },
{ SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_RIGHTSTICK, RightStick },
{ SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_LEFTSHOULDER, LeftShoulder },
{ SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, RightShoulder },
{ SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_DPAD_UP, DpadUp },
{ SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_DPAD_DOWN, DpadDown },
{ SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_DPAD_LEFT, DpadLeft },
{ SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_DPAD_RIGHT, DpadRight }
};
EnumToAxis = new Dictionary<SDL.SDL_GameControllerAxis, Axis>
{
{ SDL.SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_LEFTX, LeftX },
{ SDL.SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_LEFTY, LeftY },
{ SDL.SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_RIGHTX, RightX },
{ SDL.SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_RIGHTY, RightY }
};
EnumToTrigger = new Dictionary<SDL.SDL_GameControllerAxis, Trigger>
{
{ SDL.SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_TRIGGERLEFT, TriggerLeft },
{ SDL.SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_TRIGGERRIGHT, TriggerRight }
};
}
internal void Update()
{
foreach (var (sdlEnum, button) in EnumToButton)
{
button.Update(CheckPressed(sdlEnum));
}
foreach (var (sdlEnum, axis) in EnumToAxis)
{
var sdlAxisValue = SDL.SDL_GameControllerGetAxis(Handle, sdlEnum);
var axisValue = 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 = Normalize(sdlAxisValue, 0, short.MaxValue, 0, 1);
trigger.Update(axisValue);
}
}
public bool SetVibration(float leftMotor, float rightMotor, uint durationInMilliseconds)
@ -46,50 +107,46 @@ namespace MoonWorks.Input
) == 0;
}
internal void Update()
public bool IsDown(ButtonCode buttonCode)
{
A = A.Update(IsPressed(SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_A));
B = B.Update(IsPressed(SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_B));
X = X.Update(IsPressed(SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_X));
Y = Y.Update(IsPressed(SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_Y));
Back = Back.Update(IsPressed(SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_BACK));
Guide = Guide.Update(IsPressed(SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_GUIDE));
Start = Start.Update(IsPressed(SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_START));
LeftStick = LeftStick.Update(IsPressed(SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_LEFTSTICK));
RightStick = RightStick.Update(IsPressed(SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_RIGHTSTICK));
LeftShoulder = LeftShoulder.Update(IsPressed(SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_LEFTSHOULDER));
RightShoulder = RightShoulder.Update(IsPressed(SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_RIGHTSHOULDER));
DpadUp = DpadUp.Update(IsPressed(SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_DPAD_UP));
DpadDown = DpadDown.Update(IsPressed(SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_DPAD_DOWN));
DpadLeft = DpadLeft.Update(IsPressed(SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_DPAD_LEFT));
DpadRight = DpadRight.Update(IsPressed(SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_DPAD_RIGHT));
LeftX = UpdateAxis(SDL.SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_LEFTX);
LeftY = UpdateAxis(SDL.SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_LEFTY);
RightX = UpdateAxis(SDL.SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_RIGHTX);
RightY = UpdateAxis(SDL.SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_RIGHTY);
TriggerLeft = UpdateTrigger(SDL.SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_TRIGGERLEFT);
TriggerRight = UpdateTrigger(SDL.SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_TRIGGERRIGHT);
return EnumToButton[(SDL.SDL_GameControllerButton) buttonCode].IsDown;
}
private bool IsPressed(SDL.SDL_GameControllerButton button)
public bool IsPressed(ButtonCode buttonCode)
{
return EnumToButton[(SDL.SDL_GameControllerButton) buttonCode].IsPressed;
}
public bool IsHeld(ButtonCode buttonCode)
{
return EnumToButton[(SDL.SDL_GameControllerButton) buttonCode].IsHeld;
}
public bool IsReleased(ButtonCode buttonCode)
{
return EnumToButton[(SDL.SDL_GameControllerButton) buttonCode].IsReleased;
}
public ButtonState ButtonState(ButtonCode buttonCode)
{
return EnumToButton[(SDL.SDL_GameControllerButton) buttonCode].State;
}
public float AxisValue(AxisCode axisCode)
{
return EnumToAxis[(SDL.SDL_GameControllerAxis) axisCode].Value;
}
public float TriggerValue(TriggerCode triggerCode)
{
return EnumToTrigger[(SDL.SDL_GameControllerAxis) triggerCode].Value;
}
private bool CheckPressed(SDL.SDL_GameControllerButton button)
{
return MoonWorks.Conversions.ByteToBool(SDL.SDL_GameControllerGetButton(Handle, button));
}
private float UpdateAxis(SDL.SDL_GameControllerAxis axis)
{
var axisValue = SDL.SDL_GameControllerGetAxis(Handle, axis);
return Normalize(axisValue, short.MinValue, short.MaxValue, -1, 1);
}
// Triggers only go from 0 to short.MaxValue
private float UpdateTrigger(SDL.SDL_GameControllerAxis trigger)
{
var triggerValue = SDL.SDL_GameControllerGetAxis(Handle, trigger);
return Normalize(triggerValue, 0, short.MaxValue, 0, 1);
}
private float Normalize(float value, short min, short max, short newMin, short newMax)
{
return ((value - min) * (newMax - newMin)) / (max - min) + newMin;

View File

@ -1,7 +1,7 @@
namespace MoonWorks.Input
{
// Enum values are equivalent to the SDL Scancode value.
public enum Keycode : int
public enum KeyCode : int
{
Unknown = 0,
A = 4,

View File

@ -21,14 +21,14 @@ namespace MoonWorks.Input
(char) 22 // Ctrl+V (Paste)
};
private static readonly Dictionary<Keycode, int> TextInputBindings = new Dictionary<Keycode, int>()
private static readonly Dictionary<KeyCode, int> TextInputBindings = new Dictionary<KeyCode, int>()
{
{ Keycode.Home, 0 },
{ Keycode.End, 1 },
{ Keycode.Backspace, 2 },
{ Keycode.Tab, 3 },
{ Keycode.Return, 4 },
{ Keycode.Delete, 5 }
{ KeyCode.Home, 0 },
{ KeyCode.End, 1 },
{ KeyCode.Backspace, 2 },
{ KeyCode.Tab, 3 },
{ KeyCode.Return, 4 },
{ KeyCode.Delete, 5 }
// Ctrl+V is special!
};
@ -37,7 +37,7 @@ namespace MoonWorks.Input
SDL.SDL_GetKeyboardState(out numKeys);
Keys = new ButtonState[numKeys];
foreach (Keycode keycode in Enum.GetValues(typeof(Keycode)))
foreach (KeyCode keycode in Enum.GetValues(typeof(KeyCode)))
{
Keys[(int) keycode] = new ButtonState();
}
@ -47,18 +47,18 @@ namespace MoonWorks.Input
{
IntPtr keyboardState = SDL.SDL_GetKeyboardState(out _);
foreach (int keycode in Enum.GetValues(typeof(Keycode)))
foreach (int keycode in Enum.GetValues(typeof(KeyCode)))
{
var keyDown = Marshal.ReadByte(keyboardState, keycode);
Keys[keycode] = Keys[keycode].Update(Conversions.ByteToBool(keyDown));
if (Conversions.ByteToBool(keyDown))
{
if (TextInputBindings.TryGetValue((Keycode) keycode, out var textIndex))
if (TextInputBindings.TryGetValue((KeyCode) keycode, out var textIndex))
{
Inputs.OnTextInput(TextInputCharacters[(textIndex)]);
}
else if (IsDown(Keycode.LeftControl) && (Keycode) keycode == Keycode.V)
else if (IsDown(KeyCode.LeftControl) && (KeyCode) keycode == KeyCode.V)
{
Inputs.OnTextInput(TextInputCharacters[6]);
}
@ -66,27 +66,27 @@ namespace MoonWorks.Input
}
}
public bool IsDown(Keycode keycode)
public bool IsDown(KeyCode keycode)
{
return Keys[(int) keycode].IsDown;
}
public bool IsPressed(Keycode keycode)
public bool IsPressed(KeyCode keycode)
{
return Keys[(int) keycode].IsPressed;
}
public bool IsHeld(Keycode keycode)
public bool IsHeld(KeyCode keycode)
{
return Keys[(int) keycode].IsHeld;
}
public bool IsReleased(Keycode keycode)
public bool IsReleased(KeyCode keycode)
{
return Keys[(int) keycode].IsReleased;
}
public ButtonState ButtonState(Keycode keycode)
public ButtonState ButtonState(KeyCode keycode)
{
return Keys[(int) keycode];
}

12
src/Input/Trigger.cs Normal file
View File

@ -0,0 +1,12 @@
namespace MoonWorks.Input
{
public class Trigger
{
public float Value { get; private set; }
internal void Update(float value)
{
Value = value;
}
}
}

9
src/Input/TriggerCode.cs Normal file
View File

@ -0,0 +1,9 @@
namespace MoonWorks.Input
{
// Enum values correspond to SDL GameControllerAxis
public enum TriggerCode
{
Left = 4,
Right = 5
}
}