12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121 |
- //
- // ConsoleDriver.cs: Base class for Terminal.Gui ConsoleDriver implementations.
- //
- using System.Text;
- using System;
- using System.Diagnostics;
- using System.Linq;
- using Terminal.Gui.ConsoleDrivers;
- namespace Terminal.Gui;
- /// <summary>
- /// Base class for Terminal.Gui ConsoleDriver implementations.
- /// </summary>
- /// <remarks>
- /// There are currently four implementations:
- /// - <see cref="CursesDriver"/> (for Unix and Mac)
- /// - <see cref="WindowsDriver"/>
- /// - <see cref="NetDriver"/> that uses the .NET Console API
- /// - <see cref="FakeConsole"/> for unit testing.
- /// </remarks>
- public abstract class ConsoleDriver {
- /// <summary>
- /// Set this to true in any unit tests that attempt to test drivers other than FakeDriver.
- /// <code>
- /// public ColorTests ()
- /// {
- /// ConsoleDriver.RunningUnitTests = true;
- /// }
- /// </code>
- /// </summary>
- internal static bool RunningUnitTests { get; set; }
- #region Setup & Teardown
- /// <summary>
- /// Initializes the driver
- /// </summary>
- /// <returns>Returns an instance of <see cref="MainLoop"/> using the <see cref="IMainLoopDriver"/> for the driver.</returns>
- internal abstract MainLoop Init ();
- /// <summary>
- /// Ends the execution of the console driver.
- /// </summary>
- internal abstract void End ();
- #endregion
- /// <summary>
- /// The event fired when the terminal is resized.
- /// </summary>
- public event EventHandler<SizeChangedEventArgs> SizeChanged;
- /// <summary>
- /// Called when the terminal size changes. Fires the <see cref="SizeChanged"/> event.
- /// </summary>
- /// <param name="args"></param>
- public void OnSizeChanged (SizeChangedEventArgs args) => SizeChanged?.Invoke (this, args);
- /// <summary>
- /// The number of columns visible in the terminal.
- /// </summary>
- public virtual int Cols {
- get => _cols;
- internal set {
- _cols = value;
- ClearContents();
- }
- }
- /// <summary>
- /// The number of rows visible in the terminal.
- /// </summary>
- public virtual int Rows {
- get => _rows;
- internal set {
- _rows = value;
- ClearContents();
- }
- }
- /// <summary>
- /// The leftmost column in the terminal.
- /// </summary>
- public virtual int Left { get; internal set; } = 0;
- /// <summary>
- /// The topmost row in the terminal.
- /// </summary>
- public virtual int Top { get; internal set; } = 0;
- /// <summary>
- /// Get the operating system clipboard.
- /// </summary>
- public IClipboard Clipboard { get; internal set; }
- /// <summary>
- /// The contents of the application output. The driver outputs this buffer to the terminal when <see cref="UpdateScreen"/>
- /// is called.
- /// <remarks>
- /// The format of the array is rows, columns. The first index is the row, the second index is the column.
- /// </remarks>
- /// </summary>
- public Cell [,] Contents { get; internal set; }
- /// <summary>
- /// Gets the column last set by <see cref="Move"/>. <see cref="Col"/> and <see cref="Row"/>
- /// are used by <see cref="AddRune(Rune)"/> and <see cref="AddStr"/> to determine where to add content.
- /// </summary>
- public int Col { get; internal set; }
- /// <summary>
- /// Gets the row last set by <see cref="Move"/>. <see cref="Col"/> and <see cref="Row"/>
- /// are used by <see cref="AddRune(Rune)"/> and <see cref="AddStr"/> to determine where to add content.
- /// </summary>
- public int Row { get; internal set; }
- /// <summary>
- /// Updates <see cref="Col"/> and <see cref="Row"/> to the specified column and row in <see cref="Contents"/>.
- /// Used by <see cref="AddRune(Rune)"/> and <see cref="AddStr"/> to determine where to add content.
- /// </summary>
- /// <remarks>
- /// <para>
- /// This does not move the cursor on the screen, it only updates the internal state of the driver.
- /// </para>
- /// <para>
- /// If <paramref name="col"/> or <paramref name="row"/> are negative or beyond <see cref="Cols"/> and <see cref="Rows"/>,
- /// the method still sets those properties.
- /// </para>
- /// </remarks>
- /// <param name="col">Column to move to.</param>
- /// <param name="row">Row to move to.</param>
- public virtual void Move (int col, int row)
- {
- Col = col;
- Row = row;
- }
- /// <summary>
- /// Tests if the specified rune is supported by the driver.
- /// </summary>
- /// <param name="rune"></param>
- /// <returns><see langword="true"/> if the rune can be properly presented; <see langword="false"/> if the driver
- /// does not support displaying this rune.</returns>
- public virtual bool IsRuneSupported (Rune rune) => Rune.IsValid (rune.Value);
- /// <summary>
- /// Adds the specified rune to the display at the current cursor position.
- /// </summary>
- /// <remarks>
- /// <para>
- /// When the method returns, <see cref="Col"/> will be incremented by the number of columns <paramref name="rune"/> required,
- /// even if the new column value is outside of the <see cref="Clip"/> or screen dimensions defined by <see cref="Cols"/>.
- /// </para>
- /// <para>
- /// If <paramref name="rune"/> requires more than one column, and <see cref="Col"/> plus the number of columns needed
- /// exceeds the <see cref="Clip"/> or screen dimensions, the default Unicode replacement character (U+FFFD) will be added instead.
- /// </para>
- /// </remarks>
- /// <param name="rune">Rune to add.</param>
- public void AddRune (Rune rune)
- {
- int runeWidth = -1;
- bool validLocation = IsValidLocation (Col, Row);
- if (validLocation) {
- rune = rune.MakePrintable ();
- runeWidth = rune.GetColumns ();
- if (runeWidth == 0 && rune.IsCombiningMark ()) {
- // AtlasEngine does not support NON-NORMALIZED combining marks in a way
- // compatible with the driver architecture. Any CMs (except in the first col)
- // are correctly combined with the base char, but are ALSO treated as 1 column
- // width codepoints E.g. `echo "[e`u{0301}`u{0301}]"` will output `[é ]`.
- //
- // Until this is addressed (see Issue #), we do our best by
- // a) Attempting to normalize any CM with the base char to it's left
- // b) Ignoring any CMs that don't normalize
- if (Col > 0) {
- if (Contents [Row, Col - 1].CombiningMarks.Count > 0) {
- // Just add this mark to the list
- Contents [Row, Col - 1].CombiningMarks.Add (rune);
- // Ignore. Don't move to next column (let the driver figure out what to do).
- } else {
- // Attempt to normalize the cell to our left combined with this mark
- string combined = Contents [Row, Col - 1].Rune + rune.ToString ();
- // Normalize to Form C (Canonical Composition)
- string normalized = combined.Normalize (NormalizationForm.FormC);
- if (normalized.Length == 1) {
- // It normalized! We can just set the Cell to the left with the
- // normalized codepoint
- Contents [Row, Col - 1].Rune = (Rune)normalized [0];
- // Ignore. Don't move to next column because we're already there
- } else {
- // It didn't normalize. Add it to the Cell to left's CM list
- Contents [Row, Col - 1].CombiningMarks.Add (rune);
- // Ignore. Don't move to next column (let the driver figure out what to do).
- }
- }
- Contents [Row, Col - 1].Attribute = CurrentAttribute;
- Contents [Row, Col - 1].IsDirty = true;
- } else {
- // Most drivers will render a combining mark at col 0 as the mark
- Contents [Row, Col].Rune = rune;
- Contents [Row, Col].Attribute = CurrentAttribute;
- Contents [Row, Col].IsDirty = true;
- Col++;
- }
- } else {
- Contents [Row, Col].Attribute = CurrentAttribute;
- Contents [Row, Col].IsDirty = true;
- if (Col > 0) {
- // Check if cell to left has a wide glyph
- if (Contents [Row, Col - 1].Rune.GetColumns () > 1) {
- // Invalidate cell to left
- Contents [Row, Col - 1].Rune = Rune.ReplacementChar;
- Contents [Row, Col - 1].IsDirty = true;
- }
- }
- if (runeWidth < 1) {
- Contents [Row, Col].Rune = Rune.ReplacementChar;
- } else if (runeWidth == 1) {
- Contents [Row, Col].Rune = rune;
- if (Col < Clip.Right - 1) {
- Contents [Row, Col + 1].IsDirty = true;
- }
- } else if (runeWidth == 2) {
- if (Col == Clip.Right - 1) {
- // We're at the right edge of the clip, so we can't display a wide character.
- // TODO: Figure out if it is better to show a replacement character or ' '
- Contents [Row, Col].Rune = Rune.ReplacementChar;
- } else {
- Contents [Row, Col].Rune = rune;
- if (Col < Clip.Right - 1) {
- // Invalidate cell to right so that it doesn't get drawn
- // TODO: Figure out if it is better to show a replacement character or ' '
- Contents [Row, Col + 1].Rune = Rune.ReplacementChar;
- Contents [Row, Col + 1].IsDirty = true;
- }
- }
- } else {
- // This is a non-spacing character, so we don't need to do anything
- Contents [Row, Col].Rune = (Rune)' ';
- Contents [Row, Col].IsDirty = false;
- }
- _dirtyLines [Row] = true;
- }
- }
- if (runeWidth is < 0 or > 0) {
- Col++;
- }
- if (runeWidth > 1) {
- Debug.Assert (runeWidth <= 2);
- if (validLocation && Col < Clip.Right) {
- // This is a double-width character, and we are not at the end of the line.
- // Col now points to the second column of the character. Ensure it doesn't
- // Get rendered.
- Contents [Row, Col].IsDirty = false;
- Contents [Row, Col].Attribute = CurrentAttribute;
- // TODO: Determine if we should wipe this out (for now now)
- //Contents [Row, Col].Rune = (Rune)' ';
- }
- Col++;
- }
- }
- /// <summary>
- /// Adds the specified <see langword="char"/> to the display at the current cursor position. This method
- /// is a convenience method that calls <see cref="AddRune(Rune)"/> with the <see cref="Rune"/> constructor.
- /// </summary>
- /// <param name="c">Character to add.</param>
- public void AddRune (char c) => AddRune (new Rune (c));
- /// <summary>
- /// Adds the <paramref name="str"/> to the display at the cursor position.
- /// </summary>
- /// <remarks>
- /// <para>
- /// When the method returns, <see cref="Col"/> will be incremented by the number of columns <paramref name="str"/> required,
- /// unless the new column value is outside of the <see cref="Clip"/> or screen dimensions defined by <see cref="Cols"/>.
- /// </para>
- /// <para>
- /// If <paramref name="str"/> requires more columns than are available, the output will be clipped.
- /// </para>
- /// </remarks>
- /// <param name="str">String.</param>
- public void AddStr (string str)
- {
- var runes = str.EnumerateRunes ().ToList ();
- for (int i = 0; i < runes.Count; i++) {
- //if (runes [i].IsCombiningMark()) {
- // // Attempt to normalize
- // string combined = runes [i-1] + runes [i].ToString();
- // // Normalize to Form C (Canonical Composition)
- // string normalized = combined.Normalize (NormalizationForm.FormC);
- // runes [i-]
- //}
- AddRune (runes [i]);
- }
- }
- Rect _clip;
- /// <summary>
- /// Tests whether the specified coordinate are valid for drawing.
- /// </summary>
- /// <param name="col">The column.</param>
- /// <param name="row">The row.</param>
- /// <returns><see langword="false"/> if the coordinate is outside of the
- /// screen bounds or outside of <see cref="Clip"/>. <see langword="true"/> otherwise.</returns>
- public bool IsValidLocation (int col, int row) =>
- col >= 0 && row >= 0 &&
- col < Cols && row < Rows &&
- Clip.Contains (col, row);
- /// <summary>
- /// Gets or sets the clip rectangle that <see cref="AddRune(Rune)"/> and <see cref="AddStr(string)"/> are
- /// subject to.
- /// </summary>
- /// <value>The rectangle describing the bounds of <see cref="Clip"/>.</value>
- public Rect Clip {
- get => _clip;
- set => _clip = value;
- }
- /// <summary>
- /// Updates the screen to reflect all the changes that have been done to the display buffer
- /// </summary>
- public abstract void Refresh ();
- /// <summary>
- /// Sets the position of the terminal cursor to <see cref="Col"/> and <see cref="Row"/>.
- /// </summary>
- public abstract void UpdateCursor ();
- /// <summary>
- /// Gets the terminal cursor visibility.
- /// </summary>
- /// <param name="visibility">The current <see cref="CursorVisibility"/></param>
- /// <returns><see langword="true"/> upon success</returns>
- public abstract bool GetCursorVisibility (out CursorVisibility visibility);
- /// <summary>
- /// Sets the terminal cursor visibility.
- /// </summary>
- /// <param name="visibility">The wished <see cref="CursorVisibility"/></param>
- /// <returns><see langword="true"/> upon success</returns>
- public abstract bool SetCursorVisibility (CursorVisibility visibility);
- /// <summary>
- /// Determines if the terminal cursor should be visible or not and sets it accordingly.
- /// </summary>
- /// <returns><see langword="true"/> upon success</returns>
- public abstract bool EnsureCursorVisibility ();
- // As performance is a concern, we keep track of the dirty lines and only refresh those.
- // This is in addition to the dirty flag on each cell.
- internal bool [] _dirtyLines;
- /// <summary>
- /// Clears the <see cref="Contents"/> of the driver.
- /// </summary>
- public void ClearContents ()
- {
- // TODO: This method is really "Clear Contents" now and should not be abstract (or virtual)
- Contents = new Cell [Rows, Cols];
- Clip = new Rect (0, 0, Cols, Rows);
- _dirtyLines = new bool [Rows];
- lock (Contents) {
- // Can raise an exception while is still resizing.
- try {
- for (int row = 0; row < Rows; row++) {
- for (int c = 0; c < Cols; c++) {
- Contents [row, c] = new Cell () {
- Rune = (Rune)' ',
- Attribute = new Attribute (Color.White, Color.Black),
- IsDirty = true
- };
- _dirtyLines [row] = true;
- }
- }
- } catch (IndexOutOfRangeException) { }
- }
- }
- /// <summary>
- /// Redraws the physical screen with the contents that have been queued up via any of the printing commands.
- /// </summary>
- public abstract void UpdateScreen ();
- #region Color Handling
- /// <summary>
- /// Gets whether the <see cref="ConsoleDriver"/> supports TrueColor output.
- /// </summary>
- public virtual bool SupportsTrueColor => true;
- /// <summary>
- /// Gets or sets whether the <see cref="ConsoleDriver"/> should use 16 colors instead of the default TrueColors. See <see cref="Application.Force16Colors"/>
- /// to change this setting via <see cref="ConfigurationManager"/>.
- /// </summary>
- /// <remarks>
- /// <para>
- /// Will be forced to <see langword="true"/> if <see cref="ConsoleDriver.SupportsTrueColor"/> is <see langword="false"/>, indicating
- /// that the <see cref="ConsoleDriver"/> cannot support TrueColor.
- /// </para>
- /// </remarks>
- internal virtual bool Force16Colors {
- get => Application.Force16Colors || !SupportsTrueColor;
- set => Application.Force16Colors = value || !SupportsTrueColor;
- }
- Attribute _currentAttribute;
- int _cols;
- int _rows;
- /// <summary>
- /// The <see cref="Attribute"/> that will be used for the next <see cref="AddRune(Rune)"/> or <see cref="AddStr"/> call.
- /// </summary>
- public Attribute CurrentAttribute {
- get => _currentAttribute;
- set {
- if (Application.Driver != null) {
- _currentAttribute = new Attribute (value.Foreground, value.Background);
- return;
- }
- _currentAttribute = value;
- }
- }
- /// <summary>
- /// Selects the specified attribute as the attribute to use for future calls to AddRune and AddString.
- /// </summary>
- /// <remarks>
- /// Implementations should call <c>base.SetAttribute(c)</c>.
- /// </remarks>
- /// <param name="c">C.</param>
- public Attribute SetAttribute (Attribute c)
- {
- var prevAttribute = CurrentAttribute;
- CurrentAttribute = c;
- return prevAttribute;
- }
- /// <summary>
- /// Gets the current <see cref="Attribute"/>.
- /// </summary>
- /// <returns>The current attribute.</returns>
- public Attribute GetAttribute () => CurrentAttribute;
- // TODO: This is only overridden by CursesDriver. Once CursesDriver supports 24-bit color, this virtual method can be
- // removed (and Attribute can lose the platformColor property).
- /// <summary>
- /// Makes an <see cref="Attribute"/>.
- /// </summary>
- /// <param name="foreground">The foreground color.</param>
- /// <param name="background">The background color.</param>
- /// <returns>The attribute for the foreground and background colors.</returns>
- public virtual Attribute MakeColor (Color foreground, Color background) =>
- // Encode the colors into the int value.
- new (
- 0, // only used by cursesdriver!
- foreground,
- background
- );
- #endregion
- #region Mouse and Keyboard
- /// <summary>
- /// Event fired when a key is pressed down. This is a precursor to <see cref="KeyUp"/>.
- /// </summary>
- public event EventHandler<Key> KeyDown;
- /// <summary>
- /// Called when a key is pressed down. Fires the <see cref="KeyDown"/> event. This is a precursor to <see cref="OnKeyUp"/>.
- /// </summary>
- /// <param name="a"></param>
- public void OnKeyDown (Key a) => KeyDown?.Invoke (this, a);
- /// <summary>
- /// Event fired when a key is released.
- /// </summary>
- /// <remarks>
- /// Drivers that do not support key release events will fire this event after <see cref="KeyDown"/> processing is complete.
- /// </remarks>
- public event EventHandler<Key> KeyUp;
- /// <summary>
- /// Called when a key is released. Fires the <see cref="KeyUp"/> event.
- /// </summary>
- /// <remarks>
- /// Drivers that do not support key release events will calls this method after <see cref="OnKeyDown"/> processing is complete.
- /// </remarks>
- /// <param name="a"></param>
- public void OnKeyUp (Key a) => KeyUp?.Invoke (this, a);
- /// <summary>
- /// Event fired when a mouse event occurs.
- /// </summary>
- public event EventHandler<MouseEventEventArgs> MouseEvent;
- /// <summary>
- /// Called when a mouse event occurs. Fires the <see cref="MouseEvent"/> event.
- /// </summary>
- /// <param name="a"></param>
- public void OnMouseEvent (MouseEventEventArgs a) => MouseEvent?.Invoke (this, a);
- /// <summary>
- /// Simulates a key press.
- /// </summary>
- /// <param name="keyChar">The key character.</param>
- /// <param name="key">The key.</param>
- /// <param name="shift">If <see langword="true"/> simulates the Shift key being pressed.</param>
- /// <param name="alt">If <see langword="true"/> simulates the Alt key being pressed.</param>
- /// <param name="ctrl">If <see langword="true"/> simulates the Ctrl key being pressed.</param>
- public abstract void SendKeys (char keyChar, ConsoleKey key, bool shift, bool alt, bool ctrl);
- #endregion
- /// <summary>
- /// Enables diagnostic functions
- /// </summary>
- [Flags]
- public enum DiagnosticFlags : uint {
- /// <summary>
- /// All diagnostics off
- /// </summary>
- Off = 0b_0000_0000,
- /// <summary>
- /// When enabled, <see cref="Frame.OnDrawFrames"/> will draw a
- /// ruler in the frame for any side with a padding value greater than 0.
- /// </summary>
- FrameRuler = 0b_0000_0001,
- /// <summary>
- /// When enabled, <see cref="Frame.OnDrawFrames"/> will draw a
- /// 'L', 'R', 'T', and 'B' when clearing <see cref="Thickness"/>'s instead of ' '.
- /// </summary>
- FramePadding = 0b_0000_0010
- }
- /// <summary>
- /// Set flags to enable/disable <see cref="ConsoleDriver"/> diagnostics.
- /// </summary>
- public static DiagnosticFlags Diagnostics { get; set; }
- /// <summary>
- /// Suspends the application (e.g. on Linux via SIGTSTP) and upon resume, resets the console driver.
- /// </summary>
- /// <remarks>This is only implemented in <see cref="CursesDriver"/>.</remarks>
- public abstract void Suspend ();
- // TODO: Move FillRect to ./Drawing
- /// <summary>
- /// Fills the specified rectangle with the specified rune.
- /// </summary>
- /// <param name="rect"></param>
- /// <param name="rune"></param>
- public void FillRect (Rect rect, Rune rune = default)
- {
- for (int r = rect.Y; r < rect.Y + rect.Height; r++) {
- for (int c = rect.X; c < rect.X + rect.Width; c++) {
- Application.Driver.Move (c, r);
- Application.Driver.AddRune (rune == default ? new Rune (' ') : rune);
- }
- }
- }
- /// <summary>
- /// Fills the specified rectangle with the specified <see langword="char"/>. This method
- /// is a convenience method that calls <see cref="FillRect(Rect, Rune)"/>.
- /// </summary>
- /// <param name="rect"></param>
- /// <param name="c"></param>
- public void FillRect (Rect rect, char c) => FillRect (rect, new Rune (c));
- /// <summary>
- /// Returns the name of the driver and relevant library version information.
- /// </summary>
- /// <returns></returns>
- public virtual string GetVersionInfo () => GetType ().Name;
- }
- /// <summary>
- /// Terminal Cursor Visibility settings.
- /// </summary>
- /// <remarks>
- /// Hex value are set as 0xAABBCCDD where :
- ///
- /// AA stand for the TERMINFO DECSUSR parameter value to be used under Linux and MacOS
- /// BB stand for the NCurses curs_set parameter value to be used under Linux and MacOS
- /// CC stand for the CONSOLE_CURSOR_INFO.bVisible parameter value to be used under Windows
- /// DD stand for the CONSOLE_CURSOR_INFO.dwSize parameter value to be used under Windows
- ///</remarks>
- public enum CursorVisibility {
- /// <summary>
- /// Cursor caret has default
- /// </summary>
- /// <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>
- Default = 0x00010119,
- /// <summary>
- /// Cursor caret is hidden
- /// </summary>
- Invisible = 0x03000019,
- /// <summary>
- /// Cursor caret is normally shown as a blinking underline bar _
- /// </summary>
- Underline = 0x03010119,
- /// <summary>
- /// Cursor caret is normally shown as a underline bar _
- /// </summary>
- /// <remarks>Under Windows, this is equivalent to <see ref="UnderscoreBlinking"/></remarks>
- UnderlineFix = 0x04010119,
- /// <summary>
- /// Cursor caret is displayed a blinking vertical bar |
- /// </summary>
- /// <remarks>Works under Xterm-like terminal otherwise this is equivalent to <see ref="Underscore"/></remarks>
- Vertical = 0x05010119,
- /// <summary>
- /// Cursor caret is displayed a blinking vertical bar |
- /// </summary>
- /// <remarks>Works under Xterm-like terminal otherwise this is equivalent to <see ref="Underscore"/></remarks>
- VerticalFix = 0x06010119,
- /// <summary>
- /// Cursor caret is displayed as a blinking block ▉
- /// </summary>
- Box = 0x01020164,
- /// <summary>
- /// Cursor caret is displayed a block ▉
- /// </summary>
- /// <remarks>Works under Xterm-like terminal otherwise this is equivalent to <see ref="Block"/></remarks>
- BoxFix = 0x02020164
- }
- /// <summary>
- /// The <see cref="KeyCode"/> enumeration encodes key information from <see cref="ConsoleDriver"/>s and provides a consistent
- /// way for application code to specify keys and receive key events.
- /// <para>
- /// The <see cref="Key"/> class provides a higher-level abstraction, with helper methods and properties for common
- /// operations. For example, <see cref="Key.IsAlt"/> and <see cref="Key.IsCtrl"/> provide a convenient way
- /// to check whether the Alt or Ctrl modifier keys were pressed when a key was pressed.
- /// </para>
- /// </summary>
- /// <remarks>
- /// <para>
- /// 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
- /// 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
- /// values for uppercase characters, these enum values represent *lowercase*, un-shifted characters.
- /// </para>
- /// <para>
- /// 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.).
- /// </para>
- /// <para>
- /// The shift modifiers (<see cref="KeyCode.ShiftMask"/>, <see cref="KeyCode.CtrlMask"/>, and <see cref="KeyCode.AltMask"/>) can be combined (with logical or)
- /// 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
- /// <see cref="KeyCode.ShiftMask"/> | <see cref="KeyCode.A"/> represents the 'A' key (shifted 'a' key). Likewise, <see cref="KeyCode.AltMask"/> | <see cref="KeyCode.A"/>
- /// represents the 'Alt+A' key combination.
- /// </para>
- /// <para>
- /// All other keys that produce a printable character are encoded as the Unicode value of the character. For example, the <see cref="KeyCode"/>
- /// for the '!' character is 33, which is the Unicode value for '!'. Likewise, `â` is 226, `Â` is 194, etc.
- /// </para>
- /// <para>
- /// If the <see cref="SpecialMask"/> is set, then the value is that of the special mask,
- /// otherwise, the value is the one of the lower bits (as extracted by <see cref="CharMask"/>).
- /// </para>
- /// </remarks>
- [Flags]
- public enum KeyCode : uint {
- /// <summary>
- /// Mask that indicates that the key is a unicode codepoint. Values outside this range
- /// indicate the key has shift modifiers or is a special key like function keys, arrows keys and so on.
- /// </summary>
- CharMask = 0x_f_ffff,
- /// <summary>
- /// If the <see cref="SpecialMask"/> is set, then the value is that of the special mask,
- /// otherwise, the value is in the the lower bits (as extracted by <see cref="CharMask"/>).
- /// </summary>
- SpecialMask = 0x_fff0_0000,
- /// <summary>
- /// When this value is set, the Key encodes the sequence Shift-KeyValue.
- /// The actual value must be extracted by removing the ShiftMask.
- /// </summary>
- ShiftMask = 0x_1000_0000,
- /// <summary>
- /// When this value is set, the Key encodes the sequence Alt-KeyValue.
- /// The actual value must be extracted by removing the AltMask.
- /// </summary>
- AltMask = 0x_8000_0000,
- /// <summary>
- /// When this value is set, the Key encodes the sequence Ctrl-KeyValue.
- /// The actual value must be extracted by removing the CtrlMask.
- /// </summary>
- CtrlMask = 0x_4000_0000,
- /// <summary>
- /// The key code representing an invalid or empty key.
- /// </summary>
- Null = 0,
- /// <summary>
- /// Backspace key.
- /// </summary>
- Backspace = 8,
- /// <summary>
- /// The key code for the tab key (forwards tab key).
- /// </summary>
- Tab = 9,
- /// <summary>
- /// The key code for the return key.
- /// </summary>
- Enter = ConsoleKey.Enter,
- /// <summary>
- /// The key code for the clear key.
- /// </summary>
- Clear = 12,
- /// <summary>
- /// The key code for the escape key.
- /// </summary>
- Esc = 27,
- /// <summary>
- /// The key code for the space bar key.
- /// </summary>
- Space = 32,
- /// <summary>
- /// Digit 0.
- /// </summary>
- D0 = 48,
- /// <summary>
- /// Digit 1.
- /// </summary>
- D1,
- /// <summary>
- /// Digit 2.
- /// </summary>
- D2,
- /// <summary>
- /// Digit 3.
- /// </summary>
- D3,
- /// <summary>
- /// Digit 4.
- /// </summary>
- D4,
- /// <summary>
- /// Digit 5.
- /// </summary>
- D5,
- /// <summary>
- /// Digit 6.
- /// </summary>
- D6,
- /// <summary>
- /// Digit 7.
- /// </summary>
- D7,
- /// <summary>
- /// Digit 8.
- /// </summary>
- D8,
- /// <summary>
- /// Digit 9.
- /// </summary>
- D9,
- /// <summary>
- /// The key code for the A key
- /// </summary>
- A = 65,
- /// <summary>
- /// The key code for the B key
- /// </summary>
- B,
- /// <summary>
- /// The key code for the C key
- /// </summary>
- C,
- /// <summary>
- /// The key code for the D key
- /// </summary>
- D,
- /// <summary>
- /// The key code for the E key
- /// </summary>
- E,
- /// <summary>
- /// The key code for the F key
- /// </summary>
- F,
- /// <summary>
- /// The key code for the G key
- /// </summary>
- G,
- /// <summary>
- /// The key code for the H key
- /// </summary>
- H,
- /// <summary>
- /// The key code for the I key
- /// </summary>
- I,
- /// <summary>
- /// The key code for the J key
- /// </summary>
- J,
- /// <summary>
- /// The key code for the K key
- /// </summary>
- K,
- /// <summary>
- /// The key code for the L key
- /// </summary>
- L,
- /// <summary>
- /// The key code for the M key
- /// </summary>
- M,
- /// <summary>
- /// The key code for the N key
- /// </summary>
- N,
- /// <summary>
- /// The key code for the O key
- /// </summary>
- O,
- /// <summary>
- /// The key code for the P key
- /// </summary>
- P,
- /// <summary>
- /// The key code for the Q key
- /// </summary>
- Q,
- /// <summary>
- /// The key code for the R key
- /// </summary>
- R,
- /// <summary>
- /// The key code for the S key
- /// </summary>
- S,
- /// <summary>
- /// The key code for the T key
- /// </summary>
- T,
- /// <summary>
- /// The key code for the U key
- /// </summary>
- U,
- /// <summary>
- /// The key code for the V key
- /// </summary>
- V,
- /// <summary>
- /// The key code for the W key
- /// </summary>
- W,
- /// <summary>
- /// The key code for the X key
- /// </summary>
- X,
- /// <summary>
- /// The key code for the Y key
- /// </summary>
- Y,
- /// <summary>
- /// The key code for the Z key
- /// </summary>
- Z,
- ///// <summary>
- ///// The key code for the Delete key.
- ///// </summary>
- //Delete = 127,
- // --- Special keys ---
- // The values below are common non-alphanum keys. Their values are
- // based on the .NET ConsoleKey values, which, in-turn are based on the
- // VK_ values from the Windows API.
- // We add MaxCodePoint to avoid conflicts with the Unicode values.
- /// <summary>
- /// The maximum Unicode codepoint value. Used to encode the non-alphanumeric control
- /// keys.
- /// </summary>
- MaxCodePoint = 0x10FFFF,
- /// <summary>
- /// Cursor up key
- /// </summary>
- CursorUp = MaxCodePoint + ConsoleKey.UpArrow,
- /// <summary>
- /// Cursor down key.
- /// </summary>
- CursorDown = MaxCodePoint + ConsoleKey.DownArrow,
- /// <summary>
- /// Cursor left key.
- /// </summary>
- CursorLeft = MaxCodePoint + ConsoleKey.LeftArrow,
- /// <summary>
- /// Cursor right key.
- /// </summary>
- CursorRight = MaxCodePoint + ConsoleKey.RightArrow,
- /// <summary>
- /// Page Up key.
- /// </summary>
- PageUp = MaxCodePoint + ConsoleKey.PageUp,
- /// <summary>
- /// Page Down key.
- /// </summary>
- PageDown = MaxCodePoint + ConsoleKey.PageDown,
- /// <summary>
- /// Home key.
- /// </summary>
- Home = MaxCodePoint + ConsoleKey.Home,
- /// <summary>
- /// End key.
- /// </summary>
- End = MaxCodePoint + ConsoleKey.End,
- /// <summary>
- /// Insert (INS) key.
- /// </summary>
- Insert = MaxCodePoint + ConsoleKey.Insert,
- /// <summary>
- /// Delete (DEL) key.
- /// </summary>
- Delete = MaxCodePoint + ConsoleKey.Delete,
- /// <summary>
- /// Print screen character key.
- /// </summary>
- PrintScreen = MaxCodePoint + ConsoleKey.PrintScreen,
- /// <summary>
- /// F1 key.
- /// </summary>
- F1 = MaxCodePoint + ConsoleKey.F1,
- /// <summary>
- /// F2 key.
- /// </summary>
- F2 = MaxCodePoint + ConsoleKey.F2,
- /// <summary>
- /// F3 key.
- /// </summary>
- F3 = MaxCodePoint + ConsoleKey.F3,
- /// <summary>
- /// F4 key.
- /// </summary>
- F4 = MaxCodePoint + ConsoleKey.F4,
- /// <summary>
- /// F5 key.
- /// </summary>
- F5 = MaxCodePoint + ConsoleKey.F5,
- /// <summary>
- /// F6 key.
- /// </summary>
- F6 = MaxCodePoint + ConsoleKey.F6,
- /// <summary>
- /// F7 key.
- /// </summary>
- F7 = MaxCodePoint + ConsoleKey.F7,
- /// <summary>
- /// F8 key.
- /// </summary>
- F8 = MaxCodePoint + ConsoleKey.F8,
- /// <summary>
- /// F9 key.
- /// </summary>
- F9 = MaxCodePoint + ConsoleKey.F9,
- /// <summary>
- /// F10 key.
- /// </summary>
- F10 = MaxCodePoint + ConsoleKey.F10,
- /// <summary>
- /// F11 key.
- /// </summary>
- F11 = MaxCodePoint + ConsoleKey.F11,
- /// <summary>
- /// F12 key.
- /// </summary>
- F12 = MaxCodePoint + ConsoleKey.F12,
- /// <summary>
- /// F13 key.
- /// </summary>
- F13 = MaxCodePoint + ConsoleKey.F13,
- /// <summary>
- /// F14 key.
- /// </summary>
- F14 = MaxCodePoint + ConsoleKey.F14,
- /// <summary>
- /// F15 key.
- /// </summary>
- F15 = MaxCodePoint + ConsoleKey.F15,
- /// <summary>
- /// F16 key.
- /// </summary>
- F16 = MaxCodePoint + ConsoleKey.F16,
- /// <summary>
- /// F17 key.
- /// </summary>
- F17 = MaxCodePoint + ConsoleKey.F17,
- /// <summary>
- /// F18 key.
- /// </summary>
- F18 = MaxCodePoint + ConsoleKey.F18,
- /// <summary>
- /// F19 key.
- /// </summary>
- F19 = MaxCodePoint + ConsoleKey.F19,
- /// <summary>
- /// F20 key.
- /// </summary>
- F20 = MaxCodePoint + ConsoleKey.F20,
- /// <summary>
- /// F21 key.
- /// </summary>
- F21 = MaxCodePoint + ConsoleKey.F21,
- /// <summary>
- /// F22 key.
- /// </summary>
- F22 = MaxCodePoint + ConsoleKey.F22,
- /// <summary>
- /// F23 key.
- /// </summary>
- F23 = MaxCodePoint + ConsoleKey.F23,
- /// <summary>
- /// F24 key.
- /// </summary>
- F24 = MaxCodePoint + ConsoleKey.F24,
- }
|