Compare commits

...

7 Commits

Author SHA1 Message Date
Evan Husted
501b199e24 UI: setting: Disable Input when Out of Focus 2025-02-11 22:12:05 -06:00
Evan Husted
8aecccadb8 misc: chore: Format AvaHostUIHandler 2025-02-11 21:23:04 -06:00
Evan Husted
e23d610f49 UI: Change Update Available button text color to white 2025-02-11 21:18:05 -06:00
Evan Husted
f6822f7358 misc: chore: add direct error code tuple to DisplayErrorAppletDialog
for use when i find the list of error codes -> causes
2025-02-11 21:09:55 -06:00
Evan Husted
d3f84a1305 misc: chore: Rename UserSelectorDialog to ProfileSelectorDialog 2025-02-11 20:50:06 -06:00
Evan Husted
06d34a5992 misc: chore: optimize UserSelectorDialog closed handler 2025-02-11 20:36:11 -06:00
Evan Husted
e8e1dc6619 misc: chore: this isn't even bound to a XAML element, why was this an async void 2025-02-11 20:30:46 -06:00
19 changed files with 183 additions and 84 deletions

View File

@@ -158,13 +158,15 @@ namespace Ryujinx.HLE.HOS.Applets.Error
string[] buttons = GetButtonsText(module, description, "DlgBtn"); string[] buttons = GetButtonsText(module, description, "DlgBtn");
bool showDetails = _horizon.Device.UIHandler.DisplayErrorAppletDialog($"Error Code: {module}-{description:0000}", "\n" + message, buttons); (uint Module, uint Description) errorCodeTuple = (module, uint.Parse(description.ToString("0000")));
bool showDetails = _horizon.Device.UIHandler.DisplayErrorAppletDialog($"Error Code: {module}-{description:0000}", "\n" + message, buttons, errorCodeTuple);
if (showDetails) if (showDetails)
{ {
message = GetMessageText(module, description, "FlvMsg"); message = GetMessageText(module, description, "FlvMsg");
buttons = GetButtonsText(module, description, "FlvBtn"); buttons = GetButtonsText(module, description, "FlvBtn");
_horizon.Device.UIHandler.DisplayErrorAppletDialog($"Details: {module}-{description:0000}", "\n" + message, buttons); _horizon.Device.UIHandler.DisplayErrorAppletDialog($"Details: {module}-{description:0000}", "\n" + message, buttons, errorCodeTuple);
} }
} }

View File

@@ -45,10 +45,12 @@ namespace Ryujinx.HLE.UI
/// <param name="value">The value associated to the <paramref name="kind"/>.</param> /// <param name="value">The value associated to the <paramref name="kind"/>.</param>
void ExecuteProgram(Switch device, ProgramSpecifyKind kind, ulong value); void ExecuteProgram(Switch device, ProgramSpecifyKind kind, ulong value);
/// <summary>
/// Displays a Message Dialog box specific to Error Applet and blocks until it is closed. /// Displays a Message Dialog box specific to Error Applet and blocks until it is closed.
/// </summary> /// </summary>
/// <returns>False when OK is pressed, True when another button (Details) is pressed.</returns> /// <returns>False when OK is pressed, True when another button (Details) is pressed.</returns>
bool DisplayErrorAppletDialog(string title, string message, string[] buttonsText); // ReSharper disable once UnusedParameter.Global
bool DisplayErrorAppletDialog(string title, string message, string[] buttonsText, (uint Module, uint Description)? errorCode = null);
/// <summary> /// <summary>
/// Creates a handler to process keyboard inputs into text strings. /// Creates a handler to process keyboard inputs into text strings.

View File

