diff options
| author | Exhigh <exhigh01@gmail.com> | 2024-04-29 04:51:08 +0530 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-04-28 20:21:08 -0300 |
| commit | 56c5dbe5572190df3cb176955c50afe9724c2f56 (patch) | |
| tree | 46c25abc33de6059233248b8afb0d5e040fa9383 /src | |
| parent | 5976a5161b850e4082d6f354a1be6b153547590a (diff) | |
Fix Cursor States On Windows (#6725)
* [Ava]: Fix Cursor States On Windows
It's been sometime since the last PR #5415 was made and last time i was waiting for Ava 11 to be merged before re-writing the code and along the way forgot about the PR.
Anyway this PR supersedes both #5288 and #5415, and fixes issue: #5136
* Now, the bounds for which the cursor should be detected in renderer should be accurate to any scaling / resolution, taking into account the status and the menu bar. ( This issue was partially resolved by #6450 )
* Reduced the number of times the cursor updates from per frame update to updating only when the cursor state needs to be changed.
* Fixed the issue wherein you weren't able to resize the window, because of the cursor passthrough which caused the cursor to reset from the reset icon or flicker.
* Fixed the issue caused by #6450 which caused the cursor to disappear over the submenus while cursor was set to always hide.
* Changed the cursor state to not disappear while the game is being loaded. ( Needs Feedback ).
* Removed an unused library import.
* PR feedback
* Fix excessive line breaks and whitespaces and other feedback
* Add a check before calculating cursor idle time, such that it calculates only while the cursor mode is OnIdle.
* PR Feedback
* Rework the cursor state check code block
Co-Authored-By: gdkchan <5624669+gdkchan@users.noreply.github.com>
* PR Feedback
* A simpler version of the previous implementation.
Co-Authored-By: gdkchan <5624669+gdkchan@users.noreply.github.com>
* PR Feedback
* PR Feedback
---------
Co-authored-by: gdkchan <5624669+gdkchan@users.noreply.github.com>
Diffstat (limited to 'src')
| -rw-r--r-- | src/Ryujinx/AppHost.cs | 116 | ||||
| -rw-r--r-- | src/Ryujinx/UI/Helpers/Win32NativeInterop.cs | 3 | ||||
| -rw-r--r-- | src/Ryujinx/UI/Renderer/EmbeddedWindow.cs | 2 | ||||
| -rw-r--r-- | src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs | 12 | ||||
| -rw-r--r-- | src/Ryujinx/UI/Views/Main/MainMenuBarView.axaml | 5 | ||||
| -rw-r--r-- | src/Ryujinx/UI/Windows/MainWindow.axaml.cs | 7 |
6 files changed, 108 insertions, 37 deletions
diff --git a/src/Ryujinx/AppHost.cs b/src/Ryujinx/AppHost.cs index 43e7a79e..d405f320 100644 --- a/src/Ryujinx/AppHost.cs +++ b/src/Ryujinx/AppHost.cs @@ -94,6 +94,17 @@ namespace Ryujinx.Ava private long _lastCursorMoveTime; private bool _isCursorInRenderer = true; + private bool _ignoreCursorState = false; + + private enum CursorStates + { + CursorIsHidden, + CursorIsVisible, + ForceChangeCursor + }; + + private CursorStates _cursorState = !ConfigurationState.Instance.Hid.EnableMouse.Value ? + CursorStates.CursorIsVisible : CursorStates.CursorIsHidden; private bool _isStopped; private bool _isActive; @@ -201,23 +212,65 @@ namespace Ryujinx.Ava private void TopLevel_PointerEnteredOrMoved(object sender, PointerEventArgs e) { + if (!_viewModel.IsActive) + { + _isCursorInRenderer = false; + _ignoreCursorState = false; + return; + } + if (sender is MainWindow window) { - _lastCursorMoveTime = Stopwatch.GetTimestamp(); + if (ConfigurationState.Instance.HideCursor.Value == HideCursorMode.OnIdle) + { + _lastCursorMoveTime = Stopwatch.GetTimestamp(); + } var point = e.GetCurrentPoint(window).Position; var bounds = RendererHost.EmbeddedWindow.Bounds; + var windowYOffset = bounds.Y + window.MenuBarHeight; + var windowYLimit = (int)window.Bounds.Height - window.StatusBarHeight - 1; + + if (!_viewModel.ShowMenuAndStatusBar) + { + windowYOffset -= window.MenuBarHeight; + windowYLimit += window.StatusBarHeight + 1; + } _isCursorInRenderer = point.X >= bounds.X && - point.X <= bounds.Width + bounds.X && - point.Y >= bounds.Y && - point.Y <= bounds.Height + bounds.Y; + Math.Ceiling(point.X) <= (int)window.Bounds.Width && + point.Y >= windowYOffset && + point.Y <= windowYLimit && + !_viewModel.IsSubMenuOpen; + + _ignoreCursorState = false; } } private void TopLevel_PointerExited(object sender, PointerEventArgs e) { _isCursorInRenderer = false; + + if (sender is MainWindow window) + { + var point = e.GetCurrentPoint(window).Position; + var bounds = RendererHost.EmbeddedWindow.Bounds; + var windowYOffset = bounds.Y + window.MenuBarHeight; + var windowYLimit = (int)window.Bounds.Height - window.StatusBarHeight - 1; + + if (!_viewModel.ShowMenuAndStatusBar) + { + windowYOffset -= window.MenuBarHeight; + windowYLimit += window.StatusBarHeight + 1; + } + + _ignoreCursorState = (point.X == bounds.X || + Math.Ceiling(point.X) == (int)window.Bounds.Width) && + point.Y >= windowYOffset && + point.Y <= windowYLimit; + } + + _cursorState = CursorStates.ForceChangeCursor; } private void UpdateScalingFilterLevel(object sender, ReactiveEventArgs<int> e) @@ -245,9 +298,14 @@ namespace Ryujinx.Ava if (OperatingSystem.IsWindows()) { - SetCursor(_defaultCursorWin); + if (_cursorState != CursorStates.CursorIsHidden && !_ignoreCursorState) + { + SetCursor(_defaultCursorWin); + } } }); + + _cursorState = CursorStates.CursorIsVisible; } private void HideCursor() @@ -261,6 +319,8 @@ namespace Ryujinx.Ava SetCursor(_invisibleCursorWin); } }); + + _cursorState = CursorStates.CursorIsHidden; } private void SetRendererWindowSize(Size size) @@ -523,6 +583,8 @@ namespace Ryujinx.Ava { _lastCursorMoveTime = Stopwatch.GetTimestamp(); } + + _cursorState = CursorStates.ForceChangeCursor; } public async Task<bool> LoadGuestApplication() @@ -1037,38 +1099,32 @@ namespace Ryujinx.Ava if (_viewModel.IsActive) { - if (_isCursorInRenderer) + bool isCursorVisible = true; + + if (_isCursorInRenderer && !_viewModel.ShowLoadProgress) { - if (ConfigurationState.Instance.Hid.EnableMouse) + if (ConfigurationState.Instance.Hid.EnableMouse.Value) { - HideCursor(); + isCursorVisible = ConfigurationState.Instance.HideCursor.Value == HideCursorMode.Never; } else { - switch (ConfigurationState.Instance.HideCursor.Value) - { - case HideCursorMode.Never: - ShowCursor(); - break; - case HideCursorMode.OnIdle: - if (Stopwatch.GetTimestamp() - _lastCursorMoveTime >= CursorHideIdleTime * Stopwatch.Frequency) - { - HideCursor(); - } - else - { - ShowCursor(); - } - break; - case HideCursorMode.Always: - HideCursor(); - break; - } + isCursorVisible = ConfigurationState.Instance.HideCursor.Value == HideCursorMode.Never || + (ConfigurationState.Instance.HideCursor.Value == HideCursorMode.OnIdle && + Stopwatch.GetTimestamp() - _lastCursorMoveTime < CursorHideIdleTime * Stopwatch.Frequency); } } - else + + if (_cursorState != (isCursorVisible ? CursorStates.CursorIsVisible : CursorStates.CursorIsHidden)) { - ShowCursor(); + if (isCursorVisible) + { + ShowCursor(); + } + else + { + HideCursor(); + } } Dispatcher.UIThread.Post(() => @@ -1154,7 +1210,7 @@ namespace Ryujinx.Ava // Touchscreen. bool hasTouch = false; - if (_viewModel.IsActive && !ConfigurationState.Instance.Hid.EnableMouse) + if (_viewModel.IsActive && !ConfigurationState.Instance.Hid.EnableMouse.Value) { hasTouch = TouchScreenManager.Update(true, (_inputManager.MouseDriver as AvaloniaMouseDriver).IsButtonPressed(MouseButton.Button1), ConfigurationState.Instance.Graphics.AspectRatio.Value.ToFloat()); } diff --git a/src/Ryujinx/UI/Helpers/Win32NativeInterop.cs b/src/Ryujinx/UI/Helpers/Win32NativeInterop.cs index fce2d518..01478cb3 100644 --- a/src/Ryujinx/UI/Helpers/Win32NativeInterop.cs +++ b/src/Ryujinx/UI/Helpers/Win32NativeInterop.cs @@ -111,8 +111,5 @@ namespace Ryujinx.Ava.UI.Helpers [LibraryImport("user32.dll", SetLastError = true)] public static partial IntPtr SetWindowLongPtrW(IntPtr hWnd, int nIndex, IntPtr value); - - [LibraryImport("user32.dll", SetLastError = true)] - public static partial IntPtr SetWindowLongW(IntPtr hWnd, int nIndex, int value); } } diff --git a/src/Ryujinx/UI/Renderer/EmbeddedWindow.cs b/src/Ryujinx/UI/Renderer/EmbeddedWindow.cs index 8c5e31ff..0930e779 100644 --- a/src/Ryujinx/UI/Renderer/EmbeddedWindow.cs +++ b/src/Ryujinx/UI/Renderer/EmbeddedWindow.cs @@ -157,7 +157,7 @@ namespace Ryujinx.Ava.UI.Renderer lpfnWndProc = Marshal.GetFunctionPointerForDelegate(_wndProcDelegate), style = ClassStyles.CsOwndc, lpszClassName = Marshal.StringToHGlobalUni(_className), - hCursor = CreateArrowCursor(), + hCursor = CreateArrowCursor() }; RegisterClassEx(ref wndClassEx); diff --git a/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs b/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs index 130e708c..549eebf1 100644 --- a/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs @@ -104,6 +104,7 @@ namespace Ryujinx.Ava.UI.ViewModels private double _windowHeight; private bool _isActive; + private bool _isSubMenuOpen; public ApplicationData ListSelectedApplication; public ApplicationData GridSelectedApplication; @@ -317,6 +318,17 @@ namespace Ryujinx.Ava.UI.ViewModels } } + public bool IsSubMenuOpen + { + get => _isSubMenuOpen; + set + { + _isSubMenuOpen = value; + + OnPropertyChanged(); + } + } + public bool ShowAll { get => _showAll; diff --git a/src/Ryujinx/UI/Views/Main/MainMenuBarView.axaml b/src/Ryujinx/UI/Views/Main/MainMenuBarView.axaml index 30358ada..ea432f78 100644 --- a/src/Ryujinx/UI/Views/Main/MainMenuBarView.axaml +++ b/src/Ryujinx/UI/Views/Main/MainMenuBarView.axaml @@ -1,4 +1,4 @@ -<UserControl +<UserControl xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" @@ -16,7 +16,8 @@ Name="Menu" Height="35" Margin="0" - HorizontalAlignment="Left"> + HorizontalAlignment="Left" + IsOpen="{Binding IsSubMenuOpen, Mode=OneWayToSource}"> <Menu.ItemsPanel> <ItemsPanelTemplate> <DockPanel Margin="0" HorizontalAlignment="Stretch" /> diff --git a/src/Ryujinx/UI/Windows/MainWindow.axaml.cs b/src/Ryujinx/UI/Windows/MainWindow.axaml.cs index 37e2e71a..eebbb81f 100644 --- a/src/Ryujinx/UI/Windows/MainWindow.axaml.cs +++ b/src/Ryujinx/UI/Windows/MainWindow.axaml.cs @@ -56,6 +56,9 @@ namespace Ryujinx.Ava.UI.Windows public static bool ShowKeyErrorOnLoad { get; set; } public ApplicationLibrary ApplicationLibrary { get; set; } + public readonly double StatusBarHeight; + public readonly double MenuBarHeight; + public MainWindow() { ViewModel = new MainWindowViewModel(); @@ -74,7 +77,9 @@ namespace Ryujinx.Ava.UI.Windows ViewModel.Title = $"Ryujinx {Program.Version}"; // NOTE: Height of MenuBar and StatusBar is not usable here, since it would still be 0 at this point. - double barHeight = MenuBar.MinHeight + StatusBarView.StatusBar.MinHeight; + StatusBarHeight = StatusBarView.StatusBar.MinHeight; + MenuBarHeight = MenuBar.MinHeight; + double barHeight = MenuBarHeight + StatusBarHeight; Height = ((Height - barHeight) / Program.WindowScaleFactor) + barHeight; Width /= Program.WindowScaleFactor; |
