using System; using System.Collections.Generic; using MoonWorks.Math; using SDL2; namespace MoonWorks.Input { public class Gamepad { internal IntPtr Handle; internal int Index; public Button A { get; } = new Button(); public Button B { get; } = new Button(); public Button X { get; } = new Button(); public Button Y { get; } = new Button(); public Button Back { get; } = new Button(); public Button Guide { get; } = new Button(); public Button Start { get; } = new Button(); public Button LeftStick { get; } = new Button(); public Button RightStick { get; } = new Button(); public Button LeftShoulder { get; } = new Button(); public Button RightShoulder { get; } = new Button(); public Button DpadUp { get; } = new Button(); public Button DpadDown { get; } = new Button(); public Button DpadLeft { get; } = new Button(); public Button DpadRight { get; } = new Button(); public Axis LeftX { get; } = new Axis(); public Axis LeftY { get; } = new Axis(); public Axis RightX { get; } = new Axis(); public Axis RightY { get; } = new Axis(); public Trigger TriggerLeft { get; } = new Trigger(); public Trigger TriggerRight { get; } = new Trigger(); public bool IsDummy => Handle == IntPtr.Zero; private Dictionary EnumToButton; private Dictionary EnumToAxis; private Dictionary EnumToTrigger; internal Gamepad(IntPtr handle, int index) { Handle = handle; Index = index; 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() { if (!IsDummy) { 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 = 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); } } } /// /// Sets vibration values on the left and right motors. /// public bool SetVibration(float leftMotor, float rightMotor, uint durationInMilliseconds) { return SDL.SDL_GameControllerRumble( Handle, (ushort) (MathHelper.Clamp(leftMotor, 0f, 1f) * 0xFFFF), (ushort) (MathHelper.Clamp(rightMotor, 0f, 1f) * 0xFFFF), durationInMilliseconds ) == 0; } /// /// True if the button is pressed or held. /// public bool IsDown(ButtonCode buttonCode) { return EnumToButton[(SDL.SDL_GameControllerButton) buttonCode].IsDown; } /// /// True if the button was pressed this exact frame. /// public bool IsPressed(ButtonCode buttonCode) { return EnumToButton[(SDL.SDL_GameControllerButton) buttonCode].IsPressed; } /// /// True if the button has been continuously held for more than one frame. /// public bool IsHeld(ButtonCode buttonCode) { return EnumToButton[(SDL.SDL_GameControllerButton) buttonCode].IsHeld; } /// /// True if the button is not pressed. /// public bool IsReleased(ButtonCode buttonCode) { return EnumToButton[(SDL.SDL_GameControllerButton) buttonCode].IsReleased; } /// /// Obtains the button state given a ButtonCode. /// public ButtonState ButtonState(ButtonCode buttonCode) { return EnumToButton[(SDL.SDL_GameControllerButton) buttonCode].State; } /// /// Obtains the axis value given an AxisCode. /// /// A value between -1 and 1. public float AxisValue(AxisCode axisCode) { return EnumToAxis[(SDL.SDL_GameControllerAxis) axisCode].Value; } /// /// Obtains the trigger value given an TriggerCode. /// /// A value between 0 and 1. 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)); } } }