From 5050a9369d5477850cb9e2de7d1fd5c2abdf1176 Mon Sep 17 00:00:00 2001 From: cosmonaut Date: Fri, 18 Mar 2022 11:46:44 -0700 Subject: [PATCH] Input API rework --- src/Input/Axis.cs | 12 ++ src/Input/AxisCode.cs | 11 ++ src/Input/Button.cs | 17 +++ src/Input/ButtonCode.cs | 22 ++++ src/Input/ButtonState.cs | 2 +- src/Input/Gamepad.cs | 173 ++++++++++++++++++--------- src/Input/{Keycode.cs => KeyCode.cs} | 2 +- src/Input/Keyboard.cs | 32 ++--- src/Input/Trigger.cs | 12 ++ src/Input/TriggerCode.cs | 9 ++ 10 files changed, 216 insertions(+), 76 deletions(-) create mode 100644 src/Input/Axis.cs create mode 100644 src/Input/AxisCode.cs create mode 100644 src/Input/Button.cs create mode 100644 src/Input/ButtonCode.cs rename src/Input/{Keycode.cs => KeyCode.cs} (98%) create mode 100644 src/Input/Trigger.cs create mode 100644 src/Input/TriggerCode.cs diff --git a/src/Input/Axis.cs b/src/Input/Axis.cs new file mode 100644 index 00000000..4fed2b94 --- /dev/null +++ b/src/Input/Axis.cs @@ -0,0 +1,12 @@ +namespace MoonWorks.Input +{ + public class Axis + { + public float Value { get; private set; } + + internal void Update(float value) + { + Value = value; + } + } +} diff --git a/src/Input/AxisCode.cs b/src/Input/AxisCode.cs new file mode 100644 index 00000000..258ad690 --- /dev/null +++ b/src/Input/AxisCode.cs @@ -0,0 +1,11 @@ +namespace MoonWorks.Input +{ + // Enum values are equivalent to SDL GameControllerAxis + public enum AxisCode + { + LeftX, + LeftY, + RightX, + RightY + } +} diff --git a/src/Input/Button.cs b/src/Input/Button.cs new file mode 100644 index 00000000..615d8a3a --- /dev/null +++ b/src/Input/Button.cs @@ -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); + } + } +} diff --git a/src/Input/ButtonCode.cs b/src/Input/ButtonCode.cs new file mode 100644 index 00000000..c28b9aff --- /dev/null +++ b/src/Input/ButtonCode.cs @@ -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 + } +} diff --git a/src/Input/ButtonState.cs b/src/Input/ButtonState.cs index 17306bfb..270f6b9a 100644 --- a/src/Input/ButtonState.cs +++ b/src/Input/ButtonState.cs @@ -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; diff --git a/src/Input/Gamepad.cs b/src/Input/Gamepad.cs index 44fa317b..f0cb554d 100644 --- a/src/Input/Gamepad.cs +++ b/src/Input/Gamepad.cs @@ -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 EnumToButton; + private Dictionary EnumToAxis; + private Dictionary EnumToTrigger; internal Gamepad(IntPtr handle) { Handle = handle; + + EnumToButton = new Dictionary + { + { 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.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.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; diff --git a/src/Input/Keycode.cs b/src/Input/KeyCode.cs similarity index 98% rename from src/Input/Keycode.cs rename to src/Input/KeyCode.cs index 88dadd9a..d39a2abe 100644 --- a/src/Input/Keycode.cs +++ b/src/Input/KeyCode.cs @@ -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, diff --git a/src/Input/Keyboard.cs b/src/Input/Keyboard.cs index 2aa939fe..43ef24b3 100644 --- a/src/Input/Keyboard.cs +++ b/src/Input/Keyboard.cs @@ -21,14 +21,14 @@ namespace MoonWorks.Input (char) 22 // Ctrl+V (Paste) }; - private static readonly Dictionary TextInputBindings = new Dictionary() + private static readonly Dictionary TextInputBindings = new Dictionary() { - { 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]; } diff --git a/src/Input/Trigger.cs b/src/Input/Trigger.cs new file mode 100644 index 00000000..19a2b291 --- /dev/null +++ b/src/Input/Trigger.cs @@ -0,0 +1,12 @@ +namespace MoonWorks.Input +{ + public class Trigger + { + public float Value { get; private set; } + + internal void Update(float value) + { + Value = value; + } + } +} diff --git a/src/Input/TriggerCode.cs b/src/Input/TriggerCode.cs new file mode 100644 index 00000000..346ef0a9 --- /dev/null +++ b/src/Input/TriggerCode.cs @@ -0,0 +1,9 @@ +namespace MoonWorks.Input +{ + // Enum values correspond to SDL GameControllerAxis + public enum TriggerCode + { + Left = 4, + Right = 5 + } +}