aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorExhigh <exhigh01@gmail.com>2024-04-29 04:51:08 +0530
committerGitHub <noreply@github.com>2024-04-28 20:21:08 -0300
commit56c5dbe5572190df3cb176955c50afe9724c2f56 (patch)
tree46c25abc33de6059233248b8afb0d5e040fa9383 /src
parent5976a5161b850e4082d6f354a1be6b153547590a (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.cs116
-rw-r--r--src/Ryujinx/UI/Helpers/Win32NativeInterop.cs3
-rw-r--r--src/Ryujinx/UI/Renderer/EmbeddedWindow.cs2
-rw-r--r--src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs12
-rw-r--r--src/Ryujinx/UI/Views/Main/MainMenuBarView.axaml5
-rw-r--r--src/Ryujinx/UI/Windows/MainWindow.axaml.cs7
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;