ConsoleDriver.cs 31 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099
  1. //
  2. // ConsoleDriver.cs: Base class for Terminal.Gui ConsoleDriver implementations.
  3. //
  4. using System.Text;
  5. using System;
  6. using System.Diagnostics;
  7. using System.Linq;
  8. using Terminal.Gui.ConsoleDrivers;
  9. namespace Terminal.Gui;
  10. /// <summary>
  11. /// Base class for Terminal.Gui ConsoleDriver implementations.
  12. /// </summary>
  13. /// <remarks>
  14. /// There are currently four implementations:
  15. /// - <see cref="CursesDriver"/> (for Unix and Mac)
  16. /// - <see cref="WindowsDriver"/>
  17. /// - <see cref="NetDriver"/> that uses the .NET Console API
  18. /// - <see cref="FakeConsole"/> for unit testing.
  19. /// </remarks>
  20. public abstract class ConsoleDriver {
  21. /// <summary>
  22. /// Set this to true in any unit tests that attempt to test drivers other than FakeDriver.
  23. /// <code>
  24. /// public ColorTests ()
  25. /// {
  26. /// ConsoleDriver.RunningUnitTests = true;
  27. /// }
  28. /// </code>
  29. /// </summary>
  30. internal static bool RunningUnitTests { get; set; }
  31. #region Setup & Teardown
  32. /// <summary>
  33. /// Initializes the driver
  34. /// </summary>
  35. /// <returns>Returns an instance of <see cref="MainLoop"/> using the <see cref="IMainLoopDriver"/> for the driver.</returns>
  36. internal abstract MainLoop Init ();
  37. /// <summary>
  38. /// Ends the execution of the console driver.
  39. /// </summary>
  40. internal abstract void End ();
  41. #endregion
  42. /// <summary>
  43. /// The event fired when the terminal is resized.
  44. /// </summary>
  45. public event EventHandler<SizeChangedEventArgs> SizeChanged;
  46. /// <summary>
  47. /// Called when the terminal size changes. Fires the <see cref="SizeChanged"/> event.
  48. /// </summary>
  49. /// <param name="args"></param>
  50. public void OnSizeChanged (SizeChangedEventArgs args) => SizeChanged?.Invoke (this, args);
  51. /// <summary>
  52. /// The number of columns visible in the terminal.
  53. /// </summary>
  54. public virtual int Cols { get; internal set; }
  55. /// <summary>
  56. /// The number of rows visible in the terminal.
  57. /// </summary>
  58. public virtual int Rows { get; internal set; }
  59. /// <summary>
  60. /// The leftmost column in the terminal.
  61. /// </summary>
  62. public virtual int Left { get; internal set; } = 0;
  63. /// <summary>
  64. /// The topmost row in the terminal.
  65. /// </summary>
  66. public virtual int Top { get; internal set; } = 0;
  67. /// <summary>
  68. /// Get the operating system clipboard.
  69. /// </summary>
  70. public IClipboard Clipboard { get; internal set; }
  71. /// <summary>
  72. /// The contents of the application output. The driver outputs this buffer to the terminal when <see cref="UpdateScreen"/>
  73. /// is called.
  74. /// <remarks>
  75. /// The format of the array is rows, columns. The first index is the row, the second index is the column.
  76. /// </remarks>
  77. /// </summary>
  78. public Cell [,] Contents { get; internal set; }
  79. /// <summary>
  80. /// Gets the column last set by <see cref="Move"/>. <see cref="Col"/> and <see cref="Row"/>
  81. /// are used by <see cref="AddRune(Rune)"/> and <see cref="AddStr"/> to determine where to add content.
  82. /// </summary>
  83. public int Col { get; internal set; }
  84. /// <summary>
  85. /// Gets the row last set by <see cref="Move"/>. <see cref="Col"/> and <see cref="Row"/>
  86. /// are used by <see cref="AddRune(Rune)"/> and <see cref="AddStr"/> to determine where to add content.
  87. /// </summary>
  88. public int Row { get; internal set; }
  89. /// <summary>
  90. /// Updates <see cref="Col"/> and <see cref="Row"/> to the specified column and row in <see cref="Contents"/>.
  91. /// Used by <see cref="AddRune(Rune)"/> and <see cref="AddStr"/> to determine where to add content.
  92. /// </summary>
  93. /// <remarks>
  94. /// <para>
  95. /// This does not move the cursor on the screen, it only updates the internal state of the driver.
  96. /// </para>
  97. /// <para>
  98. /// If <paramref name="col"/> or <paramref name="row"/> are negative or beyond <see cref="Cols"/> and <see cref="Rows"/>,
  99. /// the method still sets those properties.
  100. /// </para>
  101. /// </remarks>
  102. /// <param name="col">Column to move to.</param>
  103. /// <param name="row">Row to move to.</param>
  104. public virtual void Move (int col, int row)
  105. {
  106. Col = col;
  107. Row = row;
  108. }
  109. /// <summary>
  110. /// Tests if the specified rune is supported by the driver.
  111. /// </summary>
  112. /// <param name="rune"></param>
  113. /// <returns><see langword="true"/> if the rune can be properly presented; <see langword="false"/> if the driver
  114. /// does not support displaying this rune.</returns>
  115. public virtual bool IsRuneSupported (Rune rune) => Rune.IsValid (rune.Value);
  116. /// <summary>
  117. /// Adds the specified rune to the display at the current cursor position.
  118. /// </summary>
  119. /// <remarks>
  120. /// <para>
  121. /// When the method returns, <see cref="Col"/> will be incremented by the number of columns <paramref name="rune"/> required,
  122. /// even if the new column value is outside of the <see cref="Clip"/> or screen dimensions defined by <see cref="Cols"/>.
  123. /// </para>
  124. /// <para>
  125. /// If <paramref name="rune"/> requires more than one column, and <see cref="Col"/> plus the number of columns needed
  126. /// exceeds the <see cref="Clip"/> or screen dimensions, the default Unicode replacement character (U+FFFD) will be added instead.
  127. /// </para>
  128. /// </remarks>
  129. /// <param name="rune">Rune to add.</param>
  130. public void AddRune (Rune rune)
  131. {
  132. int runeWidth = -1;
  133. bool validLocation = IsValidLocation (Col, Row);
  134. if (validLocation) {
  135. rune = rune.MakePrintable ();
  136. runeWidth = rune.GetColumns ();
  137. if (runeWidth == 0 && rune.IsCombiningMark ()) {
  138. if (Col > 0) {
  139. if (Contents [Row, Col - 1].CombiningMarks.Count > 0) {
  140. // Just add this mark to the list
  141. Contents [Row, Col - 1].CombiningMarks.Add (rune);
  142. // Don't move to next column (let the driver figure out what to do).
  143. } else {
  144. // Attempt to normalize the cell to our left combined with this mark
  145. string combined = Contents [Row, Col - 1].Rune + rune.ToString ();
  146. // Normalize to Form C (Canonical Composition)
  147. string normalized = combined.Normalize (NormalizationForm.FormC);
  148. if (normalized.Length == 1) {
  149. // It normalized! We can just set the Cell to the left with the
  150. // normalized codepoint
  151. Contents [Row, Col - 1].Rune = (Rune)normalized [0];
  152. // Don't move to next column because we're already there
  153. } else {
  154. // It didn't normalize. Add it to the Cell to left's CM list
  155. Contents [Row, Col - 1].CombiningMarks.Add (rune);
  156. // Don't move to next column (let the driver figure out what to do).
  157. }
  158. }
  159. Contents [Row, Col - 1].Attribute = CurrentAttribute;
  160. Contents [Row, Col - 1].IsDirty = true;
  161. } else {
  162. // Most drivers will render a combining mark at col 0 as the mark
  163. Contents [Row, Col].Rune = rune;
  164. Contents [Row, Col].Attribute = CurrentAttribute;
  165. Contents [Row, Col].IsDirty = true;
  166. Col++;
  167. }
  168. } else {
  169. Contents [Row, Col].Attribute = CurrentAttribute;
  170. Contents [Row, Col].IsDirty = true;
  171. if (Col > 0) {
  172. // Check if cell to left has a wide glyph
  173. if (Contents [Row, Col - 1].Rune.GetColumns () > 1) {
  174. // Invalidate cell to left
  175. Contents [Row, Col - 1].Rune = Rune.ReplacementChar;
  176. Contents [Row, Col - 1].IsDirty = true;
  177. }
  178. }
  179. if (runeWidth < 1) {
  180. Contents [Row, Col].Rune = Rune.ReplacementChar;
  181. } else if (runeWidth == 1) {
  182. Contents [Row, Col].Rune = rune;
  183. if (Col < Clip.Right - 1) {
  184. Contents [Row, Col + 1].IsDirty = true;
  185. }
  186. } else if (runeWidth == 2) {
  187. if (Col == Clip.Right - 1) {
  188. // We're at the right edge of the clip, so we can't display a wide character.
  189. // TODO: Figure out if it is better to show a replacement character or ' '
  190. Contents [Row, Col].Rune = Rune.ReplacementChar;
  191. } else {
  192. Contents [Row, Col].Rune = rune;
  193. if (Col < Clip.Right - 1) {
  194. // Invalidate cell to right so that it doesn't get drawn
  195. // TODO: Figure out if it is better to show a replacement character or ' '
  196. Contents [Row, Col + 1].Rune = Rune.ReplacementChar;
  197. Contents [Row, Col + 1].IsDirty = true;
  198. }
  199. }
  200. } else {
  201. // This is a non-spacing character, so we don't need to do anything
  202. Contents [Row, Col].Rune = (Rune)' ';
  203. Contents [Row, Col].IsDirty = false;
  204. }
  205. _dirtyLines [Row] = true;
  206. }
  207. }
  208. if (runeWidth is < 0 or > 0) {
  209. Col++;
  210. }
  211. if (runeWidth > 1) {
  212. Debug.Assert (runeWidth <= 2);
  213. if (validLocation && Col < Clip.Right) {
  214. // This is a double-width character, and we are not at the end of the line.
  215. // Col now points to the second column of the character. Ensure it doesn't
  216. // Get rendered.
  217. Contents [Row, Col].IsDirty = false;
  218. Contents [Row, Col].Attribute = CurrentAttribute;
  219. // TODO: Determine if we should wipe this out (for now now)
  220. //Contents [Row, Col].Rune = (Rune)' ';
  221. }
  222. Col++;
  223. }
  224. }
  225. /// <summary>
  226. /// Adds the specified <see langword="char"/> to the display at the current cursor position. This method
  227. /// is a convenience method that calls <see cref="AddRune(Rune)"/> with the <see cref="Rune"/> constructor.
  228. /// </summary>
  229. /// <param name="c">Character to add.</param>
  230. public void AddRune (char c) => AddRune (new Rune (c));
  231. /// <summary>
  232. /// Adds the <paramref name="str"/> to the display at the cursor position.
  233. /// </summary>
  234. /// <remarks>
  235. /// <para>
  236. /// When the method returns, <see cref="Col"/> will be incremented by the number of columns <paramref name="str"/> required,
  237. /// unless the new column value is outside of the <see cref="Clip"/> or screen dimensions defined by <see cref="Cols"/>.
  238. /// </para>
  239. /// <para>
  240. /// If <paramref name="str"/> requires more columns than are available, the output will be clipped.
  241. /// </para>
  242. /// </remarks>
  243. /// <param name="str">String.</param>
  244. public void AddStr (string str)
  245. {
  246. var runes = str.EnumerateRunes ().ToList ();
  247. for (int i = 0; i < runes.Count; i++) {
  248. //if (runes [i].IsCombiningMark()) {
  249. // // Attempt to normalize
  250. // string combined = runes [i-1] + runes [i].ToString();
  251. // // Normalize to Form C (Canonical Composition)
  252. // string normalized = combined.Normalize (NormalizationForm.FormC);
  253. // runes [i-]
  254. //}
  255. AddRune (runes [i]);
  256. }
  257. }
  258. Rect _clip;
  259. /// <summary>
  260. /// Tests whether the specified coordinate are valid for drawing.
  261. /// </summary>
  262. /// <param name="col">The column.</param>
  263. /// <param name="row">The row.</param>
  264. /// <returns><see langword="false"/> if the coordinate is outside of the
  265. /// screen bounds or outside of <see cref="Clip"/>. <see langword="true"/> otherwise.</returns>
  266. public bool IsValidLocation (int col, int row) =>
  267. col >= 0 && row >= 0 &&
  268. col < Cols && row < Rows &&
  269. Clip.Contains (col, row);
  270. /// <summary>
  271. /// Gets or sets the clip rectangle that <see cref="AddRune(Rune)"/> and <see cref="AddStr(string)"/> are
  272. /// subject to.
  273. /// </summary>
  274. /// <value>The rectangle describing the bounds of <see cref="Clip"/>.</value>
  275. public Rect Clip {
  276. get => _clip;
  277. set => _clip = value;
  278. }
  279. /// <summary>
  280. /// Updates the screen to reflect all the changes that have been done to the display buffer
  281. /// </summary>
  282. public abstract void Refresh ();
  283. /// <summary>
  284. /// Sets the position of the terminal cursor to <see cref="Col"/> and <see cref="Row"/>.
  285. /// </summary>
  286. public abstract void UpdateCursor ();
  287. /// <summary>
  288. /// Gets the terminal cursor visibility.
  289. /// </summary>
  290. /// <param name="visibility">The current <see cref="CursorVisibility"/></param>
  291. /// <returns><see langword="true"/> upon success</returns>
  292. public abstract bool GetCursorVisibility (out CursorVisibility visibility);
  293. /// <summary>
  294. /// Sets the terminal cursor visibility.
  295. /// </summary>
  296. /// <param name="visibility">The wished <see cref="CursorVisibility"/></param>
  297. /// <returns><see langword="true"/> upon success</returns>
  298. public abstract bool SetCursorVisibility (CursorVisibility visibility);
  299. /// <summary>
  300. /// Determines if the terminal cursor should be visible or not and sets it accordingly.
  301. /// </summary>
  302. /// <returns><see langword="true"/> upon success</returns>
  303. public abstract bool EnsureCursorVisibility ();
  304. // As performance is a concern, we keep track of the dirty lines and only refresh those.
  305. // This is in addition to the dirty flag on each cell.
  306. internal bool [] _dirtyLines;
  307. /// <summary>
  308. /// Clears the <see cref="Contents"/> of the driver.
  309. /// </summary>
  310. public void ClearContents ()
  311. {
  312. // TODO: This method is really "Clear Contents" now and should not be abstract (or virtual)
  313. Contents = new Cell [Rows, Cols];
  314. Clip = new Rect (0, 0, Cols, Rows);
  315. _dirtyLines = new bool [Rows];
  316. lock (Contents) {
  317. // Can raise an exception while is still resizing.
  318. try {
  319. for (int row = 0; row < Rows; row++) {
  320. for (int c = 0; c < Cols; c++) {
  321. Contents [row, c] = new Cell () {
  322. Rune = (Rune)' ',
  323. Attribute = new Attribute (Color.White, Color.Black),
  324. IsDirty = true
  325. };
  326. _dirtyLines [row] = true;
  327. }
  328. }
  329. } catch (IndexOutOfRangeException) { }
  330. }
  331. }
  332. /// <summary>
  333. /// Redraws the physical screen with the contents that have been queued up via any of the printing commands.
  334. /// </summary>
  335. public abstract void UpdateScreen ();
  336. #region Color Handling
  337. /// <summary>
  338. /// Gets whether the <see cref="ConsoleDriver"/> supports TrueColor output.
  339. /// </summary>
  340. public virtual bool SupportsTrueColor => true;
  341. /// <summary>
  342. /// Gets or sets whether the <see cref="ConsoleDriver"/> should use 16 colors instead of the default TrueColors. See <see cref="Application.Force16Colors"/>
  343. /// to change this setting via <see cref="ConfigurationManager"/>.
  344. /// </summary>
  345. /// <remarks>
  346. /// <para>
  347. /// Will be forced to <see langword="true"/> if <see cref="ConsoleDriver.SupportsTrueColor"/> is <see langword="false"/>, indicating
  348. /// that the <see cref="ConsoleDriver"/> cannot support TrueColor.
  349. /// </para>
  350. /// </remarks>
  351. internal virtual bool Force16Colors {
  352. get => Application.Force16Colors || !SupportsTrueColor;
  353. set => Application.Force16Colors = value || !SupportsTrueColor;
  354. }
  355. Attribute _currentAttribute;
  356. /// <summary>
  357. /// The <see cref="Attribute"/> that will be used for the next <see cref="AddRune(Rune)"/> or <see cref="AddStr"/> call.
  358. /// </summary>
  359. public Attribute CurrentAttribute {
  360. get => _currentAttribute;
  361. set {
  362. if (Application.Driver != null) {
  363. _currentAttribute = new Attribute (value.Foreground, value.Background);
  364. return;
  365. }
  366. _currentAttribute = value;
  367. }
  368. }
  369. /// <summary>
  370. /// Selects the specified attribute as the attribute to use for future calls to AddRune and AddString.
  371. /// </summary>
  372. /// <remarks>
  373. /// Implementations should call <c>base.SetAttribute(c)</c>.
  374. /// </remarks>
  375. /// <param name="c">C.</param>
  376. public Attribute SetAttribute (Attribute c)
  377. {
  378. var prevAttribute = CurrentAttribute;
  379. CurrentAttribute = c;
  380. return prevAttribute;
  381. }
  382. /// <summary>
  383. /// Gets the current <see cref="Attribute"/>.
  384. /// </summary>
  385. /// <returns>The current attribute.</returns>
  386. public Attribute GetAttribute () => CurrentAttribute;
  387. // TODO: This is only overridden by CursesDriver. Once CursesDriver supports 24-bit color, this virtual method can be
  388. // removed (and Attribute can lose the platformColor property).
  389. /// <summary>
  390. /// Makes an <see cref="Attribute"/>.
  391. /// </summary>
  392. /// <param name="foreground">The foreground color.</param>
  393. /// <param name="background">The background color.</param>
  394. /// <returns>The attribute for the foreground and background colors.</returns>
  395. public virtual Attribute MakeColor (Color foreground, Color background) =>
  396. // Encode the colors into the int value.
  397. new (
  398. 0, // only used by cursesdriver!
  399. foreground,
  400. background
  401. );
  402. #endregion
  403. #region Mouse and Keyboard
  404. /// <summary>
  405. /// Event fired when a key is pressed down. This is a precursor to <see cref="KeyUp"/>.
  406. /// </summary>
  407. public event EventHandler<Key> KeyDown;
  408. /// <summary>
  409. /// Called when a key is pressed down. Fires the <see cref="KeyDown"/> event. This is a precursor to <see cref="OnKeyUp"/>.
  410. /// </summary>
  411. /// <param name="a"></param>
  412. public void OnKeyDown (Key a) => KeyDown?.Invoke (this, a);
  413. /// <summary>
  414. /// Event fired when a key is released.
  415. /// </summary>
  416. /// <remarks>
  417. /// Drivers that do not support key release events will fire this event after <see cref="KeyDown"/> processing is complete.
  418. /// </remarks>
  419. public event EventHandler<Key> KeyUp;
  420. /// <summary>
  421. /// Called when a key is released. Fires the <see cref="KeyUp"/> event.
  422. /// </summary>
  423. /// <remarks>
  424. /// Drivers that do not support key release events will calls this method after <see cref="OnKeyDown"/> processing is complete.
  425. /// </remarks>
  426. /// <param name="a"></param>
  427. public void OnKeyUp (Key a) => KeyUp?.Invoke (this, a);
  428. /// <summary>
  429. /// Event fired when a mouse event occurs.
  430. /// </summary>
  431. public event EventHandler<MouseEventEventArgs> MouseEvent;
  432. /// <summary>
  433. /// Called when a mouse event occurs. Fires the <see cref="MouseEvent"/> event.
  434. /// </summary>
  435. /// <param name="a"></param>
  436. public void OnMouseEvent (MouseEventEventArgs a) => MouseEvent?.Invoke (this, a);
  437. /// <summary>
  438. /// Simulates a key press.
  439. /// </summary>
  440. /// <param name="keyChar">The key character.</param>
  441. /// <param name="key">The key.</param>
  442. /// <param name="shift">If <see langword="true"/> simulates the Shift key being pressed.</param>
  443. /// <param name="alt">If <see langword="true"/> simulates the Alt key being pressed.</param>
  444. /// <param name="ctrl">If <see langword="true"/> simulates the Ctrl key being pressed.</param>
  445. public abstract void SendKeys (char keyChar, ConsoleKey key, bool shift, bool alt, bool ctrl);
  446. #endregion
  447. /// <summary>
  448. /// Enables diagnostic functions
  449. /// </summary>
  450. [Flags]
  451. public enum DiagnosticFlags : uint {
  452. /// <summary>
  453. /// All diagnostics off
  454. /// </summary>
  455. Off = 0b_0000_0000,
  456. /// <summary>
  457. /// When enabled, <see cref="Frame.OnDrawFrames"/> will draw a
  458. /// ruler in the frame for any side with a padding value greater than 0.
  459. /// </summary>
  460. FrameRuler = 0b_0000_0001,
  461. /// <summary>
  462. /// When enabled, <see cref="Frame.OnDrawFrames"/> will draw a
  463. /// 'L', 'R', 'T', and 'B' when clearing <see cref="Thickness"/>'s instead of ' '.
  464. /// </summary>
  465. FramePadding = 0b_0000_0010
  466. }
  467. /// <summary>
  468. /// Set flags to enable/disable <see cref="ConsoleDriver"/> diagnostics.
  469. /// </summary>
  470. public static DiagnosticFlags Diagnostics { get; set; }
  471. /// <summary>
  472. /// Suspends the application (e.g. on Linux via SIGTSTP) and upon resume, resets the console driver.
  473. /// </summary>
  474. /// <remarks>This is only implemented in <see cref="CursesDriver"/>.</remarks>
  475. public abstract void Suspend ();
  476. // TODO: Move FillRect to ./Drawing
  477. /// <summary>
  478. /// Fills the specified rectangle with the specified rune.
  479. /// </summary>
  480. /// <param name="rect"></param>
  481. /// <param name="rune"></param>
  482. public void FillRect (Rect rect, Rune rune = default)
  483. {
  484. for (int r = rect.Y; r < rect.Y + rect.Height; r++) {
  485. for (int c = rect.X; c < rect.X + rect.Width; c++) {
  486. Application.Driver.Move (c, r);
  487. Application.Driver.AddRune (rune == default ? new Rune (' ') : rune);
  488. }
  489. }
  490. }
  491. /// <summary>
  492. /// Fills the specified rectangle with the specified <see langword="char"/>. This method
  493. /// is a convenience method that calls <see cref="FillRect(Rect, Rune)"/>.
  494. /// </summary>
  495. /// <param name="rect"></param>
  496. /// <param name="c"></param>
  497. public void FillRect (Rect rect, char c) => FillRect (rect, new Rune (c));
  498. /// <summary>
  499. /// Returns the name of the driver and relevant library version information.
  500. /// </summary>
  501. /// <returns></returns>
  502. public virtual string GetVersionInfo () => GetType ().Name;
  503. }
  504. /// <summary>
  505. /// Terminal Cursor Visibility settings.
  506. /// </summary>
  507. /// <remarks>
  508. /// Hex value are set as 0xAABBCCDD where :
  509. ///
  510. /// AA stand for the TERMINFO DECSUSR parameter value to be used under Linux and MacOS
  511. /// BB stand for the NCurses curs_set parameter value to be used under Linux and MacOS
  512. /// CC stand for the CONSOLE_CURSOR_INFO.bVisible parameter value to be used under Windows
  513. /// DD stand for the CONSOLE_CURSOR_INFO.dwSize parameter value to be used under Windows
  514. ///</remarks>
  515. public enum CursorVisibility {
  516. /// <summary>
  517. /// Cursor caret has default
  518. /// </summary>
  519. /// <remarks>Works under Xterm-like terminal otherwise this is equivalent to <see ref="Underscore"/>. This default directly depends of the XTerm user configuration settings so it could be Block, I-Beam, Underline with possible blinking.</remarks>
  520. Default = 0x00010119,
  521. /// <summary>
  522. /// Cursor caret is hidden
  523. /// </summary>
  524. Invisible = 0x03000019,
  525. /// <summary>
  526. /// Cursor caret is normally shown as a blinking underline bar _
  527. /// </summary>
  528. Underline = 0x03010119,
  529. /// <summary>
  530. /// Cursor caret is normally shown as a underline bar _
  531. /// </summary>
  532. /// <remarks>Under Windows, this is equivalent to <see ref="UnderscoreBlinking"/></remarks>
  533. UnderlineFix = 0x04010119,
  534. /// <summary>
  535. /// Cursor caret is displayed a blinking vertical bar |
  536. /// </summary>
  537. /// <remarks>Works under Xterm-like terminal otherwise this is equivalent to <see ref="Underscore"/></remarks>
  538. Vertical = 0x05010119,
  539. /// <summary>
  540. /// Cursor caret is displayed a blinking vertical bar |
  541. /// </summary>
  542. /// <remarks>Works under Xterm-like terminal otherwise this is equivalent to <see ref="Underscore"/></remarks>
  543. VerticalFix = 0x06010119,
  544. /// <summary>
  545. /// Cursor caret is displayed as a blinking block ▉
  546. /// </summary>
  547. Box = 0x01020164,
  548. /// <summary>
  549. /// Cursor caret is displayed a block ▉
  550. /// </summary>
  551. /// <remarks>Works under Xterm-like terminal otherwise this is equivalent to <see ref="Block"/></remarks>
  552. BoxFix = 0x02020164
  553. }
  554. /// <summary>
  555. /// The <see cref="KeyCode"/> enumeration encodes key information from <see cref="ConsoleDriver"/>s and provides a consistent
  556. /// way for application code to specify keys and receive key events.
  557. /// <para>
  558. /// The <see cref="Key"/> class provides a higher-level abstraction, with helper methods and properties for common
  559. /// operations. For example, <see cref="Key.IsAlt"/> and <see cref="Key.IsCtrl"/> provide a convenient way
  560. /// to check whether the Alt or Ctrl modifier keys were pressed when a key was pressed.
  561. /// </para>
  562. /// </summary>
  563. /// <remarks>
  564. /// <para>
  565. /// Lowercase alpha keys are encoded as values between 65 and 90 corresponding to the un-shifted A to Z keys on a keyboard. Enum values
  566. /// are provided for these (e.g. <see cref="KeyCode.A"/>, <see cref="KeyCode.B"/>, etc.). Even though the values are the same as the ASCII
  567. /// values for uppercase characters, these enum values represent *lowercase*, un-shifted characters.
  568. /// </para>
  569. /// <para>
  570. /// Numeric keys are the values between 48 and 57 corresponding to 0 to 9 (e.g. <see cref="KeyCode.D0"/>, <see cref="KeyCode.D1"/>, etc.).
  571. /// </para>
  572. /// <para>
  573. /// The shift modifiers (<see cref="KeyCode.ShiftMask"/>, <see cref="KeyCode.CtrlMask"/>, and <see cref="KeyCode.AltMask"/>) can be combined (with logical or)
  574. /// with the other key codes to represent shifted keys. For example, the <see cref="KeyCode.A"/> enum value represents the un-shifted 'a' key, while
  575. /// <see cref="KeyCode.ShiftMask"/> | <see cref="KeyCode.A"/> represents the 'A' key (shifted 'a' key). Likewise, <see cref="KeyCode.AltMask"/> | <see cref="KeyCode.A"/>
  576. /// represents the 'Alt+A' key combination.
  577. /// </para>
  578. /// <para>
  579. /// All other keys that produce a printable character are encoded as the Unicode value of the character. For example, the <see cref="KeyCode"/>
  580. /// for the '!' character is 33, which is the Unicode value for '!'. Likewise, `â` is 226, `Â` is 194, etc.
  581. /// </para>
  582. /// <para>
  583. /// If the <see cref="SpecialMask"/> is set, then the value is that of the special mask,
  584. /// otherwise, the value is the one of the lower bits (as extracted by <see cref="CharMask"/>).
  585. /// </para>
  586. /// </remarks>
  587. [Flags]
  588. public enum KeyCode : uint {
  589. /// <summary>
  590. /// Mask that indicates that the key is a unicode codepoint. Values outside this range
  591. /// indicate the key has shift modifiers or is a special key like function keys, arrows keys and so on.
  592. /// </summary>
  593. CharMask = 0x_f_ffff,
  594. /// <summary>
  595. /// If the <see cref="SpecialMask"/> is set, then the value is that of the special mask,
  596. /// otherwise, the value is in the the lower bits (as extracted by <see cref="CharMask"/>).
  597. /// </summary>
  598. SpecialMask = 0x_fff0_0000,
  599. /// <summary>
  600. /// When this value is set, the Key encodes the sequence Shift-KeyValue.
  601. /// The actual value must be extracted by removing the ShiftMask.
  602. /// </summary>
  603. ShiftMask = 0x_1000_0000,
  604. /// <summary>
  605. /// When this value is set, the Key encodes the sequence Alt-KeyValue.
  606. /// The actual value must be extracted by removing the AltMask.
  607. /// </summary>
  608. AltMask = 0x_8000_0000,
  609. /// <summary>
  610. /// When this value is set, the Key encodes the sequence Ctrl-KeyValue.
  611. /// The actual value must be extracted by removing the CtrlMask.
  612. /// </summary>
  613. CtrlMask = 0x_4000_0000,
  614. /// <summary>
  615. /// The key code representing an invalid or empty key.
  616. /// </summary>
  617. Null = 0,
  618. /// <summary>
  619. /// Backspace key.
  620. /// </summary>
  621. Backspace = 8,
  622. /// <summary>
  623. /// The key code for the tab key (forwards tab key).
  624. /// </summary>
  625. Tab = 9,
  626. /// <summary>
  627. /// The key code for the return key.
  628. /// </summary>
  629. Enter = ConsoleKey.Enter,
  630. /// <summary>
  631. /// The key code for the clear key.
  632. /// </summary>
  633. Clear = 12,
  634. /// <summary>
  635. /// The key code for the escape key.
  636. /// </summary>
  637. Esc = 27,
  638. /// <summary>
  639. /// The key code for the space bar key.
  640. /// </summary>
  641. Space = 32,
  642. /// <summary>
  643. /// Digit 0.
  644. /// </summary>
  645. D0 = 48,
  646. /// <summary>
  647. /// Digit 1.
  648. /// </summary>
  649. D1,
  650. /// <summary>
  651. /// Digit 2.
  652. /// </summary>
  653. D2,
  654. /// <summary>
  655. /// Digit 3.
  656. /// </summary>
  657. D3,
  658. /// <summary>
  659. /// Digit 4.
  660. /// </summary>
  661. D4,
  662. /// <summary>
  663. /// Digit 5.
  664. /// </summary>
  665. D5,
  666. /// <summary>
  667. /// Digit 6.
  668. /// </summary>
  669. D6,
  670. /// <summary>
  671. /// Digit 7.
  672. /// </summary>
  673. D7,
  674. /// <summary>
  675. /// Digit 8.
  676. /// </summary>
  677. D8,
  678. /// <summary>
  679. /// Digit 9.
  680. /// </summary>
  681. D9,
  682. /// <summary>
  683. /// The key code for the A key
  684. /// </summary>
  685. A = 65,
  686. /// <summary>
  687. /// The key code for the B key
  688. /// </summary>
  689. B,
  690. /// <summary>
  691. /// The key code for the C key
  692. /// </summary>
  693. C,
  694. /// <summary>
  695. /// The key code for the D key
  696. /// </summary>
  697. D,
  698. /// <summary>
  699. /// The key code for the E key
  700. /// </summary>
  701. E,
  702. /// <summary>
  703. /// The key code for the F key
  704. /// </summary>
  705. F,
  706. /// <summary>
  707. /// The key code for the G key
  708. /// </summary>
  709. G,
  710. /// <summary>
  711. /// The key code for the H key
  712. /// </summary>
  713. H,
  714. /// <summary>
  715. /// The key code for the I key
  716. /// </summary>
  717. I,
  718. /// <summary>
  719. /// The key code for the J key
  720. /// </summary>
  721. J,
  722. /// <summary>
  723. /// The key code for the K key
  724. /// </summary>
  725. K,
  726. /// <summary>
  727. /// The key code for the L key
  728. /// </summary>
  729. L,
  730. /// <summary>
  731. /// The key code for the M key
  732. /// </summary>
  733. M,
  734. /// <summary>
  735. /// The key code for the N key
  736. /// </summary>
  737. N,
  738. /// <summary>
  739. /// The key code for the O key
  740. /// </summary>
  741. O,
  742. /// <summary>
  743. /// The key code for the P key
  744. /// </summary>
  745. P,
  746. /// <summary>
  747. /// The key code for the Q key
  748. /// </summary>
  749. Q,
  750. /// <summary>
  751. /// The key code for the R key
  752. /// </summary>
  753. R,
  754. /// <summary>
  755. /// The key code for the S key
  756. /// </summary>
  757. S,
  758. /// <summary>
  759. /// The key code for the T key
  760. /// </summary>
  761. T,
  762. /// <summary>
  763. /// The key code for the U key
  764. /// </summary>
  765. U,
  766. /// <summary>
  767. /// The key code for the V key
  768. /// </summary>
  769. V,
  770. /// <summary>
  771. /// The key code for the W key
  772. /// </summary>
  773. W,
  774. /// <summary>
  775. /// The key code for the X key
  776. /// </summary>
  777. X,
  778. /// <summary>
  779. /// The key code for the Y key
  780. /// </summary>
  781. Y,
  782. /// <summary>
  783. /// The key code for the Z key
  784. /// </summary>
  785. Z,
  786. ///// <summary>
  787. ///// The key code for the Delete key.
  788. ///// </summary>
  789. //Delete = 127,
  790. // --- Special keys ---
  791. // The values below are common non-alphanum keys. Their values are
  792. // based on the .NET ConsoleKey values, which, in-turn are based on the
  793. // VK_ values from the Windows API.
  794. // We add MaxCodePoint to avoid conflicts with the Unicode values.
  795. /// <summary>
  796. /// The maximum Unicode codepoint value. Used to encode the non-alphanumeric control
  797. /// keys.
  798. /// </summary>
  799. MaxCodePoint = 0x10FFFF,
  800. /// <summary>
  801. /// Cursor up key
  802. /// </summary>
  803. CursorUp = MaxCodePoint + ConsoleKey.UpArrow,
  804. /// <summary>
  805. /// Cursor down key.
  806. /// </summary>
  807. CursorDown = MaxCodePoint + ConsoleKey.DownArrow,
  808. /// <summary>
  809. /// Cursor left key.
  810. /// </summary>
  811. CursorLeft = MaxCodePoint + ConsoleKey.LeftArrow,
  812. /// <summary>
  813. /// Cursor right key.
  814. /// </summary>
  815. CursorRight = MaxCodePoint + ConsoleKey.RightArrow,
  816. /// <summary>
  817. /// Page Up key.
  818. /// </summary>
  819. PageUp = MaxCodePoint + ConsoleKey.PageUp,
  820. /// <summary>
  821. /// Page Down key.
  822. /// </summary>
  823. PageDown = MaxCodePoint + ConsoleKey.PageDown,
  824. /// <summary>
  825. /// Home key.
  826. /// </summary>
  827. Home = MaxCodePoint + ConsoleKey.Home,
  828. /// <summary>
  829. /// End key.
  830. /// </summary>
  831. End = MaxCodePoint + ConsoleKey.End,
  832. /// <summary>
  833. /// Insert (INS) key.
  834. /// </summary>
  835. Insert = MaxCodePoint + ConsoleKey.Insert,
  836. /// <summary>
  837. /// Delete (DEL) key.
  838. /// </summary>
  839. Delete = MaxCodePoint + ConsoleKey.Delete,
  840. /// <summary>
  841. /// Print screen character key.
  842. /// </summary>
  843. PrintScreen = MaxCodePoint + ConsoleKey.PrintScreen,
  844. /// <summary>
  845. /// F1 key.
  846. /// </summary>
  847. F1 = MaxCodePoint + ConsoleKey.F1,
  848. /// <summary>
  849. /// F2 key.
  850. /// </summary>
  851. F2 = MaxCodePoint + ConsoleKey.F2,
  852. /// <summary>
  853. /// F3 key.
  854. /// </summary>
  855. F3 = MaxCodePoint + ConsoleKey.F3,
  856. /// <summary>
  857. /// F4 key.
  858. /// </summary>
  859. F4 = MaxCodePoint + ConsoleKey.F4,
  860. /// <summary>
  861. /// F5 key.
  862. /// </summary>
  863. F5 = MaxCodePoint + ConsoleKey.F5,
  864. /// <summary>
  865. /// F6 key.
  866. /// </summary>
  867. F6 = MaxCodePoint + ConsoleKey.F6,
  868. /// <summary>
  869. /// F7 key.
  870. /// </summary>
  871. F7 = MaxCodePoint + ConsoleKey.F7,
  872. /// <summary>
  873. /// F8 key.
  874. /// </summary>
  875. F8 = MaxCodePoint + ConsoleKey.F8,
  876. /// <summary>
  877. /// F9 key.
  878. /// </summary>
  879. F9 = MaxCodePoint + ConsoleKey.F9,
  880. /// <summary>
  881. /// F10 key.
  882. /// </summary>
  883. F10 = MaxCodePoint + ConsoleKey.F10,
  884. /// <summary>
  885. /// F11 key.
  886. /// </summary>
  887. F11 = MaxCodePoint + ConsoleKey.F11,
  888. /// <summary>
  889. /// F12 key.
  890. /// </summary>
  891. F12 = MaxCodePoint + ConsoleKey.F12,
  892. /// <summary>
  893. /// F13 key.
  894. /// </summary>
  895. F13 = MaxCodePoint + ConsoleKey.F13,
  896. /// <summary>
  897. /// F14 key.
  898. /// </summary>
  899. F14 = MaxCodePoint + ConsoleKey.F14,
  900. /// <summary>
  901. /// F15 key.
  902. /// </summary>
  903. F15 = MaxCodePoint + ConsoleKey.F15,
  904. /// <summary>
  905. /// F16 key.
  906. /// </summary>
  907. F16 = MaxCodePoint + ConsoleKey.F16,
  908. /// <summary>
  909. /// F17 key.
  910. /// </summary>
  911. F17 = MaxCodePoint + ConsoleKey.F17,
  912. /// <summary>
  913. /// F18 key.
  914. /// </summary>
  915. F18 = MaxCodePoint + ConsoleKey.F18,
  916. /// <summary>
  917. /// F19 key.
  918. /// </summary>
  919. F19 = MaxCodePoint + ConsoleKey.F19,
  920. /// <summary>
  921. /// F20 key.
  922. /// </summary>
  923. F20 = MaxCodePoint + ConsoleKey.F20,
  924. /// <summary>
  925. /// F21 key.
  926. /// </summary>
  927. F21 = MaxCodePoint + ConsoleKey.F21,
  928. /// <summary>
  929. /// F22 key.
  930. /// </summary>
  931. F22 = MaxCodePoint + ConsoleKey.F22,
  932. /// <summary>
  933. /// F23 key.
  934. /// </summary>
  935. F23 = MaxCodePoint + ConsoleKey.F23,
  936. /// <summary>
  937. /// F24 key.
  938. /// </summary>
  939. F24 = MaxCodePoint + ConsoleKey.F24,
  940. }