diff --git a/Keybinding.Test/ModifierAliasNormalizationTests.cs b/Keybinding.Test/ModifierAliasNormalizationTests.cs index 449fd09..2f1c3aa 100644 --- a/Keybinding.Test/ModifierAliasNormalizationTests.cs +++ b/Keybinding.Test/ModifierAliasNormalizationTests.cs @@ -93,6 +93,16 @@ public void EveryConstructionPath_NormalizesModifierAliases(string alias, string [DataRow("D7", "7")] [DataRow("D8", "8")] [DataRow("D9", "9")] + // Browser KeyboardEvent.code and Silk.NET Key names for letters and digits (ktsu-dev/Keybinding#218) + [DataRow("KeyA", "A")] + [DataRow("KeyS", "S")] + [DataRow("KeyZ", "Z")] + [DataRow("Digit0", "0")] + [DataRow("Digit1", "1")] + [DataRow("Digit9", "9")] + [DataRow("Number0", "0")] + [DataRow("Number1", "1")] + [DataRow("Number9", "9")] public void ChordParse_KeyAliasesMatchCanonicalName(string alias, string canonical) { ArgumentNullException.ThrowIfNull(alias); @@ -104,6 +114,39 @@ public void ChordParse_KeyAliasesMatchCanonicalName(string alias, string canonic Assert.AreEqual(new Note(canonical), new Note(NoteName.Create(alias.ToUpperInvariant()))); } + [TestMethod] + [DataRow("ControlLeft+KeyS", "Ctrl+S")] + [DataRow("ControlLeft+Digit1", "Ctrl+1")] + [DataRow("ControlLeft+Number1", "Ctrl+1")] + [DataRow("ShiftLeft+MetaLeft+KeyK", "Shift+Meta+K")] + public void ChordParse_BrowserAndSilkKeyNames_DisplayAsCanonicalChord(string framework, string canonical) + { + Chord chord = Chord.Parse(framework); + + Assert.AreEqual(Chord.Parse(canonical), chord); + Assert.AreEqual(canonical, chord.ToString()); + } + + [TestMethod] + [DataRow("Numpad1")] + [DataRow("NumPad1")] + [DataRow("Keypad1")] + [DataRow("Key")] + [DataRow("Key1")] + [DataRow("KeyAB")] + [DataRow("Digit")] + [DataRow("DigitA")] + [DataRow("Digit10")] + [DataRow("Number")] + [DataRow("NumberA")] + public void NoteConstructor_OtherKeyNamesStayDistinct(string key) + { + ArgumentNullException.ThrowIfNull(key); + Note note = new(key); + + Assert.AreEqual(key.ToUpperInvariant(), note.Key.ToString()); + } + [TestMethod] [DataRow("control")] [DataRow("Control")] diff --git a/Keybinding/Models/MusicalTypes.cs b/Keybinding/Models/MusicalTypes.cs index acbe933..57db5f1 100644 --- a/Keybinding/Models/MusicalTypes.cs +++ b/Keybinding/Models/MusicalTypes.cs @@ -71,11 +71,26 @@ private static string ValidateKey(string key) => /// The canonical key name private static string CanonicalizeKey(string key) { + // Letter and main-row digit keys as UI frameworks name them: WinForms/WPF D0-D9, browser + // KeyboardEvent.code KeyA-KeyZ and Digit0-Digit9, and Silk.NET Key.Number0-Number9. + // Numpad keys (NumPad0-9, Numpad0-9, Keypad0-9) stay distinct, as an app may bind them separately. if (key.Length == 2 && key[0] == 'D' && key[1] is >= '0' and <= '9') { return key[1..]; } + if (key.Length == 4 && key.StartsWith("KEY", StringComparison.Ordinal) && key[3] is >= 'A' and <= 'Z') + { + return key[3..]; + } + + if (((key.Length == 6 && key.StartsWith("DIGIT", StringComparison.Ordinal)) + || (key.Length == 7 && key.StartsWith("NUMBER", StringComparison.Ordinal))) + && key[^1] is >= '0' and <= '9') + { + return key[^1..]; + } + return key switch { // Modifiers, including the left and right variants and the names UI frameworks give them