using OpenTK; using OpenTK.Input; using Ryujinx.HLE.Input; using System; namespace Ryujinx.UI.Input { public enum ControllerInputId { Invalid, LStick, DPadUp, DPadDown, DPadLeft, DPadRight, Back, LShoulder, RStick, A, B, X, Y, Start, RShoulder, LTrigger, RTrigger, LJoystick, RJoystick } public struct NpadControllerLeft { public ControllerInputId Stick; public ControllerInputId StickButton; public ControllerInputId DPadUp; public ControllerInputId DPadDown; public ControllerInputId DPadLeft; public ControllerInputId DPadRight; public ControllerInputId ButtonMinus; public ControllerInputId ButtonL; public ControllerInputId ButtonZl; } public struct NpadControllerRight { public ControllerInputId Stick; public ControllerInputId StickButton; public ControllerInputId ButtonA; public ControllerInputId ButtonB; public ControllerInputId ButtonX; public ControllerInputId ButtonY; public ControllerInputId ButtonPlus; public ControllerInputId ButtonR; public ControllerInputId ButtonZr; } public class NpadController { public bool Enabled { private set; get; } public int Index { private set; get; } public float Deadzone { private set; get; } public float TriggerThreshold { private set; get; } public NpadControllerLeft Left { private set; get; } public NpadControllerRight Right { private set; get; } public NpadController( bool enabled, int index, float deadzone, float triggerThreshold, NpadControllerLeft left, NpadControllerRight right) { Enabled = enabled; Index = index; Deadzone = deadzone; TriggerThreshold = triggerThreshold; Left = left; Right = right; //Unmapped controllers are problematic, skip them if (GamePad.GetName(index) == "Unmapped Controller") { Enabled = false; } } public HidControllerButtons GetButtons() { if (!Enabled) { return 0; } GamePadState gpState = GamePad.GetState(Index); HidControllerButtons buttons = 0; if (IsPressed(gpState, Left.DPadUp)) buttons |= HidControllerButtons.DpadUp; if (IsPressed(gpState, Left.DPadDown)) buttons |= HidControllerButtons.DpadDown; if (IsPressed(gpState, Left.DPadLeft)) buttons |= HidControllerButtons.DpadLeft; if (IsPressed(gpState, Left.DPadRight)) buttons |= HidControllerButtons.DPadRight; if (IsPressed(gpState, Left.StickButton)) buttons |= HidControllerButtons.StickLeft; if (IsPressed(gpState, Left.ButtonMinus)) buttons |= HidControllerButtons.Minus; if (IsPressed(gpState, Left.ButtonL)) buttons |= HidControllerButtons.L; if (IsPressed(gpState, Left.ButtonZl)) buttons |= HidControllerButtons.Zl; if (IsPressed(gpState, Right.ButtonA)) buttons |= HidControllerButtons.A; if (IsPressed(gpState, Right.ButtonB)) buttons |= HidControllerButtons.B; if (IsPressed(gpState, Right.ButtonX)) buttons |= HidControllerButtons.X; if (IsPressed(gpState, Right.ButtonY)) buttons |= HidControllerButtons.Y; if (IsPressed(gpState, Right.StickButton)) buttons |= HidControllerButtons.StickRight; if (IsPressed(gpState, Right.ButtonPlus)) buttons |= HidControllerButtons.Plus; if (IsPressed(gpState, Right.ButtonR)) buttons |= HidControllerButtons.R; if (IsPressed(gpState, Right.ButtonZr)) buttons |= HidControllerButtons.Zr; return buttons; } public (short, short) GetLeftStick() { if (!Enabled) { return (0, 0); } return GetStick(Left.Stick); } public (short, short) GetRightStick() { if (!Enabled) { return (0, 0); } return GetStick(Right.Stick); } private (short, short) GetStick(ControllerInputId joystick) { GamePadState gpState = GamePad.GetState(Index); switch (joystick) { case ControllerInputId.LJoystick: return ApplyDeadzone(gpState.ThumbSticks.Left); case ControllerInputId.RJoystick: return ApplyDeadzone(gpState.ThumbSticks.Right); default: return (0, 0); } } private (short, short) ApplyDeadzone(Vector2 axis) { return (ClampAxis(MathF.Abs(axis.X) > Deadzone ? axis.X : 0f), ClampAxis(MathF.Abs(axis.Y) > Deadzone ? axis.Y : 0f)); } private static short ClampAxis(float value) { if (value <= -short.MaxValue) { return -short.MaxValue; } else { return (short)(value * short.MaxValue); } } private bool IsPressed(GamePadState gpState, ControllerInputId button) { switch (button) { case ControllerInputId.A: return gpState.Buttons.A == ButtonState.Pressed; case ControllerInputId.B: return gpState.Buttons.B == ButtonState.Pressed; case ControllerInputId.X: return gpState.Buttons.X == ButtonState.Pressed; case ControllerInputId.Y: return gpState.Buttons.Y == ButtonState.Pressed; case ControllerInputId.LStick: return gpState.Buttons.LeftStick == ButtonState.Pressed; case ControllerInputId.RStick: return gpState.Buttons.RightStick == ButtonState.Pressed; case ControllerInputId.LShoulder: return gpState.Buttons.LeftShoulder == ButtonState.Pressed; case ControllerInputId.RShoulder: return gpState.Buttons.RightShoulder == ButtonState.Pressed; case ControllerInputId.DPadUp: return gpState.DPad.Up == ButtonState.Pressed; case ControllerInputId.DPadDown: return gpState.DPad.Down == ButtonState.Pressed; case ControllerInputId.DPadLeft: return gpState.DPad.Left == ButtonState.Pressed; case ControllerInputId.DPadRight: return gpState.DPad.Right == ButtonState.Pressed; case ControllerInputId.Start: return gpState.Buttons.Start == ButtonState.Pressed; case ControllerInputId.Back: return gpState.Buttons.Back == ButtonState.Pressed; case ControllerInputId.LTrigger: return gpState.Triggers.Left >= TriggerThreshold; case ControllerInputId.RTrigger: return gpState.Triggers.Right >= TriggerThreshold; //Using thumbsticks as buttons is not common, but it would be nice not to ignore them case ControllerInputId.LJoystick: return gpState.ThumbSticks.Left.X >= Deadzone || gpState.ThumbSticks.Left.Y >= Deadzone; case ControllerInputId.RJoystick: return gpState.ThumbSticks.Right.X >= Deadzone || gpState.ThumbSticks.Right.Y >= Deadzone; default: return false; } } } }