Fix settings keyboard input focus loss

This commit is contained in:
Babib3l
2026-03-21 22:45:19 +01:00
parent 9a5e4c06af
commit 7becde9d8e
3 changed files with 79 additions and 11 deletions

View File

@@ -15,6 +15,7 @@ namespace Ryujinx.Ava.Input
private readonly Control _control; private readonly Control _control;
private readonly Dictionary<Key, int> _semanticPressedKeys; private readonly Dictionary<Key, int> _semanticPressedKeys;
private readonly Dictionary<ConfigPhysicalKey, int> _physicalPressedKeys; private readonly Dictionary<ConfigPhysicalKey, int> _physicalPressedKeys;
private readonly Dictionary<Key, ConfigPhysicalKey> _observedPhysicalKeysBySemanticKey;
private readonly KeyboardInputMode _defaultMode; private readonly KeyboardInputMode _defaultMode;
public event EventHandler<KeyEventArgs> KeyPressed; public event EventHandler<KeyEventArgs> KeyPressed;
@@ -29,6 +30,7 @@ namespace Ryujinx.Ava.Input
_control = control; _control = control;
_semanticPressedKeys = []; _semanticPressedKeys = [];
_physicalPressedKeys = []; _physicalPressedKeys = [];
_observedPhysicalKeysBySemanticKey = [];
_defaultMode = defaultMode; _defaultMode = defaultMode;
_control.KeyDown += OnKeyPress; _control.KeyDown += OnKeyPress;
@@ -192,17 +194,37 @@ namespace Ryujinx.Ava.Input
private void UpdateKeyStates(KeyEventArgs args, bool isPressed) private void UpdateKeyStates(KeyEventArgs args, bool isPressed)
{ {
UpdateKeyState(_semanticPressedKeys, AvaloniaKeyboardMappingHelper.ToInputKey(args.PhysicalKey, args.Key), isPressed); Key semanticKey = AvaloniaKeyboardMappingHelper.ToInputKey(args.Key);
UpdateKeyState(_physicalPressedKeys, GetPhysicalInputKey(args), isPressed); Key resolvedSemanticKey = AvaloniaKeyboardMappingHelper.ToInputKey(args.PhysicalKey, args.Key);
ConfigPhysicalKey physicalKey = GetPhysicalInputKey(args, semanticKey);
UpdateKeyState(_semanticPressedKeys, resolvedSemanticKey, isPressed);
UpdateKeyState(_physicalPressedKeys, physicalKey, isPressed);
if (isPressed &&
semanticKey is not Key.Unknown and not Key.Unbound &&
physicalKey is not ConfigPhysicalKey.Unknown and not ConfigPhysicalKey.Unbound)
{
_observedPhysicalKeysBySemanticKey[semanticKey] = physicalKey;
}
} }
private static ConfigPhysicalKey GetPhysicalInputKey(KeyEventArgs args) private ConfigPhysicalKey GetPhysicalInputKey(KeyEventArgs args, Key semanticKey)
{ {
Key key = AvaloniaKeyboardMappingHelper.ToInputKey(args.PhysicalKey); Key key = AvaloniaKeyboardMappingHelper.ToInputKey(args.PhysicalKey);
return key is >= Key.Unknown and < Key.Count if (key is >= Key.Unknown and < Key.Count)
? (ConfigPhysicalKey)(int)key {
: ConfigPhysicalKey.Unknown; return (ConfigPhysicalKey)(int)key;
}
if (semanticKey is not Key.Unknown and not Key.Unbound &&
_observedPhysicalKeysBySemanticKey.TryGetValue(semanticKey, out ConfigPhysicalKey observedPhysicalKey))
{
return observedPhysicalKey;
}
return ConfigPhysicalKey.Unknown;
} }
public void Dispose() public void Dispose()

View File

