fix audiomix
This commit is contained in:
parent
e1cb957d7b
commit
82664ef69b
@ -48,8 +48,7 @@ namespace Ryujinx.Audio.Backends.SDL3
|
|||||||
|
|
||||||
private static bool IsSupportedInternal()
|
private static bool IsSupportedInternal()
|
||||||
{
|
{
|
||||||
nint device = OpenStream(SampleFormat.PcmInt16, Constants.TargetSampleRate, Constants.ChannelCountMax,
|
nint device = OpenStream(SampleFormat.PcmInt16, Constants.TargetSampleRate, Constants.ChannelCountMax, null);
|
||||||
Constants.TargetSampleCount, null);
|
|
||||||
|
|
||||||
if (device != 0)
|
if (device != 0)
|
||||||
{
|
{
|
||||||
@ -100,7 +99,7 @@ namespace Ryujinx.Audio.Backends.SDL3
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static SDL_AudioSpec GetSDL3Spec(SampleFormat requestedSampleFormat, uint requestedSampleRate,
|
private static SDL_AudioSpec GetSDL3Spec(SampleFormat requestedSampleFormat, uint requestedSampleRate,
|
||||||
uint requestedChannelCount, uint sampleCount)
|
uint requestedChannelCount)
|
||||||
{
|
{
|
||||||
return new SDL_AudioSpec
|
return new SDL_AudioSpec
|
||||||
{
|
{
|
||||||
@ -123,10 +122,9 @@ namespace Ryujinx.Audio.Backends.SDL3
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal static nint OpenStream(SampleFormat requestedSampleFormat, uint requestedSampleRate,
|
internal static nint OpenStream(SampleFormat requestedSampleFormat, uint requestedSampleRate,
|
||||||
uint requestedChannelCount, uint sampleCount, SDL_AudioStreamCallback callback)
|
uint requestedChannelCount, SDL_AudioStreamCallback callback)
|
||||||
{
|
{
|
||||||
SDL_AudioSpec desired = GetSDL3Spec(requestedSampleFormat, requestedSampleRate, requestedChannelCount,
|
SDL_AudioSpec desired = GetSDL3Spec(requestedSampleFormat, requestedSampleRate, requestedChannelCount);
|
||||||
sampleCount);
|
|
||||||
|
|
||||||
nint stream =
|
nint stream =
|
||||||
SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, ref desired, callback, nint.Zero);
|
SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, ref desired, callback, nint.Zero);
|
||||||
@ -139,16 +137,6 @@ namespace Ryujinx.Audio.Backends.SDL3
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// bool isValid = got.format == desired.format && got.freq == desired.freq && got.channels == desired.channels;
|
|
||||||
//
|
|
||||||
// if (!isValid)
|
|
||||||
// {
|
|
||||||
// Logger.Error?.Print(LogClass.Application, "SDL3 open audio device is not valid");
|
|
||||||
// SDL_DestroyAudioStream(stream);
|
|
||||||
//
|
|
||||||
// return 0;
|
|
||||||
// }
|
|
||||||
|
|
||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,7 +4,6 @@ using Ryujinx.Common.Logging;
|
|||||||
using Ryujinx.Common.Memory;
|
using Ryujinx.Common.Memory;
|
||||||
using Ryujinx.Memory;
|
using Ryujinx.Memory;
|
||||||
using System;
|
using System;
|
||||||
using System.Buffers;
|
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using static SDL3.SDL;
|
using static SDL3.SDL;
|
||||||
@ -22,7 +21,6 @@ namespace Ryujinx.Audio.Backends.SDL3
|
|||||||
private bool _hasSetupError;
|
private bool _hasSetupError;
|
||||||
private readonly SDL_AudioStreamCallback _callbackDelegate;
|
private readonly SDL_AudioStreamCallback _callbackDelegate;
|
||||||
private readonly int _bytesPerFrame;
|
private readonly int _bytesPerFrame;
|
||||||
private uint _sampleCount;
|
|
||||||
private bool _started;
|
private bool _started;
|
||||||
private float _volume;
|
private float _volume;
|
||||||
private readonly SDL_AudioFormat _nativeSampleFormat;
|
private readonly SDL_AudioFormat _nativeSampleFormat;
|
||||||
@ -38,7 +36,6 @@ namespace Ryujinx.Audio.Backends.SDL3
|
|||||||
_callbackDelegate = Update;
|
_callbackDelegate = Update;
|
||||||
_bytesPerFrame = BackendHelper.GetSampleSize(RequestedSampleFormat) * (int)RequestedChannelCount;
|
_bytesPerFrame = BackendHelper.GetSampleSize(RequestedSampleFormat) * (int)RequestedChannelCount;
|
||||||
_nativeSampleFormat = SDL3HardwareDeviceDriver.GetSDL3Format(RequestedSampleFormat);
|
_nativeSampleFormat = SDL3HardwareDeviceDriver.GetSDL3Format(RequestedSampleFormat);
|
||||||
_sampleCount = uint.MaxValue;
|
|
||||||
_started = false;
|
_started = false;
|
||||||
_volume = 1f;
|
_volume = 1f;
|
||||||
}
|
}
|
||||||
@ -47,15 +44,12 @@ namespace Ryujinx.Audio.Backends.SDL3
|
|||||||
{
|
{
|
||||||
uint bufferSampleCount = (uint)GetSampleCount(buffer);
|
uint bufferSampleCount = (uint)GetSampleCount(buffer);
|
||||||
bool needAudioSetup = (_outputStream == 0 && !_hasSetupError) ||
|
bool needAudioSetup = (_outputStream == 0 && !_hasSetupError) ||
|
||||||
(bufferSampleCount >= Constants.TargetSampleCount &&
|
(bufferSampleCount >= Constants.TargetSampleCount);
|
||||||
bufferSampleCount < _sampleCount);
|
|
||||||
|
|
||||||
if (needAudioSetup)
|
if (needAudioSetup)
|
||||||
{
|
{
|
||||||
_sampleCount = Math.Max(Constants.TargetSampleCount, bufferSampleCount);
|
|
||||||
|
|
||||||
nint newOutputStream = SDL3HardwareDeviceDriver.OpenStream(RequestedSampleFormat, RequestedSampleRate,
|
nint newOutputStream = SDL3HardwareDeviceDriver.OpenStream(RequestedSampleFormat, RequestedSampleRate,
|
||||||
RequestedChannelCount, _sampleCount, _callbackDelegate);
|
RequestedChannelCount, _callbackDelegate);
|
||||||
|
|
||||||
_hasSetupError = newOutputStream == 0;
|
_hasSetupError = newOutputStream == 0;
|
||||||
|
|
||||||
@ -68,18 +62,21 @@ namespace Ryujinx.Audio.Backends.SDL3
|
|||||||
|
|
||||||
_outputStream = newOutputStream;
|
_outputStream = newOutputStream;
|
||||||
|
|
||||||
// SDL_PauseAudioDevice(_outputStream, _started ? 0 : 1);
|
if (_started)
|
||||||
SDL_ResumeAudioStreamDevice(_outputStream);
|
{
|
||||||
|
SDL_ResumeAudioStreamDevice(_outputStream);
|
||||||
Logger.Info?.Print(LogClass.Audio,
|
}
|
||||||
$"New audio stream setup with a target sample count of {_sampleCount}");
|
else
|
||||||
|
{
|
||||||
|
SDL_PauseAudioStreamDevice(_outputStream);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private unsafe void Update(nint userdata, nint stream, int additional_amount, int total_amount)
|
private unsafe void Update(nint userdata, nint stream, int additionalAmount, int totalAmount)
|
||||||
{
|
{
|
||||||
int maxFrameCount = (int)GetSampleCount(additional_amount);
|
int maxFrameCount = (int)GetSampleCount(additionalAmount);
|
||||||
int bufferedFrames = _ringBuffer.Length / _bytesPerFrame;
|
int bufferedFrames = _ringBuffer.Length / _bytesPerFrame;
|
||||||
|
|
||||||
int frameCount = Math.Min(bufferedFrames, maxFrameCount);
|
int frameCount = Math.Min(bufferedFrames, maxFrameCount);
|
||||||
@ -90,24 +87,22 @@ namespace Ryujinx.Audio.Backends.SDL3
|
|||||||
}
|
}
|
||||||
|
|
||||||
using SpanOwner<byte> samplesOwner = SpanOwner<byte>.Rent(frameCount * _bytesPerFrame);
|
using SpanOwner<byte> samplesOwner = SpanOwner<byte>.Rent(frameCount * _bytesPerFrame);
|
||||||
using SpanOwner<byte> destinationOwner = SpanOwner<byte>.Rent(frameCount * _bytesPerFrame);
|
|
||||||
|
|
||||||
Span<byte> samples = samplesOwner.Span;
|
Span<byte> samples = samplesOwner.Span;
|
||||||
Span<byte> destinationBuffer = destinationOwner.Span;
|
int samplesLength = samples.Length;
|
||||||
|
_ringBuffer.Read(samples, 0, samplesLength);
|
||||||
|
|
||||||
_ringBuffer.Read(samples, 0, samples.Length);
|
fixed (byte* p = samples)
|
||||||
|
|
||||||
fixed (byte* pSrc = samples, pDst = destinationBuffer)
|
|
||||||
{
|
{
|
||||||
nint pStreamSrc = (nint)pSrc;
|
nint pStreamSrc = (nint)p;
|
||||||
nint pStreamDst = (nint)pDst;
|
nint pStreamDst = SDL_calloc(1,samplesLength);
|
||||||
|
|
||||||
// Apply volume to written data
|
// Apply volume to written data
|
||||||
SDL_MixAudio(pStreamDst, pStreamSrc, _nativeSampleFormat, (uint)samples.Length, _driver.Volume);
|
SDL_MixAudio(pStreamDst, pStreamSrc, _nativeSampleFormat, (uint)samplesLength, _driver.Volume);
|
||||||
SDL_PutAudioStreamData(stream, pStreamSrc, samples.Length);
|
SDL_PutAudioStreamData(stream, pStreamDst, samplesLength);
|
||||||
|
SDL_free(pStreamDst);
|
||||||
}
|
}
|
||||||
|
|
||||||
ulong sampleCount = GetSampleCount(samples.Length);
|
ulong sampleCount = GetSampleCount(samplesLength);
|
||||||
|
|
||||||
ulong availaibleSampleCount = sampleCount;
|
ulong availaibleSampleCount = sampleCount;
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ namespace Ryujinx.Input.SDL3
|
|||||||
|
|
||||||
private float _triggerThreshold;
|
private float _triggerThreshold;
|
||||||
|
|
||||||
public SDL3Gamepad(SDL_JoystickID joystickId, string driverId)
|
public SDL3Gamepad(uint joystickId, string driverId)
|
||||||
{
|
{
|
||||||
_gamepadHandle = SDL_OpenGamepad(joystickId);
|
_gamepadHandle = SDL_OpenGamepad(joystickId);
|
||||||
_buttonsUserMapping = new List<ButtonMappingEntry>(20);
|
_buttonsUserMapping = new List<ButtonMappingEntry>(20);
|
||||||
|
@ -12,7 +12,7 @@ namespace Ryujinx.Input.SDl3
|
|||||||
{
|
{
|
||||||
public class SDL3GamepadDriver : IGamepadDriver
|
public class SDL3GamepadDriver : IGamepadDriver
|
||||||
{
|
{
|
||||||
private readonly Dictionary<SDL_JoystickID, string> _gamepadsInstanceIdsMapping;
|
private readonly Dictionary<uint, string> _gamepadsInstanceIdsMapping;
|
||||||
private readonly List<string> _gamepadsIds;
|
private readonly List<string> _gamepadsIds;
|
||||||
private readonly Lock _lock = new();
|
private readonly Lock _lock = new();
|
||||||
|
|
||||||
@ -34,7 +34,7 @@ namespace Ryujinx.Input.SDl3
|
|||||||
|
|
||||||
public SDL3GamepadDriver()
|
public SDL3GamepadDriver()
|
||||||
{
|
{
|
||||||
_gamepadsInstanceIdsMapping = new Dictionary<SDL_JoystickID, string>();
|
_gamepadsInstanceIdsMapping = new Dictionary<uint, string>();
|
||||||
_gamepadsIds = new List<string>();
|
_gamepadsIds = new List<string>();
|
||||||
|
|
||||||
SDL3Driver.Instance.Initialize();
|
SDL3Driver.Instance.Initialize();
|
||||||
@ -43,7 +43,7 @@ namespace Ryujinx.Input.SDl3
|
|||||||
SDL3Driver.Instance.OnJoyBatteryUpdated += HandleJoyBatteryUpdated;
|
SDL3Driver.Instance.OnJoyBatteryUpdated += HandleJoyBatteryUpdated;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GenerateGamepadId(SDL_JoystickID joystickId)
|
private string GenerateGamepadId(uint joystickId)
|
||||||
{
|
{
|
||||||
int bufferSize = 33;
|
int bufferSize = 33;
|
||||||
Span<byte> pszGuid = stackalloc byte[bufferSize];
|
Span<byte> pszGuid = stackalloc byte[bufferSize];
|
||||||
@ -65,7 +65,7 @@ namespace Ryujinx.Input.SDl3
|
|||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
private KeyValuePair<SDL_JoystickID,string> GetGamepadInfoByGamepadId(string id)
|
private KeyValuePair<uint,string> GetGamepadInfoByGamepadId(string id)
|
||||||
{
|
{
|
||||||
lock (_lock)
|
lock (_lock)
|
||||||
{
|
{
|
||||||
@ -73,7 +73,7 @@ namespace Ryujinx.Input.SDl3
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleJoyStickDisconnected(SDL_JoystickID joystickId)
|
private void HandleJoyStickDisconnected(uint joystickId)
|
||||||
{
|
{
|
||||||
bool joyConPairDisconnected = false;
|
bool joyConPairDisconnected = false;
|
||||||
if (!_gamepadsInstanceIdsMapping.Remove(joystickId, out string id))
|
if (!_gamepadsInstanceIdsMapping.Remove(joystickId, out string id))
|
||||||
@ -96,7 +96,7 @@ namespace Ryujinx.Input.SDl3
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleJoyStickConnected(SDL_JoystickID joystickId)
|
private void HandleJoyStickConnected(uint joystickId)
|
||||||
{
|
{
|
||||||
bool joyConPairConnected = false;
|
bool joyConPairConnected = false;
|
||||||
|
|
||||||
@ -135,7 +135,7 @@ namespace Ryujinx.Input.SDl3
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleJoyBatteryUpdated(SDL_JoystickID joystickId, SDL_JoyBatteryEvent joyBatteryEvent)
|
private void HandleJoyBatteryUpdated(uint joystickId, SDL_JoyBatteryEvent joyBatteryEvent)
|
||||||
{
|
{
|
||||||
Logger.Info?.Print(LogClass.Hid,
|
Logger.Info?.Print(LogClass.Hid,
|
||||||
$"{SDL_GetGamepadNameForID(joystickId)}, Battery percent: {joyBatteryEvent.percent}");
|
$"{SDL_GetGamepadNameForID(joystickId)}, Battery percent: {joyBatteryEvent.percent}");
|
||||||
|
@ -63,17 +63,9 @@ namespace Ryujinx.Input.SDL3
|
|||||||
|
|
||||||
private nint _gamepadHandle;
|
private nint _gamepadHandle;
|
||||||
|
|
||||||
private enum JoyConType
|
private readonly SDL_GamepadType _gamepadType;
|
||||||
{
|
|
||||||
Left, Right
|
|
||||||
}
|
|
||||||
|
|
||||||
public const string LeftName = "Nintendo Switch Joy-Con (L)";
|
public SDL3JoyCon(uint joystickId, string driverId)
|
||||||
public const string RightName = "Nintendo Switch Joy-Con (R)";
|
|
||||||
|
|
||||||
private readonly JoyConType _joyConType;
|
|
||||||
|
|
||||||
public SDL3JoyCon(SDL_JoystickID joystickId, string driverId)
|
|
||||||
{
|
{
|
||||||
_gamepadHandle = SDL_OpenGamepad(joystickId);
|
_gamepadHandle = SDL_OpenGamepad(joystickId);
|
||||||
_buttonsUserMapping = new List<ButtonMappingEntry>(10);
|
_buttonsUserMapping = new List<ButtonMappingEntry>(10);
|
||||||
@ -98,24 +90,15 @@ namespace Ryujinx.Input.SDL3
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (Name)
|
_gamepadType = SDL_GetGamepadType(_gamepadHandle);
|
||||||
|
_buttonsDriverMapping = _gamepadType switch
|
||||||
{
|
{
|
||||||
case LeftName:
|
SDL_GamepadType.SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_LEFT => ToSDLButtonMapping(
|
||||||
{
|
_leftButtonsDriverMapping),
|
||||||
_buttonsDriverMapping = ToSDLButtonMapping(_leftButtonsDriverMapping);
|
SDL_GamepadType.SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT => ToSDLButtonMapping(
|
||||||
_joyConType = JoyConType.Left;
|
_rightButtonsDriverMapping),
|
||||||
break;
|
_ => throw new InvalidOperationException($"Unexpected JoyConType value: {_gamepadType}")
|
||||||
}
|
};
|
||||||
case RightName:
|
|
||||||
{
|
|
||||||
_buttonsDriverMapping = ToSDLButtonMapping(_rightButtonsDriverMapping);
|
|
||||||
_joyConType = JoyConType.Right;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
throw new InvalidOperationException(
|
|
||||||
$"Unexpected Name: {Name}. Expected '{LeftName}' or '{RightName}'.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static SDL_GamepadButton[] ToSDLButtonMapping(
|
private static SDL_GamepadButton[] ToSDLButtonMapping(
|
||||||
@ -205,11 +188,11 @@ namespace Ryujinx.Input.SDL3
|
|||||||
return Vector3.Zero;
|
return Vector3.Zero;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector3 value = _joyConType switch
|
Vector3 value = _gamepadType switch
|
||||||
{
|
{
|
||||||
JoyConType.Left => new Vector3(-values[2], values[1], values[0]),
|
SDL_GamepadType.SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_LEFT => new Vector3(-values[2], values[1], values[0]),
|
||||||
JoyConType.Right => new Vector3(values[2], values[1], -values[0]),
|
SDL_GamepadType.SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT => new Vector3(values[2], values[1], -values[0]),
|
||||||
_ => throw new ArgumentOutOfRangeException($"Unexpected JoyConType value: {_joyConType}")
|
_ => throw new ArgumentOutOfRangeException($"Unexpected JoyConType value: {_gamepadType}")
|
||||||
};
|
};
|
||||||
|
|
||||||
return inputId switch
|
return inputId switch
|
||||||
@ -237,9 +220,9 @@ namespace Ryujinx.Input.SDL3
|
|||||||
_stickUserMapping[(int)StickInputId.Right] = (StickInputId)_configuration.RightJoyconStick.Joystick;
|
_stickUserMapping[(int)StickInputId.Right] = (StickInputId)_configuration.RightJoyconStick.Joystick;
|
||||||
|
|
||||||
|
|
||||||
switch (_joyConType)
|
switch (_gamepadType)
|
||||||
{
|
{
|
||||||
case JoyConType.Left:
|
case SDL_GamepadType.SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_LEFT:
|
||||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.LeftStick,
|
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.LeftStick,
|
||||||
(GamepadButtonInputId)_configuration.LeftJoyconStick.StickButton));
|
(GamepadButtonInputId)_configuration.LeftJoyconStick.StickButton));
|
||||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadUp,
|
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadUp,
|
||||||
@ -261,7 +244,7 @@ namespace Ryujinx.Input.SDL3
|
|||||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleLeftTrigger0,
|
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleLeftTrigger0,
|
||||||
(GamepadButtonInputId)_configuration.LeftJoycon.ButtonSl));
|
(GamepadButtonInputId)_configuration.LeftJoycon.ButtonSl));
|
||||||
break;
|
break;
|
||||||
case JoyConType.Right:
|
case SDL_GamepadType.SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT:
|
||||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.RightStick,
|
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.RightStick,
|
||||||
(GamepadButtonInputId)_configuration.RightJoyconStick.StickButton));
|
(GamepadButtonInputId)_configuration.RightJoyconStick.StickButton));
|
||||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.A,
|
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.A,
|
||||||
@ -316,7 +299,6 @@ namespace Ryujinx.Input.SDL3
|
|||||||
// Do not touch state of button already pressed
|
// Do not touch state of button already pressed
|
||||||
if (!result.IsPressed(entry.To))
|
if (!result.IsPressed(entry.To))
|
||||||
{
|
{
|
||||||
|
|
||||||
result.SetPressed(entry.To, rawState.IsPressed(entry.From));
|
result.SetPressed(entry.To, rawState.IsPressed(entry.From));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -367,8 +349,8 @@ namespace Ryujinx.Input.SDL3
|
|||||||
if (inputId == StickInputId.Unbound)
|
if (inputId == StickInputId.Unbound)
|
||||||
return (0.0f, 0.0f);
|
return (0.0f, 0.0f);
|
||||||
|
|
||||||
if (inputId == StickInputId.Left && _joyConType == JoyConType.Right ||
|
if (inputId == StickInputId.Left && _gamepadType == SDL_GamepadType.SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT ||
|
||||||
inputId == StickInputId.Right && _joyConType == JoyConType.Left)
|
inputId == StickInputId.Right && _gamepadType == SDL_GamepadType.SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_LEFT)
|
||||||
{
|
{
|
||||||
return (0.0f, 0.0f);
|
return (0.0f, 0.0f);
|
||||||
}
|
}
|
||||||
@ -401,8 +383,8 @@ namespace Ryujinx.Input.SDL3
|
|||||||
|
|
||||||
return inputId switch
|
return inputId switch
|
||||||
{
|
{
|
||||||
StickInputId.Left when _joyConType == JoyConType.Left => (resultY, -resultX),
|
StickInputId.Left when _gamepadType == SDL_GamepadType.SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_LEFT => (resultY, -resultX),
|
||||||
StickInputId.Right when _joyConType == JoyConType.Right => (-resultY, resultX),
|
StickInputId.Right when _gamepadType == SDL_GamepadType.SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_LEFT => (-resultY, resultX),
|
||||||
_ => (0.0f, 0.0f)
|
_ => (0.0f, 0.0f)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -421,18 +403,14 @@ namespace Ryujinx.Input.SDL3
|
|||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (SDL_GetGamepadButton(_gamepadHandle, button))
|
|
||||||
// {
|
|
||||||
// Console.WriteLine(inputId+", "+button);
|
|
||||||
// }
|
|
||||||
return SDL_GetGamepadButton(_gamepadHandle, button);
|
return SDL_GetGamepadButton(_gamepadHandle, button);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool IsJoyCon(SDL_JoystickID joystickId)
|
public static bool IsJoyCon(uint joystickId)
|
||||||
{
|
{
|
||||||
var gamepadName = SDL_GetGamepadNameForID(joystickId);
|
var gamepadName = SDL_GetGamepadTypeForID(joystickId);
|
||||||
return gamepadName is LeftName or RightName;
|
return gamepadName is SDL_GamepadType.SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_LEFT
|
||||||
|
or SDL_GamepadType.SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,21 +11,24 @@ namespace Ryujinx.Input.SDL3
|
|||||||
class SDL3JoyConPair(SDL3JoyCon left, SDL3JoyCon right) : IGamepad
|
class SDL3JoyConPair(SDL3JoyCon left, SDL3JoyCon right) : IGamepad
|
||||||
{
|
{
|
||||||
private StandardControllerInputConfig _configuration;
|
private StandardControllerInputConfig _configuration;
|
||||||
|
|
||||||
private readonly record struct ButtonMappingEntry(GamepadButtonInputId To, GamepadButtonInputId From)
|
private readonly record struct ButtonMappingEntry(GamepadButtonInputId To, GamepadButtonInputId From)
|
||||||
{
|
{
|
||||||
public bool IsValid => To is not GamepadButtonInputId.Unbound && From is not GamepadButtonInputId.Unbound;
|
public bool IsValid => To is not GamepadButtonInputId.Unbound && From is not GamepadButtonInputId.Unbound;
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly StickInputId[] _stickUserMapping = new StickInputId[(int)StickInputId.Count]
|
private readonly StickInputId[] _stickUserMapping = new StickInputId[(int)StickInputId.Count]
|
||||||
{
|
{
|
||||||
StickInputId.Unbound, StickInputId.Left, StickInputId.Right,
|
StickInputId.Unbound, StickInputId.Left, StickInputId.Right,
|
||||||
};
|
};
|
||||||
|
|
||||||
public GamepadFeaturesFlag Features => (left?.Features ?? GamepadFeaturesFlag.None) |
|
public GamepadFeaturesFlag Features => (left?.Features ?? GamepadFeaturesFlag.None) |
|
||||||
(right?.Features ?? GamepadFeaturesFlag.None);
|
(right?.Features ?? GamepadFeaturesFlag.None);
|
||||||
|
|
||||||
public const string Id = "JoyConPair";
|
public const string Id = "JoyConPair";
|
||||||
private readonly Lock _userMappingLock = new();
|
private readonly Lock _userMappingLock = new();
|
||||||
|
|
||||||
private readonly List<ButtonMappingEntry> _buttonsUserMapping = new List<ButtonMappingEntry>(20);
|
private readonly List<ButtonMappingEntry> _buttonsUserMapping = new List<ButtonMappingEntry>(20);
|
||||||
string IGamepad.Id => Id;
|
string IGamepad.Id => Id;
|
||||||
|
|
||||||
public string Name => "* Nintendo Switch Joy-Con (L/R)";
|
public string Name => "* Nintendo Switch Joy-Con (L/R)";
|
||||||
@ -185,20 +188,21 @@ namespace Ryujinx.Input.SDL3
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool IsCombinable(Dictionary<SDL_JoystickID, string> gamepadsInstanceIdsMapping)
|
public static bool IsCombinable(Dictionary<uint, string> gamepadsInstanceIdsMapping)
|
||||||
{
|
{
|
||||||
var gamepadNames = gamepadsInstanceIdsMapping.Keys.Select(id => SDL_GetGamepadNameForID(id)).ToArray();
|
var gamepadTypes = gamepadsInstanceIdsMapping.Keys.Select(SDL_GetGamepadTypeForID).ToArray();
|
||||||
return gamepadNames.Contains(SDL3JoyCon.LeftName) && gamepadNames.Contains(SDL3JoyCon.RightName);
|
return gamepadTypes.Contains(SDL_GamepadType.SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_LEFT) &&
|
||||||
|
gamepadTypes.Contains(SDL_GamepadType.SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IGamepad GetGamepad(Dictionary<SDL_JoystickID, string> gamepadsInstanceIdsMapping)
|
public static IGamepad GetGamepad(Dictionary<uint, string> gamepadsInstanceIdsMapping)
|
||||||
{
|
{
|
||||||
var leftPair =
|
var leftPair =
|
||||||
gamepadsInstanceIdsMapping.FirstOrDefault(pair =>
|
gamepadsInstanceIdsMapping.FirstOrDefault(pair =>
|
||||||
SDL_GetGamepadNameForID(pair.Key) == SDL3JoyCon.LeftName);
|
SDL_GetGamepadTypeForID(pair.Key) == SDL_GamepadType.SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_LEFT);
|
||||||
var rightPair =
|
var rightPair =
|
||||||
gamepadsInstanceIdsMapping.FirstOrDefault(pair =>
|
gamepadsInstanceIdsMapping.FirstOrDefault(pair =>
|
||||||
SDL_GetGamepadNameForID(pair.Key) == SDL3JoyCon.RightName);
|
SDL_GetGamepadTypeForID(pair.Key) == SDL_GamepadType.SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT);
|
||||||
if (leftPair.Key == 0 || rightPair.Key == 0)
|
if (leftPair.Key == 0 || rightPair.Key == 0)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
|
@ -82,6 +82,10 @@ public static unsafe partial class SDL
|
|||||||
[LibraryImport(nativeLibName)]
|
[LibraryImport(nativeLibName)]
|
||||||
[UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
|
[UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
|
||||||
public static partial IntPtr SDL_malloc(UIntPtr size);
|
public static partial IntPtr SDL_malloc(UIntPtr size);
|
||||||
|
|
||||||
|
[LibraryImport(nativeLibName)]
|
||||||
|
[UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
|
||||||
|
public static partial IntPtr SDL_calloc(int nmemb, int size);
|
||||||
|
|
||||||
[LibraryImport(nativeLibName)]
|
[LibraryImport(nativeLibName)]
|
||||||
[UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
|
[UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
|
||||||
@ -752,6 +756,7 @@ public static unsafe partial class SDL
|
|||||||
public static partial SDLBool SDL_WriteS64BE(IntPtr dst, long value);
|
public static partial SDLBool SDL_WriteS64BE(IntPtr dst, long value);
|
||||||
|
|
||||||
// /usr/local/include/SDL3/SDL_audio.h
|
// /usr/local/include/SDL3/SDL_audio.h
|
||||||
|
public const uint SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK = 0xFFFFFFFFu;
|
||||||
|
|
||||||
public enum SDL_AudioFormat
|
public enum SDL_AudioFormat
|
||||||
{
|
{
|
||||||
@ -2615,6 +2620,7 @@ public static unsafe partial class SDL
|
|||||||
public static partial SDL_PowerState SDL_GetPowerInfo(out int seconds, out int percent);
|
public static partial SDL_PowerState SDL_GetPowerInfo(out int seconds, out int percent);
|
||||||
|
|
||||||
// /usr/local/include/SDL3/SDL_sensor.h
|
// /usr/local/include/SDL3/SDL_sensor.h
|
||||||
|
public const float SDL_STANDARD_GRAVITY = 9.80665f;
|
||||||
|
|
||||||
public enum SDL_SensorType
|
public enum SDL_SensorType
|
||||||
{
|
{
|
||||||
@ -2693,7 +2699,7 @@ public static unsafe partial class SDL
|
|||||||
public const string SDL_PROP_JOYSTICK_CAP_PLAYER_LED_BOOLEAN = "SDL.joystick.cap.player_led";
|
public const string SDL_PROP_JOYSTICK_CAP_PLAYER_LED_BOOLEAN = "SDL.joystick.cap.player_led";
|
||||||
public const string SDL_PROP_JOYSTICK_CAP_RUMBLE_BOOLEAN = "SDL.joystick.cap.rumble";
|
public const string SDL_PROP_JOYSTICK_CAP_RUMBLE_BOOLEAN = "SDL.joystick.cap.rumble";
|
||||||
public const string SDL_PROP_JOYSTICK_CAP_TRIGGER_RUMBLE_BOOLEAN = "SDL.joystick.cap.trigger_rumble";
|
public const string SDL_PROP_JOYSTICK_CAP_TRIGGER_RUMBLE_BOOLEAN = "SDL.joystick.cap.trigger_rumble";
|
||||||
|
|
||||||
public enum SDL_JoystickType
|
public enum SDL_JoystickType
|
||||||
{
|
{
|
||||||
SDL_JOYSTICK_TYPE_UNKNOWN = 0,
|
SDL_JOYSTICK_TYPE_UNKNOWN = 0,
|
||||||
@ -2749,7 +2755,7 @@ public static unsafe partial class SDL
|
|||||||
|
|
||||||
[LibraryImport(nativeLibName)]
|
[LibraryImport(nativeLibName)]
|
||||||
[UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
|
[UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
|
||||||
public static partial SDL_GUID SDL_GetJoystickGUIDForID(SDL_JoystickID instance_id);
|
public static partial SDL_GUID SDL_GetJoystickGUIDForID(uint instance_id);
|
||||||
|
|
||||||
[LibraryImport(nativeLibName)]
|
[LibraryImport(nativeLibName)]
|
||||||
[UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
|
[UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
|
||||||
@ -4620,7 +4626,7 @@ public static unsafe partial class SDL
|
|||||||
public SDL_EventType type;
|
public SDL_EventType type;
|
||||||
public uint reserved;
|
public uint reserved;
|
||||||
public ulong timestamp;
|
public ulong timestamp;
|
||||||
public SDL_JoystickID which;
|
public uint which;
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
@ -4629,7 +4635,7 @@ public static unsafe partial class SDL
|
|||||||
public SDL_EventType type;
|
public SDL_EventType type;
|
||||||
public uint reserved;
|
public uint reserved;
|
||||||
public ulong timestamp;
|
public ulong timestamp;
|
||||||
public SDL_JoystickID which;
|
public uint which;
|
||||||
public SDL_PowerState state;
|
public SDL_PowerState state;
|
||||||
public int percent;
|
public int percent;
|
||||||
}
|
}
|
||||||
@ -8048,19 +8054,4 @@ public static unsafe partial class SDL
|
|||||||
[LibraryImport(nativeLibName)]
|
[LibraryImport(nativeLibName)]
|
||||||
[UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
|
[UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
|
||||||
public static partial int SDL_EnterAppMainCallbacks(int argc, IntPtr argv, SDL_AppInit_func appinit, SDL_AppIterate_func appiter, SDL_AppEvent_func appevent, SDL_AppQuit_func appquit);
|
public static partial int SDL_EnterAppMainCallbacks(int argc, IntPtr argv, SDL_AppInit_func appinit, SDL_AppIterate_func appiter, SDL_AppEvent_func appevent, SDL_AppQuit_func appquit);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -33,9 +33,9 @@ namespace Ryujinx.SDL3.Common
|
|||||||
private uint _refereceCount;
|
private uint _refereceCount;
|
||||||
private Thread _worker;
|
private Thread _worker;
|
||||||
|
|
||||||
public event Action<SDL_JoystickID> OnJoyStickConnected;
|
public event Action<uint> OnJoyStickConnected;
|
||||||
public event Action<SDL_JoystickID> OnJoystickDisconnected;
|
public event Action<uint> OnJoystickDisconnected;
|
||||||
public event Action<SDL_JoystickID, SDL_JoyBatteryEvent> OnJoyBatteryUpdated;
|
public event Action<uint, SDL_JoyBatteryEvent> OnJoyBatteryUpdated;
|
||||||
|
|
||||||
private ConcurrentDictionary<uint, Action<SDL_Event>> _registeredWindowHandlers;
|
private ConcurrentDictionary<uint, Action<SDL_Event>> _registeredWindowHandlers;
|
||||||
|
|
||||||
@ -123,8 +123,7 @@ namespace Ryujinx.SDL3.Common
|
|||||||
|
|
||||||
private void HandleSDLEvent(ref SDL_Event evnt)
|
private void HandleSDLEvent(ref SDL_Event evnt)
|
||||||
{
|
{
|
||||||
var type = (SDL_EventType)evnt.type;
|
if (evnt.type == (uint)SDL_EventType.SDL_EVENT_GAMEPAD_ADDED)
|
||||||
if (type == SDL_EventType.SDL_EVENT_GAMEPAD_ADDED)
|
|
||||||
{
|
{
|
||||||
var instanceId = evnt.jdevice.which;
|
var instanceId = evnt.jdevice.which;
|
||||||
|
|
||||||
@ -132,7 +131,7 @@ namespace Ryujinx.SDL3.Common
|
|||||||
|
|
||||||
OnJoyStickConnected?.Invoke(instanceId);
|
OnJoyStickConnected?.Invoke(instanceId);
|
||||||
}
|
}
|
||||||
else if (type == SDL_EventType.SDL_EVENT_GAMEPAD_REMOVED)
|
else if (evnt.type == (uint)SDL_EventType.SDL_EVENT_GAMEPAD_REMOVED)
|
||||||
{
|
{
|
||||||
var instanceId = evnt.jdevice.which;
|
var instanceId = evnt.jdevice.which;
|
||||||
|
|
||||||
@ -140,13 +139,13 @@ namespace Ryujinx.SDL3.Common
|
|||||||
|
|
||||||
OnJoystickDisconnected?.Invoke(instanceId);
|
OnJoystickDisconnected?.Invoke(instanceId);
|
||||||
}
|
}
|
||||||
else if (type == SDL_EventType.SDL_EVENT_JOYSTICK_BATTERY_UPDATED)
|
else if (evnt.type == (uint)SDL_EventType.SDL_EVENT_JOYSTICK_BATTERY_UPDATED)
|
||||||
{
|
{
|
||||||
OnJoyBatteryUpdated?.Invoke(evnt.jbattery.which, evnt.jbattery);
|
OnJoyBatteryUpdated?.Invoke(evnt.jbattery.which, evnt.jbattery);
|
||||||
}
|
}
|
||||||
else if (type is >= SDL_EventType.SDL_EVENT_WINDOW_FIRST and <= SDL_EventType.SDL_EVENT_WINDOW_LAST
|
else if (evnt.type is >= (uint)SDL_EventType.SDL_EVENT_WINDOW_FIRST and <= (uint)SDL_EventType.SDL_EVENT_WINDOW_LAST
|
||||||
or SDL_EventType.SDL_EVENT_MOUSE_BUTTON_DOWN
|
or (uint)SDL_EventType.SDL_EVENT_MOUSE_BUTTON_DOWN
|
||||||
or SDL_EventType.SDL_EVENT_MOUSE_BUTTON_UP)
|
or (uint)SDL_EventType.SDL_EVENT_MOUSE_BUTTON_UP)
|
||||||
{
|
{
|
||||||
if (_registeredWindowHandlers.TryGetValue(evnt.window.windowID, out Action<SDL_Event> handler))
|
if (_registeredWindowHandlers.TryGetValue(evnt.window.windowID, out Action<SDL_Event> handler))
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user