From 6db29d6c20dd5d36d79630e4a3cf4c2b95a19f62 Mon Sep 17 00:00:00 2001 From: Isaac Marovitz Date: Fri, 23 Feb 2024 19:00:09 -0500 Subject: [PATCH] Fix Hotkeys --- .../UI/Models/Input/HotkeysConfig.cs | 133 ++++++++++++++++++ .../UI/ViewModels/SettingsViewModel.cs | 18 +-- .../Views/Input/ControllerInputView.axaml.cs | 4 +- .../UI/Views/Input/KeyboardInputView.axaml.cs | 10 +- .../Views/Settings/SettingsHotkeysView.axaml | 37 ++--- .../Settings/SettingsHotkeysView.axaml.cs | 115 +++++++++++---- .../Configuration/Hid/KeyboardHotkeys.cs | 2 - 7 files changed, 248 insertions(+), 71 deletions(-) create mode 100644 src/Ryujinx.Ava/UI/Models/Input/HotkeysConfig.cs diff --git a/src/Ryujinx.Ava/UI/Models/Input/HotkeysConfig.cs b/src/Ryujinx.Ava/UI/Models/Input/HotkeysConfig.cs new file mode 100644 index 000000000..81ae8946f --- /dev/null +++ b/src/Ryujinx.Ava/UI/Models/Input/HotkeysConfig.cs @@ -0,0 +1,133 @@ +using Ryujinx.Ava.UI.ViewModels; +using Ryujinx.Common.Configuration.Hid; + +namespace Ryujinx.Ava.UI.Models.Input +{ + public class HotkeysConfig : BaseModel + { + private Key _toggleVsync; + public Key ToggleVsync + { + get => _toggleVsync; + set + { + _toggleVsync = value; + OnPropertyChanged(); + } + } + + private Key _screenshot; + public Key Screenshot { + get => _screenshot; + set + { + _screenshot = value; + OnPropertyChanged(); + } + } + + private Key _showUI; + public Key ShowUI { + get => _showUI; + set + { + _showUI = value; + OnPropertyChanged(); + } + } + + private Key _pause; + public Key Pause { + get => _pause; + set + { + _pause = value; + OnPropertyChanged(); + } + } + + private Key _toggleMute; + public Key ToggleMute { + get => _toggleMute; + set + { + _toggleMute = value; + OnPropertyChanged(); + } + } + + private Key _resScaleUp; + public Key ResScaleUp { + get => _resScaleUp; + set + { + _resScaleUp = value; + OnPropertyChanged(); + } + } + + private Key _resScaleDown; + public Key ResScaleDown { + get => _resScaleDown; + set + { + _resScaleDown = value; + OnPropertyChanged(); + } + } + + private Key _volumeUp; + public Key VolumeUp { + get => _volumeUp; + set + { + _volumeUp = value; + OnPropertyChanged(); + } + } + + private Key _volumeDown; + public Key VolumeDown { + get => _volumeDown; + set + { + _volumeDown = value; + OnPropertyChanged(); + } + } + + public HotkeysConfig(KeyboardHotkeys config) + { + if (config != null) + { + ToggleVsync = config.ToggleVsync; + Screenshot = config.Screenshot; + ShowUI = config.ShowUI; + Pause = config.Pause; + ToggleMute = config.ToggleMute; + ResScaleUp = config.ResScaleUp; + ResScaleDown = config.ResScaleDown; + VolumeUp = config.VolumeUp; + VolumeDown = config.VolumeDown; + } + } + + public KeyboardHotkeys GetConfig() + { + var config = new KeyboardHotkeys + { + ToggleVsync = ToggleVsync, + Screenshot = Screenshot, + ShowUI = ShowUI, + Pause = Pause, + ToggleMute = ToggleMute, + ResScaleUp = ResScaleUp, + ResScaleDown = ResScaleDown, + VolumeUp = VolumeUp, + VolumeDown = VolumeDown + }; + + return config; + } + } +} diff --git a/src/Ryujinx.Ava/UI/ViewModels/SettingsViewModel.cs b/src/Ryujinx.Ava/UI/ViewModels/SettingsViewModel.cs index bcaa08600..5e27f32ad 100644 --- a/src/Ryujinx.Ava/UI/ViewModels/SettingsViewModel.cs +++ b/src/Ryujinx.Ava/UI/ViewModels/SettingsViewModel.cs @@ -7,9 +7,9 @@ using Ryujinx.Audio.Backends.SDL2; using Ryujinx.Audio.Backends.SoundIo; using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.UI.Helpers; +using Ryujinx.Ava.UI.Models.Input; using Ryujinx.Ava.UI.Windows; using Ryujinx.Common.Configuration; -using Ryujinx.Common.Configuration.Hid; using Ryujinx.Common.Configuration.Multiplayer; using Ryujinx.Common.GraphicsDriver; using Ryujinx.Common.Logging; @@ -46,7 +46,6 @@ namespace Ryujinx.Ava.UI.ViewModels private bool _isVulkanAvailable = true; private bool _directoryChanged; private readonly List _gpuIds = new(); - private KeyboardHotkeys _keyboardHotkeys; private int _graphicsBackendIndex; private int _scalingFilter; private int _scalingFilterLevel; @@ -242,16 +241,7 @@ namespace Ryujinx.Ava.UI.ViewModels get => new(Enum.GetNames()); } - public KeyboardHotkeys KeyboardHotkeys - { - get => _keyboardHotkeys; - set - { - _keyboardHotkeys = value; - - OnPropertyChanged(); - } - } + public HotkeysConfig KeyboardHotkeys { get; set; } public int NetworkInterfaceIndex { @@ -418,7 +408,7 @@ namespace Ryujinx.Ava.UI.ViewModels EnableMouse = config.Hid.EnableMouse; // Keyboard Hotkeys - KeyboardHotkeys = config.Hid.Hotkeys.Value; + KeyboardHotkeys = new HotkeysConfig(config.Hid.Hotkeys.Value); // System Region = (int)config.System.Region.Value; @@ -505,7 +495,7 @@ namespace Ryujinx.Ava.UI.ViewModels config.Hid.EnableMouse.Value = EnableMouse; // Keyboard Hotkeys - config.Hid.Hotkeys.Value = KeyboardHotkeys; + config.Hid.Hotkeys.Value = KeyboardHotkeys.GetConfig(); // System config.System.Region.Value = (Region)Region; diff --git a/src/Ryujinx.Ava/UI/Views/Input/ControllerInputView.axaml.cs b/src/Ryujinx.Ava/UI/Views/Input/ControllerInputView.axaml.cs index 52fc62389..01b52c8f9 100644 --- a/src/Ryujinx.Ava/UI/Views/Input/ControllerInputView.axaml.cs +++ b/src/Ryujinx.Ava/UI/Views/Input/ControllerInputView.axaml.cs @@ -52,7 +52,7 @@ namespace Ryujinx.Ava.UI.Views.Input bool isStick = button.Tag != null && button.Tag.ToString() == "stick"; - if (_currentAssigner == null && (bool)button.IsChecked) + if (_currentAssigner == null) { _currentAssigner = new ButtonKeyAssigner(button); @@ -149,8 +149,6 @@ namespace Ryujinx.Ava.UI.Views.Input { if (_currentAssigner != null) { - ToggleButton oldButton = _currentAssigner.ToggledButton; - _currentAssigner.Cancel(); _currentAssigner = null; button.IsChecked = false; diff --git a/src/Ryujinx.Ava/UI/Views/Input/KeyboardInputView.axaml.cs b/src/Ryujinx.Ava/UI/Views/Input/KeyboardInputView.axaml.cs index f7024c5d1..fdeb282be 100644 --- a/src/Ryujinx.Ava/UI/Views/Input/KeyboardInputView.axaml.cs +++ b/src/Ryujinx.Ava/UI/Views/Input/KeyboardInputView.axaml.cs @@ -49,9 +49,7 @@ namespace Ryujinx.Ava.UI.Views.Input return; } - bool isStick = button.Tag != null && button.Tag.ToString() == "stick"; - - if (_currentAssigner == null && (bool)button.IsChecked) + if (_currentAssigner == null) { _currentAssigner = new ButtonKeyAssigner(button); @@ -60,7 +58,7 @@ namespace Ryujinx.Ava.UI.Views.Input PointerPressed += MouseClick; IKeyboard keyboard = (IKeyboard)(DataContext as KeyboardInputViewModel).parentModel.AvaloniaKeyboardDriver.GetGamepad("0"); // Open Avalonia keyboard for cancel operations. - IButtonAssigner assigner = CreateButtonAssigner(isStick); + IButtonAssigner assigner = CreateButtonAssigner(); _currentAssigner.ButtonAssigned += (sender, e) => { @@ -166,8 +164,6 @@ namespace Ryujinx.Ava.UI.Views.Input { if (_currentAssigner != null) { - ToggleButton oldButton = _currentAssigner.ToggledButton; - _currentAssigner.Cancel(); _currentAssigner = null; button.IsChecked = false; @@ -191,7 +187,7 @@ namespace Ryujinx.Ava.UI.Views.Input PointerPressed -= MouseClick; } - private IButtonAssigner CreateButtonAssigner(bool forStick) + private IButtonAssigner CreateButtonAssigner() { IButtonAssigner assigner; diff --git a/src/Ryujinx.Ava/UI/Views/Settings/SettingsHotkeysView.axaml b/src/Ryujinx.Ava/UI/Views/Settings/SettingsHotkeysView.axaml index 51542e083..cfd5d21dc 100644 --- a/src/Ryujinx.Ava/UI/Views/Settings/SettingsHotkeysView.axaml +++ b/src/Ryujinx.Ava/UI/Views/Settings/SettingsHotkeysView.axaml @@ -9,6 +9,7 @@ xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers" mc:Ignorable="d" x:DataType="viewModels:SettingsViewModel" + x:CompileBindings="True" Focusable="True"> @@ -50,56 +51,56 @@ Text="{locale:Locale SettingsTabHotkeysHotkeys}" /> - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + diff --git a/src/Ryujinx.Ava/UI/Views/Settings/SettingsHotkeysView.axaml.cs b/src/Ryujinx.Ava/UI/Views/Settings/SettingsHotkeysView.axaml.cs index b006d703f..10625ad8e 100644 --- a/src/Ryujinx.Ava/UI/Views/Settings/SettingsHotkeysView.axaml.cs +++ b/src/Ryujinx.Ava/UI/Views/Settings/SettingsHotkeysView.axaml.cs @@ -2,8 +2,10 @@ using Avalonia.Controls; using Avalonia.Controls.Primitives; using Avalonia.Input; using Avalonia.Interactivity; +using Avalonia.LogicalTree; using Ryujinx.Ava.Input; using Ryujinx.Ava.UI.Helpers; +using Ryujinx.Ava.UI.ViewModels; using Ryujinx.Input; using Ryujinx.Input.Assigner; @@ -17,9 +19,27 @@ namespace Ryujinx.Ava.UI.Views.Settings public SettingsHotkeysView() { InitializeComponent(); + + foreach (ILogical visual in SettingButtons.GetLogicalDescendants()) + { + if (visual is ToggleButton button and not CheckBox) + { + button.IsCheckedChanged += Button_IsCheckedChanged; + } + } _avaloniaKeyboardDriver = new AvaloniaKeyboardDriver(this); } + protected override void OnPointerReleased(PointerReleasedEventArgs e) + { + base.OnPointerReleased(e); + + if (_currentAssigner != null && _currentAssigner.ToggledButton != null && !_currentAssigner.ToggledButton.IsPointerOver) + { + _currentAssigner.Cancel(); + } + } + private void MouseClick(object sender, PointerPressedEventArgs e) { bool shouldUnbind = e.GetCurrentPoint(this).Properties.IsMiddleButtonPressed; @@ -29,53 +49,94 @@ namespace Ryujinx.Ava.UI.Views.Settings PointerPressed -= MouseClick; } - private void Button_Checked(object sender, RoutedEventArgs e) + private void Button_IsCheckedChanged(object sender, RoutedEventArgs e) { if (sender is ToggleButton button) { - if (_currentAssigner != null && button == _currentAssigner.ToggledButton) + if ((bool)button.IsChecked) { - return; - } + if (_currentAssigner != null && button == _currentAssigner.ToggledButton) + { + return; + } - if (_currentAssigner == null && button.IsChecked != null && (bool)button.IsChecked) - { - _currentAssigner = new ButtonKeyAssigner(button); + if (_currentAssigner == null) + { + _currentAssigner = new ButtonKeyAssigner(button); - this.Focus(NavigationMethod.Pointer); + this.Focus(NavigationMethod.Pointer); - PointerPressed += MouseClick; + PointerPressed += MouseClick; - var keyboard = (IKeyboard)_avaloniaKeyboardDriver.GetGamepad(_avaloniaKeyboardDriver.GamepadsIds[0]); - IButtonAssigner assigner = new KeyboardKeyAssigner(keyboard); + var keyboard = (IKeyboard)_avaloniaKeyboardDriver.GetGamepad("0"); + IButtonAssigner assigner = new KeyboardKeyAssigner(keyboard); - _currentAssigner.GetInputAndAssign(assigner); + _currentAssigner.ButtonAssigned += (sender, e) => + { + if (e.ButtonValue.HasValue) + { + var viewModel = (DataContext) as SettingsViewModel; + var buttonValue = e.ButtonValue.Value; + + switch (button.Name) + { + case "ToggleVsync": + viewModel.KeyboardHotkeys.ToggleVsync = buttonValue.AsKey(); + break; + case "Screenshot": + viewModel.KeyboardHotkeys.Screenshot = buttonValue.AsKey(); + break; + case "ShowUI": + viewModel.KeyboardHotkeys.ShowUI = buttonValue.AsKey(); + break; + case "Pause": + viewModel.KeyboardHotkeys.Pause = buttonValue.AsKey(); + break; + case "ToggleMute": + viewModel.KeyboardHotkeys.ToggleMute = buttonValue.AsKey(); + break; + case "ResScaleUp": + viewModel.KeyboardHotkeys.ResScaleUp = buttonValue.AsKey(); + break; + case "ResScaleDown": + viewModel.KeyboardHotkeys.ResScaleDown = buttonValue.AsKey(); + break; + case "VolumeUp": + viewModel.KeyboardHotkeys.VolumeUp = buttonValue.AsKey(); + break; + case "VolumeDown": + viewModel.KeyboardHotkeys.VolumeDown = buttonValue.AsKey(); + break; + } + } + }; + + _currentAssigner.GetInputAndAssign(assigner, keyboard); + } + else + { + if (_currentAssigner != null) + { + _currentAssigner.Cancel(); + _currentAssigner = null; + button.IsChecked = false; + } + } } else { - if (_currentAssigner != null) - { - ToggleButton oldButton = _currentAssigner.ToggledButton; - - _currentAssigner.Cancel(); - _currentAssigner = null; - - button.IsChecked = false; - } + _currentAssigner?.Cancel(); + _currentAssigner = null; } } } - private void Button_Unchecked(object sender, RoutedEventArgs e) - { - _currentAssigner?.Cancel(); - _currentAssigner = null; - } - public void Dispose() { _currentAssigner?.Cancel(); _currentAssigner = null; + + _avaloniaKeyboardDriver.Dispose(); } } } diff --git a/src/Ryujinx.Common/Configuration/Hid/KeyboardHotkeys.cs b/src/Ryujinx.Common/Configuration/Hid/KeyboardHotkeys.cs index e9c163cf2..0cb49ca8c 100644 --- a/src/Ryujinx.Common/Configuration/Hid/KeyboardHotkeys.cs +++ b/src/Ryujinx.Common/Configuration/Hid/KeyboardHotkeys.cs @@ -1,7 +1,5 @@ namespace Ryujinx.Common.Configuration.Hid { - // NOTE: Please don't change this to struct. - // This breaks Avalonia's TwoWay binding, which makes us unable to save new KeyboardHotkeys. public class KeyboardHotkeys { public Key ToggleVsync { get; set; }