mirror of
https://git.ryujinx.app/ryubing/ryujinx.git
synced 2026-06-05 11:59:15 +00:00
Fix settings keyboard input focus loss
This commit is contained in:
@@ -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()
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user