A game framework written with osu! in mind.

Fix exact match not matching expectations

+52 -43
+31 -20
osu.Framework.Tests/Input/KeyCombinationModifierTest.cs
··· 12 private static readonly object[][] key_combination_display_test_cases = 13 { 14 // test single combination matches. 15 - new object[] { new KeyCombination(InputKey.Shift), new KeyCombination(InputKey.LShift), false, true }, 16 - new object[] { new KeyCombination(InputKey.Shift), new KeyCombination(InputKey.RShift), false, true }, 17 - new object[] { new KeyCombination(InputKey.Shift), new KeyCombination(InputKey.Shift), false, true }, 18 - new object[] { new KeyCombination(InputKey.LShift), new KeyCombination(InputKey.RShift), false, false }, 19 - new object[] { new KeyCombination(InputKey.RShift), new KeyCombination(InputKey.RShift), false, true }, 20 21 - new object[] { new KeyCombination(InputKey.Shift), new KeyCombination(InputKey.LShift), true, true }, 22 - new object[] { new KeyCombination(InputKey.Shift), new KeyCombination(InputKey.RShift), true, true }, 23 - new object[] { new KeyCombination(InputKey.Shift), new KeyCombination(InputKey.Shift), true, true }, 24 - new object[] { new KeyCombination(InputKey.LShift), new KeyCombination(InputKey.RShift), true, false }, 25 - new object[] { new KeyCombination(InputKey.RShift), new KeyCombination(InputKey.RShift), true, true }, 26 27 // test multiple combination matches. 28 - new object[] { new KeyCombination(InputKey.Shift), new KeyCombination(InputKey.Shift, InputKey.LShift), false, true }, 29 - new object[] { new KeyCombination(InputKey.Shift), new KeyCombination(InputKey.Shift, InputKey.RShift), false, true }, 30 - new object[] { new KeyCombination(InputKey.LShift), new KeyCombination(InputKey.Shift, InputKey.RShift), false, false }, 31 - new object[] { new KeyCombination(InputKey.RShift), new KeyCombination(InputKey.Shift, InputKey.RShift), false, true }, 32 33 - new object[] { new KeyCombination(InputKey.Shift), new KeyCombination(InputKey.Shift, InputKey.LShift), true, true }, 34 - new object[] { new KeyCombination(InputKey.Shift), new KeyCombination(InputKey.Shift, InputKey.RShift), true, true }, 35 - new object[] { new KeyCombination(InputKey.LShift), new KeyCombination(InputKey.Shift, InputKey.RShift), true, false }, 36 - new object[] { new KeyCombination(InputKey.RShift), new KeyCombination(InputKey.Shift, InputKey.RShift), true, true }, 37 }; 38 39 [TestCaseSource(nameof(key_combination_display_test_cases))] 40 - public void TestLeftRightModifierHandling(KeyCombination candidate, KeyCombination pressed, bool exactModifiers, bool shouldContain) 41 - => Assert.AreEqual(shouldContain, KeyCombination.ContainsAll(candidate.Keys, pressed.Keys, exactModifiers)); 42 } 43 }
··· 12 private static readonly object[][] key_combination_display_test_cases = 13 { 14 // test single combination matches. 15 + new object[] { new KeyCombination(InputKey.Shift), new KeyCombination(InputKey.LShift), KeyCombinationMatchingMode.Any, true }, 16 + new object[] { new KeyCombination(InputKey.Shift), new KeyCombination(InputKey.RShift), KeyCombinationMatchingMode.Any, true }, 17 + new object[] { new KeyCombination(InputKey.Shift), new KeyCombination(InputKey.Shift), KeyCombinationMatchingMode.Any, true }, 18 + new object[] { new KeyCombination(InputKey.LShift), new KeyCombination(InputKey.RShift), KeyCombinationMatchingMode.Any, false }, 19 + new object[] { new KeyCombination(InputKey.RShift), new KeyCombination(InputKey.RShift), KeyCombinationMatchingMode.Any, true }, 20 21 + new object[] { new KeyCombination(InputKey.Shift), new KeyCombination(InputKey.LShift), KeyCombinationMatchingMode.Exact, true }, 22 + new object[] { new KeyCombination(InputKey.Shift), new KeyCombination(InputKey.RShift), KeyCombinationMatchingMode.Exact, true }, 23 + new object[] { new KeyCombination(InputKey.Shift), new KeyCombination(InputKey.Shift), KeyCombinationMatchingMode.Exact, true }, 24 + new object[] { new KeyCombination(InputKey.LShift), new KeyCombination(InputKey.RShift), KeyCombinationMatchingMode.Exact, false }, 25 + new object[] { new KeyCombination(InputKey.RShift), new KeyCombination(InputKey.RShift), KeyCombinationMatchingMode.Exact, true }, 26 + 27 + new object[] { new KeyCombination(InputKey.Shift), new KeyCombination(InputKey.LShift), KeyCombinationMatchingMode.Modifiers, true }, 28 + new object[] { new KeyCombination(InputKey.Shift), new KeyCombination(InputKey.RShift), KeyCombinationMatchingMode.Modifiers, true }, 29 + new object[] { new KeyCombination(InputKey.Shift), new KeyCombination(InputKey.Shift), KeyCombinationMatchingMode.Modifiers, true }, 30 + new object[] { new KeyCombination(InputKey.LShift), new KeyCombination(InputKey.RShift), KeyCombinationMatchingMode.Modifiers, false }, 31 + new object[] { new KeyCombination(InputKey.RShift), new KeyCombination(InputKey.RShift), KeyCombinationMatchingMode.Modifiers, true }, 32 33 // test multiple combination matches. 34 + new object[] { new KeyCombination(InputKey.Shift), new KeyCombination(InputKey.Shift, InputKey.LShift), KeyCombinationMatchingMode.Any, true }, 35 + new object[] { new KeyCombination(InputKey.Shift), new KeyCombination(InputKey.Shift, InputKey.RShift), KeyCombinationMatchingMode.Any, true }, 36 + new object[] { new KeyCombination(InputKey.LShift), new KeyCombination(InputKey.Shift, InputKey.RShift), KeyCombinationMatchingMode.Any, false }, 37 + new object[] { new KeyCombination(InputKey.RShift), new KeyCombination(InputKey.Shift, InputKey.RShift), KeyCombinationMatchingMode.Any, true }, 38 + 39 + new object[] { new KeyCombination(InputKey.Shift), new KeyCombination(InputKey.Shift, InputKey.LShift), KeyCombinationMatchingMode.Exact, true }, 40 + new object[] { new KeyCombination(InputKey.Shift), new KeyCombination(InputKey.Shift, InputKey.RShift), KeyCombinationMatchingMode.Exact, true }, 41 + new object[] { new KeyCombination(InputKey.LShift), new KeyCombination(InputKey.Shift, InputKey.RShift), KeyCombinationMatchingMode.Exact, false }, 42 + new object[] { new KeyCombination(InputKey.RShift), new KeyCombination(InputKey.Shift, InputKey.RShift), KeyCombinationMatchingMode.Exact, true }, 43 44 + new object[] { new KeyCombination(InputKey.Shift), new KeyCombination(InputKey.Shift, InputKey.LShift), KeyCombinationMatchingMode.Modifiers, true }, 45 + new object[] { new KeyCombination(InputKey.Shift), new KeyCombination(InputKey.Shift, InputKey.RShift), KeyCombinationMatchingMode.Modifiers, true }, 46 + new object[] { new KeyCombination(InputKey.LShift), new KeyCombination(InputKey.Shift, InputKey.RShift), KeyCombinationMatchingMode.Modifiers, false }, 47 + new object[] { new KeyCombination(InputKey.RShift), new KeyCombination(InputKey.Shift, InputKey.RShift), KeyCombinationMatchingMode.Modifiers, true }, 48 }; 49 50 [TestCaseSource(nameof(key_combination_display_test_cases))] 51 + public void TestLeftRightModifierHandling(KeyCombination candidate, KeyCombination pressed, KeyCombinationMatchingMode matchingMode, bool shouldContain) 52 + => Assert.AreEqual(shouldContain, KeyCombination.ContainsAll(candidate.Keys, pressed.Keys, matchingMode)); 53 } 54 }
+21 -23
osu.Framework/Input/Bindings/KeyCombination.cs
··· 78 if (Keys == pressedKeys.Keys) // Fast test for reference equality of underlying array 79 return true; 80 81 - switch (matchingMode) 82 - { 83 - case KeyCombinationMatchingMode.Any: 84 - return ContainsAll(pressedKeys.Keys, Keys, false); 85 - 86 - case KeyCombinationMatchingMode.Exact: 87 - // Keys are always ordered 88 - return pressedKeys.Keys.SequenceEqual(Keys); 89 - 90 - case KeyCombinationMatchingMode.Modifiers: 91 - return ContainsAll(pressedKeys.Keys, Keys, true); 92 - 93 - default: 94 - return false; 95 - } 96 } 97 98 /// <summary> ··· 100 /// </summary> 101 /// <param name="pressedKey">The keys which have been pressed by a user.</param> 102 /// <param name="candidateKey">The candidate key binding to match against.</param> 103 - /// <param name="exactModifiers">Whether exact matching should be used (ie. no excess modifier keys can be pressed).</param> 104 /// <returns>Whether this is a match.</returns> 105 [MethodImpl(MethodImplOptions.AggressiveInlining)] 106 - internal static bool ContainsAll(ImmutableArray<InputKey> pressedKey, ImmutableArray<InputKey> candidateKey, bool exactModifiers) 107 { 108 // can be local function once attribute on local functions are implemented 109 // optimized to avoid allocation ··· 114 return false; 115 } 116 117 - if (exactModifiers) 118 { 119 - foreach (var key in pressedKey) 120 - { 121 - if (IsModifierKey(key) && !ContainsKey(candidateKey, key)) 122 - return false; 123 - } 124 } 125 126 return true;
··· 78 if (Keys == pressedKeys.Keys) // Fast test for reference equality of underlying array 79 return true; 80 81 + return ContainsAll(pressedKeys.Keys, Keys, matchingMode); 82 } 83 84 /// <summary> ··· 86 /// </summary> 87 /// <param name="pressedKey">The keys which have been pressed by a user.</param> 88 /// <param name="candidateKey">The candidate key binding to match against.</param> 89 + /// <param name="matchingMode">The matching mode to be used when checking.</param> 90 /// <returns>Whether this is a match.</returns> 91 [MethodImpl(MethodImplOptions.AggressiveInlining)] 92 + internal static bool ContainsAll(ImmutableArray<InputKey> pressedKey, ImmutableArray<InputKey> candidateKey, KeyCombinationMatchingMode matchingMode) 93 { 94 // can be local function once attribute on local functions are implemented 95 // optimized to avoid allocation ··· 100 return false; 101 } 102 103 + switch (matchingMode) 104 { 105 + case KeyCombinationMatchingMode.Exact: 106 + foreach (var key in pressedKey) 107 + { 108 + if (!ContainsKey(candidateKey, key)) 109 + return false; 110 + } 111 + 112 + break; 113 + 114 + case KeyCombinationMatchingMode.Modifiers: 115 + foreach (var key in pressedKey) 116 + { 117 + if (IsModifierKey(key) && !ContainsKey(candidateKey, key)) 118 + return false; 119 + } 120 + 121 + break; 122 } 123 124 return true;