mirror of
https://git.ryujinx.app/ryubing/ryujinx.git
synced 2025-06-27 22:06:24 +02:00
Input cycling hotkeys
This commit is contained in:
parent
8765dc9901
commit
175d5f9bb3
9 changed files with 520 additions and 139 deletions
|
@ -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": {
|
||||
|
|
|
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides default input configurations for keyboard and controller devices
|
||||
/// </summary>
|
||||
public static class DefaultInputConfigurationProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a default keyboard input configuration
|
||||
/// </summary>
|
||||
/// <param name="id">Device ID</param>
|
||||
/// <param name="name">Device name</param>
|
||||
/// <param name="playerIndex">Player index</param>
|
||||
/// <param name="controllerType">Controller type (defaults to ProController)</param>
|
||||
/// <returns>Default keyboard input configuration</returns>
|
||||
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<Key>
|
||||
{
|
||||
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<Key>
|
||||
{
|
||||
StickUp = Key.W,
|
||||
StickDown = Key.S,
|
||||
StickLeft = Key.A,
|
||||
StickRight = Key.D,
|
||||
StickButton = Key.F,
|
||||
},
|
||||
RightJoycon = new RightJoyconCommonConfig<Key>
|
||||
{
|
||||
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<Key>
|
||||
{
|
||||
StickUp = Key.I,
|
||||
StickDown = Key.K,
|
||||
StickLeft = Key.J,
|
||||
StickRight = Key.L,
|
||||
StickButton = Key.H,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a default controller input configuration
|
||||
/// </summary>
|
||||
/// <param name="id">Device ID</param>
|
||||
/// <param name="name">Device name</param>
|
||||
/// <param name="playerIndex">Player index</param>
|
||||
/// <param name="isNintendoStyle">Whether to use Nintendo-style button mapping</param>
|
||||
/// <returns>Default controller input configuration</returns>
|
||||
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<ConfigGamepadInputId>
|
||||
{
|
||||
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<ConfigGamepadInputId, ConfigStickInputId>
|
||||
{
|
||||
Joystick = ConfigStickInputId.Left,
|
||||
StickButton = ConfigGamepadInputId.LeftStick,
|
||||
InvertStickX = false,
|
||||
InvertStickY = false,
|
||||
},
|
||||
RightJoycon = new RightJoyconCommonConfig<ConfigGamepadInputId>
|
||||
{
|
||||
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<ConfigGamepadInputId, ConfigStickInputId>
|
||||
{
|
||||
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,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the short name of a gamepad by removing SDL prefix and truncating if too long
|
||||
/// </summary>
|
||||
/// <param name="name">Full gamepad name</param>
|
||||
/// <param name="maxLength">Maximum length before truncation (default: 50)</param>
|
||||
/// <returns>Short gamepad name</returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines if a controller uses Nintendo-style button mapping
|
||||
/// </summary>
|
||||
/// <param name="name">Controller name</param>
|
||||
/// <returns>True if Nintendo-style mapping should be used</returns>
|
||||
public static bool IsNintendoStyleController(string name)
|
||||
{
|
||||
return name.Contains("Nintendo");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,5 +15,9 @@ namespace Ryujinx.Ava.Common
|
|||
CustomVSyncIntervalIncrement,
|
||||
CustomVSyncIntervalDecrement,
|
||||
TurboMode,
|
||||
CycleInputDevicePlayer1,
|
||||
CycleInputDevicePlayer2,
|
||||
CycleInputDevicePlayer3,
|
||||
CycleInputDevicePlayer4,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<InputConfig> 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<InputConfig> 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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Key>
|
||||
{
|
||||
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<Key>
|
||||
{
|
||||
StickUp = Key.W,
|
||||
StickDown = Key.S,
|
||||
StickLeft = Key.A,
|
||||
StickRight = Key.D,
|
||||
StickButton = Key.F,
|
||||
},
|
||||
RightJoycon = new RightJoyconCommonConfig<Key>
|
||||
{
|
||||
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<Key>
|
||||
{
|
||||
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<ConfigGamepadInputId>
|
||||
{
|
||||
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<ConfigGamepadInputId, ConfigStickInputId>
|
||||
{
|
||||
Joystick = ConfigStickInputId.Left,
|
||||
StickButton = ConfigGamepadInputId.LeftStick,
|
||||
InvertStickX = false,
|
||||
InvertStickY = false,
|
||||
},
|
||||
RightJoycon = new RightJoyconCommonConfig<ConfigGamepadInputId>
|
||||
{
|
||||
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<ConfigGamepadInputId, ConfigStickInputId>
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -120,6 +120,30 @@
|
|||
<TextBlock Text="{ext:Locale SettingsTabHotkeysOnlyWhilePressed}" Margin="10,0" />
|
||||
<CheckBox IsChecked="{Binding KeyboardHotkey.TurboModeWhileHeld}" />
|
||||
</StackPanel>
|
||||
<StackPanel>
|
||||
<TextBlock Text="{ext:Locale SettingsTabHotkeysCycleInputDevicePlayer1}" Classes="settingHeader" />
|
||||
<ToggleButton Name="CycleInputDevicePlayer1">
|
||||
<TextBlock Text="{Binding KeyboardHotkey.CycleInputDevicePlayer1, Converter={x:Static helpers:KeyValueConverter.Instance}}" />
|
||||
</ToggleButton>
|
||||
</StackPanel>
|
||||
<StackPanel>
|
||||
<TextBlock Text="{ext:Locale SettingsTabHotkeysCycleInputDevicePlayer2}" Classes="settingHeader" />
|
||||
<ToggleButton Name="CycleInputDevicePlayer2">
|
||||
<TextBlock Text="{Binding KeyboardHotkey.CycleInputDevicePlayer2, Converter={x:Static helpers:KeyValueConverter.Instance}}" />
|
||||
</ToggleButton>
|
||||
</StackPanel>
|
||||
<StackPanel>
|
||||
<TextBlock Text="{ext:Locale SettingsTabHotkeysCycleInputDevicePlayer3}" Classes="settingHeader" />
|
||||
<ToggleButton Name="CycleInputDevicePlayer3">
|
||||
<TextBlock Text="{Binding KeyboardHotkey.CycleInputDevicePlayer3, Converter={x:Static helpers:KeyValueConverter.Instance}}" />
|
||||
</ToggleButton>
|
||||
</StackPanel>
|
||||
<StackPanel>
|
||||
<TextBlock Text="{ext:Locale SettingsTabHotkeysCycleInputDevicePlayer4}" Classes="settingHeader" />
|
||||
<ToggleButton Name="CycleInputDevicePlayer4">
|
||||
<TextBlock Text="{Binding KeyboardHotkey.CycleInputDevicePlayer4, Converter={x:Static helpers:KeyValueConverter.Instance}}" />
|
||||
</ToggleButton>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</ScrollViewer>
|
||||
|
|
|
@ -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<Key>();
|
||||
break;
|
||||
case "CycleInputDevicePlayer1":
|
||||
ViewModel.KeyboardHotkey.CycleInputDevicePlayer1 = buttonValue.AsHidType<Key>();
|
||||
break;
|
||||
case "CycleInputDevicePlayer2":
|
||||
ViewModel.KeyboardHotkey.CycleInputDevicePlayer2 = buttonValue.AsHidType<Key>();
|
||||
break;
|
||||
case "CycleInputDevicePlayer3":
|
||||
ViewModel.KeyboardHotkey.CycleInputDevicePlayer3 = buttonValue.AsHidType<Key>();
|
||||
break;
|
||||
case "CycleInputDevicePlayer4":
|
||||
ViewModel.KeyboardHotkey.CycleInputDevicePlayer4 = buttonValue.AsHidType<Key>();
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue