WindowsDriver.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764
  1. using System;
  2. using System.Runtime.InteropServices;
  3. using System.Threading.Tasks;
  4. using Mono.Terminal;
  5. using NStack;
  6. namespace Terminal.Gui {
  7. internal class WindowsConsole {
  8. public const int STD_OUTPUT_HANDLE = -11;
  9. public const int STD_INPUT_HANDLE = -10;
  10. public const int STD_ERROR_HANDLE = -12;
  11. public IntPtr InputHandle, OutputHandle;
  12. public IntPtr ScreenBuffer;
  13. public WindowsConsole ()
  14. {
  15. InputHandle = GetStdHandle (STD_INPUT_HANDLE);
  16. OutputHandle = GetStdHandle (STD_OUTPUT_HANDLE);
  17. }
  18. public CharInfo[] OriginalStdOutChars;
  19. public bool WriteToConsole (CharInfo[] charInfoBuffer, Coord coords, SmallRect window)
  20. {
  21. if (ScreenBuffer == IntPtr.Zero)
  22. {
  23. ScreenBuffer = CreateConsoleScreenBuffer (
  24. DesiredAccess.GenericRead | DesiredAccess.GenericWrite,
  25. ShareMode.FileShareRead | ShareMode.FileShareWrite,
  26. IntPtr.Zero,
  27. 1,
  28. IntPtr.Zero
  29. );
  30. var err = Marshal.GetLastWin32Error ();
  31. if (err != 0)
  32. {
  33. throw new System.ComponentModel.Win32Exception(err);
  34. }
  35. if (!SetConsoleActiveScreenBuffer (ScreenBuffer))
  36. {
  37. err = Marshal.GetLastWin32Error();
  38. throw new System.ComponentModel.Win32Exception(err);
  39. }
  40. OriginalStdOutChars = new CharInfo[Console.WindowHeight * Console.WindowWidth];
  41. ReadConsoleOutput (
  42. OutputHandle,
  43. OriginalStdOutChars,
  44. coords,
  45. new Coord() { X = 0, Y = 0 },
  46. ref window
  47. );
  48. }
  49. return WriteConsoleOutput (
  50. ScreenBuffer,
  51. charInfoBuffer,
  52. coords,
  53. new Coord() { X = 0, Y = 0 },
  54. ref window
  55. );
  56. }
  57. public bool SetCursorPosition(Coord position)
  58. {
  59. return SetConsoleCursorPosition (ScreenBuffer, position);
  60. }
  61. public void PollEvents (Action<InputRecord> inputEventHandler)
  62. {
  63. if (OriginalConsoleMode != 0)
  64. return;
  65. OriginalConsoleMode = ConsoleMode;
  66. ConsoleMode |= (uint)ConsoleModes.EnableMouseInput;
  67. ConsoleMode &= ~(uint)ConsoleModes.EnableQuickEditMode;
  68. ConsoleMode |= (uint)ConsoleModes.EnableExtendedFlags;
  69. Task.Run (() =>
  70. {
  71. uint numberEventsRead = 0;
  72. uint length = 1;
  73. InputRecord[] records = new InputRecord[length];
  74. while (
  75. ContinueListeningForConsoleEvents &&
  76. ReadConsoleInput(InputHandle, records, length, out numberEventsRead) &&
  77. numberEventsRead > 0
  78. )
  79. {
  80. inputEventHandler (records[0]);
  81. }
  82. });
  83. }
  84. public void Cleanup ()
  85. {
  86. ContinueListeningForConsoleEvents = false;
  87. ConsoleMode = OriginalConsoleMode;
  88. OriginalConsoleMode = 0;
  89. if (!SetConsoleActiveScreenBuffer (OutputHandle))
  90. {
  91. var err = Marshal.GetLastWin32Error ();
  92. Console.WriteLine("Error: {0}", err);
  93. }
  94. }
  95. private bool ContinueListeningForConsoleEvents = true;
  96. private uint OriginalConsoleMode = 0;
  97. public uint ConsoleMode {
  98. get {
  99. uint v;
  100. GetConsoleMode (InputHandle, out v);
  101. return v;
  102. }
  103. set {
  104. SetConsoleMode (InputHandle, value);
  105. }
  106. }
  107. [Flags]
  108. public enum ConsoleModes : uint
  109. {
  110. EnableMouseInput = 16,
  111. EnableQuickEditMode = 64,
  112. EnableExtendedFlags = 128,
  113. }
  114. [StructLayout (LayoutKind.Explicit, CharSet = CharSet.Unicode)]
  115. public struct KeyEventRecord {
  116. [FieldOffset (0), MarshalAs (UnmanagedType.Bool)]
  117. public bool bKeyDown;
  118. [FieldOffset (4), MarshalAs (UnmanagedType.U2)]
  119. public ushort wRepeatCount;
  120. [FieldOffset (6), MarshalAs (UnmanagedType.U2)]
  121. public ushort wVirtualKeyCode;
  122. [FieldOffset (8), MarshalAs (UnmanagedType.U2)]
  123. public ushort wVirtualScanCode;
  124. [FieldOffset (10)]
  125. public char UnicodeChar;
  126. [FieldOffset (12), MarshalAs (UnmanagedType.U4)]
  127. public ControlKeyState dwControlKeyState;
  128. }
  129. [Flags]
  130. public enum ButtonState {
  131. Button1Pressed = 1,
  132. Button2Pressed = 4,
  133. Button3Pressed = 8,
  134. Button4Pressed = 16,
  135. RightmostButtonPressed = 2,
  136. }
  137. [Flags]
  138. public enum ControlKeyState {
  139. RightAltPressed = 1,
  140. LeftAltPressed = 2,
  141. RightControlPressed = 4,
  142. LeftControlPressed = 8,
  143. ShiftPressed = 16,
  144. NumlockOn = 32,
  145. ScrolllockOn = 64,
  146. CapslockOn = 128,
  147. EnhancedKey = 256
  148. }
  149. [Flags]
  150. public enum EventFlags {
  151. MouseMoved = 1,
  152. DoubleClick = 2,
  153. MouseWheeled = 4,
  154. MouseHorizontalWheeled = 8
  155. }
  156. [StructLayout (LayoutKind.Explicit)]
  157. public struct MouseEventRecord {
  158. [FieldOffset (0)]
  159. public Coordinate MousePosition;
  160. [FieldOffset (4)]
  161. public ButtonState ButtonState;
  162. [FieldOffset (8)]
  163. public ControlKeyState ControlKeyState;
  164. [FieldOffset (12)]
  165. public EventFlags EventFlags;
  166. public override string ToString ()
  167. {
  168. return $"[Mouse({MousePosition},{ButtonState},{ControlKeyState},{EventFlags}";
  169. }
  170. }
  171. [StructLayout (LayoutKind.Sequential)]
  172. public struct Coordinate {
  173. public short X;
  174. public short Y;
  175. public Coordinate (short X, short Y)
  176. {
  177. this.X = X;
  178. this.Y = Y;
  179. }
  180. public override string ToString () => $"({X},{Y})";
  181. };
  182. internal struct WindowBufferSizeRecord {
  183. public Coordinate size;
  184. public WindowBufferSizeRecord (short x, short y)
  185. {
  186. this.size = new Coordinate (x, y);
  187. }
  188. public override string ToString () => $"[WindowBufferSize{size}";
  189. }
  190. [StructLayout (LayoutKind.Sequential)]
  191. public struct MenuEventRecord {
  192. public uint dwCommandId;
  193. }
  194. [StructLayout (LayoutKind.Sequential)]
  195. public struct FocusEventRecord {
  196. public uint bSetFocus;
  197. }
  198. public enum EventType {
  199. Focus = 0x10,
  200. Key = 0x1,
  201. Menu = 0x8,
  202. Mouse = 2,
  203. WindowBufferSize = 4
  204. }
  205. [StructLayout (LayoutKind.Explicit)]
  206. public struct InputRecord {
  207. [FieldOffset (0)]
  208. public EventType EventType;
  209. [FieldOffset (4)]
  210. public KeyEventRecord KeyEvent;
  211. [FieldOffset (4)]
  212. public MouseEventRecord MouseEvent;
  213. [FieldOffset (4)]
  214. public WindowBufferSizeRecord WindowBufferSizeEvent;
  215. [FieldOffset (4)]
  216. public MenuEventRecord MenuEvent;
  217. [FieldOffset (4)]
  218. public FocusEventRecord FocusEvent;
  219. public override string ToString ()
  220. {
  221. switch (EventType) {
  222. case EventType.Focus:
  223. return FocusEvent.ToString ();
  224. case EventType.Key:
  225. return KeyEvent.ToString ();
  226. case EventType.Menu:
  227. return MenuEvent.ToString ();
  228. case EventType.Mouse:
  229. return MouseEvent.ToString ();
  230. case EventType.WindowBufferSize:
  231. return WindowBufferSizeEvent.ToString ();
  232. default:
  233. return "Unknown event type: " + EventType;
  234. }
  235. }
  236. };
  237. [Flags]
  238. enum ShareMode : uint
  239. {
  240. FileShareRead = 1,
  241. FileShareWrite = 2,
  242. }
  243. [Flags]
  244. enum DesiredAccess : uint
  245. {
  246. GenericRead = 2147483648,
  247. GenericWrite = 1073741824,
  248. }
  249. [StructLayout(LayoutKind.Sequential)]
  250. public struct ConsoleScreenBufferInfo
  251. {
  252. public Coord dwSize;
  253. public Coord dwCursorPosition;
  254. public ushort wAttributes;
  255. public SmallRect srWindow;
  256. public Coord dwMaximumWindowSize;
  257. }
  258. [StructLayout(LayoutKind.Sequential)]
  259. public struct Coord
  260. {
  261. public short X;
  262. public short Y;
  263. public Coord(short X, short Y)
  264. {
  265. this.X = X;
  266. this.Y = Y;
  267. }
  268. };
  269. [StructLayout(LayoutKind.Explicit, CharSet=CharSet.Unicode)]
  270. public struct CharUnion
  271. {
  272. [FieldOffset(0)] public char UnicodeChar;
  273. [FieldOffset(0)] public byte AsciiChar;
  274. }
  275. [StructLayout(LayoutKind.Explicit, CharSet=CharSet.Unicode)]
  276. public struct CharInfo
  277. {
  278. [FieldOffset(0)] public CharUnion Char;
  279. [FieldOffset(2)] public ushort Attributes;
  280. }
  281. [StructLayout(LayoutKind.Sequential)]
  282. public struct SmallRect
  283. {
  284. public short Left;
  285. public short Top;
  286. public short Right;
  287. public short Bottom;
  288. }
  289. [DllImport ("kernel32.dll", SetLastError = true)]
  290. static extern IntPtr GetStdHandle (int nStdHandle);
  291. [DllImport ("kernel32.dll", EntryPoint = "ReadConsoleInputW", CharSet = CharSet.Unicode)]
  292. public static extern bool ReadConsoleInput (
  293. IntPtr hConsoleInput,
  294. [Out] InputRecord [] lpBuffer,
  295. uint nLength,
  296. out uint lpNumberOfEventsRead);
  297. [DllImport("kernel32.dll", SetLastError=true, CharSet=CharSet.Unicode)]
  298. static extern bool ReadConsoleOutput(
  299. IntPtr hConsoleOutput,
  300. [Out] CharInfo[] lpBuffer,
  301. Coord dwBufferSize,
  302. Coord dwBufferCoord,
  303. ref SmallRect lpReadRegion
  304. );
  305. [DllImport("kernel32.dll", EntryPoint="WriteConsoleOutput", SetLastError=true, CharSet=CharSet.Unicode)]
  306. static extern bool WriteConsoleOutput(
  307. IntPtr hConsoleOutput,
  308. CharInfo[] lpBuffer,
  309. Coord dwBufferSize,
  310. Coord dwBufferCoord,
  311. ref SmallRect lpWriteRegion
  312. );
  313. [DllImport ("kernel32.dll")]
  314. static extern bool SetConsoleCursorPosition(IntPtr hConsoleOutput, Coord dwCursorPosition);
  315. [DllImport ("kernel32.dll")]
  316. static extern bool GetConsoleMode (IntPtr hConsoleHandle, out uint lpMode);
  317. [DllImport ("kernel32.dll")]
  318. static extern bool SetConsoleMode (IntPtr hConsoleHandle, uint dwMode);
  319. [DllImport("kernel32.dll", SetLastError = true)]
  320. static extern IntPtr CreateConsoleScreenBuffer(
  321. DesiredAccess dwDesiredAccess,
  322. ShareMode dwShareMode,
  323. IntPtr secutiryAttributes,
  324. UInt32 flags,
  325. IntPtr screenBufferData
  326. );
  327. [DllImport("kernel32.dll", SetLastError = true)]
  328. static extern bool SetConsoleActiveScreenBuffer(IntPtr Handle);
  329. }
  330. internal class WindowsDriver : ConsoleDriver {
  331. Action TerminalResized;
  332. WindowsConsole WinConsole;
  333. WindowsConsole.CharInfo[] OutputBuffer;
  334. int cols, rows;
  335. public override int Cols => cols;
  336. public override int Rows => rows;
  337. static bool sync;
  338. public WindowsDriver ()
  339. {
  340. WinConsole = new WindowsConsole();
  341. cols = Console.WindowWidth;
  342. rows = Console.WindowHeight - 1;
  343. ResizeScreen ();
  344. UpdateOffScreen ();
  345. }
  346. private MouseEvent ToDriverMouse(WindowsConsole.MouseEventRecord mouseEvent)
  347. {
  348. MouseFlags mouseFlag = MouseFlags.AllEvents;
  349. if (mouseEvent.EventFlags == 0)
  350. {
  351. switch (mouseEvent.ButtonState)
  352. {
  353. case WindowsConsole.ButtonState.Button1Pressed:
  354. mouseFlag = MouseFlags.Button1Clicked;
  355. break;
  356. case WindowsConsole.ButtonState.Button2Pressed:
  357. mouseFlag = MouseFlags.Button2Clicked;
  358. break;
  359. case WindowsConsole.ButtonState.Button3Pressed:
  360. mouseFlag = MouseFlags.Button3Clicked;
  361. break;
  362. }
  363. }
  364. else if(mouseEvent.EventFlags == WindowsConsole.EventFlags.MouseMoved)
  365. {
  366. mouseFlag = MouseFlags.ReportMousePosition;
  367. }
  368. return new MouseEvent () {
  369. X = mouseEvent.MousePosition.X,
  370. Y = mouseEvent.MousePosition.Y,
  371. Flags = mouseFlag
  372. };
  373. }
  374. private ConsoleKeyInfo ToConsoleKeyInfo (WindowsConsole.KeyEventRecord keyEvent)
  375. {
  376. var state = keyEvent.dwControlKeyState;
  377. bool shift = (state & WindowsConsole.ControlKeyState.ShiftPressed) != 0;
  378. bool alt = (state & (WindowsConsole.ControlKeyState.LeftAltPressed | WindowsConsole.ControlKeyState.RightAltPressed)) != 0;
  379. bool control = (state & (WindowsConsole.ControlKeyState.LeftControlPressed | WindowsConsole.ControlKeyState.RightControlPressed)) != 0;
  380. return new ConsoleKeyInfo(keyEvent.UnicodeChar, (ConsoleKey)keyEvent.wVirtualKeyCode, shift, alt, control);
  381. }
  382. public Key MapKey (ConsoleKeyInfo keyInfo)
  383. {
  384. switch (keyInfo.Key) {
  385. case ConsoleKey.Escape:
  386. return Key.Esc;
  387. case ConsoleKey.Tab:
  388. return Key.Tab;
  389. case ConsoleKey.Home:
  390. return Key.Home;
  391. case ConsoleKey.End:
  392. return Key.End;
  393. case ConsoleKey.LeftArrow:
  394. return Key.CursorLeft;
  395. case ConsoleKey.RightArrow:
  396. return Key.CursorRight;
  397. case ConsoleKey.UpArrow:
  398. return Key.CursorUp;
  399. case ConsoleKey.DownArrow:
  400. return Key.CursorDown;
  401. case ConsoleKey.PageUp:
  402. return Key.PageUp;
  403. case ConsoleKey.PageDown:
  404. return Key.PageDown;
  405. case ConsoleKey.Enter:
  406. return Key.Enter;
  407. case ConsoleKey.Spacebar:
  408. return Key.Space;
  409. case ConsoleKey.Backspace:
  410. return Key.Backspace;
  411. case ConsoleKey.Delete:
  412. return Key.Delete;
  413. case ConsoleKey.Oem1:
  414. case ConsoleKey.Oem2:
  415. case ConsoleKey.Oem3:
  416. case ConsoleKey.Oem4:
  417. case ConsoleKey.Oem5:
  418. case ConsoleKey.Oem6:
  419. case ConsoleKey.Oem7:
  420. case ConsoleKey.Oem8:
  421. case ConsoleKey.Oem102:
  422. case ConsoleKey.OemPeriod:
  423. case ConsoleKey.OemComma:
  424. case ConsoleKey.OemPlus:
  425. case ConsoleKey.OemMinus:
  426. return (Key)((uint)keyInfo.KeyChar);
  427. }
  428. var key = keyInfo.Key;
  429. if (key >= ConsoleKey.A && key <= ConsoleKey.Z) {
  430. var delta = key - ConsoleKey.A;
  431. if (keyInfo.Modifiers == ConsoleModifiers.Control)
  432. return (Key)((uint)Key.ControlA + delta);
  433. if (keyInfo.Modifiers == ConsoleModifiers.Alt)
  434. return (Key)(((uint)Key.AltMask) | ((uint)'A' + delta));
  435. if (keyInfo.Modifiers == ConsoleModifiers.Shift)
  436. return (Key)((uint)'A' + delta);
  437. else
  438. return (Key)((uint)'a' + delta);
  439. }
  440. if (key >= ConsoleKey.D0 && key <= ConsoleKey.D9) {
  441. var delta = key - ConsoleKey.D0;
  442. if (keyInfo.Modifiers == ConsoleModifiers.Alt)
  443. return (Key)(((uint)Key.AltMask) | ((uint)'0' + delta));
  444. if (keyInfo.Modifiers == ConsoleModifiers.Shift)
  445. return (Key)((uint)keyInfo.KeyChar);
  446. return (Key)((uint)'0' + delta);
  447. }
  448. if (key >= ConsoleKey.F1 && key <= ConsoleKey.F10) {
  449. var delta = key - ConsoleKey.F1;
  450. return (Key)((int)Key.F1 + delta);
  451. }
  452. return (Key)(0xffffffff);
  453. }
  454. public override void PrepareToRun (MainLoop mainLoop, Action<KeyEvent> keyHandler, Action<MouseEvent> mouseHandler)
  455. {
  456. WinConsole.PollEvents (inputEvent =>
  457. {
  458. switch(inputEvent.EventType)
  459. {
  460. case WindowsConsole.EventType.Key:
  461. if (inputEvent.KeyEvent.bKeyDown == false)
  462. return;
  463. var map = MapKey (ToConsoleKeyInfo (inputEvent.KeyEvent));
  464. if (map == (Key) 0xffffffff)
  465. return;
  466. keyHandler (new KeyEvent (map));
  467. break;
  468. case WindowsConsole.EventType.Mouse:
  469. mouseHandler (ToDriverMouse (inputEvent.MouseEvent));
  470. break;
  471. case WindowsConsole.EventType.WindowBufferSize:
  472. cols = inputEvent.WindowBufferSizeEvent.size.X;
  473. rows = inputEvent.WindowBufferSizeEvent.size.Y - 1;
  474. ResizeScreen ();
  475. UpdateOffScreen ();
  476. TerminalResized ();
  477. break;
  478. }
  479. });
  480. }
  481. public override void Init (Action terminalResized)
  482. {
  483. TerminalResized = terminalResized;
  484. Colors.Base = new ColorScheme ();
  485. Colors.Dialog = new ColorScheme ();
  486. Colors.Menu = new ColorScheme ();
  487. Colors.Error = new ColorScheme ();
  488. HLine = '\u2500';
  489. VLine = '\u2502';
  490. Stipple = '\u2592';
  491. Diamond = '\u25c6';
  492. ULCorner = '\u250C';
  493. LLCorner = '\u2514';
  494. URCorner = '\u2510';
  495. LRCorner = '\u2518';
  496. LeftTee = '\u251c';
  497. RightTee = '\u2524';
  498. TopTee = '\u22a4';
  499. BottomTee = '\u22a5';
  500. Colors.Base.Normal = MakeColor (ConsoleColor.White, ConsoleColor.Blue);
  501. Colors.Base.Focus = MakeColor (ConsoleColor.Black, ConsoleColor.Cyan);
  502. Colors.Base.HotNormal = MakeColor (ConsoleColor.Yellow, ConsoleColor.Blue);
  503. Colors.Base.HotFocus = MakeColor (ConsoleColor.Yellow, ConsoleColor.Cyan);
  504. Colors.Menu.HotFocus = MakeColor (ConsoleColor.Yellow, ConsoleColor.Black);
  505. Colors.Menu.Focus = MakeColor (ConsoleColor.White, ConsoleColor.Black);
  506. Colors.Menu.HotNormal = MakeColor (ConsoleColor.Yellow, ConsoleColor.Cyan);
  507. Colors.Menu.Normal = MakeColor (ConsoleColor.White, ConsoleColor.Cyan);
  508. Colors.Dialog.Normal = MakeColor (ConsoleColor.Black, ConsoleColor.Gray);
  509. Colors.Dialog.Focus = MakeColor (ConsoleColor.Black, ConsoleColor.Cyan);
  510. Colors.Dialog.HotNormal = MakeColor (ConsoleColor.Blue, ConsoleColor.Gray);
  511. Colors.Dialog.HotFocus = MakeColor (ConsoleColor.Blue, ConsoleColor.Cyan);
  512. Colors.Error.Normal = MakeColor (ConsoleColor.White, ConsoleColor.Red);
  513. Colors.Error.Focus = MakeColor (ConsoleColor.Black, ConsoleColor.Gray);
  514. Colors.Error.HotNormal = MakeColor (ConsoleColor.Yellow, ConsoleColor.Red);
  515. Colors.Error.HotFocus = Colors.Error.HotNormal;
  516. Console.Clear ();
  517. }
  518. void ResizeScreen ()
  519. {
  520. OutputBuffer = new WindowsConsole.CharInfo[Rows * Cols];
  521. Clip = new Rect (0, 0, Cols, Rows);
  522. }
  523. void UpdateOffScreen ()
  524. {
  525. for (int row = 0; row < rows; row++)
  526. for (int col = 0; col < cols; col++)
  527. {
  528. int position = row * cols + col;
  529. OutputBuffer[position].Attributes = (ushort)MakeColor(ConsoleColor.White, ConsoleColor.Blue);
  530. OutputBuffer[position].Char.UnicodeChar = ' ';
  531. }
  532. }
  533. int ccol, crow;
  534. public override void Move (int col, int row)
  535. {
  536. ccol = col;
  537. crow = row;
  538. }
  539. public override void AddRune (Rune rune)
  540. {
  541. var position = crow * Cols + ccol;
  542. if (Clip.Contains (ccol, crow))
  543. {
  544. OutputBuffer[position].Attributes = (ushort)currentAttribute;
  545. OutputBuffer[position].Char.UnicodeChar = (char)rune;
  546. }
  547. ccol++;
  548. if (ccol == Cols) {
  549. ccol = 0;
  550. if (crow + 1 < Rows)
  551. crow++;
  552. }
  553. if (sync)
  554. UpdateScreen ();
  555. }
  556. public override void AddStr (ustring str)
  557. {
  558. foreach (var rune in str)
  559. AddRune (rune);
  560. }
  561. int currentAttribute;
  562. public override void SetAttribute (Attribute c)
  563. {
  564. currentAttribute = c.value;
  565. }
  566. private Attribute MakeColor (ConsoleColor f, ConsoleColor b)
  567. {
  568. // Encode the colors into the int value.
  569. return new Attribute ()
  570. {
  571. value = ((int)f | (int)b << 4)
  572. };
  573. }
  574. public override void Refresh()
  575. {
  576. var bufferCoords = new WindowsConsole.Coord ()
  577. {
  578. X = (short)Clip.Width,
  579. Y = (short)Clip.Height
  580. };
  581. var window = new WindowsConsole.SmallRect ()
  582. {
  583. Top = 0,
  584. Left = 0,
  585. Right = (short)Clip.Right,
  586. Bottom = (short)Clip.Bottom
  587. };
  588. UpdateCursor();
  589. WinConsole.WriteToConsole (OutputBuffer, bufferCoords, window);
  590. }
  591. public override void UpdateScreen ()
  592. {
  593. var bufferCoords = new WindowsConsole.Coord ()
  594. {
  595. X = (short)Clip.Width,
  596. Y = (short)Clip.Height
  597. };
  598. var window = new WindowsConsole.SmallRect ()
  599. {
  600. Top = 0,
  601. Left = 0,
  602. Right = (short)Clip.Right,
  603. Bottom = (short)Clip.Bottom
  604. };
  605. UpdateCursor();
  606. WinConsole.WriteToConsole (OutputBuffer, bufferCoords, window);
  607. }
  608. public override void UpdateCursor()
  609. {
  610. var position = new WindowsConsole.Coord()
  611. {
  612. X = (short)ccol,
  613. Y = (short)crow
  614. };
  615. WinConsole.SetCursorPosition(position);
  616. }
  617. public override void End ()
  618. {
  619. WinConsole.Cleanup();
  620. }
  621. #region Unused
  622. public override void SetColors (ConsoleColor foreground, ConsoleColor background)
  623. {
  624. }
  625. public override void SetColors (short foregroundColorId, short backgroundColorId)
  626. {
  627. }
  628. public override void Suspend ()
  629. {
  630. }
  631. public override void StartReportingMouseMoves ()
  632. {
  633. }
  634. public override void StopReportingMouseMoves ()
  635. {
  636. }
  637. public override void UncookMouse ()
  638. {
  639. }
  640. public override void CookMouse ()
  641. {
  642. }
  643. #endregion
  644. }
  645. }