2
0

WindowsInputProcessorTests.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. using System.Collections.Concurrent;
  2. using Terminal.Gui.ConsoleDrivers;
  3. using InputRecord = Terminal.Gui.WindowsConsole.InputRecord;
  4. using ButtonState = Terminal.Gui.WindowsConsole.ButtonState;
  5. using MouseEventRecord = Terminal.Gui.WindowsConsole.MouseEventRecord;
  6. namespace UnitTests.ConsoleDrivers.V2;
  7. public class WindowsInputProcessorTests
  8. {
  9. [Fact]
  10. public void Test_ProcessQueue_CapitalHLowerE ()
  11. {
  12. ConcurrentQueue<InputRecord> queue = new ();
  13. queue.Enqueue (
  14. new()
  15. {
  16. EventType = WindowsConsole.EventType.Key,
  17. KeyEvent = new()
  18. {
  19. bKeyDown = true,
  20. UnicodeChar = 'H',
  21. dwControlKeyState = WindowsConsole.ControlKeyState.CapslockOn,
  22. wVirtualKeyCode = (ConsoleKeyMapping.VK)72,
  23. wVirtualScanCode = 35
  24. }
  25. });
  26. queue.Enqueue (
  27. new()
  28. {
  29. EventType = WindowsConsole.EventType.Key,
  30. KeyEvent = new()
  31. {
  32. bKeyDown = false,
  33. UnicodeChar = 'H',
  34. dwControlKeyState = WindowsConsole.ControlKeyState.CapslockOn,
  35. wVirtualKeyCode = (ConsoleKeyMapping.VK)72,
  36. wVirtualScanCode = 35
  37. }
  38. });
  39. queue.Enqueue (
  40. new()
  41. {
  42. EventType = WindowsConsole.EventType.Key,
  43. KeyEvent = new()
  44. {
  45. bKeyDown = true,
  46. UnicodeChar = 'i',
  47. dwControlKeyState = WindowsConsole.ControlKeyState.NoControlKeyPressed,
  48. wVirtualKeyCode = (ConsoleKeyMapping.VK)73,
  49. wVirtualScanCode = 23
  50. }
  51. });
  52. queue.Enqueue (
  53. new()
  54. {
  55. EventType = WindowsConsole.EventType.Key,
  56. KeyEvent = new()
  57. {
  58. bKeyDown = false,
  59. UnicodeChar = 'i',
  60. dwControlKeyState = WindowsConsole.ControlKeyState.NoControlKeyPressed,
  61. wVirtualKeyCode = (ConsoleKeyMapping.VK)73,
  62. wVirtualScanCode = 23
  63. }
  64. });
  65. var processor = new WindowsInputProcessor (queue);
  66. List<Key> ups = new ();
  67. List<Key> downs = new ();
  68. processor.KeyUp += (s, e) => { ups.Add (e); };
  69. processor.KeyDown += (s, e) => { downs.Add (e); };
  70. Assert.Empty (ups);
  71. Assert.Empty (downs);
  72. processor.ProcessQueue ();
  73. Assert.Equal (Key.H.WithShift, ups [0]);
  74. Assert.Equal (Key.H.WithShift, downs [0]);
  75. Assert.Equal (Key.I, ups [1]);
  76. Assert.Equal (Key.I, downs [1]);
  77. }
  78. [Fact]
  79. public void Test_ProcessQueue_Mouse_Move ()
  80. {
  81. ConcurrentQueue<InputRecord> queue = new ();
  82. queue.Enqueue (
  83. new()
  84. {
  85. EventType = WindowsConsole.EventType.Mouse,
  86. MouseEvent = new()
  87. {
  88. MousePosition = new (32, 31),
  89. ButtonState = ButtonState.NoButtonPressed,
  90. ControlKeyState = WindowsConsole.ControlKeyState.NoControlKeyPressed,
  91. EventFlags = WindowsConsole.EventFlags.MouseMoved
  92. }
  93. });
  94. var processor = new WindowsInputProcessor (queue);
  95. List<MouseEventArgs> mouseEvents = new ();
  96. processor.MouseEvent += (s, e) => { mouseEvents.Add (e); };
  97. Assert.Empty (mouseEvents);
  98. processor.ProcessQueue ();
  99. MouseEventArgs s = Assert.Single (mouseEvents);
  100. Assert.Equal (MouseFlags.ReportMousePosition, s.Flags);
  101. Assert.Equal (s.ScreenPosition, new (32, 31));
  102. }
  103. [Theory]
  104. [InlineData (ButtonState.Button1Pressed, MouseFlags.Button1Pressed)]
  105. [InlineData (ButtonState.Button2Pressed, MouseFlags.Button2Pressed)]
  106. [InlineData (ButtonState.Button3Pressed, MouseFlags.Button3Pressed)]
  107. [InlineData (ButtonState.Button4Pressed, MouseFlags.Button4Pressed)]
  108. internal void Test_ProcessQueue_Mouse_Pressed (ButtonState state, MouseFlags expectedFlag)
  109. {
  110. ConcurrentQueue<InputRecord> queue = new ();
  111. queue.Enqueue (
  112. new()
  113. {
  114. EventType = WindowsConsole.EventType.Mouse,
  115. MouseEvent = new()
  116. {
  117. MousePosition = new (32, 31),
  118. ButtonState = state,
  119. ControlKeyState = WindowsConsole.ControlKeyState.NoControlKeyPressed,
  120. EventFlags = WindowsConsole.EventFlags.MouseMoved
  121. }
  122. });
  123. var processor = new WindowsInputProcessor (queue);
  124. List<MouseEventArgs> mouseEvents = new ();
  125. processor.MouseEvent += (s, e) => { mouseEvents.Add (e); };
  126. Assert.Empty (mouseEvents);
  127. processor.ProcessQueue ();
  128. MouseEventArgs s = Assert.Single (mouseEvents);
  129. Assert.Equal (s.Flags, MouseFlags.ReportMousePosition | expectedFlag);
  130. Assert.Equal (s.ScreenPosition, new (32, 31));
  131. }
  132. [Theory]
  133. [InlineData (100, MouseFlags.WheeledUp)]
  134. [InlineData (-100, MouseFlags.WheeledDown)]
  135. internal void Test_ProcessQueue_Mouse_Wheel (int wheelValue, MouseFlags expectedFlag)
  136. {
  137. ConcurrentQueue<InputRecord> queue = new ();
  138. queue.Enqueue (
  139. new()
  140. {
  141. EventType = WindowsConsole.EventType.Mouse,
  142. MouseEvent = new()
  143. {
  144. MousePosition = new (32, 31),
  145. ButtonState = (ButtonState)wheelValue,
  146. ControlKeyState = WindowsConsole.ControlKeyState.NoControlKeyPressed,
  147. EventFlags = WindowsConsole.EventFlags.MouseWheeled
  148. }
  149. });
  150. var processor = new WindowsInputProcessor (queue);
  151. List<MouseEventArgs> mouseEvents = new ();
  152. processor.MouseEvent += (s, e) => { mouseEvents.Add (e); };
  153. Assert.Empty (mouseEvents);
  154. processor.ProcessQueue ();
  155. MouseEventArgs s = Assert.Single (mouseEvents);
  156. Assert.Equal (s.Flags, expectedFlag);
  157. Assert.Equal (s.ScreenPosition, new (32, 31));
  158. }
  159. public static IEnumerable<object []> MouseFlagTestData ()
  160. {
  161. yield return new object []
  162. {
  163. new []
  164. {
  165. Tuple.Create (ButtonState.Button1Pressed, MouseFlags.Button1Pressed | MouseFlags.ReportMousePosition),
  166. Tuple.Create (ButtonState.NoButtonPressed, MouseFlags.Button1Released | MouseFlags.ReportMousePosition),
  167. Tuple.Create (ButtonState.NoButtonPressed, MouseFlags.ReportMousePosition | MouseFlags.ReportMousePosition)
  168. }
  169. };
  170. yield return new object []
  171. {
  172. new []
  173. {
  174. Tuple.Create (ButtonState.Button2Pressed, MouseFlags.Button2Pressed | MouseFlags.ReportMousePosition),
  175. Tuple.Create (ButtonState.NoButtonPressed, MouseFlags.Button2Released | MouseFlags.ReportMousePosition),
  176. Tuple.Create (ButtonState.NoButtonPressed, MouseFlags.ReportMousePosition | MouseFlags.ReportMousePosition)
  177. }
  178. };
  179. yield return new object []
  180. {
  181. new []
  182. {
  183. Tuple.Create (ButtonState.Button3Pressed, MouseFlags.Button3Pressed | MouseFlags.ReportMousePosition),
  184. Tuple.Create (ButtonState.NoButtonPressed, MouseFlags.Button3Released | MouseFlags.ReportMousePosition),
  185. Tuple.Create (ButtonState.NoButtonPressed, MouseFlags.ReportMousePosition | MouseFlags.ReportMousePosition)
  186. }
  187. };
  188. yield return new object []
  189. {
  190. new []
  191. {
  192. Tuple.Create (ButtonState.Button4Pressed, MouseFlags.Button4Pressed | MouseFlags.ReportMousePosition),
  193. Tuple.Create (ButtonState.NoButtonPressed, MouseFlags.Button4Released | MouseFlags.ReportMousePosition),
  194. Tuple.Create (ButtonState.NoButtonPressed, MouseFlags.ReportMousePosition | MouseFlags.ReportMousePosition)
  195. }
  196. };
  197. yield return new object []
  198. {
  199. new []
  200. {
  201. Tuple.Create (ButtonState.RightmostButtonPressed, MouseFlags.Button3Pressed | MouseFlags.ReportMousePosition),
  202. Tuple.Create (ButtonState.NoButtonPressed, MouseFlags.Button3Released | MouseFlags.ReportMousePosition),
  203. Tuple.Create (ButtonState.NoButtonPressed, MouseFlags.ReportMousePosition | MouseFlags.ReportMousePosition)
  204. }
  205. };
  206. // Tests for holding down 2 buttons at once and releasing them one after the other
  207. yield return new object []
  208. {
  209. new []
  210. {
  211. Tuple.Create (
  212. ButtonState.Button1Pressed | ButtonState.Button2Pressed,
  213. MouseFlags.Button1Pressed | MouseFlags.Button2Pressed | MouseFlags.ReportMousePosition),
  214. Tuple.Create (ButtonState.Button1Pressed, MouseFlags.Button1Pressed | MouseFlags.Button2Released | MouseFlags.ReportMousePosition),
  215. Tuple.Create (ButtonState.NoButtonPressed, MouseFlags.Button1Released | MouseFlags.ReportMousePosition),
  216. Tuple.Create (ButtonState.NoButtonPressed, MouseFlags.ReportMousePosition)
  217. }
  218. };
  219. yield return new object []
  220. {
  221. new []
  222. {
  223. Tuple.Create (
  224. ButtonState.Button3Pressed | ButtonState.Button4Pressed,
  225. MouseFlags.Button3Pressed | MouseFlags.Button4Pressed | MouseFlags.ReportMousePosition),
  226. Tuple.Create (ButtonState.Button3Pressed, MouseFlags.Button3Pressed | MouseFlags.Button4Released | MouseFlags.ReportMousePosition),
  227. Tuple.Create (ButtonState.NoButtonPressed, MouseFlags.Button3Released | MouseFlags.ReportMousePosition),
  228. Tuple.Create (ButtonState.NoButtonPressed, MouseFlags.ReportMousePosition)
  229. }
  230. };
  231. // Test for holding down 2 buttons at once and releasing them simultaneously
  232. yield return new object []
  233. {
  234. new []
  235. {
  236. Tuple.Create (
  237. ButtonState.Button1Pressed | ButtonState.Button2Pressed,
  238. MouseFlags.Button1Pressed | MouseFlags.Button2Pressed | MouseFlags.ReportMousePosition),
  239. Tuple.Create (ButtonState.NoButtonPressed, MouseFlags.Button1Released | MouseFlags.Button2Released | MouseFlags.ReportMousePosition),
  240. Tuple.Create (ButtonState.NoButtonPressed, MouseFlags.ReportMousePosition)
  241. }
  242. };
  243. // Test that rightmost and button 3 are the same button so 2 states is still only 1 flag
  244. yield return new object []
  245. {
  246. new []
  247. {
  248. Tuple.Create (ButtonState.Button3Pressed | ButtonState.RightmostButtonPressed, MouseFlags.Button3Pressed | MouseFlags.ReportMousePosition),
  249. // Can swap between without raising the released
  250. Tuple.Create (ButtonState.Button3Pressed, MouseFlags.Button3Pressed | MouseFlags.ReportMousePosition),
  251. Tuple.Create (ButtonState.RightmostButtonPressed, MouseFlags.Button3Pressed | MouseFlags.ReportMousePosition),
  252. // Now with neither we get released
  253. Tuple.Create (ButtonState.NoButtonPressed, MouseFlags.Button3Released | MouseFlags.ReportMousePosition),
  254. Tuple.Create (ButtonState.NoButtonPressed, MouseFlags.ReportMousePosition)
  255. }
  256. };
  257. }
  258. [Theory]
  259. [MemberData (nameof (MouseFlagTestData))]
  260. internal void MouseFlags_Should_Map_Correctly (Tuple<ButtonState, MouseFlags> [] inputOutputPairs)
  261. {
  262. var processor = new WindowsInputProcessor (new ());
  263. foreach (Tuple<ButtonState, MouseFlags> pair in inputOutputPairs)
  264. {
  265. var mockEvent = new MouseEventRecord { ButtonState = pair.Item1 };
  266. MouseEventArgs result = processor.ToDriverMouse (mockEvent);
  267. Assert.Equal (pair.Item2, result.Flags);
  268. }
  269. }
  270. }