diff --git a/src/Ryujinx.Input.SDL2/SDL2GamepadDriver.cs b/src/Ryujinx.Input.SDL2/SDL2GamepadDriver.cs index 3e3681145..2c73d1604 100644 --- a/src/Ryujinx.Input.SDL2/SDL2GamepadDriver.cs +++ b/src/Ryujinx.Input.SDL2/SDL2GamepadDriver.cs @@ -152,7 +152,8 @@ namespace Ryujinx.Input.SDL2 private void HandleJoyBatteryUpdated(int joystickDeviceId, SDL_JoystickPowerLevel powerLevel) { - Logger.Info?.Print(LogClass.Hid, $"{SDL_GameControllerNameForIndex(joystickDeviceId) } power level: {powerLevel}"); + Logger.Info?.Print(LogClass.Hid, + $"{SDL_GameControllerNameForIndex(joystickDeviceId)} power level: {powerLevel}"); } protected virtual void Dispose(bool disposing) @@ -201,8 +202,17 @@ namespace Ryujinx.Input.SDL2 } nint gamepadHandle = SDL_GameControllerOpen(joystickIndex); + if (gamepadHandle == nint.Zero) + { + return null; + } - return gamepadHandle == nint.Zero ? null : new SDL2Gamepad(gamepadHandle, id); + if (SDL_GameControllerName(gamepadHandle).StartsWith(SDL2JoyCon.Prefix)) + { + return new SDL2JoyCon(gamepadHandle, id); + } + + return new SDL2Gamepad(gamepadHandle, id); } } } diff --git a/src/Ryujinx.Input.SDL2/SDL2JoyCon.cs b/src/Ryujinx.Input.SDL2/SDL2JoyCon.cs new file mode 100644 index 000000000..f7e0ccbf9 --- /dev/null +++ b/src/Ryujinx.Input.SDL2/SDL2JoyCon.cs @@ -0,0 +1,134 @@ +using Ryujinx.Common.Configuration.Hid; +using System.Numerics; + +namespace Ryujinx.Input.SDL2 +{ + internal class SDL2JoyCon : IGamepad + { + readonly IGamepad _gamepad; + private enum JoyConType + { + Left , Right + } + + public const string Prefix = "Nintendo Switch Joy-Con"; + public const string LeftName = "Nintendo Switch Joy-Con (L)"; + public const string RightName = "Nintendo Switch Joy-Con (R)"; + + private readonly JoyConType _joyConType; + + public SDL2JoyCon(nint gamepadHandle, string driverId) + { + _gamepad = new SDL2Gamepad(gamepadHandle, driverId); + _joyConType = Name switch + { + LeftName => JoyConType.Left, + RightName => JoyConType.Right, + _ => JoyConType.Left + }; + } + + public Vector3 GetMotionData(MotionInputId inputId) + { + var motionData = _gamepad.GetMotionData(inputId); + return _joyConType switch + { + JoyConType.Left => new Vector3(-motionData.Z, motionData.Y, motionData.X), + JoyConType.Right => new Vector3(motionData.Z, motionData.Y, -motionData.X), + _ => Vector3.Zero + }; + } + + public void SetTriggerThreshold(float triggerThreshold) + { + _gamepad.SetTriggerThreshold(triggerThreshold); + } + + public void SetConfiguration(InputConfig configuration) + { + _gamepad.SetConfiguration(configuration); + } + + public void Rumble(float lowFrequency, float highFrequency, uint durationMs) + { + _gamepad.Rumble(lowFrequency, highFrequency, durationMs); + } + + public GamepadStateSnapshot GetMappedStateSnapshot() + { + return GetStateSnapshot(); + } + + public GamepadStateSnapshot GetStateSnapshot() + { + return IGamepad.GetStateSnapshot(this); + } + + + public (float, float) GetStick(StickInputId inputId) + { + if (inputId == StickInputId.Left) + { + switch (_joyConType) + { + case JoyConType.Left: + { + (float x, float y) = _gamepad.GetStick(inputId); + return (y, -x); + } + case JoyConType.Right: + { + (float x, float y) = _gamepad.GetStick(inputId); + return (-y, x); + } + } + } + return (0, 0); + } + + public GamepadFeaturesFlag Features => _gamepad.Features; + public string Id => _gamepad.Id; + public string Name => _gamepad.Name; + public bool IsConnected => _gamepad.IsConnected; + + public bool IsPressed(GamepadButtonInputId inputId) + { + return _joyConType switch + { + JoyConType.Left => inputId switch + { + GamepadButtonInputId.LeftStick => _gamepad.IsPressed(GamepadButtonInputId.LeftStick), + GamepadButtonInputId.DpadUp => _gamepad.IsPressed(GamepadButtonInputId.Y), + GamepadButtonInputId.DpadDown => _gamepad.IsPressed(GamepadButtonInputId.A), + GamepadButtonInputId.DpadLeft => _gamepad.IsPressed(GamepadButtonInputId.B), + GamepadButtonInputId.DpadRight => _gamepad.IsPressed(GamepadButtonInputId.X), + GamepadButtonInputId.Minus => _gamepad.IsPressed(GamepadButtonInputId.Start), + GamepadButtonInputId.LeftShoulder => _gamepad.IsPressed(GamepadButtonInputId.Paddle2), + GamepadButtonInputId.LeftTrigger => _gamepad.IsPressed(GamepadButtonInputId.Paddle4), + GamepadButtonInputId.SingleRightTrigger0 => _gamepad.IsPressed(GamepadButtonInputId.RightShoulder), + GamepadButtonInputId.SingleLeftTrigger0 => _gamepad.IsPressed(GamepadButtonInputId.LeftShoulder), + _ => false + }, + JoyConType.Right => inputId switch + { + GamepadButtonInputId.RightStick => _gamepad.IsPressed(GamepadButtonInputId.LeftStick), + GamepadButtonInputId.A => _gamepad.IsPressed(GamepadButtonInputId.B), + GamepadButtonInputId.B => _gamepad.IsPressed(GamepadButtonInputId.Y), + GamepadButtonInputId.X => _gamepad.IsPressed(GamepadButtonInputId.A), + GamepadButtonInputId.Y => _gamepad.IsPressed(GamepadButtonInputId.X), + GamepadButtonInputId.Plus => _gamepad.IsPressed(GamepadButtonInputId.Start), + GamepadButtonInputId.RightShoulder => _gamepad.IsPressed(GamepadButtonInputId.Paddle1), + GamepadButtonInputId.RightTrigger => _gamepad.IsPressed(GamepadButtonInputId.Paddle3), + GamepadButtonInputId.SingleRightTrigger1 => _gamepad.IsPressed(GamepadButtonInputId.RightShoulder), + GamepadButtonInputId.SingleLeftTrigger1 => _gamepad.IsPressed(GamepadButtonInputId.LeftShoulder), + _ => false + } + }; + } + + public void Dispose() + { + _gamepad.Dispose(); + } + } +} diff --git a/src/Ryujinx.Input.SDL2/SDL2JoyConPair.cs b/src/Ryujinx.Input.SDL2/SDL2JoyConPair.cs index 4c825dd1a..5ff11f987 100644 --- a/src/Ryujinx.Input.SDL2/SDL2JoyConPair.cs +++ b/src/Ryujinx.Input.SDL2/SDL2JoyConPair.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using System.Linq; using System.Numerics; -using System.Threading; using static SDL2.SDL; namespace Ryujinx.Input.SDL2 @@ -20,15 +19,6 @@ namespace Ryujinx.Input.SDL2 StickInputId.Right ]; - private readonly record struct ButtonMappingEntry(GamepadButtonInputId To, GamepadButtonInputId From) - { - public bool IsValid => To is not GamepadButtonInputId.Unbound && From is not GamepadButtonInputId.Unbound; - } - - private readonly List _buttonsUserMapping = new(20); - - private readonly Lock _userMappingLock = new(); - public GamepadFeaturesFlag Features => (left?.Features ?? GamepadFeaturesFlag.None) | (right?.Features ?? GamepadFeaturesFlag.None); @@ -36,8 +26,6 @@ namespace Ryujinx.Input.SDL2 string IGamepad.Id => Id; public string Name => "Nintendo Switch Joy-Con (L/R)"; - private const string LeftName = "Nintendo Switch Joy-Con (L)"; - private const string RightName = "Nintendo Switch Joy-Con (R)"; public bool IsConnected => left is { IsConnected: true } && right is { IsConnected: true }; public void Dispose() @@ -48,57 +36,19 @@ namespace Ryujinx.Input.SDL2 public GamepadStateSnapshot GetMappedStateSnapshot() { - GamepadStateSnapshot rawState = GetStateSnapshot(); - GamepadStateSnapshot result = default; - - lock (_userMappingLock) - { - if (_buttonsUserMapping.Count == 0) - return rawState; - - - // ReSharper disable once ForeachCanBePartlyConvertedToQueryUsingAnotherGetEnumerator - foreach (ButtonMappingEntry entry in _buttonsUserMapping) - { - if (!entry.IsValid) - continue; - - // Do not touch state of button already pressed - if (!result.IsPressed(entry.To)) - { - result.SetPressed(entry.To, rawState.IsPressed(entry.From)); - } - } - - (float leftStickX, float leftStickY) = rawState.GetStick(_stickUserMapping[(int)StickInputId.Left]); - (float rightStickX, float rightStickY) = rawState.GetStick(_stickUserMapping[(int)StickInputId.Right]); - - result.SetStick(StickInputId.Left, leftStickX, leftStickY); - result.SetStick(StickInputId.Right, rightStickX, rightStickY); - } - - return result; + return GetStateSnapshot(); } public Vector3 GetMotionData(MotionInputId inputId) { - Vector3 motionData; - switch (inputId) + return inputId switch { - case MotionInputId.Accelerometer: - case MotionInputId.Gyroscope: - motionData = left.GetMotionData(inputId); - return new Vector3(-motionData.Z, motionData.Y, motionData.X); - case MotionInputId.SecondAccelerometer: - motionData = right.GetMotionData(MotionInputId.Accelerometer); - return new Vector3(motionData.Z, motionData.Y, -motionData.X); - case MotionInputId.SecondGyroscope: - motionData = right.GetMotionData(MotionInputId.Gyroscope); - return new Vector3(motionData.Z, motionData.Y, -motionData.X); - case MotionInputId.Invalid: - default: - return Vector3.Zero; - } + MotionInputId.Accelerometer or + MotionInputId.Gyroscope => left.GetMotionData(inputId), + MotionInputId.SecondAccelerometer => right.GetMotionData(MotionInputId.Accelerometer), + MotionInputId.SecondGyroscope => right.GetMotionData(MotionInputId.Gyroscope), + _ => Vector3.Zero + }; } public GamepadStateSnapshot GetStateSnapshot() @@ -108,53 +58,17 @@ namespace Ryujinx.Input.SDL2 public (float, float) GetStick(StickInputId inputId) { - switch (inputId) + return inputId switch { - case StickInputId.Left: - { - (float x, float y) = left.GetStick(StickInputId.Left); - return (y, -x); - } - case StickInputId.Right: - { - (float x, float y) = right.GetStick(StickInputId.Left); - return (-y, x); - } - case StickInputId.Unbound: - case StickInputId.Count: - default: - return (0, 0); - } + StickInputId.Left => left.GetStick(StickInputId.Left), + StickInputId.Right => right.GetStick(StickInputId.Left), + _ => (0, 0) + }; } public bool IsPressed(GamepadButtonInputId inputId) { - return inputId switch - { - GamepadButtonInputId.LeftStick => left.IsPressed(GamepadButtonInputId.LeftStick), - GamepadButtonInputId.DpadUp => left.IsPressed(GamepadButtonInputId.Y), - GamepadButtonInputId.DpadDown => left.IsPressed(GamepadButtonInputId.A), - GamepadButtonInputId.DpadLeft => left.IsPressed(GamepadButtonInputId.B), - GamepadButtonInputId.DpadRight => left.IsPressed(GamepadButtonInputId.X), - GamepadButtonInputId.Minus => left.IsPressed(GamepadButtonInputId.Start), - GamepadButtonInputId.LeftShoulder => left.IsPressed(GamepadButtonInputId.Paddle2), - GamepadButtonInputId.LeftTrigger => left.IsPressed(GamepadButtonInputId.Paddle4), - GamepadButtonInputId.SingleRightTrigger0 => left.IsPressed(GamepadButtonInputId.LeftShoulder), - GamepadButtonInputId.SingleLeftTrigger0 => left.IsPressed(GamepadButtonInputId.RightShoulder), - - GamepadButtonInputId.RightStick => right.IsPressed(GamepadButtonInputId.LeftStick), - GamepadButtonInputId.A => right.IsPressed(GamepadButtonInputId.B), - GamepadButtonInputId.B => right.IsPressed(GamepadButtonInputId.Y), - GamepadButtonInputId.X => right.IsPressed(GamepadButtonInputId.A), - GamepadButtonInputId.Y => right.IsPressed(GamepadButtonInputId.X), - GamepadButtonInputId.Plus => right.IsPressed(GamepadButtonInputId.Start), - GamepadButtonInputId.RightShoulder => right.IsPressed(GamepadButtonInputId.Paddle1), - GamepadButtonInputId.RightTrigger => right.IsPressed(GamepadButtonInputId.Paddle3), - GamepadButtonInputId.SingleRightTrigger1 => right.IsPressed(GamepadButtonInputId.LeftShoulder), - GamepadButtonInputId.SingleLeftTrigger1 => right.IsPressed(GamepadButtonInputId.RightShoulder), - - _ => false - }; + return left.IsPressed(inputId) || right.IsPressed(inputId); } public void Rumble(float lowFrequency, float highFrequency, uint durationMs) @@ -178,64 +92,8 @@ namespace Ryujinx.Input.SDL2 public void SetConfiguration(InputConfig configuration) { - lock (_userMappingLock) - { - _configuration = (StandardControllerInputConfig)configuration; - left.SetConfiguration(configuration); - right.SetConfiguration(configuration); - - _buttonsUserMapping.Clear(); - - // First update sticks - _stickUserMapping[(int)StickInputId.Left] = (StickInputId)_configuration.LeftJoyconStick.Joystick; - _stickUserMapping[(int)StickInputId.Right] = (StickInputId)_configuration.RightJoyconStick.Joystick; - - // Then left joycon - _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.LeftStick, - (GamepadButtonInputId)_configuration.LeftJoyconStick.StickButton)); - _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadUp, - (GamepadButtonInputId)_configuration.LeftJoycon.DpadUp)); - _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadDown, - (GamepadButtonInputId)_configuration.LeftJoycon.DpadDown)); - _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadLeft, - (GamepadButtonInputId)_configuration.LeftJoycon.DpadLeft)); - _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadRight, - (GamepadButtonInputId)_configuration.LeftJoycon.DpadRight)); - _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.Minus, - (GamepadButtonInputId)_configuration.LeftJoycon.ButtonMinus)); - _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.LeftShoulder, - (GamepadButtonInputId)_configuration.LeftJoycon.ButtonL)); - _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.LeftTrigger, - (GamepadButtonInputId)_configuration.LeftJoycon.ButtonZl)); - _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleRightTrigger0, - (GamepadButtonInputId)_configuration.LeftJoycon.ButtonSr)); - _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleLeftTrigger0, - (GamepadButtonInputId)_configuration.LeftJoycon.ButtonSl)); - - // Finally right joycon - _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.RightStick, - (GamepadButtonInputId)_configuration.RightJoyconStick.StickButton)); - _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.A, - (GamepadButtonInputId)_configuration.RightJoycon.ButtonA)); - _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.B, - (GamepadButtonInputId)_configuration.RightJoycon.ButtonB)); - _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.X, - (GamepadButtonInputId)_configuration.RightJoycon.ButtonX)); - _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.Y, - (GamepadButtonInputId)_configuration.RightJoycon.ButtonY)); - _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.Plus, - (GamepadButtonInputId)_configuration.RightJoycon.ButtonPlus)); - _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.RightShoulder, - (GamepadButtonInputId)_configuration.RightJoycon.ButtonR)); - _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.RightTrigger, - (GamepadButtonInputId)_configuration.RightJoycon.ButtonZr)); - _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleRightTrigger1, - (GamepadButtonInputId)_configuration.RightJoycon.ButtonSr)); - _buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleLeftTrigger1, - (GamepadButtonInputId)_configuration.RightJoycon.ButtonSl)); - - SetTriggerThreshold(_configuration.TriggerThreshold); - } + left.SetConfiguration(configuration); + right.SetConfiguration(configuration); } public void SetTriggerThreshold(float triggerThreshold) @@ -254,8 +112,8 @@ namespace Ryujinx.Input.SDL2 { var gamepadNames = gamepadsIds.Where(gamepadId => gamepadId != Id) .Select((_, index) => SDL_GameControllerNameForIndex(index)).ToList(); - int leftIndex = gamepadNames.IndexOf(LeftName); - int rightIndex = gamepadNames.IndexOf(RightName); + int leftIndex = gamepadNames.IndexOf(SDL2JoyCon.LeftName); + int rightIndex = gamepadNames.IndexOf(SDL2JoyCon.RightName); return (leftIndex, rightIndex); } @@ -277,8 +135,8 @@ namespace Ryujinx.Input.SDL2 } - return new SDL2JoyConPair(new SDL2Gamepad(leftGamepadHandle, gamepadsIds[leftIndex]), - new SDL2Gamepad(rightGamepadHandle, gamepadsIds[rightIndex])); + return new SDL2JoyConPair(new SDL2JoyCon(leftGamepadHandle, gamepadsIds[leftIndex]), + new SDL2JoyCon(rightGamepadHandle, gamepadsIds[rightIndex])); } } }