Implement new Virtual Controller Joystick. Add Game Requirements

This commit is contained in:
Stossy11 2025-03-24 17:23:47 +11:00
parent 8917ebf708
commit 2b7e29fa21
14 changed files with 467 additions and 127 deletions

View file

@ -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,7 +45,7 @@ namespace Ryujinx.Input.SDL2
}
}
private static string GenerateGamepadId(int joystickIndex)
private string GenerateGamepadId(int joystickIndex)
{
Guid guid = SDL_JoystickGetDeviceGUID(joystickIndex);
@ -44,14 +54,16 @@ namespace Ryujinx.Input.SDL2
return null;
}
// Include joystickIndex at the start of the ID to maintain compatibility with GetJoystickIndexByGamepadId
return joystickIndex + "-" + guid;
}
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))
// Parse the joystick index from the ID string
if (data.Length < 2 || !int.TryParse(data[0], out int joystickIndex))
{
return -1;
}
@ -64,7 +76,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,6 +90,13 @@ namespace Ryujinx.Input.SDL2
{
if (SDL_IsGameController(joystickDeviceId) == SDL_bool.SDL_TRUE)
{
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;
}
string id = GenerateGamepadId(joystickDeviceId);
if (id == null)
@ -81,16 +104,21 @@ namespace Ryujinx.Input.SDL2
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))
// Check if we already have this gamepad ID in our list
lock (_lock)
{
return;
if (_gamepadsIds.Contains(id))
{
return;
}
}
if (_gamepadsInstanceIdsMapping.TryAdd(joystickInstanceId, id))
{
_gamepadsIds.Add(id);
lock (_lock)
{
_gamepadsIds.Add(id);
}
OnGamepadConnected?.Invoke(id);
}
@ -103,13 +131,17 @@ namespace Ryujinx.Input.SDL2
{
SDL2Driver.Instance.OnJoyStickConnected -= HandleJoyStickConnected;
SDL2Driver.Instance.OnJoystickDisconnected -= HandleJoyStickDisconnected;
// Simulate a full disconnect when disposing
foreach (string id in _gamepadsIds)
{
OnGamepadDisconnected?.Invoke(id);
}
_gamepadsIds.Clear();
lock (_lock)
{
_gamepadsIds.Clear();
}
SDL2Driver.Instance.Dispose();
}
@ -130,11 +162,6 @@ namespace Ryujinx.Input.SDL2
return null;
}
if (id != GenerateGamepadId(joystickIndex))
{
return null;
}
IntPtr gamepadHandle = SDL_GameControllerOpen(joystickIndex);
if (gamepadHandle == IntPtr.Zero)
@ -145,4 +172,4 @@ namespace Ryujinx.Input.SDL2
return new SDL2Gamepad(gamepadHandle, id);
}
}
}
}