ConsoleDriver.cs 30 KB

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