From c4b9aedc0f2851fe08de1b7477e2a722619bc83e Mon Sep 17 00:00:00 2001 From: madwind Date: Mon, 13 Jan 2025 22:44:44 +0800 Subject: [PATCH] update --- src/Ryujinx.Input.SDL3/SDL3Gamepad.cs | 13 ++-- src/Ryujinx.Input.SDL3/SDL3GamepadDriver.cs | 73 +++++++-------------- src/Ryujinx.Input.SDL3/SDL3JoyCon.cs | 47 ++++++++----- src/Ryujinx.Input.SDL3/SDL3JoyConPair.cs | 45 +++++-------- src/Ryujinx.SDL3-CS/SDL3.cs | 21 ++++-- src/Ryujinx.SDL3.Common/SDL3Driver.cs | 16 ++--- 6 files changed, 102 insertions(+), 113 deletions(-) diff --git a/src/Ryujinx.Input.SDL3/SDL3Gamepad.cs b/src/Ryujinx.Input.SDL3/SDL3Gamepad.cs index ea019badc..b1162cdb8 100644 --- a/src/Ryujinx.Input.SDL3/SDL3Gamepad.cs +++ b/src/Ryujinx.Input.SDL3/SDL3Gamepad.cs @@ -60,13 +60,13 @@ namespace Ryujinx.Input.SDL3 private float _triggerThreshold; - public SDL3Gamepad(GamepadInfo gamepadInfo) + public SDL3Gamepad(SDL_JoystickID joystickId, string driverId) { - _gamepadHandle = gamepadInfo.gamepadHandle; + _gamepadHandle = SDL_OpenGamepad(joystickId); _buttonsUserMapping = new List(20); Name = SDL_GetGamepadName(_gamepadHandle); - Id = gamepadInfo.driverId; + Id = driverId; Features = GetFeaturesFlag(); _triggerThreshold = 0.0f; @@ -110,7 +110,7 @@ namespace Ryujinx.Input.SDL3 public bool IsConnected => SDL_GamepadConnected(_gamepadHandle); - protected virtual void Dispose(bool disposing) + private void Dispose(bool disposing) { if (disposing && _gamepadHandle != nint.Zero) { @@ -370,12 +370,13 @@ namespace Ryujinx.Input.SDL3 SDL_GamepadAxis.SDL_GAMEPAD_AXIS_RIGHT_TRIGGER)) > _triggerThreshold; } - if (_buttonsDriverMapping[(int)inputId] == SDL_GamepadButton.SDL_GAMEPAD_BUTTON_INVALID) + var button = _buttonsDriverMapping[(int)inputId]; + if (button == SDL_GamepadButton.SDL_GAMEPAD_BUTTON_INVALID) { return false; } - return SDL_GetGamepadButton(_gamepadHandle, _buttonsDriverMapping[(int)inputId]); + return SDL_GetGamepadButton(_gamepadHandle, button); } } } diff --git a/src/Ryujinx.Input.SDL3/SDL3GamepadDriver.cs b/src/Ryujinx.Input.SDL3/SDL3GamepadDriver.cs index d810d36d7..3f18aad57 100644 --- a/src/Ryujinx.Input.SDL3/SDL3GamepadDriver.cs +++ b/src/Ryujinx.Input.SDL3/SDL3GamepadDriver.cs @@ -12,7 +12,7 @@ namespace Ryujinx.Input.SDl3 { public class SDL3GamepadDriver : IGamepadDriver { - private readonly Dictionary _gamepadsInstanceIdsMapping; + private readonly Dictionary _gamepadsInstanceIdsMapping; private readonly List _gamepadsIds; private readonly Lock _lock = new(); @@ -34,36 +34,21 @@ namespace Ryujinx.Input.SDl3 public SDL3GamepadDriver() { - _gamepadsInstanceIdsMapping = new Dictionary(); + _gamepadsInstanceIdsMapping = new Dictionary(); _gamepadsIds = new List(); SDL3Driver.Instance.Initialize(); SDL3Driver.Instance.OnJoyStickConnected += HandleJoyStickConnected; SDL3Driver.Instance.OnJoystickDisconnected += HandleJoyStickDisconnected; SDL3Driver.Instance.OnJoyBatteryUpdated += HandleJoyBatteryUpdated; - - // IntPtr joystickArray = SDL_GetJoysticks(out int count); - // - // var joystickIDs = new int[count]; - // Marshal.Copy(joystickArray, joystickIDs, 0, count); - // - // for (int i = 0; i < count; i++) - // { - // HandleJoyStickConnected((uint)joystickIDs[i]); - // } } - private string GenerateGamepadId(uint joystickIndex) + private string GenerateGamepadId(SDL_JoystickID joystickId) { int bufferSize = 33; - Span pszGUID = stackalloc byte[bufferSize]; - SDL_GUIDToString(SDL_GetJoystickGUIDForID(joystickIndex), pszGUID, bufferSize); - var guid = Encoding.UTF8.GetString(pszGUID); - - // if (guid == new SDL_GUID()) - // { - // return null; - // } + Span pszGuid = stackalloc byte[bufferSize]; + SDL_GUIDToString(SDL_GetJoystickGUIDForID(joystickId), pszGuid, bufferSize); + var guid = Encoding.UTF8.GetString(pszGuid); string id; lock (_lock) @@ -80,24 +65,23 @@ namespace Ryujinx.Input.SDl3 return id; } - private GamepadInfo GetJoystickIndexByGamepadId(string id) + private KeyValuePair GetGamepadInfoByGamepadId(string id) { lock (_lock) { - return _gamepadsInstanceIdsMapping.FirstOrDefault(x => x.Value.driverId == id).Value; + return _gamepadsInstanceIdsMapping.FirstOrDefault(gamepadId => gamepadId.Value == id); } } - private void HandleJoyStickDisconnected(uint joystickInstanceId) + private void HandleJoyStickDisconnected(SDL_JoystickID joystickId) { bool joyConPairDisconnected = false; - if (!_gamepadsInstanceIdsMapping.Remove(joystickInstanceId, out GamepadInfo gamepadInfo)) + if (!_gamepadsInstanceIdsMapping.Remove(joystickId, out string id)) return; lock (_lock) { - _gamepadsIds.Remove(gamepadInfo.driverId); - SDL_CloseGamepad(gamepadInfo.gamepadHandle); + _gamepadsIds.Remove(id); if (!SDL3JoyConPair.IsCombinable(_gamepadsInstanceIdsMapping)) { _gamepadsIds.Remove(SDL3JoyConPair.Id); @@ -105,40 +89,35 @@ namespace Ryujinx.Input.SDl3 } } - OnGamepadDisconnected?.Invoke(gamepadInfo.driverId); + OnGamepadDisconnected?.Invoke(id); if (joyConPairDisconnected) { OnGamepadDisconnected?.Invoke(SDL3JoyConPair.Id); } } - private void HandleJoyStickConnected(uint gamepadInstanceId) + private void HandleJoyStickConnected(SDL_JoystickID joystickId) { bool joyConPairConnected = false; - if (_gamepadsInstanceIdsMapping.ContainsKey(gamepadInstanceId)) + if (_gamepadsInstanceIdsMapping.ContainsKey(joystickId)) { // Sometimes a JoyStick connected event fires after the app starts even though it was connected before // so it is rejected to avoid doubling the entries. return; } - string id = GenerateGamepadId(gamepadInstanceId); + string id = GenerateGamepadId(joystickId); if (id == null) { return; } - if (_gamepadsInstanceIdsMapping.TryAdd(gamepadInstanceId, new GamepadInfo(id, SDL_OpenGamepad(gamepadInstanceId)))) + if (_gamepadsInstanceIdsMapping.TryAdd(joystickId, id)) { lock (_lock) { - if (gamepadInstanceId <= _gamepadsIds.FindLastIndex(_ => true)) - { - // _gamepadsIds.Insert(joystickDeviceId, id); - } - else - _gamepadsIds.Add(id); + _gamepadsIds.Add(id); if (SDL3JoyConPair.IsCombinable(_gamepadsInstanceIdsMapping)) { @@ -156,10 +135,10 @@ namespace Ryujinx.Input.SDl3 } } - private void HandleJoyBatteryUpdated(uint joystickDeviceId, SDL_JoyBatteryEvent joyBatteryEvent) + private void HandleJoyBatteryUpdated(SDL_JoystickID joystickId, SDL_JoyBatteryEvent joyBatteryEvent) { Logger.Info?.Print(LogClass.Hid, - $"{SDL_GetGamepadNameForID(joystickDeviceId)}, Battery percent: {joyBatteryEvent.percent}"); + $"{SDL_GetGamepadNameForID(joystickId)}, Battery percent: {joyBatteryEvent.percent}"); } protected virtual void Dispose(bool disposing) @@ -200,18 +179,14 @@ namespace Ryujinx.Input.SDl3 } } - var gamepadInfo = GetJoystickIndexByGamepadId(id); - if (gamepadInfo == null) + var gamepadInfo = GetGamepadInfoByGamepadId(id); + + if (SDL3JoyCon.IsJoyCon(gamepadInfo.Key)) { - return null; + return new SDL3JoyCon(gamepadInfo.Key, gamepadInfo.Value); } - if (SDL3JoyCon.IsJoyCon(gamepadInfo.gamepadHandle)) - { - return new SDL3JoyCon(gamepadInfo); - } - - return new SDL3Gamepad(gamepadInfo); + return new SDL3Gamepad(gamepadInfo.Key, gamepadInfo.Value); } } } diff --git a/src/Ryujinx.Input.SDL3/SDL3JoyCon.cs b/src/Ryujinx.Input.SDL3/SDL3JoyCon.cs index 02451b17e..8ab87aca0 100644 --- a/src/Ryujinx.Input.SDL3/SDL3JoyCon.cs +++ b/src/Ryujinx.Input.SDL3/SDL3JoyCon.cs @@ -3,13 +3,14 @@ using Ryujinx.Common.Configuration.Hid.Controller; using Ryujinx.Common.Logging; using System; using System.Collections.Generic; +using System.Linq; using System.Numerics; using System.Threading; using static SDL3.SDL; namespace Ryujinx.Input.SDL3 { - internal class SDL3JoyCon : IGamepad + class SDL3JoyCon : IGamepad { private bool HasConfiguration => _configuration != null; @@ -48,7 +49,7 @@ namespace Ryujinx.Input.SDL3 { GamepadButtonInputId.SingleLeftTrigger1, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_LEFT_SHOULDER } }; - private readonly Dictionary _buttonsDriverMapping; + private readonly SDL_GamepadButton[] _buttonsDriverMapping; private readonly Lock _userMappingLock = new(); private readonly List _buttonsUserMapping; @@ -61,7 +62,7 @@ namespace Ryujinx.Input.SDL3 public GamepadFeaturesFlag Features { get; } private nint _gamepadHandle; - + private enum JoyConType { Left, Right @@ -72,16 +73,15 @@ namespace Ryujinx.Input.SDL3 private readonly JoyConType _joyConType; - public SDL3JoyCon(GamepadInfo gamepadInfo) + public SDL3JoyCon(SDL_JoystickID joystickId, string driverId) { - _gamepadHandle = gamepadInfo.gamepadHandle; + _gamepadHandle = SDL_OpenGamepad(joystickId); _buttonsUserMapping = new List(10); Name = SDL_GetGamepadName(_gamepadHandle); - Id = gamepadInfo.driverId; + Id = driverId; Features = GetFeaturesFlag(); - Console.WriteLine(Name+": "+Features); - + // Enable motion tracking if (Features.HasFlag(GamepadFeaturesFlag.Motion)) { @@ -102,19 +102,32 @@ namespace Ryujinx.Input.SDL3 { case LeftName: { - _buttonsDriverMapping = _leftButtonsDriverMapping; + _buttonsDriverMapping = ToSDLButtonMapping(_leftButtonsDriverMapping); _joyConType = JoyConType.Left; break; } case RightName: { - _buttonsDriverMapping = _rightButtonsDriverMapping; + _buttonsDriverMapping = ToSDLButtonMapping(_rightButtonsDriverMapping); _joyConType = JoyConType.Right; break; } + default: + throw new InvalidOperationException( + $"Unexpected Name: {Name}. Expected '{LeftName}' or '{RightName}'."); } } + private static SDL_GamepadButton[] ToSDLButtonMapping( + Dictionary buttonsDriverMapping) + { + return Enumerable.Range(0, (int)GamepadButtonInputId.Count) + .Select(i => + buttonsDriverMapping.GetValueOrDefault((GamepadButtonInputId)i, + SDL_GamepadButton.SDL_GAMEPAD_BUTTON_INVALID)) + .ToArray(); + } + private GamepadFeaturesFlag GetFeaturesFlag() { GamepadFeaturesFlag result = GamepadFeaturesFlag.None; @@ -136,11 +149,11 @@ namespace Ryujinx.Input.SDL3 public string Name { get; } public bool IsConnected => SDL_GamepadConnected(_gamepadHandle); - protected virtual void Dispose(bool disposing) + private void Dispose(bool disposing) { if (disposing && _gamepadHandle != nint.Zero) { - // SDL_CloseGamepad(_gamepadHandle); + SDL_CloseGamepad(_gamepadHandle); _gamepadHandle = nint.Zero; } } @@ -195,7 +208,8 @@ namespace Ryujinx.Input.SDL3 Vector3 value = _joyConType switch { JoyConType.Left => new Vector3(-values[2], values[1], values[0]), - JoyConType.Right => new Vector3(values[2], values[1], -values[0]) + JoyConType.Right => new Vector3(values[2], values[1], -values[0]), + _ => throw new ArgumentOutOfRangeException($"Unexpected JoyConType value: {_joyConType}") }; return inputId switch @@ -401,7 +415,8 @@ namespace Ryujinx.Input.SDL3 public bool IsPressed(GamepadButtonInputId inputId) { - if (!_buttonsDriverMapping.TryGetValue(inputId, out var button)) + var button = _buttonsDriverMapping[(int)inputId]; + if (button == SDL_GamepadButton.SDL_GAMEPAD_BUTTON_INVALID) { return false; } @@ -413,9 +428,9 @@ namespace Ryujinx.Input.SDL3 return SDL_GetGamepadButton(_gamepadHandle, button); } - public static bool IsJoyCon(IntPtr gamepadHandle) + public static bool IsJoyCon(SDL_JoystickID joystickId) { - var gamepadName = SDL_GetGamepadName(gamepadHandle); + var gamepadName = SDL_GetGamepadNameForID(joystickId); return gamepadName is LeftName or RightName; } } diff --git a/src/Ryujinx.Input.SDL3/SDL3JoyConPair.cs b/src/Ryujinx.Input.SDL3/SDL3JoyConPair.cs index 558392afa..ef8ae9b01 100644 --- a/src/Ryujinx.Input.SDL3/SDL3JoyConPair.cs +++ b/src/Ryujinx.Input.SDL3/SDL3JoyConPair.cs @@ -1,5 +1,4 @@ using Ryujinx.Common.Configuration.Hid; -using Ryujinx.Common.Configuration.Hid.Controller; using System.Collections.Generic; using System.Linq; using System.Numerics; @@ -7,24 +6,15 @@ using static SDL3.SDL; namespace Ryujinx.Input.SDL3 { - internal class SDL3JoyConPair(IGamepad left, IGamepad right) : IGamepad + class SDL3JoyConPair(IGamepad left, IGamepad right) : IGamepad { - private StandardControllerInputConfig _configuration; - - private readonly StickInputId[] _stickUserMapping = - [ - StickInputId.Unbound, - StickInputId.Left, - StickInputId.Right - ]; - public GamepadFeaturesFlag Features => (left?.Features ?? GamepadFeaturesFlag.None) | (right?.Features ?? GamepadFeaturesFlag.None); public const string Id = "JoyConPair"; string IGamepad.Id => Id; - public string Name => "Nintendo Switch Joy-Con (L/R)"; + public string Name => "* Nintendo Switch Joy-Con (L/R)"; public bool IsConnected => left is { IsConnected: true } && right is { IsConnected: true }; public void Dispose() @@ -101,32 +91,27 @@ namespace Ryujinx.Input.SDL3 right.SetTriggerThreshold(triggerThreshold); } - public static bool IsCombinable(Dictionary gamepadsInstanceIdsMapping) + public static bool IsCombinable(Dictionary gamepadsInstanceIdsMapping) { - (GamepadInfo leftGamepadInfo, GamepadInfo rightGamepadInfo) = DetectJoyConPair(gamepadsInstanceIdsMapping); - return leftGamepadInfo != null && rightGamepadInfo != null; + var gamepadNames = gamepadsInstanceIdsMapping.Keys.Select(id => SDL_GetGamepadNameForID(id)).ToArray(); + return gamepadNames.Contains(SDL3JoyCon.LeftName) && gamepadNames.Contains(SDL3JoyCon.RightName); } - private static (GamepadInfo leftGamepadInfo, GamepadInfo rightGamepadInfo) DetectJoyConPair( - Dictionary gamepadsInstanceIdsMapping) + public static IGamepad GetGamepad(Dictionary gamepadsInstanceIdsMapping) { - var leftGamepadInfo = gamepadsInstanceIdsMapping - .FirstOrDefault(item => SDL_GetGamepadNameForID(item.Key) == SDL3JoyCon.LeftName).Value; - var rightGamepadInfo = gamepadsInstanceIdsMapping - .FirstOrDefault(item => SDL_GetGamepadNameForID(item.Key) == SDL3JoyCon.RightName).Value; - - return (leftGamepadInfo, rightGamepadInfo); - } - - public static IGamepad GetGamepad(Dictionary gamepadsInstanceIdsMapping) - { - (GamepadInfo leftGamepadInfo, GamepadInfo rightGamepadInfo) = DetectJoyConPair(gamepadsInstanceIdsMapping); - if (leftGamepadInfo == null || rightGamepadInfo == null) + var leftPair = + gamepadsInstanceIdsMapping.FirstOrDefault(pair => + SDL_GetGamepadNameForID(pair.Key) == SDL3JoyCon.LeftName); + var rightPair = + gamepadsInstanceIdsMapping.FirstOrDefault(pair => + SDL_GetGamepadNameForID(pair.Key) == SDL3JoyCon.RightName); + if (leftPair.Key == 0 || rightPair.Key == 0) { return null; } - return new SDL3JoyConPair(new SDL3JoyCon(leftGamepadInfo), new SDL3JoyCon(rightGamepadInfo)); + return new SDL3JoyConPair(new SDL3JoyCon(leftPair.Key, leftPair.Value), + new SDL3JoyCon(rightPair.Key, rightPair.Value)); } } } diff --git a/src/Ryujinx.SDL3-CS/SDL3.cs b/src/Ryujinx.SDL3-CS/SDL3.cs index ffb7261f6..8afa0a94c 100644 --- a/src/Ryujinx.SDL3-CS/SDL3.cs +++ b/src/Ryujinx.SDL3-CS/SDL3.cs @@ -9,6 +9,7 @@ using System.Text; public static unsafe partial class SDL { + // Custom marshaller for SDL-owned strings returned by SDL. [CustomMarshaller(typeof(string), MarshalMode.ManagedToUnmanagedOut, typeof(SDLOwnedStringMarshaller))] public static unsafe class SDLOwnedStringMarshaller @@ -2591,7 +2592,7 @@ public static unsafe partial class SDL [LibraryImport(nativeLibName, StringMarshalling = StringMarshalling.Utf8)] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - public static partial void SDL_GUIDToString(SDL_GUID guid, Span pszGUID, int cbGUID); + public static partial void SDL_GUIDToString(SDL_GUID guid, Span pszGUID, int cbGUID); [LibraryImport(nativeLibName, StringMarshalling = StringMarshalling.Utf8)] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] @@ -2748,7 +2749,7 @@ public static unsafe partial class SDL [LibraryImport(nativeLibName)] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - public static partial SDL_GUID SDL_GetJoystickGUIDForID(uint instance_id); + public static partial SDL_GUID SDL_GetJoystickGUIDForID(SDL_JoystickID instance_id); [LibraryImport(nativeLibName)] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] @@ -4619,7 +4620,7 @@ public static unsafe partial class SDL public SDL_EventType type; public uint reserved; public ulong timestamp; - public uint which; + public SDL_JoystickID which; } [StructLayout(LayoutKind.Sequential)] @@ -4628,7 +4629,7 @@ public static unsafe partial class SDL public SDL_EventType type; public uint reserved; public ulong timestamp; - public uint which; + public SDL_JoystickID which; public SDL_PowerState state; public int percent; } @@ -8050,4 +8051,16 @@ public static unsafe partial class SDL public const uint SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK = 0xFFFFFFFFu; public const float SDL_STANDARD_GRAVITY = 9.80665f; + public record struct SDL_JoystickID + { + public uint Value; + + public SDL_JoystickID(uint value) + { + Value = value; + } + + public static implicit operator uint(SDL_JoystickID id) => id.Value; + public static implicit operator SDL_JoystickID(uint value) => new SDL_JoystickID(value); + } } diff --git a/src/Ryujinx.SDL3.Common/SDL3Driver.cs b/src/Ryujinx.SDL3.Common/SDL3Driver.cs index 73982ef12..52d7240bb 100644 --- a/src/Ryujinx.SDL3.Common/SDL3Driver.cs +++ b/src/Ryujinx.SDL3.Common/SDL3Driver.cs @@ -7,6 +7,7 @@ using System.IO; using System.Threading; using static SDL3.SDL; + namespace Ryujinx.SDL3.Common { public class SDL3Driver : IDisposable @@ -32,9 +33,9 @@ namespace Ryujinx.SDL3.Common private uint _refereceCount; private Thread _worker; - public event Action OnJoyStickConnected; - public event Action OnJoystickDisconnected; - public event Action OnJoyBatteryUpdated; + public event Action OnJoyStickConnected; + public event Action OnJoystickDisconnected; + public event Action OnJoyBatteryUpdated; private ConcurrentDictionary> _registeredWindowHandlers; @@ -54,11 +55,10 @@ namespace Ryujinx.SDL3.Common } SDL_SetHint(SDL_HINT_APP_NAME, "Ryujinx"); - SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, "1"); - SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, "1"); + // SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, "1"); + // SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, "1"); SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1"); SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH_HOME_LED, "0"); - SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, "1"); SDL_SetHint(SDL_HINT_VIDEO_ALLOW_SCREENSAVER, "1"); // // @@ -126,7 +126,7 @@ namespace Ryujinx.SDL3.Common var type = (SDL_EventType)evnt.type; if (type == SDL_EventType.SDL_EVENT_GAMEPAD_ADDED) { - uint instanceId = evnt.jdevice.which; + var instanceId = evnt.jdevice.which; Logger.Debug?.Print(LogClass.Application, $"Added joystick instance id {instanceId}"); @@ -134,7 +134,7 @@ namespace Ryujinx.SDL3.Common } else if (type == SDL_EventType.SDL_EVENT_GAMEPAD_REMOVED) { - uint instanceId = evnt.jdevice.which; + var instanceId = evnt.jdevice.which; Logger.Debug?.Print(LogClass.Application, $"Removed joystick instance id {instanceId}");