Ryujinx/Ryujinx.Input.SDL2/SDL2GamepadDriver.cs
Mary eb056218a1
audio: Implement a SDL2 backend (#2258)
* audio: Implement a SDL2 backend

This adds support to SDL2 as an audio backend.
It has the same compatibility level as OpenAL without its issues.

I also took the liberty of restructuring the SDL2 code to have one
shared project between audio and input.

The configuration version was also incremented.

* Address gdkchan's comments

* Fix update logic

* Add an heuristic to pick the correct target sample count wanted by the game

* Address gdkchan's comments

* Address Ac_k's comments

* Fix audren output

* Address gdkchan's comments
2021-05-05 23:37:09 +02:00

140 lines
3.9 KiB
C#

using Ryujinx.SDL2.Common;
using System;
using System.Collections.Generic;
using static SDL2.SDL;
namespace Ryujinx.Input.SDL2
{
public class SDL2GamepadDriver : IGamepadDriver
{
private Dictionary<int, string> _gamepadsInstanceIdsMapping;
private List<string> _gamepadsIds;
public ReadOnlySpan<string> GamepadsIds => _gamepadsIds.ToArray();
public string DriverName => "SDL2";
public event Action<string> OnGamepadConnected;
public event Action<string> OnGamepadDisconnected;
public SDL2GamepadDriver()
{
_gamepadsInstanceIdsMapping = new Dictionary<int, string>();
_gamepadsIds = new List<string>();
SDL2Driver.Instance.Initialize();
SDL2Driver.Instance.OnJoyStickConnected += HandleJoyStickConnected;
SDL2Driver.Instance.OnJoystickDisconnected += HandleJoyStickDisconnected;
// Add already connected gamepads
for (int joystickIndex = 0; joystickIndex < SDL_NumJoysticks(); joystickIndex++)
{
HandleJoyStickConnected(joystickIndex, SDL_JoystickGetDeviceInstanceID(joystickIndex));
}
}
private string GenerateGamepadId(int joystickIndex)
{
Guid guid = SDL_JoystickGetDeviceGUID(joystickIndex);
if (guid == Guid.Empty)
{
return null;
}
return joystickIndex + "-" + guid.ToString();
}
private int GetJoystickIndexByGamepadId(string id)
{
string[] data = id.Split("-");
if (data.Length != 6 || !int.TryParse(data[0], out int joystickIndex))
{
return -1;
}
return joystickIndex;
}
private void HandleJoyStickDisconnected(int joystickInstanceId)
{
if (_gamepadsInstanceIdsMapping.TryGetValue(joystickInstanceId, out string id))
{
_gamepadsInstanceIdsMapping.Remove(joystickInstanceId);
_gamepadsIds.Remove(id);
OnGamepadDisconnected?.Invoke(id);
}
}
private void HandleJoyStickConnected(int joystickDeviceId, int joystickInstanceId)
{
if (SDL_IsGameController(joystickDeviceId) == SDL_bool.SDL_TRUE)
{
string id = GenerateGamepadId(joystickDeviceId);
if (id == null)
{
return;
}
if (_gamepadsInstanceIdsMapping.TryAdd(joystickInstanceId, id))
{
_gamepadsIds.Add(id);
OnGamepadConnected?.Invoke(id);
}
}
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
SDL2Driver.Instance.OnJoyStickConnected -= HandleJoyStickConnected;
SDL2Driver.Instance.OnJoystickDisconnected -= HandleJoyStickDisconnected;
// Simulate a full disconnect when disposing
foreach (string id in _gamepadsIds)
{
OnGamepadDisconnected?.Invoke(id);
}
_gamepadsIds.Clear();
SDL2Driver.Instance.Dispose();
}
}
public void Dispose()
{
Dispose(true);
}
public IGamepad GetGamepad(string id)
{
int joystickIndex = GetJoystickIndexByGamepadId(id);
if (joystickIndex == -1)
{
return null;
}
if (id != GenerateGamepadId(joystickIndex))
{
return null;
}
IntPtr gamepadHandle = SDL_GameControllerOpen(joystickIndex);
if (gamepadHandle == IntPtr.Zero)
{
return null;
}
return new SDL2Gamepad(gamepadHandle, id);
}
}
}