Input API rework

pull/17/head
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 public struct ButtonState
{ {
private ButtonStatus ButtonStatus { get; set; } public ButtonStatus ButtonStatus { get; }
public bool IsPressed => ButtonStatus == ButtonStatus.Pressed; public bool IsPressed => ButtonStatus == ButtonStatus.Pressed;
public bool IsHeld => ButtonStatus == ButtonStatus.Held; public bool IsHeld => ButtonStatus == ButtonStatus.Held;

View File

@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Generic;
using MoonWorks.Math; using MoonWorks.Math;
using SDL2; using SDL2;
@ -8,32 +9,92 @@ namespace MoonWorks.Input
{ {
internal IntPtr Handle; internal IntPtr Handle;
public ButtonState A { get; private set; } = new ButtonState(); public Button A { get; private set; } = new Button();
public ButtonState B { get; private set; } = new ButtonState(); public Button B { get; private set; } = new Button();
public ButtonState X { get; private set; } = new ButtonState(); public Button X { get; private set; } = new Button();
public ButtonState Y { get; private set; } = new ButtonState(); public Button Y { get; private set; } = new Button();
public ButtonState Back { get; private set; } = new ButtonState(); public Button Back { get; private set; } = new Button();
public ButtonState Guide { get; private set; } = new ButtonState(); public Button Guide { get; private set; } = new Button();
public ButtonState Start { get; private set; } = new ButtonState(); public Button Start { get; private set; } = new Button();
public ButtonState LeftStick { get; private set; } = new ButtonState(); public Button LeftStick { get; private set; } = new Button();
public ButtonState RightStick { get; private set; } = new ButtonState(); public Button RightStick { get; private set; } = new Button();
public ButtonState LeftShoulder { get; private set; } = new ButtonState(); public Button LeftShoulder { get; private set; } = new Button();
public ButtonState RightShoulder { get; private set; } = new ButtonState(); public Button RightShoulder { get; private set; } = new Button();
public ButtonState DpadUp { get; private set; } = new ButtonState(); public Button DpadUp { get; private set; } = new Button();
public ButtonState DpadDown { get; private set; } = new ButtonState(); public Button DpadDown { get; private set; } = new Button();
public ButtonState DpadLeft { get; private set; } = new ButtonState(); public Button DpadLeft { get; private set; } = new Button();
public ButtonState DpadRight { get; private set; } = new ButtonState(); public Button DpadRight { get; private set; } = new Button();
public float LeftX { get; private set; } public Axis LeftX { get; private set; }
public float LeftY { get; private set; } public Axis LeftY { get; private set; }
public float RightX { get; private set; } public Axis RightX { get; private set; }
public float RightY { get; private set; } public Axis RightY { get; private set; }
public float TriggerLeft { get; private set; }
public float TriggerRight { 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) internal Gamepad(IntPtr handle)
{ {
Handle = 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) public bool SetVibration(float leftMotor, float rightMotor, uint durationInMilliseconds)
@ -46,50 +107,46 @@ namespace MoonWorks.Input
) == 0; ) == 0;
} }
internal void Update() public bool IsDown(ButtonCode buttonCode)
{ {
A = A.Update(IsPressed(SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_A)); return EnumToButton[(SDL.SDL_GameControllerButton) buttonCode].IsDown;
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);
} }
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)); 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) private float Normalize(float value, short min, short max, short newMin, short newMax)
{ {
return ((value - min) * (newMax - newMin)) / (max - min) + newMin; return ((value - min) * (newMax - newMin)) / (max - min) + newMin;

View File

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

View File

@ -21,14 +21,14 @@ namespace MoonWorks.Input
(char) 22 // Ctrl+V (Paste) (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.Home, 0 },
{ Keycode.End, 1 }, { KeyCode.End, 1 },
{ Keycode.Backspace, 2 }, { KeyCode.Backspace, 2 },
{ Keycode.Tab, 3 }, { KeyCode.Tab, 3 },
{ Keycode.Return, 4 }, { KeyCode.Return, 4 },
{ Keycode.Delete, 5 } { KeyCode.Delete, 5 }
// Ctrl+V is special! // Ctrl+V is special!
}; };
@ -37,7 +37,7 @@ namespace MoonWorks.Input
SDL.SDL_GetKeyboardState(out numKeys); SDL.SDL_GetKeyboardState(out numKeys);
Keys = new ButtonState[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(); Keys[(int) keycode] = new ButtonState();
} }
@ -47,18 +47,18 @@ namespace MoonWorks.Input
{ {
IntPtr keyboardState = SDL.SDL_GetKeyboardState(out _); 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); var keyDown = Marshal.ReadByte(keyboardState, keycode);
Keys[keycode] = Keys[keycode].Update(Conversions.ByteToBool(keyDown)); Keys[keycode] = Keys[keycode].Update(Conversions.ByteToBool(keyDown));
if (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)]); 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]); 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; return Keys[(int) keycode].IsDown;
} }
public bool IsPressed(Keycode keycode) public bool IsPressed(KeyCode keycode)
{ {
return Keys[(int) keycode].IsPressed; return Keys[(int) keycode].IsPressed;
} }
public bool IsHeld(Keycode keycode) public bool IsHeld(KeyCode keycode)
{ {
return Keys[(int) keycode].IsHeld; return Keys[(int) keycode].IsHeld;
} }
public bool IsReleased(Keycode keycode) public bool IsReleased(KeyCode keycode)
{ {
return Keys[(int) keycode].IsReleased; return Keys[(int) keycode].IsReleased;
} }
public ButtonState ButtonState(Keycode keycode) public ButtonState ButtonState(KeyCode keycode)
{ {
return Keys[(int) 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
}
}