|
@@ -7,35 +7,43 @@ namespace PixiEditor.Helpers;
|
|
|
|
|
|
internal static class InputKeyHelpers
|
|
|
{
|
|
|
+ const string Russian = "00000419";
|
|
|
+ const string Ukrainian = "00000422";
|
|
|
+ const string UkrainianEnhanced = "00020422";
|
|
|
+ const string Arabic1 = "00000401";
|
|
|
+ const string Arabic2 = "00010401";
|
|
|
+ const string Arabic3 = "00020401";
|
|
|
+ private const string InvariantLayoutCode = "00000409"; // Also known as the US Layout
|
|
|
+
|
|
|
+ private static nint? invariantLayout;
|
|
|
+
|
|
|
/// <summary>
|
|
|
/// Returns the charcter of the <paramref name="key"/> mapped to the users keyboard layout
|
|
|
/// </summary>
|
|
|
- public static string GetKeyboardKey(Key key) => GetKeyboardKey(key, CultureInfo.CurrentCulture);
|
|
|
-
|
|
|
- public static string GetKeyboardKey(Key key, CultureInfo culture) => key switch
|
|
|
+ public static string GetKeyboardKey(Key key, bool forceInvariant = false) => key switch
|
|
|
{
|
|
|
- >= Key.NumPad0 and <= Key.Divide => $"Num {GetMappedKey(key, culture)}",
|
|
|
+ >= Key.NumPad0 and <= Key.Divide => $"Num {GetMappedKey(key, forceInvariant)}",
|
|
|
Key.Space => nameof(Key.Space),
|
|
|
Key.Tab => nameof(Key.Tab),
|
|
|
Key.Return => "Enter",
|
|
|
Key.Back => "Backspace",
|
|
|
Key.Escape => "Esc",
|
|
|
- _ => GetMappedKey(key, culture),
|
|
|
+ _ => GetMappedKey(key, forceInvariant),
|
|
|
};
|
|
|
|
|
|
- private static string GetMappedKey(Key key, CultureInfo culture)
|
|
|
+ private static string GetMappedKey(Key key, bool forceInvariant)
|
|
|
{
|
|
|
int virtualKey = KeyInterop.VirtualKeyFromKey(key);
|
|
|
byte[] keyboardState = new byte[256];
|
|
|
|
|
|
- uint scanCode = Win32.MapVirtualKeyExW((uint)virtualKey, Win32.MapType.MAPVK_VK_TO_VSC, culture.KeyboardLayoutId);
|
|
|
- StringBuilder stringBuilder = new(3);
|
|
|
-
|
|
|
- int result = Win32.ToUnicode((uint)virtualKey, scanCode, keyboardState, stringBuilder, stringBuilder.Capacity, 0);
|
|
|
+ nint targetLayout = GetLayoutHkl(forceInvariant);
|
|
|
+
|
|
|
+ uint scanCode = Win32.MapVirtualKeyExW((uint)virtualKey, Win32.MapType.MAPVK_VK_TO_VSC, targetLayout);
|
|
|
+
|
|
|
+ StringBuilder stringBuilder = new(5);
|
|
|
+ int result = Win32.ToUnicodeEx((uint)virtualKey, scanCode, keyboardState, stringBuilder, stringBuilder.Capacity, 0, targetLayout);
|
|
|
|
|
|
- string stringResult;
|
|
|
-
|
|
|
- stringResult = result switch
|
|
|
+ string stringResult = result switch
|
|
|
{
|
|
|
0 => key.ToString(),
|
|
|
-1 => stringBuilder.ToString().ToUpper(),
|
|
@@ -44,4 +52,26 @@ internal static class InputKeyHelpers
|
|
|
|
|
|
return stringResult;
|
|
|
}
|
|
|
+
|
|
|
+ private static nint GetLayoutHkl(bool forceInvariant = false)
|
|
|
+ {
|
|
|
+ if (forceInvariant)
|
|
|
+ {
|
|
|
+ invariantLayout ??= Win32.LoadKeyboardLayoutA(InvariantLayoutCode, 1);
|
|
|
+ return invariantLayout.Value;
|
|
|
+ }
|
|
|
+
|
|
|
+ var builder = new StringBuilder(8);
|
|
|
+ bool success = Win32.GetKeyboardLayoutNameW(builder);
|
|
|
+
|
|
|
+ // Fallback to US layout for certain layouts. Do not prepend a 0x and make sure the string is 8 chars long
|
|
|
+ // Layouts can be found here https://learn.microsoft.com/en-us/windows-hardware/manufacture/desktop/windows-language-pack-default-values?view=windows-11
|
|
|
+ if (!success || builder.ToString() is not (Russian or Ukrainian or UkrainianEnhanced or Arabic1 or Arabic2 or Arabic3))
|
|
|
+ {
|
|
|
+ return Win32.GetKeyboardLayout(0);
|
|
|
+ }
|
|
|
+
|
|
|
+ invariantLayout ??= Win32.LoadKeyboardLayoutA(InvariantLayoutCode, 1);
|
|
|
+ return invariantLayout.Value;
|
|
|
+ }
|
|
|
}
|