@@ -43,6 +43,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
private const string KeyboardString = "keyboard"; private const string KeyboardString = "keyboard";
private const string ControllerString = "controller"; private const string ControllerString = "controller";
private readonly MainWindow _mainWindow; private readonly MainWindow _mainWindow;
private Control _keyboardDriverControl;
private PlayerIndex _playerId; private PlayerIndex _playerId;
private PlayerIndex _playerIdChoose; private PlayerIndex _playerIdChoose;
@@ -66,7 +67,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
private static readonly InputConfigJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions()); private static readonly InputConfigJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions());
public IGamepadDriver AvaloniaKeyboardDriver { get; } public IGamepadDriver AvaloniaKeyboardDriver { get; private set; }
public IGamepad SelectedGamepad public IGamepad SelectedGamepad
{ {
@@ -291,9 +292,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
{ {
_mainWindow = RyujinxApp.MainWindow; _mainWindow = RyujinxApp.MainWindow;
AvaloniaKeyboardDriver keyboardDriver = new(owner, KeyboardInputMode.Physical); ReplaceKeyboardDriver(owner);
keyboardDriver.KeyPressed += PhysicalKeyLabelHelper.ObserveKeyPress;
AvaloniaKeyboardDriver = keyboardDriver;
PhysicalKeyLabelHelper.LabelsChanged += OnPhysicalKeyLabelsChanged; PhysicalKeyLabelHelper.LabelsChanged += OnPhysicalKeyLabelsChanged;
_mainWindow.InputManager.GamepadDriver.OnGamepadConnected += HandleOnGamepadConnected; _mainWindow.InputManager.GamepadDriver.OnGamepadConnected += HandleOnGamepadConnected;
@@ -313,6 +312,16 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
_isChangeTrackingActive = true; _isChangeTrackingActive = true;
} }
public void RetargetKeyboardDriver(Control owner)
{
if (!Program.PreviewerDetached)
{
return;
}
ReplaceKeyboardDriver(owner);
}
public InputViewModel() public InputViewModel()
{ {
PlayerIndexes = []; PlayerIndexes = [];
@@ -1096,6 +1105,34 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
} }
} }
private void ReplaceKeyboardDriver(Control owner)
{
Control target = TopLevel.GetTopLevel(owner) as Control ?? owner;
if (ReferenceEquals(_keyboardDriverControl, target))
{
return;
}
if (AvaloniaKeyboardDriver is AvaloniaKeyboardDriver oldKeyboardDriver)
{
oldKeyboardDriver.KeyPressed -= PhysicalKeyLabelHelper.ObserveKeyPress;
oldKeyboardDriver.Dispose();
}
_keyboardDriverControl = target;
AvaloniaKeyboardDriver keyboardDriver = new(target, KeyboardInputMode.Physical);
keyboardDriver.KeyPressed += PhysicalKeyLabelHelper.ObserveKeyPress;
AvaloniaKeyboardDriver = keyboardDriver;
if (_isLoaded && Device > 0 && Device < Devices.Count && Devices[Device].Type == DeviceType.Keyboard)
{
SelectedGamepad?.Dispose();
LoadInputDriver();
}
}
public void Dispose() public void Dispose()
{ {
GC.SuppressFinalize(this); GC.SuppressFinalize(this);
@@ -1110,7 +1147,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
SelectedGamepad?.Dispose(); SelectedGamepad?.Dispose();
AvaloniaKeyboardDriver.Dispose(); AvaloniaKeyboardDriver?.Dispose();
} }
} }
} }

View File

@@ -1,4 +1,5 @@
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia;
using FluentAvalonia.UI.Controls; using FluentAvalonia.UI.Controls;
using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.Systems.Configuration; using Ryujinx.Ava.Systems.Configuration;
@@ -20,6 +21,13 @@ namespace Ryujinx.Ava.UI.Views.Input
InitializeComponent(); InitializeComponent();
} }
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
{
base.OnAttachedToVisualTree(e);
ViewModel?.RetargetKeyboardDriver(this);
}
public void SaveCurrentProfile() public void SaveCurrentProfile()
{ {
ViewModel.Save(); ViewModel.Save();
@@ -30,6 +38,7 @@ namespace Ryujinx.Ava.UI.Views.Input
Dispose(); Dispose();
ViewModel = new InputViewModel(this, enableConfigGlobal); // Create new Input Page with global input configs ViewModel = new InputViewModel(this, enableConfigGlobal); // Create new Input Page with global input configs
InitializeComponent(); InitializeComponent();
ViewModel.RetargetKeyboardDriver(this);
} }
private async void PlayerIndexBox_OnSelectionChanged(object sender, SelectionChangedEventArgs e) private async void PlayerIndexBox_OnSelectionChanged(object sender, SelectionChangedEventArgs e)