Merge branch 'master' into implement-IsSixAxisSensorAtRest

This commit is contained in:
Shyanne
2026-02-03 22:58:06 -05:00
11 changed files with 249 additions and 123 deletions

View File

@@ -83,39 +83,7 @@ namespace Ryujinx.Audio.Backends.Apple
}
}
public static bool IsSupported => IsSupportedInternal();
private static bool IsSupportedInternal()
{
if (!OperatingSystem.IsMacOS()) return false;
try
{
AudioStreamBasicDescription format =
GetAudioFormat(SampleFormat.PcmInt16, Constants.TargetSampleRate, 2);
int result = AudioQueueNewOutput(
ref format,
nint.Zero,
nint.Zero,
nint.Zero,
nint.Zero,
0,
out nint testQueue);
if (result == 0)
{
AudioQueueDispose(testQueue, true);
return true;
}
return false;
}
catch (Exception e)
{
Logger.Error?.Print(LogClass.Audio, $"Failed to check if AudioToolbox is supported: {e.Message}\n{e.StackTrace}");
return false;
}
}
public static bool IsSupported => OperatingSystem.IsMacOSVersionAtLeast(10, 5);
public ManualResetEvent GetUpdateRequiredEvent()
=> _updateRequiredEvent;

View File

@@ -17,7 +17,7 @@ namespace Ryujinx.Audio.Renderer.Common
public uint MixesSize;
public uint SinksSize;
public uint PerformanceBufferSize;
public uint Unknown24;
public uint SplitterSize;
public uint RenderInfoSize;
#pragma warning disable IDE0051, CS0169 // Remove unused field

View File

@@ -433,8 +433,12 @@ namespace Ryujinx.Audio.Renderer.Server
public ResultCode UpdateSplitter(SplitterContext context)
{
long initialInputConsumed = _inputReader.Consumed;
if (context.Update(ref _inputReader))
{
_inputReader.SetConsumed(initialInputConsumed + _inputHeader.SplitterSize);
return ResultCode.Success;
}

View File

@@ -5,6 +5,7 @@ using Ryujinx.Common.Logging;
using Ryujinx.Common.Memory;
using Ryujinx.Common.Utilities;
using Ryujinx.Cpu;
using Ryujinx.HLE.Exceptions;
using Ryujinx.HLE.HOS.Ipc;
using Ryujinx.HLE.HOS.Kernel.Threading;
using Ryujinx.HLE.HOS.Services.Ldn.Types;
@@ -14,6 +15,7 @@ using Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.Types;
using Ryujinx.Horizon.Common;
using Ryujinx.Memory;
using System;
using System.ComponentModel;
using System.IO;
using System.Net;
using System.Net.NetworkInformation;
@@ -487,6 +489,23 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
return ResultCode.Success;
}
[CommandCmif(106)] // 20.0.0+
// SetProtocol
public ResultCode SetProtocol(ServiceCtx context)
{
uint protocolValue = context.RequestData.ReadUInt32();
// On NX only input value 1 or 3 is allowed, with an error being thrown otherwise.
if (protocolValue != 1 && protocolValue != 3)
{
throw new ArgumentException($"{GetType().FullName}: Protocol value is not 1 or 3!! Protocol value: {protocolValue}");
}
Logger.Stub?.PrintStub(LogClass.ServiceLdn, $"Protocol value: {protocolValue}");
return ResultCode.Success;
}
[CommandCmif(200)]
// OpenAccessPoint()
public ResultCode OpenAccessPoint(ServiceCtx context)

View File

