diff --git a/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs b/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs index 50662f364..8189207bc 100644 --- a/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs @@ -370,12 +370,14 @@ namespace Terminal.Gui { return keyMod != Key.Null ? keyMod | key : key; } + Action keyDownHandler; Action keyHandler; Action keyUpHandler; private CursorVisibility savedCursorVisibility; public override void PrepareToRun (MainLoop mainLoop, Action keyHandler, Action keyDownHandler, Action keyUpHandler, Action mouseHandler) { + this.keyDownHandler = keyDownHandler; this.keyHandler = keyHandler; this.keyUpHandler = keyUpHandler; @@ -386,20 +388,25 @@ namespace Terminal.Gui { void ProcessInput (ConsoleKeyInfo consoleKey) { keyModifiers = new KeyModifiers (); - var map = MapKey (consoleKey); - if (map == (Key)0xffffffff) - return; - - if (consoleKey.Modifiers.HasFlag (ConsoleModifiers.Alt)) { - keyModifiers.Alt = true; - } if (consoleKey.Modifiers.HasFlag (ConsoleModifiers.Shift)) { keyModifiers.Shift = true; } + if (consoleKey.Modifiers.HasFlag (ConsoleModifiers.Alt)) { + keyModifiers.Alt = true; + } if (consoleKey.Modifiers.HasFlag (ConsoleModifiers.Control)) { keyModifiers.Ctrl = true; } + var map = MapKey (consoleKey); + if (map == (Key)0xffffffff) { + if ((consoleKey.Modifiers & (ConsoleModifiers.Shift | ConsoleModifiers.Alt | ConsoleModifiers.Control)) != 0) { + keyDownHandler (new KeyEvent (map, keyModifiers)); + keyUpHandler (new KeyEvent (map, keyModifiers)); + } + return; + } + keyDownHandler (new KeyEvent (map, keyModifiers)); keyHandler (new KeyEvent (map, keyModifiers)); keyUpHandler (new KeyEvent (map, keyModifiers)); } diff --git a/Terminal.Gui/Core/View.cs b/Terminal.Gui/Core/View.cs index 67dfdf755..ea9d80885 100644 --- a/Terminal.Gui/Core/View.cs +++ b/Terminal.Gui/Core/View.cs @@ -1932,8 +1932,14 @@ namespace Terminal.Gui { if (args.Handled) { return true; } - if (Focused?.Enabled == true && Focused?.OnKeyDown (keyEvent) == true) { - return true; + if (Focused?.Enabled == true) { + Focused.KeyDown?.Invoke (args); + if (args.Handled) { + return true; + } + if (Focused?.OnKeyDown (keyEvent) == true) { + return true; + } } return false; @@ -1956,8 +1962,14 @@ namespace Terminal.Gui { if (args.Handled) { return true; } - if (Focused?.Enabled == true && Focused?.OnKeyUp (keyEvent) == true) { - return true; + if (Focused?.Enabled == true) { + Focused.KeyUp?.Invoke (args); + if (args.Handled) { + return true; + } + if (Focused?.OnKeyUp (keyEvent) == true) { + return true; + } } return false; diff --git a/UnitTests/ViewTests.cs b/UnitTests/ViewTests.cs index 3c03abe3f..5218060ab 100644 --- a/UnitTests/ViewTests.cs +++ b/UnitTests/ViewTests.cs @@ -3910,5 +3910,135 @@ This is a tes Assert.True (viewCalled); Assert.True (tvCalled); } + + [Fact, AutoInitShutdown] + public void KeyDown_And_KeyUp_Events_Must_Called_Before_OnKeyDown_And_OnKeyUp () + { + var keyDown = false; + var keyPress = false; + var keyUp = false; + + var view = new DerivedView (); + view.KeyDown += (e) => { + Assert.Equal (Key.a, e.KeyEvent.Key); + Assert.False (keyDown); + Assert.False (view.IsKeyDown); + e.Handled = true; + keyDown = true; + }; + view.KeyPress += (e) => { + Assert.Equal (Key.a, e.KeyEvent.Key); + Assert.False (keyPress); + Assert.False (view.IsKeyPress); + e.Handled = true; + keyPress = true; + }; + view.KeyUp += (e) => { + Assert.Equal (Key.a, e.KeyEvent.Key); + Assert.False (keyUp); + Assert.False (view.IsKeyUp); + e.Handled = true; + keyUp = true; + }; + + Application.Top.Add (view); + + Console.MockKeyPresses.Push (new ConsoleKeyInfo ('a', ConsoleKey.A, false, false, false)); + + Application.Iteration += () => Application.RequestStop (); + + Assert.True (view.CanFocus); + + Application.Run (); + Application.Shutdown (); + + Assert.True (keyDown); + Assert.True (keyPress); + Assert.True (keyUp); + Assert.False (view.IsKeyDown); + Assert.False (view.IsKeyPress); + Assert.False (view.IsKeyUp); + } + + public class DerivedView : View { + public DerivedView () + { + CanFocus = true; + } + + public bool IsKeyDown { get; set; } + public bool IsKeyPress { get; set; } + public bool IsKeyUp { get; set; } + + public override bool OnKeyDown (KeyEvent keyEvent) + { + IsKeyDown = true; + return true; + } + + public override bool ProcessKey (KeyEvent keyEvent) + { + IsKeyPress = true; + return true; + } + + public override bool OnKeyUp (KeyEvent keyEvent) + { + IsKeyUp = true; + return true; + } + } + + [Theory, AutoInitShutdown] + [InlineData (true, false, false)] + [InlineData (true, true, false)] + [InlineData (true, true, true)] + public void KeyDown_And_KeyUp_Events_With_Only_Key_Modifiers (bool shift, bool alt, bool control) + { + var keyDown = false; + var keyPress = false; + var keyUp = false; + + var view = new DerivedView (); + view.KeyDown += (e) => { + Assert.Equal (-1, e.KeyEvent.KeyValue); + Assert.Equal (shift, e.KeyEvent.IsShift); + Assert.Equal (alt, e.KeyEvent.IsAlt); + Assert.Equal (control, e.KeyEvent.IsCtrl); + Assert.False (keyDown); + Assert.False (view.IsKeyDown); + keyDown = true; + }; + view.KeyPress += (e) => { + keyPress = true; + }; + view.KeyUp += (e) => { + Assert.Equal (-1, e.KeyEvent.KeyValue); + Assert.Equal (shift, e.KeyEvent.IsShift); + Assert.Equal (alt, e.KeyEvent.IsAlt); + Assert.Equal (control, e.KeyEvent.IsCtrl); + Assert.False (keyUp); + Assert.False (view.IsKeyUp); + keyUp = true; + }; + + Application.Top.Add (view); + + Console.MockKeyPresses.Push (new ConsoleKeyInfo ('\0', (ConsoleKey)'\0', shift, alt, control)); + + Application.Iteration += () => Application.RequestStop (); + + Assert.True (view.CanFocus); + + Application.Run (); + Application.Shutdown (); + + Assert.True (keyDown); + Assert.False (keyPress); + Assert.True (keyUp); + Assert.True (view.IsKeyDown); + Assert.False (view.IsKeyPress); + Assert.True (view.IsKeyUp); + } } }