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
This commit is contained in:
Vova 2025-03-06 14:52:30 +10:00
parent 6e824e44b8
commit f2329d0e8a
3 changed files with 113 additions and 149 deletions

View file

@ -88,7 +88,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
public bool IsKeyboard => !IsController; public bool IsKeyboard => !IsController;
public bool IsRight { get; set; } public bool IsRight { get; set; }
public bool IsLeft { 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 HasLed => SelectedGamepad.Features.HasFlag(GamepadFeaturesFlag.Led);
public bool CanClearLed => SelectedGamepad.Name.ContainsIgnoreCase("DualSense"); 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. // 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 // To save the settings, you still need to click the apply button
_profileChoose = value; _profileChoose = value;
LoadProfile(); LoadProfile();
OnPropertyChanged(); OnPropertyChanged();
@ -167,7 +166,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
LoadDevice(); LoadDevice();
LoadProfiles(); LoadProfiles();
DeviceIndexBeforeChange = Device; RevertDeviceId = Devices[Device].Id;
_isLoaded = true; _isLoaded = true;
_isChangeTrackingActive = true; _isChangeTrackingActive = true;
OnPropertyChanged(); OnPropertyChanged();
@ -179,6 +178,8 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
get => _controller; get => _controller;
set set
{ {
MarkAsChanged();
_controller = value; _controller = value;
if (_controller == -1) if (_controller == -1)
@ -216,7 +217,6 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
LoadInputDriver(); LoadInputDriver();
LoadProfiles(); LoadProfiles();
SetChangeTrackingActive();
} }
OnPropertyChanged(); OnPropertyChanged();
@ -258,10 +258,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
get => _device; get => _device;
set set
{ {
if (!IsModified) MarkAsChanged();
{
DeviceIndexBeforeChange = _device;
}
_device = value < 0 ? 0 : value; _device = value < 0 ? 0 : value;
@ -282,8 +279,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
} }
} }
FindPairedDevice(); FindPairedDeviceInConfigFile();
SetChangeTrackingActive();
OnPropertyChanged(); OnPropertyChanged();
NotifyChanges(); NotifyChanges();
} }
@ -363,50 +359,35 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
ConfigViewModel = new ControllerInputViewModel(this, new GamepadInputConfig(controllerInputConfig), VisualStick); ConfigViewModel = new ControllerInputViewModel(this, new GamepadInputConfig(controllerInputConfig), VisualStick);
} }
FindPairedDevice(); FindPairedDeviceInConfigFile();
} }
private void FindPairedDevice() private void FindPairedDeviceInConfigFile()
{ {
// This feature allows you to display a notification // This function allows you to output a message about the device configuration found in the file
// if a configuration is found, but the gamepad is not connected. // NOTE: if the configuration is found, we display the message "Waiting for controller connection",
if (Config != null) // 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;
(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;
}
} }
private void SetChangeTrackingActive()
{
if (_isChangeTrackingActive) private void MarkAsChanged()
{
//If tracking is active, then allow changing the modifier
if (!IsModified && _isChangeTrackingActive)
{ {
RevertDeviceId = Devices[Device].Id; // Remember the device to undo changes
IsModified = true; IsModified = true;
} }
} }
public void DisableDeviceForSaving() public void UnlinkDevice()
{ {
// "Disabled" mode is available after unbinding the device // "Disabled" mode is available after unbinding the device
// NOTE: the IsModified flag to be able to apply the settings. // NOTE: the IsModified flag to be able to apply the settings.
IsModified = true;
NotificationView = false; NotificationView = false;
IsModified = true;
} }
@ -477,34 +458,31 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
private async void HandleOnGamepadDisconnected(string id) private async void HandleOnGamepadDisconnected(string id)
{ {
_isChangeTrackingActive = false; _isChangeTrackingActive = false; // Disable configuration change tracking
await Dispatcher.UIThread.InvokeAsync(() => await Dispatcher.UIThread.InvokeAsync(() =>
{ {
LoadDevices(); LoadDevices();
IsModified = true; IsModified = true;
LoadSavedConfiguration(); RevertChanges();
FindPairedDevice(); FindPairedDeviceInConfigFile();
_isChangeTrackingActive = true; _isChangeTrackingActive = true; // Enable configuration change tracking
return System.Threading.Tasks.Task.CompletedTask; return System.Threading.Tasks.Task.CompletedTask;
}); });
} }
private async void HandleOnGamepadConnected(string id) private async void HandleOnGamepadConnected(string id)
{ {
_isChangeTrackingActive = false; _isChangeTrackingActive = false; // Disable configuration change tracking
await Dispatcher.UIThread.InvokeAsync(() => await Dispatcher.UIThread.InvokeAsync(() =>
{ {
LoadDevices(); LoadDevices();
if (Config != null) IsModified = true;
{ RevertChanges();
// Load configuration after connection if it is in the configuration file
IsModified = true; _isChangeTrackingActive = true;// Enable configuration change tracking
LoadSavedConfiguration();
}
_isChangeTrackingActive = true;
}); });
} }
@ -810,8 +788,8 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
public void LoadProfileButton() public void LoadProfileButton()
{ {
IsModified = true;
LoadProfile(); LoadProfile();
IsModified = true;
} }
public async void LoadProfile() public async void LoadProfile()
@ -865,12 +843,11 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
{ {
_isLoaded = false; _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); LoadConfiguration(config);
// This line of code hard-links profiles to controllers, the commented line allows profiles to be applied to all controllers //LoadDevice(); This line of code hard-links profiles to controllers, the commented line allows profiles to be applied to all controllers
// LoadDevice();
_isLoaded = true; _isLoaded = true;
@ -880,56 +857,58 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
public async void SaveProfile() public async void SaveProfile()
{ {
if (Device == 0)
{
return;
}
if (ConfigViewModel == null) if (Device == 0)
{ {
return; return;
} }
if (ProfileName == LocaleManager.Instance[LocaleKeys.ControllerSettingsProfileDefault]) if (ConfigViewModel == null)
{ {
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogProfileDefaultProfileOverwriteErrorMessage]); return;
}
return; if (ProfileName == LocaleManager.Instance[LocaleKeys.ControllerSettingsProfileDefault])
} {
else await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogProfileDefaultProfileOverwriteErrorMessage]);
{
bool validFileName = ProfileName.IndexOfAny(Path.GetInvalidFileNameChars()) == -1;
if (validFileName) return;
{ }
string path = Path.Combine(GetProfileBasePath(), ProfileName + ".json"); else
{
bool validFileName = ProfileName.IndexOfAny(Path.GetInvalidFileNameChars()) == -1;
InputConfig config = null; if (validFileName)
{
string path = Path.Combine(GetProfileBasePath(), ProfileName + ".json");
if (IsKeyboard) InputConfig config = null;
{
config = (ConfigViewModel as KeyboardInputViewModel).Config.GetConfig();
}
else if (IsController)
{
config = (ConfigViewModel as ControllerInputViewModel).Config.GetConfig();
}
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() 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 Device = Devices.ToList().FindIndex(d => d.Id == RevertDeviceId);
// 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;
LoadDevice(); LoadDevice();
LoadConfiguration(); LoadConfiguration();
IsModified = false;
OnPropertyChanged(); OnPropertyChanged();
} IsModified = false;
} }
public void Save() public void Save()
@ -988,7 +958,9 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
} }
IsModified = false; IsModified = false;
DeviceIndexBeforeChange = Device;
RevertDeviceId = Devices[Device].Id; // Remember selected device after saving
List <InputConfig> newConfig = []; List <InputConfig> newConfig = [];
newConfig.AddRange(ConfigurationState.Instance.Hid.InputConfig.Value); newConfig.AddRange(ConfigurationState.Instance.Hid.InputConfig.Value);

