From d71deb30466df834a9580eb852c9be39d85c02eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Hamil?= Date: Wed, 29 Jan 2025 19:53:09 +0300 Subject: [PATCH] Ability to assign hotkeys to cycle controllers for players --- .../Configuration/Hid/KeyboardHotkeys.cs | 3 + src/Ryujinx/AppHost.cs | 23 +++ src/Ryujinx/Assets/locales.json | 25 +++ src/Ryujinx/Common/KeyboardHotkeyState.cs | 8 + src/Ryujinx/UI/Models/Input/HotkeyConfig.cs | 14 ++ src/Ryujinx/UI/ViewModels/CycleController.cs | 48 +++++ .../UI/ViewModels/Input/InputViewModel.cs | 8 + .../Views/Settings/SettingsHotkeysView.axaml | 185 +++++++++++------- .../Settings/SettingsHotkeysView.axaml.cs | 19 +- 9 files changed, 261 insertions(+), 72 deletions(-) create mode 100644 src/Ryujinx/UI/ViewModels/CycleController.cs diff --git a/src/Ryujinx.Common/Configuration/Hid/KeyboardHotkeys.cs b/src/Ryujinx.Common/Configuration/Hid/KeyboardHotkeys.cs index 6b8152b9d..895c76cd7 100644 --- a/src/Ryujinx.Common/Configuration/Hid/KeyboardHotkeys.cs +++ b/src/Ryujinx.Common/Configuration/Hid/KeyboardHotkeys.cs @@ -1,3 +1,5 @@ +using System.Collections.Generic; + namespace Ryujinx.Common.Configuration.Hid { public class KeyboardHotkeys @@ -13,5 +15,6 @@ namespace Ryujinx.Common.Configuration.Hid public Key VolumeDown { get; set; } public Key CustomVSyncIntervalIncrement { get; set; } public Key CustomVSyncIntervalDecrement { get; set; } + public List CycleControllers { get; set; } } } diff --git a/src/Ryujinx/AppHost.cs b/src/Ryujinx/AppHost.cs index b26921e6a..10625af58 100644 --- a/src/Ryujinx/AppHost.cs +++ b/src/Ryujinx/AppHost.cs @@ -40,6 +40,7 @@ using Ryujinx.HLE; using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.HOS; using Ryujinx.HLE.HOS.Services.Account.Acc; +using Ryujinx.HLE.HOS.Services.Hid; using Ryujinx.HLE.HOS.SystemState; using Ryujinx.Input; using Ryujinx.Input.HLE; @@ -49,6 +50,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; +using System.Linq; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; @@ -1309,6 +1311,18 @@ namespace Ryujinx.Ava _viewModel.Volume = Device.GetVolume(); break; + case KeyboardHotkeyState.CycleControllersPlayer1: + case KeyboardHotkeyState.CycleControllersPlayer2: + case KeyboardHotkeyState.CycleControllersPlayer3: + case KeyboardHotkeyState.CycleControllersPlayer4: + case KeyboardHotkeyState.CycleControllersPlayer5: + case KeyboardHotkeyState.CycleControllersPlayer6: + case KeyboardHotkeyState.CycleControllersPlayer7: + case KeyboardHotkeyState.CycleControllersPlayer8: + var player = currentHotkeyState - KeyboardHotkeyState.CycleControllersPlayer1; + var ivm = new UI.ViewModels.Input.InputViewModel(); + Dispatcher.UIThread.Invoke(() => ivm.CyclePlayerDevice(player)); + break; case KeyboardHotkeyState.None: (_keyboardInterface as AvaloniaKeyboard).Clear(); break; @@ -1391,6 +1405,15 @@ namespace Ryujinx.Ava state = KeyboardHotkeyState.CustomVSyncIntervalDecrement; } + foreach (var cycle in ConfigurationState.Instance.Hid.Hotkeys.Value.CycleControllers?.Select((value, index) => (value, index)) ?? []) + { + if (_keyboardInterface.IsPressed((Key)cycle.value)) + { + state = KeyboardHotkeyState.CycleControllersPlayer1 + cycle.index; + break; + } + } + return state; } } diff --git a/src/Ryujinx/Assets/locales.json b/src/Ryujinx/Assets/locales.json index 698d31730..dc93a8a6f 100644 --- a/src/Ryujinx/Assets/locales.json +++ b/src/Ryujinx/Assets/locales.json @@ -5947,6 +5947,31 @@ "zh_TW": "啟用警告日誌" } }, + { + "ID": "SettingsTabHotkeysCycleControllers", + "Translations": { + "ar_SA": "", + "de_DE": "", + "el_GR": "", + "en_US": "Cycle Controllers", + "es_ES": "", + "fr_FR": "", + "he_IL": "", + "it_IT": "", + "ja_JP": "", + "ko_KR": "", + "no_NO": "", + "pl_PL": "", + "pt_BR": "", + "ru_RU": "", + "sv_SE": "", + "th_TH": "", + "tr_TR": "", + "uk_UA": "", + "zh_CN": "", + "zh_TW": "" + } + }, { "ID": "SettingsTabLoggingEnableErrorLogs", "Translations": { diff --git a/src/Ryujinx/Common/KeyboardHotkeyState.cs b/src/Ryujinx/Common/KeyboardHotkeyState.cs index 060c678d2..de2042a23 100644 --- a/src/Ryujinx/Common/KeyboardHotkeyState.cs +++ b/src/Ryujinx/Common/KeyboardHotkeyState.cs @@ -14,5 +14,13 @@ namespace Ryujinx.Ava.Common VolumeDown, CustomVSyncIntervalIncrement, CustomVSyncIntervalDecrement, + CycleControllersPlayer1, + CycleControllersPlayer2, + CycleControllersPlayer3, + CycleControllersPlayer4, + CycleControllersPlayer5, + CycleControllersPlayer6, + CycleControllersPlayer7, + CycleControllersPlayer8 } } diff --git a/src/Ryujinx/UI/Models/Input/HotkeyConfig.cs b/src/Ryujinx/UI/Models/Input/HotkeyConfig.cs index 40f53c673..9d3b9120e 100644 --- a/src/Ryujinx/UI/Models/Input/HotkeyConfig.cs +++ b/src/Ryujinx/UI/Models/Input/HotkeyConfig.cs @@ -1,6 +1,11 @@ using CommunityToolkit.Mvvm.ComponentModel; +using DynamicData; +using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.ViewModels; using Ryujinx.Common.Configuration.Hid; +using System.Collections.ObjectModel; +using System.Linq; +using System.Windows.Input; namespace Ryujinx.Ava.UI.Models.Input { @@ -28,8 +33,15 @@ namespace Ryujinx.Ava.UI.Models.Input [ObservableProperty] private Key _customVSyncIntervalDecrement; + public ObservableCollection CycleControllers { get; set; } = new ObservableCollection(); + public ICommand AddCycleController { get; set; } + public ICommand RemoveCycleController { get; set; } + public bool CanRemoveCycleController => CycleControllers.Count > 0 && CycleControllers.Count < 8; + public HotkeyConfig(KeyboardHotkeys config) { + AddCycleController = MiniCommand.Create(() => CycleControllers.Add(new CycleController(CycleControllers.Count + 1, Key.Unbound))); + RemoveCycleController = MiniCommand.Create(() => CycleControllers.Remove(CycleControllers.Last())); if (config == null) return; @@ -44,6 +56,7 @@ namespace Ryujinx.Ava.UI.Models.Input VolumeDown = config.VolumeDown; CustomVSyncIntervalIncrement = config.CustomVSyncIntervalIncrement; CustomVSyncIntervalDecrement = config.CustomVSyncIntervalDecrement; + CycleControllers.AddRange((config.CycleControllers ?? []).Select((x, i) => new CycleController(i + 1, x))); } public KeyboardHotkeys GetConfig() => @@ -60,6 +73,7 @@ namespace Ryujinx.Ava.UI.Models.Input VolumeDown = VolumeDown, CustomVSyncIntervalIncrement = CustomVSyncIntervalIncrement, CustomVSyncIntervalDecrement = CustomVSyncIntervalDecrement, + CycleControllers = CycleControllers.Select(x => x.Hotkey).ToList() }; } } diff --git a/src/Ryujinx/UI/ViewModels/CycleController.cs b/src/Ryujinx/UI/ViewModels/CycleController.cs new file mode 100644 index 000000000..a8cad0ab6 --- /dev/null +++ b/src/Ryujinx/UI/ViewModels/CycleController.cs @@ -0,0 +1,48 @@ +using Ryujinx.Ava.Common.Locale; +using Ryujinx.Common.Configuration.Hid; + +namespace Ryujinx.Ava.UI.ViewModels +{ + public class CycleController : BaseModel + { + private string _player; + private Key _hotkey; + + public string Player + { + get => _player; + set + { + _player = value; + OnPropertyChanged(nameof(Player)); + } + } + + public Key Hotkey + { + get => _hotkey; + set + { + _hotkey = value; + OnPropertyChanged(nameof(Hotkey)); + } + } + + public CycleController(int v, Key x) + { + Player = v switch + { + 1 => LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer1], + 2 => LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer2], + 3 => LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer3], + 4 => LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer4], + 5 => LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer5], + 6 => LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer6], + 7 => LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer7], + 8 => LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer8], + _ => LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer] + " " + v + }; + Hotkey = x; + } + } +} diff --git a/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs b/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs index 5b7bcfd32..68a296315 100644 --- a/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs @@ -897,5 +897,13 @@ namespace Ryujinx.Ava.UI.ViewModels.Input AvaloniaKeyboardDriver.Dispose(); } + + public void CyclePlayerDevice(int player) + { + LoadDevices(); + PlayerId = (PlayerIndex)player; + Device = (Device + 1) % Devices.Count; + Save(); + } } } diff --git a/src/Ryujinx/UI/Views/Settings/SettingsHotkeysView.axaml b/src/Ryujinx/UI/Views/Settings/SettingsHotkeysView.axaml index 87b6dda7d..6f5e8e9bc 100644 --- a/src/Ryujinx/UI/Views/Settings/SettingsHotkeysView.axaml +++ b/src/Ryujinx/UI/Views/Settings/SettingsHotkeysView.axaml @@ -1,4 +1,4 @@ - - - -