mirror of
https://git.ryujinx.app/ryubing/ryujinx.git
synced 2026-06-05 03:49:17 +00:00
Fix input settings device selection state
This commit is contained in:
28
src/Ryujinx/UI/Helpers/InputDeviceNameConverter.cs
Normal file
28
src/Ryujinx/UI/Helpers/InputDeviceNameConverter.cs
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
using Avalonia.Data.Converters;
|
||||||
|
using Avalonia.Markup.Xaml;
|
||||||
|
using Ryujinx.Ava.UI.Models;
|
||||||
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
|
||||||
|
namespace Ryujinx.Ava.UI.Helpers
|
||||||
|
{
|
||||||
|
internal class InputDeviceNameConverter : MarkupExtension, IValueConverter
|
||||||
|
{
|
||||||
|
public static readonly InputDeviceNameConverter Instance = new();
|
||||||
|
|
||||||
|
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
return value is ValueTuple<DeviceType, string, string> device ? device.Item3 : string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override object ProvideValue(IServiceProvider serviceProvider)
|
||||||
|
{
|
||||||
|
return Instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -91,7 +91,6 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
|
|||||||
public ObservableCollection<(DeviceType Type, string Id, string Name)> Devices { get; set; }
|
public ObservableCollection<(DeviceType Type, string Id, string Name)> Devices { get; set; }
|
||||||
internal ObservableCollection<ControllerModel> Controllers { get; set; }
|
internal ObservableCollection<ControllerModel> Controllers { get; set; }
|
||||||
public AvaloniaList<string> ProfilesList { get; set; }
|
public AvaloniaList<string> ProfilesList { get; set; }
|
||||||
public AvaloniaList<string> DeviceList { get; set; }
|
|
||||||
|
|
||||||
public bool UseGlobalConfig;
|
public bool UseGlobalConfig;
|
||||||
|
|
||||||
@@ -101,7 +100,6 @@ 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 string RevertDeviceId { get; set; }
|
|
||||||
public bool HasLed => (SelectedGamepad.Features & GamepadFeaturesFlag.Led) != 0;
|
public bool HasLed => (SelectedGamepad.Features & GamepadFeaturesFlag.Led) != 0;
|
||||||
public bool CanClearLed => SelectedGamepad.Name.ContainsIgnoreCase("DualSense");
|
public bool CanClearLed => SelectedGamepad.Name.ContainsIgnoreCase("DualSense");
|
||||||
|
|
||||||
@@ -165,7 +163,6 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
|
|||||||
LoadDevice();
|
LoadDevice();
|
||||||
LoadProfiles();
|
LoadProfiles();
|
||||||
|
|
||||||
RevertDeviceId = Devices[Device].Id;
|
|
||||||
_isLoaded = true;
|
_isLoaded = true;
|
||||||
_isChangeTrackingActive = true;
|
_isChangeTrackingActive = true;
|
||||||
OnPropertyChanged();
|
OnPropertyChanged();
|
||||||
@@ -177,15 +174,22 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
|
|||||||
get => _controller;
|
get => _controller;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
MarkAsChanged();
|
int controllerIndex = value < 0 ? 0 : value;
|
||||||
|
|
||||||
_controller = value;
|
if (controllerIndex == _controller)
|
||||||
|
|
||||||
if (_controller == -1)
|
|
||||||
{
|
{
|
||||||
_controller = 0;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MarkAsChanged();
|
||||||
|
ApplyControllerSelection(controllerIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ApplyControllerSelection(int controllerIndex)
|
||||||
|
{
|
||||||
|
_controller = controllerIndex;
|
||||||
|
|
||||||
if (Controllers.Count > 0 && _controller < Controllers.Count && _controller > -1)
|
if (Controllers.Count > 0 && _controller < Controllers.Count && _controller > -1)
|
||||||
{
|
{
|
||||||
ControllerType controller = Controllers[_controller].Type;
|
ControllerType controller = Controllers[_controller].Type;
|
||||||
@@ -218,10 +222,9 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
|
|||||||
LoadProfiles();
|
LoadProfiles();
|
||||||
}
|
}
|
||||||
|
|
||||||
OnPropertyChanged();
|
OnPropertyChanged(nameof(Controller));
|
||||||
NotifyChanges();
|
NotifyChanges();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public string ControllerImage
|
public string ControllerImage
|
||||||
{
|
{
|
||||||
@@ -257,15 +260,14 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
|
|||||||
get => _device;
|
get => _device;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
MarkAsChanged();
|
if (value < 0 || value >= Devices.Count)
|
||||||
|
|
||||||
_device = value < 0 ? 0 : value;
|
|
||||||
|
|
||||||
if (_device >= Devices.Count)
|
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MarkAsChanged();
|
||||||
|
_device = value;
|
||||||
|
|
||||||
DeviceType selected = Devices[_device].Type;
|
DeviceType selected = Devices[_device].Type;
|
||||||
|
|
||||||
if (selected != DeviceType.None)
|
if (selected != DeviceType.None)
|
||||||
@@ -280,10 +282,39 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
|
|||||||
|
|
||||||
FindPairedDeviceInConfigFile();
|
FindPairedDeviceInConfigFile();
|
||||||
OnPropertyChanged();
|
OnPropertyChanged();
|
||||||
|
OnPropertyChanged(nameof(SelectedDeviceItem));
|
||||||
NotifyChanges();
|
NotifyChanges();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public object SelectedDeviceItem
|
||||||
|
{
|
||||||
|
get => _device >= 0 && _device < Devices.Count ? Devices[_device] : null;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value is not ValueTuple<DeviceType, string, string> selectedDevice)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int deviceIndex = Devices.ToList().FindIndex(device =>
|
||||||
|
device.Type == selectedDevice.Item1 &&
|
||||||
|
device.Id == selectedDevice.Item2);
|
||||||
|
|
||||||
|
if (deviceIndex < 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (deviceIndex == _device)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Device = deviceIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public InputConfig Config { get; set; }
|
public InputConfig Config { get; set; }
|
||||||
|
|
||||||
public InputViewModel(UserControl owner, bool useGlobal = false) : this()
|
public InputViewModel(UserControl owner, bool useGlobal = false) : this()
|
||||||
@@ -328,7 +359,6 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
|
|||||||
Controllers = [];
|
Controllers = [];
|
||||||
Devices = [];
|
Devices = [];
|
||||||
ProfilesList = [];
|
ProfilesList = [];
|
||||||
DeviceList = [];
|
|
||||||
VisualStick = new StickVisualizer(this);
|
VisualStick = new StickVisualizer(this);
|
||||||
|
|
||||||
ControllerImage = ProControllerResource;
|
ControllerImage = ProControllerResource;
|
||||||
@@ -409,7 +439,6 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
|
|||||||
//If tracking is active, then allow changing the modifier
|
//If tracking is active, then allow changing the modifier
|
||||||
if (!IsModified && _isChangeTrackingActive)
|
if (!IsModified && _isChangeTrackingActive)
|
||||||
{
|
{
|
||||||
RevertDeviceId = Devices[Device].Id; // Remember the device to undo changes
|
|
||||||
IsModified = true;
|
IsModified = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -424,12 +453,14 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
|
|||||||
|
|
||||||
public void LoadDevice()
|
public void LoadDevice()
|
||||||
{
|
{
|
||||||
|
int deviceIndex = 0;
|
||||||
|
|
||||||
if (Config == null || Config.Backend == InputBackendType.Invalid)
|
if (Config == null || Config.Backend == InputBackendType.Invalid)
|
||||||
{
|
{
|
||||||
Device = 0;
|
ApplyLoadedDevice(deviceIndex);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
DeviceType type = DeviceType.None;
|
DeviceType type = DeviceType.None;
|
||||||
|
|
||||||
if (Config is StandardKeyboardInputConfig)
|
if (Config is StandardKeyboardInputConfig)
|
||||||
@@ -443,15 +474,33 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
|
|||||||
}
|
}
|
||||||
|
|
||||||
(DeviceType Type, string Id, string Name) item = Devices.FirstOrDefault(x => x.Type == type && x.Id == Config.Id);
|
(DeviceType Type, string Id, string Name) item = Devices.FirstOrDefault(x => x.Type == type && x.Id == Config.Id);
|
||||||
|
|
||||||
if (item != default)
|
if (item != default)
|
||||||
{
|
{
|
||||||
Device = Devices.ToList().FindIndex(x => x.Id == item.Id);
|
deviceIndex = Devices.ToList().FindIndex(x => x.Id == item.Id);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
ApplyLoadedDevice(deviceIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ApplyLoadedDevice(int deviceIndex)
|
||||||
{
|
{
|
||||||
Device = 0;
|
_device = deviceIndex is >= 0 and < int.MaxValue ? deviceIndex : 0;
|
||||||
|
|
||||||
|
if (_device >= Devices.Count)
|
||||||
|
{
|
||||||
|
_device = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_device > 0 && Devices[_device].Type != DeviceType.None)
|
||||||
|
{
|
||||||
|
LoadControllers();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FindPairedDeviceInConfigFile();
|
||||||
|
OnPropertyChanged(nameof(Device));
|
||||||
|
OnPropertyChanged(nameof(SelectedDeviceItem));
|
||||||
|
NotifyChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LoadInputDriver()
|
private void LoadInputDriver()
|
||||||
@@ -569,7 +618,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
|
|||||||
{
|
{
|
||||||
Controllers.Add(new(ControllerType.Handheld, LocaleManager.Instance[LocaleKeys.ControllerSettingsControllerTypeHandheld]));
|
Controllers.Add(new(ControllerType.Handheld, LocaleManager.Instance[LocaleKeys.ControllerSettingsControllerTypeHandheld]));
|
||||||
|
|
||||||
Controller = 0;
|
ApplyControllerSelection(0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -587,14 +636,14 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
|
|||||||
// Workaround: set the box to 1 and then 0
|
// Workaround: set the box to 1 and then 0
|
||||||
if (controllerIndex == 0)
|
if (controllerIndex == 0)
|
||||||
{
|
{
|
||||||
Controller = 1;
|
ApplyControllerSelection(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
Controller = controllerIndex;
|
ApplyControllerSelection(controllerIndex);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Controller = 0;
|
ApplyControllerSelection(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -622,6 +671,14 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
|
|||||||
|
|
||||||
public void LoadDevices()
|
public void LoadDevices()
|
||||||
{
|
{
|
||||||
|
int selectedDeviceIndex = 0;
|
||||||
|
(DeviceType Type, string Id, string Name) selectedDevice = default;
|
||||||
|
|
||||||
|
if (_device >= 0 && _device < Devices.Count)
|
||||||
|
{
|
||||||
|
selectedDevice = Devices[_device];
|
||||||
|
}
|
||||||
|
|
||||||
string GetGamepadName(IGamepad gamepad, int controllerNumber)
|
string GetGamepadName(IGamepad gamepad, int controllerNumber)
|
||||||
{
|
{
|
||||||
return $"{GetShortGamepadName(gamepad.Name)} ({controllerNumber})";
|
return $"{GetShortGamepadName(gamepad.Name)} ({controllerNumber})";
|
||||||
@@ -642,7 +699,6 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
|
|||||||
lock (Devices)
|
lock (Devices)
|
||||||
{
|
{
|
||||||
Devices.Clear();
|
Devices.Clear();
|
||||||
DeviceList.Clear();
|
|
||||||
Devices.Add((DeviceType.None, Disabled, LocaleManager.Instance[LocaleKeys.ControllerSettingsDeviceDisabled]));
|
Devices.Add((DeviceType.None, Disabled, LocaleManager.Instance[LocaleKeys.ControllerSettingsDeviceDisabled]));
|
||||||
|
|
||||||
|
|
||||||
@@ -668,9 +724,20 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DeviceList.AddRange(Devices.Select(x => x.Name));
|
if (selectedDevice != default)
|
||||||
Device = Math.Min(Device, DeviceList.Count - 1);
|
{
|
||||||
|
selectedDeviceIndex = Devices.ToList().FindIndex(device =>
|
||||||
|
device.Type == selectedDevice.Type &&
|
||||||
|
device.Id == selectedDevice.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (selectedDeviceIndex < 0)
|
||||||
|
{
|
||||||
|
selectedDeviceIndex = Math.Clamp(_device, 0, Devices.Count - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ApplyLoadedDevice(selectedDeviceIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetProfileBasePath()
|
private string GetProfileBasePath()
|
||||||
@@ -1024,9 +1091,6 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
|
|||||||
|
|
||||||
public void RevertChanges()
|
public void RevertChanges()
|
||||||
{
|
{
|
||||||
LoadConfiguration(); // configuration preload is required if the paired gamepad was disconnected but was changed to another gamepad
|
|
||||||
Device = Devices.ToList().FindIndex(d => d.Id == RevertDeviceId);
|
|
||||||
|
|
||||||
_isLoaded = false;
|
_isLoaded = false;
|
||||||
LoadConfiguration();
|
LoadConfiguration();
|
||||||
LoadDevice();
|
LoadDevice();
|
||||||
@@ -1046,8 +1110,6 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
|
|||||||
|
|
||||||
IsModified = false;
|
IsModified = false;
|
||||||
|
|
||||||
RevertDeviceId = Devices[Device].Id; // Remember selected device after saving
|
|
||||||
|
|
||||||
List<InputConfig> newConfig = [];
|
List<InputConfig> newConfig = [];
|
||||||
|
|
||||||
if (UseGlobalConfig && Program.UseExtraConfig)
|
if (UseGlobalConfig && Program.UseExtraConfig)
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||||
xmlns:ext="clr-namespace:Ryujinx.Ava.Common.Markup"
|
xmlns:ext="clr-namespace:Ryujinx.Ava.Common.Markup"
|
||||||
|
xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:models="clr-namespace:Ryujinx.Ava.UI.Models"
|
xmlns:models="clr-namespace:Ryujinx.Ava.UI.Models"
|
||||||
@@ -161,8 +162,14 @@
|
|||||||
Name="DeviceBox"
|
Name="DeviceBox"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
ItemsSource="{Binding DeviceList}"
|
ItemsSource="{Binding Devices}"
|
||||||
SelectedIndex="{Binding Device}" />
|
SelectedItem="{Binding SelectedDeviceItem, Mode=TwoWay}">
|
||||||
|
<ComboBox.ItemTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<TextBlock Text="{Binding ., Converter={x:Static helpers:InputDeviceNameConverter.Instance}}" />
|
||||||
|
</DataTemplate>
|
||||||
|
</ComboBox.ItemTemplate>
|
||||||
|
</ComboBox>
|
||||||
<Button
|
<Button
|
||||||
Grid.Column="2"
|
Grid.Column="2"
|
||||||
MinWidth="0"
|
MinWidth="0"
|
||||||
|
|||||||
Reference in New Issue
Block a user