From d2bb580aea4c8b08386d4cc7800f899d85e71d85 Mon Sep 17 00:00:00 2001 From: MutantAura Date: Thu, 30 May 2024 01:01:18 +0100 Subject: [PATCH 01/17] Initial implementation of analog stick visualization. --- .../Input/ControllerInputViewModel.cs | 77 ++++++++++++++++++- .../UI/ViewModels/Input/InputViewModel.cs | 2 + .../UI/Views/Input/ControllerInputView.axaml | 73 ++++++++++++++++-- 3 files changed, 145 insertions(+), 7 deletions(-) diff --git a/src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs b/src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs index d291f09a0..863d350fb 100644 --- a/src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs @@ -3,14 +3,31 @@ using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using FluentAvalonia.UI.Controls; using Ryujinx.Ava.UI.Helpers; +using Ryujinx.Ava.Input; using Ryujinx.Ava.UI.Models.Input; using Ryujinx.Ava.UI.Views.Input; +using Ryujinx.Input; +using System.Threading; +using System.Threading.Tasks; namespace Ryujinx.Ava.UI.ViewModels.Input { public partial class ControllerInputViewModel : BaseModel { [ObservableProperty] private GamepadInputConfig _config; + + private const int StickUiPollMs = 50; // Milliseconds per poll. + private const float CanvasCenterOffset = 75f/2f; + private const int StickScaleFactor = 30; + + private IGamepad _selectedGamepad; + + // Offset from origin for UI stick visualization. + private (float, float) _uiStickLeft; + private (float, float) _uiStickRight; + + internal CancellationTokenSource _pollTokenSource = new(); + private CancellationToken _pollToken; private bool _isLeft; public bool IsLeft @@ -39,8 +56,41 @@ namespace Ryujinx.Ava.UI.ViewModels.Input public bool HasSides => IsLeft ^ IsRight; [ObservableProperty] private SvgImage _image; - + public InputViewModel ParentModel { get; } + + public (float, float) UiStickLeft + { + get => (_uiStickLeft.Item1 * StickScaleFactor, _uiStickLeft.Item2 * StickScaleFactor); + set + { + _uiStickLeft = value; + + OnPropertyChanged(); + OnPropertyChanged(nameof(UiStickRightX)); + OnPropertyChanged(nameof(UiStickRightY)); + } + } + + public (float, float) UiStickRight + { + get => (_uiStickRight.Item1 * StickScaleFactor, _uiStickRight.Item2 * StickScaleFactor); + set + { + _uiStickRight = value; + + OnPropertyChanged(); + OnPropertyChanged(nameof(UiStickLeftX)); + OnPropertyChanged(nameof(UiStickLeftY)); + } + } + + public float canvasCenter => CanvasCenterOffset; + + public float UiStickLeftX => UiStickLeft.Item1 + CanvasCenterOffset; + public float UiStickLeftY => UiStickLeft.Item2 + CanvasCenterOffset; + public float UiStickRightX => UiStickRight.Item1 + CanvasCenterOffset; + public float UiStickRightY => UiStickRight.Item2 + CanvasCenterOffset; public ControllerInputViewModel(InputViewModel model, GamepadInputConfig config) { @@ -48,6 +98,11 @@ namespace Ryujinx.Ava.UI.ViewModels.Input model.NotifyChangesEvent += OnParentModelChanged; OnParentModelChanged(); Config = config; + + _pollTokenSource = new(); + _pollToken = _pollTokenSource.Token; + + Task.Run(() => PollSticks(_pollToken)); } public async void ShowMotionConfig() @@ -59,7 +114,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input { await RumbleInputView.Show(this); } - + public RelayCommand LedDisabledChanged => Commands.Create(() => { if (!Config.EnableLedChanging) return; @@ -70,6 +125,24 @@ namespace Ryujinx.Ava.UI.ViewModels.Input ParentModel.SelectedGamepad.SetLed(Config.LedColor.ToUInt32()); }); + private async Task PollSticks(CancellationToken token) + { + while (!token.IsCancellationRequested) + { + _selectedGamepad = ParentModel.SelectedGamepad; + + if (_selectedGamepad != null && _selectedGamepad is not AvaloniaKeyboard) + { + UiStickLeft = _selectedGamepad.GetStick(StickInputId.Left); + UiStickRight = _selectedGamepad.GetStick(StickInputId.Right); + } + + await Task.Delay(StickUiPollMs); + } + + _pollTokenSource.Dispose(); + } + public void OnParentModelChanged() { IsLeft = ParentModel.IsLeft; diff --git a/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs b/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs index c59ec540c..51fbe01fb 100644 --- a/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs @@ -884,6 +884,8 @@ namespace Ryujinx.Ava.UI.ViewModels.Input _mainWindow.InputManager.GamepadDriver.OnGamepadConnected -= HandleOnGamepadConnected; _mainWindow.InputManager.GamepadDriver.OnGamepadDisconnected -= HandleOnGamepadDisconnected; + (ConfigViewModel as ControllerInputViewModel)._pollTokenSource?.Cancel(); + _mainWindow.ViewModel.AppHost?.NpadManager.UnblockInputUpdates(); SelectedGamepad?.Dispose(); diff --git a/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml b/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml index 1662f4a3d..052216397 100644 --- a/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml +++ b/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml @@ -319,12 +319,75 @@ HorizontalAlignment="Stretch" VerticalAlignment="Stretch"> - + MinHeight="90"> + + + + + + + + + + + + + + + Date: Thu, 30 May 2024 14:03:43 +0100 Subject: [PATCH 02/17] Polish the aesthetic and include deadzone visualization. --- .../Input/ControllerInputViewModel.cs | 12 ++- .../UI/Views/Input/ControllerInputView.axaml | 96 ++++++++++++------- 2 files changed, 71 insertions(+), 37 deletions(-) diff --git a/src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs b/src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs index 863d350fb..c453b283f 100644 --- a/src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs @@ -7,6 +7,7 @@ using Ryujinx.Ava.Input; using Ryujinx.Ava.UI.Models.Input; using Ryujinx.Ava.UI.Views.Input; using Ryujinx.Input; +using System; using System.Threading; using System.Threading.Tasks; @@ -17,8 +18,8 @@ namespace Ryujinx.Ava.UI.ViewModels.Input [ObservableProperty] private GamepadInputConfig _config; private const int StickUiPollMs = 50; // Milliseconds per poll. - private const float CanvasCenterOffset = 75f/2f; - private const int StickScaleFactor = 30; + private const float CanvasCenterOffset = 47.5f; + private const int StickScaleFactor = 45; private IGamepad _selectedGamepad; @@ -69,6 +70,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input OnPropertyChanged(); OnPropertyChanged(nameof(UiStickRightX)); OnPropertyChanged(nameof(UiStickRightY)); + OnPropertyChanged(nameof(UiDeadzoneRight)); } } @@ -82,6 +84,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input OnPropertyChanged(); OnPropertyChanged(nameof(UiStickLeftX)); OnPropertyChanged(nameof(UiStickLeftY)); + OnPropertyChanged(nameof(UiDeadzoneLeft)); } } @@ -91,7 +94,10 @@ namespace Ryujinx.Ava.UI.ViewModels.Input public float UiStickLeftY => UiStickLeft.Item2 + CanvasCenterOffset; public float UiStickRightX => UiStickRight.Item1 + CanvasCenterOffset; public float UiStickRightY => UiStickRight.Item2 + CanvasCenterOffset; - + + public float UiDeadzoneLeft => Config.DeadzoneLeft * 95; + public float UiDeadzoneRight => Config.DeadzoneRight * 95; + public ControllerInputViewModel(InputViewModel model, GamepadInputConfig config) { ParentModel = model; diff --git a/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml b/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml index 052216397..2dc73e2fd 100644 --- a/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml +++ b/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml @@ -334,56 +334,84 @@ BorderBrush="{DynamicResource ThemeControlBorderColor}" BorderThickness="1" CornerRadius="5" - Height="100" - Width="100"> + Height="105" + Width="105"> - + + + + + + + + Fill="Red" + Width="5" + Height="5" + Canvas.Bottom="{Binding UiStickLeftY}" + Canvas.Left="{Binding UiStickLeftX}" /> + Height="105" + Width="105"> - + + + + + + + + Fill="Red" + Width="5" + Height="5" + Canvas.Bottom="{Binding UiStickRightY}" + Canvas.Left="{Binding UiStickRightX}" /> -- 2.47.1 From ce13830063a1df3541e939d929475c68becff08a Mon Sep 17 00:00:00 2001 From: MutantAura Date: Thu, 30 May 2024 14:29:05 +0100 Subject: [PATCH 03/17] Clean up some magic numbers between code and axaml. --- .../Input/ControllerInputViewModel.cs | 17 +++++--- .../UI/Views/Input/ControllerInputView.axaml | 40 +++++++++---------- 2 files changed, 31 insertions(+), 26 deletions(-) diff --git a/src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs b/src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs index c453b283f..bad2a22c2 100644 --- a/src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs @@ -7,7 +7,6 @@ using Ryujinx.Ava.Input; using Ryujinx.Ava.UI.Models.Input; using Ryujinx.Ava.UI.Views.Input; using Ryujinx.Input; -using System; using System.Threading; using System.Threading.Tasks; @@ -18,7 +17,11 @@ namespace Ryujinx.Ava.UI.ViewModels.Input [ObservableProperty] private GamepadInputConfig _config; private const int StickUiPollMs = 50; // Milliseconds per poll. - private const float CanvasCenterOffset = 47.5f; + private const int StickCircumference = 5; + + private const int CanvasSize = 100; + private const int StickBorderSize = CanvasSize + 5; + private const float CanvasCenterOffset = (CanvasSize - StickCircumference) / 2; private const int StickScaleFactor = 45; private IGamepad _selectedGamepad; @@ -88,15 +91,17 @@ namespace Ryujinx.Ava.UI.ViewModels.Input } } - public float canvasCenter => CanvasCenterOffset; + public int UiStickCircumference => StickCircumference; + public int UiCanvasSize => CanvasSize; + public int UiStickBorderSize => StickBorderSize; public float UiStickLeftX => UiStickLeft.Item1 + CanvasCenterOffset; public float UiStickLeftY => UiStickLeft.Item2 + CanvasCenterOffset; public float UiStickRightX => UiStickRight.Item1 + CanvasCenterOffset; public float UiStickRightY => UiStickRight.Item2 + CanvasCenterOffset; - - public float UiDeadzoneLeft => Config.DeadzoneLeft * 95; - public float UiDeadzoneRight => Config.DeadzoneRight * 95; + + public float UiDeadzoneLeft => Config.DeadzoneLeft * (CanvasSize - StickCircumference); + public float UiDeadzoneRight => Config.DeadzoneRight * (CanvasSize - StickCircumference); public ControllerInputViewModel(InputViewModel model, GamepadInputConfig config) { diff --git a/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml b/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml index 2dc73e2fd..d7fc36b44 100644 --- a/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml +++ b/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml @@ -334,15 +334,15 @@ BorderBrush="{DynamicResource ThemeControlBorderColor}" BorderThickness="1" CornerRadius="5" - Height="105" - Width="105"> + Height="{Binding UiStickBorderSize}" + Width="{Binding UiStickBorderSize}"> + Height="{Binding UiCanvasSize}" + Width="{Binding UiCanvasSize}"> @@ -352,8 +352,8 @@ HorizontalAlignment="Center" Stroke="Black" StrokeThickness="1" - Width="100" - Height="100" + Width="{Binding UiCanvasSize}" + Height="{Binding UiCanvasSize}" Canvas.Bottom="2" Canvas.Left="2" /> @@ -376,15 +376,15 @@ BorderBrush="{DynamicResource ThemeControlBorderColor}" BorderThickness="1" CornerRadius="5" - Height="105" - Width="105"> + Height="{Binding UiStickBorderSize}" + Width="{Binding UiStickBorderSize}"> + Height="{Binding UiCanvasSize}" + Width="{Binding UiCanvasSize}"> @@ -394,8 +394,8 @@ HorizontalAlignment="Center" Stroke="Black" StrokeThickness="1" - Width="100" - Height="100" + Width="{Binding UiCanvasSize}" + Height="{Binding UiCanvasSize}" Canvas.Bottom="2" Canvas.Left="2" /> -- 2.47.1 From 93d1476a2a7a76e8e91fc25947c9b6414d84e994 Mon Sep 17 00:00:00 2001 From: MutantAura Date: Thu, 30 May 2024 14:32:17 +0100 Subject: [PATCH 04/17] Remove unused grid definitions. --- src/Ryujinx/UI/Views/Input/ControllerInputView.axaml | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml b/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml index d7fc36b44..972308a9c 100644 --- a/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml +++ b/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml @@ -344,11 +344,7 @@ Height="{Binding UiCanvasSize}" Width="{Binding UiCanvasSize}" Background="{DynamicResource ThemeBackgroundColor}"> - - - - - - Date: Thu, 30 May 2024 14:35:58 +0100 Subject: [PATCH 05/17] whitespace --- src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs b/src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs index bad2a22c2..a4dc9d7a3 100644 --- a/src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs @@ -25,7 +25,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input private const int StickScaleFactor = 45; private IGamepad _selectedGamepad; - + // Offset from origin for UI stick visualization. private (float, float) _uiStickLeft; private (float, float) _uiStickRight; @@ -76,7 +76,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input OnPropertyChanged(nameof(UiDeadzoneRight)); } } - + public (float, float) UiStickRight { get => (_uiStickRight.Item1 * StickScaleFactor, _uiStickRight.Item2 * StickScaleFactor); -- 2.47.1 From 75c7a29278e02974d25f2de09e8f41c1f74b3c29 Mon Sep 17 00:00:00 2001 From: MutantAura Date: Thu, 30 May 2024 14:38:42 +0100 Subject: [PATCH 06/17] style and analyzers --- src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs b/src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs index a4dc9d7a3..2d4a2e25c 100644 --- a/src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs @@ -31,7 +31,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input private (float, float) _uiStickRight; internal CancellationTokenSource _pollTokenSource = new(); - private CancellationToken _pollToken; + private readonly CancellationToken _pollToken; private bool _isLeft; public bool IsLeft @@ -148,7 +148,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input UiStickRight = _selectedGamepad.GetStick(StickInputId.Right); } - await Task.Delay(StickUiPollMs); + await Task.Delay(StickUiPollMs, token); } _pollTokenSource.Dispose(); -- 2.47.1 From ffe366d9538416795b45a19054d19905768a81c9 Mon Sep 17 00:00:00 2001 From: MutantAura Date: Thu, 30 May 2024 18:45:57 +0100 Subject: [PATCH 07/17] Cleanup AXAML and hide sticks when only one is present on guest controller. --- .../UI/Views/Input/ControllerInputView.axaml | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml b/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml index 972308a9c..f36d5af5e 100644 --- a/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml +++ b/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml @@ -319,7 +319,7 @@ HorizontalAlignment="Stretch" VerticalAlignment="Stretch"> - + Width="{Binding UiStickBorderSize}" + IsVisible="{Binding IsLeft}"> + Height="{Binding UiCanvasSize}"/> - + Width="{Binding UiStickBorderSize}" + IsVisible="{Binding IsRight}"> + Height="{Binding UiCanvasSize}"/> Date: Thu, 30 May 2024 19:41:47 +0100 Subject: [PATCH 08/17] Fix some issues with stick magnitude. --- .../Input/ControllerInputViewModel.cs | 108 +++++++++++++++--- 1 file changed, 89 insertions(+), 19 deletions(-) diff --git a/src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs b/src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs index 2d4a2e25c..009d30f43 100644 --- a/src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs @@ -7,6 +7,7 @@ using Ryujinx.Ava.Input; using Ryujinx.Ava.UI.Models.Input; using Ryujinx.Ava.UI.Views.Input; using Ryujinx.Input; +using System; using System.Threading; using System.Threading.Tasks; @@ -15,14 +16,16 @@ namespace Ryujinx.Ava.UI.ViewModels.Input public partial class ControllerInputViewModel : BaseModel { [ObservableProperty] private GamepadInputConfig _config; - - private const int StickUiPollMs = 50; // Milliseconds per poll. - private const int StickCircumference = 5; + + private const int DrawStickPollRate = 50; // Milliseconds per poll. + private const int DrawStickCircumference = 5; + private const float DrawStickScaleFactor = DrawStickCanvasCenter; - private const int CanvasSize = 100; - private const int StickBorderSize = CanvasSize + 5; - private const float CanvasCenterOffset = (CanvasSize - StickCircumference) / 2; - private const int StickScaleFactor = 45; + private const int DrawStickCanvasSize = 100; + private const int DrawStickBorderSize = DrawStickCanvasSize + 5; + private const float DrawStickCanvasCenter = (DrawStickCanvasSize - DrawStickCircumference) / 2; + + private const float MaxVectorLength = DrawStickCanvasSize / 2; private IGamepad _selectedGamepad; @@ -30,6 +33,9 @@ namespace Ryujinx.Ava.UI.ViewModels.Input private (float, float) _uiStickLeft; private (float, float) _uiStickRight; + private float _vectorLength; + private float _vectorMultiplier; + internal CancellationTokenSource _pollTokenSource = new(); private readonly CancellationToken _pollToken; @@ -65,7 +71,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input public (float, float) UiStickLeft { - get => (_uiStickLeft.Item1 * StickScaleFactor, _uiStickLeft.Item2 * StickScaleFactor); + get => (_uiStickLeft.Item1 * DrawStickScaleFactor, _uiStickLeft.Item2 * DrawStickScaleFactor); set { _uiStickLeft = value; @@ -79,7 +85,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input public (float, float) UiStickRight { - get => (_uiStickRight.Item1 * StickScaleFactor, _uiStickRight.Item2 * StickScaleFactor); + get => (_uiStickRight.Item1 * DrawStickScaleFactor, _uiStickRight.Item2 * DrawStickScaleFactor); set { _uiStickRight = value; @@ -91,17 +97,76 @@ namespace Ryujinx.Ava.UI.ViewModels.Input } } - public int UiStickCircumference => StickCircumference; - public int UiCanvasSize => CanvasSize; - public int UiStickBorderSize => StickBorderSize; + public int UiStickCircumference => DrawStickCircumference; + public int UiCanvasSize => DrawStickCanvasSize; + public int UiStickBorderSize => DrawStickBorderSize; - public float UiStickLeftX => UiStickLeft.Item1 + CanvasCenterOffset; - public float UiStickLeftY => UiStickLeft.Item2 + CanvasCenterOffset; - public float UiStickRightX => UiStickRight.Item1 + CanvasCenterOffset; - public float UiStickRightY => UiStickRight.Item2 + CanvasCenterOffset; + public float UiStickLeftX + { + get + { + _vectorMultiplier = 1; + _vectorLength = GetVectorLength(UiStickLeft); + + if (_vectorLength > MaxVectorLength) + { + _vectorMultiplier = MaxVectorLength / _vectorLength; + } - public float UiDeadzoneLeft => Config.DeadzoneLeft * (CanvasSize - StickCircumference); - public float UiDeadzoneRight => Config.DeadzoneRight * (CanvasSize - StickCircumference); + return (UiStickLeft.Item1 * _vectorMultiplier) + DrawStickCanvasCenter; + } + } + + public float UiStickLeftY + { + get + { + _vectorMultiplier = 1; + _vectorLength = GetVectorLength(UiStickLeft); + + if (_vectorLength > MaxVectorLength) + { + _vectorMultiplier = MaxVectorLength / _vectorLength; + } + + return (UiStickLeft.Item2 * _vectorMultiplier) + DrawStickCanvasCenter; + } + } + + public float UiStickRightX + { + get + { + _vectorMultiplier = 1; + _vectorLength = GetVectorLength(UiStickRight); + + if (_vectorLength > MaxVectorLength) + { + _vectorMultiplier = MaxVectorLength / _vectorLength; + } + + return (UiStickRight.Item1 * _vectorMultiplier) + DrawStickCanvasCenter; + } + } + + public float UiStickRightY + { + get + { + _vectorMultiplier = 1; + _vectorLength = GetVectorLength(UiStickRight); + + if (_vectorLength > MaxVectorLength) + { + _vectorMultiplier = MaxVectorLength / _vectorLength; + } + + return (UiStickRight.Item2 * _vectorMultiplier) + DrawStickCanvasCenter; + } + } + + public float UiDeadzoneLeft => Config.DeadzoneLeft * DrawStickCanvasSize - DrawStickCircumference; + public float UiDeadzoneRight => Config.DeadzoneRight * DrawStickCanvasSize - DrawStickCircumference; public ControllerInputViewModel(InputViewModel model, GamepadInputConfig config) { @@ -148,12 +213,17 @@ namespace Ryujinx.Ava.UI.ViewModels.Input UiStickRight = _selectedGamepad.GetStick(StickInputId.Right); } - await Task.Delay(StickUiPollMs, token); + await Task.Delay(DrawStickPollRate, token); } _pollTokenSource.Dispose(); } + private float GetVectorLength((float, float) raw) + { + return (float)Math.Sqrt((raw.Item1 * raw.Item1) + (raw.Item2 * raw.Item2)); + } + public void OnParentModelChanged() { IsLeft = ParentModel.IsLeft; -- 2.47.1 From 43ece083b282d80c4636c9def887c64a488f20ca Mon Sep 17 00:00:00 2001 From: MutantAura Date: Thu, 30 May 2024 19:44:56 +0100 Subject: [PATCH 09/17] Move some backing fields to match others. formatting pt.2 --- .../Input/ControllerInputViewModel.cs | 29 +++++++++---------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs b/src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs index 009d30f43..64e228f08 100644 --- a/src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs @@ -24,15 +24,11 @@ namespace Ryujinx.Ava.UI.ViewModels.Input private const int DrawStickCanvasSize = 100; private const int DrawStickBorderSize = DrawStickCanvasSize + 5; private const float DrawStickCanvasCenter = (DrawStickCanvasSize - DrawStickCircumference) / 2; - + private const float MaxVectorLength = DrawStickCanvasSize / 2; private IGamepad _selectedGamepad; - // Offset from origin for UI stick visualization. - private (float, float) _uiStickLeft; - private (float, float) _uiStickRight; - private float _vectorLength; private float _vectorMultiplier; @@ -64,10 +60,12 @@ namespace Ryujinx.Ava.UI.ViewModels.Input } public bool HasSides => IsLeft ^ IsRight; - + [ObservableProperty] private SvgImage _image; public InputViewModel ParentModel { get; } + + private (float, float) _uiStickLeft; public (float, float) UiStickLeft { @@ -83,6 +81,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input } } + private (float, float) _uiStickRight; public (float, float) UiStickRight { get => (_uiStickRight.Item1 * DrawStickScaleFactor, _uiStickRight.Item2 * DrawStickScaleFactor); @@ -121,15 +120,15 @@ namespace Ryujinx.Ava.UI.ViewModels.Input { get { - _vectorMultiplier = 1; - _vectorLength = GetVectorLength(UiStickLeft); + _vectorMultiplier = 1; + _vectorLength = GetVectorLength(UiStickLeft); if (_vectorLength > MaxVectorLength) { _vectorMultiplier = MaxVectorLength / _vectorLength; } - return (UiStickLeft.Item2 * _vectorMultiplier) + DrawStickCanvasCenter; + return (UiStickLeft.Item2 * _vectorMultiplier) + DrawStickCanvasCenter; } } @@ -137,15 +136,15 @@ namespace Ryujinx.Ava.UI.ViewModels.Input { get { - _vectorMultiplier = 1; - _vectorLength = GetVectorLength(UiStickRight); + _vectorMultiplier = 1; + _vectorLength = GetVectorLength(UiStickRight); if (_vectorLength > MaxVectorLength) { _vectorMultiplier = MaxVectorLength / _vectorLength; } - return (UiStickRight.Item1 * _vectorMultiplier) + DrawStickCanvasCenter; + return (UiStickRight.Item1 * _vectorMultiplier) + DrawStickCanvasCenter; } } @@ -153,15 +152,15 @@ namespace Ryujinx.Ava.UI.ViewModels.Input { get { - _vectorMultiplier = 1; - _vectorLength = GetVectorLength(UiStickRight); + _vectorMultiplier = 1; + _vectorLength = GetVectorLength(UiStickRight); if (_vectorLength > MaxVectorLength) { _vectorMultiplier = MaxVectorLength / _vectorLength; } - return (UiStickRight.Item2 * _vectorMultiplier) + DrawStickCanvasCenter; + return (UiStickRight.Item2 * _vectorMultiplier) + DrawStickCanvasCenter; } } -- 2.47.1 From cfa5ad0757be746493291bb5517f29fed68ea61f Mon Sep 17 00:00:00 2001 From: MutantAura Date: Fri, 31 May 2024 00:07:09 +0100 Subject: [PATCH 10/17] Simplfy clamping and fix bug on window close. --- .../Input/ControllerInputViewModel.cs | 84 ++++--------------- .../UI/ViewModels/Input/InputViewModel.cs | 2 +- 2 files changed, 19 insertions(+), 67 deletions(-) diff --git a/src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs b/src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs index 64e228f08..5abfb0786 100644 --- a/src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs @@ -99,70 +99,11 @@ namespace Ryujinx.Ava.UI.ViewModels.Input public int UiStickCircumference => DrawStickCircumference; public int UiCanvasSize => DrawStickCanvasSize; public int UiStickBorderSize => DrawStickBorderSize; - - public float UiStickLeftX - { - get - { - _vectorMultiplier = 1; - _vectorLength = GetVectorLength(UiStickLeft); - - if (_vectorLength > MaxVectorLength) - { - _vectorMultiplier = MaxVectorLength / _vectorLength; - } - - return (UiStickLeft.Item1 * _vectorMultiplier) + DrawStickCanvasCenter; - } - } - - public float UiStickLeftY - { - get - { - _vectorMultiplier = 1; - _vectorLength = GetVectorLength(UiStickLeft); - - if (_vectorLength > MaxVectorLength) - { - _vectorMultiplier = MaxVectorLength / _vectorLength; - } - - return (UiStickLeft.Item2 * _vectorMultiplier) + DrawStickCanvasCenter; - } - } - - public float UiStickRightX - { - get - { - _vectorMultiplier = 1; - _vectorLength = GetVectorLength(UiStickRight); - - if (_vectorLength > MaxVectorLength) - { - _vectorMultiplier = MaxVectorLength / _vectorLength; - } - - return (UiStickRight.Item1 * _vectorMultiplier) + DrawStickCanvasCenter; - } - } - - public float UiStickRightY - { - get - { - _vectorMultiplier = 1; - _vectorLength = GetVectorLength(UiStickRight); - - if (_vectorLength > MaxVectorLength) - { - _vectorMultiplier = MaxVectorLength / _vectorLength; - } - - return (UiStickRight.Item2 * _vectorMultiplier) + DrawStickCanvasCenter; - } - } + + public float UiStickLeftX => ClampVector(UiStickLeft).Item1; + public float UiStickLeftY => ClampVector(UiStickLeft).Item2; + public float UiStickRightX => ClampVector(UiStickRight).Item1; + public float UiStickRightY => ClampVector(UiStickRight).Item2; public float UiDeadzoneLeft => Config.DeadzoneLeft * DrawStickCanvasSize - DrawStickCircumference; public float UiDeadzoneRight => Config.DeadzoneRight * DrawStickCanvasSize - DrawStickCircumference; @@ -218,9 +159,20 @@ namespace Ryujinx.Ava.UI.ViewModels.Input _pollTokenSource.Dispose(); } - private float GetVectorLength((float, float) raw) + private (float, float) ClampVector((float, float) vect) { - return (float)Math.Sqrt((raw.Item1 * raw.Item1) + (raw.Item2 * raw.Item2)); + _vectorMultiplier = 1; + _vectorLength = MathF.Sqrt((vect.Item1 * vect.Item1) + (vect.Item2 * vect.Item2)); + + if (_vectorLength > MaxVectorLength) + { + _vectorMultiplier = MaxVectorLength / _vectorLength; + } + + vect.Item1 = vect.Item1 * _vectorMultiplier + DrawStickCanvasCenter; + vect.Item2 = vect.Item2 * _vectorMultiplier + DrawStickCanvasCenter; + + return vect; } public void OnParentModelChanged() diff --git a/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs b/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs index 51fbe01fb..7d69b13a3 100644 --- a/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs @@ -884,7 +884,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input _mainWindow.InputManager.GamepadDriver.OnGamepadConnected -= HandleOnGamepadConnected; _mainWindow.InputManager.GamepadDriver.OnGamepadDisconnected -= HandleOnGamepadDisconnected; - (ConfigViewModel as ControllerInputViewModel)._pollTokenSource?.Cancel(); + (ConfigViewModel as ControllerInputViewModel)?._pollTokenSource.Cancel(); _mainWindow.ViewModel.AppHost?.NpadManager.UnblockInputUpdates(); -- 2.47.1 From 16ca8e500576a3169b1e23a2ecb1ade560c08646 Mon Sep 17 00:00:00 2001 From: MutantAura Date: Fri, 31 May 2024 01:42:33 +0100 Subject: [PATCH 11/17] Move most logic into new `StickVisualizer` class and add keyboard support. --- .../UI/Models/Input/StickVisualizer.cs | 123 ++++++++++++++++++ .../Input/ControllerInputViewModel.cs | 64 ++++----- .../UI/ViewModels/Input/InputViewModel.cs | 2 +- .../Input/KeyboardInputViewModel.cs | 88 ++++++++++++- .../UI/Views/Input/ControllerInputView.axaml | 56 ++++---- .../UI/Views/Input/KeyboardInputView.axaml | 89 ++++++++++++- 6 files changed, 355 insertions(+), 67 deletions(-) create mode 100644 src/Ryujinx/UI/Models/Input/StickVisualizer.cs diff --git a/src/Ryujinx/UI/Models/Input/StickVisualizer.cs b/src/Ryujinx/UI/Models/Input/StickVisualizer.cs new file mode 100644 index 000000000..83cfd4766 --- /dev/null +++ b/src/Ryujinx/UI/Models/Input/StickVisualizer.cs @@ -0,0 +1,123 @@ +using Ryujinx.Ava.UI.ViewModels; +using System; +using System.Threading; + +namespace Ryujinx.Ava.UI.Models.Input +{ + public class StickVisualizer : BaseModel + { + public const int DrawStickPollRate = 50; // Milliseconds per poll. + public const int DrawStickCircumference = 5; + public const float DrawStickScaleFactor = DrawStickCanvasCenter; + public const int DrawStickCanvasSize = 100; + public const int DrawStickBorderSize = DrawStickCanvasSize + 5; + public const float DrawStickCanvasCenter = (DrawStickCanvasSize - DrawStickCircumference) / 2; + public const float MaxVectorLength = DrawStickCanvasSize / 2; + + public CancellationTokenSource PollTokenSource = new(); + public CancellationToken PollToken; + + private static float _vectorLength; + private static float _vectorMultiplier; + + private GamepadInputConfig _gamepadConfig; + public GamepadInputConfig GamepadConfig + { + get => _gamepadConfig; + set + { + _gamepadConfig = value; + + OnPropertyChanged(); + } + } + + private KeyboardInputConfig _keyboardConfig; + public KeyboardInputConfig KeyboardConfig + { + get => _keyboardConfig; + set + { + _keyboardConfig = value; + + OnPropertyChanged(); + } + } + + private (float, float) _uiStickLeft; + public (float, float) UiStickLeft + { + get => (_uiStickLeft.Item1 * DrawStickScaleFactor, _uiStickLeft.Item2 * DrawStickScaleFactor); + set + { + _uiStickLeft = value; + + OnPropertyChanged(); + OnPropertyChanged(nameof(UiStickRightX)); + OnPropertyChanged(nameof(UiStickRightY)); + OnPropertyChanged(nameof(UiDeadzoneRight)); + } + } + + private (float, float) _uiStickRight; + public (float, float) UiStickRight + { + get => (_uiStickRight.Item1 * DrawStickScaleFactor, _uiStickRight.Item2 * DrawStickScaleFactor); + set + { + _uiStickRight = value; + + OnPropertyChanged(); + OnPropertyChanged(nameof(UiStickLeftX)); + OnPropertyChanged(nameof(UiStickLeftY)); + OnPropertyChanged(nameof(UiDeadzoneLeft)); + } + } + + public float UiStickLeftX => ClampVector(UiStickLeft).Item1; + public float UiStickLeftY => ClampVector(UiStickLeft).Item2; + public float UiStickRightX => ClampVector(UiStickRight).Item1; + public float UiStickRightY => ClampVector(UiStickRight).Item2; + + public int UiStickCircumference => DrawStickCircumference; + public int UiCanvasSize => DrawStickCanvasSize; + public int UiStickBorderSize => DrawStickBorderSize; + + public float? UiDeadzoneLeft => _gamepadConfig?.DeadzoneLeft * DrawStickCanvasSize - DrawStickCircumference; + public float? UiDeadzoneRight => _gamepadConfig?.DeadzoneRight * DrawStickCanvasSize - DrawStickCircumference; + + public void UpdateConfig(object config) + { + if (config is GamepadInputConfig padConfig) + { + GamepadConfig = padConfig; + + return; + } + else if (config is KeyboardInputConfig keyConfig) + { + KeyboardConfig = keyConfig; + + return; + } + + throw new ArgumentException($"Invalid configuration: {config}"); + } + + public static (float, float) ClampVector((float, float) vect) + { + _vectorMultiplier = 1; + _vectorLength = MathF.Sqrt((vect.Item1 * vect.Item1) + (vect.Item2 * vect.Item2)); + + if (_vectorLength > MaxVectorLength) + { + _vectorMultiplier = MaxVectorLength / _vectorLength; + } + + vect.Item1 = vect.Item1 * _vectorMultiplier + DrawStickCanvasCenter; + vect.Item2 = vect.Item2 * _vectorMultiplier + DrawStickCanvasCenter; + + return vect; + } + } +} diff --git a/src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs b/src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs index 5abfb0786..aa2f15e6e 100644 --- a/src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs @@ -7,7 +7,6 @@ using Ryujinx.Ava.Input; using Ryujinx.Ava.UI.Models.Input; using Ryujinx.Ava.UI.Views.Input; using Ryujinx.Input; -using System; using System.Threading; using System.Threading.Tasks; @@ -15,8 +14,6 @@ namespace Ryujinx.Ava.UI.ViewModels.Input { public partial class ControllerInputViewModel : BaseModel { - [ObservableProperty] private GamepadInputConfig _config; - private const int DrawStickPollRate = 50; // Milliseconds per poll. private const int DrawStickCircumference = 5; private const float DrawStickScaleFactor = DrawStickCanvasCenter; @@ -26,15 +23,34 @@ namespace Ryujinx.Ava.UI.ViewModels.Input private const float DrawStickCanvasCenter = (DrawStickCanvasSize - DrawStickCircumference) / 2; private const float MaxVectorLength = DrawStickCanvasSize / 2; - + private IGamepad _selectedGamepad; - private float _vectorLength; - private float _vectorMultiplier; + private StickVisualizer _stickVisualizer; + public StickVisualizer StickVisualizer + { + get => _stickVisualizer; + set + { + _stickVisualizer = value; - internal CancellationTokenSource _pollTokenSource = new(); - private readonly CancellationToken _pollToken; + OnPropertyChanged(); + } + } + + private GamepadInputConfig _config; + public GamepadInputConfig Config + { + get => _config; + set + { + _config = value; + StickVisualizer.UpdateConfig(Config); + OnPropertyChanged(); + } + } + private bool _isLeft; public bool IsLeft { @@ -64,7 +80,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input [ObservableProperty] private SvgImage _image; public InputViewModel ParentModel { get; } - + private (float, float) _uiStickLeft; public (float, float) UiStickLeft @@ -113,12 +129,12 @@ namespace Ryujinx.Ava.UI.ViewModels.Input ParentModel = model; model.NotifyChangesEvent += OnParentModelChanged; OnParentModelChanged(); + _stickVisualizer = new(); Config = config; - _pollTokenSource = new(); - _pollToken = _pollTokenSource.Token; + StickVisualizer.PollToken = StickVisualizer.PollTokenSource.Token; - Task.Run(() => PollSticks(_pollToken)); + Task.Run(() => PollSticks(StickVisualizer.PollToken)); } public async void ShowMotionConfig() @@ -149,30 +165,14 @@ namespace Ryujinx.Ava.UI.ViewModels.Input if (_selectedGamepad != null && _selectedGamepad is not AvaloniaKeyboard) { - UiStickLeft = _selectedGamepad.GetStick(StickInputId.Left); - UiStickRight = _selectedGamepad.GetStick(StickInputId.Right); + StickVisualizer.UiStickLeft = _selectedGamepad.GetStick(StickInputId.Left); + StickVisualizer.UiStickRight = _selectedGamepad.GetStick(StickInputId.Right); } - await Task.Delay(DrawStickPollRate, token); + await Task.Delay(StickVisualizer.DrawStickPollRate, token); } - _pollTokenSource.Dispose(); - } - - private (float, float) ClampVector((float, float) vect) - { - _vectorMultiplier = 1; - _vectorLength = MathF.Sqrt((vect.Item1 * vect.Item1) + (vect.Item2 * vect.Item2)); - - if (_vectorLength > MaxVectorLength) - { - _vectorMultiplier = MaxVectorLength / _vectorLength; - } - - vect.Item1 = vect.Item1 * _vectorMultiplier + DrawStickCanvasCenter; - vect.Item2 = vect.Item2 * _vectorMultiplier + DrawStickCanvasCenter; - - return vect; + StickVisualizer.PollTokenSource.Dispose(); } public void OnParentModelChanged() diff --git a/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs b/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs index 7d69b13a3..7bb082893 100644 --- a/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs @@ -884,7 +884,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input _mainWindow.InputManager.GamepadDriver.OnGamepadConnected -= HandleOnGamepadConnected; _mainWindow.InputManager.GamepadDriver.OnGamepadDisconnected -= HandleOnGamepadDisconnected; - (ConfigViewModel as ControllerInputViewModel)?._pollTokenSource.Cancel(); + (ConfigViewModel as ControllerInputViewModel)?.StickVisualizer.PollTokenSource.Cancel(); _mainWindow.ViewModel.AppHost?.NpadManager.UnblockInputUpdates(); diff --git a/src/Ryujinx/UI/ViewModels/Input/KeyboardInputViewModel.cs b/src/Ryujinx/UI/ViewModels/Input/KeyboardInputViewModel.cs index 5ff9bb578..8f325e67c 100644 --- a/src/Ryujinx/UI/ViewModels/Input/KeyboardInputViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/Input/KeyboardInputViewModel.cs @@ -1,12 +1,40 @@ using Avalonia.Svg.Skia; using CommunityToolkit.Mvvm.ComponentModel; using Ryujinx.Ava.UI.Models.Input; +using Ryujinx.Input; +using System.Threading; +using System.Threading.Tasks; namespace Ryujinx.Ava.UI.ViewModels.Input { public partial class KeyboardInputViewModel : BaseModel { - [ObservableProperty] private KeyboardInputConfig _config; + private (float, float) _leftBuffer = (0, 0); + private (float, float) _rightBuffer = (0, 0); + private StickVisualizer _stickVisualizer; + public StickVisualizer StickVisualizer + { + get => _stickVisualizer; + set + { + _stickVisualizer = value; + + OnPropertyChanged(); + } + } + + private KeyboardInputConfig _config; + public KeyboardInputConfig Config + { + get => _config; + set + { + _config = value; + StickVisualizer.UpdateConfig(_config); + + OnPropertyChanged(); + } + } private bool _isLeft; public bool IsLeft @@ -43,7 +71,65 @@ namespace Ryujinx.Ava.UI.ViewModels.Input ParentModel = model; model.NotifyChangesEvent += OnParentModelChanged; OnParentModelChanged(); + _stickVisualizer = new(); Config = config; + + StickVisualizer.PollToken = StickVisualizer.PollTokenSource.Token; + + Task.Run(() => PollKeyboard(StickVisualizer.PollToken)); + } + + private async Task PollKeyboard(CancellationToken token) + { + while (!token.IsCancellationRequested) + { + if (ParentModel.IsKeyboard) + { + IKeyboard keyboard = (IKeyboard)ParentModel.AvaloniaKeyboardDriver.GetGamepad("0"); + var snap = keyboard.GetKeyboardStateSnapshot(); + + if (snap.IsPressed((Key)Config.LeftStickRight)) + { + _leftBuffer.Item1 += 1; + } + if (snap.IsPressed((Key)Config.LeftStickLeft)) + { + _leftBuffer.Item1 -= 1; + } + if (snap.IsPressed((Key)Config.LeftStickUp)) + { + _leftBuffer.Item2 += 1; + } + if (snap.IsPressed((Key)Config.LeftStickDown)) + { + _leftBuffer.Item2 -= 1; + } + + if (snap.IsPressed((Key)Config.RightStickRight)) + { + _rightBuffer.Item1 += 1; + } + if (snap.IsPressed((Key)Config.RightStickLeft)) + { + _rightBuffer.Item1 -= 1; + } + if (snap.IsPressed((Key)Config.RightStickUp)) + { + _rightBuffer.Item2 += 1; + } + if (snap.IsPressed((Key)Config.RightStickDown)) + { + _rightBuffer.Item2 -= 1; + } + + StickVisualizer.UiStickLeft = _leftBuffer; + StickVisualizer.UiStickRight = _rightBuffer; + } + + await Task.Delay(StickVisualizer.DrawStickPollRate, token); + } + + StickVisualizer.PollTokenSource.Dispose(); } public void OnParentModelChanged() diff --git a/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml b/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml index f36d5af5e..9740d9dcc 100644 --- a/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml +++ b/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml @@ -334,72 +334,72 @@ BorderBrush="{DynamicResource ThemeControlBorderColor}" BorderThickness="1" CornerRadius="5" - Height="{Binding UiStickBorderSize}" - Width="{Binding UiStickBorderSize}" + Height="{Binding StickVisualizer.UiStickBorderSize}" + Width="{Binding StickVisualizer.UiStickBorderSize}" IsVisible="{Binding IsLeft}"> + Height="{Binding StickVisualizer.UiCanvasSize}" + Width="{Binding StickVisualizer.UiCanvasSize}"> + Width="{Binding StickVisualizer.UiCanvasSize}" + Height="{Binding StickVisualizer.UiCanvasSize}"/> + Height="{Binding StickVisualizer.UiDeadzoneLeft}" + Width="{Binding StickVisualizer.UiDeadzoneLeft}"/> + Width="{Binding StickVisualizer.UiStickCircumference}" + Height="{Binding StickVisualizer.UiStickCircumference}" + Canvas.Bottom="{Binding StickVisualizer.UiStickLeftY}" + Canvas.Left="{Binding StickVisualizer.UiStickLeftX}" /> + Height="{Binding StickVisualizer.UiCanvasSize}" + Width="{Binding StickVisualizer.UiCanvasSize}"> + Width="{Binding StickVisualizer.UiCanvasSize}" + Height="{Binding StickVisualizer.UiCanvasSize}"/> + Height="{Binding StickVisualizer.UiDeadzoneRight}" + Width="{Binding StickVisualizer.UiDeadzoneRight}"/> + Width="{Binding StickVisualizer.UiStickCircumference}" + Height="{Binding StickVisualizer.UiStickCircumference}" + Canvas.Bottom="{Binding StickVisualizer.UiStickRightY}" + Canvas.Left="{Binding StickVisualizer.UiStickRightX}" /> diff --git a/src/Ryujinx/UI/Views/Input/KeyboardInputView.axaml b/src/Ryujinx/UI/Views/Input/KeyboardInputView.axaml index ecb9053f7..2ffbce07f 100644 --- a/src/Ryujinx/UI/Views/Input/KeyboardInputView.axaml +++ b/src/Ryujinx/UI/Views/Input/KeyboardInputView.axaml @@ -312,12 +312,91 @@ HorizontalAlignment="Stretch" VerticalAlignment="Stretch"> - + MinHeight="90"> + + + + + + + + + + + + + + + + + + + + + Date: Mon, 3 Jun 2024 23:10:04 +0100 Subject: [PATCH 12/17] Consolidate most logic into `StickVisualizer`. --- .../UI/Models/Input/StickVisualizer.cs | 151 +++++++++++++++++- .../Input/ControllerInputViewModel.cs | 109 ++----------- .../UI/ViewModels/Input/InputViewModel.cs | 25 ++- .../Input/KeyboardInputViewModel.cs | 91 ++--------- .../UI/Views/Input/ControllerInputView.axaml | 56 +++---- .../UI/Views/Input/KeyboardInputView.axaml | 60 +++---- 6 files changed, 244 insertions(+), 248 deletions(-) diff --git a/src/Ryujinx/UI/Models/Input/StickVisualizer.cs b/src/Ryujinx/UI/Models/Input/StickVisualizer.cs index 83cfd4766..b7e9ec331 100644 --- a/src/Ryujinx/UI/Models/Input/StickVisualizer.cs +++ b/src/Ryujinx/UI/Models/Input/StickVisualizer.cs @@ -1,10 +1,13 @@ using Ryujinx.Ava.UI.ViewModels; +using Ryujinx.Ava.UI.ViewModels.Input; +using Ryujinx.Input; using System; using System.Threading; +using System.Threading.Tasks; namespace Ryujinx.Ava.UI.Models.Input { - public class StickVisualizer : BaseModel + public class StickVisualizer : BaseModel, IDisposable { public const int DrawStickPollRate = 50; // Milliseconds per poll. public const int DrawStickCircumference = 5; @@ -14,12 +17,26 @@ namespace Ryujinx.Ava.UI.Models.Input public const float DrawStickCanvasCenter = (DrawStickCanvasSize - DrawStickCircumference) / 2; public const float MaxVectorLength = DrawStickCanvasSize / 2; - public CancellationTokenSource PollTokenSource = new(); + public CancellationTokenSource PollTokenSource; public CancellationToken PollToken; private static float _vectorLength; private static float _vectorMultiplier; + private bool disposedValue; + + private DeviceType _type; + public DeviceType Type + { + get => _type; + set + { + _type = value; + + OnPropertyChanged(); + } + } + private GamepadInputConfig _gamepadConfig; public GamepadInputConfig GamepadConfig { @@ -86,22 +103,119 @@ namespace Ryujinx.Ava.UI.Models.Input public float? UiDeadzoneLeft => _gamepadConfig?.DeadzoneLeft * DrawStickCanvasSize - DrawStickCircumference; public float? UiDeadzoneRight => _gamepadConfig?.DeadzoneRight * DrawStickCanvasSize - DrawStickCircumference; + private InputViewModel Parent; + + public StickVisualizer(InputViewModel parent) + { + Parent = parent; + + PollTokenSource = new CancellationTokenSource(); + PollToken = PollTokenSource.Token; + + Task.Run(Initialize, PollToken); + } + public void UpdateConfig(object config) { - if (config is GamepadInputConfig padConfig) + if (config is ControllerInputViewModel padConfig) { - GamepadConfig = padConfig; + GamepadConfig = padConfig.Config; + Type = DeviceType.Controller; return; } - else if (config is KeyboardInputConfig keyConfig) + else if (config is KeyboardInputViewModel keyConfig) { - KeyboardConfig = keyConfig; + KeyboardConfig = keyConfig.Config; + Type = DeviceType.Keyboard; return; } - throw new ArgumentException($"Invalid configuration: {config}"); + Type = DeviceType.None; + } + + public async Task Initialize() + { + (float, float) leftBuffer; + (float, float) rightBuffer; + + while (!PollToken.IsCancellationRequested) + { + leftBuffer = (0f, 0f); + rightBuffer = (0f, 0f); + + switch (Type) + { + case DeviceType.Keyboard: + IKeyboard keyboard = (IKeyboard)Parent.AvaloniaKeyboardDriver.GetGamepad("0"); + + if (keyboard != null) + { + KeyboardStateSnapshot snapshot = keyboard.GetKeyboardStateSnapshot(); + + if (snapshot.IsPressed((Key)KeyboardConfig.LeftStickRight)) + { + leftBuffer.Item1 += 1; + } + if (snapshot.IsPressed((Key)KeyboardConfig.LeftStickLeft)) + { + leftBuffer.Item1 -= 1; + } + if (snapshot.IsPressed((Key)KeyboardConfig.LeftStickUp)) + { + leftBuffer.Item2 += 1; + } + if (snapshot.IsPressed((Key)KeyboardConfig.LeftStickDown)) + { + leftBuffer.Item2 -= 1; + } + + if (snapshot.IsPressed((Key)KeyboardConfig.RightStickRight)) + { + rightBuffer.Item1 += 1; + } + if (snapshot.IsPressed((Key)KeyboardConfig.RightStickLeft)) + { + rightBuffer.Item1 -= 1; + } + if (snapshot.IsPressed((Key)KeyboardConfig.RightStickUp)) + { + rightBuffer.Item2 += 1; + } + if (snapshot.IsPressed((Key)KeyboardConfig.RightStickDown)) + { + rightBuffer.Item2 -= 1; + } + + UiStickLeft = leftBuffer; + UiStickRight = rightBuffer; + } + break; + + case DeviceType.Controller: + IGamepad controller = Parent.SelectedGamepad; + + if (controller != null) + { + leftBuffer = controller.GetStick((StickInputId)GamepadConfig.LeftJoystick); + rightBuffer = controller.GetStick((StickInputId)GamepadConfig.RightJoystick); + } + break; + + case DeviceType.None: + break; + default: + throw new ArgumentException($"Unable to poll device type \"{Type}\""); + } + + UiStickLeft = leftBuffer; + UiStickRight = rightBuffer; + + await Task.Delay(DrawStickPollRate, PollToken); + } + + PollTokenSource.Dispose(); } public static (float, float) ClampVector((float, float) vect) @@ -119,5 +233,28 @@ namespace Ryujinx.Ava.UI.Models.Input return vect; } + + protected virtual void Dispose(bool disposing) + { + if (!disposedValue) + { + if (disposing) + { + PollTokenSource.Cancel(); + } + + KeyboardConfig = null; + GamepadConfig = null; + Parent = null; + + disposedValue = true; + } + } + + public void Dispose() + { + Dispose(disposing: true); + GC.SuppressFinalize(this); + } } } diff --git a/src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs b/src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs index aa2f15e6e..6c683a50a 100644 --- a/src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs @@ -6,38 +6,11 @@ using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.Input; using Ryujinx.Ava.UI.Models.Input; using Ryujinx.Ava.UI.Views.Input; -using Ryujinx.Input; -using System.Threading; -using System.Threading.Tasks; namespace Ryujinx.Ava.UI.ViewModels.Input { public partial class ControllerInputViewModel : BaseModel { - private const int DrawStickPollRate = 50; // Milliseconds per poll. - private const int DrawStickCircumference = 5; - private const float DrawStickScaleFactor = DrawStickCanvasCenter; - - private const int DrawStickCanvasSize = 100; - private const int DrawStickBorderSize = DrawStickCanvasSize + 5; - private const float DrawStickCanvasCenter = (DrawStickCanvasSize - DrawStickCircumference) / 2; - - private const float MaxVectorLength = DrawStickCanvasSize / 2; - - private IGamepad _selectedGamepad; - - private StickVisualizer _stickVisualizer; - public StickVisualizer StickVisualizer - { - get => _stickVisualizer; - set - { - _stickVisualizer = value; - - OnPropertyChanged(); - } - } - private GamepadInputConfig _config; public GamepadInputConfig Config { @@ -45,7 +18,18 @@ namespace Ryujinx.Ava.UI.ViewModels.Input set { _config = value; - StickVisualizer.UpdateConfig(Config); + + OnPropertyChanged(); + } + } + + private StickVisualizer _visualizer; + public StickVisualizer Visualizer + { + get => _visualizer; + set + { + _visualizer = value; OnPropertyChanged(); } @@ -81,60 +65,13 @@ namespace Ryujinx.Ava.UI.ViewModels.Input public InputViewModel ParentModel { get; } - private (float, float) _uiStickLeft; - - public (float, float) UiStickLeft - { - get => (_uiStickLeft.Item1 * DrawStickScaleFactor, _uiStickLeft.Item2 * DrawStickScaleFactor); - set - { - _uiStickLeft = value; - - OnPropertyChanged(); - OnPropertyChanged(nameof(UiStickRightX)); - OnPropertyChanged(nameof(UiStickRightY)); - OnPropertyChanged(nameof(UiDeadzoneRight)); - } - } - - private (float, float) _uiStickRight; - public (float, float) UiStickRight - { - get => (_uiStickRight.Item1 * DrawStickScaleFactor, _uiStickRight.Item2 * DrawStickScaleFactor); - set - { - _uiStickRight = value; - - OnPropertyChanged(); - OnPropertyChanged(nameof(UiStickLeftX)); - OnPropertyChanged(nameof(UiStickLeftY)); - OnPropertyChanged(nameof(UiDeadzoneLeft)); - } - } - - public int UiStickCircumference => DrawStickCircumference; - public int UiCanvasSize => DrawStickCanvasSize; - public int UiStickBorderSize => DrawStickBorderSize; - - public float UiStickLeftX => ClampVector(UiStickLeft).Item1; - public float UiStickLeftY => ClampVector(UiStickLeft).Item2; - public float UiStickRightX => ClampVector(UiStickRight).Item1; - public float UiStickRightY => ClampVector(UiStickRight).Item2; - - public float UiDeadzoneLeft => Config.DeadzoneLeft * DrawStickCanvasSize - DrawStickCircumference; - public float UiDeadzoneRight => Config.DeadzoneRight * DrawStickCanvasSize - DrawStickCircumference; - - public ControllerInputViewModel(InputViewModel model, GamepadInputConfig config) + public ControllerInputViewModel(InputViewModel model, GamepadInputConfig config, StickVisualizer visualizer) { ParentModel = model; + Visualizer = visualizer; model.NotifyChangesEvent += OnParentModelChanged; OnParentModelChanged(); - _stickVisualizer = new(); Config = config; - - StickVisualizer.PollToken = StickVisualizer.PollTokenSource.Token; - - Task.Run(() => PollSticks(StickVisualizer.PollToken)); } public async void ShowMotionConfig() @@ -157,24 +94,6 @@ namespace Ryujinx.Ava.UI.ViewModels.Input ParentModel.SelectedGamepad.SetLed(Config.LedColor.ToUInt32()); }); - private async Task PollSticks(CancellationToken token) - { - while (!token.IsCancellationRequested) - { - _selectedGamepad = ParentModel.SelectedGamepad; - - if (_selectedGamepad != null && _selectedGamepad is not AvaloniaKeyboard) - { - StickVisualizer.UiStickLeft = _selectedGamepad.GetStick(StickInputId.Left); - StickVisualizer.UiStickRight = _selectedGamepad.GetStick(StickInputId.Right); - } - - await Task.Delay(StickVisualizer.DrawStickPollRate, token); - } - - StickVisualizer.PollTokenSource.Dispose(); - } - public void OnParentModelChanged() { IsLeft = ParentModel.IsLeft; diff --git a/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs b/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs index 7bb082893..f25effbce 100644 --- a/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs @@ -48,7 +48,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input private int _controller; private string _controllerImage; private int _device; - [ObservableProperty] private object _configViewModel; + private object _configViewModel; [ObservableProperty] private string _profileName; private bool _isLoaded; @@ -67,6 +67,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input OnPropertiesChanged(nameof(HasLed), nameof(CanClearLed)); } } + public StickVisualizer VisualStick { get; private set; } public ObservableCollection PlayerIndexes { get; set; } public ObservableCollection<(DeviceType Type, string Id, string Name)> Devices { get; set; } @@ -87,6 +88,19 @@ namespace Ryujinx.Ava.UI.ViewModels.Input public bool IsModified { get; set; } public event Action NotifyChangesEvent; + public object ConfigViewModel + { + get => _configViewModel; + set + { + _configViewModel = value; + + VisualStick.UpdateConfig(value); + + OnPropertyChanged(); + } + } + public PlayerIndex PlayerIdChoose { get => _playerIdChoose; @@ -262,6 +276,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input Devices = new ObservableCollection<(DeviceType Type, string Id, string Name)>(); ProfilesList = new AvaloniaList(); DeviceList = new AvaloniaList(); + VisualStick = new StickVisualizer(this); ControllerImage = ProControllerResource; @@ -282,12 +297,12 @@ namespace Ryujinx.Ava.UI.ViewModels.Input if (Config is StandardKeyboardInputConfig keyboardInputConfig) { - ConfigViewModel = new KeyboardInputViewModel(this, new KeyboardInputConfig(keyboardInputConfig)); + ConfigViewModel = new KeyboardInputViewModel(this, new KeyboardInputConfig(keyboardInputConfig), VisualStick); } if (Config is StandardControllerInputConfig controllerInputConfig) { - ConfigViewModel = new ControllerInputViewModel(this, new GamepadInputConfig(controllerInputConfig)); + ConfigViewModel = new ControllerInputViewModel(this, new GamepadInputConfig(controllerInputConfig), VisualStick); } } @@ -884,10 +899,10 @@ namespace Ryujinx.Ava.UI.ViewModels.Input _mainWindow.InputManager.GamepadDriver.OnGamepadConnected -= HandleOnGamepadConnected; _mainWindow.InputManager.GamepadDriver.OnGamepadDisconnected -= HandleOnGamepadDisconnected; - (ConfigViewModel as ControllerInputViewModel)?.StickVisualizer.PollTokenSource.Cancel(); - _mainWindow.ViewModel.AppHost?.NpadManager.UnblockInputUpdates(); + VisualStick.Dispose(); + SelectedGamepad?.Dispose(); AvaloniaKeyboardDriver.Dispose(); diff --git a/src/Ryujinx/UI/ViewModels/Input/KeyboardInputViewModel.cs b/src/Ryujinx/UI/ViewModels/Input/KeyboardInputViewModel.cs index 8f325e67c..bab8db7ce 100644 --- a/src/Ryujinx/UI/ViewModels/Input/KeyboardInputViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/Input/KeyboardInputViewModel.cs @@ -1,28 +1,11 @@ using Avalonia.Svg.Skia; using CommunityToolkit.Mvvm.ComponentModel; using Ryujinx.Ava.UI.Models.Input; -using Ryujinx.Input; -using System.Threading; -using System.Threading.Tasks; namespace Ryujinx.Ava.UI.ViewModels.Input { public partial class KeyboardInputViewModel : BaseModel { - private (float, float) _leftBuffer = (0, 0); - private (float, float) _rightBuffer = (0, 0); - private StickVisualizer _stickVisualizer; - public StickVisualizer StickVisualizer - { - get => _stickVisualizer; - set - { - _stickVisualizer = value; - - OnPropertyChanged(); - } - } - private KeyboardInputConfig _config; public KeyboardInputConfig Config { @@ -30,7 +13,18 @@ namespace Ryujinx.Ava.UI.ViewModels.Input set { _config = value; - StickVisualizer.UpdateConfig(_config); + + OnPropertyChanged(); + } + } + + private StickVisualizer _visualizer; + public StickVisualizer Visualizer + { + get => _visualizer; + set + { + _visualizer = value; OnPropertyChanged(); } @@ -66,70 +60,13 @@ namespace Ryujinx.Ava.UI.ViewModels.Input public readonly InputViewModel ParentModel; - public KeyboardInputViewModel(InputViewModel model, KeyboardInputConfig config) + public KeyboardInputViewModel(InputViewModel model, KeyboardInputConfig config, StickVisualizer visualizer) { ParentModel = model; + Visualizer = visualizer; model.NotifyChangesEvent += OnParentModelChanged; OnParentModelChanged(); - _stickVisualizer = new(); Config = config; - - StickVisualizer.PollToken = StickVisualizer.PollTokenSource.Token; - - Task.Run(() => PollKeyboard(StickVisualizer.PollToken)); - } - - private async Task PollKeyboard(CancellationToken token) - { - while (!token.IsCancellationRequested) - { - if (ParentModel.IsKeyboard) - { - IKeyboard keyboard = (IKeyboard)ParentModel.AvaloniaKeyboardDriver.GetGamepad("0"); - var snap = keyboard.GetKeyboardStateSnapshot(); - - if (snap.IsPressed((Key)Config.LeftStickRight)) - { - _leftBuffer.Item1 += 1; - } - if (snap.IsPressed((Key)Config.LeftStickLeft)) - { - _leftBuffer.Item1 -= 1; - } - if (snap.IsPressed((Key)Config.LeftStickUp)) - { - _leftBuffer.Item2 += 1; - } - if (snap.IsPressed((Key)Config.LeftStickDown)) - { - _leftBuffer.Item2 -= 1; - } - - if (snap.IsPressed((Key)Config.RightStickRight)) - { - _rightBuffer.Item1 += 1; - } - if (snap.IsPressed((Key)Config.RightStickLeft)) - { - _rightBuffer.Item1 -= 1; - } - if (snap.IsPressed((Key)Config.RightStickUp)) - { - _rightBuffer.Item2 += 1; - } - if (snap.IsPressed((Key)Config.RightStickDown)) - { - _rightBuffer.Item2 -= 1; - } - - StickVisualizer.UiStickLeft = _leftBuffer; - StickVisualizer.UiStickRight = _rightBuffer; - } - - await Task.Delay(StickVisualizer.DrawStickPollRate, token); - } - - StickVisualizer.PollTokenSource.Dispose(); } public void OnParentModelChanged() diff --git a/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml b/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml index 9740d9dcc..2c96d8cae 100644 --- a/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml +++ b/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml @@ -334,72 +334,72 @@ BorderBrush="{DynamicResource ThemeControlBorderColor}" BorderThickness="1" CornerRadius="5" - Height="{Binding StickVisualizer.UiStickBorderSize}" - Width="{Binding StickVisualizer.UiStickBorderSize}" + Height="{Binding Visualizer.UiStickBorderSize}" + Width="{Binding Visualizer.UiStickBorderSize}" IsVisible="{Binding IsLeft}"> + Height="{Binding Visualizer.UiCanvasSize}" + Width="{Binding Visualizer.UiCanvasSize}"> + Width="{Binding Visualizer.UiCanvasSize}" + Height="{Binding Visualizer.UiCanvasSize}"/> + Height="{Binding Visualizer.UiDeadzoneLeft}" + Width="{Binding Visualizer.UiDeadzoneLeft}"/> + Width="{Binding Visualizer.UiStickCircumference}" + Height="{Binding Visualizer.UiStickCircumference}" + Canvas.Bottom="{Binding Visualizer.UiStickLeftY}" + Canvas.Left="{Binding Visualizer.UiStickLeftX}" /> + Height="{Binding Visualizer.UiCanvasSize}" + Width="{Binding Visualizer.UiCanvasSize}"> + Width="{Binding Visualizer.UiCanvasSize}" + Height="{Binding Visualizer.UiCanvasSize}"/> + Height="{Binding Visualizer.UiDeadzoneRight}" + Width="{Binding Visualizer.UiDeadzoneRight}"/> + Width="{Binding Visualizer.UiStickCircumference}" + Height="{Binding Visualizer.UiStickCircumference}" + Canvas.Bottom="{Binding Visualizer.UiStickRightY}" + Canvas.Left="{Binding Visualizer.UiStickRightX}" /> diff --git a/src/Ryujinx/UI/Views/Input/KeyboardInputView.axaml b/src/Ryujinx/UI/Views/Input/KeyboardInputView.axaml index 2ffbce07f..afe0e7700 100644 --- a/src/Ryujinx/UI/Views/Input/KeyboardInputView.axaml +++ b/src/Ryujinx/UI/Views/Input/KeyboardInputView.axaml @@ -327,72 +327,60 @@ BorderBrush="{DynamicResource ThemeControlBorderColor}" BorderThickness="1" CornerRadius="5" - Height="{Binding StickVisualizer.UiStickBorderSize}" - Width="{Binding StickVisualizer.UiStickBorderSize}" + Height="{Binding Visualizer.UiStickBorderSize}" + Width="{Binding Visualizer.UiStickBorderSize}" IsVisible="{Binding IsLeft}"> + Height="{Binding Visualizer.UiCanvasSize}" + Width="{Binding Visualizer.UiCanvasSize}"> - + Width="{Binding Visualizer.UiCanvasSize}" + Height="{Binding Visualizer.UiCanvasSize}"/> + Width="{Binding Visualizer.UiStickCircumference}" + Height="{Binding Visualizer.UiStickCircumference}" + Canvas.Bottom="{Binding Visualizer.UiStickLeftY}" + Canvas.Left="{Binding Visualizer.UiStickLeftX}" /> + Height="{Binding Visualizer.UiCanvasSize}" + Width="{Binding Visualizer.UiCanvasSize}"> - + Width="{Binding Visualizer.UiCanvasSize}" + Height="{Binding Visualizer.UiCanvasSize}"/> + Width="{Binding Visualizer.UiStickCircumference}" + Height="{Binding Visualizer.UiStickCircumference}" + Canvas.Bottom="{Binding Visualizer.UiStickRightY}" + Canvas.Left="{Binding Visualizer.UiStickRightX}" /> -- 2.47.1 From 6a283190b38354b6e7c10139dfec691d927ebdac Mon Sep 17 00:00:00 2001 From: Evan Husted Date: Fri, 24 Jan 2025 22:24:02 -0600 Subject: [PATCH 13/17] Add the controller image back --- .../UI/Views/Input/ControllerInputView.axaml | 157 +++++++++--------- src/Ryujinx/UI/Windows/SettingsWindow.axaml | 2 +- 2 files changed, 83 insertions(+), 76 deletions(-) diff --git a/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml b/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml index 2c96d8cae..7bb71b960 100644 --- a/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml +++ b/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml @@ -325,90 +325,97 @@ CornerRadius="5" Margin="0,10" MinHeight="90"> - - - - + + + + - + + Background="{DynamicResource ThemeBackgroundColor}"> + + + - - - - - - - + + + - + + Background="{DynamicResource ThemeBackgroundColor}"> + + + - - - - + + + - + + CornerRadius="5"> @@ -427,8 +434,8 @@ Minimum="0" Value="{Binding Config.TriggerThreshold, Mode=TwoWay}" /> + Width="25" + Text="{Binding Config.TriggerThreshold, StringFormat=\{0:0.00\}}" /> - Date: Sun, 2 Mar 2025 16:04:35 -0600 Subject: [PATCH 14/17] Restyle stick visualizer --- .../UI/Views/Input/ControllerInputView.axaml | 22 ++++++++----------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml b/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml index c592c2b14..1d34f9fa9 100644 --- a/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml +++ b/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml @@ -320,7 +320,7 @@ BorderBrush="{DynamicResource ThemeControlBorderColor}" BorderThickness="1" CornerRadius="5" - Margin="0,10" + Margin="0,5" MinHeight="90"> @@ -351,19 +349,19 @@ Background="{DynamicResource ThemeBackgroundColor}"> @@ -387,19 +383,19 @@ Background="{DynamicResource ThemeBackgroundColor}"> Date: Sun, 2 Mar 2025 16:10:43 -0600 Subject: [PATCH 15/17] optimize spacing --- src/Ryujinx/UI/Views/Input/ControllerInputView.axaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml b/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml index 1d34f9fa9..b1ab7ad3f 100644 --- a/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml +++ b/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml @@ -320,7 +320,7 @@ BorderBrush="{DynamicResource ThemeControlBorderColor}" BorderThickness="1" CornerRadius="5" - Margin="0,5" + Margin="0,0, 0, 5" MinHeight="90"> -- 2.47.1 From e8071e9c43e9ebbf96fe20ada5610481e18fc550 Mon Sep 17 00:00:00 2001 From: Evan Husted Date: Sun, 2 Mar 2025 16:10:58 -0600 Subject: [PATCH 16/17] slight settings window default height bump --- src/Ryujinx/UI/Windows/SettingsWindow.axaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Ryujinx/UI/Windows/SettingsWindow.axaml b/src/Ryujinx/UI/Windows/SettingsWindow.axaml index a2b2519a1..54ca4cbbd 100644 --- a/src/Ryujinx/UI/Windows/SettingsWindow.axaml +++ b/src/Ryujinx/UI/Windows/SettingsWindow.axaml @@ -12,7 +12,7 @@ xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers" xmlns:helper="clr-namespace:Ryujinx.Common.Helper;assembly=Ryujinx.Common" Width="1100" - Height="918" + Height="927" MinWidth="800" MinHeight="480" WindowStartupLocation="CenterOwner" -- 2.47.1 From 5a3eac99d6c26e6cf4c82bc523cc2a5624bd0cab Mon Sep 17 00:00:00 2001 From: Evan Husted Date: Sun, 2 Mar 2025 17:50:40 -0600 Subject: [PATCH 17/17] change all grid RowDefinitions/ColumnDefinitions to direct property setters --- .../UI/Applet/ProfileSelectorDialog.axaml | 8 +--- .../UI/Controls/ApplicationGridView.axaml | 11 +---- .../UI/Controls/ApplicationListView.axaml | 5 +-- .../UI/Controls/UpdateWaitWindow.axaml | 10 +---- .../UI/Views/Input/ControllerInputView.axaml | 45 +++---------------- src/Ryujinx/UI/Views/Input/InputView.axaml | 42 +++-------------- .../UI/Views/Input/KeyboardInputView.axaml | 27 ++--------- .../UI/Views/Input/MotionInputView.axaml | 22 ++------- .../UI/Views/Input/RumbleInputView.axaml | 6 +-- .../UI/Views/Settings/SettingsInputView.axaml | 7 +-- .../UI/Views/Settings/SettingsUIView.axaml | 14 +----- .../UI/Views/User/UserEditorView.axaml | 10 +---- .../User/UserFirmwareAvatarSelectorView.axaml | 8 +--- .../User/UserProfileImageSelectorView.axaml | 7 +-- .../UI/Views/User/UserRecovererView.axaml | 12 +---- .../UI/Views/User/UserSaveManagerView.axaml | 25 ++--------- .../UI/Views/User/UserSelectorView.axaml | 6 +-- .../Windows/GameSpecificSettingsWindow.axaml | 16 +++---- src/Ryujinx/UI/Windows/ModManagerWindow.axaml | 6 +-- src/Ryujinx/UI/Windows/XCITrimmerWindow.axaml | 44 +++--------------- 20 files changed, 50 insertions(+), 281 deletions(-) diff --git a/src/Ryujinx/UI/Applet/ProfileSelectorDialog.axaml b/src/Ryujinx/UI/Applet/ProfileSelectorDialog.axaml index d929cc501..20d466031 100644 --- a/src/Ryujinx/UI/Applet/ProfileSelectorDialog.axaml +++ b/src/Ryujinx/UI/Applet/ProfileSelectorDialog.axaml @@ -17,12 +17,8 @@ - - - - - - + + - - - - + - - - - - + - - - - + - - - - - - - - + VerticalAlignment="Stretch" ColumnDefinitions="Auto,*" RowDefinitions="Auto,Auto"> - - - - - + MinHeight="450" ColumnDefinitions="Auto,*,Auto"> - - - - - - - - + HorizontalAlignment="Stretch" ColumnDefinitions="*,*" RowDefinitions="*,*"> - - - - - + - - - - - + - - - - - + - - - - - - - - + HorizontalAlignment="Stretch" ColumnDefinitions="*,*" RowDefinitions="*,*"> - - - - - - + - - - - + VerticalAlignment="Center" ColumnDefinitions="Auto,*"> - - - - - - - + VerticalAlignment="Center" ColumnDefinitions="Auto,*,Auto,Auto,Auto"> - - - - - - + - - - - - + HorizontalAlignment="Stretch" ColumnDefinitions="Auto,*,Auto"> - - - - + VerticalAlignment="Center" ColumnDefinitions="Auto,*"> - - - - - + MinHeight="450" ColumnDefinitions="Auto,*,Auto"> - - - - - - - - + HorizontalAlignment="Stretch" ColumnDefinitions="*,*" RowDefinitions="*,*"> - - - - - - - - + HorizontalAlignment="Stretch" ColumnDefinitions="*,*" RowDefinitions="*,*"> - - - - - + - - - - - + - - - - - - - - - + - - - - - + - - - - - - + diff --git a/src/Ryujinx/UI/Views/Settings/SettingsUIView.axaml b/src/Ryujinx/UI/Views/Settings/SettingsUIView.axaml index 2a46dcf49..7dd5211a7 100644 --- a/src/Ryujinx/UI/Views/Settings/SettingsUIView.axaml +++ b/src/Ryujinx/UI/Views/Settings/SettingsUIView.axaml @@ -177,12 +177,7 @@ - - - - - - + - - - - - - + - - - - - - - - - + - - - - - - + VerticalAlignment="Stretch" RowDefinitions="Auto,*,Auto,Auto"> - - - - - + VerticalAlignment="Center" RowDefinitions="Auto,70,Auto"> - - - - + VerticalAlignment="Stretch" RowDefinitions="*,Auto"> - - - - - + - - - - - - + - - - - + HorizontalAlignment="Stretch" ColumnDefinitions="Auto,*"> - - - - + Margin="10,0, 0, 0" ColumnDefinitions="Auto,*">