@@ -185,6 +185,15 @@ namespace Ryujinx.Input.HLE
} }
} }
public bool InputUpdatesBlocked
{
get
{
lock (_lock)
return _blockInputUpdates;
}
}
public void BlockInputUpdates() public void BlockInputUpdates()
{ {
lock (_lock) lock (_lock)

View File

@@ -3497,6 +3497,31 @@
"zh_TW": "記住視窗大小/位置" "zh_TW": "記住視窗大小/位置"
} }
}, },
{
"ID": "SettingsTabGeneralDisableInputWhenOutOfFocus",
"Translations": {
"ar_SA": "",
"de_DE": "",
"el_GR": "",
"en_US": "Disable Input when Out of Focus",
"es_ES": "",
"fr_FR": "",
"he_IL": "",
"it_IT": "",
"ja_JP": "",
"ko_KR": "",
"no_NO": "Deaktiver inndata når vinduet er ute av fokus",
"pl_PL": "",
"pt_BR": "",
"ru_RU": "",
"sv_SE": "",
"th_TH": "",
"tr_TR": "",
"uk_UA": "",
"zh_CN": "",
"zh_TW": ""
}
},
{ {
"ID": "SettingsTabGeneralShowTitleBar", "ID": "SettingsTabGeneralShowTitleBar",
"Translations": { "Translations": {

View File

@@ -513,7 +513,7 @@ namespace Ryujinx.Headless
Exit(); Exit();
} }
public bool DisplayErrorAppletDialog(string title, string message, string[] buttonsText) public bool DisplayErrorAppletDialog(string title, string message, string[] buttonsText, (uint Module, uint Description)? errorCode = null)
{ {
SDL_MessageBoxData data = new() SDL_MessageBoxData data = new()
{ {
@@ -521,7 +521,7 @@ namespace Ryujinx.Headless
message = message, message = message,
buttons = new SDL_MessageBoxButtonData[buttonsText.Length], buttons = new SDL_MessageBoxButtonData[buttonsText.Length],
numbuttons = buttonsText.Length, numbuttons = buttonsText.Length,
window = WindowHandle, window = WindowHandle
}; };
for (int i = 0; i < buttonsText.Length; i++) for (int i = 0; i < buttonsText.Length; i++)

View File

@@ -75,31 +75,32 @@ namespace Ryujinx.Ava.UI.Applet
bool opened = false; bool opened = false;
UserResult response = await ContentDialogHelper.ShowDeferredContentDialog(_parent, UserResult response = await ContentDialogHelper.ShowDeferredContentDialog(_parent,
title, title,
message, message,
string.Empty, string.Empty,
LocaleManager.Instance[LocaleKeys.DialogOpenSettingsWindowLabel], LocaleManager.Instance[LocaleKeys.DialogOpenSettingsWindowLabel],
string.Empty, string.Empty,
LocaleManager.Instance[LocaleKeys.SettingsButtonClose], LocaleManager.Instance[LocaleKeys.SettingsButtonClose],
(int)Symbol.Important, (int)Symbol.Important,
deferEvent, deferEvent,
async window => async window =>
{ {
if (opened) if (opened)
{ {
return; return;
} }
opened = true; opened = true;
_parent.SettingsWindow = new SettingsWindow(_parent.VirtualFileSystem, _parent.ContentManager); _parent.SettingsWindow =
new SettingsWindow(_parent.VirtualFileSystem, _parent.ContentManager);
await _parent.SettingsWindow.ShowDialog(window); await _parent.SettingsWindow.ShowDialog(window);
_parent.SettingsWindow = null; _parent.SettingsWindow = null;
opened = false; opened = false;
}); });
if (response == UserResult.Ok) if (response == UserResult.Ok)
{ {
@@ -110,7 +111,9 @@ namespace Ryujinx.Ava.UI.Applet
} }
catch (Exception ex) catch (Exception ex)
{ {
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogMessageDialogErrorExceptionMessage, ex)); await ContentDialogHelper.CreateErrorDialog(
LocaleManager.Instance.UpdateAndGetDynamicValue(
LocaleKeys.DialogMessageDialogErrorExceptionMessage, ex));
dialogCloseEvent.Set(); dialogCloseEvent.Set();
} }
@@ -134,7 +137,9 @@ namespace Ryujinx.Ava.UI.Applet
try try
{ {
_parent.ViewModel.AppHost.NpadManager.BlockInputUpdates(); _parent.ViewModel.AppHost.NpadManager.BlockInputUpdates();
(UserResult result, string userInput) = await SwkbdAppletDialog.ShowInputDialog(LocaleManager.Instance[LocaleKeys.SoftwareKeyboard], args); (UserResult result, string userInput) =
await SwkbdAppletDialog.ShowInputDialog(LocaleManager.Instance[LocaleKeys.SoftwareKeyboard],
args);
if (result == UserResult.Ok) if (result == UserResult.Ok)
{ {
@@ -146,7 +151,9 @@ namespace Ryujinx.Ava.UI.Applet
{ {
error = true; error = true;
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogSoftwareKeyboardErrorExceptionMessage, ex)); await ContentDialogHelper.CreateErrorDialog(
LocaleManager.Instance.UpdateAndGetDynamicValue(
LocaleKeys.DialogSoftwareKeyboardErrorExceptionMessage, ex));
} }
finally finally
{ {
@@ -177,7 +184,8 @@ namespace Ryujinx.Ava.UI.Applet
args.InitialText = "Ryujinx"; args.InitialText = "Ryujinx";
args.StringLengthMin = 1; args.StringLengthMin = 1;
args.StringLengthMax = 25; args.StringLengthMax = 25;
(UserResult result, string userInput) = await SwkbdAppletDialog.ShowInputDialog(LocaleManager.Instance[LocaleKeys.CabinetDialog], args); (UserResult result, string userInput) =
await SwkbdAppletDialog.ShowInputDialog(LocaleManager.Instance[LocaleKeys.CabinetDialog], args);
if (result == UserResult.Ok) if (result == UserResult.Ok)
{ {
inputText = userInput; inputText = userInput;
@@ -201,11 +209,13 @@ namespace Ryujinx.Ava.UI.Applet
Dispatcher.UIThread.InvokeAsync(async () => Dispatcher.UIThread.InvokeAsync(async () =>
{ {
dialogCloseEvent.Set(); dialogCloseEvent.Set();
await ContentDialogHelper.CreateInfoDialog(LocaleManager.Instance[LocaleKeys.CabinetScanDialog], await ContentDialogHelper.CreateInfoDialog(
string.Empty, LocaleManager.Instance[LocaleKeys.CabinetScanDialog],
LocaleManager.Instance[LocaleKeys.InputDialogOk], string.Empty,
string.Empty, LocaleManager.Instance[LocaleKeys.InputDialogOk],
LocaleManager.Instance[LocaleKeys.CabinetTitle]); string.Empty,
LocaleManager.Instance[LocaleKeys.CabinetTitle]
);
}); });
dialogCloseEvent.WaitOne(); dialogCloseEvent.WaitOne();
} }
@@ -217,7 +227,8 @@ namespace Ryujinx.Ava.UI.Applet
_parent.ViewModel.AppHost?.Stop(); _parent.ViewModel.AppHost?.Stop();
} }
public bool DisplayErrorAppletDialog(string title, string message, string[] buttons) public bool DisplayErrorAppletDialog(string title, string message, string[] buttons,
(uint Module, uint Description)? errorCode = null)
{ {
ManualResetEvent dialogCloseEvent = new(false); ManualResetEvent dialogCloseEvent = new(false);
@@ -229,9 +240,7 @@ namespace Ryujinx.Ava.UI.Applet
{ {
ErrorAppletWindow msgDialog = new(_parent, buttons, message) ErrorAppletWindow msgDialog = new(_parent, buttons, message)
{ {
Title = title, Title = title, WindowStartupLocation = WindowStartupLocation.CenterScreen, Width = 400
WindowStartupLocation = WindowStartupLocation.CenterScreen,
Width = 400
}; };
object response = await msgDialog.Run(); object response = await msgDialog.Run();
@@ -249,7 +258,9 @@ namespace Ryujinx.Ava.UI.Applet
{ {
dialogCloseEvent.Set(); dialogCloseEvent.Set();
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogErrorAppletErrorExceptionMessage, ex)); await ContentDialogHelper.CreateErrorDialog(
LocaleManager.Instance.UpdateAndGetDynamicValue(
LocaleKeys.DialogErrorAppletErrorExceptionMessage, ex));
} }
}); });
@@ -278,13 +289,11 @@ namespace Ryujinx.Ava.UI.Applet
.ForEach(profile => profiles.Add(new Models.UserProfile(profile, nav))); .ForEach(profile => profiles.Add(new Models.UserProfile(profile, nav)));
profiles.Add(new Models.UserProfile(guest, nav)); profiles.Add(new Models.UserProfile(guest, nav));
UserSelectorDialogViewModel viewModel = new() ProfileSelectorDialogViewModel viewModel = new()
{ {
Profiles = profiles, Profiles = profiles, SelectedUserId = _parent.AccountManager.LastOpenedUser.UserId
SelectedUserId = _parent.AccountManager.LastOpenedUser.UserId
}; };
UserSelectorDialog content = new(viewModel); (selected, _) = await ProfileSelectorDialog.ShowInputDialog(viewModel);
(selected, _) = await UserSelectorDialog.ShowInputDialog(content);
dialogCloseEvent.Set(); dialogCloseEvent.Set();
}); });
@@ -311,6 +320,7 @@ namespace Ryujinx.Ava.UI.Applet
} }
} }
} }
return profile; return profile;
} }
} }