View file

@ -75,7 +75,7 @@
Margin="5,0,0,0" Margin="5,0,0,0"
VerticalAlignment="Center" VerticalAlignment="Center"
ToolTip.Tip="{ext:Locale ControllerSettingsCancelCurrentChangesToolTip}" ToolTip.Tip="{ext:Locale ControllerSettingsCancelCurrentChangesToolTip}"
Command="{Binding LoadSavedConfiguration}"> Command="{Binding RevertChanges}">
<ui:SymbolIcon <ui:SymbolIcon
Symbol="Undo" Symbol="Undo"
FontSize="15" FontSize="15"
@ -207,14 +207,13 @@
<TextBlock <TextBlock
Margin="5,20,0,0" Margin="5,20,0,0"
Text="{ext:Locale ControllerSettingsDisableDeviceForSaving}" /> Text="{ext:Locale ControllerSettingsDisableDeviceForSaving}" />
<Button <Button
MinWidth="0" MinWidth="0"
Width="90" Width="90"
Height="27" Height="27"
Margin="5,10,0,0" Margin="5,10,0,0"
VerticalAlignment="Center" VerticalAlignment="Center"
Command="{Binding DisableDeviceForSaving}"> Command="{Binding UnlinkDevice}">
<TextBlock <TextBlock
Text="{ext:Locale ControllerSettingsUnlink}" Text="{ext:Locale ControllerSettingsUnlink}"
VerticalAlignment="Center" VerticalAlignment="Center"

