GuiTestContext.Input.cs 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. using System.Drawing;
  2. #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
  3. namespace TerminalGuiFluentTesting;
  4. public partial class GuiTestContext
  5. {
  6. /// <summary>
  7. /// Simulates a right click at the given screen coordinates on the current driver.
  8. /// This is a raw input event that goes through entire processing pipeline as though
  9. /// user had pressed the mouse button physically.
  10. /// </summary>
  11. /// <param name="screenX">0 indexed screen coordinates</param>
  12. /// <param name="screenY">0 indexed screen coordinates</param>
  13. /// <returns></returns>
  14. public GuiTestContext RightClick (int screenX, int screenY)
  15. {
  16. return EnqueueMouseEvent (new ()
  17. {
  18. Flags = MouseFlags.Button3Clicked,
  19. ScreenPosition = new (screenX, screenY)
  20. });
  21. }
  22. /// <summary>
  23. /// Simulates a left click at the given screen coordinates on the current driver.
  24. /// This is a raw input event that goes through entire processing pipeline as though
  25. /// user had pressed the mouse button physically.
  26. /// </summary>
  27. /// <param name="screenX">0 indexed screen coordinates</param>
  28. /// <param name="screenY">0 indexed screen coordinates</param>
  29. /// <returns></returns>
  30. public GuiTestContext LeftClick (int screenX, int screenY)
  31. {
  32. return EnqueueMouseEvent (new ()
  33. {
  34. Flags = MouseFlags.Button1Clicked,
  35. ScreenPosition = new (screenX, screenY),
  36. });
  37. }
  38. /// <summary>
  39. /// Simulates a left mouse click on the top-left cell of the Viewport of the View of type TView determined by the
  40. /// <paramref name="evaluator"/>.
  41. /// </summary>
  42. /// <typeparam name="TView"></typeparam>
  43. /// <param name="evaluator"></param>
  44. /// <returns></returns>
  45. public GuiTestContext LeftClick<TView> (Func<TView, bool> evaluator) where TView : View
  46. {
  47. return EnqueueMouseEvent (new ()
  48. {
  49. Flags = MouseFlags.Button1Clicked,
  50. }, evaluator);
  51. }
  52. private GuiTestContext EnqueueMouseEvent (MouseEventArgs mouseEvent)
  53. {
  54. // Enqueue the mouse event
  55. WaitIteration ((app) =>
  56. {
  57. if (app.Driver is { })
  58. {
  59. mouseEvent.Position = mouseEvent.ScreenPosition;
  60. app.Driver.InputProcessor.EnqueueMouseEvent (app, mouseEvent);
  61. }
  62. else
  63. {
  64. Fail ("Expected Application.Driver to be non-null.");
  65. }
  66. });
  67. // Wait for the event to be processed (similar to EnqueueKeyEvent)
  68. return WaitIteration ();
  69. }
  70. private GuiTestContext EnqueueMouseEvent<TView> (MouseEventArgs mouseEvent, Func<TView, bool> evaluator) where TView : View
  71. {
  72. var screen = Point.Empty;
  73. GuiTestContext ctx = WaitIteration ((_) =>
  74. {
  75. TView v = Find (evaluator);
  76. screen = v.ViewportToScreen (new Point (0, 0));
  77. });
  78. mouseEvent.ScreenPosition = screen;
  79. mouseEvent.Position = new Point (0, 0);
  80. EnqueueMouseEvent (mouseEvent);
  81. return ctx;
  82. }
  83. //private GuiTestContext Click (WindowsConsole.ButtonState btn, int screenX, int screenY)
  84. //{
  85. // switch (_driverType)
  86. // {
  87. // case TestDriver.Windows:
  88. // _winInput!.InputQueue!.Enqueue (
  89. // new ()
  90. // {
  91. // EventType = WindowsConsole.EventType.Mouse,
  92. // MouseEvent = new ()
  93. // {
  94. // ButtonState = btn,
  95. // MousePosition = new ((short)screenX, (short)screenY)
  96. // }
  97. // });
  98. // _winInput.InputQueue.Enqueue (
  99. // new ()
  100. // {
  101. // EventType = WindowsConsole.EventType.Mouse,
  102. // MouseEvent = new ()
  103. // {
  104. // ButtonState = WindowsConsole.ButtonState.NoButtonPressed,
  105. // MousePosition = new ((short)screenX, (short)screenY)
  106. // }
  107. // });
  108. // return WaitUntil (() => _winInput.InputQueue.IsEmpty);
  109. // case TestDriver.DotNet:
  110. // int netButton = btn switch
  111. // {
  112. // WindowsConsole.ButtonState.Button1Pressed => 0,
  113. // WindowsConsole.ButtonState.Button2Pressed => 1,
  114. // WindowsConsole.ButtonState.Button3Pressed => 2,
  115. // WindowsConsole.ButtonState.RightmostButtonPressed => 2,
  116. // _ => throw new ArgumentOutOfRangeException (nameof (btn))
  117. // };
  118. // foreach (ConsoleKeyInfo k in NetSequences.Click (netButton, screenX, screenY))
  119. // {
  120. // SendNetKey (k, false);
  121. // }
  122. // return WaitIteration ();
  123. // case TestDriver.Unix:
  124. // int unixButton = btn switch
  125. // {
  126. // WindowsConsole.ButtonState.Button1Pressed => 0,
  127. // WindowsConsole.ButtonState.Button2Pressed => 1,
  128. // WindowsConsole.ButtonState.Button3Pressed => 2,
  129. // WindowsConsole.ButtonState.RightmostButtonPressed => 2,
  130. // _ => throw new ArgumentOutOfRangeException (nameof (btn))
  131. // };
  132. // foreach (ConsoleKeyInfo k in NetSequences.Click (unixButton, screenX, screenY))
  133. // {
  134. // SendUnixKey (k.KeyChar, false);
  135. // }
  136. // return WaitIteration ();
  137. // case TestDriver.Fake:
  138. // int fakeButton = btn switch
  139. // {
  140. // WindowsConsole.ButtonState.Button1Pressed => 0,
  141. // WindowsConsole.ButtonState.Button2Pressed => 1,
  142. // WindowsConsole.ButtonState.Button3Pressed => 2,
  143. // WindowsConsole.ButtonState.RightmostButtonPressed => 2,
  144. // _ => throw new ArgumentOutOfRangeException (nameof (btn))
  145. // };
  146. // foreach (ConsoleKeyInfo k in NetSequences.Click (fakeButton, screenX, screenY))
  147. // {
  148. // SendFakeKey (k, false);
  149. // }
  150. // return WaitIteration ();
  151. // default:
  152. // throw new ArgumentOutOfRangeException ();
  153. // }
  154. //}
  155. /// <summary>
  156. /// Enqueues a key down event to the current driver's input processor.
  157. /// </summary>
  158. /// <param name="key"></param>
  159. /// <returns></returns>
  160. /// <summary>
  161. /// Enqueues a key down event to the current driver's input processor.
  162. /// </summary>
  163. public GuiTestContext EnqueueKeyEvent (Key key)
  164. {
  165. //Logging.Trace ($"Enqueuing key: {key}");
  166. // Enqueue the key event and wait for it to be processed.
  167. // We do this by subscribing to the Driver.KeyDown event and waiting until it is raised.
  168. // This prevents the application from missing the key event if we enqueue it and immediately return.
  169. bool keyReceived = false;
  170. if (App?.Driver is { })
  171. {
  172. App.Driver.KeyDown += DriverOnKeyDown;
  173. App.Driver.EnqueueKeyEvent (key);
  174. WaitUntil (() => keyReceived);
  175. }
  176. return this;
  177. void DriverOnKeyDown (object? sender, Key e)
  178. {
  179. App.Driver.KeyDown -= DriverOnKeyDown;
  180. keyReceived = true;
  181. }
  182. }
  183. }