KeyboardEventTests.cs 11 KB

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