From 39f58e453b93b2cfd58f3d9ea8127925ab5b81f9 Mon Sep 17 00:00:00 2001 From: Babib3l Date: Wed, 18 Mar 2026 21:19:35 +0100 Subject: [PATCH] Track keyboard labels from host layout events --- .../Hid/KeyboardKeyExtensions.cs | 19 ------- src/Ryujinx/Input/AvaloniaKeyboardDriver.cs | 2 + .../UI/Helpers/PhysicalKeyLabelHelper.cs | 54 +++++++++++++++++++ 3 files changed, 56 insertions(+), 19 deletions(-) delete mode 100644 src/Ryujinx.Common/Configuration/Hid/KeyboardKeyExtensions.cs diff --git a/src/Ryujinx.Common/Configuration/Hid/KeyboardKeyExtensions.cs b/src/Ryujinx.Common/Configuration/Hid/KeyboardKeyExtensions.cs deleted file mode 100644 index f6bf50987..000000000 --- a/src/Ryujinx.Common/Configuration/Hid/KeyboardKeyExtensions.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace Ryujinx.Common.Configuration.Hid -{ - public static class KeyboardKeyExtensions - { - public static Key ToKey(this PhysicalKey key) - { - return key is >= PhysicalKey.Unknown and < PhysicalKey.Count - ? (Key)(int)key - : Key.Unknown; - } - - public static PhysicalKey ToPhysicalKey(this Key key) - { - return key is >= Key.Unknown and < Key.Count - ? (PhysicalKey)(int)key - : PhysicalKey.Unknown; - } - } -} diff --git a/src/Ryujinx/Input/AvaloniaKeyboardDriver.cs b/src/Ryujinx/Input/AvaloniaKeyboardDriver.cs index f68d1cfb5..5386fb0ec 100644 --- a/src/Ryujinx/Input/AvaloniaKeyboardDriver.cs +++ b/src/Ryujinx/Input/AvaloniaKeyboardDriver.cs @@ -1,6 +1,7 @@ using Avalonia.Controls; using Avalonia.Input; using Ryujinx.Ava.Common.Locale; +using Ryujinx.Ava.UI.Helpers; using Ryujinx.Input; using System; using System.Collections.Generic; @@ -83,6 +84,7 @@ namespace Ryujinx.Ava.Input { UpdateKeyState(_semanticPressedKeys, GetInputKey(args, KeyboardInputMode.Semantic), true); UpdateKeyState(_physicalPressedKeys, GetInputKey(args, KeyboardInputMode.Physical), true); + PhysicalKeyLabelHelper.UpdateFromEvent(args); KeyPressed?.Invoke(this, args); } diff --git a/src/Ryujinx/UI/Helpers/PhysicalKeyLabelHelper.cs b/src/Ryujinx/UI/Helpers/PhysicalKeyLabelHelper.cs index a3f437457..b272003ae 100644 --- a/src/Ryujinx/UI/Helpers/PhysicalKeyLabelHelper.cs +++ b/src/Ryujinx/UI/Helpers/PhysicalKeyLabelHelper.cs @@ -3,6 +3,7 @@ using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Input; using Ryujinx.Common.Configuration.Hid; using System; +using System.Collections.Concurrent; using System.Collections.Generic; using AvaPhysicalKey = Avalonia.Input.PhysicalKey; using ConfigPhysicalKey = Ryujinx.Common.Configuration.Hid.PhysicalKey; @@ -12,6 +13,8 @@ namespace Ryujinx.Ava.UI.Helpers { internal static class PhysicalKeyLabelHelper { + private static readonly ConcurrentDictionary _observedLayoutLabels = new(); + private static readonly Dictionary _localizedKeysMap = new() { [ConfigPhysicalKey.Unknown] = LocaleKeys.KeyboardLayout_KeyUnknown, @@ -70,6 +73,11 @@ namespace Ryujinx.Ava.UI.Helpers return GetLocalizedString(localeKey); } + if (_observedLayoutLabels.TryGetValue(key, out string observedLabel)) + { + return observedLabel; + } + if (TryGetPrintableKeySymbol(key, out string label)) { return label; @@ -78,6 +86,25 @@ namespace Ryujinx.Ava.UI.Helpers return key.ToString(); } + public static void UpdateFromEvent(KeyEventArgs args) + { + if (args.KeyModifiers != KeyModifiers.None) + { + return; + } + + InputKey inputKey = AvaloniaKeyboardMappingHelper.ToInputKey(args.PhysicalKey); + if (!TryConvertToConfigPhysicalKey(inputKey, out ConfigPhysicalKey physicalKey) || _localizedKeysMap.ContainsKey(physicalKey)) + { + return; + } + + if (TryNormalizePrintableSymbol(args.KeySymbol, out string label)) + { + _observedLayoutLabels[physicalKey] = label; + } + } + private static bool TryGetPrintableKeySymbol(ConfigPhysicalKey key, out string label) { // The legacy enum name for the ISO extra key is misleading, so give it a distinct physical label. @@ -109,6 +136,33 @@ namespace Ryujinx.Ava.UI.Helpers return true; } + private static bool TryNormalizePrintableSymbol(string keySymbol, out string label) + { + if (string.IsNullOrEmpty(keySymbol) || keySymbol.Length != 1 || char.IsControl(keySymbol[0])) + { + label = string.Empty; + return false; + } + + label = char.IsLetter(keySymbol[0]) + ? char.ToUpperInvariant(keySymbol[0]).ToString() + : keySymbol; + + return true; + } + + private static bool TryConvertToConfigPhysicalKey(InputKey key, out ConfigPhysicalKey physicalKey) + { + if (key is >= InputKey.Unknown and < InputKey.Count) + { + physicalKey = (ConfigPhysicalKey)(int)key; + return true; + } + + physicalKey = ConfigPhysicalKey.Unknown; + return false; + } + private static string GetLocalizedString(LocaleKeys localeKey) { if (OperatingSystem.IsMacOS())