diff --git a/tests/Avalonia.Base.UnitTests/Input/AccessKeyHandlerTests.cs b/tests/Avalonia.Base.UnitTests/Input/AccessKeyHandlerTests.cs new file mode 100644 index 0000000000..4d8ece4dda --- /dev/null +++ b/tests/Avalonia.Base.UnitTests/Input/AccessKeyHandlerTests.cs @@ -0,0 +1,205 @@ +using System.Collections.Generic; +using Avalonia.Controls; +using Avalonia.Input; +using Avalonia.UnitTests; +using Moq; +using Xunit; + +namespace Avalonia.Base.UnitTests.Input +{ + public class AccessKeyHandlerTests + { + [Fact] + public void Should_Raise_Key_Events_For_Unregistered_Access_Key() + { + var root = new TestRoot(); + var target = new AccessKeyHandler(); + var events = new List(); + + target.SetOwner(root); + root.KeyDown += (s, e) => events.Add($"KeyDown {e.Key}"); + root.KeyUp += (s, e) => events.Add($"KeyUp {e.Key}"); + + KeyDown(root, Key.LeftAlt); + KeyDown(root, Key.A, KeyModifiers.Alt); + KeyUp(root, Key.A, KeyModifiers.Alt); + KeyUp(root, Key.LeftAlt); + + Assert.Equal(new[] + { + "KeyDown LeftAlt", + "KeyDown A", + "KeyUp A", + "KeyUp LeftAlt", + }, events); + } + + [Fact] + public void Should_Raise_Key_Events_For_Unregistered_Access_Key_With_MainMenu() + { + var root = new TestRoot(); + var target = new AccessKeyHandler(); + var menu = Mock.Of(); + var events = new List(); + + target.SetOwner(root); + target.MainMenu = menu; + root.KeyDown += (s, e) => events.Add($"KeyDown {e.Key}"); + root.KeyUp += (s, e) => events.Add($"KeyUp {e.Key}"); + + KeyDown(root, Key.LeftAlt); + KeyDown(root, Key.A, KeyModifiers.Alt); + KeyUp(root, Key.A, KeyModifiers.Alt); + KeyUp(root, Key.LeftAlt); + + Assert.Equal(new[] + { + "KeyDown LeftAlt", + "KeyDown A", + "KeyUp A", + "KeyUp LeftAlt", + }, events); + } + + [Fact] + public void Should_Raise_Key_Events_For_Alt_Key() + { + var root = new TestRoot(); + var target = new AccessKeyHandler(); + var events = new List(); + + target.SetOwner(root); + root.KeyDown += (s, e) => events.Add($"KeyDown {e.Key}"); + root.KeyUp += (s, e) => events.Add($"KeyUp {e.Key}"); + + KeyDown(root, Key.LeftAlt); + KeyUp(root, Key.LeftAlt); + + Assert.Equal(new[] + { + "KeyDown LeftAlt", + "KeyUp LeftAlt", + }, events); + } + + [Fact] + public void Should_Raise_Key_Events_For_Alt_Key_With_MainMenu() + { + var root = new TestRoot(); + var target = new AccessKeyHandler(); + var menu = new Mock(); + var events = new List(); + + menu.SetupAllProperties(); + menu.Setup(x => x.Open()).Callback(() => menu.Setup(x => x.IsOpen).Returns(true)); + + target.SetOwner(root); + target.MainMenu = menu.Object; + + root.KeyDown += (s, e) => events.Add($"KeyDown {e.Key}"); + root.KeyUp += (s, e) => events.Add($"KeyUp {e.Key}"); + + KeyDown(root, Key.LeftAlt); + KeyUp(root, Key.LeftAlt); + KeyDown(root, Key.LeftAlt); + KeyUp(root, Key.LeftAlt); + + Assert.Equal(new[] + { + "KeyDown LeftAlt", + "KeyUp LeftAlt", + "KeyDown LeftAlt", + "KeyUp LeftAlt", + }, events); + } + + [Fact] + public void Should_Raise_Key_Events_For_Registered_Access_Key() + { + var button = new Button(); + var root = new TestRoot(button); + var target = new AccessKeyHandler(); + var events = new List(); + + target.SetOwner(root); + target.Register('A', button); + root.KeyDown += (s, e) => events.Add($"KeyDown {e.Key}"); + root.KeyUp += (s, e) => events.Add($"KeyUp {e.Key}"); + + KeyDown(root, Key.LeftAlt); + KeyDown(root, Key.A, KeyModifiers.Alt); + KeyUp(root, Key.A, KeyModifiers.Alt); + KeyUp(root, Key.LeftAlt); + + // This differs from WPF which doesn't raise the `A` key event, but matches UWP. + Assert.Equal(new[] + { + "KeyDown LeftAlt", + "KeyDown A", + "KeyUp A", + "KeyUp LeftAlt", + }, events); + } + + [Fact] + public void Should_Raise_AccessKeyPressed_For_Registered_Access_Key() + { + var button = new Button(); + var root = new TestRoot(button); + var target = new AccessKeyHandler(); + var raised = 0; + + target.SetOwner(root); + target.Register('A', button); + button.AddHandler(AccessKeyHandler.AccessKeyPressedEvent, (s, e) => ++raised); + + KeyDown(root, Key.LeftAlt); + Assert.Equal(0, raised); + + KeyDown(root, Key.A, KeyModifiers.Alt); + Assert.Equal(1, raised); + + KeyUp(root, Key.A, KeyModifiers.Alt); + KeyUp(root, Key.LeftAlt); + + Assert.Equal(1, raised); + } + + [Fact] + public void Should_Open_MainMenu_On_Alt_KeyUp() + { + var root = new TestRoot(); + var target = new AccessKeyHandler(); + var menu = new Mock(); + + target.SetOwner(root); + target.MainMenu = menu.Object; + + KeyDown(root, Key.LeftAlt); + menu.Verify(x => x.Open(), Times.Never); + + KeyUp(root, Key.LeftAlt); + menu.Verify(x => x.Open(), Times.Once); + } + + private static void KeyDown(IInputElement target, Key key, KeyModifiers modifiers = KeyModifiers.None) + { + target.RaiseEvent(new KeyEventArgs + { + RoutedEvent = InputElement.KeyDownEvent, + Key = key, + KeyModifiers = modifiers, + }); + } + + private static void KeyUp(IInputElement target, Key key, KeyModifiers modifiers = KeyModifiers.None) + { + target.RaiseEvent(new KeyEventArgs + { + RoutedEvent = InputElement.KeyUpEvent, + Key = key, + KeyModifiers = modifiers, + }); + } + } +}