@@ -33,7 +33,20 @@ namespace Ryujinx.Horizon.Prepo.Ipc
[CmifCommand(10100)] // 1.0.0-5.1.0
[CmifCommand(10102)] // 6.0.0-9.2.0
[CmifCommand(10104)] // 10.0.0+
public Result SaveReport([Buffer(HipcBufferFlags.In | HipcBufferFlags.Pointer)] ReadOnlySpan<byte> gameRoomBuffer, [Buffer(HipcBufferFlags.In | HipcBufferFlags.MapAlias)] ReadOnlySpan<byte> reportBuffer, [ClientProcessId] ulong pid)
public Result SaveReportOld([Buffer(HipcBufferFlags.In | HipcBufferFlags.Pointer)] ReadOnlySpan<byte> gameRoomBuffer, [Buffer(HipcBufferFlags.In | HipcBufferFlags.MapAlias)] ReadOnlySpan<byte> reportBuffer, [ClientProcessId] ulong pid)
{
if ((_permissionLevel & PrepoServicePermissionLevel.User) == 0)
{
return PrepoResult.PermissionDenied;
}
ProcessPlayReport(PlayReportKind.Normal, gameRoomBuffer, reportBuffer, pid, Uid.Null);
return Result.Success;
}
[CmifCommand(10106)] // 21.0.0+
public Result SaveReport([Buffer(HipcBufferFlags.In | HipcBufferFlags.Pointer)] ReadOnlySpan<byte> gameRoomBuffer, [Buffer(HipcBufferFlags.In | HipcBufferFlags.MapAlias)] ReadOnlySpan<byte> reportBuffer, [ClientProcessId] ulong pid, bool optInCheckEnabled)
{
if ((_permissionLevel & PrepoServicePermissionLevel.User) == 0)
{
@@ -48,7 +61,20 @@ namespace Ryujinx.Horizon.Prepo.Ipc
[CmifCommand(10101)] // 1.0.0-5.1.0
[CmifCommand(10103)] // 6.0.0-9.2.0
[CmifCommand(10105)] // 10.0.0+
public Result SaveReportWithUser(Uid userId, [Buffer(HipcBufferFlags.In | HipcBufferFlags.Pointer)] ReadOnlySpan<byte> gameRoomBuffer, [Buffer(HipcBufferFlags.In | HipcBufferFlags.MapAlias)] ReadOnlySpan<byte> reportBuffer, [ClientProcessId] ulong pid)
public Result SaveReportWithUserOld(Uid userId, [Buffer(HipcBufferFlags.In | HipcBufferFlags.Pointer)] ReadOnlySpan<byte> gameRoomBuffer, [Buffer(HipcBufferFlags.In | HipcBufferFlags.MapAlias)] ReadOnlySpan<byte> reportBuffer, [ClientProcessId] ulong pid)
{
if ((_permissionLevel & PrepoServicePermissionLevel.User) == 0)
{
return PrepoResult.PermissionDenied;
}
ProcessPlayReport(PlayReportKind.Normal, gameRoomBuffer, reportBuffer, pid, userId, true);
return Result.Success;
}
[CmifCommand(10107)] // 21.0.0+
public Result SaveReportWithUser(Uid userId, [Buffer(HipcBufferFlags.In | HipcBufferFlags.Pointer)] ReadOnlySpan<byte> gameRoomBuffer, [Buffer(HipcBufferFlags.In | HipcBufferFlags.MapAlias)] ReadOnlySpan<byte> reportBuffer, [ClientProcessId] ulong pid, bool optInCheckEnabled)
{
if ((_permissionLevel & PrepoServicePermissionLevel.User) == 0)
{

View File

@@ -8,8 +8,10 @@ namespace Ryujinx.Horizon.Sdk.Prepo
{
interface IPrepoService : IServiceObject
{
Result SaveReport(ReadOnlySpan<byte> gameRoomBuffer, ReadOnlySpan<byte> reportBuffer, ulong pid);
Result SaveReportWithUser(Uid userId, ReadOnlySpan<byte> gameRoomBuffer, ReadOnlySpan<byte> reportBuffer, ulong pid);
Result SaveReportOld(ReadOnlySpan<byte> gameRoomBuffer, ReadOnlySpan<byte> reportBuffer, ulong pid);
Result SaveReport(ReadOnlySpan<byte> gameRoomBuffer, ReadOnlySpan<byte> reportBuffer, ulong pid, bool optInCheckEnabled);
Result SaveReportWithUserOld(Uid userId, ReadOnlySpan<byte> gameRoomBuffer, ReadOnlySpan<byte> reportBuffer, ulong pid);
Result SaveReportWithUser(Uid userId, ReadOnlySpan<byte> gameRoomBuffer, ReadOnlySpan<byte> reportBuffer, ulong pid, bool optInCheckEnabled);
Result RequestImmediateTransmission();
Result GetTransmissionStatus(out int status);
Result GetSystemSessionId(out ulong systemSessionId);

View File

@@ -9,10 +9,20 @@ using static SDL.SDL3;
namespace Ryujinx.Input.SDL3
{
public unsafe class SDL3GamepadDriver : IGamepadDriver
{
private readonly Dictionary<SDL_JoystickID, string> _gamepadsInstanceIdsMapping;
private readonly Dictionary<SDL_JoystickID, string> _gamepadsIds;
/// <summary>
/// Unlinked joy-cons
/// </summary>
private readonly Dictionary<SDL_JoystickID, string> _joyConsIds;
/// <summary>
/// Linked joy-cons, remove dual joy-con from <c>_gamepadsIds</c> when a linked joy-con is removed
/// </summary>
private readonly Dictionary<SDL_JoystickID,string> _linkedJoyConsIds;
private readonly Lock _lock = new();
public ReadOnlySpan<string> GamepadsIds
@@ -21,7 +31,11 @@ namespace Ryujinx.Input.SDL3
{
lock (_lock)
{
return _gamepadsIds.Values.ToArray();
List<string> temp = [];
temp.AddRange(_gamepadsIds.Values);
temp.AddRange(_joyConsIds.Values);
temp.AddRange(_linkedJoyConsIds.Values);
return temp.ToArray();
}
}
}
@@ -35,6 +49,8 @@ namespace Ryujinx.Input.SDL3
{
_gamepadsInstanceIdsMapping = new Dictionary<SDL_JoystickID, string>();
_gamepadsIds = [];
_joyConsIds = [];
_linkedJoyConsIds = [];
SDL3Driver.Instance.Initialize();
SDL3Driver.Instance.OnJoyStickConnected += HandleJoyStickConnected;
@@ -92,7 +108,7 @@ namespace Ryujinx.Input.SDL3
int guidIndex = 0;
id = guidIndex + "-" + guidString;
while (_gamepadsIds.ContainsValue(id))
while (_gamepadsIds.ContainsValue(id) || _joyConsIds.ContainsValue(id) || _linkedJoyConsIds.ContainsValue(id))
{
id = (++guidIndex) + "-" + guidString;
}
@@ -104,16 +120,47 @@ namespace Ryujinx.Input.SDL3
private void HandleJoyStickDisconnected(SDL_JoystickID joystickInstanceId)
{
bool joyConPairDisconnected = false;
string fakeId = null;
if (!_gamepadsInstanceIdsMapping.Remove(joystickInstanceId, out string id))
return;
lock (_lock)
{
_gamepadsIds.Remove(joystickInstanceId);
if (!SDL3JoyConPair.IsCombinable(_gamepadsIds))
if (!_linkedJoyConsIds.ContainsKey(joystickInstanceId))
{
_gamepadsIds.Remove(GetInstanceIdFromId(SDL3JoyConPair.Id));
if (!_joyConsIds.Remove(joystickInstanceId))
{
_gamepadsIds.Remove(joystickInstanceId);
}
}
else
{
foreach (string matchId in _gamepadsIds.Values)
{
if (matchId.Contains(id))
{
fakeId = matchId;
break;
}
}
string leftId = fakeId!.Split('_')[0];
string rightId = fakeId!.Split('_')[1];
if (leftId == id)
{
_linkedJoyConsIds.Remove(GetInstanceIdFromId(rightId));
_joyConsIds.Add(GetInstanceIdFromId(rightId), rightId);
}
else
{
_linkedJoyConsIds.Remove(GetInstanceIdFromId(leftId));
_joyConsIds.Add(GetInstanceIdFromId(leftId), leftId);
}
_linkedJoyConsIds.Remove(joystickInstanceId);
_gamepadsIds.Remove(GetInstanceIdFromId(fakeId));
joyConPairDisconnected = true;
}
}
@@ -121,13 +168,14 @@ namespace Ryujinx.Input.SDL3
OnGamepadDisconnected?.Invoke(id);
if (joyConPairDisconnected)
{
OnGamepadDisconnected?.Invoke(SDL3JoyConPair.Id);
OnGamepadDisconnected?.Invoke(fakeId);
}
}
private void HandleJoyStickConnected(SDL_JoystickID joystickInstanceId)
{
bool joyConPairConnected = false;
string fakeId = null;
if (SDL_IsGamepad(joystickInstanceId))
{
@@ -149,27 +197,40 @@ namespace Ryujinx.Input.SDL3
{
lock (_lock)
{
_gamepadsIds.Add(joystickInstanceId, id);
if (SDL3JoyConPair.IsCombinable(_gamepadsIds))
if (!SDL3JoyCon.IsJoyCon(joystickInstanceId))
{
// TODO - It appears that you can only have one joy con pair connected at a time?
// This was also the behavior before SDL3
_gamepadsIds.Remove(GetInstanceIdFromId(SDL3JoyConPair.Id));
uint fakeInstanceID = uint.MaxValue;
while (!_gamepadsIds.TryAdd((SDL_JoystickID)fakeInstanceID, SDL3JoyConPair.Id))
_gamepadsIds.Add(joystickInstanceId, id);
}
else
{
if (SDL3JoyConPair.IsCombinable(joystickInstanceId, _joyConsIds, out SDL_JoystickID match))
{
fakeInstanceID--;
_joyConsIds.Remove(match, out string matchId);
_linkedJoyConsIds.Add(joystickInstanceId, id);
_linkedJoyConsIds.Add(match, matchId);
uint fakeInstanceId = uint.MaxValue;
fakeId = SDL3JoyCon.IsLeftJoyCon(joystickInstanceId)
? $"{id}_{matchId}"
: $"{matchId}_{id}";
while (!_gamepadsIds.TryAdd((SDL_JoystickID)fakeInstanceId, fakeId))
{
fakeInstanceId--;
}
_gamepadsInstanceIdsMapping.Add((SDL_JoystickID)fakeInstanceId, fakeId);
joyConPairConnected = true;
}
else
{
_joyConsIds.Add(joystickInstanceId, id);
}
joyConPairConnected = true;
}
}
OnGamepadConnected?.Invoke(id);
if (joyConPairConnected)
{
OnGamepadConnected?.Invoke(SDL3JoyConPair.Id);
OnGamepadConnected?.Invoke(fakeId);
}
}
}
@@ -193,10 +254,22 @@ namespace Ryujinx.Input.SDL3
{
OnGamepadDisconnected?.Invoke(gamepad.Value);
}
foreach (var gamepad in _joyConsIds)
{
OnGamepadDisconnected?.Invoke(gamepad.Value);
}
foreach (var gamepad in _linkedJoyConsIds)
{
OnGamepadDisconnected?.Invoke(gamepad.Value);
}
lock (_lock)
{
_gamepadsIds.Clear();
_joyConsIds.Clear();
_linkedJoyConsIds.Clear();
}
SDL3Driver.Instance.Dispose();
@@ -215,11 +288,27 @@ namespace Ryujinx.Input.SDL3
public IGamepad GetGamepad(string id)
{
if (id == SDL3JoyConPair.Id)
// joy-con pair ids is the combined ids of its parts which are split using a '_'
if (id.Contains('_'))
{
lock (_lock)
{
return SDL3JoyConPair.GetGamepad(_gamepadsIds);
string leftId = id.Split('_')[0];
string rightId = id.Split('_')[1];
SDL_JoystickID leftInstanceId = GetInstanceIdFromId(leftId);
SDL_JoystickID rightInstanceId = GetInstanceIdFromId(rightId);
SDL_Gamepad* leftGamepadHandle = SDL_OpenGamepad(leftInstanceId);
SDL_Gamepad* rightGamepadHandle = SDL_OpenGamepad(rightInstanceId);
if (leftGamepadHandle == null || rightGamepadHandle == null)
{
return null;
}
return new SDL3JoyConPair(new SDL3JoyCon(leftGamepadHandle, leftId),
new SDL3JoyCon(rightGamepadHandle, rightId));
}
}
@@ -232,7 +321,7 @@ namespace Ryujinx.Input.SDL3
return null;
}
if (SDL_GetGamepadName(gamepadHandle).StartsWith(SDL3JoyCon.Prefix))
if (SDL3JoyCon.IsJoyCon(instanceId))
{
return new SDL3JoyCon(gamepadHandle, id);
}
@@ -249,6 +338,22 @@ namespace Ryujinx.Input.SDL3
yield return GetGamepad(gamepad.Value);
}
}
lock (_joyConsIds)
{
foreach (var gamepad in _joyConsIds)
{
yield return GetGamepad(gamepad.Value);
}
}
lock (_linkedJoyConsIds)
{
foreach (var gamepad in _linkedJoyConsIds)
{
yield return GetGamepad(gamepad.Value);
}
}
}
}
}

View File

@@ -24,10 +24,10 @@ namespace Ryujinx.Input.SDL3
private readonly Dictionary<GamepadButtonInputId, SDL_GamepadButton> _leftButtonsDriverMapping = new()
{
{GamepadButtonInputId.LeftStick, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_LEFT_STICK},
{GamepadButtonInputId.DpadUp, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_NORTH},
{GamepadButtonInputId.DpadDown, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_SOUTH},
{GamepadButtonInputId.DpadLeft, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_EAST},
{GamepadButtonInputId.DpadRight, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_WEST},
{GamepadButtonInputId.DpadUp, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_WEST},
{GamepadButtonInputId.DpadDown, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_EAST},
{GamepadButtonInputId.DpadLeft, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_SOUTH},
{GamepadButtonInputId.DpadRight, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_NORTH},
{GamepadButtonInputId.Minus, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_START},
{GamepadButtonInputId.LeftShoulder, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_LEFT_PADDLE1},
{GamepadButtonInputId.LeftTrigger, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_LEFT_PADDLE2},
@@ -37,10 +37,10 @@ namespace Ryujinx.Input.SDL3
private readonly Dictionary<GamepadButtonInputId, SDL_GamepadButton> _rightButtonsDriverMapping = new()
{
{GamepadButtonInputId.RightStick, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_LEFT_STICK},
{GamepadButtonInputId.A, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_EAST},
{GamepadButtonInputId.B, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_NORTH},
{GamepadButtonInputId.X, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_SOUTH},
{GamepadButtonInputId.Y, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_WEST},
{GamepadButtonInputId.A, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_SOUTH},
{GamepadButtonInputId.B, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_WEST},
{GamepadButtonInputId.X, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_EAST},
{GamepadButtonInputId.Y, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_NORTH},
{GamepadButtonInputId.Plus, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_START},
{GamepadButtonInputId.RightShoulder, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_RIGHT_PADDLE1},
{GamepadButtonInputId.RightTrigger, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_RIGHT_PADDLE2},
@@ -398,5 +398,15 @@ namespace Ryujinx.Input.SDL3
return SDL_GetGamepadButton(_gamepadHandle, button);
}
public static bool IsJoyCon(SDL_JoystickID gamepadsId)
{
return SDL_GetGamepadNameForID(gamepadsId) is LeftName or RightName;
}
public static bool IsLeftJoyCon(SDL_JoystickID gamepadsId)
{
return SDL_GetGamepadNameForID(gamepadsId) is LeftName;
}
}
}

View File

@@ -15,7 +15,7 @@ namespace Ryujinx.Input.SDL3
public const string Id = "JoyConPair";
string IGamepad.Id => Id;
public string Name => "* Nintendo Switch Joy-Con (L/R)";
public string Name => "Nintendo Switch Dual Joy-Con (L/R)";
public bool IsConnected => left is { IsConnected: true } && right is { IsConnected: true };
public void Dispose()
@@ -96,44 +96,23 @@ namespace Ryujinx.Input.SDL3
right.SetTriggerThreshold(triggerThreshold);
}
public static bool IsCombinable(Dictionary<SDL_JoystickID, string> gamepadsIds)
public static bool IsCombinable(SDL_JoystickID joyCon1, Dictionary<SDL_JoystickID, string> joyConIds, out SDL_JoystickID match)
{
(int leftIndex, int rightIndex) = DetectJoyConPair(gamepadsIds);
return leftIndex >= 0 && rightIndex >= 0;
}
bool isLeft = SDL3JoyCon.IsLeftJoyCon(joyCon1);
string matchName = isLeft ? SDL3JoyCon.RightName : SDL3JoyCon.LeftName;
match = 0;
private static (int leftIndex, int rightIndex) DetectJoyConPair(Dictionary<SDL_JoystickID, string> gamepadsIds)
{
Dictionary<string, SDL_JoystickID> gamepadNames = gamepadsIds
.Where(gamepadId => gamepadId.Value != Id && SDL_GetGamepadNameForID(gamepadId.Key) is SDL3JoyCon.LeftName or SDL3JoyCon.RightName)
.Select(gamepad => (SDL_GetGamepadNameForID(gamepad.Key), gamepad.Key))
.ToDictionary();
SDL_JoystickID idx;
int leftIndex = gamepadNames.TryGetValue(SDL3JoyCon.LeftName, out idx) ? (int)idx : -1;
int rightIndex = gamepadNames.TryGetValue(SDL3JoyCon.RightName, out idx) ? (int)idx : -1;
return (leftIndex, rightIndex);
}
public unsafe static IGamepad GetGamepad(Dictionary<SDL_JoystickID, string> gamepadsIds)
{
(int leftIndex, int rightIndex) = DetectJoyConPair(gamepadsIds);
if (leftIndex <= 0 || rightIndex <= 0)
foreach (var joyConId in joyConIds.Keys)
{
return null;
if (SDL_GetGamepadNameForID(joyConId) == matchName)
{
match = joyConId;
return true;
}
}
SDL_Gamepad* leftGamepadHandle = SDL_OpenGamepad((SDL_JoystickID)leftIndex);
SDL_Gamepad* rightGamepadHandle = SDL_OpenGamepad((SDL_JoystickID)rightIndex);
if (leftGamepadHandle == null || rightGamepadHandle == null)
{
return null;
}
return new SDL3JoyConPair(new SDL3JoyCon(leftGamepadHandle, gamepadsIds[(SDL_JoystickID)leftIndex]),
new SDL3JoyCon(rightGamepadHandle, gamepadsIds[(SDL_JoystickID)rightIndex]));
return false;
}
}
}

