KeyboardEventTests.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. using Xunit.Abstractions;
  2. // Alias Console to MockConsole so we don't accidentally use Console
  3. namespace Terminal.Gui.ViewTests;
  4. public class KeyboardEventTests (ITestOutputHelper output) : TestsAllViews
  5. {
  6. /// <summary>
  7. /// This tests that when a new key down event is sent to the view will fire the key-down related
  8. /// events: KeyDown and KeyDownNotHandled. Note that KeyUp is independent.
  9. /// </summary>
  10. [Theory]
  11. [MemberData (nameof (AllViewTypes))]
  12. public void AllViews_NewKeyDownEvent_All_EventsFire (Type viewType)
  13. {
  14. var view = CreateInstanceIfNotGeneric (viewType);
  15. if (view == null)
  16. {
  17. output.WriteLine ($"ERROR: Skipping generic view: {viewType}");
  18. return;
  19. }
  20. output.WriteLine ($"Testing {viewType}");
  21. var keyDown = false;
  22. view.KeyDown += (s, a) =>
  23. {
  24. a.Handled = false; // don't handle it so the other events are called
  25. keyDown = true;
  26. };
  27. var keyDownNotHandled = false;
  28. view.KeyDownNotHandled += (s, a) =>
  29. {
  30. a.Handled = true;
  31. keyDownNotHandled = true;
  32. };
  33. // Key.Empty is invalid, but it's used here to test that the event is fired
  34. Assert.True (view.NewKeyDownEvent (Key.Empty)); // this will be true because the ProcessKeyDown event handled it
  35. Assert.True (keyDown);
  36. Assert.True (keyDownNotHandled);
  37. view.Dispose ();
  38. }
  39. /// <summary>
  40. /// This tests that when a new key up event is sent to the view the view will fire the 1 key-up related event:
  41. /// KeyUp
  42. /// </summary>
  43. [Theory]
  44. [MemberData (nameof (AllViewTypes))]
  45. public void AllViews_NewKeyUpEvent_All_EventsFire (Type viewType)
  46. {
  47. var view = CreateInstanceIfNotGeneric (viewType);
  48. if (view == null)
  49. {
  50. output.WriteLine ($"ERROR: Generic view {viewType}");
  51. return;
  52. }
  53. output.WriteLine ($"Testing {view.GetType ().Name}");
  54. var keyUp = false;
  55. view.KeyUp += (s, a) =>
  56. {
  57. a.Handled = true;
  58. keyUp = true;
  59. };
  60. Assert.True (view.NewKeyUpEvent (Key.A)); // this will be true because the KeyUp event handled it
  61. Assert.True (keyUp);
  62. view.Dispose ();
  63. }
  64. [Theory]
  65. [InlineData (true, false, false)]
  66. [InlineData (true, true, false)]
  67. [InlineData (true, true, true)]
  68. public void NewKeyDownUpEvents_Events_Are_Raised_With_Only_Key_Modifiers (bool shift, bool alt, bool control)
  69. {
  70. var keyDown = false;
  71. var keyDownNotHandled = false;
  72. var keyUp = false;
  73. var view = new OnNewKeyTestView ();
  74. view.CancelVirtualMethods = false;
  75. view.KeyDown += (s, e) =>
  76. {
  77. Assert.Equal (KeyCode.Null, e.KeyCode & ~KeyCode.CtrlMask & ~KeyCode.AltMask & ~KeyCode.ShiftMask);
  78. Assert.Equal (shift, e.IsShift);
  79. Assert.Equal (alt, e.IsAlt);
  80. Assert.Equal (control, e.IsCtrl);
  81. Assert.False (keyDown);
  82. Assert.True (view.OnKeyDownCalled);
  83. keyDown = true;
  84. };
  85. view.KeyDownNotHandled += (s, e) => { keyDownNotHandled = true; };
  86. view.KeyUp += (s, e) =>
  87. {
  88. Assert.Equal (KeyCode.Null, e.KeyCode & ~KeyCode.CtrlMask & ~KeyCode.AltMask & ~KeyCode.ShiftMask);
  89. Assert.Equal (shift, e.IsShift);
  90. Assert.Equal (alt, e.IsAlt);
  91. Assert.Equal (control, e.IsCtrl);
  92. Assert.False (keyUp);
  93. Assert.True (view.OnKeyUpCalled);
  94. keyUp = true;
  95. };
  96. view.NewKeyDownEvent (
  97. new (
  98. KeyCode.Null
  99. | (shift ? KeyCode.ShiftMask : 0)
  100. | (alt ? KeyCode.AltMask : 0)
  101. | (control ? KeyCode.CtrlMask : 0)
  102. )
  103. );
  104. Assert.True (keyDownNotHandled);
  105. Assert.True (view.OnKeyDownCalled);
  106. Assert.True (view.OnProcessKeyDownCalled);
  107. view.NewKeyUpEvent (
  108. new (
  109. KeyCode.Null
  110. | (shift ? KeyCode.ShiftMask : 0)
  111. | (alt ? KeyCode.AltMask : 0)
  112. | (control ? KeyCode.CtrlMask : 0)
  113. )
  114. );
  115. Assert.True (keyUp);
  116. Assert.True (view.OnKeyUpCalled);
  117. }
  118. [Fact]
  119. public void NewKeyDownEvent_Handled_True_Stops_Processing ()
  120. {
  121. var keyDown = false;
  122. var keyDownNotHandled = false;
  123. var view = new OnNewKeyTestView ();
  124. Assert.True (view.CanFocus);
  125. view.CancelVirtualMethods = false;
  126. view.KeyDown += (s, e) =>
  127. {
  128. Assert.Equal (KeyCode.A, e.KeyCode);
  129. Assert.False (keyDown);
  130. Assert.True (view.OnKeyDownCalled);
  131. e.Handled = true;
  132. keyDown = true;
  133. };
  134. view.KeyDownNotHandled += (s, e) =>
  135. {
  136. Assert.Equal (KeyCode.A, e.KeyCode);
  137. Assert.False (keyDownNotHandled);
  138. Assert.False (view.OnProcessKeyDownCalled);
  139. e.Handled = true;
  140. keyDownNotHandled = true;
  141. };
  142. view.NewKeyDownEvent (Key.A);
  143. Assert.True (keyDown);
  144. Assert.False (keyDownNotHandled);
  145. Assert.True (view.OnKeyDownCalled);
  146. Assert.False (view.OnProcessKeyDownCalled);
  147. }
  148. [Fact]
  149. public void NewKeyDownEvent_KeyDown_Handled_Stops_Processing ()
  150. {
  151. var view = new View ();
  152. var keyDownNotHandled = false;
  153. var setHandledTo = false;
  154. view.KeyDown += (s, e) =>
  155. {
  156. e.Handled = setHandledTo;
  157. Assert.Equal (setHandledTo, e.Handled);
  158. Assert.Equal (KeyCode.N, e.KeyCode);
  159. };
  160. view.KeyDownNotHandled += (s, e) =>
  161. {
  162. keyDownNotHandled = true;
  163. Assert.False (e.Handled);
  164. Assert.Equal (KeyCode.N, e.KeyCode);
  165. };
  166. view.NewKeyDownEvent (Key.N);
  167. Assert.True (keyDownNotHandled);
  168. keyDownNotHandled = false;
  169. setHandledTo = true;
  170. view.NewKeyDownEvent (Key.N);
  171. Assert.False (keyDownNotHandled);
  172. }
  173. [Fact]
  174. public void NewKeyDownEvent_ProcessKeyDown_Handled_Stops_Processing ()
  175. {
  176. var keyDown = false;
  177. var keyDownNotHandled = false;
  178. var view = new OnNewKeyTestView ();
  179. Assert.True (view.CanFocus);
  180. view.CancelVirtualMethods = false;
  181. view.KeyDown += (s, e) =>
  182. {
  183. Assert.Equal (KeyCode.A, e.KeyCode);
  184. Assert.False (keyDown);
  185. Assert.True (view.OnKeyDownCalled);
  186. e.Handled = false;
  187. keyDown = true;
  188. };
  189. view.KeyDownNotHandled += (s, e) =>
  190. {
  191. Assert.Equal (KeyCode.A, e.KeyCode);
  192. Assert.False (keyDownNotHandled);
  193. Assert.True (view.OnProcessKeyDownCalled);
  194. e.Handled = true;
  195. keyDownNotHandled = true;
  196. };
  197. view.NewKeyDownEvent (Key.A);
  198. Assert.True (keyDown);
  199. Assert.True (keyDownNotHandled);
  200. Assert.True (view.OnKeyDownCalled);
  201. Assert.True (view.OnProcessKeyDownCalled);
  202. }
  203. [Fact]
  204. public void NewKeyUpEvent_KeyUp_Handled_True_Stops_Processing ()
  205. {
  206. var keyUp = false;
  207. var view = new OnNewKeyTestView ();
  208. Assert.True (view.CanFocus);
  209. view.CancelVirtualMethods = false;
  210. view.KeyUp += (s, e) =>
  211. {
  212. Assert.Equal (KeyCode.A, e.KeyCode);
  213. Assert.False (keyUp);
  214. Assert.False (view.OnProcessKeyDownCalled);
  215. e.Handled = true;
  216. keyUp = true;
  217. };
  218. view.NewKeyUpEvent (Key.A);
  219. Assert.True (keyUp);
  220. Assert.True (view.OnKeyUpCalled);
  221. Assert.False (view.OnKeyDownCalled);
  222. Assert.False (view.OnProcessKeyDownCalled);
  223. }
  224. [Theory]
  225. [InlineData (null, null)]
  226. [InlineData (true, true)]
  227. [InlineData (false, false)]
  228. public void InvokeCommandsBoundToKey_Returns_Nullable_Properly (bool? toReturn, bool? expected)
  229. {
  230. var view = new KeyBindingsTestView ();
  231. view.CommandReturns = toReturn;
  232. bool? result = view.InvokeCommandsBoundToKey (Key.A);
  233. Assert.Equal (expected, result);
  234. }
  235. /// <summary>A view that overrides the OnKey* methods so we can test that they are called.</summary>
  236. public class KeyBindingsTestView : View
  237. {
  238. public KeyBindingsTestView ()
  239. {
  240. CanFocus = true;
  241. AddCommand (Command.HotKey, () => CommandReturns);
  242. KeyBindings.Add (Key.A, Command.HotKey);
  243. }
  244. public bool? CommandReturns { get; set; }
  245. }
  246. /// <summary>A view that overrides the OnKey* methods so we can test that they are called.</summary>
  247. public class OnNewKeyTestView : View
  248. {
  249. public OnNewKeyTestView () { CanFocus = true; }
  250. public bool CancelVirtualMethods { set; private get; }
  251. public bool OnKeyDownCalled { get; set; }
  252. public bool OnProcessKeyDownCalled { get; set; }
  253. public bool OnKeyUpCalled { get; set; }
  254. public override string Text { get; set; }
  255. protected override bool OnKeyDown (Key keyEvent)
  256. {
  257. OnKeyDownCalled = true;
  258. return CancelVirtualMethods;
  259. }
  260. public override bool OnKeyUp (Key keyEvent)
  261. {
  262. OnKeyUpCalled = true;
  263. return CancelVirtualMethods;
  264. }
  265. protected override bool OnKeyDownNotHandled (Key keyEvent)
  266. {
  267. OnProcessKeyDownCalled = true;
  268. return CancelVirtualMethods;
  269. }
  270. }
  271. }