diff --git a/src/Ryujinx.Ava/AppHost.cs b/src/Ryujinx.Ava/AppHost.cs index 957a1c9d3..e11a954d8 100644 --- a/src/Ryujinx.Ava/AppHost.cs +++ b/src/Ryujinx.Ava/AppHost.cs @@ -157,7 +157,7 @@ namespace Ryujinx.Ava _isFirmwareTitle = true; } - ConfigurationState.Instance.HideCursorOnIdle.Event += HideCursorState_Changed; + ConfigurationState.Instance.HideCursor.Event += HideCursorState_Changed; _topLevel.PointerMoved += TopLevel_PointerMoved; @@ -468,9 +468,9 @@ namespace Ryujinx.Ava (_rendererHost.EmbeddedWindow as EmbeddedWindowOpenGL)?.MakeCurrent(null); } - private void HideCursorState_Changed(object sender, ReactiveEventArgs<bool> state) + private void HideCursorState_Changed(object sender, ReactiveEventArgs<HideCursorMode> state) { - if (state.NewValue) + if (state.NewValue == HideCursorMode.OnIdle) { _lastCursorMoveTime = Stopwatch.GetTimestamp(); } @@ -965,30 +965,38 @@ namespace Ryujinx.Ava if (_viewModel.IsActive) { - if (ConfigurationState.Instance.Hid.EnableMouse) + if (_isCursorInRenderer) { - if (_isCursorInRenderer) + if (ConfigurationState.Instance.Hid.EnableMouse) { HideCursor(); } else { - ShowCursor(); + 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; + } } } else { - if (ConfigurationState.Instance.HideCursorOnIdle) - { - if (Stopwatch.GetTimestamp() - _lastCursorMoveTime >= CursorHideIdleTime * Stopwatch.Frequency) - { - HideCursor(); - } - else - { - ShowCursor(); - } - } + ShowCursor(); } Dispatcher.UIThread.Post(() => @@ -1133,4 +1141,4 @@ namespace Ryujinx.Ava return state; } } -} +} \ No newline at end of file diff --git a/src/Ryujinx.Ava/Assets/Locales/en_US.json b/src/Ryujinx.Ava/Assets/Locales/en_US.json index 3a4bfc65e..617cad34f 100644 --- a/src/Ryujinx.Ava/Assets/Locales/en_US.json +++ b/src/Ryujinx.Ava/Assets/Locales/en_US.json @@ -80,7 +80,10 @@ "SettingsTabGeneralEnableDiscordRichPresence": "Enable Discord Rich Presence", "SettingsTabGeneralCheckUpdatesOnLaunch": "Check for Updates on Launch", "SettingsTabGeneralShowConfirmExitDialog": "Show \"Confirm Exit\" Dialog", - "SettingsTabGeneralHideCursorOnIdle": "Hide Cursor on Idle", + "SettingsTabGeneralHideCursor": "Hide Cursor:", + "SettingsTabGeneralHideCursorNever": "Never", + "SettingsTabGeneralHideCursorOnIdle": "On Idle", + "SettingsTabGeneralHideCursorAlways": "Always", "SettingsTabGeneralGameDirectories": "Game Directories", "SettingsTabGeneralAdd": "Add", "SettingsTabGeneralRemove": "Remove", diff --git a/src/Ryujinx.Ava/Program.cs b/src/Ryujinx.Ava/Program.cs index 7f35c62a4..0629e6062 100644 --- a/src/Ryujinx.Ava/Program.cs +++ b/src/Ryujinx.Ava/Program.cs @@ -183,6 +183,18 @@ namespace Ryujinx.Ava { ConfigurationState.Instance.System.EnableDockedMode.Value = CommandLineState.OverrideDockedMode.Value; } + + // Check if HideCursor was overridden. + if (CommandLineState.OverrideHideCursor is not null) + { + ConfigurationState.Instance.HideCursor.Value = CommandLineState.OverrideHideCursor!.ToLower() switch + { + "never" => HideCursorMode.Never, + "onidle" => HideCursorMode.OnIdle, + "always" => HideCursorMode.Always, + _ => ConfigurationState.Instance.HideCursor.Value + }; + } } private static void PrintSystemInfo() @@ -226,4 +238,4 @@ namespace Ryujinx.Ava Logger.Shutdown(); } } -} +} \ No newline at end of file diff --git a/src/Ryujinx.Ava/UI/ViewModels/SettingsViewModel.cs b/src/Ryujinx.Ava/UI/ViewModels/SettingsViewModel.cs index 232c9d436..08612117a 100644 --- a/src/Ryujinx.Ava/UI/ViewModels/SettingsViewModel.cs +++ b/src/Ryujinx.Ava/UI/ViewModels/SettingsViewModel.cs @@ -132,7 +132,7 @@ namespace Ryujinx.Ava.UI.ViewModels public bool EnableDiscordIntegration { get; set; } public bool CheckUpdatesOnStart { get; set; } public bool ShowConfirmExit { get; set; } - public bool HideCursorOnIdle { get; set; } + public int HideCursor { get; set; } public bool EnableDockedMode { get; set; } public bool EnableKeyboard { get; set; } public bool EnableMouse { get; set; } @@ -375,7 +375,7 @@ namespace Ryujinx.Ava.UI.ViewModels EnableDiscordIntegration = config.EnableDiscordIntegration; CheckUpdatesOnStart = config.CheckUpdatesOnStart; ShowConfirmExit = config.ShowConfirmExit; - HideCursorOnIdle = config.HideCursorOnIdle; + HideCursor = (int)config.HideCursor.Value; GameDirectories.Clear(); GameDirectories.AddRange(config.Ui.GameDirs.Value); @@ -458,7 +458,7 @@ namespace Ryujinx.Ava.UI.ViewModels config.EnableDiscordIntegration.Value = EnableDiscordIntegration; config.CheckUpdatesOnStart.Value = CheckUpdatesOnStart; config.ShowConfirmExit.Value = ShowConfirmExit; - config.HideCursorOnIdle.Value = HideCursorOnIdle; + config.HideCursor.Value = (HideCursorMode)HideCursor; if (_directoryChanged) { diff --git a/src/Ryujinx.Ava/UI/Views/Settings/SettingsUIView.axaml b/src/Ryujinx.Ava/UI/Views/Settings/SettingsUIView.axaml index 61b6c4335..acc5e2b70 100644 --- a/src/Ryujinx.Ava/UI/Views/Settings/SettingsUIView.axaml +++ b/src/Ryujinx.Ava/UI/Views/Settings/SettingsUIView.axaml @@ -1,4 +1,4 @@ -<UserControl +<UserControl x:Class="Ryujinx.Ava.UI.Views.Settings.SettingsUIView" xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" @@ -12,7 +12,7 @@ <Design.DataContext> <viewModels:SettingsViewModel /> </Design.DataContext> - <ScrollViewer + <ScrollViewer Name="UiPage" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" @@ -37,9 +37,24 @@ <CheckBox IsChecked="{Binding ShowConfirmExit}"> <TextBlock Text="{locale:Locale SettingsTabGeneralShowConfirmExitDialog}" /> </CheckBox> - <CheckBox IsChecked="{Binding HideCursorOnIdle}"> - <TextBlock Text="{locale:Locale SettingsTabGeneralHideCursorOnIdle}" /> - </CheckBox> + <StackPanel Margin="0, 15, 0, 10" Orientation="Horizontal"> + <TextBlock VerticalAlignment="Center" + Text="{locale:Locale SettingsTabGeneralHideCursor}" + Width="150" /> + <ComboBox SelectedIndex="{Binding HideCursor}" + HorizontalContentAlignment="Left" + MinWidth="100"> + <ComboBoxItem> + <TextBlock Text="{locale:Locale SettingsTabGeneralHideCursorNever}" /> + </ComboBoxItem> + <ComboBoxItem> + <TextBlock Text="{locale:Locale SettingsTabGeneralHideCursorOnIdle}" /> + </ComboBoxItem> + <ComboBoxItem> + <TextBlock Text="{locale:Locale SettingsTabGeneralHideCursorAlways}" /> + </ComboBoxItem> + </ComboBox> + </StackPanel> </StackPanel> <Separator Height="1" /> <TextBlock Classes="h1" Text="{locale:Locale SettingsTabGeneralGameDirectories}" /> @@ -105,7 +120,7 @@ <RowDefinition /> <RowDefinition /> </Grid.RowDefinitions> - <CheckBox + <CheckBox IsChecked="{Binding EnableCustomTheme}" ToolTip.Tip="{locale:Locale CustomThemeCheckTooltip}"> <TextBlock Text="{locale:Locale SettingsTabGeneralThemeEnableCustomTheme}" /> @@ -122,7 +137,7 @@ Grid.Column="1" Margin="0,10,0,0" Text="{Binding CustomThemePath}" /> - <Button + <Button Grid.Row="1" Grid.Column="2" Margin="10,10,0,0" @@ -153,4 +168,4 @@ </StackPanel> </Border> </ScrollViewer> -</UserControl> \ No newline at end of file +</UserControl> diff --git a/src/Ryujinx.Common/Configuration/HideCursorMode.cs b/src/Ryujinx.Common/Configuration/HideCursorMode.cs new file mode 100644 index 000000000..895fc1076 --- /dev/null +++ b/src/Ryujinx.Common/Configuration/HideCursorMode.cs @@ -0,0 +1,9 @@ +namespace Ryujinx.Common.Configuration +{ + public enum HideCursorMode + { + Never, + OnIdle, + Always + } +} \ No newline at end of file diff --git a/src/Ryujinx.Headless.SDL2/HideCursor.cs b/src/Ryujinx.Headless.SDL2/HideCursor.cs deleted file mode 100644 index 2dc0bd6ab..000000000 --- a/src/Ryujinx.Headless.SDL2/HideCursor.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ryujinx.Headless.SDL2 -{ - public enum HideCursor - { - Never, - OnIdle, - Always - } -} \ No newline at end of file diff --git a/src/Ryujinx.Headless.SDL2/OpenGL/OpenGLWindow.cs b/src/Ryujinx.Headless.SDL2/OpenGL/OpenGLWindow.cs index 69b0f42fb..dc7d811b9 100644 --- a/src/Ryujinx.Headless.SDL2/OpenGL/OpenGLWindow.cs +++ b/src/Ryujinx.Headless.SDL2/OpenGL/OpenGLWindow.cs @@ -107,8 +107,8 @@ namespace Ryujinx.Headless.SDL2.OpenGL GraphicsDebugLevel glLogLevel, AspectRatio aspectRatio, bool enableMouse, - HideCursor hideCursor) - : base(inputManager, glLogLevel, aspectRatio, enableMouse, hideCursor) + HideCursorMode hideCursorMode) + : base(inputManager, glLogLevel, aspectRatio, enableMouse, hideCursorMode) { _glLogLevel = glLogLevel; } diff --git a/src/Ryujinx.Headless.SDL2/Options.cs b/src/Ryujinx.Headless.SDL2/Options.cs index 982d09909..7dffa1b00 100644 --- a/src/Ryujinx.Headless.SDL2/Options.cs +++ b/src/Ryujinx.Headless.SDL2/Options.cs @@ -76,8 +76,8 @@ namespace Ryujinx.Headless.SDL2 [Option("enable-mouse", Required = false, Default = false, HelpText = "Enable or disable mouse support.")] public bool EnableMouse { get; set; } - [Option("hide-cursor", Required = false, Default = HideCursor.OnIdle, HelpText = "Change when the cursor gets hidden.")] - public HideCursor HideCursor { get; set; } + [Option("hide-cursor", Required = false, Default = HideCursorMode.OnIdle, HelpText = "Change when the cursor gets hidden.")] + public HideCursorMode HideCursorMode { get; set; } [Option("list-input-profiles", Required = false, HelpText = "List inputs profiles.")] public bool ListInputProfiles { get; set; } diff --git a/src/Ryujinx.Headless.SDL2/Program.cs b/src/Ryujinx.Headless.SDL2/Program.cs index b0bdb97f1..453c470e7 100644 --- a/src/Ryujinx.Headless.SDL2/Program.cs +++ b/src/Ryujinx.Headless.SDL2/Program.cs @@ -478,8 +478,8 @@ namespace Ryujinx.Headless.SDL2 private static WindowBase CreateWindow(Options options) { return options.GraphicsBackend == GraphicsBackend.Vulkan - ? new VulkanWindow(_inputManager, options.LoggingGraphicsDebugLevel, options.AspectRatio, options.EnableMouse, options.HideCursor) - : new OpenGLWindow(_inputManager, options.LoggingGraphicsDebugLevel, options.AspectRatio, options.EnableMouse, options.HideCursor); + ? new VulkanWindow(_inputManager, options.LoggingGraphicsDebugLevel, options.AspectRatio, options.EnableMouse, options.HideCursorMode) + : new OpenGLWindow(_inputManager, options.LoggingGraphicsDebugLevel, options.AspectRatio, options.EnableMouse, options.HideCursorMode); } private static IRenderer CreateRenderer(Options options, WindowBase window) diff --git a/src/Ryujinx.Headless.SDL2/SDL2MouseDriver.cs b/src/Ryujinx.Headless.SDL2/SDL2MouseDriver.cs index 8c3412ff9..7b88e2655 100644 --- a/src/Ryujinx.Headless.SDL2/SDL2MouseDriver.cs +++ b/src/Ryujinx.Headless.SDL2/SDL2MouseDriver.cs @@ -1,4 +1,5 @@ -using Ryujinx.Input; +using Ryujinx.Common.Configuration; +using Ryujinx.Input; using System; using System.Diagnostics; using System.Drawing; @@ -13,7 +14,7 @@ namespace Ryujinx.Headless.SDL2 private const int CursorHideIdleTime = 5; // seconds private bool _isDisposed; - private HideCursor _hideCursor; + private HideCursorMode _hideCursorMode; private bool _isHidden; private long _lastCursorMoveTime; @@ -23,12 +24,12 @@ namespace Ryujinx.Headless.SDL2 public Vector2 Scroll { get; private set; } public Size _clientSize; - public SDL2MouseDriver(HideCursor hideCursor) + public SDL2MouseDriver(HideCursorMode hideCursorMode) { PressedButtons = new bool[(int)MouseButton.Count]; - _hideCursor = hideCursor; + _hideCursorMode = hideCursorMode; - if (_hideCursor == HideCursor.Always) + if (_hideCursorMode == HideCursorMode.Always) { SDL_ShowCursor(SDL_DISABLE); _isHidden = true; @@ -59,7 +60,7 @@ namespace Ryujinx.Headless.SDL2 private void CheckIdle() { - if (_hideCursor != HideCursor.OnIdle) + if (_hideCursorMode != HideCursorMode.OnIdle) { return; } diff --git a/src/Ryujinx.Headless.SDL2/Vulkan/VulkanWindow.cs b/src/Ryujinx.Headless.SDL2/Vulkan/VulkanWindow.cs index 172b7685a..5d048da1f 100644 --- a/src/Ryujinx.Headless.SDL2/Vulkan/VulkanWindow.cs +++ b/src/Ryujinx.Headless.SDL2/Vulkan/VulkanWindow.cs @@ -17,8 +17,8 @@ namespace Ryujinx.Headless.SDL2.Vulkan GraphicsDebugLevel glLogLevel, AspectRatio aspectRatio, bool enableMouse, - HideCursor hideCursor) - : base(inputManager, glLogLevel, aspectRatio, enableMouse, hideCursor) + HideCursorMode hideCursorMode) + : base(inputManager, glLogLevel, aspectRatio, enableMouse, hideCursorMode) { _glLogLevel = glLogLevel; } diff --git a/src/Ryujinx.Headless.SDL2/WindowBase.cs b/src/Ryujinx.Headless.SDL2/WindowBase.cs index e33710421..7c3101535 100644 --- a/src/Ryujinx.Headless.SDL2/WindowBase.cs +++ b/src/Ryujinx.Headless.SDL2/WindowBase.cs @@ -78,9 +78,9 @@ namespace Ryujinx.Headless.SDL2 GraphicsDebugLevel glLogLevel, AspectRatio aspectRatio, bool enableMouse, - HideCursor hideCursor) + HideCursorMode hideCursorMode) { - MouseDriver = new SDL2MouseDriver(hideCursor); + MouseDriver = new SDL2MouseDriver(hideCursorMode); _inputManager = inputManager; _inputManager.SetMouseDriver(MouseDriver); NpadManager = _inputManager.CreateNpadManager(); diff --git a/src/Ryujinx.Ui.Common/Configuration/ConfigurationFileFormat.cs b/src/Ryujinx.Ui.Common/Configuration/ConfigurationFileFormat.cs index 3168766b5..f0489915d 100644 --- a/src/Ryujinx.Ui.Common/Configuration/ConfigurationFileFormat.cs +++ b/src/Ryujinx.Ui.Common/Configuration/ConfigurationFileFormat.cs @@ -162,9 +162,9 @@ namespace Ryujinx.Ui.Common.Configuration public bool ShowConfirmExit { get; set; } /// <summary> - /// Hide Cursor on Idle + /// Whether to hide cursor on idle, always or never /// </summary> - public bool HideCursorOnIdle { get; set; } + public HideCursorMode HideCursor { get; set; } /// <summary> /// Enables or disables Vertical Sync @@ -395,4 +395,4 @@ namespace Ryujinx.Ui.Common.Configuration JsonHelper.SerializeToFile(path, this, ConfigurationFileFormatSettings.SerializerContext.ConfigurationFileFormat); } } -} +} \ No newline at end of file diff --git a/src/Ryujinx.Ui.Common/Configuration/ConfigurationState.cs b/src/Ryujinx.Ui.Common/Configuration/ConfigurationState.cs index fc3693ae8..146a9b500 100644 --- a/src/Ryujinx.Ui.Common/Configuration/ConfigurationState.cs +++ b/src/Ryujinx.Ui.Common/Configuration/ConfigurationState.cs @@ -613,7 +613,7 @@ namespace Ryujinx.Ui.Common.Configuration /// <summary> /// Hide Cursor on Idle /// </summary> - public ReactiveObject<bool> HideCursorOnIdle { get; private set; } + public ReactiveObject<HideCursorMode> HideCursor { get; private set; } private ConfigurationState() { @@ -626,7 +626,7 @@ namespace Ryujinx.Ui.Common.Configuration EnableDiscordIntegration = new ReactiveObject<bool>(); CheckUpdatesOnStart = new ReactiveObject<bool>(); ShowConfirmExit = new ReactiveObject<bool>(); - HideCursorOnIdle = new ReactiveObject<bool>(); + HideCursor = new ReactiveObject<HideCursorMode>(); } public ConfigurationFileFormat ToFileFormat() @@ -662,7 +662,7 @@ namespace Ryujinx.Ui.Common.Configuration EnableDiscordIntegration = EnableDiscordIntegration, CheckUpdatesOnStart = CheckUpdatesOnStart, ShowConfirmExit = ShowConfirmExit, - HideCursorOnIdle = HideCursorOnIdle, + HideCursor = HideCursor, EnableVsync = Graphics.EnableVsync, EnableShaderCache = Graphics.EnableShaderCache, EnableTextureRecompression = Graphics.EnableTextureRecompression, @@ -767,7 +767,7 @@ namespace Ryujinx.Ui.Common.Configuration EnableDiscordIntegration.Value = true; CheckUpdatesOnStart.Value = true; ShowConfirmExit.Value = true; - HideCursorOnIdle.Value = false; + HideCursor.Value = Ryujinx.Common.Configuration.HideCursorMode.Never; Graphics.EnableVsync.Value = true; Graphics.EnableShaderCache.Value = true; Graphics.EnableTextureRecompression.Value = false; @@ -1046,7 +1046,7 @@ namespace Ryujinx.Ui.Common.Configuration { Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 22."); - configurationFileFormat.HideCursorOnIdle = false; + configurationFileFormat.HideCursor = HideCursorMode.Never; configurationFileUpdated = true; } @@ -1427,7 +1427,7 @@ namespace Ryujinx.Ui.Common.Configuration EnableDiscordIntegration.Value = configurationFileFormat.EnableDiscordIntegration; CheckUpdatesOnStart.Value = configurationFileFormat.CheckUpdatesOnStart; ShowConfirmExit.Value = configurationFileFormat.ShowConfirmExit; - HideCursorOnIdle.Value = configurationFileFormat.HideCursorOnIdle; + HideCursor.Value = configurationFileFormat.HideCursor; Graphics.EnableVsync.Value = configurationFileFormat.EnableVsync; Graphics.EnableShaderCache.Value = configurationFileFormat.EnableShaderCache; Graphics.EnableTextureRecompression.Value = configurationFileFormat.EnableTextureRecompression; diff --git a/src/Ryujinx.Ui.Common/Helper/CommandLineState.cs b/src/Ryujinx.Ui.Common/Helper/CommandLineState.cs index 8ca7fba18..660a4ce92 100644 --- a/src/Ryujinx.Ui.Common/Helper/CommandLineState.cs +++ b/src/Ryujinx.Ui.Common/Helper/CommandLineState.cs @@ -9,6 +9,7 @@ namespace Ryujinx.Ui.Common.Helper public static bool? OverrideDockedMode { get; private set; } public static string OverrideGraphicsBackend { get; private set; } + public static string OverrideHideCursor { get; private set; } public static string BaseDirPathArg { get; private set; } public static string Profile { get; private set; } public static string LaunchPathArg { get; private set; } @@ -76,6 +77,16 @@ namespace Ryujinx.Ui.Common.Helper case "--handheld-mode": OverrideDockedMode = false; break; + case "--hide-cursor": + if (i + 1 >= args.Length) + { + Logger.Error?.Print(LogClass.Application, $"Invalid option '{arg}'"); + + continue; + } + + OverrideHideCursor = args[++i]; + break; default: LaunchPathArg = arg; break; diff --git a/src/Ryujinx/Program.cs b/src/Ryujinx/Program.cs index 2e6ede444..836483d89 100644 --- a/src/Ryujinx/Program.cs +++ b/src/Ryujinx/Program.cs @@ -209,7 +209,7 @@ namespace Ryujinx } } - // Check if graphics backend was overridden + // Check if graphics backend was overridden. if (CommandLineState.OverrideGraphicsBackend != null) { if (CommandLineState.OverrideGraphicsBackend.ToLower() == "opengl") @@ -224,7 +224,19 @@ namespace Ryujinx } } - // Check if docked mode was overriden. + // Check if HideCursor was overridden. + if (CommandLineState.OverrideHideCursor is not null) + { + ConfigurationState.Instance.HideCursor.Value = CommandLineState.OverrideHideCursor!.ToLower() switch + { + "never" => HideCursorMode.Never, + "onidle" => HideCursorMode.OnIdle, + "always" => HideCursorMode.Always, + _ => ConfigurationState.Instance.HideCursor.Value + }; + } + + // Check if docked mode was overridden. if (CommandLineState.OverrideDockedMode.HasValue) { ConfigurationState.Instance.System.EnableDockedMode.Value = CommandLineState.OverrideDockedMode.Value; diff --git a/src/Ryujinx/Ui/RendererWidgetBase.cs b/src/Ryujinx/Ui/RendererWidgetBase.cs index 65afa6e47..0fa7240b8 100644 --- a/src/Ryujinx/Ui/RendererWidgetBase.cs +++ b/src/Ryujinx/Ui/RendererWidgetBase.cs @@ -72,7 +72,7 @@ namespace Ryujinx.Ui const int CursorHideIdleTime = 5; // seconds private static readonly Cursor _invisibleCursor = new Cursor(Display.Default, CursorType.BlankCursor); private long _lastCursorMoveTime; - private bool _hideCursorOnIdle; + private HideCursorMode _hideCursorMode; private InputManager _inputManager; private IKeyboard _keyboardInterface; private GraphicsDebugLevel _glLogLevel; @@ -113,10 +113,10 @@ namespace Ryujinx.Ui _gpuCancellationTokenSource = new CancellationTokenSource(); - _hideCursorOnIdle = ConfigurationState.Instance.HideCursorOnIdle; + _hideCursorMode = ConfigurationState.Instance.HideCursor; _lastCursorMoveTime = Stopwatch.GetTimestamp(); - ConfigurationState.Instance.HideCursorOnIdle.Event += HideCursorStateChanged; + ConfigurationState.Instance.HideCursor.Event += HideCursorStateChanged; ConfigurationState.Instance.Graphics.AntiAliasing.Event += UpdateAnriAliasing; ConfigurationState.Instance.Graphics.ScalingFilter.Event += UpdateScalingFilter; ConfigurationState.Instance.Graphics.ScalingFilterLevel.Event += UpdateScalingFilterLevel; @@ -145,26 +145,32 @@ namespace Ryujinx.Ui return Renderer.GetHardwareInfo().GpuVendor; } - private void HideCursorStateChanged(object sender, ReactiveEventArgs<bool> state) + private void HideCursorStateChanged(object sender, ReactiveEventArgs<HideCursorMode> state) { Application.Invoke(delegate { - _hideCursorOnIdle = state.NewValue; + _hideCursorMode = state.NewValue; - if (_hideCursorOnIdle) + switch (_hideCursorMode) { - _lastCursorMoveTime = Stopwatch.GetTimestamp(); - } - else - { - Window.Cursor = null; + case HideCursorMode.Never: + Window.Cursor = null; + break; + case HideCursorMode.OnIdle: + _lastCursorMoveTime = Stopwatch.GetTimestamp(); + break; + case HideCursorMode.Always: + Window.Cursor = _invisibleCursor; + break; + default: + throw new ArgumentOutOfRangeException(); } }); } private void Renderer_Destroyed(object sender, EventArgs e) { - ConfigurationState.Instance.HideCursorOnIdle.Event -= HideCursorStateChanged; + ConfigurationState.Instance.HideCursor.Event -= HideCursorStateChanged; ConfigurationState.Instance.Graphics.AntiAliasing.Event -= UpdateAnriAliasing; ConfigurationState.Instance.Graphics.ScalingFilter.Event -= UpdateScalingFilter; ConfigurationState.Instance.Graphics.ScalingFilterLevel.Event -= UpdateScalingFilterLevel; @@ -180,7 +186,7 @@ namespace Ryujinx.Ui protected override bool OnMotionNotifyEvent(EventMotion evnt) { - if (_hideCursorOnIdle) + if (_hideCursorMode == HideCursorMode.OnIdle) { _lastCursorMoveTime = Stopwatch.GetTimestamp(); } @@ -315,15 +321,28 @@ namespace Ryujinx.Ui _toggleDockedMode = toggleDockedMode; - if (_hideCursorOnIdle && !ConfigurationState.Instance.Hid.EnableMouse) + if (ConfigurationState.Instance.Hid.EnableMouse.Value) { - long cursorMoveDelta = Stopwatch.GetTimestamp() - _lastCursorMoveTime; - Window.Cursor = (cursorMoveDelta >= CursorHideIdleTime * Stopwatch.Frequency) ? _invisibleCursor : null; + if (_isMouseInClient) + { + Window.Cursor = _invisibleCursor; + } } - - if (ConfigurationState.Instance.Hid.EnableMouse && _isMouseInClient) + else { - Window.Cursor = _invisibleCursor; + switch (_hideCursorMode) + { + case HideCursorMode.OnIdle: + long cursorMoveDelta = Stopwatch.GetTimestamp() - _lastCursorMoveTime; + Window.Cursor = (cursorMoveDelta >= CursorHideIdleTime * Stopwatch.Frequency) ? _invisibleCursor : null; + break; + case HideCursorMode.Always: + Window.Cursor = _invisibleCursor; + break; + case HideCursorMode.Never: + Window.Cursor = null; + break; + } } } @@ -775,4 +794,4 @@ namespace Ryujinx.Ui return state; } } -} +} \ No newline at end of file diff --git a/src/Ryujinx/Ui/Windows/SettingsWindow.cs b/src/Ryujinx/Ui/Windows/SettingsWindow.cs index 27080bda3..3fb0447d3 100644 --- a/src/Ryujinx/Ui/Windows/SettingsWindow.cs +++ b/src/Ryujinx/Ui/Windows/SettingsWindow.cs @@ -52,7 +52,9 @@ namespace Ryujinx.Ui.Windows [GUI] CheckButton _discordToggle; [GUI] CheckButton _checkUpdatesToggle; [GUI] CheckButton _showConfirmExitToggle; - [GUI] CheckButton _hideCursorOnIdleToggle; + [GUI] RadioButton _hideCursorNever; + [GUI] RadioButton _hideCursorOnIdle; + [GUI] RadioButton _hideCursorAlways; [GUI] CheckButton _vSyncToggle; [GUI] CheckButton _shaderCacheToggle; [GUI] CheckButton _textureRecompressionToggle; @@ -226,9 +228,17 @@ namespace Ryujinx.Ui.Windows _showConfirmExitToggle.Click(); } - if (ConfigurationState.Instance.HideCursorOnIdle) + switch (ConfigurationState.Instance.HideCursor.Value) { - _hideCursorOnIdleToggle.Click(); + case HideCursorMode.Never: + _hideCursorNever.Click(); + break; + case HideCursorMode.OnIdle: + _hideCursorOnIdle.Click(); + break; + case HideCursorMode.Always: + _hideCursorAlways.Click(); + break; } if (ConfigurationState.Instance.Graphics.EnableVsync) @@ -560,6 +570,18 @@ namespace Ryujinx.Ui.Windows _directoryChanged = false; } + HideCursorMode hideCursor = HideCursorMode.Never; + + if (_hideCursorOnIdle.Active) + { + hideCursor = HideCursorMode.OnIdle; + } + + if (_hideCursorAlways.Active) + { + hideCursor = HideCursorMode.Always; + } + if (!float.TryParse(_resScaleText.Buffer.Text, out float resScaleCustom) || resScaleCustom <= 0.0f) { resScaleCustom = 1.0f; @@ -602,7 +624,7 @@ namespace Ryujinx.Ui.Windows ConfigurationState.Instance.EnableDiscordIntegration.Value = _discordToggle.Active; ConfigurationState.Instance.CheckUpdatesOnStart.Value = _checkUpdatesToggle.Active; ConfigurationState.Instance.ShowConfirmExit.Value = _showConfirmExitToggle.Active; - ConfigurationState.Instance.HideCursorOnIdle.Value = _hideCursorOnIdleToggle.Active; + ConfigurationState.Instance.HideCursor.Value = hideCursor; ConfigurationState.Instance.Graphics.EnableVsync.Value = _vSyncToggle.Active; ConfigurationState.Instance.Graphics.EnableShaderCache.Value = _shaderCacheToggle.Active; ConfigurationState.Instance.Graphics.EnableTextureRecompression.Value = _textureRecompressionToggle.Active; @@ -813,4 +835,4 @@ namespace Ryujinx.Ui.Windows Dispose(); } } -} +} \ No newline at end of file diff --git a/src/Ryujinx/Ui/Windows/SettingsWindow.glade b/src/Ryujinx/Ui/Windows/SettingsWindow.glade index 8ae6ea72f..0caa477bd 100644 --- a/src/Ryujinx/Ui/Windows/SettingsWindow.glade +++ b/src/Ryujinx/Ui/Windows/SettingsWindow.glade @@ -160,19 +160,83 @@ </packing> </child> <child> - <object class="GtkCheckButton" id="_hideCursorOnIdleToggle"> - <property name="label" translatable="yes">Hide Cursor On Idle</property> + <object class="GtkBox" id="_hideCursorBox"> <property name="visible">True</property> - <property name="can-focus">True</property> - <property name="receives-default">False</property> - <property name="halign">start</property> - <property name="draw-indicator">True</property> + <property name="can-focus">False</property> + <child> + <object class="GtkLabel"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="halign">end</property> + <property name="label" translatable="yes">Hide Cursor:</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="padding">5</property> + <property name="position">2</property> + </packing> + </child> + <child> + <object class="GtkRadioButton" id="_hideCursorNever"> + <property name="label" translatable="yes">Never</property> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="receives-default">False</property> + <property name="halign">start</property> + <property name="margin-top">5</property> + <property name="margin-bottom">5</property> + <property name="active">True</property> + <property name="draw-indicator">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">3</property> + </packing> + </child> + <child> + <object class="GtkRadioButton" id="_hideCursorOnIdle"> + <property name="label" translatable="yes">On Idle</property> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="receives-default">False</property> + <property name="halign">start</property> + <property name="margin-top">5</property> + <property name="margin-bottom">5</property> + <property name="draw-indicator">True</property> + <property name="group">_hideCursorNever</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">4</property> + </packing> + </child> + <child> + <object class="GtkRadioButton" id="_hideCursorAlways"> + <property name="label" translatable="yes">Always</property> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="receives-default">False</property> + <property name="halign">start</property> + <property name="margin-top">5</property> + <property name="margin-bottom">5</property> + <property name="draw-indicator">True</property> + <property name="group">_hideCursorNever</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">5</property> + </packing> + </child> </object> <packing> <property name="expand">False</property> <property name="fill">True</property> <property name="padding">5</property> - <property name="position">3</property> + <property name="position">4</property> </packing> </child> </object>