View File

@@ -184,7 +184,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
_controller = 0;
}
if (Controllers.Count > 0 && value < Controllers.Count && _controller > -1)
if (Controllers.Count > 0 && _controller < Controllers.Count && _controller > -1)
{
ControllerType controller = Controllers[_controller].Type;
@@ -467,7 +467,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
IsModified = true;
RevertChanges();
FindPairedDeviceInConfigFile();
_isChangeTrackingActive = true; // Enable configuration change tracking
}
@@ -521,7 +521,17 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
if (Config != null && Controllers.ToList().FindIndex(x => x.Type == Config.ControllerType) != -1)
{
Controller = Controllers.ToList().FindIndex(x => x.Type == Config.ControllerType);
int controllerIndex = Controllers.ToList().FindIndex(x => x.Type == Config.ControllerType);
// Avalonia bug: setting a newly instanced ComboBox to 0
// causes the selected item to show up blank
// Workaround: set the box to 1 and then 0
if (controllerIndex == 0)
{
Controller = 1;
}
Controller = controllerIndex;
}
else
{
@@ -576,7 +586,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
DeviceList.Clear();
Devices.Add((DeviceType.None, Disabled, LocaleManager.Instance[LocaleKeys.ControllerSettingsDeviceDisabled]));
int controllerNumber = 0;
foreach (string id in _mainWindow.InputManager.KeyboardDriver.GamepadsIds)
{
using IGamepad gamepad = _mainWindow.InputManager.KeyboardDriver.GetGamepad(id);
@@ -593,6 +603,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
if (gamepad != null)
{
int controllerNumber = 0;
string name = GetUniqueGamepadName(gamepad, ref controllerNumber);
Devices.Add((DeviceType.Controller, id, name));
}
@@ -950,8 +961,10 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
LoadConfiguration(); // configuration preload is required if the paired gamepad was disconnected but was changed to another gamepad
Device = Devices.ToList().FindIndex(d => d.Id == RevertDeviceId);
LoadDevice();
_isLoaded = false;
LoadConfiguration();
LoadDevice();
_isLoaded = true;
OnPropertyChanged();
IsModified = false;