aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Ryujinx.Input.SDL2/SDL2GamepadDriver.cs74
-rw-r--r--src/Ryujinx.Input/HLE/NpadManager.cs47
2 files changed, 89 insertions, 32 deletions
diff --git a/src/Ryujinx.Input.SDL2/SDL2GamepadDriver.cs b/src/Ryujinx.Input.SDL2/SDL2GamepadDriver.cs
index 0e3a1301..c741493c 100644
--- a/src/Ryujinx.Input.SDL2/SDL2GamepadDriver.cs
+++ b/src/Ryujinx.Input.SDL2/SDL2GamepadDriver.cs
@@ -9,8 +9,18 @@ namespace Ryujinx.Input.SDL2
{
private readonly Dictionary<int, string> _gamepadsInstanceIdsMapping;
private readonly List<string> _gamepadsIds;
+ private readonly object _lock = new object();
- public ReadOnlySpan<string> GamepadsIds => _gamepadsIds.ToArray();
+ public ReadOnlySpan<string> GamepadsIds
+ {
+ get
+ {
+ lock (_lock)
+ {
+ return _gamepadsIds.ToArray();
+ }
+ }
+ }
public string DriverName => "SDL2";
@@ -35,28 +45,39 @@ namespace Ryujinx.Input.SDL2
}
}
- private static string GenerateGamepadId(int joystickIndex)
+ private string GenerateGamepadId(int joystickIndex)
{
Guid guid = SDL_JoystickGetDeviceGUID(joystickIndex);
+ // Add a unique identifier to the start of the GUID in case of duplicates.
+
if (guid == Guid.Empty)
{
return null;
}
- return joystickIndex + "-" + guid;
+ string id;
+
+ lock (_lock)
+ {
+ int guidIndex = 0;
+ id = guidIndex + "-" + guid;
+
+ while (_gamepadsIds.Contains(id))
+ {
+ id = (++guidIndex) + "-" + guid;
+ }
+ }
+
+ return id;
}
- private static int GetJoystickIndexByGamepadId(string id)
+ private int GetJoystickIndexByGamepadId(string id)
{
- string[] data = id.Split("-");
-
- if (data.Length != 6 || !int.TryParse(data[0], out int joystickIndex))
+ lock (_lock)
{
- return -1;
+ return _gamepadsIds.IndexOf(id);
}
-
- return joystickIndex;
}
private void HandleJoyStickDisconnected(int joystickInstanceId)
@@ -64,7 +85,11 @@ namespace Ryujinx.Input.SDL2
if (_gamepadsInstanceIdsMapping.TryGetValue(joystickInstanceId, out string id))
{
_gamepadsInstanceIdsMapping.Remove(joystickInstanceId);
- _gamepadsIds.Remove(id);
+
+ lock (_lock)
+ {
+ _gamepadsIds.Remove(id);
+ }
OnGamepadDisconnected?.Invoke(id);
}
@@ -74,23 +99,26 @@ namespace Ryujinx.Input.SDL2
{
if (SDL_IsGameController(joystickDeviceId) == SDL_bool.SDL_TRUE)
{
- string id = GenerateGamepadId(joystickDeviceId);
-
- if (id == null)
+ if (_gamepadsInstanceIdsMapping.ContainsKey(joystickInstanceId))
{
+ // 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;
}
- // 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.
- if (_gamepadsIds.Contains(id))
+ string id = GenerateGamepadId(joystickDeviceId);
+
+ if (id == null)
{
return;
}
if (_gamepadsInstanceIdsMapping.TryAdd(joystickInstanceId, id))
{
- _gamepadsIds.Add(id);
+ lock (_lock)
+ {
+ _gamepadsIds.Add(id);
+ }
OnGamepadConnected?.Invoke(id);
}
@@ -110,7 +138,10 @@ namespace Ryujinx.Input.SDL2
OnGamepadDisconnected?.Invoke(id);
}
- _gamepadsIds.Clear();
+ lock (_lock)
+ {
+ _gamepadsIds.Clear();
+ }
SDL2Driver.Instance.Dispose();
}
@@ -131,11 +162,6 @@ namespace Ryujinx.Input.SDL2
return null;
}
- if (id != GenerateGamepadId(joystickIndex))
- {
- return null;
- }
-
IntPtr gamepadHandle = SDL_GameControllerOpen(joystickIndex);
if (gamepadHandle == IntPtr.Zero)
diff --git a/src/Ryujinx.Input/HLE/NpadManager.cs b/src/Ryujinx.Input/HLE/NpadManager.cs
index 25887748..5ae73bda 100644
--- a/src/Ryujinx.Input/HLE/NpadManager.cs
+++ b/src/Ryujinx.Input/HLE/NpadManager.cs
@@ -5,6 +5,7 @@ using Ryujinx.HLE.HOS.Services.Hid;
using System;
using System.Collections.Generic;
using System.Diagnostics;
+using System.Linq;
using System.Runtime.CompilerServices;
using CemuHookClient = Ryujinx.Input.Motion.CemuHook.Client;
using ControllerType = Ryujinx.Common.Configuration.Hid.ControllerType;
@@ -69,7 +70,20 @@ namespace Ryujinx.Input.HLE
private void HandleOnGamepadDisconnected(string obj)
{
// Force input reload
- ReloadConfiguration(_inputConfig, _enableKeyboard, _enableMouse);
+ lock (_lock)
+ {
+ // Forcibly disconnect any controllers with this ID.
+ for (int i = 0; i < _controllers.Length; i++)
+ {
+ if (_controllers[i]?.Id == obj)
+ {
+ _controllers[i]?.Dispose();
+ _controllers[i] = null;
+ }
+ }
+
+ ReloadConfiguration(_inputConfig, _enableKeyboard, _enableMouse);
+ }
}
private void HandleOnGamepadConnected(string id)
@@ -106,31 +120,48 @@ namespace Ryujinx.Input.HLE
{
lock (_lock)
{
- for (int i = 0; i < _controllers.Length; i++)
- {
- _controllers[i]?.Dispose();
- _controllers[i] = null;
- }
+ NpadController[] oldControllers = _controllers.ToArray();
List<InputConfig> validInputs = new();
foreach (InputConfig inputConfigEntry in inputConfig)
{
- NpadController controller = new(_cemuHookClient);
+ NpadController controller;
+ int index = (int)inputConfigEntry.PlayerIndex;
+
+ if (oldControllers[index] != null)
+ {
+ // Try reuse the existing controller.
+ controller = oldControllers[index];
+ oldControllers[index] = null;
+ }
+ else
+ {
+ controller = new(_cemuHookClient);
+ }
bool isValid = DriverConfigurationUpdate(ref controller, inputConfigEntry);
if (!isValid)
{
+ _controllers[index] = null;
controller.Dispose();
}
else
{
- _controllers[(int)inputConfigEntry.PlayerIndex] = controller;
+ _controllers[index] = controller;
validInputs.Add(inputConfigEntry);
}
}
+ for (int i = 0; i < oldControllers.Length; i++)
+ {
+ // Disconnect any controllers that weren't reused by the new configuration.
+
+ oldControllers[i]?.Dispose();
+ oldControllers[i] = null;
+ }
+
_inputConfig = inputConfig;
_enableKeyboard = enableKeyboard;
_enableMouse = enableMouse;