瀏覽代碼

Merge pull request #2070 from BDisp/view-keydown-keyup-fix

Fixes #2069. Enable KeyDown and KeyUp events to be canceled (like KeyPress)
Tig Kindel 2 年之前
父節點
當前提交
df72859542
共有 3 個文件被更改,包括 160 次插入11 次删除
  1. 14 7
      Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs
  2. 16 4
      Terminal.Gui/Core/View.cs
  3. 130 0
      UnitTests/ViewTests.cs

+ 14 - 7
Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs

@@ -370,12 +370,14 @@ namespace Terminal.Gui {
 			return keyMod != Key.Null ? keyMod | key : key;
 		}
 
+		Action<KeyEvent> keyDownHandler;
 		Action<KeyEvent> keyHandler;
 		Action<KeyEvent> keyUpHandler;
 		private CursorVisibility savedCursorVisibility;
 
 		public override void PrepareToRun (MainLoop mainLoop, Action<KeyEvent> keyHandler, Action<KeyEvent> keyDownHandler, Action<KeyEvent> keyUpHandler, Action<MouseEvent> 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));
 		}

+ 16 - 4
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;

+ 130 - 0
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);
+		}
 	}
 }