Improved interaction with "Input" settings. #708

Open
Goodfeat wants to merge 27 commits from Goodfeat/Master_PR into master
3 changed files with 113 additions and 149 deletions
Showing only changes of commit f2329d0e8a - Show all commits

View File

@ -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 <InputConfig> newConfig = [];
newConfig.AddRange(ConfigurationState.Instance.Hid.InputConfig.Value);

View File

@ -75,7 +75,7 @@
Margin="5,0,0,0"
VerticalAlignment="Center"
ToolTip.Tip="{ext:Locale ControllerSettingsCancelCurrentChangesToolTip}"
Command="{Binding LoadSavedConfiguration}">
Command="{Binding RevertChanges}">
<ui:SymbolIcon
Symbol="Undo"
FontSize="15"
@ -206,15 +206,14 @@
<StackPanel>
<TextBlock
Margin="5,20,0,0"
Text="{ext:Locale ControllerSettingsDisableDeviceForSaving}" />
Text="{ext:Locale ControllerSettingsDisableDeviceForSaving}" />
<Button
MinWidth="0"
Width="90"
Height="27"
Margin="5,10,0,0"
VerticalAlignment="Center"
Command="{Binding DisableDeviceForSaving}">
Command="{Binding UnlinkDevice}">
<TextBlock
Text="{ext:Locale ControllerSettingsUnlink}"
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)
{
bool shouldUnbind = e.GetCurrentPoint(this).Properties.IsMiddleButtonPressed;
@ -207,47 +202,45 @@ namespace Ryujinx.Ava.UI.Views.Input
private void DeleteBind()
{
if (DataContext is not KeyboardInputViewModel viewModel)
return;
if (_currentAssigner != null)
{
Dictionary<string, Action> buttonActions = new Dictionary<string, Action>
{
{ "ButtonZl", () => viewModel.Config.ButtonZl = Key.Unbound },
{ "ButtonL", () => viewModel.Config.ButtonL = Key.Unbound },
{ "ButtonMinus", () => viewModel.Config.ButtonMinus = Key.Unbound },
{ "LeftStickButton", () => viewModel.Config.LeftStickButton = Key.Unbound },
{ "LeftStickUp", () => viewModel.Config.LeftStickUp = Key.Unbound },
{ "LeftStickDown", () => viewModel.Config.LeftStickDown = Key.Unbound },
{ "LeftStickRight", () => viewModel.Config.LeftStickRight = Key.Unbound },
{ "LeftStickLeft", () => viewModel.Config.LeftStickLeft = Key.Unbound },
{ "DpadUp", () => viewModel.Config.DpadUp = Key.Unbound },
{ "DpadDown", () => viewModel.Config.DpadDown = Key.Unbound },
{ "DpadLeft", () => viewModel.Config.DpadLeft = Key.Unbound },
{ "DpadRight", () => viewModel.Config.DpadRight = Key.Unbound },
{ "LeftButtonSr", () => viewModel.Config.LeftButtonSr = Key.Unbound },
{ "LeftButtonSl", () => viewModel.Config.LeftButtonSl = Key.Unbound },
{ "RightButtonSr", () => viewModel.Config.RightButtonSr = Key.Unbound },
{ "RightButtonSl", () => viewModel.Config.RightButtonSl = Key.Unbound },
{ "ButtonZr", () => viewModel.Config.ButtonZr = Key.Unbound },
{ "ButtonR", () => viewModel.Config.ButtonR = Key.Unbound },
{ "ButtonPlus", () => viewModel.Config.ButtonPlus = Key.Unbound },
{ "ButtonA", () => viewModel.Config.ButtonA = Key.Unbound },
{ "ButtonB", () => viewModel.Config.ButtonB = Key.Unbound },
{ "ButtonX", () => viewModel.Config.ButtonX = Key.Unbound },
{ "ButtonY", () => viewModel.Config.ButtonY = Key.Unbound },
{ "RightStickButton", () => viewModel.Config.RightStickButton = Key.Unbound },
{ "RightStickUp", () => viewModel.Config.RightStickUp = Key.Unbound },
{ "RightStickDown", () => viewModel.Config.RightStickDown = Key.Unbound },
{ "RightStickRight", () => viewModel.Config.RightStickRight = Key.Unbound },
{ "RightStickLeft", () => viewModel.Config.RightStickLeft = Key.Unbound }
{ "ButtonZl", () => ViewModel.Config.ButtonZl = Key.Unbound },
{ "ButtonL", () => ViewModel.Config.ButtonL = Key.Unbound },
{ "ButtonMinus", () => ViewModel.Config.ButtonMinus = Key.Unbound },
{ "LeftStickButton", () => ViewModel.Config.LeftStickButton = Key.Unbound },
{ "LeftStickUp", () => ViewModel.Config.LeftStickUp = Key.Unbound },
{ "LeftStickDown", () => ViewModel.Config.LeftStickDown = Key.Unbound },
{ "LeftStickRight", () => ViewModel.Config.LeftStickRight = Key.Unbound },
{ "LeftStickLeft", () => ViewModel.Config.LeftStickLeft = Key.Unbound },
{ "DpadUp", () => ViewModel.Config.DpadUp = Key.Unbound },
{ "DpadDown", () => ViewModel.Config.DpadDown = Key.Unbound },
{ "DpadLeft", () => ViewModel.Config.DpadLeft = Key.Unbound },
{ "DpadRight", () => ViewModel.Config.DpadRight = Key.Unbound },
{ "LeftButtonSr", () => ViewModel.Config.LeftButtonSr = Key.Unbound },
{ "LeftButtonSl", () => ViewModel.Config.LeftButtonSl = Key.Unbound },
{ "RightButtonSr", () => ViewModel.Config.RightButtonSr = Key.Unbound },
{ "RightButtonSl", () => ViewModel.Config.RightButtonSl = Key.Unbound },
{ "ButtonZr", () => ViewModel.Config.ButtonZr = Key.Unbound },
{ "ButtonR", () => ViewModel.Config.ButtonR = Key.Unbound },
{ "ButtonPlus", () => ViewModel.Config.ButtonPlus = Key.Unbound },
{ "ButtonA", () => ViewModel.Config.ButtonA = Key.Unbound },
{ "ButtonB", () => ViewModel.Config.ButtonB = Key.Unbound },
{ "ButtonX", () => ViewModel.Config.ButtonX = Key.Unbound },
{ "ButtonY", () => ViewModel.Config.ButtonY = Key.Unbound },
{ "RightStickButton", () => ViewModel.Config.RightStickButton = Key.Unbound },
{ "RightStickUp", () => ViewModel.Config.RightStickUp = Key.Unbound },
{ "RightStickDown", () => ViewModel.Config.RightStickDown = Key.Unbound },
{ "RightStickRight", () => ViewModel.Config.RightStickRight = Key.Unbound },
{ "RightStickLeft", () => ViewModel.Config.RightStickLeft = Key.Unbound }
};
if (buttonActions.TryGetValue(_currentAssigner.ToggledButton.Name, out Action action))
{
action();
FlagInputConfigChanged();
ViewModel.ParentModel.IsModified = true;
}
}
}