View File

@@ -1,5 +1,5 @@
<UserControl <UserControl
x:Class="Ryujinx.Ava.UI.Applet.UserSelectorDialog" x:Class="Ryujinx.Ava.UI.Applet.ProfileSelectorDialog"
xmlns="https://github.com/avaloniaui" xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
@@ -12,9 +12,9 @@
d:DesignWidth="800" d:DesignWidth="800"
mc:Ignorable="d" mc:Ignorable="d"
Focusable="True" Focusable="True"
x:DataType="viewModels:UserSelectorDialogViewModel"> x:DataType="viewModels:ProfileSelectorDialogViewModel">
<Design.DataContext> <Design.DataContext>
<viewModels:UserSelectorDialogViewModel /> <viewModels:ProfileSelectorDialogViewModel />
</Design.DataContext> </Design.DataContext>
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch"> <Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">

View File

@@ -16,15 +16,15 @@ using UserProfileSft = Ryujinx.HLE.HOS.Services.Account.Acc.UserProfile;
namespace Ryujinx.Ava.UI.Applet namespace Ryujinx.Ava.UI.Applet
{ {
public partial class UserSelectorDialog : UserControl, INotifyPropertyChanged public partial class ProfileSelectorDialog : UserControl
{ {
public UserSelectorDialogViewModel ViewModel { get; set; } public ProfileSelectorDialogViewModel ViewModel { get; set; }
public UserSelectorDialog(UserSelectorDialogViewModel viewModel) public ProfileSelectorDialog(ProfileSelectorDialogViewModel viewModel)
{ {
DataContext = ViewModel = viewModel;
InitializeComponent(); InitializeComponent();
ViewModel = viewModel;
DataContext = ViewModel;
} }
private void Grid_PointerEntered(object sender, PointerEventArgs e) private void Grid_PointerEntered(object sender, PointerEventArgs e)
@@ -54,7 +54,7 @@ namespace Ryujinx.Ava.UI.Applet
if (ViewModel.Profiles[selectedIndex] is UserProfile userProfile) if (ViewModel.Profiles[selectedIndex] is UserProfile userProfile)
{ {
ViewModel.SelectedUserId = userProfile.UserId; ViewModel.SelectedUserId = userProfile.UserId;
Logger.Info?.Print(LogClass.UI, $"Selected user: {userProfile.UserId}"); Logger.Info?.Print(LogClass.UI, $"Selected: {userProfile.UserId}", "ProfileSelector");
ObservableCollection<BaseModel> newProfiles = []; ObservableCollection<BaseModel> newProfiles = [];
@@ -79,7 +79,7 @@ namespace Ryujinx.Ava.UI.Applet
} }
} }
public static async Task<(UserId Id, bool Result)> ShowInputDialog(UserSelectorDialog content) public static async Task<(UserId Id, bool Result)> ShowInputDialog(ProfileSelectorDialogViewModel viewModel)
{ {
ContentDialog contentDialog = new() ContentDialog contentDialog = new()
{ {
@@ -87,22 +87,25 @@ namespace Ryujinx.Ava.UI.Applet
PrimaryButtonText = LocaleManager.Instance[LocaleKeys.Continue], PrimaryButtonText = LocaleManager.Instance[LocaleKeys.Continue],
SecondaryButtonText = string.Empty, SecondaryButtonText = string.Empty,
CloseButtonText = LocaleManager.Instance[LocaleKeys.Cancel], CloseButtonText = LocaleManager.Instance[LocaleKeys.Cancel],
Content = content, Content = new ProfileSelectorDialog(viewModel),
Padding = new Thickness(0) Padding = new Thickness(0)
}; };
UserId result = UserId.Null; UserId result = UserId.Null;
bool input = false; bool input = false;
contentDialog.Closed += Handler;
await ContentDialogHelper.ShowAsync(contentDialog);
return (result, input);
void Handler(ContentDialog sender, ContentDialogClosedEventArgs eventArgs) void Handler(ContentDialog sender, ContentDialogClosedEventArgs eventArgs)
{ {
if (eventArgs.Result == ContentDialogResult.Primary) if (eventArgs.Result == ContentDialogResult.Primary)
{ {
if (contentDialog.Content is UserSelectorDialog view) result = viewModel.SelectedUserId;
{ input = true;
result = view.ViewModel.SelectedUserId;
input = true;
}
} }
else else
{ {
@@ -110,12 +113,6 @@ namespace Ryujinx.Ava.UI.Applet
input = false; input = false;
} }
} }
contentDialog.Closed += Handler;
await ContentDialogHelper.ShowAsync(contentDialog);
return (result, input);
} }
} }
} }

