KeyboardEventTests.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505
  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
  5. {
  6. private readonly ITestOutputHelper _output;
  7. public KeyboardEventTests (ITestOutputHelper output) { _output = output; }
  8. /// <summary>
  9. /// This tests that when a new key down event is sent to the view the view will fire the 3 key-down related
  10. /// events: KeyDown, InvokingKeyBindings, and ProcessKeyDown. Note that KeyUp is independent.
  11. /// </summary>
  12. [Fact]
  13. public void AllViews_KeyDown_All_EventsFire ()
  14. {
  15. foreach (View view in TestHelpers.GetAllViews ())
  16. {
  17. if (view == null)
  18. {
  19. _output.WriteLine ($"ERROR: null view from {nameof (TestHelpers.GetAllViews)}");
  20. continue;
  21. }
  22. _output.WriteLine ($"Testing {view.GetType ().Name}");
  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 invokingKeyBindings = false;
  30. view.InvokingKeyBindings += (s, a) =>
  31. {
  32. a.Handled = false; // don't handle it so the other events are called
  33. invokingKeyBindings = true;
  34. };
  35. var keyDownProcessed = false;
  36. view.ProcessKeyDown += (s, a) =>
  37. {
  38. a.Handled = true;
  39. keyDownProcessed = true;
  40. };
  41. Assert.True (view.NewKeyDownEvent (Key.A)); // this will be true because the ProcessKeyDown event handled it
  42. Assert.True (keyDown);
  43. Assert.True (invokingKeyBindings);
  44. Assert.True (keyDownProcessed);
  45. view.Dispose ();
  46. }
  47. }
  48. /// <summary>
  49. /// This tests that when a new key up event is sent to the view the view will fire the 1 key-up related event:
  50. /// KeyUp
  51. /// </summary>
  52. [Fact]
  53. public void AllViews_KeyUp_All_EventsFire ()
  54. {
  55. foreach (View view in TestHelpers.GetAllViews ())
  56. {
  57. if (view == null)
  58. {
  59. _output.WriteLine ($"ERROR: null view from {nameof (TestHelpers.GetAllViews)}");
  60. continue;
  61. }
  62. _output.WriteLine ($"Testing {view.GetType ().Name}");
  63. var keyUp = false;
  64. view.KeyUp += (s, a) =>
  65. {
  66. a.Handled = true;
  67. keyUp = true;
  68. };
  69. Assert.True (view.NewKeyUpEvent (Key.A)); // this will be true because the KeyUp event handled it
  70. Assert.True (keyUp);
  71. view.Dispose ();
  72. }
  73. }
  74. [Theory]
  75. [InlineData (true, false, false)]
  76. [InlineData (true, true, false)]
  77. [InlineData (true, true, true)]
  78. public void Events_Are_Called_With_Only_Key_Modifiers (bool shift, bool alt, bool control)
  79. {
  80. var keyDown = false;
  81. var keyPressed = false;
  82. var keyUp = false;
  83. var view = new OnKeyTestView ();
  84. view.CancelVirtualMethods = false;
  85. view.KeyDown += (s, e) =>
  86. {
  87. Assert.Equal (KeyCode.Null, e.KeyCode & ~KeyCode.CtrlMask & ~KeyCode.AltMask & ~KeyCode.ShiftMask);
  88. Assert.Equal (shift, e.IsShift);
  89. Assert.Equal (alt, e.IsAlt);
  90. Assert.Equal (control, e.IsCtrl);
  91. Assert.False (keyDown);
  92. Assert.False (view.OnKeyDownContinued);
  93. keyDown = true;
  94. };
  95. view.ProcessKeyDown += (s, e) => { keyPressed = true; };
  96. view.KeyUp += (s, e) =>
  97. {
  98. Assert.Equal (KeyCode.Null, e.KeyCode & ~KeyCode.CtrlMask & ~KeyCode.AltMask & ~KeyCode.ShiftMask);
  99. Assert.Equal (shift, e.IsShift);
  100. Assert.Equal (alt, e.IsAlt);
  101. Assert.Equal (control, e.IsCtrl);
  102. Assert.False (keyUp);
  103. Assert.False (view.OnKeyUpContinued);
  104. keyUp = true;
  105. };
  106. //view.ProcessKeyDownEvent (new (Key.Null | (shift ? Key.ShiftMask : 0) | (alt ? Key.AltMask : 0) | (control ? Key.CtrlMask : 0)));
  107. //Assert.True (keyDown);
  108. //Assert.True (view.OnKeyDownWasCalled);
  109. //Assert.True (view.OnProcessKeyDownWasCalled);
  110. view.NewKeyDownEvent (
  111. new Key (
  112. KeyCode.Null
  113. | (shift ? KeyCode.ShiftMask : 0)
  114. | (alt ? KeyCode.AltMask : 0)
  115. | (control ? KeyCode.CtrlMask : 0)
  116. )
  117. );
  118. Assert.True (keyPressed);
  119. Assert.True (view.OnKeyDownContinued);
  120. Assert.True (view.OnKeyPressedContinued);
  121. view.NewKeyUpEvent (
  122. new Key (
  123. KeyCode.Null
  124. | (shift ? KeyCode.ShiftMask : 0)
  125. | (alt ? KeyCode.AltMask : 0)
  126. | (control ? KeyCode.CtrlMask : 0)
  127. )
  128. );
  129. Assert.True (keyUp);
  130. Assert.True (view.OnKeyUpContinued);
  131. }
  132. [Fact]
  133. public void InvokingKeyBindings_Handled_Cancels ()
  134. {
  135. var view = new View ();
  136. var keyPressInvoked = false;
  137. var invokingKeyBindingsInvoked = false;
  138. var processKeyPressInvoked = false;
  139. var setHandledTo = false;
  140. view.KeyDown += (s, e) =>
  141. {
  142. keyPressInvoked = true;
  143. Assert.False (e.Handled);
  144. Assert.Equal (KeyCode.N, e.KeyCode);
  145. };
  146. view.InvokingKeyBindings += (s, e) =>
  147. {
  148. invokingKeyBindingsInvoked = true;
  149. e.Handled = setHandledTo;
  150. Assert.Equal (setHandledTo, e.Handled);
  151. Assert.Equal (KeyCode.N, e.KeyCode);
  152. };
  153. view.ProcessKeyDown += (s, e) =>
  154. {
  155. processKeyPressInvoked = true;
  156. processKeyPressInvoked = true;
  157. Assert.False (e.Handled);
  158. Assert.Equal (KeyCode.N, e.KeyCode);
  159. };
  160. view.NewKeyDownEvent (Key.N);
  161. Assert.True (keyPressInvoked);
  162. Assert.True (invokingKeyBindingsInvoked);
  163. Assert.True (processKeyPressInvoked);
  164. keyPressInvoked = false;
  165. invokingKeyBindingsInvoked = false;
  166. processKeyPressInvoked = false;
  167. setHandledTo = true;
  168. view.NewKeyDownEvent (Key.N);
  169. Assert.True (keyPressInvoked);
  170. Assert.True (invokingKeyBindingsInvoked);
  171. Assert.False (processKeyPressInvoked);
  172. }
  173. [Fact]
  174. public void InvokingKeyBindings_Handled_True_Stops_Processing ()
  175. {
  176. var keyDown = false;
  177. var invokingKeyBindings = false;
  178. var keyPressed = false;
  179. var view = new OnKeyTestView ();
  180. Assert.True (view.CanFocus);
  181. view.CancelVirtualMethods = false;
  182. view.KeyDown += (s, e) =>
  183. {
  184. Assert.Equal (KeyCode.A, e.KeyCode);
  185. Assert.False (keyDown);
  186. Assert.False (view.OnKeyDownContinued);
  187. e.Handled = false;
  188. keyDown = true;
  189. };
  190. view.InvokingKeyBindings += (s, e) =>
  191. {
  192. Assert.Equal (KeyCode.A, e.KeyCode);
  193. Assert.False (keyPressed);
  194. Assert.False (view.OnInvokingKeyBindingsContinued);
  195. e.Handled = true;
  196. invokingKeyBindings = true;
  197. };
  198. view.ProcessKeyDown += (s, e) =>
  199. {
  200. Assert.Equal (KeyCode.A, e.KeyCode);
  201. Assert.False (keyPressed);
  202. Assert.False (view.OnKeyPressedContinued);
  203. e.Handled = true;
  204. keyPressed = true;
  205. };
  206. view.NewKeyDownEvent (Key.A);
  207. Assert.True (keyDown);
  208. Assert.True (invokingKeyBindings);
  209. Assert.False (keyPressed);
  210. Assert.True (view.OnKeyDownContinued);
  211. Assert.False (view.OnInvokingKeyBindingsContinued);
  212. Assert.False (view.OnKeyPressedContinued);
  213. }
  214. [Fact]
  215. public void KeyDown_Handled_True_Stops_Processing ()
  216. {
  217. var keyDown = false;
  218. var invokingKeyBindings = false;
  219. var keyPressed = false;
  220. var view = new OnKeyTestView ();
  221. Assert.True (view.CanFocus);
  222. view.CancelVirtualMethods = false;
  223. view.KeyDown += (s, e) =>
  224. {
  225. Assert.Equal (KeyCode.A, e.KeyCode);
  226. Assert.False (keyDown);
  227. Assert.False (view.OnKeyDownContinued);
  228. e.Handled = true;
  229. keyDown = true;
  230. };
  231. view.InvokingKeyBindings += (s, e) =>
  232. {
  233. Assert.Equal (KeyCode.A, e.KeyCode);
  234. Assert.False (keyPressed);
  235. Assert.False (view.OnInvokingKeyBindingsContinued);
  236. e.Handled = true;
  237. invokingKeyBindings = true;
  238. };
  239. view.ProcessKeyDown += (s, e) =>
  240. {
  241. Assert.Equal (KeyCode.A, e.KeyCode);
  242. Assert.False (keyPressed);
  243. Assert.False (view.OnKeyPressedContinued);
  244. e.Handled = true;
  245. keyPressed = true;
  246. };
  247. view.NewKeyDownEvent (Key.A);
  248. Assert.True (keyDown);
  249. Assert.False (invokingKeyBindings);
  250. Assert.False (keyPressed);
  251. Assert.False (view.OnKeyDownContinued);
  252. Assert.False (view.OnInvokingKeyBindingsContinued);
  253. Assert.False (view.OnKeyPressedContinued);
  254. }
  255. [Fact]
  256. public void KeyPress_Handled_Cancels ()
  257. {
  258. var view = new View ();
  259. var invokingKeyBindingsInvoked = false;
  260. var processKeyPressInvoked = false;
  261. var setHandledTo = false;
  262. view.KeyDown += (s, e) =>
  263. {
  264. e.Handled = setHandledTo;
  265. Assert.Equal (setHandledTo, e.Handled);
  266. Assert.Equal (KeyCode.N, e.KeyCode);
  267. };
  268. view.InvokingKeyBindings += (s, e) =>
  269. {
  270. invokingKeyBindingsInvoked = true;
  271. Assert.False (e.Handled);
  272. Assert.Equal (KeyCode.N, e.KeyCode);
  273. };
  274. view.ProcessKeyDown += (s, e) =>
  275. {
  276. processKeyPressInvoked = true;
  277. Assert.False (e.Handled);
  278. Assert.Equal (KeyCode.N, e.KeyCode);
  279. };
  280. view.NewKeyDownEvent (Key.N);
  281. Assert.True (invokingKeyBindingsInvoked);
  282. Assert.True (processKeyPressInvoked);
  283. invokingKeyBindingsInvoked = false;
  284. processKeyPressInvoked = false;
  285. setHandledTo = true;
  286. view.NewKeyDownEvent (Key.N);
  287. Assert.False (invokingKeyBindingsInvoked);
  288. Assert.False (processKeyPressInvoked);
  289. }
  290. [Fact]
  291. public void KeyPressed_Handled_True_Stops_Processing ()
  292. {
  293. var keyDown = false;
  294. var invokingKeyBindings = false;
  295. var keyPressed = false;
  296. var view = new OnKeyTestView ();
  297. Assert.True (view.CanFocus);
  298. view.CancelVirtualMethods = false;
  299. view.KeyDown += (s, e) =>
  300. {
  301. Assert.Equal (KeyCode.A, e.KeyCode);
  302. Assert.False (keyDown);
  303. Assert.False (view.OnKeyDownContinued);
  304. e.Handled = false;
  305. keyDown = true;
  306. };
  307. view.InvokingKeyBindings += (s, e) =>
  308. {
  309. Assert.Equal (KeyCode.A, e.KeyCode);
  310. Assert.False (keyPressed);
  311. Assert.False (view.OnInvokingKeyBindingsContinued);
  312. e.Handled = false;
  313. invokingKeyBindings = true;
  314. };
  315. view.ProcessKeyDown += (s, e) =>
  316. {
  317. Assert.Equal (KeyCode.A, e.KeyCode);
  318. Assert.False (keyPressed);
  319. Assert.False (view.OnKeyPressedContinued);
  320. e.Handled = true;
  321. keyPressed = true;
  322. };
  323. view.NewKeyDownEvent (Key.A);
  324. Assert.True (keyDown);
  325. Assert.True (invokingKeyBindings);
  326. Assert.True (keyPressed);
  327. Assert.True (view.OnKeyDownContinued);
  328. Assert.True (view.OnInvokingKeyBindingsContinued);
  329. Assert.False (view.OnKeyPressedContinued);
  330. }
  331. [Fact]
  332. public void KeyUp_Handled_True_Stops_Processing ()
  333. {
  334. var keyUp = false;
  335. var view = new OnKeyTestView ();
  336. Assert.True (view.CanFocus);
  337. view.CancelVirtualMethods = false;
  338. view.KeyUp += (s, e) =>
  339. {
  340. Assert.Equal (KeyCode.A, e.KeyCode);
  341. Assert.False (keyUp);
  342. Assert.False (view.OnKeyPressedContinued);
  343. e.Handled = true;
  344. keyUp = true;
  345. };
  346. view.NewKeyUpEvent (Key.A);
  347. Assert.True (keyUp);
  348. Assert.False (view.OnKeyUpContinued);
  349. Assert.False (view.OnKeyDownContinued);
  350. Assert.False (view.OnInvokingKeyBindingsContinued);
  351. Assert.False (view.OnKeyPressedContinued);
  352. }
  353. [Theory]
  354. [InlineData (null, null)]
  355. [InlineData (true, true)]
  356. [InlineData (false, false)]
  357. public void OnInvokingKeyBindings_Returns_Nullable_Properly (bool? toReturn, bool? expected)
  358. {
  359. var view = new KeyBindingsTestView ();
  360. view.CommandReturns = toReturn;
  361. bool? result = view.OnInvokingKeyBindings (Key.A);
  362. Assert.Equal (expected, result);
  363. }
  364. /// <summary>A view that overrides the OnKey* methods so we can test that they are called.</summary>
  365. public class KeyBindingsTestView : View
  366. {
  367. public KeyBindingsTestView ()
  368. {
  369. CanFocus = true;
  370. AddCommand (Command.HotKey, () => CommandReturns);
  371. KeyBindings.Add (Key.A, Command.HotKey);
  372. }
  373. public bool? CommandReturns { get; set; }
  374. }
  375. /// <summary>A view that overrides the OnKey* methods so we can test that they are called.</summary>
  376. public class OnKeyTestView : View
  377. {
  378. public OnKeyTestView () { CanFocus = true; }
  379. public bool CancelVirtualMethods { set; private get; }
  380. public bool OnInvokingKeyBindingsContinued { get; set; }
  381. public bool OnKeyDownContinued { get; set; }
  382. public bool OnKeyPressedContinued { get; set; }
  383. public bool OnKeyUpContinued { get; set; }
  384. public override string Text { get; set; }
  385. public override bool? OnInvokingKeyBindings (Key keyEvent)
  386. {
  387. bool? handled = base.OnInvokingKeyBindings (keyEvent);
  388. if (handled != null && (bool)handled)
  389. {
  390. return true;
  391. }
  392. OnInvokingKeyBindingsContinued = true;
  393. return CancelVirtualMethods;
  394. }
  395. public override bool OnKeyDown (Key keyEvent)
  396. {
  397. if (base.OnKeyDown (keyEvent))
  398. {
  399. return true;
  400. }
  401. OnKeyDownContinued = true;
  402. return CancelVirtualMethods;
  403. }
  404. public override bool OnKeyUp (Key keyEvent)
  405. {
  406. if (base.OnKeyUp (keyEvent))
  407. {
  408. return true;
  409. }
  410. OnKeyUpContinued = true;
  411. return CancelVirtualMethods;
  412. }
  413. public override bool OnProcessKeyDown (Key keyEvent)
  414. {
  415. if (base.OnProcessKeyDown (keyEvent))
  416. {
  417. return true;
  418. }
  419. OnKeyPressedContinued = true;
  420. return CancelVirtualMethods;
  421. }
  422. }
  423. }