Improved interaction with "Input" settings.
- paired devices have notifications that they are configured and require connection - paired devices load the configuration when connected - A notification appears when changing control configuration settings. - Now control settings will be saved only when they are changed - Added a button to roll back changes to the previously saved state - Fixed a bug: when switching the "player", if the "input device" and "controller type" settings were changed, the save dialog box did not appear. - "Motion", "Rumble" and "Led" also have events notifying about changes
This commit is contained in:
@@ -68,18 +68,21 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
|
||||
}
|
||||
|
||||
public async void ShowMotionConfig()
|
||||
{
|
||||
{
|
||||
await MotionInputView.Show(this);
|
||||
ParentModel.IsModified = true;
|
||||
}
|
||||
|
||||
public async void ShowRumbleConfig()
|
||||
{
|
||||
{
|
||||
await RumbleInputView.Show(this);
|
||||
ParentModel.IsModified = true;
|
||||
}
|
||||
|
||||
public async void ShowLedConfig()
|
||||
{
|
||||
await LedInputView.Show(this);
|
||||
ParentModel.IsModified = true;
|
||||
}
|
||||
|
||||
public void OnParentModelChanged()
|
||||
|
||||
@@ -91,7 +91,19 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
|
||||
public bool HasLed => SelectedGamepad.Features.HasFlag(GamepadFeaturesFlag.Led);
|
||||
public bool CanClearLed => SelectedGamepad.Name.ContainsIgnoreCase("DualSense");
|
||||
|
||||
public bool IsModified { get; set; }
|
||||
public bool _isChangeTrackingActive;
|
||||
|
||||
public bool _isModified;
|
||||
public bool IsModified
|
||||
{
|
||||
get => _isModified;
|
||||
set
|
||||
{
|
||||
_isModified = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public event Action NotifyChangesEvent;
|
||||
|
||||
public PlayerIndex PlayerIdChoose
|
||||
@@ -106,14 +118,14 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
|
||||
set
|
||||
{
|
||||
if (IsModified)
|
||||
{
|
||||
|
||||
{
|
||||
_playerIdChoose = value;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
IsModified = false;
|
||||
_playerId = value;
|
||||
_isChangeTrackingActive = false;
|
||||
|
||||
if (!Enum.IsDefined<PlayerIndex>(_playerId))
|
||||
{
|
||||
@@ -121,13 +133,12 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
|
||||
|
||||
}
|
||||
_isLoaded = false;
|
||||
|
||||
LoadConfiguration();
|
||||
LoadDevice();
|
||||
LoadProfiles();
|
||||
|
||||
_isLoaded = true;
|
||||
|
||||
_isChangeTrackingActive = true;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
@@ -171,11 +182,12 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
|
||||
IsLeft = false;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
LoadInputDriver();
|
||||
LoadProfiles();
|
||||
SetChangeTrackingActive();
|
||||
}
|
||||
|
||||
|
||||
OnPropertyChanged();
|
||||
NotifyChanges();
|
||||
}
|
||||
@@ -233,14 +245,28 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
|
||||
LoadConfiguration(LoadDefaultConfiguration());
|
||||
}
|
||||
}
|
||||
|
||||
FindPairedDevice();
|
||||
SetChangeTrackingActive();
|
||||
OnPropertyChanged();
|
||||
NotifyChanges();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public InputConfig Config { get; set; }
|
||||
|
||||
public bool _notificationView;
|
||||
|
||||
public bool NotificationView
|
||||
{
|
||||
get => _notificationView;
|
||||
set
|
||||
{
|
||||
_notificationView = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public InputViewModel(UserControl owner) : this()
|
||||
{
|
||||
if (Program.PreviewerDetached)
|
||||
@@ -260,6 +286,8 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
|
||||
|
||||
PlayerId = PlayerIndex.Player1;
|
||||
}
|
||||
|
||||
_isChangeTrackingActive = true;
|
||||
}
|
||||
|
||||
public InputViewModel()
|
||||
@@ -296,8 +324,54 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
|
||||
{
|
||||
ConfigViewModel = new ControllerInputViewModel(this, new GamepadInputConfig(controllerInputConfig));
|
||||
}
|
||||
|
||||
FindPairedDevice();
|
||||
}
|
||||
|
||||
private void FindPairedDevice()
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
private void SetChangeTrackingActive()
|
||||
{
|
||||
|
||||
if (_isChangeTrackingActive)
|
||||
{
|
||||
IsModified = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void DisableDeviceForSaving()
|
||||
{
|
||||
// "Disabled" mode is available after unbinding the device
|
||||
// NOTE: the IsModified flag to be able to apply the settings.
|
||||
IsModified = true;
|
||||
NotificationView = false;
|
||||
}
|
||||
|
||||
|
||||
public void LoadDevice()
|
||||
{
|
||||
if (Config == null || Config.Backend == InputBackendType.Invalid)
|
||||
@@ -363,14 +437,33 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleOnGamepadDisconnected(string id)
|
||||
private async void HandleOnGamepadDisconnected(string id)
|
||||
{
|
||||
Dispatcher.UIThread.Post(LoadDevices);
|
||||
_isChangeTrackingActive = false;
|
||||
await Dispatcher.UIThread.InvokeAsync(() =>
|
||||
{
|
||||
LoadDevices();
|
||||
FindPairedDevice();
|
||||
_isChangeTrackingActive = true;
|
||||
return System.Threading.Tasks.Task.CompletedTask;
|
||||
});
|
||||
}
|
||||
|
||||
private void HandleOnGamepadConnected(string id)
|
||||
private async void HandleOnGamepadConnected(string id)
|
||||
{
|
||||
Dispatcher.UIThread.Post(LoadDevices);
|
||||
_isChangeTrackingActive = false;
|
||||
|
||||
await Dispatcher.UIThread.InvokeAsync(() =>
|
||||
{
|
||||
LoadDevices();
|
||||
|
||||
if (Config != null)
|
||||
{
|
||||
LoadSavedConfiguration(); // Load configuration after connection if it is in the configuration file
|
||||
}
|
||||
|
||||
_isChangeTrackingActive = true;
|
||||
});
|
||||
}
|
||||
|
||||
private string GetCurrentGamepadId()
|
||||
@@ -813,8 +906,23 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
|
||||
}
|
||||
}
|
||||
|
||||
public void LoadSavedConfiguration()
|
||||
{
|
||||
LoadConfiguration();
|
||||
LoadDevice();
|
||||
LoadProfiles();
|
||||
IsModified = false;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
|
||||
public void Save()
|
||||
{
|
||||
|
||||
if (!IsModified)
|
||||
{
|
||||
return; //If the input settings were not touched, then do nothing
|
||||
}
|
||||
|
||||
IsModified = false;
|
||||
|
||||
List<InputConfig> newConfig = [];
|
||||
|
||||
@@ -63,8 +63,9 @@ namespace Ryujinx.Ava.UI.Views.Input
|
||||
};
|
||||
|
||||
if (!float.IsNaN(_changeSlider) && _changeSlider != (float)check.Value)
|
||||
{
|
||||
(DataContext as ControllerInputViewModel)!.ParentModel.IsModified = true;
|
||||
{
|
||||
FlagInputConfigChanged();
|
||||
|
||||
_changeSlider = (float)check.Value;
|
||||
}
|
||||
}
|
||||
@@ -74,7 +75,8 @@ namespace Ryujinx.Ava.UI.Views.Input
|
||||
{
|
||||
if (sender is CheckBox { IsPointerOver: true })
|
||||
{
|
||||
(DataContext as ControllerInputViewModel)!.ParentModel.IsModified = true;
|
||||
FlagInputConfigChanged();
|
||||
|
||||
_currentAssigner?.Cancel();
|
||||
_currentAssigner = null;
|
||||
}
|
||||
@@ -101,7 +103,7 @@ namespace Ryujinx.Ava.UI.Views.Input
|
||||
this.Focus(NavigationMethod.Pointer);
|
||||
|
||||
PointerPressed += MouseClick;
|
||||
|
||||
|
||||
ControllerInputViewModel viewModel = (DataContext as ControllerInputViewModel);
|
||||
|
||||
IKeyboard keyboard =
|
||||
@@ -114,7 +116,7 @@ namespace Ryujinx.Ava.UI.Views.Input
|
||||
if (e.ButtonValue.HasValue)
|
||||
{
|
||||
Button buttonValue = e.ButtonValue.Value;
|
||||
viewModel.ParentModel.IsModified = true;
|
||||
FlagInputConfigChanged();
|
||||
|
||||
switch (button.Name)
|
||||
{
|
||||
@@ -208,6 +210,11 @@ namespace Ryujinx.Ava.UI.Views.Input
|
||||
}
|
||||
}
|
||||
|
||||
private void FlagInputConfigChanged()
|
||||
{
|
||||
(DataContext as ControllerInputViewModel)!.ParentModel.IsModified = true;
|
||||
}
|
||||
|
||||
private void MouseClick(object sender, PointerPressedEventArgs e)
|
||||
{
|
||||
bool shouldUnbind = e.GetCurrentPoint(this).Properties.IsMiddleButtonPressed;
|
||||
@@ -239,7 +246,6 @@ namespace Ryujinx.Ava.UI.Views.Input
|
||||
{
|
||||
gamepad?.ClearLed();
|
||||
}
|
||||
|
||||
_currentAssigner?.Cancel();
|
||||
_currentAssigner = null;
|
||||
}
|
||||
|
||||
@@ -50,13 +50,21 @@
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock
|
||||
<StackPanel
|
||||
Orientation="Vertical"
|
||||
Margin="5,0,10,0"
|
||||
Width="90"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Text="{ext:Locale ControllerSettingsPlayer}" />
|
||||
Width="90">
|
||||
<TextBlock
|
||||
Text="{ext:Locale ControllerSettingsPlayer}" />
|
||||
<TextBlock
|
||||
Classes="pending"
|
||||
Text ="{ext:Locale ControllerSettingsModifiedNotification}"
|
||||
IsVisible="{Binding IsModified}"/>
|
||||
</StackPanel>
|
||||
<ComboBox
|
||||
Grid.Column="1"
|
||||
Name="PlayerIndexBox"
|
||||
@@ -71,6 +79,18 @@
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
<Button
|
||||
Grid.Column="2"
|
||||
MinWidth="0"
|
||||
Margin="5,0,0,0"
|
||||
VerticalAlignment="Center"
|
||||
ToolTip.Tip="{ext:Locale ControllerSettingsCancelCurrentChangesToolTip}"
|
||||
Command="{Binding LoadSavedConfiguration}">
|
||||
<ui:SymbolIcon
|
||||
Symbol="Cancel"
|
||||
FontSize="15"
|
||||
Height="20" />
|
||||
</Button>
|
||||
</Grid>
|
||||
<!-- Profile Selection -->
|
||||
<Grid
|
||||
@@ -174,7 +194,7 @@
|
||||
MinWidth="0"
|
||||
Margin="5,0,0,0"
|
||||
VerticalAlignment="Center"
|
||||
Command="{Binding LoadDevices}">
|
||||
Command="{Binding LoadDevice}">
|
||||
<ui:SymbolIcon
|
||||
Symbol="Refresh"
|
||||
FontSize="15"
|
||||
@@ -211,15 +231,37 @@
|
||||
</Grid>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
<ContentControl Content="{Binding ConfigViewModel}" IsVisible="{Binding ShowSettings}">
|
||||
<ContentControl.DataTemplates>
|
||||
<DataTemplate DataType="viewModels:ControllerInputViewModel">
|
||||
<views:ControllerInputView />
|
||||
</DataTemplate>
|
||||
<DataTemplate DataType="viewModels:KeyboardInputViewModel">
|
||||
<views:KeyboardInputView />
|
||||
</DataTemplate>
|
||||
</ContentControl.DataTemplates>
|
||||
<ContentControl IsVisible="{Binding NotificationView}">
|
||||
<ContentControl.Content>
|
||||
<StackPanel>
|
||||
<TextBlock
|
||||
Margin="5,20,0,0"
|
||||
Text="{ext:Locale ControllerSettingsDisableDeviceForSaving}" />
|
||||
|
||||
<Button
|
||||
MinWidth="0"
|
||||
Width="90"
|
||||
Height="27"
|
||||
Margin="5,10,0,0"
|
||||
VerticalAlignment="Center"
|
||||
Command="{Binding DisableDeviceForSaving}">
|
||||
<TextBlock
|
||||
Text="{ext:Locale ControllerSettingsUnlink}"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Center" />
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</ContentControl.Content>
|
||||
</ContentControl>
|
||||
<ContentControl Content="{Binding ConfigViewModel}" IsVisible="{Binding ShowSettings}">
|
||||
<ContentControl.DataTemplates>
|
||||
<DataTemplate DataType="viewModels:ControllerInputViewModel">
|
||||
<views:ControllerInputView />
|
||||
</DataTemplate>
|
||||
<DataTemplate DataType="viewModels:KeyboardInputViewModel">
|
||||
<views:KeyboardInputView />
|
||||
</DataTemplate>
|
||||
</ContentControl.DataTemplates>
|
||||
</ContentControl>
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
|
||||
@@ -62,14 +62,15 @@ namespace Ryujinx.Ava.UI.Views.Input
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
ViewModel.PlayerId = ViewModel.PlayerIdChoose;
|
||||
|
||||
ViewModel.IsModified = false;
|
||||
ViewModel.PlayerId = ViewModel.PlayerIdChoose;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
ViewModel.Dispose();
|
||||
|
||||
@@ -73,7 +73,7 @@ namespace Ryujinx.Ava.UI.Views.Input
|
||||
if (e.ButtonValue.HasValue)
|
||||
{
|
||||
Button buttonValue = e.ButtonValue.Value;
|
||||
viewModel.ParentModel.IsModified = true;
|
||||
FlagInputConfigChanged();
|
||||
|
||||
switch (button.Name)
|
||||
{
|
||||
@@ -184,6 +184,11 @@ 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;
|
||||
|
||||
Reference in New Issue
Block a user