View File

@@ -264,7 +264,7 @@ namespace Ryujinx.Ava.UI.ViewModels
Logger.Error?.Print(LogClass.Application, $"Couldn't get valid amiibo data: {exception}"); Logger.Error?.Print(LogClass.Application, $"Couldn't get valid amiibo data: {exception}");
// Neither local or remote files are valid JSON, close window. // Neither local or remote files are valid JSON, close window.
ShowInfoDialog(); await ShowInfoDialog();
Close(); Close();
} }
else if (!remoteIsValid) else if (!remoteIsValid)
@@ -273,7 +273,7 @@ namespace Ryujinx.Ava.UI.ViewModels
// Only the local file is valid, the local one should be used // Only the local file is valid, the local one should be used
// but the user should be warned. // but the user should be warned.
ShowInfoDialog(); await ShowInfoDialog();
} }
} }
@@ -525,7 +525,7 @@ namespace Ryujinx.Ava.UI.ViewModels
AmiiboImage = bitmap; AmiiboImage = bitmap;
} }
private static async void ShowInfoDialog() private static async Task ShowInfoDialog()
{ {
await ContentDialogHelper.CreateInfoDialog(LocaleManager.Instance[LocaleKeys.DialogAmiiboApiTitle], await ContentDialogHelper.CreateInfoDialog(LocaleManager.Instance[LocaleKeys.DialogAmiiboApiTitle],
LocaleManager.Instance[LocaleKeys.DialogAmiiboApiConnectErrorMessage], LocaleManager.Instance[LocaleKeys.DialogAmiiboApiConnectErrorMessage],

View File

@@ -4,7 +4,7 @@ using System.Collections.ObjectModel;
namespace Ryujinx.Ava.UI.ViewModels namespace Ryujinx.Ava.UI.ViewModels
{ {
public partial class UserSelectorDialogViewModel : BaseModel public partial class ProfileSelectorDialogViewModel : BaseModel
{ {
[ObservableProperty] private UserId _selectedUserId; [ObservableProperty] private UserId _selectedUserId;

View File

@@ -126,6 +126,8 @@ namespace Ryujinx.Ava.UI.ViewModels
public bool EnableDockedMode { get; set; } public bool EnableDockedMode { get; set; }
public bool EnableKeyboard { get; set; } public bool EnableKeyboard { get; set; }
public bool EnableMouse { get; set; } public bool EnableMouse { get; set; }
public bool DisableInputWhenOutOfFocus { get; set; }
public VSyncMode VSyncMode public VSyncMode VSyncMode
{ {
get => _vSyncMode; get => _vSyncMode;
@@ -498,6 +500,7 @@ namespace Ryujinx.Ava.UI.ViewModels
EnableDockedMode = config.System.EnableDockedMode; EnableDockedMode = config.System.EnableDockedMode;
EnableKeyboard = config.Hid.EnableKeyboard; EnableKeyboard = config.Hid.EnableKeyboard;
EnableMouse = config.Hid.EnableMouse; EnableMouse = config.Hid.EnableMouse;
DisableInputWhenOutOfFocus = config.Hid.DisableInputWhenOutOfFocus;
// Keyboard Hotkeys // Keyboard Hotkeys
KeyboardHotkey = new HotkeyConfig(config.Hid.Hotkeys.Value); KeyboardHotkey = new HotkeyConfig(config.Hid.Hotkeys.Value);
@@ -609,6 +612,7 @@ namespace Ryujinx.Ava.UI.ViewModels
config.System.EnableDockedMode.Value = EnableDockedMode; config.System.EnableDockedMode.Value = EnableDockedMode;
config.Hid.EnableKeyboard.Value = EnableKeyboard; config.Hid.EnableKeyboard.Value = EnableKeyboard;
config.Hid.EnableMouse.Value = EnableMouse; config.Hid.EnableMouse.Value = EnableMouse;
config.Hid.DisableInputWhenOutOfFocus.Value = DisableInputWhenOutOfFocus;
// Keyboard Hotkeys // Keyboard Hotkeys
config.Hid.Hotkeys.Value = KeyboardHotkey.GetConfig(); config.Hid.Hotkeys.Value = KeyboardHotkey.GetConfig();

View File

@@ -290,12 +290,12 @@
<Binding Path="UpdateAvailable" /> <Binding Path="UpdateAvailable" />
</MultiBinding> </MultiBinding>
</StackPanel.IsVisible> </StackPanel.IsVisible>
<Button Margin="0, 0, 5, 0" <Button Margin="0, 0, 5, -2"
Command="{Binding UpdateCommand}" Command="{Binding UpdateCommand}"
Background="{DynamicResource SystemAccentColor}"> Background="{DynamicResource SystemAccentColor}">
<TextBlock <TextBlock
Margin="-5" Margin="-5"
Foreground="Black" Foreground="{StaticResource SystemColorButtonTextColor}"
HorizontalAlignment="Right" HorizontalAlignment="Right"
VerticalAlignment="Center" VerticalAlignment="Center"
Text="{ext:Locale UpdaterBackgroundStatusBarButtonText}" /> Text="{ext:Locale UpdaterBackgroundStatusBarButtonText}" />

View File

@@ -37,6 +37,9 @@
<CheckBox IsChecked="{Binding RememberWindowState}"> <CheckBox IsChecked="{Binding RememberWindowState}">
<TextBlock Text="{ext:Locale SettingsTabGeneralRememberWindowState}" /> <TextBlock Text="{ext:Locale SettingsTabGeneralRememberWindowState}" />
</CheckBox> </CheckBox>
<CheckBox IsChecked="{Binding DisableInputWhenOutOfFocus}">
<TextBlock Text="{ext:Locale SettingsTabGeneralDisableInputWhenOutOfFocus}" />
</CheckBox>
<CheckBox IsChecked="{Binding ShowTitleBar}" IsVisible="{x:Static helper:RunningPlatform.IsWindows}"> <CheckBox IsChecked="{Binding ShowTitleBar}" IsVisible="{x:Static helper:RunningPlatform.IsWindows}">
<TextBlock Text="{ext:Locale SettingsTabGeneralShowTitleBar}" /> <TextBlock Text="{ext:Locale SettingsTabGeneralShowTitleBar}" />
</CheckBox> </CheckBox>

View File

@@ -21,7 +21,9 @@
x:DataType="viewModels:MainWindowViewModel" x:DataType="viewModels:MainWindowViewModel"
mc:Ignorable="d" mc:Ignorable="d"
WindowStartupLocation="Manual" WindowStartupLocation="Manual"
Focusable="True"> Focusable="True"
GotFocus="InputElement_OnGotFocus"
LostFocus="InputElement_OnLostFocus">
<Window.Styles> <Window.Styles>
<Style Selector="TitleBar:fullscreen"> <Style Selector="TitleBar:fullscreen">
<Setter Property="Background" Value="#000000" /> <Setter Property="Background" Value="#000000" />

View File

@@ -1,6 +1,7 @@
using Avalonia; using Avalonia;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Controls.Primitives; using Avalonia.Controls.Primitives;
using Avalonia.Input;
using Avalonia.Interactivity; using Avalonia.Interactivity;
using Avalonia.Platform; using Avalonia.Platform;
using Avalonia.Threading; using Avalonia.Threading;
@@ -761,5 +762,34 @@ namespace Ryujinx.Ava.UI.Windows
_intelMacWarningShown = true; _intelMacWarningShown = true;
} }
private void InputElement_OnGotFocus(object sender, GotFocusEventArgs e)
{
if (!_didDisableInputUpdates)
return;
if (!ConfigurationState.Instance.Hid.DisableInputWhenOutOfFocus)
return;
if (ViewModel.AppHost is not { NpadManager.InputUpdatesBlocked: true } appHost)
return;
appHost.NpadManager.UnblockInputUpdates();
_didDisableInputUpdates = appHost.NpadManager.InputUpdatesBlocked;
}
private bool _didDisableInputUpdates;
private void InputElement_OnLostFocus(object sender, RoutedEventArgs e)
{
if (!ConfigurationState.Instance.Hid.DisableInputWhenOutOfFocus)
return;
if (ViewModel.AppHost is not { NpadManager.InputUpdatesBlocked: false } appHost)
return;
appHost.NpadManager.BlockInputUpdates();
_didDisableInputUpdates = appHost.NpadManager.InputUpdatesBlocked;
}
} }
} }

View File

@@ -15,7 +15,7 @@ namespace Ryujinx.Ava.Utilities.Configuration
/// <summary> /// <summary>
/// The current version of the file format /// The current version of the file format
/// </summary> /// </summary>
public const int CurrentVersion = 65; public const int CurrentVersion = 66;
/// <summary> /// <summary>
/// Version of the configuration file format /// Version of the configuration file format
@@ -384,6 +384,11 @@ namespace Ryujinx.Ava.Utilities.Configuration
/// </summary> /// </summary>
public bool EnableMouse { get; set; } public bool EnableMouse { get; set; }
/// <summary>
/// Enable/disable the ability to control Ryujinx when it's not the currently focused window.
/// </summary>
public bool DisableInputWhenOutOfFocus { get; set; }
/// <summary> /// <summary>
/// Hotkey Keyboard Bindings /// Hotkey Keyboard Bindings
/// </summary> /// </summary>

View File

@@ -139,6 +139,7 @@ namespace Ryujinx.Ava.Utilities.Configuration
Hid.EnableKeyboard.Value = cff.EnableKeyboard; Hid.EnableKeyboard.Value = cff.EnableKeyboard;
Hid.EnableMouse.Value = cff.EnableMouse; Hid.EnableMouse.Value = cff.EnableMouse;
Hid.DisableInputWhenOutOfFocus.Value = cff.DisableInputWhenOutOfFocus;
Hid.Hotkeys.Value = cff.Hotkeys; Hid.Hotkeys.Value = cff.Hotkeys;
Hid.InputConfig.Value = cff.InputConfig ?? []; Hid.InputConfig.Value = cff.InputConfig ?? [];
Hid.RainbowSpeed.Value = cff.RainbowSpeed; Hid.RainbowSpeed.Value = cff.RainbowSpeed;
@@ -433,7 +434,8 @@ namespace Ryujinx.Ava.Utilities.Configuration
(62, static cff => cff.RainbowSpeed = 1f), (62, static cff => cff.RainbowSpeed = 1f),
(63, static cff => cff.MatchSystemTime = false), (63, static cff => cff.MatchSystemTime = false),
(64, static cff => cff.LoggingEnableAvalonia = false), (64, static cff => cff.LoggingEnableAvalonia = false),
(65, static cff => cff.UpdateCheckerType = cff.CheckUpdatesOnStart ? UpdaterType.PromptAtStartup : UpdaterType.Off) (65, static cff => cff.UpdateCheckerType = cff.CheckUpdatesOnStart ? UpdaterType.PromptAtStartup : UpdaterType.Off),
(66, static cff => cff.DisableInputWhenOutOfFocus = false)
); );
} }
} }

