Simplify gameplay keyboard physical-key paths

This commit is contained in:
Babib3l
2026-03-19 20:45:48 +01:00
parent 327f90b420
commit 3cbe372b18
9 changed files with 120 additions and 136 deletions

View File

@@ -375,31 +375,6 @@
"zh_TW": "右 ⌘"
}
},
{
"ID": "KeyMenu",
"Translations": {
"ar_SA": "زر القائمة",
"de_DE": "",
"el_GR": "",
"en_US": "Menu",
"es_ES": null,
"fr_FR": null,
"he_IL": "",
"it_IT": "Menù",
"ja_JP": "",
"ko_KR": "메뉴",
"no_NO": "Meny",
"pl_PL": "",
"pt_BR": null,
"ru_RU": "Меню",
"sv_SE": "Meny",
"th_TH": "เมนู",
"tr_TR": "Menü",
"uk_UA": "Меню",
"zh_CN": "菜单键",
"zh_TW": "功能表鍵"
}
},
{
"ID": "KeyUp",
"Translations": {
@@ -1926,4 +1901,4 @@
}
}
]
}
}

View File

@@ -8,23 +8,19 @@ using System.Runtime.CompilerServices;
using System.Threading;
using SDL;
using static SDL.SDL3;
using ConfigPhysicalKey = Ryujinx.Common.Configuration.Hid.PhysicalKey;
namespace Ryujinx.Input.SDL3
{
class SDL3Keyboard : IKeyboard
{
private readonly record struct ButtonMappingEntry(GamepadButtonInputId To, Key From)
{
public bool IsValid => To is not GamepadButtonInputId.Unbound && From is not Key.Unbound;
}
private readonly Lock _userMappingLock = new();
#pragma warning disable IDE0052 // Remove unread private member
private readonly SDL3KeyboardDriver _driver;
#pragma warning restore IDE0052
private StandardKeyboardInputConfig _configuration;
private readonly List<ButtonMappingEntry> _buttonsUserMapping;
private readonly List<KeyboardInputMappingHelper.KeyboardButtonMapping> _buttonsUserMapping;
private static readonly SDL_Keycode[] _keysDriverMapping =
@@ -193,9 +189,9 @@ namespace Ryujinx.Input.SDL3
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private unsafe static int ToSDL3Scancode(Key key)
private unsafe static int ToSDL3Scancode(ConfigPhysicalKey key)
{
if (key is >= Key.Unknown and <= Key.Menu)
if (key is >= ConfigPhysicalKey.Unknown and <= ConfigPhysicalKey.Menu)
{
return -1;
}
@@ -203,18 +199,18 @@ namespace Ryujinx.Input.SDL3
return (int)SDL_GetScancodeFromKey(_keysDriverMapping[(int)key], null);
}
private static SDL_Keymod GetKeyboardModifierMask(Key key)
private static SDL_Keymod GetKeyboardModifierMask(ConfigPhysicalKey key)
{
return key switch
{
Key.ShiftLeft => SDL_Keymod.SDL_KMOD_LSHIFT,
Key.ShiftRight => SDL_Keymod.SDL_KMOD_RSHIFT,
Key.ControlLeft => SDL_Keymod.SDL_KMOD_LCTRL,
Key.ControlRight => SDL_Keymod.SDL_KMOD_RCTRL,
Key.AltLeft => SDL_Keymod.SDL_KMOD_LALT,
Key.AltRight => SDL_Keymod.SDL_KMOD_RALT,
Key.WinLeft => SDL_Keymod.SDL_KMOD_LGUI,
Key.WinRight => SDL_Keymod.SDL_KMOD_RGUI,
ConfigPhysicalKey.ShiftLeft => SDL_Keymod.SDL_KMOD_LSHIFT,
ConfigPhysicalKey.ShiftRight => SDL_Keymod.SDL_KMOD_RSHIFT,
ConfigPhysicalKey.ControlLeft => SDL_Keymod.SDL_KMOD_LCTRL,
ConfigPhysicalKey.ControlRight => SDL_Keymod.SDL_KMOD_RCTRL,
ConfigPhysicalKey.AltLeft => SDL_Keymod.SDL_KMOD_LALT,
ConfigPhysicalKey.AltRight => SDL_Keymod.SDL_KMOD_RALT,
ConfigPhysicalKey.WinLeft => SDL_Keymod.SDL_KMOD_LGUI,
ConfigPhysicalKey.WinRight => SDL_Keymod.SDL_KMOD_RGUI,
// NOTE: Menu key isn't supported by SDL3.
_ => SDL_Keymod.SDL_KMOD_NONE
};
@@ -230,9 +226,9 @@ namespace Ryujinx.Input.SDL3
rawKeyboardState = SDL_GetKeyboardState(null);
}
bool[] keysState = new bool[(int)Key.Count];
bool[] keysState = new bool[(int)ConfigPhysicalKey.Count];
for (Key key = 0; key < Key.Count; key++)
for (ConfigPhysicalKey key = 0; key < ConfigPhysicalKey.Count; key++)
{
int index = ToSDL3Scancode(key);
if (index == -1)
@@ -274,9 +270,9 @@ namespace Ryujinx.Input.SDL3
return result;
}
foreach (ButtonMappingEntry entry in _buttonsUserMapping)
foreach (KeyboardInputMappingHelper.KeyboardButtonMapping entry in _buttonsUserMapping)
{
if (entry.From == Key.Unknown || entry.From == Key.Unbound || entry.To == GamepadButtonInputId.Unbound)
if (!entry.IsValid)
{
continue;
}
@@ -327,10 +323,7 @@ namespace Ryujinx.Input.SDL3
_buttonsUserMapping.Clear();
foreach (KeyboardInputMappingHelper.KeyboardButtonMapping mapping in KeyboardInputMappingHelper.BuildButtonMappings(_configuration))
{
_buttonsUserMapping.Add(new ButtonMappingEntry(mapping.To, mapping.From));
}
_buttonsUserMapping.AddRange(KeyboardInputMappingHelper.BuildButtonMappings(_configuration));
}
}

View File

@@ -1,5 +1,6 @@
using System.Buffers;
using System.Runtime.CompilerServices;
using ConfigPhysicalKey = Ryujinx.Common.Configuration.Hid.PhysicalKey;
namespace Ryujinx.Input
{
@@ -33,12 +34,12 @@ namespace Ryujinx.Input
{
if (_keyState is null)
{
_keyState = new bool[(int)Key.Count];
_keyState = new bool[(int)ConfigPhysicalKey.Count];
}
for (Key key = 0; key < Key.Count; key++)
for (ConfigPhysicalKey key = 0; key < ConfigPhysicalKey.Count; key++)
{
_keyState[(int)key] = keyboard.IsPressed(key);
_keyState[(int)key] = keyboard.IsPressed((Key)(int)key);
}
return new KeyboardStateSnapshot(_keyState);

View File

@@ -8,36 +8,36 @@ namespace Ryujinx.Input
{
public static class KeyboardInputMappingHelper
{
public readonly record struct KeyboardButtonMapping(GamepadButtonInputId To, Key From)
public readonly record struct KeyboardButtonMapping(GamepadButtonInputId To, ConfigPhysicalKey From)
{
public bool IsValid => To is not GamepadButtonInputId.Unbound && From is not Key.Unknown and not Key.Unbound;
public bool IsValid => To is not GamepadButtonInputId.Unbound && From is not ConfigPhysicalKey.Unknown and not ConfigPhysicalKey.Unbound;
}
public static KeyboardButtonMapping[] BuildButtonMappings(StandardKeyboardInputConfig configuration) =>
[
// Left JoyCon
new(GamepadButtonInputId.LeftStick, configuration.LeftJoyconStick.StickButton.ToInputKey()),
new(GamepadButtonInputId.DpadUp, configuration.LeftJoycon.DpadUp.ToInputKey()),
new(GamepadButtonInputId.DpadDown, configuration.LeftJoycon.DpadDown.ToInputKey()),
new(GamepadButtonInputId.DpadLeft, configuration.LeftJoycon.DpadLeft.ToInputKey()),
new(GamepadButtonInputId.DpadRight, configuration.LeftJoycon.DpadRight.ToInputKey()),
new(GamepadButtonInputId.Minus, configuration.LeftJoycon.ButtonMinus.ToInputKey()),
new(GamepadButtonInputId.LeftShoulder, configuration.LeftJoycon.ButtonL.ToInputKey()),
new(GamepadButtonInputId.LeftTrigger, configuration.LeftJoycon.ButtonZl.ToInputKey()),
new(GamepadButtonInputId.SingleRightTrigger0, configuration.LeftJoycon.ButtonSr.ToInputKey()),
new(GamepadButtonInputId.SingleLeftTrigger0, configuration.LeftJoycon.ButtonSl.ToInputKey()),
new(GamepadButtonInputId.LeftStick, configuration.LeftJoyconStick.StickButton),
new(GamepadButtonInputId.DpadUp, configuration.LeftJoycon.DpadUp),
new(GamepadButtonInputId.DpadDown, configuration.LeftJoycon.DpadDown),
new(GamepadButtonInputId.DpadLeft, configuration.LeftJoycon.DpadLeft),
new(GamepadButtonInputId.DpadRight, configuration.LeftJoycon.DpadRight),
new(GamepadButtonInputId.Minus, configuration.LeftJoycon.ButtonMinus),
new(GamepadButtonInputId.LeftShoulder, configuration.LeftJoycon.ButtonL),
new(GamepadButtonInputId.LeftTrigger, configuration.LeftJoycon.ButtonZl),
new(GamepadButtonInputId.SingleRightTrigger0, configuration.LeftJoycon.ButtonSr),
new(GamepadButtonInputId.SingleLeftTrigger0, configuration.LeftJoycon.ButtonSl),
// Right JoyCon
new(GamepadButtonInputId.RightStick, configuration.RightJoyconStick.StickButton.ToInputKey()),
new(GamepadButtonInputId.A, configuration.RightJoycon.ButtonA.ToInputKey()),
new(GamepadButtonInputId.B, configuration.RightJoycon.ButtonB.ToInputKey()),
new(GamepadButtonInputId.X, configuration.RightJoycon.ButtonX.ToInputKey()),
new(GamepadButtonInputId.Y, configuration.RightJoycon.ButtonY.ToInputKey()),
new(GamepadButtonInputId.Plus, configuration.RightJoycon.ButtonPlus.ToInputKey()),
new(GamepadButtonInputId.RightShoulder, configuration.RightJoycon.ButtonR.ToInputKey()),
new(GamepadButtonInputId.RightTrigger, configuration.RightJoycon.ButtonZr.ToInputKey()),
new(GamepadButtonInputId.SingleRightTrigger1, configuration.RightJoycon.ButtonSr.ToInputKey()),
new(GamepadButtonInputId.SingleLeftTrigger1, configuration.RightJoycon.ButtonSl.ToInputKey()),
new(GamepadButtonInputId.RightStick, configuration.RightJoyconStick.StickButton),
new(GamepadButtonInputId.A, configuration.RightJoycon.ButtonA),
new(GamepadButtonInputId.B, configuration.RightJoycon.ButtonB),
new(GamepadButtonInputId.X, configuration.RightJoycon.ButtonX),
new(GamepadButtonInputId.Y, configuration.RightJoycon.ButtonY),
new(GamepadButtonInputId.Plus, configuration.RightJoycon.ButtonPlus),
new(GamepadButtonInputId.RightShoulder, configuration.RightJoycon.ButtonR),
new(GamepadButtonInputId.RightTrigger, configuration.RightJoycon.ButtonZr),
new(GamepadButtonInputId.SingleRightTrigger1, configuration.RightJoycon.ButtonSr),
new(GamepadButtonInputId.SingleLeftTrigger1, configuration.RightJoycon.ButtonSl),
];
public static (short X, short Y) GetStickValues(ref KeyboardStateSnapshot snapshot, JoyconConfigKeyboardStick<ConfigPhysicalKey> stickConfig)
@@ -45,22 +45,22 @@ namespace Ryujinx.Input
short stickX = 0;
short stickY = 0;
if (snapshot.IsPressed(stickConfig.StickUp.ToInputKey()))
if (snapshot.IsPressed(stickConfig.StickUp))
{
stickY += 1;
}
if (snapshot.IsPressed(stickConfig.StickDown.ToInputKey()))
if (snapshot.IsPressed(stickConfig.StickDown))
{
stickY -= 1;
}
if (snapshot.IsPressed(stickConfig.StickRight.ToInputKey()))
if (snapshot.IsPressed(stickConfig.StickRight))
{
stickX += 1;
}
if (snapshot.IsPressed(stickConfig.StickLeft.ToInputKey()))
if (snapshot.IsPressed(stickConfig.StickLeft))
{
stickX -= 1;
}

View File

@@ -1,4 +1,5 @@
using System.Runtime.CompilerServices;
using ConfigPhysicalKey = Ryujinx.Common.Configuration.Hid.PhysicalKey;
namespace Ryujinx.Input
{
@@ -25,5 +26,8 @@ namespace Ryujinx.Input
/// <returns>True if the given key is pressed</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool IsPressed(Key key) => KeysState[(int)key];
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool IsPressed(ConfigPhysicalKey key) => KeysState[(int)key];
}
}

View File

@@ -1,14 +0,0 @@
using ConfigPhysicalKey = Ryujinx.Common.Configuration.Hid.PhysicalKey;
namespace Ryujinx.Input
{
public static class PhysicalKeyExtensions
{
public static Key ToInputKey(this ConfigPhysicalKey key)
{
return key is >= ConfigPhysicalKey.Unknown and < ConfigPhysicalKey.Count
? (Key)(int)key
: Key.Unknown;
}
}
}

View File

@@ -12,7 +12,7 @@ namespace Ryujinx.Ava.Input
{
internal class AvaloniaKeyboard : IKeyboard
{
private readonly List<ButtonMappingEntry> _buttonsUserMapping;
private readonly List<KeyboardInputMappingHelper.KeyboardButtonMapping> _buttonsUserMapping;
private readonly AvaloniaKeyboardDriver _driver;
private readonly KeyboardInputMode _mode;
private StandardKeyboardInputConfig _configuration;
@@ -25,12 +25,6 @@ namespace Ryujinx.Ava.Input
public bool IsConnected => true;
public GamepadFeaturesFlag Features => GamepadFeaturesFlag.None;
private readonly record struct ButtonMappingEntry(GamepadButtonInputId To, Key From)
{
public bool IsValid => To is not GamepadButtonInputId.Unbound && From is not Key.Unknown and not Key.Unbound;
}
public AvaloniaKeyboard(AvaloniaKeyboardDriver driver, string id, string name, KeyboardInputMode mode)
{
_buttonsUserMapping = [];
@@ -58,7 +52,7 @@ namespace Ryujinx.Ava.Input
return result;
}
foreach (ButtonMappingEntry entry in _buttonsUserMapping)
foreach (KeyboardInputMappingHelper.KeyboardButtonMapping entry in _buttonsUserMapping)
{
if (!entry.IsValid)
{
@@ -117,10 +111,7 @@ namespace Ryujinx.Ava.Input
_buttonsUserMapping.Clear();
foreach (KeyboardInputMappingHelper.KeyboardButtonMapping mapping in KeyboardInputMappingHelper.BuildButtonMappings(_configuration))
{
_buttonsUserMapping.Add(new ButtonMappingEntry(mapping.To, mapping.From));
}
_buttonsUserMapping.AddRange(KeyboardInputMappingHelper.BuildButtonMappings(_configuration));
}
}

View File

@@ -4,6 +4,7 @@ using Ryujinx.Ava.Common.Locale;
using Ryujinx.Input;
using System;
using System.Collections.Generic;
using ConfigPhysicalKey = Ryujinx.Common.Configuration.Hid.PhysicalKey;
using Key = Ryujinx.Input.Key;
namespace Ryujinx.Ava.Input
@@ -13,7 +14,7 @@ namespace Ryujinx.Ava.Input
private static readonly string[] _keyboardIdentifers = ["0"];
private readonly Control _control;
private readonly Dictionary<Key, int> _semanticPressedKeys;
private readonly Dictionary<Key, int> _physicalPressedKeys;
private readonly Dictionary<ConfigPhysicalKey, int> _physicalPressedKeys;
private readonly KeyboardInputMode _defaultMode;
public event EventHandler<KeyEventArgs> KeyPressed;
@@ -98,12 +99,21 @@ namespace Ryujinx.Ava.Input
return false;
}
return GetPressedKeys(mode).ContainsKey(key);
return mode == KeyboardInputMode.Physical
? _physicalPressedKeys.ContainsKey((ConfigPhysicalKey)(int)key)
: _semanticPressedKeys.ContainsKey(key);
}
internal void Clear(KeyboardInputMode mode)
{
GetPressedKeys(mode).Clear();
if (mode == KeyboardInputMode.Physical)
{
_physicalPressedKeys.Clear();
}
else
{
_semanticPressedKeys.Clear();
}
}
public void Clear()
@@ -112,11 +122,6 @@ namespace Ryujinx.Ava.Input
_physicalPressedKeys.Clear();
}
private Dictionary<Key, int> GetPressedKeys(KeyboardInputMode mode)
{
return mode == KeyboardInputMode.Physical ? _physicalPressedKeys : _semanticPressedKeys;
}
private static void UpdateKeyState(Dictionary<Key, int> pressedKeys, Key key, bool isPressed)
{
if (key is Key.Unknown or Key.Unbound)
@@ -151,24 +156,53 @@ namespace Ryujinx.Ava.Input
}
}
private void UpdateKeyStates(KeyEventArgs args, bool isPressed)
private static void UpdateKeyState(Dictionary<ConfigPhysicalKey, int> pressedKeys, ConfigPhysicalKey key, bool isPressed)
{
UpdateKeyState(_semanticPressedKeys, GetInputKey(args, KeyboardInputMode.Semantic), isPressed);
UpdateKeyState(_physicalPressedKeys, GetInputKey(args, KeyboardInputMode.Physical), isPressed);
}
private static Key GetInputKey(KeyEventArgs args, KeyboardInputMode mode)
{
if (mode == KeyboardInputMode.Physical)
if (key is ConfigPhysicalKey.Unknown or ConfigPhysicalKey.Unbound)
{
Key physicalKey = AvaloniaKeyboardMappingHelper.ToInputKey(args.PhysicalKey);
return physicalKey != Key.Unknown
? physicalKey
: AvaloniaKeyboardMappingHelper.ToInputKey(args.Key);
return;
}
return AvaloniaKeyboardMappingHelper.ToInputKey(args.PhysicalKey, args.Key);
if (isPressed)
{
if (pressedKeys.TryGetValue(key, out int count))
{
pressedKeys[key] = count + 1;
}
else
{
pressedKeys[key] = 1;
}
return;
}
if (pressedKeys.TryGetValue(key, out int currentCount))
{
if (currentCount <= 1)
{
pressedKeys.Remove(key);
}
else
{
pressedKeys[key] = currentCount - 1;
}
}
}
private void UpdateKeyStates(KeyEventArgs args, bool isPressed)
{
UpdateKeyState(_semanticPressedKeys, AvaloniaKeyboardMappingHelper.ToInputKey(args.PhysicalKey, args.Key), isPressed);
UpdateKeyState(_physicalPressedKeys, GetPhysicalInputKey(args), isPressed);
}
private static ConfigPhysicalKey GetPhysicalInputKey(KeyEventArgs args)
{
Key key = AvaloniaKeyboardMappingHelper.ToInputKey(args.PhysicalKey);
return key is >= Key.Unknown and < Key.Count
? (ConfigPhysicalKey)(int)key
: ConfigPhysicalKey.Unknown;
}
public void Dispose()

View File

@@ -154,42 +154,42 @@ namespace Ryujinx.Ava.UI.Models.Input
{
KeyboardStateSnapshot snapshot = keyboard.GetKeyboardStateSnapshot();
if (snapshot.IsPressed(KeyboardConfig.LeftStickRight.ToInputKey()))
if (snapshot.IsPressed(KeyboardConfig.LeftStickRight))
{
leftBuffer.Item1 += 1;
}
if (snapshot.IsPressed(KeyboardConfig.LeftStickLeft.ToInputKey()))
if (snapshot.IsPressed(KeyboardConfig.LeftStickLeft))
{
leftBuffer.Item1 -= 1;
}
if (snapshot.IsPressed(KeyboardConfig.LeftStickUp.ToInputKey()))
if (snapshot.IsPressed(KeyboardConfig.LeftStickUp))
{
leftBuffer.Item2 += 1;
}
if (snapshot.IsPressed(KeyboardConfig.LeftStickDown.ToInputKey()))
if (snapshot.IsPressed(KeyboardConfig.LeftStickDown))
{
leftBuffer.Item2 -= 1;
}
if (snapshot.IsPressed(KeyboardConfig.RightStickRight.ToInputKey()))
if (snapshot.IsPressed(KeyboardConfig.RightStickRight))
{
rightBuffer.Item1 += 1;
}
if (snapshot.IsPressed(KeyboardConfig.RightStickLeft.ToInputKey()))
if (snapshot.IsPressed(KeyboardConfig.RightStickLeft))
{
rightBuffer.Item1 -= 1;
}
if (snapshot.IsPressed(KeyboardConfig.RightStickUp.ToInputKey()))
if (snapshot.IsPressed(KeyboardConfig.RightStickUp))
{
rightBuffer.Item2 += 1;
}
if (snapshot.IsPressed(KeyboardConfig.RightStickDown.ToInputKey()))
if (snapshot.IsPressed(KeyboardConfig.RightStickDown))
{
rightBuffer.Item2 -= 1;
}