From f2329d0e8af3b5a0b7a7e577f74bf3369d98ad2a Mon Sep 17 00:00:00 2001 From: Vova Date: Thu, 6 Mar 2025 14:52:30 +1000 Subject: [PATCH] Fixed bug with turning off active gamepad (independent profiles) When switching profiles, if the profile does not belong to the gamepad itself, the gamepad began to be displayed as turned off. Fixed a bug where the return button did not return the initially selected gamepad --- .../UI/ViewModels/Input/InputViewModel.cs | 190 ++++++++---------- src/Ryujinx/UI/Views/Input/InputView.axaml | 7 +- .../UI/Views/Input/KeyboardInputView.axaml.cs | 65 +++--- 3 files changed, 113 insertions(+), 149 deletions(-) diff --git a/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs b/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs index 0431eab42..52f538a1a 100644 --- a/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs @@ -88,7 +88,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input public bool IsKeyboard => !IsController; public bool IsRight { get; set; } public bool IsLeft { get; set; } - public int DeviceIndexBeforeChange { get; set; } + public string RevertDeviceId { get; set; } public bool HasLed => SelectedGamepad.Features.HasFlag(GamepadFeaturesFlag.Led); public bool CanClearLed => SelectedGamepad.Name.ContainsIgnoreCase("DualSense"); @@ -116,7 +116,6 @@ namespace Ryujinx.Ava.UI.ViewModels.Input { // When you select a profile, the settings from the profile will be applied. // To save the settings, you still need to click the apply button - _profileChoose = value; LoadProfile(); OnPropertyChanged(); @@ -167,7 +166,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input LoadDevice(); LoadProfiles(); - DeviceIndexBeforeChange = Device; + RevertDeviceId = Devices[Device].Id; _isLoaded = true; _isChangeTrackingActive = true; OnPropertyChanged(); @@ -179,6 +178,8 @@ namespace Ryujinx.Ava.UI.ViewModels.Input get => _controller; set { + MarkAsChanged(); + _controller = value; if (_controller == -1) @@ -216,7 +217,6 @@ namespace Ryujinx.Ava.UI.ViewModels.Input LoadInputDriver(); LoadProfiles(); - SetChangeTrackingActive(); } OnPropertyChanged(); @@ -258,10 +258,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input get => _device; set { - if (!IsModified) - { - DeviceIndexBeforeChange = _device; - } + MarkAsChanged(); _device = value < 0 ? 0 : value; @@ -282,8 +279,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input } } - FindPairedDevice(); - SetChangeTrackingActive(); + FindPairedDeviceInConfigFile(); OnPropertyChanged(); NotifyChanges(); } @@ -363,50 +359,35 @@ namespace Ryujinx.Ava.UI.ViewModels.Input ConfigViewModel = new ControllerInputViewModel(this, new GamepadInputConfig(controllerInputConfig), VisualStick); } - FindPairedDevice(); + FindPairedDeviceInConfigFile(); } - private void FindPairedDevice() + private void FindPairedDeviceInConfigFile() { - // This feature allows you to display a notification - // if a configuration is found, but the gamepad is not connected. - if (Config != null) - { - (DeviceType Type, string Id, string Name) activeDevice = Devices.FirstOrDefault(d => d.Id == Config.Id); - - if (activeDevice.Id != Config.Id) - { - // display notification when input device is turned off, and - // if device and configuration do not match (different controllers) - NotificationView = true; - } - else - { - NotificationView = false; - } - } - else - { - NotificationView = false; - } + // This function allows you to output a message about the device configuration found in the file + // NOTE: if the configuration is found, we display the message "Waiting for controller connection", + // but only if the id gamepad belongs to the selected player + NotificationView = Config != null && Devices.FirstOrDefault(d => d.Id == Config.Id).Id != Config.Id && Config.PlayerIndex == PlayerId; } - private void SetChangeTrackingActive() + + private void MarkAsChanged() { - - if (_isChangeTrackingActive) + //If tracking is active, then allow changing the modifier + if (!IsModified && _isChangeTrackingActive) { + RevertDeviceId = Devices[Device].Id; // Remember the device to undo changes IsModified = true; } } - public void DisableDeviceForSaving() + public void UnlinkDevice() { // "Disabled" mode is available after unbinding the device // NOTE: the IsModified flag to be able to apply the settings. - IsModified = true; NotificationView = false; + IsModified = true; } @@ -477,34 +458,31 @@ namespace Ryujinx.Ava.UI.ViewModels.Input private async void HandleOnGamepadDisconnected(string id) { - _isChangeTrackingActive = false; + _isChangeTrackingActive = false; // Disable configuration change tracking await Dispatcher.UIThread.InvokeAsync(() => { LoadDevices(); IsModified = true; - LoadSavedConfiguration(); - FindPairedDevice(); + RevertChanges(); + FindPairedDeviceInConfigFile(); - _isChangeTrackingActive = true; + _isChangeTrackingActive = true; // Enable configuration change tracking return System.Threading.Tasks.Task.CompletedTask; }); } private async void HandleOnGamepadConnected(string id) { - _isChangeTrackingActive = false; + _isChangeTrackingActive = false; // Disable configuration change tracking await Dispatcher.UIThread.InvokeAsync(() => { LoadDevices(); - if (Config != null) - { - // Load configuration after connection if it is in the configuration file - IsModified = true; - LoadSavedConfiguration(); - } - _isChangeTrackingActive = true; + IsModified = true; + RevertChanges(); + + _isChangeTrackingActive = true;// Enable configuration change tracking }); } @@ -809,9 +787,9 @@ namespace Ryujinx.Ava.UI.ViewModels.Input } public void LoadProfileButton() - { - IsModified = true; + { LoadProfile(); + IsModified = true; } public async void LoadProfile() @@ -865,12 +843,11 @@ namespace Ryujinx.Ava.UI.ViewModels.Input { _isLoaded = false; - config.Id = null; // ignore device IDs (there is no longer a need to store device IDs for presets due to their independence from devices) + config.Id = Config.Id; // Set current device id instead of changing device(independent profiles) LoadConfiguration(config); - // This line of code hard-links profiles to controllers, the commented line allows profiles to be applied to all controllers - // LoadDevice(); + //LoadDevice(); This line of code hard-links profiles to controllers, the commented line allows profiles to be applied to all controllers _isLoaded = true; @@ -880,56 +857,58 @@ namespace Ryujinx.Ava.UI.ViewModels.Input public async void SaveProfile() { - if (Device == 0) - { - return; - } + + if (Device == 0) + { + return; + } + + if (ConfigViewModel == null) + { + return; + } + + if (ProfileName == LocaleManager.Instance[LocaleKeys.ControllerSettingsProfileDefault]) + { + await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogProfileDefaultProfileOverwriteErrorMessage]); - if (ConfigViewModel == null) - { - return; - } + return; + } + else + { + bool validFileName = ProfileName.IndexOfAny(Path.GetInvalidFileNameChars()) == -1; - if (ProfileName == LocaleManager.Instance[LocaleKeys.ControllerSettingsProfileDefault]) - { - await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogProfileDefaultProfileOverwriteErrorMessage]); + if (validFileName) + { + string path = Path.Combine(GetProfileBasePath(), ProfileName + ".json"); - return; - } - else - { - bool validFileName = ProfileName.IndexOfAny(Path.GetInvalidFileNameChars()) == -1; + InputConfig config = null; - if (validFileName) - { - string path = Path.Combine(GetProfileBasePath(), ProfileName + ".json"); + if (IsKeyboard) + { + config = (ConfigViewModel as KeyboardInputViewModel).Config.GetConfig(); + } + else if (IsController) + { + config = (ConfigViewModel as ControllerInputViewModel).Config.GetConfig(); + } - InputConfig config = null; + config.ControllerType = Controllers[_controller].Type; - if (IsKeyboard) - { - config = (ConfigViewModel as KeyboardInputViewModel).Config.GetConfig(); - } - else if (IsController) - { - config = (ConfigViewModel as ControllerInputViewModel).Config.GetConfig(); - } + string jsonString = JsonHelper.Serialize(config, _serializerContext.InputConfig); - config.ControllerType = Controllers[_controller].Type; + await File.WriteAllTextAsync(path, jsonString); - string jsonString = JsonHelper.Serialize(config, _serializerContext.InputConfig); + LoadProfiles(); - await File.WriteAllTextAsync(path, jsonString); - - LoadProfiles(); - - ProfileChoose = ProfileName; // Show new profile - } - else - { - await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogProfileInvalidProfileNameErrorMessage]); - } - } + ProfileChoose = ProfileName; // Show new profile + } + else + { + await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogProfileInvalidProfileNameErrorMessage]); + } + } + } public async void RemoveProfile() @@ -961,22 +940,13 @@ namespace Ryujinx.Ava.UI.ViewModels.Input } } - public void LoadSavedConfiguration() + public void RevertChanges() { - // Restores settings and sets the previously selected device to the last saved state - // NOTE: The current order allows the configuration and device to be loaded correctly until the configuration is changed. - - if (IsModified) // Fixes random gamepad appearance in "disabled" option - { - Device = DeviceIndexBeforeChange; - + Device = Devices.ToList().FindIndex(d => d.Id == RevertDeviceId); LoadDevice(); LoadConfiguration(); - - IsModified = false; - OnPropertyChanged(); - } + IsModified = false; } public void Save() @@ -988,7 +958,9 @@ namespace Ryujinx.Ava.UI.ViewModels.Input } IsModified = false; - DeviceIndexBeforeChange = Device; + + RevertDeviceId = Devices[Device].Id; // Remember selected device after saving + List newConfig = []; newConfig.AddRange(ConfigurationState.Instance.Hid.InputConfig.Value); diff --git a/src/Ryujinx/UI/Views/Input/InputView.axaml b/src/Ryujinx/UI/Views/Input/InputView.axaml index a8c453912..4e695afeb 100644 --- a/src/Ryujinx/UI/Views/Input/InputView.axaml +++ b/src/Ryujinx/UI/Views/Input/InputView.axaml @@ -75,7 +75,7 @@ Margin="5,0,0,0" VerticalAlignment="Center" ToolTip.Tip="{ext:Locale ControllerSettingsCancelCurrentChangesToolTip}" - Command="{Binding LoadSavedConfiguration}"> + Command="{Binding RevertChanges}"> - + Text="{ext:Locale ControllerSettingsDisableDeviceForSaving}" />