WindowsConsole.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379
  1. #nullable enable
  2. using System.Runtime.InteropServices;
  3. // ReSharper disable InconsistentNaming
  4. namespace Terminal.Gui.Drivers;
  5. #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
  6. /// <summary>
  7. /// Definitions for Windows Console API structures and constants.
  8. /// </summary>
  9. public class WindowsConsole
  10. {
  11. /// <summary>
  12. /// Standard input handle constant.
  13. /// </summary>
  14. public const int STD_INPUT_HANDLE = -10;
  15. /// <summary>
  16. /// Windows Console mode flags.
  17. /// </summary>
  18. [Flags]
  19. public enum ConsoleModes : uint
  20. {
  21. EnableProcessedInput = 1,
  22. EnableVirtualTerminalProcessing = 4,
  23. EnableMouseInput = 16,
  24. EnableQuickEditMode = 64,
  25. EnableExtendedFlags = 128
  26. }
  27. /// <summary>
  28. /// Key event record structure.
  29. /// </summary>
  30. [StructLayout (LayoutKind.Explicit, CharSet = CharSet.Unicode)]
  31. public struct KeyEventRecord
  32. {
  33. [FieldOffset (0)]
  34. [MarshalAs (UnmanagedType.Bool)]
  35. public bool bKeyDown;
  36. [FieldOffset (4)]
  37. [MarshalAs (UnmanagedType.U2)]
  38. public ushort wRepeatCount;
  39. [FieldOffset (6)]
  40. [MarshalAs (UnmanagedType.U2)]
  41. public ConsoleKeyMapping.VK wVirtualKeyCode;
  42. [FieldOffset (8)]
  43. [MarshalAs (UnmanagedType.U2)]
  44. public ushort wVirtualScanCode;
  45. [FieldOffset (10)]
  46. public char UnicodeChar;
  47. [FieldOffset (12)]
  48. [MarshalAs (UnmanagedType.U4)]
  49. public ControlKeyState dwControlKeyState;
  50. public readonly override string ToString ()
  51. {
  52. return
  53. $"[KeyEventRecord({(bKeyDown ? "down" : "up")},{wRepeatCount},{wVirtualKeyCode},{wVirtualScanCode},{new Rune (UnicodeChar).MakePrintable ()},{dwControlKeyState})]";
  54. }
  55. }
  56. [Flags]
  57. public enum ButtonState
  58. {
  59. NoButtonPressed = 0,
  60. Button1Pressed = 1,
  61. Button2Pressed = 4,
  62. Button3Pressed = 8,
  63. Button4Pressed = 16,
  64. RightmostButtonPressed = 2
  65. }
  66. [Flags]
  67. public enum ControlKeyState
  68. {
  69. NoControlKeyPressed = 0,
  70. RightAltPressed = 1,
  71. LeftAltPressed = 2,
  72. RightControlPressed = 4,
  73. LeftControlPressed = 8,
  74. ShiftPressed = 16,
  75. NumlockOn = 32,
  76. ScrolllockOn = 64,
  77. CapslockOn = 128,
  78. EnhancedKey = 256
  79. }
  80. [Flags]
  81. public enum EventFlags
  82. {
  83. NoEvent = 0,
  84. MouseMoved = 1,
  85. DoubleClick = 2,
  86. MouseWheeled = 4,
  87. MouseHorizontalWheeled = 8
  88. }
  89. [StructLayout (LayoutKind.Explicit)]
  90. public struct MouseEventRecord
  91. {
  92. [FieldOffset (0)]
  93. public Coord MousePosition;
  94. [FieldOffset (4)]
  95. public ButtonState ButtonState;
  96. [FieldOffset (8)]
  97. public ControlKeyState ControlKeyState;
  98. [FieldOffset (12)]
  99. public EventFlags EventFlags;
  100. public readonly override string ToString () { return $"[Mouse{MousePosition},{ButtonState},{ControlKeyState},{EventFlags}]"; }
  101. }
  102. public struct WindowBufferSizeRecord (short x, short y)
  103. {
  104. public Coord _size = new (x, y);
  105. public readonly override string ToString () { return $"[WindowBufferSize{_size}"; }
  106. }
  107. [StructLayout (LayoutKind.Sequential)]
  108. public struct MenuEventRecord
  109. {
  110. public uint dwCommandId;
  111. }
  112. [StructLayout (LayoutKind.Sequential)]
  113. public struct FocusEventRecord
  114. {
  115. public uint bSetFocus;
  116. }
  117. public enum EventType : ushort
  118. {
  119. Focus = 0x10,
  120. Key = 0x1,
  121. Menu = 0x8,
  122. Mouse = 2,
  123. WindowBufferSize = 4
  124. }
  125. [StructLayout (LayoutKind.Explicit)]
  126. public struct InputRecord
  127. {
  128. [FieldOffset (0)]
  129. public EventType EventType;
  130. [FieldOffset (4)]
  131. public KeyEventRecord KeyEvent;
  132. [FieldOffset (4)]
  133. public MouseEventRecord MouseEvent;
  134. [FieldOffset (4)]
  135. public WindowBufferSizeRecord WindowBufferSizeEvent;
  136. [FieldOffset (4)]
  137. public MenuEventRecord MenuEvent;
  138. [FieldOffset (4)]
  139. public FocusEventRecord FocusEvent;
  140. public readonly override string ToString ()
  141. {
  142. return (EventType switch
  143. {
  144. EventType.Focus => FocusEvent.ToString (),
  145. EventType.Key => KeyEvent.ToString (),
  146. EventType.Menu => MenuEvent.ToString (),
  147. EventType.Mouse => MouseEvent.ToString (),
  148. EventType.WindowBufferSize => WindowBufferSizeEvent.ToString (),
  149. _ => "Unknown event type: " + EventType
  150. })!;
  151. }
  152. }
  153. [StructLayout (LayoutKind.Sequential)]
  154. public struct Coord
  155. {
  156. public short X;
  157. public short Y;
  158. public Coord (short x, short y)
  159. {
  160. X = x;
  161. Y = y;
  162. }
  163. public readonly override string ToString () { return $"({X},{Y})"; }
  164. }
  165. [StructLayout (LayoutKind.Explicit, CharSet = CharSet.Unicode)]
  166. public struct CharUnion
  167. {
  168. [FieldOffset (0)]
  169. public char UnicodeChar;
  170. [FieldOffset (0)]
  171. public byte AsciiChar;
  172. }
  173. [StructLayout (LayoutKind.Explicit, CharSet = CharSet.Unicode)]
  174. public struct CharInfo
  175. {
  176. [FieldOffset (0)]
  177. public CharUnion Char;
  178. [FieldOffset (2)]
  179. public ushort Attributes;
  180. }
  181. [StructLayout (LayoutKind.Sequential)]
  182. public struct SmallRect
  183. {
  184. public short Left;
  185. public short Top;
  186. public short Right;
  187. public short Bottom;
  188. public SmallRect (short left, short top, short right, short bottom)
  189. {
  190. Left = left;
  191. Top = top;
  192. Right = right;
  193. Bottom = bottom;
  194. }
  195. public static void MakeEmpty (ref SmallRect rect) { rect.Left = -1; }
  196. public static void Update (ref SmallRect rect, short col, short row)
  197. {
  198. if (rect.Left == -1)
  199. {
  200. rect.Left = rect.Right = col;
  201. rect.Bottom = rect.Top = row;
  202. return;
  203. }
  204. if (col >= rect.Left && col <= rect.Right && row >= rect.Top && row <= rect.Bottom)
  205. {
  206. return;
  207. }
  208. if (col < rect.Left)
  209. {
  210. rect.Left = col;
  211. }
  212. if (col > rect.Right)
  213. {
  214. rect.Right = col;
  215. }
  216. if (row < rect.Top)
  217. {
  218. rect.Top = row;
  219. }
  220. if (row > rect.Bottom)
  221. {
  222. rect.Bottom = row;
  223. }
  224. }
  225. public readonly override string ToString () { return $"Left={Left},Top={Top},Right={Right},Bottom={Bottom}"; }
  226. }
  227. [StructLayout (LayoutKind.Sequential)]
  228. public struct ConsoleKeyInfoEx
  229. {
  230. public ConsoleKeyInfo ConsoleKeyInfo;
  231. public bool CapsLock;
  232. public bool NumLock;
  233. public bool ScrollLock;
  234. public ConsoleKeyInfoEx (ConsoleKeyInfo consoleKeyInfo, bool capslock, bool numlock, bool scrolllock)
  235. {
  236. ConsoleKeyInfo = consoleKeyInfo;
  237. CapsLock = capslock;
  238. NumLock = numlock;
  239. ScrollLock = scrolllock;
  240. }
  241. /// <summary>
  242. /// Prints a ConsoleKeyInfoEx structure
  243. /// </summary>
  244. /// <param name="ex"></param>
  245. /// <returns></returns>
  246. public readonly string ToString (ConsoleKeyInfoEx ex)
  247. {
  248. var ke = new Key ((KeyCode)ex.ConsoleKeyInfo.KeyChar);
  249. var sb = new StringBuilder ();
  250. sb.Append ($"Key: {(KeyCode)ex.ConsoleKeyInfo.Key} ({ex.ConsoleKeyInfo.Key})");
  251. sb.Append ((ex.ConsoleKeyInfo.Modifiers & ConsoleModifiers.Shift) != 0 ? " | Shift" : string.Empty);
  252. sb.Append ((ex.ConsoleKeyInfo.Modifiers & ConsoleModifiers.Control) != 0 ? " | Control" : string.Empty);
  253. sb.Append ((ex.ConsoleKeyInfo.Modifiers & ConsoleModifiers.Alt) != 0 ? " | Alt" : string.Empty);
  254. sb.Append ($", KeyChar: {ke.AsRune.MakePrintable ()} ({(uint)ex.ConsoleKeyInfo.KeyChar}) ");
  255. sb.Append (ex.CapsLock ? "caps," : string.Empty);
  256. sb.Append (ex.NumLock ? "num," : string.Empty);
  257. sb.Append (ex.ScrollLock ? "scroll," : string.Empty);
  258. string s = sb.ToString ().TrimEnd (',').TrimEnd (' ');
  259. return $"[ConsoleKeyInfoEx({s})]";
  260. }
  261. }
  262. [StructLayout (LayoutKind.Sequential)]
  263. public struct ConsoleCursorInfo
  264. {
  265. /// <summary>
  266. /// The percentage of the character cell that is filled by the cursor.This value is between 1 and 100.
  267. /// The cursor appearance varies, ranging from completely filling the cell to showing up as a horizontal
  268. /// line at the bottom of the cell.
  269. /// </summary>
  270. public uint dwSize;
  271. public bool bVisible;
  272. }
  273. // See: https://github.com/gui-cs/Terminal.Gui/issues/357
  274. [StructLayout (LayoutKind.Sequential)]
  275. public struct CONSOLE_SCREEN_BUFFER_INFOEX
  276. {
  277. public uint cbSize;
  278. public Coord dwSize;
  279. public Coord dwCursorPosition;
  280. public ushort wAttributes;
  281. public SmallRect srWindow;
  282. public Coord dwMaximumWindowSize;
  283. public ushort wPopupAttributes;
  284. public bool bFullscreenSupported;
  285. [MarshalAs (UnmanagedType.ByValArray, SizeConst = 16)]
  286. public COLORREF [] ColorTable;
  287. }
  288. [StructLayout (LayoutKind.Explicit, Size = 4)]
  289. public struct COLORREF
  290. {
  291. public COLORREF (byte r, byte g, byte b)
  292. {
  293. Value = 0;
  294. R = r;
  295. G = g;
  296. B = b;
  297. }
  298. public COLORREF (uint value)
  299. {
  300. R = 0;
  301. G = 0;
  302. B = 0;
  303. Value = value & 0x00FFFFFF;
  304. }
  305. [FieldOffset (0)]
  306. public byte R;
  307. [FieldOffset (1)]
  308. public byte G;
  309. [FieldOffset (2)]
  310. public byte B;
  311. [FieldOffset (0)]
  312. public uint Value;
  313. }
  314. }