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;
}
});
}