ConsoleDriver.cs 30 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069
  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. /// TODO: Strongly consider renaming these from .A to .Z to .A_Lowercase to .Z_Lowercase (or .a to .z).
  573. /// </para>
  574. /// <para>
  575. /// 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.).
  576. /// </para>
  577. /// <para>
  578. /// The shift modifiers (<see cref="KeyCode.ShiftMask"/>, <see cref="KeyCode.CtrlMask"/>, and <see cref="KeyCode.AltMask"/>) can be combined (with logical or)
  579. /// 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
  580. /// <see cref="KeyCode.ShiftMask"/> | <see cref="KeyCode.A"/> represents the 'A' key (shifted 'a' key). Likewise, <see cref="KeyCode.AltMask"/> | <see cref="KeyCode.A"/>
  581. /// represents the 'Alt+A' key combination.
  582. /// </para>
  583. /// <para>
  584. /// All other keys that produce a printable character are encoded as the Unicode value of the character. For example, the <see cref="KeyCode"/>
  585. /// for the '!' character is 33, which is the Unicode value for '!'. Likewise, `â` is 226, `Â` is 194, etc.
  586. /// </para>
  587. /// <para>
  588. /// If the <see cref="SpecialMask"/> is set, then the value is that of the special mask,
  589. /// otherwise, the value is the one of the lower bits (as extracted by <see cref="CharMask"/>).
  590. /// </para>
  591. /// </remarks>
  592. [Flags]
  593. public enum KeyCode : uint {
  594. /// <summary>
  595. /// Mask that indicates that this is a character value, values outside this range
  596. /// indicate special characters like Alt-key combinations or special keys on the
  597. /// keyboard like function keys, arrows keys and so on.
  598. /// </summary>
  599. CharMask = 0xfffff,
  600. /// <summary>
  601. /// If the <see cref="SpecialMask"/> is set, then the value is that of the special mask,
  602. /// otherwise, the value is the one of the lower bits (as extracted by <see cref="CharMask"/>).
  603. /// </summary>
  604. SpecialMask = 0xfff00000,
  605. /// <summary>
  606. /// The key code representing null or empty
  607. /// </summary>
  608. Null = '\0',
  609. /// <summary>
  610. /// Backspace key.
  611. /// </summary>
  612. Backspace = 8,
  613. /// <summary>
  614. /// The key code for the tab key (forwards tab key).
  615. /// </summary>
  616. Tab = 9,
  617. /// <summary>
  618. /// The key code for the return key.
  619. /// </summary>
  620. Enter = '\n',
  621. /// <summary>
  622. /// The key code for the clear key.
  623. /// </summary>
  624. Clear = 12,
  625. /// <summary>
  626. /// The key code for the Shift key.
  627. /// </summary>
  628. ShiftKey = 16,
  629. /// <summary>
  630. /// The key code for the Ctrl key.
  631. /// </summary>
  632. CtrlKey = 17,
  633. /// <summary>
  634. /// The key code for the Alt key.
  635. /// </summary>
  636. AltKey = 18,
  637. /// <summary>
  638. /// The key code for the CapsLock key.
  639. /// </summary>
  640. CapsLock = 20,
  641. ///// <summary>
  642. ///// The key code for the NumLock key.
  643. ///// </summary>
  644. //NumLock = 144,
  645. ///// <summary>
  646. ///// The key code for the ScrollLock key.
  647. ///// </summary>
  648. //ScrollLock = 145,
  649. /// <summary>
  650. /// The key code for the escape key.
  651. /// </summary>
  652. Esc = 27,
  653. /// <summary>
  654. /// The key code for the space bar key.
  655. /// </summary>
  656. Space = 32,
  657. /// <summary>
  658. /// Digit 0.
  659. /// </summary>
  660. D0 = 48,
  661. /// <summary>
  662. /// Digit 1.
  663. /// </summary>
  664. D1,
  665. /// <summary>
  666. /// Digit 2.
  667. /// </summary>
  668. D2,
  669. /// <summary>
  670. /// Digit 3.
  671. /// </summary>
  672. D3,
  673. /// <summary>
  674. /// Digit 4.
  675. /// </summary>
  676. D4,
  677. /// <summary>
  678. /// Digit 5.
  679. /// </summary>
  680. D5,
  681. /// <summary>
  682. /// Digit 6.
  683. /// </summary>
  684. D6,
  685. /// <summary>
  686. /// Digit 7.
  687. /// </summary>
  688. D7,
  689. /// <summary>
  690. /// Digit 8.
  691. /// </summary>
  692. D8,
  693. /// <summary>
  694. /// Digit 9.
  695. /// </summary>
  696. D9,
  697. /// <summary>
  698. /// The key code for the user pressing Shift-A
  699. /// </summary>
  700. A = 65,
  701. /// <summary>
  702. /// The key code for the user pressing Shift-B
  703. /// </summary>
  704. B,
  705. /// <summary>
  706. /// The key code for the user pressing Shift-C
  707. /// </summary>
  708. C,
  709. /// <summary>
  710. /// The key code for the user pressing Shift-D
  711. /// </summary>
  712. D,
  713. /// <summary>
  714. /// The key code for the user pressing Shift-E
  715. /// </summary>
  716. E,
  717. /// <summary>
  718. /// The key code for the user pressing Shift-F
  719. /// </summary>
  720. F,
  721. /// <summary>
  722. /// The key code for the user pressing Shift-G
  723. /// </summary>
  724. G,
  725. /// <summary>
  726. /// The key code for the user pressing Shift-H
  727. /// </summary>
  728. H,
  729. /// <summary>
  730. /// The key code for the user pressing Shift-I
  731. /// </summary>
  732. I,
  733. /// <summary>
  734. /// The key code for the user pressing Shift-J
  735. /// </summary>
  736. J,
  737. /// <summary>
  738. /// The key code for the user pressing Shift-K
  739. /// </summary>
  740. K,
  741. /// <summary>
  742. /// The key code for the user pressing Shift-L
  743. /// </summary>
  744. L,
  745. /// <summary>
  746. /// The key code for the user pressing Shift-M
  747. /// </summary>
  748. M,
  749. /// <summary>
  750. /// The key code for the user pressing Shift-N
  751. /// </summary>
  752. N,
  753. /// <summary>
  754. /// The key code for the user pressing Shift-O
  755. /// </summary>
  756. O,
  757. /// <summary>
  758. /// The key code for the user pressing Shift-P
  759. /// </summary>
  760. P,
  761. /// <summary>
  762. /// The key code for the user pressing Shift-Q
  763. /// </summary>
  764. Q,
  765. /// <summary>
  766. /// The key code for the user pressing Shift-R
  767. /// </summary>
  768. R,
  769. /// <summary>
  770. /// The key code for the user pressing Shift-S
  771. /// </summary>
  772. S,
  773. /// <summary>
  774. /// The key code for the user pressing Shift-T
  775. /// </summary>
  776. T,
  777. /// <summary>
  778. /// The key code for the user pressing Shift-U
  779. /// </summary>
  780. U,
  781. /// <summary>
  782. /// The key code for the user pressing Shift-V
  783. /// </summary>
  784. V,
  785. /// <summary>
  786. /// The key code for the user pressing Shift-W
  787. /// </summary>
  788. W,
  789. /// <summary>
  790. /// The key code for the user pressing Shift-X
  791. /// </summary>
  792. X,
  793. /// <summary>
  794. /// The key code for the user pressing Shift-Y
  795. /// </summary>
  796. Y,
  797. /// <summary>
  798. /// The key code for the user pressing Shift-Z
  799. /// </summary>
  800. Z,
  801. /// <summary>
  802. /// The key code for the user pressing A
  803. /// </summary>
  804. Delete = 127,
  805. /// <summary>
  806. /// When this value is set, the Key encodes the sequence Shift-KeyValue.
  807. /// </summary>
  808. ShiftMask = 0x10000000,
  809. /// <summary>
  810. /// When this value is set, the Key encodes the sequence Alt-KeyValue.
  811. /// And the actual value must be extracted by removing the AltMask.
  812. /// </summary>
  813. AltMask = 0x80000000,
  814. /// <summary>
  815. /// When this value is set, the Key encodes the sequence Ctrl-KeyValue.
  816. /// And the actual value must be extracted by removing the CtrlMask.
  817. /// </summary>
  818. CtrlMask = 0x40000000,
  819. /// <summary>
  820. /// Cursor up key
  821. /// </summary>
  822. CursorUp = 0x100000,
  823. /// <summary>
  824. /// Cursor down key.
  825. /// </summary>
  826. CursorDown,
  827. /// <summary>
  828. /// Cursor left key.
  829. /// </summary>
  830. CursorLeft,
  831. /// <summary>
  832. /// Cursor right key.
  833. /// </summary>
  834. CursorRight,
  835. /// <summary>
  836. /// Page Up key.
  837. /// </summary>
  838. PageUp,
  839. /// <summary>
  840. /// Page Down key.
  841. /// </summary>
  842. PageDown,
  843. /// <summary>
  844. /// Home key.
  845. /// </summary>
  846. Home,
  847. /// <summary>
  848. /// End key.
  849. /// </summary>
  850. End,
  851. /// <summary>
  852. /// Insert character key.
  853. /// </summary>
  854. InsertChar,
  855. /// <summary>
  856. /// Delete character key.
  857. /// </summary>
  858. DeleteChar,
  859. /// <summary>
  860. /// Print screen character key.
  861. /// </summary>
  862. PrintScreen,
  863. /// <summary>
  864. /// F1 key.
  865. /// </summary>
  866. F1,
  867. /// <summary>
  868. /// F2 key.
  869. /// </summary>
  870. F2,
  871. /// <summary>
  872. /// F3 key.
  873. /// </summary>
  874. F3,
  875. /// <summary>
  876. /// F4 key.
  877. /// </summary>
  878. F4,
  879. /// <summary>
  880. /// F5 key.
  881. /// </summary>
  882. F5,
  883. /// <summary>
  884. /// F6 key.
  885. /// </summary>
  886. F6,
  887. /// <summary>
  888. /// F7 key.
  889. /// </summary>
  890. F7,
  891. /// <summary>
  892. /// F8 key.
  893. /// </summary>
  894. F8,
  895. /// <summary>
  896. /// F9 key.
  897. /// </summary>
  898. F9,
  899. /// <summary>
  900. /// F10 key.
  901. /// </summary>
  902. F10,
  903. /// <summary>
  904. /// F11 key.
  905. /// </summary>
  906. F11,
  907. /// <summary>
  908. /// F12 key.
  909. /// </summary>
  910. F12,
  911. /// <summary>
  912. /// F13 key.
  913. /// </summary>
  914. F13,
  915. /// <summary>
  916. /// F14 key.
  917. /// </summary>
  918. F14,
  919. /// <summary>
  920. /// F15 key.
  921. /// </summary>
  922. F15,
  923. /// <summary>
  924. /// F16 key.
  925. /// </summary>
  926. F16,
  927. /// <summary>
  928. /// F17 key.
  929. /// </summary>
  930. F17,
  931. /// <summary>
  932. /// F18 key.
  933. /// </summary>
  934. F18,
  935. /// <summary>
  936. /// F19 key.
  937. /// </summary>
  938. F19,
  939. /// <summary>
  940. /// F20 key.
  941. /// </summary>
  942. F20,
  943. /// <summary>
  944. /// F21 key.
  945. /// </summary>
  946. F21,
  947. /// <summary>
  948. /// F22 key.
  949. /// </summary>
  950. F22,
  951. /// <summary>
  952. /// F23 key.
  953. /// </summary>
  954. F23,
  955. /// <summary>
  956. /// F24 key.
  957. /// </summary>
  958. F24,
  959. /// <summary>
  960. /// A key with an unknown mapping was raised.
  961. /// </summary>
  962. Unknown
  963. }