View File

@@ -448,6 +448,11 @@ namespace Ryujinx.Ava.Utilities.Configuration
/// </summary> /// </summary>
public ReactiveObject<bool> EnableMouse { get; private set; } public ReactiveObject<bool> EnableMouse { get; private set; }
/// <summary>
/// Enable/disable the ability to control Ryujinx when it's not the currently focused window.
/// </summary>
public ReactiveObject<bool> DisableInputWhenOutOfFocus { get; private set; }
/// <summary> /// <summary>
/// Hotkey Keyboard Bindings /// Hotkey Keyboard Bindings
/// </summary> /// </summary>
@@ -469,6 +474,7 @@ namespace Ryujinx.Ava.Utilities.Configuration
{ {
EnableKeyboard = new ReactiveObject<bool>(); EnableKeyboard = new ReactiveObject<bool>();
EnableMouse = new ReactiveObject<bool>(); EnableMouse = new ReactiveObject<bool>();
DisableInputWhenOutOfFocus = new ReactiveObject<bool>();
Hotkeys = new ReactiveObject<KeyboardHotkeys>(); Hotkeys = new ReactiveObject<KeyboardHotkeys>();
InputConfig = new ReactiveObject<List<InputConfig>>(); InputConfig = new ReactiveObject<List<InputConfig>>();
RainbowSpeed = new ReactiveObject<float>(); RainbowSpeed = new ReactiveObject<float>();

View File

@@ -131,6 +131,7 @@ namespace Ryujinx.Ava.Utilities.Configuration
ShowConsole = UI.ShowConsole, ShowConsole = UI.ShowConsole,
EnableKeyboard = Hid.EnableKeyboard, EnableKeyboard = Hid.EnableKeyboard,
EnableMouse = Hid.EnableMouse, EnableMouse = Hid.EnableMouse,
DisableInputWhenOutOfFocus = Hid.DisableInputWhenOutOfFocus,
Hotkeys = Hid.Hotkeys, Hotkeys = Hid.Hotkeys,
InputConfig = Hid.InputConfig, InputConfig = Hid.InputConfig,
RainbowSpeed = Hid.RainbowSpeed, RainbowSpeed = Hid.RainbowSpeed,
@@ -245,6 +246,7 @@ namespace Ryujinx.Ava.Utilities.Configuration
UI.WindowStartup.WindowMaximized.Value = false; UI.WindowStartup.WindowMaximized.Value = false;
Hid.EnableKeyboard.Value = false; Hid.EnableKeyboard.Value = false;
Hid.EnableMouse.Value = false; Hid.EnableMouse.Value = false;
Hid.DisableInputWhenOutOfFocus.Value = false;
Hid.Hotkeys.Value = new KeyboardHotkeys Hid.Hotkeys.Value = new KeyboardHotkeys
{ {
ToggleVSyncMode = Key.F1, ToggleVSyncMode = Key.F1,