diff --git a/src/Ryujinx.Headless.SDL2/Program.cs b/src/Ryujinx.Headless.SDL2/Program.cs index 12158176a..62800d1be 100644 --- a/src/Ryujinx.Headless.SDL2/Program.cs +++ b/src/Ryujinx.Headless.SDL2/Program.cs @@ -426,6 +426,8 @@ namespace Ryujinx.Headless.SDL2 return; } + _inputManager.AddUpdaterForConfiguration(_inputConfiguration); + // Setup logging level Logger.SetEnable(LogLevel.Debug, option.LoggingEnableDebug); Logger.SetEnable(LogLevel.Stub, !option.LoggingDisableStub); @@ -482,7 +484,7 @@ namespace Ryujinx.Headless.SDL2 } _inputManager.Dispose(); - } + } private static void SetupProgressHandler() { diff --git a/src/Ryujinx.Input/HLE/InputManager.cs b/src/Ryujinx.Input/HLE/InputManager.cs index 2825542a0..61e44e354 100644 --- a/src/Ryujinx.Input/HLE/InputManager.cs +++ b/src/Ryujinx.Input/HLE/InputManager.cs @@ -1,4 +1,9 @@ +using LibHac.Common; +using Ryujinx.Common.Configuration.Hid; +using Ryujinx.Common.Logging; using System; +using System.Collections.Generic; +using System.Linq; namespace Ryujinx.Input.HLE { @@ -41,6 +46,76 @@ namespace Ryujinx.Input.HLE } } + private void removeSDPWhenExternalPadsConnected(List> availableDevices) { + //remove all steam virtual gamepads + availableDevices.RemoveAll(a => a.Item2 == "Steam Virtual Gamepad"); + //remove Steam Deck Controller if external controllers are connected (docked game mode) + if (availableDevices.Count > 1) { + var steamDeckPad = availableDevices.FindFirst( a => a.Item2 == "Steam Deck Controller"); + if (steamDeckPad.HasValue) { + availableDevices.Remove(steamDeckPad.Value); + } + } + } + + private List> getGamepadsDescriptions() { + var result = new List> (); + foreach (string id in GamepadDriver.GamepadsIds) { + result.Add(Tuple.Create(id,GamepadDriver.GetGamepad(id).Name)); + } + return result; + } + + private void LinkDevicesToPlayers(List _inputConfig) { + var _availableDevices = getGamepadsDescriptions(); + removeSDPWhenExternalPadsConnected(_availableDevices); + var _playersWithNoDevices = new List(); + //Remove all used Devices in current Config and at the same time list player with missing Devices + foreach(PlayerIndex _playerId in Enum.GetValues(typeof(PlayerIndex))) + { + var _config = _inputConfig.Find(inputConfig => inputConfig.PlayerIndex == _playerId); + if (_config != null && _config.Backend != InputBackendType.WindowKeyboard) + { + //check device id of the player is in the existing/connected devices + var _connectedDevice = _availableDevices.FindFirst(d => d.Item1 == _config.Id); + if (_connectedDevice.HasValue) + { + _availableDevices.Remove(_connectedDevice.Value); + } + else + { + _playersWithNoDevices.Add(_playerId); + } + } + } + + var hasChanges = _playersWithNoDevices.Count() > 0 && _availableDevices.Count() > 0; + if (hasChanges) + { + Logger.Info?.Print(LogClass.Configuration, $"Controllers configuration changed. Updating players configuration..."); + for (int i = 0; i < _playersWithNoDevices.Count; i++) + { + var _playerId = _playersWithNoDevices[i]; + var _config = _inputConfig.Find(inputConfig => inputConfig.PlayerIndex == _playerId); + if (_config != null && _availableDevices.Count > 0) + { + var _device = _availableDevices.First(); + var deviceId = _device.Item1; + var deviceName = _device.Item2; + _config.Id = _device.Item1; + Logger.Info?.Print(LogClass.Configuration, $"Link Player {_playerId} to Device {deviceName}"); + _availableDevices.Remove(_device); + } + } + Logger.Info?.Print(LogClass.Configuration, $"Updated players configuration to sync with Controllers configuration changes."); + } + } + + public void AddUpdaterForConfiguration(List _inputConfig) { + GamepadDriver.OnGamepadConnected += id => LinkDevicesToPlayers(_inputConfig); + GamepadDriver.OnGamepadDisconnected += id => LinkDevicesToPlayers(_inputConfig); + } + public void Dispose() { GC.SuppressFinalize(this); diff --git a/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs b/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs index 54f278cec..b8533c5b1 100644 --- a/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs @@ -97,7 +97,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input { if (IsModified) { - + _playerIdChoose = value; return; } @@ -367,12 +367,12 @@ namespace Ryujinx.Ava.UI.ViewModels.Input private void HandleOnGamepadDisconnected(string id) { - Dispatcher.UIThread.Post(LoadDevices); + Dispatcher.UIThread.Post(RefreshDevicesAndCurrentPlayerConfiguration); } private void HandleOnGamepadConnected(string id) { - Dispatcher.UIThread.Post(LoadDevices); + Dispatcher.UIThread.Post(RefreshDevicesAndCurrentPlayerConfiguration); } private string GetCurrentGamepadId() @@ -441,6 +441,21 @@ namespace Ryujinx.Ava.UI.ViewModels.Input return str[(str.IndexOf(Hyphen) + Offset)..]; } + public void RefreshDevicesAndCurrentPlayerConfiguration() + { + LoadDevices(); + + //update Device for current user based on new configuration. + var config = ConfigurationState.Instance.Hid.InputConfig.Value.Find(inputConfig => inputConfig.PlayerIndex == PlayerId); + var device = Devices.FindFirst(d => d.Id==config.Id); + if (device.HasValue) { + Device=Devices.IndexOf(device); + } else { + //0 is the None Device + Device = 0; + } + } + public void LoadDevices() { string GetGamepadName(IGamepad gamepad, int controllerNumber) @@ -464,17 +479,19 @@ namespace Ryujinx.Ava.UI.ViewModels.Input DeviceList.Clear(); Devices.Add((DeviceType.None, Disabled, LocaleManager.Instance[LocaleKeys.ControllerSettingsDeviceDisabled])); - int controllerNumber = 0; + int controllerNumber = 1; foreach (string id in _mainWindow.InputManager.KeyboardDriver.GamepadsIds) { using IGamepad gamepad = _mainWindow.InputManager.KeyboardDriver.GetGamepad(id); if (gamepad != null) { + controllerNumber++; Devices.Add((DeviceType.Keyboard, id, $"{GetShortGamepadName(gamepad.Name)}")); } } + controllerNumber = 1; foreach (string id in _mainWindow.InputManager.GamepadDriver.GamepadsIds) { using IGamepad gamepad = _mainWindow.InputManager.GamepadDriver.GetGamepad(id); @@ -482,6 +499,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input if (gamepad != null) { string name = GetUniqueGamepadName(gamepad, ref controllerNumber); + controllerNumber++; Devices.Add((DeviceType.Controller, id, name)); } } diff --git a/src/Ryujinx/UI/Windows/MainWindow.axaml.cs b/src/Ryujinx/UI/Windows/MainWindow.axaml.cs index 09c8b9448..192d0e0e9 100644 --- a/src/Ryujinx/UI/Windows/MainWindow.axaml.cs +++ b/src/Ryujinx/UI/Windows/MainWindow.axaml.cs @@ -16,6 +16,7 @@ using Ryujinx.Ava.UI.Applet; using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.ViewModels; using Ryujinx.Common; +using Ryujinx.Common.Configuration.Hid; using Ryujinx.Common.Logging; using Ryujinx.Graphics.Gpu; using Ryujinx.HLE.FileSystem; @@ -103,6 +104,8 @@ namespace Ryujinx.Ava.UI.Windows if (Program.PreviewerDetached) { InputManager = new InputManager(new AvaloniaKeyboardDriver(this), new SDL2GamepadDriver()); + InputManager.AddUpdaterForConfiguration(ConfigurationState.Instance.Hid.InputConfig); + _ = this.GetObservable(IsActiveProperty).Subscribe(it => ViewModel.IsActive = it); this.ScalingChanged += OnScalingChanged;