View file

@ -184,11 +184,6 @@ namespace Ryujinx.Ava.UI.Views.Input
} }
} }
private void FlagInputConfigChanged()
{
(DataContext as KeyboardInputViewModel)!.ParentModel.IsModified = true;
}
private void MouseClick(object sender, PointerPressedEventArgs e) private void MouseClick(object sender, PointerPressedEventArgs e)
{ {
bool shouldUnbind = e.GetCurrentPoint(this).Properties.IsMiddleButtonPressed; bool shouldUnbind = e.GetCurrentPoint(this).Properties.IsMiddleButtonPressed;
@ -207,47 +202,45 @@ namespace Ryujinx.Ava.UI.Views.Input
private void DeleteBind() private void DeleteBind()
{ {
if (DataContext is not KeyboardInputViewModel viewModel)
return;
if (_currentAssigner != null) if (_currentAssigner != null)
{ {
Dictionary<string, Action> buttonActions = new Dictionary<string, Action> Dictionary<string, Action> buttonActions = new Dictionary<string, Action>
{ {
{ "ButtonZl", () => viewModel.Config.ButtonZl = Key.Unbound }, { "ButtonZl", () => ViewModel.Config.ButtonZl = Key.Unbound },
{ "ButtonL", () => viewModel.Config.ButtonL = Key.Unbound }, { "ButtonL", () => ViewModel.Config.ButtonL = Key.Unbound },
{ "ButtonMinus", () => viewModel.Config.ButtonMinus = Key.Unbound }, { "ButtonMinus", () => ViewModel.Config.ButtonMinus = Key.Unbound },
{ "LeftStickButton", () => viewModel.Config.LeftStickButton = Key.Unbound }, { "LeftStickButton", () => ViewModel.Config.LeftStickButton = Key.Unbound },
{ "LeftStickUp", () => viewModel.Config.LeftStickUp = Key.Unbound }, { "LeftStickUp", () => ViewModel.Config.LeftStickUp = Key.Unbound },
{ "LeftStickDown", () => viewModel.Config.LeftStickDown = Key.Unbound }, { "LeftStickDown", () => ViewModel.Config.LeftStickDown = Key.Unbound },
{ "LeftStickRight", () => viewModel.Config.LeftStickRight = Key.Unbound }, { "LeftStickRight", () => ViewModel.Config.LeftStickRight = Key.Unbound },
{ "LeftStickLeft", () => viewModel.Config.LeftStickLeft = Key.Unbound }, { "LeftStickLeft", () => ViewModel.Config.LeftStickLeft = Key.Unbound },
{ "DpadUp", () => viewModel.Config.DpadUp = Key.Unbound }, { "DpadUp", () => ViewModel.Config.DpadUp = Key.Unbound },
{ "DpadDown", () => viewModel.Config.DpadDown = Key.Unbound }, { "DpadDown", () => ViewModel.Config.DpadDown = Key.Unbound },
{ "DpadLeft", () => viewModel.Config.DpadLeft = Key.Unbound }, { "DpadLeft", () => ViewModel.Config.DpadLeft = Key.Unbound },
{ "DpadRight", () => viewModel.Config.DpadRight = Key.Unbound }, { "DpadRight", () => ViewModel.Config.DpadRight = Key.Unbound },
{ "LeftButtonSr", () => viewModel.Config.LeftButtonSr = Key.Unbound }, { "LeftButtonSr", () => ViewModel.Config.LeftButtonSr = Key.Unbound },
{ "LeftButtonSl", () => viewModel.Config.LeftButtonSl = Key.Unbound }, { "LeftButtonSl", () => ViewModel.Config.LeftButtonSl = Key.Unbound },
{ "RightButtonSr", () => viewModel.Config.RightButtonSr = Key.Unbound }, { "RightButtonSr", () => ViewModel.Config.RightButtonSr = Key.Unbound },
{ "RightButtonSl", () => viewModel.Config.RightButtonSl = Key.Unbound }, { "RightButtonSl", () => ViewModel.Config.RightButtonSl = Key.Unbound },
{ "ButtonZr", () => viewModel.Config.ButtonZr = Key.Unbound }, { "ButtonZr", () => ViewModel.Config.ButtonZr = Key.Unbound },
{ "ButtonR", () => viewModel.Config.ButtonR = Key.Unbound }, { "ButtonR", () => ViewModel.Config.ButtonR = Key.Unbound },
{ "ButtonPlus", () => viewModel.Config.ButtonPlus = Key.Unbound }, { "ButtonPlus", () => ViewModel.Config.ButtonPlus = Key.Unbound },
{ "ButtonA", () => viewModel.Config.ButtonA = Key.Unbound }, { "ButtonA", () => ViewModel.Config.ButtonA = Key.Unbound },
{ "ButtonB", () => viewModel.Config.ButtonB = Key.Unbound }, { "ButtonB", () => ViewModel.Config.ButtonB = Key.Unbound },
{ "ButtonX", () => viewModel.Config.ButtonX = Key.Unbound }, { "ButtonX", () => ViewModel.Config.ButtonX = Key.Unbound },
{ "ButtonY", () => viewModel.Config.ButtonY = Key.Unbound }, { "ButtonY", () => ViewModel.Config.ButtonY = Key.Unbound },
{ "RightStickButton", () => viewModel.Config.RightStickButton = Key.Unbound }, { "RightStickButton", () => ViewModel.Config.RightStickButton = Key.Unbound },
{ "RightStickUp", () => viewModel.Config.RightStickUp = Key.Unbound }, { "RightStickUp", () => ViewModel.Config.RightStickUp = Key.Unbound },
{ "RightStickDown", () => viewModel.Config.RightStickDown = Key.Unbound }, { "RightStickDown", () => ViewModel.Config.RightStickDown = Key.Unbound },
{ "RightStickRight", () => viewModel.Config.RightStickRight = Key.Unbound }, { "RightStickRight", () => ViewModel.Config.RightStickRight = Key.Unbound },
{ "RightStickLeft", () => viewModel.Config.RightStickLeft = Key.Unbound } { "RightStickLeft", () => ViewModel.Config.RightStickLeft = Key.Unbound }
}; };
if (buttonActions.TryGetValue(_currentAssigner.ToggledButton.Name, out Action action)) if (buttonActions.TryGetValue(_currentAssigner.ToggledButton.Name, out Action action))
{ {
action(); action();
FlagInputConfigChanged(); ViewModel.ParentModel.IsModified = true;
} }
} }
} }