diff --git a/assets/locales.json b/assets/locales.json index 2f52ee71b..498bcb81e 100644 --- a/assets/locales.json +++ b/assets/locales.json @@ -24372,6 +24372,106 @@ "zh_TW": "只在按下時" } }, + { + "ID": "SettingsTabHotkeysCycleInputDevicePlayer1", + "Translations": { + "ar_SA": "تبديل جهاز الإدخال للاعب 1:", + "de_DE": "Eingabegerät für Spieler 1 wechseln:", + "el_GR": "Εναλλαγή Συσκευής Εισόδου Παίκτη 1:", + "en_US": "Cycle Input Device Player 1:", + "es_ES": "Cambiar dispositivo de entrada jugador 1:", + "fr_FR": "Changer périphérique d'entrée joueur 1 :", + "he_IL": "החלף התקן קלט שחקן 1:", + "it_IT": "Cambia dispositivo di input giocatore 1:", + "ja_JP": "プレイヤー1の入力デバイス切り替え:", + "ko_KR": "플레이어 1 입력 장치 순환:", + "no_NO": "Bytt inndataenhet spiller 1:", + "pl_PL": "Przełącz urządzenie wejściowe gracza 1:", + "pt_BR": "Alternar dispositivo de entrada jogador 1:", + "ru_RU": "Переключить устройство ввода игрока 1:", + "sv_SE": "Växla indataenhet spelare 1:", + "th_TH": "สลับอุปกรณ์ป้อนข้อมูลผู้เล่น 1:", + "tr_TR": "Oyuncu 1 Giriş Cihazını Değiştir:", + "uk_UA": "Перемкнути пристрій введення гравця 1:", + "zh_CN": "切换玩家1输入设备:", + "zh_TW": "切換玩家1輸入裝置:" + } + }, + { + "ID": "SettingsTabHotkeysCycleInputDevicePlayer2", + "Translations": { + "ar_SA": "تبديل جهاز الإدخال للاعب 2:", + "de_DE": "Eingabegerät für Spieler 2 wechseln:", + "el_GR": "Εναλλαγή Συσκευής Εισόδου Παίκτη 2:", + "en_US": "Cycle Input Device Player 2:", + "es_ES": "Cambiar dispositivo de entrada jugador 2:", + "fr_FR": "Changer périphérique d'entrée joueur 2 :", + "he_IL": "החלף התקן קלט שחקן 2:", + "it_IT": "Cambia dispositivo di input giocatore 2:", + "ja_JP": "プレイヤー2の入力デバイス切り替え:", + "ko_KR": "플레이어 2 입력 장치 순환:", + "no_NO": "Bytt inndataenhet spiller 2:", + "pl_PL": "Przełącz urządzenie wejściowe gracza 2:", + "pt_BR": "Alternar dispositivo de entrada jogador 2:", + "ru_RU": "Переключить устройство ввода игрока 2:", + "sv_SE": "Växla indataenhet spelare 2:", + "th_TH": "สลับอุปกรณ์ป้อนข้อมูลผู้เล่น 2:", + "tr_TR": "Oyuncu 2 Giriş Cihazını Değiştir:", + "uk_UA": "Перемкнути пристрій введення гравця 2:", + "zh_CN": "切换玩家2输入设备:", + "zh_TW": "切換玩家2輸入裝置:" + } + }, + { + "ID": "SettingsTabHotkeysCycleInputDevicePlayer3", + "Translations": { + "ar_SA": "تبديل جهاز الإدخال للاعب 3:", + "de_DE": "Eingabegerät für Spieler 3 wechseln:", + "el_GR": "Εναλλαγή Συσκευής Εισόδου Παίκτη 3:", + "en_US": "Cycle Input Device Player 3:", + "es_ES": "Cambiar dispositivo de entrada jugador 3:", + "fr_FR": "Changer périphérique d'entrée joueur 3 :", + "he_IL": "החלף התקן קלט שחקן 3:", + "it_IT": "Cambia dispositivo di input giocatore 3:", + "ja_JP": "プレイヤー3の入力デバイス切り替え:", + "ko_KR": "플레이어 3 입력 장치 순환:", + "no_NO": "Bytt inndataenhet spiller 3:", + "pl_PL": "Przełącz urządzenie wejściowe gracza 3:", + "pt_BR": "Alternar dispositivo de entrada jogador 3:", + "ru_RU": "Переключить устройство ввода игрока 3:", + "sv_SE": "Växla indataenhet spelare 3:", + "th_TH": "สลับอุปกรณ์ป้อนข้อมูลผู้เล่น 3:", + "tr_TR": "Oyuncu 3 Giriş Cihazını Değiştir:", + "uk_UA": "Перемкнути пристрій введення гравця 3:", + "zh_CN": "切换玩家3输入设备:", + "zh_TW": "切換玩家3輸入裝置:" + } + }, + { + "ID": "SettingsTabHotkeysCycleInputDevicePlayer4", + "Translations": { + "ar_SA": "تبديل جهاز الإدخال للاعب 4:", + "de_DE": "Eingabegerät für Spieler 4 wechseln:", + "el_GR": "Εναλλαγή Συσκευής Εισόδου Παίκτη 4:", + "en_US": "Cycle Input Device Player 4:", + "es_ES": "Cambiar dispositivo de entrada jugador 4:", + "fr_FR": "Changer périphérique d'entrée joueur 4 :", + "he_IL": "החלף התקן קלט שחקן 4:", + "it_IT": "Cambia dispositivo di input giocatore 4:", + "ja_JP": "プレイヤー4の入力デバイス切り替え:", + "ko_KR": "플레이어 4 입력 장치 순환:", + "no_NO": "Bytt inndataenhet spiller 4:", + "pl_PL": "Przełącz urządzenie wejściowe gracza 4:", + "pt_BR": "Alternar dispositivo de entrada jogador 4:", + "ru_RU": "Переключить устройство ввода игрока 4:", + "sv_SE": "Växla indataenhet spelare 4:", + "th_TH": "สลับอุปกรณ์ป้อนข้อมูลผู้เล่น 4:", + "tr_TR": "Oyuncu 4 Giriş Cihazını Değiştir:", + "uk_UA": "Перемкнути пристрій введення гравця 4:", + "zh_CN": "切换玩家4输入设备:", + "zh_TW": "切換玩家4輸入裝置:" + } + }, { "ID": "CompatibilityListLastUpdated", "Translations": { diff --git a/src/Ryujinx.Common/Configuration/Hid/DefaultInputConfigurationProvider.cs b/src/Ryujinx.Common/Configuration/Hid/DefaultInputConfigurationProvider.cs new file mode 100644 index 000000000..be145029f --- /dev/null +++ b/src/Ryujinx.Common/Configuration/Hid/DefaultInputConfigurationProvider.cs @@ -0,0 +1,200 @@ +using System; +using Ryujinx.Common.Configuration.Hid.Controller; +using Ryujinx.Common.Configuration.Hid.Controller.Motion; +using Ryujinx.Common.Configuration.Hid.Keyboard; +using ConfigGamepadInputId = Ryujinx.Common.Configuration.Hid.Controller.GamepadInputId; +using ConfigStickInputId = Ryujinx.Common.Configuration.Hid.Controller.StickInputId; + +namespace Ryujinx.Common.Configuration.Hid +{ + /// + /// Provides default input configurations for keyboard and controller devices + /// + public static class DefaultInputConfigurationProvider + { + /// + /// Creates a default keyboard input configuration + /// + /// Device ID + /// Device name + /// Player index + /// Controller type (defaults to ProController) + /// Default keyboard input configuration + public static StandardKeyboardInputConfig CreateDefaultKeyboardConfig(string id, string name, PlayerIndex playerIndex, ControllerType controllerType = ControllerType.ProController) + { + return new StandardKeyboardInputConfig + { + Version = InputConfig.CurrentVersion, + Backend = InputBackendType.WindowKeyboard, + Id = id, + Name = name, + ControllerType = ControllerType.ProController, + PlayerIndex = playerIndex, + LeftJoycon = new LeftJoyconCommonConfig + { + DpadUp = Key.Up, + DpadDown = Key.Down, + DpadLeft = Key.Left, + DpadRight = Key.Right, + ButtonMinus = Key.Minus, + ButtonL = Key.E, + ButtonZl = Key.Q, + ButtonSl = Key.Unbound, + ButtonSr = Key.Unbound, + }, + LeftJoyconStick = new JoyconConfigKeyboardStick + { + StickUp = Key.W, + StickDown = Key.S, + StickLeft = Key.A, + StickRight = Key.D, + StickButton = Key.F, + }, + RightJoycon = new RightJoyconCommonConfig + { + ButtonA = Key.Z, + ButtonB = Key.X, + ButtonX = Key.C, + ButtonY = Key.V, + ButtonPlus = Key.Plus, + ButtonR = Key.U, + ButtonZr = Key.O, + ButtonSl = Key.Unbound, + ButtonSr = Key.Unbound, + }, + RightJoyconStick = new JoyconConfigKeyboardStick + { + StickUp = Key.I, + StickDown = Key.K, + StickLeft = Key.J, + StickRight = Key.L, + StickButton = Key.H, + }, + }; + } + + /// + /// Creates a default controller input configuration + /// + /// Device ID + /// Device name + /// Player index + /// Whether to use Nintendo-style button mapping + /// Default controller input configuration + public static StandardControllerInputConfig CreateDefaultControllerConfig(string id, string name, PlayerIndex playerIndex, bool isNintendoStyle = false) + { + // Split the ID for controller configs + string cleanId = id.Split(" ")[0]; + + return new StandardControllerInputConfig + { + Version = InputConfig.CurrentVersion, + Backend = InputBackendType.GamepadSDL2, + Id = cleanId, + Name = name, + ControllerType = ControllerType.ProController, + PlayerIndex = playerIndex, + DeadzoneLeft = 0.1f, + DeadzoneRight = 0.1f, + RangeLeft = 1.0f, + RangeRight = 1.0f, + TriggerThreshold = 0.5f, + LeftJoycon = new LeftJoyconCommonConfig + { + DpadUp = ConfigGamepadInputId.DpadUp, + DpadDown = ConfigGamepadInputId.DpadDown, + DpadLeft = ConfigGamepadInputId.DpadLeft, + DpadRight = ConfigGamepadInputId.DpadRight, + ButtonMinus = ConfigGamepadInputId.Minus, + ButtonL = ConfigGamepadInputId.LeftShoulder, + ButtonZl = ConfigGamepadInputId.LeftTrigger, + ButtonSl = ConfigGamepadInputId.Unbound, + ButtonSr = ConfigGamepadInputId.Unbound, + }, + LeftJoyconStick = new JoyconConfigControllerStick + { + Joystick = ConfigStickInputId.Left, + StickButton = ConfigGamepadInputId.LeftStick, + InvertStickX = false, + InvertStickY = false, + }, + RightJoycon = new RightJoyconCommonConfig + { + ButtonA = isNintendoStyle ? ConfigGamepadInputId.A : ConfigGamepadInputId.B, + ButtonB = isNintendoStyle ? ConfigGamepadInputId.B : ConfigGamepadInputId.A, + ButtonX = isNintendoStyle ? ConfigGamepadInputId.X : ConfigGamepadInputId.Y, + ButtonY = isNintendoStyle ? ConfigGamepadInputId.Y : ConfigGamepadInputId.X, + ButtonPlus = ConfigGamepadInputId.Plus, + ButtonR = ConfigGamepadInputId.RightShoulder, + ButtonZr = ConfigGamepadInputId.RightTrigger, + ButtonSl = ConfigGamepadInputId.Unbound, + ButtonSr = ConfigGamepadInputId.Unbound, + }, + RightJoyconStick = new JoyconConfigControllerStick + { + Joystick = ConfigStickInputId.Right, + StickButton = ConfigGamepadInputId.RightStick, + InvertStickX = false, + InvertStickY = false, + }, + Motion = new StandardMotionConfigController + { + EnableMotion = true, + MotionBackend = MotionInputBackendType.GamepadDriver, + GyroDeadzone = 1, + Sensitivity = 100, + }, + Rumble = new RumbleConfigController + { + EnableRumble = false, + WeakRumble = 1f, + StrongRumble = 1f, + }, + Led = new LedConfigController + { + EnableLed = false, + TurnOffLed = false, + UseRainbow = false, + LedColor = 0xFFFFFFFF, + } + }; + } + + /// + /// Gets the short name of a gamepad by removing SDL prefix and truncating if too long + /// + /// Full gamepad name + /// Maximum length before truncation (default: 50) + /// Short gamepad name + public static string GetShortGamepadName(string name, int maxLength = 50) + { + const string SdlGamepadNamePrefix = "SDL2 Gamepad "; + const string Ellipsis = "..."; + + // First remove SDL prefix if present + string shortName = name; + if (name.StartsWith(SdlGamepadNamePrefix)) + { + shortName = name[SdlGamepadNamePrefix.Length..]; + } + + // Then truncate if too long + if (shortName.Length > maxLength) + { + return $"{shortName.AsSpan(0, maxLength - Ellipsis.Length)}{Ellipsis}"; + } + + return shortName; + } + + /// + /// Determines if a controller uses Nintendo-style button mapping + /// + /// Controller name + /// True if Nintendo-style mapping should be used + public static bool IsNintendoStyleController(string name) + { + return name.Contains("Nintendo"); + } + } +} diff --git a/src/Ryujinx.Common/Configuration/Hid/KeyboardHotkeys.cs b/src/Ryujinx.Common/Configuration/Hid/KeyboardHotkeys.cs index efdb422e7..f84434ba1 100644 --- a/src/Ryujinx.Common/Configuration/Hid/KeyboardHotkeys.cs +++ b/src/Ryujinx.Common/Configuration/Hid/KeyboardHotkeys.cs @@ -15,5 +15,9 @@ namespace Ryujinx.Common.Configuration.Hid public Key CustomVSyncIntervalDecrement { get; set; } public Key TurboMode { get; set; } public bool TurboModeWhileHeld { get; set; } + public Key CycleInputDevicePlayer1 { get; set; } + public Key CycleInputDevicePlayer2 { get; set; } + public Key CycleInputDevicePlayer3 { get; set; } + public Key CycleInputDevicePlayer4 { get; set; } } } diff --git a/src/Ryujinx/Common/KeyboardHotkeyState.cs b/src/Ryujinx/Common/KeyboardHotkeyState.cs index b6fb02f04..f7b7406d2 100644 --- a/src/Ryujinx/Common/KeyboardHotkeyState.cs +++ b/src/Ryujinx/Common/KeyboardHotkeyState.cs @@ -15,5 +15,9 @@ namespace Ryujinx.Ava.Common CustomVSyncIntervalIncrement, CustomVSyncIntervalDecrement, TurboMode, + CycleInputDevicePlayer1, + CycleInputDevicePlayer2, + CycleInputDevicePlayer3, + CycleInputDevicePlayer4, } } diff --git a/src/Ryujinx/Systems/AppHost.cs b/src/Ryujinx/Systems/AppHost.cs index 1c5f64309..801677cb2 100644 --- a/src/Ryujinx/Systems/AppHost.cs +++ b/src/Ryujinx/Systems/AppHost.cs @@ -40,6 +40,11 @@ using Ryujinx.HLE.HOS; using Ryujinx.HLE.HOS.Services.Account.Acc; using Ryujinx.Input; using Ryujinx.Input.HLE; +using Ryujinx.Common.Configuration.Hid; +using Ryujinx.Common.Configuration.Hid.Controller; +using Ryujinx.Common.Configuration.Hid.Controller.Motion; +using Ryujinx.Common.Configuration.Hid.Keyboard; +using System.Linq; using SkiaSharp; using SPB.Graphics.Vulkan; using System; @@ -1333,6 +1338,18 @@ namespace Ryujinx.Ava.Systems _viewModel.Volume = Device.GetVolume(); break; + case KeyboardHotkeyState.CycleInputDevicePlayer1: + CycleInputDevice(HLE.HOS.Services.Hid.PlayerIndex.Player1); + break; + case KeyboardHotkeyState.CycleInputDevicePlayer2: + CycleInputDevice(HLE.HOS.Services.Hid.PlayerIndex.Player2); + break; + case KeyboardHotkeyState.CycleInputDevicePlayer3: + CycleInputDevice(HLE.HOS.Services.Hid.PlayerIndex.Player3); + break; + case KeyboardHotkeyState.CycleInputDevicePlayer4: + CycleInputDevice(HLE.HOS.Services.Hid.PlayerIndex.Player4); + break; case KeyboardHotkeyState.None: (_keyboardInterface as AvaloniaKeyboard).Clear(); break; @@ -1366,6 +1383,118 @@ namespace Ryujinx.Ava.Systems return true; } + private void CycleInputDevice(HLE.HOS.Services.Hid.PlayerIndex playerIndex) + { + // Get current input configuration + List currentConfig = new(ConfigurationState.Instance.Hid.InputConfig.Value); + + // Find current configuration for this player + InputConfig playerConfig = currentConfig.FirstOrDefault(x => x.PlayerIndex == (PlayerIndex)playerIndex); + + // Get available devices from InputManager + List<(DeviceType Type, string Id, string Name)> availableDevices = []; + + // Add disabled option + availableDevices.Add((DeviceType.None, "disabled", "Disabled")); + + // Add keyboard devices + foreach (string id in _inputManager.KeyboardDriver.GamepadsIds) + { + using var gamepad = _inputManager.KeyboardDriver.GetGamepad(id); + if (gamepad != null) + { + availableDevices.Add((DeviceType.Keyboard, id, gamepad.Name)); + } + } + + // Add controller devices + int controllerNumber = 0; + foreach (string id in _inputManager.GamepadDriver.GamepadsIds) + { + using var gamepad = _inputManager.GamepadDriver.GetGamepad(id); + if (gamepad != null) + { + string name = $"{DefaultInputConfigurationProvider.GetShortGamepadName(gamepad.Name)} ({controllerNumber++})"; + availableDevices.Add((DeviceType.Controller, id, name)); + } + } + + // Find current device index + int currentIndex = 0; + if (playerConfig != null) + { + DeviceType currentType = DeviceType.None; + if (playerConfig is StandardKeyboardInputConfig) + currentType = DeviceType.Keyboard; + else if (playerConfig is StandardControllerInputConfig) + currentType = DeviceType.Controller; + + currentIndex = availableDevices.FindIndex(x => x.Type == currentType && x.Id == playerConfig.Id); + if (currentIndex == -1) currentIndex = 0; + } + + // Cycle to next device + int nextIndex = (currentIndex + 1) % availableDevices.Count; + var nextDevice = availableDevices[nextIndex]; + + // Remove existing configuration for this player + currentConfig.RemoveAll(x => x.PlayerIndex == (PlayerIndex)playerIndex); + + // Add new configuration if not disabled + if (nextDevice.Type != DeviceType.None) + { + InputConfig newConfig = CreateDefaultInputConfig(nextDevice, (PlayerIndex)playerIndex); + if (newConfig != null) + { + currentConfig.Add(newConfig); + } + } + + // Apply the new configuration + ConfigurationState.Instance.Hid.InputConfig.Value = currentConfig; + ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath); + + // Reload the input system + NpadManager.ReloadConfiguration(currentConfig, ConfigurationState.Instance.Hid.EnableKeyboard, ConfigurationState.Instance.Hid.EnableMouse); + + // Show controller overlay + ShowControllerOverlay(currentConfig); + } + + private InputConfig CreateDefaultInputConfig((DeviceType Type, string Id, string Name) device, PlayerIndex playerIndex) + { + if (device.Type == DeviceType.Keyboard) + { + return DefaultInputConfigurationProvider.CreateDefaultKeyboardConfig(device.Id, device.Name, playerIndex); + } + else if (device.Type == DeviceType.Controller) + { + bool isNintendoStyle = DefaultInputConfigurationProvider.IsNintendoStyleController(device.Name); + return DefaultInputConfigurationProvider.CreateDefaultControllerConfig(device.Id, device.Name, playerIndex, isNintendoStyle); + } + + return null; + } + + + + private void ShowControllerOverlay(List inputConfigs) + { + Dispatcher.UIThread.InvokeAsync(() => + { + try + { + var overlayWindow = new UI.Windows.ControllerOverlayWindow(_topLevel as Avalonia.Controls.Window); + overlayWindow.ShowControllerBindings(inputConfigs); + overlayWindow.Show(); + } + catch (Exception ex) + { + Logger.Error?.Print(LogClass.Application, $"Failed to show controller overlay: {ex.Message}"); + } + }); + } + private KeyboardHotkeyState GetHotkeyState() { KeyboardHotkeyState state = KeyboardHotkeyState.None; @@ -1418,6 +1547,22 @@ namespace Ryujinx.Ava.Systems { state = KeyboardHotkeyState.TurboMode; } + else if (_keyboardInterface.IsPressed((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.CycleInputDevicePlayer1)) + { + state = KeyboardHotkeyState.CycleInputDevicePlayer1; + } + else if (_keyboardInterface.IsPressed((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.CycleInputDevicePlayer2)) + { + state = KeyboardHotkeyState.CycleInputDevicePlayer2; + } + else if (_keyboardInterface.IsPressed((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.CycleInputDevicePlayer3)) + { + state = KeyboardHotkeyState.CycleInputDevicePlayer3; + } + else if (_keyboardInterface.IsPressed((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.CycleInputDevicePlayer4)) + { + state = KeyboardHotkeyState.CycleInputDevicePlayer4; + } return state; } diff --git a/src/Ryujinx/UI/Models/Input/HotkeyConfig.cs b/src/Ryujinx/UI/Models/Input/HotkeyConfig.cs index 9e557d7b1..78ab40678 100644 --- a/src/Ryujinx/UI/Models/Input/HotkeyConfig.cs +++ b/src/Ryujinx/UI/Models/Input/HotkeyConfig.cs @@ -32,6 +32,14 @@ namespace Ryujinx.Ava.UI.Models.Input [ObservableProperty] private bool _turboModeWhileHeld; + [ObservableProperty] private Key _cycleInputDevicePlayer1; + + [ObservableProperty] private Key _cycleInputDevicePlayer2; + + [ObservableProperty] private Key _cycleInputDevicePlayer3; + + [ObservableProperty] private Key _cycleInputDevicePlayer4; + public HotkeyConfig(KeyboardHotkeys config) { if (config == null) @@ -50,6 +58,10 @@ namespace Ryujinx.Ava.UI.Models.Input CustomVSyncIntervalDecrement = config.CustomVSyncIntervalDecrement; TurboMode = config.TurboMode; TurboModeWhileHeld = config.TurboModeWhileHeld; + CycleInputDevicePlayer1 = config.CycleInputDevicePlayer1; + CycleInputDevicePlayer2 = config.CycleInputDevicePlayer2; + CycleInputDevicePlayer3 = config.CycleInputDevicePlayer3; + CycleInputDevicePlayer4 = config.CycleInputDevicePlayer4; } public KeyboardHotkeys GetConfig() => @@ -67,7 +79,11 @@ namespace Ryujinx.Ava.UI.Models.Input CustomVSyncIntervalIncrement = CustomVSyncIntervalIncrement, CustomVSyncIntervalDecrement = CustomVSyncIntervalDecrement, TurboMode = TurboMode, - TurboModeWhileHeld = TurboModeWhileHeld + TurboModeWhileHeld = TurboModeWhileHeld, + CycleInputDevicePlayer1 = CycleInputDevicePlayer1, + CycleInputDevicePlayer2 = CycleInputDevicePlayer2, + CycleInputDevicePlayer3 = CycleInputDevicePlayer3, + CycleInputDevicePlayer4 = CycleInputDevicePlayer4 }; } } diff --git a/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs b/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs index 81aae6b74..7a775aa7c 100644 --- a/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs @@ -526,18 +526,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input } } - private static string GetShortGamepadName(string str) - { - const string Ellipsis = "..."; - const int MaxSize = 50; - if (str.Length > MaxSize) - { - return $"{str.AsSpan(0, MaxSize - Ellipsis.Length)}{Ellipsis}"; - } - - return str; - } private static string GetShortGamepadId(string str) { @@ -551,7 +540,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input { string GetGamepadName(IGamepad gamepad, int controllerNumber) { - return $"{GetShortGamepadName(gamepad.Name)} ({controllerNumber})"; + return $"{DefaultInputConfigurationProvider.GetShortGamepadName(gamepad.Name)} ({controllerNumber})"; } string GetUniqueGamepadName(IGamepad gamepad, ref int controllerNumber) @@ -579,7 +568,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input if (gamepad != null) { - Devices.Add((DeviceType.Keyboard, id, $"{GetShortGamepadName(gamepad.Name)}")); + Devices.Add((DeviceType.Keyboard, id, $"{DefaultInputConfigurationProvider.GetShortGamepadName(gamepad.Name)}")); } } @@ -652,138 +641,21 @@ namespace Ryujinx.Ava.UI.ViewModels.Input InputConfig config; if (activeDevice.Type == DeviceType.Keyboard) { - string id = activeDevice.Id; - string name = activeDevice.Name; - - config = new StandardKeyboardInputConfig - { - Version = InputConfig.CurrentVersion, - Backend = InputBackendType.WindowKeyboard, - Id = id, - Name = name, - ControllerType = ControllerType.ProController, - LeftJoycon = new LeftJoyconCommonConfig - { - DpadUp = Key.Up, - DpadDown = Key.Down, - DpadLeft = Key.Left, - DpadRight = Key.Right, - ButtonMinus = Key.Minus, - ButtonL = Key.E, - ButtonZl = Key.Q, - ButtonSl = Key.Unbound, - ButtonSr = Key.Unbound, - }, - LeftJoyconStick = - new JoyconConfigKeyboardStick - { - StickUp = Key.W, - StickDown = Key.S, - StickLeft = Key.A, - StickRight = Key.D, - StickButton = Key.F, - }, - RightJoycon = new RightJoyconCommonConfig - { - ButtonA = Key.Z, - ButtonB = Key.X, - ButtonX = Key.C, - ButtonY = Key.V, - ButtonPlus = Key.Plus, - ButtonR = Key.U, - ButtonZr = Key.O, - ButtonSl = Key.Unbound, - ButtonSr = Key.Unbound, - }, - RightJoyconStick = new JoyconConfigKeyboardStick - { - StickUp = Key.I, - StickDown = Key.K, - StickLeft = Key.J, - StickRight = Key.L, - StickButton = Key.H, - }, - }; + config = DefaultInputConfigurationProvider.CreateDefaultKeyboardConfig(activeDevice.Id, activeDevice.Name, _playerId); } else if (activeDevice.Type == DeviceType.Controller) { - bool isNintendoStyle = Devices.ToList().FirstOrDefault(x => x.Id == activeDevice.Id).Name.Contains("Nintendo"); - - string id = activeDevice.Id.Split(" ")[0]; - string name = activeDevice.Name; - - config = new StandardControllerInputConfig - { - Version = InputConfig.CurrentVersion, - Backend = InputBackendType.GamepadSDL2, - Id = id, - Name = name, - ControllerType = ControllerType.ProController, - DeadzoneLeft = 0.1f, - DeadzoneRight = 0.1f, - RangeLeft = 1.0f, - RangeRight = 1.0f, - TriggerThreshold = 0.5f, - LeftJoycon = new LeftJoyconCommonConfig - { - DpadUp = ConfigGamepadInputId.DpadUp, - DpadDown = ConfigGamepadInputId.DpadDown, - DpadLeft = ConfigGamepadInputId.DpadLeft, - DpadRight = ConfigGamepadInputId.DpadRight, - ButtonMinus = ConfigGamepadInputId.Minus, - ButtonL = ConfigGamepadInputId.LeftShoulder, - ButtonZl = ConfigGamepadInputId.LeftTrigger, - ButtonSl = ConfigGamepadInputId.Unbound, - ButtonSr = ConfigGamepadInputId.Unbound, - }, - LeftJoyconStick = new JoyconConfigControllerStick - { - Joystick = ConfigStickInputId.Left, - StickButton = ConfigGamepadInputId.LeftStick, - InvertStickX = false, - InvertStickY = false, - }, - RightJoycon = new RightJoyconCommonConfig - { - ButtonA = isNintendoStyle ? ConfigGamepadInputId.A : ConfigGamepadInputId.B, - ButtonB = isNintendoStyle ? ConfigGamepadInputId.B : ConfigGamepadInputId.A, - ButtonX = isNintendoStyle ? ConfigGamepadInputId.X : ConfigGamepadInputId.Y, - ButtonY = isNintendoStyle ? ConfigGamepadInputId.Y : ConfigGamepadInputId.X, - ButtonPlus = ConfigGamepadInputId.Plus, - ButtonR = ConfigGamepadInputId.RightShoulder, - ButtonZr = ConfigGamepadInputId.RightTrigger, - ButtonSl = ConfigGamepadInputId.Unbound, - ButtonSr = ConfigGamepadInputId.Unbound, - }, - RightJoyconStick = new JoyconConfigControllerStick - { - Joystick = ConfigStickInputId.Right, - StickButton = ConfigGamepadInputId.RightStick, - InvertStickX = false, - InvertStickY = false, - }, - Motion = new StandardMotionConfigController - { - MotionBackend = MotionInputBackendType.GamepadDriver, - EnableMotion = true, - Sensitivity = 100, - GyroDeadzone = 1, - }, - Rumble = new RumbleConfigController - { - StrongRumble = 1f, - WeakRumble = 1f, - EnableRumble = false, - }, - }; + bool isNintendoStyle = DefaultInputConfigurationProvider.IsNintendoStyleController(activeDevice.Name); + config = DefaultInputConfigurationProvider.CreateDefaultControllerConfig(activeDevice.Id, activeDevice.Name, _playerId, isNintendoStyle); } else { - config = new InputConfig(); + config = new InputConfig + { + PlayerIndex = _playerId + }; } - config.PlayerIndex = _playerId; - return config; } diff --git a/src/Ryujinx/UI/Views/Settings/SettingsHotkeysView.axaml b/src/Ryujinx/UI/Views/Settings/SettingsHotkeysView.axaml index 917177fb5..ba82812b9 100644 --- a/src/Ryujinx/UI/Views/Settings/SettingsHotkeysView.axaml +++ b/src/Ryujinx/UI/Views/Settings/SettingsHotkeysView.axaml @@ -120,6 +120,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Ryujinx/UI/Views/Settings/SettingsHotkeysView.axaml.cs b/src/Ryujinx/UI/Views/Settings/SettingsHotkeysView.axaml.cs index b9a5462b2..7f481f82e 100644 --- a/src/Ryujinx/UI/Views/Settings/SettingsHotkeysView.axaml.cs +++ b/src/Ryujinx/UI/Views/Settings/SettingsHotkeysView.axaml.cs @@ -82,7 +82,11 @@ namespace Ryujinx.Ava.UI.Views.Settings { "VolumeDown", () => viewModel.KeyboardHotkey.VolumeDown = Key.Unbound }, { "CustomVSyncIntervalIncrement", () => viewModel.KeyboardHotkey.CustomVSyncIntervalIncrement = Key.Unbound }, { "CustomVSyncIntervalDecrement", () => viewModel.KeyboardHotkey.CustomVSyncIntervalDecrement = Key.Unbound }, - { "TurboMode", () => viewModel.KeyboardHotkey.TurboMode = Key.Unbound } + { "TurboMode", () => viewModel.KeyboardHotkey.TurboMode = Key.Unbound }, + { "CycleInputDevicePlayer1", () => viewModel.KeyboardHotkey.CycleInputDevicePlayer1 = Key.Unbound }, + { "CycleInputDevicePlayer2", () => viewModel.KeyboardHotkey.CycleInputDevicePlayer2 = Key.Unbound }, + { "CycleInputDevicePlayer3", () => viewModel.KeyboardHotkey.CycleInputDevicePlayer3 = Key.Unbound }, + { "CycleInputDevicePlayer4", () => viewModel.KeyboardHotkey.CycleInputDevicePlayer4 = Key.Unbound } }; if (buttonActions.TryGetValue(_currentAssigner.ToggledButton.Name, out Action action)) @@ -162,6 +166,18 @@ namespace Ryujinx.Ava.UI.Views.Settings case "TurboMode": ViewModel.KeyboardHotkey.TurboMode = buttonValue.AsHidType(); break; + case "CycleInputDevicePlayer1": + ViewModel.KeyboardHotkey.CycleInputDevicePlayer1 = buttonValue.AsHidType(); + break; + case "CycleInputDevicePlayer2": + ViewModel.KeyboardHotkey.CycleInputDevicePlayer2 = buttonValue.AsHidType(); + break; + case "CycleInputDevicePlayer3": + ViewModel.KeyboardHotkey.CycleInputDevicePlayer3 = buttonValue.AsHidType(); + break; + case "CycleInputDevicePlayer4": + ViewModel.KeyboardHotkey.CycleInputDevicePlayer4 = buttonValue.AsHidType(); + break; } }); }