diff --git a/Terminal.Gui/Configuration/KeyJsonConverter.cs b/Terminal.Gui/Configuration/KeyJsonConverter.cs
index d9c17996e6..9c1a3fa50e 100644
--- a/Terminal.Gui/Configuration/KeyJsonConverter.cs
+++ b/Terminal.Gui/Configuration/KeyJsonConverter.cs
@@ -8,7 +8,9 @@ namespace Terminal.Gui;
/// Support for in JSON in the form of "Ctrl-X" or "Alt-Shift-F1".
///
public class KeyJsonConverter : JsonConverter {
+ ///
public override Key Read (ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) => Key.TryParse (reader.GetString (), out var key) ? key : Key.Empty;
+ ///
public override void Write (Utf8JsonWriter writer, Key value, JsonSerializerOptions options) => writer.WriteStringValue (value.ToString ());
}
\ No newline at end of file
diff --git a/Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs b/Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs
index 0b5bc9cc62..5e67ebb517 100644
--- a/Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs
+++ b/Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs
@@ -5,6 +5,7 @@
using System;
using System.Diagnostics;
using System.Linq;
+using Terminal.Gui.ConsoleDrivers;
namespace Terminal.Gui;
@@ -31,7 +32,6 @@ public abstract class ConsoleDriver {
internal static bool RunningUnitTests { get; set; }
#region Setup & Teardown
-
///
/// Initializes the driver
///
@@ -42,7 +42,6 @@ public abstract class ConsoleDriver {
/// Ends the execution of the console driver.
///
internal abstract void End ();
-
#endregion
///
@@ -129,10 +128,7 @@ public virtual void Move (int col, int row)
///
/// if the rune can be properly presented; if the driver
/// does not support displaying this rune.
- public virtual bool IsRuneSupported (Rune rune)
- {
- return Rune.IsValid (rune.Value);
- }
+ public virtual bool IsRuneSupported (Rune rune) => Rune.IsValid (rune.Value);
///
/// Adds the specified rune to the display at the current cursor position.
@@ -151,7 +147,7 @@ public virtual bool IsRuneSupported (Rune rune)
public void AddRune (Rune rune)
{
int runeWidth = -1;
- var validLocation = IsValidLocation (Col, Row);
+ bool validLocation = IsValidLocation (Col, Row);
if (validLocation) {
rune = rune.MakePrintable ();
runeWidth = rune.GetColumns ();
@@ -275,7 +271,7 @@ public void AddRune (Rune rune)
public void AddStr (string str)
{
var runes = str.EnumerateRunes ().ToList ();
- for (var i = 0; i < runes.Count; i++) {
+ for (int i = 0; i < runes.Count; i++) {
//if (runes [i].IsCombiningMark()) {
// // Attempt to normalize
@@ -361,8 +357,8 @@ public void ClearContents ()
lock (Contents) {
// Can raise an exception while is still resizing.
try {
- for (var row = 0; row < Rows; row++) {
- for (var c = 0; c < Cols; c++) {
+ 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),
@@ -381,11 +377,10 @@ public void ClearContents ()
public abstract void UpdateScreen ();
#region Color Handling
-
///
/// Gets whether the supports TrueColor output.
///
- public virtual bool SupportsTrueColor { get => true; }
+ public virtual bool SupportsTrueColor => true;
///
/// Gets or sets whether the should use 16 colors instead of the default TrueColors. See
@@ -399,7 +394,7 @@ public void ClearContents ()
///
internal virtual bool Force16Colors {
get => Application.Force16Colors || !SupportsTrueColor;
- set => Application.Force16Colors = (value || !SupportsTrueColor);
+ set => Application.Force16Colors = value || !SupportsTrueColor;
}
Attribute _currentAttribute;
@@ -447,17 +442,13 @@ public Attribute SetAttribute (Attribute c)
/// The foreground color.
/// The background color.
/// The attribute for the foreground and background colors.
- public virtual Attribute MakeColor (Color foreground, Color background)
- {
+ public virtual Attribute MakeColor (Color foreground, Color background) =>
// Encode the colors into the int value.
- return new Attribute (
- platformColor: 0, // only used by cursesdriver!
- foreground: foreground,
- background: background
+ new (
+ 0, // only used by cursesdriver!
+ foreground,
+ background
);
- }
-
-
#endregion
#region Mouse and Keyboard
@@ -509,7 +500,6 @@ public virtual Attribute MakeColor (Color foreground, Color background)
/// If simulates the Alt key being pressed.
/// If simulates the Ctrl key being pressed.
public abstract void SendKeys (char keyChar, ConsoleKey key, bool shift, bool alt, bool ctrl);
-
#endregion
///
@@ -521,16 +511,18 @@ public enum DiagnosticFlags : uint {
/// All diagnostics off
///
Off = 0b_0000_0000,
+
///
/// When enabled, will draw a
/// ruler in the frame for any side with a padding value greater than 0.
///
FrameRuler = 0b_0000_0001,
+
///
/// When enabled, will draw a
/// 'L', 'R', 'T', and 'B' when clearing 's instead of ' '.
///
- FramePadding = 0b_0000_0010,
+ FramePadding = 0b_0000_0010
}
///
@@ -552,8 +544,8 @@ public enum DiagnosticFlags : uint {
///
public void FillRect (Rect rect, Rune rune = default)
{
- for (var r = rect.Y; r < rect.Y + rect.Height; r++) {
- for (var c = rect.X; c < rect.X + rect.Width; c++) {
+ 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);
}
@@ -575,7 +567,6 @@ public void FillRect (Rect rect, Rune rune = default)
public virtual string GetVersionInfo () => GetType ().Name;
}
-
///
/// Terminal Cursor Visibility settings.
///
@@ -631,10 +622,9 @@ public enum CursorVisibility {
/// Cursor caret is displayed a block ▉
///
/// Works under Xterm-like terminal otherwise this is equivalent to
- BoxFix = 0x02020164,
+ BoxFix = 0x02020164
}
-
///
/// The enumeration encodes key information from s and provides a consistent
/// way for application code to specify keys and receive key events.
@@ -671,72 +661,59 @@ public enum CursorVisibility {
[Flags]
public enum KeyCode : uint {
///
- /// Mask that indicates that this is a character value, values outside this range
- /// indicate special characters like Alt-key combinations or special keys on the
- /// keyboard like function keys, arrows keys and so on.
+ /// 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.
///
- CharMask = 0xfffff,
+ CharMask = 0x_f_ffff,
///
/// If the is set, then the value is that of the special mask,
/// otherwise, the value is in the the lower bits (as extracted by ).
///
- SpecialMask = 0xfff00000,
+ SpecialMask = 0x_fff0_0000,
///
- /// The key code representing null or empty
- ///
- Null = '\0',
-
- ///
- /// Backspace key.
+ /// When this value is set, the Key encodes the sequence Shift-KeyValue.
+ /// The actual value must be extracted by removing the ShiftMask.
///
- Backspace = 8,
+ ShiftMask = 0x_1000_0000,
///
- /// The key code for the tab key (forwards tab key).
+ /// When this value is set, the Key encodes the sequence Alt-KeyValue.
+ /// The actual value must be extracted by removing the AltMask.
///
- Tab = 9,
+ AltMask = 0x_8000_0000,
///
- /// The key code for the return key.
+ /// When this value is set, the Key encodes the sequence Ctrl-KeyValue.
+ /// The actual value must be extracted by removing the CtrlMask.
///
- Enter = '\n',
+ CtrlMask = 0x_4000_0000,
///
- /// The key code for the clear key.
+ /// The key code representing an invalid or empty key.
///
- Clear = 12,
+ Null = 0,
///
- /// The key code for the Shift key.
+ /// Backspace key.
///
- ShiftKey = 16,
+ Backspace = 8,
///
- /// The key code for the Ctrl key.
+ /// The key code for the tab key (forwards tab key).
///
- CtrlKey = 17,
+ Tab = 9,
///
- /// The key code for the Alt key.
+ /// The key code for the return key.
///
- AltKey = 18,
+ Enter = ConsoleKey.Enter,
///
- /// The key code for the CapsLock key.
+ /// The key code for the clear key.
///
- CapsLock = 20,
-
- /////
- ///// The key code for the NumLock key.
- /////
- //NumLock = 144,
-
- /////
- ///// The key code for the ScrollLock key.
- /////
- //ScrollLock = 145,
+ Clear = 12,
///
/// The key code for the escape key.
@@ -752,38 +729,47 @@ public enum KeyCode : uint {
/// Digit 0.
///
D0 = 48,
+
///
/// Digit 1.
///
D1,
+
///
/// Digit 2.
///
D2,
+
///
/// Digit 3.
///
D3,
+
///
/// Digit 4.
///
D4,
+
///
/// Digit 5.
///
D5,
+
///
/// Digit 6.
///
D6,
+
///
/// Digit 7.
///
D7,
+
///
/// Digit 8.
///
D8,
+
///
/// Digit 9.
///
@@ -793,271 +779,321 @@ public enum KeyCode : uint {
/// The key code for the A key
///
A = 65,
+
///
/// The key code for the B key
///
B,
+
///
/// The key code for the C key
///
C,
+
///
/// The key code for the D key
///
D,
+
///
/// The key code for the E key
///
E,
+
///
/// The key code for the F key
///
F,
+
///
/// The key code for the G key
///
G,
+
///
/// The key code for the H key
///
H,
+
///
/// The key code for the I key
///
I,
+
///
/// The key code for the J key
///
J,
+
///
/// The key code for the K key
///
K,
+
///
/// The key code for the L key
///
L,
+
///
/// The key code for the M key
///
M,
+
///
/// The key code for the N key
///
N,
+
///
/// The key code for the O key
///
O,
+
///
/// The key code for the P key
///
P,
+
///
/// The key code for the Q key
///
Q,
+
///
/// The key code for the R key
///
R,
+
///
/// The key code for the S key
///
S,
+
///
/// The key code for the T key
///
T,
+
///
/// The key code for the U key
///
U,
+
///
/// The key code for the V key
///
V,
+
///
/// The key code for the W key
///
W,
+
///
/// The key code for the X key
///
X,
+
///
/// The key code for the Y key
///
Y,
+
///
/// The key code for the Z key
///
Z,
- ///
- /// The key code for the Delete key.
- ///
- Delete = 127,
- ///
- /// When this value is set, the Key encodes the sequence Shift-KeyValue.
- ///
- ShiftMask = 0x10000000,
+ /////
+ ///// The key code for the Delete key.
+ /////
+ //Delete = 127,
- ///
- /// When this value is set, the Key encodes the sequence Alt-KeyValue.
- /// And the actual value must be extracted by removing the AltMask.
- ///
- AltMask = 0x80000000,
+ // --- 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.
///
- /// When this value is set, the Key encodes the sequence Ctrl-KeyValue.
- /// And the actual value must be extracted by removing the CtrlMask.
+ /// The maximum Unicode codepoint value. Used to encode the non-alphanumeric control
+ /// keys.
///
- CtrlMask = 0x40000000,
+ MaxCodePoint = 0x10FFFF,
///
/// Cursor up key
///
- CursorUp = 0x100000,
+ CursorUp = MaxCodePoint + ConsoleKey.UpArrow,
+
///
/// Cursor down key.
///
- CursorDown,
+ CursorDown = MaxCodePoint + ConsoleKey.DownArrow,
+
///
/// Cursor left key.
///
- CursorLeft,
+ CursorLeft = MaxCodePoint + ConsoleKey.LeftArrow,
+
///
/// Cursor right key.
///
- CursorRight,
+ CursorRight = MaxCodePoint + ConsoleKey.RightArrow,
+
///
/// Page Up key.
///
- PageUp,
+ PageUp = MaxCodePoint + ConsoleKey.PageUp,
+
///
/// Page Down key.
///
- PageDown,
+ PageDown = MaxCodePoint + ConsoleKey.PageDown,
+
///
/// Home key.
///
- Home,
+ Home = MaxCodePoint + ConsoleKey.Home,
+
///
/// End key.
///
- End,
+ End = MaxCodePoint + ConsoleKey.End,
///
- /// Insert character key.
+ /// Insert (INS) key.
///
- InsertChar,
+ Insert = MaxCodePoint + ConsoleKey.Insert,
///
- /// Delete character key.
+ /// Delete (DEL) key.
///
- DeleteChar,
+ Delete = MaxCodePoint + ConsoleKey.Delete,
///
/// Print screen character key.
///
- PrintScreen,
+ PrintScreen = MaxCodePoint + ConsoleKey.PrintScreen,
///
/// F1 key.
///
- F1,
+ F1 = MaxCodePoint + ConsoleKey.F1,
+
///
/// F2 key.
///
- F2,
+ F2 = MaxCodePoint + ConsoleKey.F2,
+
///
/// F3 key.
///
- F3,
+ F3 = MaxCodePoint + ConsoleKey.F3,
+
///
/// F4 key.
///
- F4,
+ F4 = MaxCodePoint + ConsoleKey.F4,
+
///
/// F5 key.
///
- F5,
+ F5 = MaxCodePoint + ConsoleKey.F5,
+
///
/// F6 key.
///
- F6,
+ F6 = MaxCodePoint + ConsoleKey.F6,
+
///
/// F7 key.
///
- F7,
+ F7 = MaxCodePoint + ConsoleKey.F7,
+
///
/// F8 key.
///
- F8,
+ F8 = MaxCodePoint + ConsoleKey.F8,
+
///
/// F9 key.
///
- F9,
+ F9 = MaxCodePoint + ConsoleKey.F9,
+
///
/// F10 key.
///
- F10,
+ F10 = MaxCodePoint + ConsoleKey.F10,
+
///
/// F11 key.
///
- F11,
+ F11 = MaxCodePoint + ConsoleKey.F11,
+
///
/// F12 key.
///
- F12,
+ F12 = MaxCodePoint + ConsoleKey.F12,
+
///
/// F13 key.
///
- F13,
+ F13 = MaxCodePoint + ConsoleKey.F13,
+
///
/// F14 key.
///
- F14,
+ F14 = MaxCodePoint + ConsoleKey.F14,
+
///
/// F15 key.
///
- F15,
+ F15 = MaxCodePoint + ConsoleKey.F15,
+
///
/// F16 key.
///
- F16,
+ F16 = MaxCodePoint + ConsoleKey.F16,
+
///
/// F17 key.
///
- F17,
+ F17 = MaxCodePoint + ConsoleKey.F17,
+
///
/// F18 key.
///
- F18,
+ F18 = MaxCodePoint + ConsoleKey.F18,
+
///
/// F19 key.
///
- F19,
+ F19 = MaxCodePoint + ConsoleKey.F19,
+
///
/// F20 key.
///
- F20,
+ F20 = MaxCodePoint + ConsoleKey.F20,
+
///
/// F21 key.
///
- F21,
+ F21 = MaxCodePoint + ConsoleKey.F21,
+
///
/// F22 key.
///
- F22,
+ F22 = MaxCodePoint + ConsoleKey.F22,
+
///
/// F23 key.
///
- F23,
+ F23 = MaxCodePoint + ConsoleKey.F23,
+
///
/// F24 key.
///
- F24,
-}
-
+ F24 = MaxCodePoint + ConsoleKey.F24,
+}
\ No newline at end of file
diff --git a/Terminal.Gui/ConsoleDrivers/ConsoleKeyMapping.cs b/Terminal.Gui/ConsoleDrivers/ConsoleKeyMapping.cs
index 142a03b1b2..f18420c424 100644
--- a/Terminal.Gui/ConsoleDrivers/ConsoleKeyMapping.cs
+++ b/Terminal.Gui/ConsoleDrivers/ConsoleKeyMapping.cs
@@ -2,597 +2,1721 @@
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
-namespace Terminal.Gui.ConsoleDrivers {
+namespace Terminal.Gui.ConsoleDrivers;
+
+///
+/// Helper class to handle the scan code and virtual key from a .
+///
+public static class ConsoleKeyMapping {
+
+#if !WT_ISSUE_8871_FIXED // https://github.com/microsoft/terminal/issues/8871
///
- /// Helper class to handle the scan code and virtual key from a .
+ /// Translates (maps) a virtual-key code into a scan code or character value, or translates a scan code into a virtual-key code.
///
- public static class ConsoleKeyMapping {
- class ScanCodeMapping : IEquatable {
- public uint ScanCode;
- public uint VirtualKey;
- public ConsoleModifiers Modifiers;
- public uint UnicodeChar;
-
- public ScanCodeMapping (uint scanCode, uint virtualKey, ConsoleModifiers modifiers, uint unicodeChar)
- {
- ScanCode = scanCode;
- VirtualKey = virtualKey;
- Modifiers = modifiers;
- UnicodeChar = unicodeChar;
- }
+ ///
+ ///
+ /// If MAPVK_VK_TO_CHAR (2) - The uCode parameter is a virtual-key code and is translated into an un-shifted
+ /// character value in the low order word of the return value.
+ ///
+ ///
+ /// An un-shifted character value in the low order word of the return value. Dead keys (diacritics)
+ /// are indicated by setting the top bit of the return value. If there is no translation,
+ /// the function returns 0. See Remarks.
+ [DllImport ("user32.dll", EntryPoint = "MapVirtualKeyExW", CharSet = CharSet.Unicode)]
+ extern static uint MapVirtualKeyEx (VK vk, uint uMapType, IntPtr dwhkl);
- public bool Equals (ScanCodeMapping other)
- {
- return ScanCode.Equals (other.ScanCode) &&
- VirtualKey.Equals (other.VirtualKey) &&
- Modifiers.Equals (other.Modifiers) &&
- UnicodeChar.Equals (other.UnicodeChar);
- }
- }
+ ///
+ /// Retrieves the active input locale identifier (formerly called the keyboard layout).
+ ///
+ /// 0 for current thread
+ /// The return value is the input locale identifier for the thread.
+ /// The low word contains a Language Identifier for the input language
+ /// and the high word contains a device handle to the physical layout of the keyboard.
+ ///
+ [DllImport ("user32.dll", EntryPoint = "GetKeyboardLayout", CharSet = CharSet.Unicode)]
+ extern static IntPtr GetKeyboardLayout (IntPtr idThread);
- static ConsoleModifiers GetModifiers (ConsoleModifiers modifiers)
- {
- if (modifiers.HasFlag (ConsoleModifiers.Shift)
- && !modifiers.HasFlag (ConsoleModifiers.Alt)
- && !modifiers.HasFlag (ConsoleModifiers.Control)) {
- return ConsoleModifiers.Shift;
- } else if (modifiers == (ConsoleModifiers.Alt | ConsoleModifiers.Control)) {
- return modifiers;
- }
+ //[DllImport ("user32.dll", EntryPoint = "GetKeyboardLayoutNameW", CharSet = CharSet.Unicode)]
+ //extern static uint GetKeyboardLayoutName (uint idThread);
+
+ [DllImport ("user32.dll")]
+ extern static IntPtr GetForegroundWindow ();
+ [DllImport ("user32.dll")]
+ extern static IntPtr GetWindowThreadProcessId (IntPtr hWnd, IntPtr ProcessId);
+
+ ///
+ /// Translates the specified virtual-key code and keyboard state to the corresponding Unicode character or characters using
+ /// the Win32 API MapVirtualKey.
+ ///
+ ///
+ /// An un-shifted character value in the low order word of the return value. Dead keys (diacritics)
+ /// are indicated by setting the top bit of the return value. If there is no translation,
+ /// the function returns 0.
+ public static uint MapVKtoChar (VK vk)
+ {
+ if (Environment.OSVersion.Platform != PlatformID.Win32NT) {
return 0;
}
+ var tid = GetWindowThreadProcessId (GetForegroundWindow (), 0);
+ var hkl = GetKeyboardLayout (tid);
+ return MapVirtualKeyEx (vk, 2, hkl);
+ }
+#else
+ ///
+ /// Translates (maps) a virtual-key code into a scan code or character value, or translates a scan code into a virtual-key code.
+ ///
+ ///
+ ///
+ /// If MAPVK_VK_TO_CHAR (2) - The uCode parameter is a virtual-key code and is translated into an unshifted
+ /// character value in the low order word of the return value.
+ ///
+ /// An unshifted character value in the low order word of the return value. Dead keys (diacritics)
+ /// are indicated by setting the top bit of the return value. If there is no translation,
+ /// the function returns 0. See Remarks.
+ [DllImport ("user32.dll", EntryPoint = "MapVirtualKeyW", CharSet = CharSet.Unicode)]
+ extern static uint MapVirtualKey (VK vk, uint uMapType = 2);
+
+ uint MapVKtoChar (VK vk) => MapVirtualKeyToCharEx (vk);
+#endif
+ ///
+ /// Retrieves the name of the active input locale identifier (formerly called the keyboard layout) for the calling thread.
+ ///
+ ///
+ ///
+ [DllImport ("user32.dll")]
+ extern static bool GetKeyboardLayoutName ([Out] StringBuilder pwszKLID);
+
+ public static string GetKeyboardLayoutName ()
+ {
+ if (Environment.OSVersion.Platform != PlatformID.Win32NT) {
+ return "none";
+ }
- static ScanCodeMapping GetScanCode (string propName, uint keyValue, ConsoleModifiers modifiers)
- {
- switch (propName) {
- case "UnicodeChar":
- var sCode = scanCodes.FirstOrDefault ((e) => e.UnicodeChar == keyValue && e.Modifiers == modifiers);
- if (sCode == null && modifiers == (ConsoleModifiers.Alt | ConsoleModifiers.Control)) {
- return scanCodes.FirstOrDefault ((e) => e.UnicodeChar == keyValue && e.Modifiers == 0);
- }
- return sCode;
- case "VirtualKey":
- sCode = scanCodes.FirstOrDefault ((e) => e.VirtualKey == keyValue && e.Modifiers == modifiers);
- if (sCode == null && modifiers == (ConsoleModifiers.Alt | ConsoleModifiers.Control)) {
- return scanCodes.FirstOrDefault ((e) => e.VirtualKey == keyValue && e.Modifiers == 0);
- }
- return sCode;
- }
+ StringBuilder klidSB = new StringBuilder ();
+ GetKeyboardLayoutName (klidSB);
+ return klidSB.ToString ();
+ }
- return null;
+ class ScanCodeMapping : IEquatable {
+ public uint ScanCode;
+ public VK VirtualKey;
+ public ConsoleModifiers Modifiers;
+ public uint UnicodeChar;
+
+ public ScanCodeMapping (uint scanCode, VK virtualKey, ConsoleModifiers modifiers, uint unicodeChar)
+ {
+ ScanCode = scanCode;
+ VirtualKey = virtualKey;
+ Modifiers = modifiers;
+ UnicodeChar = unicodeChar;
}
- ///
- /// Gets the from the provided .
- ///
- ///
- ///
- public static ConsoleKeyInfo GetConsoleKeyFromKey (KeyCode key)
+ public bool Equals (ScanCodeMapping other)
{
- var mod = new ConsoleModifiers ();
- if (key.HasFlag (KeyCode.ShiftMask)) {
- mod |= ConsoleModifiers.Shift;
- }
- if (key.HasFlag (KeyCode.AltMask)) {
- mod |= ConsoleModifiers.Alt;
+ return ScanCode.Equals (other.ScanCode) &&
+ VirtualKey.Equals (other.VirtualKey) &&
+ Modifiers.Equals (other.Modifiers) &&
+ UnicodeChar.Equals (other.UnicodeChar);
+ }
+ }
+
+ static ConsoleModifiers GetModifiers (ConsoleModifiers modifiers)
+ {
+ if (modifiers.HasFlag (ConsoleModifiers.Shift)
+ && !modifiers.HasFlag (ConsoleModifiers.Alt)
+ && !modifiers.HasFlag (ConsoleModifiers.Control)) {
+ return ConsoleModifiers.Shift;
+ } else if (modifiers == (ConsoleModifiers.Alt | ConsoleModifiers.Control)) {
+ return modifiers;
+ }
+
+ return 0;
+ }
+
+ static ScanCodeMapping GetScanCode (string propName, uint keyValue, ConsoleModifiers modifiers)
+ {
+ switch (propName) {
+ case "UnicodeChar":
+ var sCode = _scanCodes.FirstOrDefault ((e) => e.UnicodeChar == keyValue && e.Modifiers == modifiers);
+ if (sCode == null && modifiers == (ConsoleModifiers.Alt | ConsoleModifiers.Control)) {
+ return _scanCodes.FirstOrDefault ((e) => e.UnicodeChar == keyValue && e.Modifiers == 0);
}
- if (key.HasFlag (KeyCode.CtrlMask)) {
- mod |= ConsoleModifiers.Control;
+ return sCode;
+ case "VirtualKey":
+ sCode = _scanCodes.FirstOrDefault ((e) => e.VirtualKey == (VK)keyValue && e.Modifiers == modifiers);
+ if (sCode == null && modifiers == (ConsoleModifiers.Alt | ConsoleModifiers.Control)) {
+ return _scanCodes.FirstOrDefault ((e) => e.VirtualKey == (VK)keyValue && e.Modifiers == 0);
}
- return GetConsoleKeyFromKey ((uint)(key & ~KeyCode.CtrlMask & ~KeyCode.ShiftMask & ~KeyCode.AltMask), mod, out _);
+ return sCode;
}
- ///
- /// Get the from a unicode character and modifiers (e.g. (Key)'a' and (Key)Key.CtrlMask).
- ///
- /// The key as a unicode codepoint.
- /// The modifier keys.
- /// The resulting scan code.
- /// The .
- public static ConsoleKeyInfo GetConsoleKeyFromKey (uint keyValue, ConsoleModifiers modifiers, out uint scanCode)
- {
- scanCode = 0;
- uint outputChar = keyValue;
- if (keyValue == 0) {
- return new ConsoleKeyInfo ((char)keyValue, ConsoleKey.None, modifiers.HasFlag (ConsoleModifiers.Shift),
+ return null;
+ }
+
+ // BUGBUG: This API is not correct. It is only used by WindowsDriver in VKPacket scenarios
+ ///
+ /// Get the scan code from a .
+ ///
+ /// The console key info.
+ /// The value if apply.
+ public static uint GetScanCodeFromConsoleKeyInfo (ConsoleKeyInfo consoleKeyInfo)
+ {
+ var mod = GetModifiers (consoleKeyInfo.Modifiers);
+ ScanCodeMapping scode = GetScanCode ("VirtualKey", (uint)consoleKeyInfo.Key, mod);
+ if (scode != null) {
+ return scode.ScanCode;
+ }
+
+ return 0;
+ }
+
+ // BUGBUG: This API is not correct. It is only used by FakeDriver and VkeyPacketSimulator
+ ///
+ /// Gets the from the provided .
+ ///
+ /// The key code.
+ /// The console key info.
+ public static ConsoleKeyInfo GetConsoleKeyInfoFromKeyCode (KeyCode key)
+ {
+ var modifiers = MapToConsoleModifiers (key);
+ var keyValue = MapKeyCodeToConsoleKey (key, out bool isConsoleKey);
+ if (isConsoleKey) {
+ var mod = GetModifiers (modifiers);
+ var scode = GetScanCode ("VirtualKey", (uint)keyValue, mod);
+ if (scode != null) {
+ return new ConsoleKeyInfo ((char)scode.UnicodeChar, (ConsoleKey)scode.VirtualKey, modifiers.HasFlag (ConsoleModifiers.Shift),
+ modifiers.HasFlag (ConsoleModifiers.Alt), modifiers.HasFlag (ConsoleModifiers.Control));
+ }
+ } else {
+ var keyChar = GetKeyCharFromUnicodeChar ((uint)keyValue, modifiers, out uint consoleKey, out _, isConsoleKey);
+ if (consoleKey != 0) {
+ return new ConsoleKeyInfo ((char)keyChar, (ConsoleKey)consoleKey, modifiers.HasFlag (ConsoleModifiers.Shift),
modifiers.HasFlag (ConsoleModifiers.Alt), modifiers.HasFlag (ConsoleModifiers.Control));
}
+ }
+
+ return new ConsoleKeyInfo ((char)keyValue, ConsoleKey.None, modifiers.HasFlag (ConsoleModifiers.Shift),
+ modifiers.HasFlag (ConsoleModifiers.Alt), modifiers.HasFlag (ConsoleModifiers.Control));
+ }
+
+ ///
+ /// Map existing modifiers to .
+ ///
+ /// The key code.
+ /// The console modifiers.
+ public static ConsoleModifiers MapToConsoleModifiers (KeyCode key)
+ {
+ var modifiers = new ConsoleModifiers ();
+ if (key.HasFlag (KeyCode.ShiftMask)) {
+ modifiers |= ConsoleModifiers.Shift;
+ }
+ if (key.HasFlag (KeyCode.AltMask)) {
+ modifiers |= ConsoleModifiers.Alt;
+ }
+ if (key.HasFlag (KeyCode.CtrlMask)) {
+ modifiers |= ConsoleModifiers.Control;
+ }
- uint consoleKey = (uint)MapKeyToConsoleKey ((KeyCode)keyValue, modifiers, out bool mappable);
- if (mappable) {
- var mod = GetModifiers (modifiers);
- var scode = GetScanCode ("UnicodeChar", keyValue, mod);
- if (scode != null) {
- consoleKey = scode.VirtualKey;
- scanCode = scode.ScanCode;
- outputChar = scode.UnicodeChar;
+ return modifiers;
+ }
+
+ ///
+ /// Gets from modifiers.
+ ///
+ /// The shift key.
+ /// The alt key.
+ /// The control key.
+ /// The console modifiers.
+ public static ConsoleModifiers GetModifiers (bool shift, bool alt, bool control)
+ {
+ var modifiers = new ConsoleModifiers ();
+ if (shift) {
+ modifiers |= ConsoleModifiers.Shift;
+ }
+ if (alt) {
+ modifiers |= ConsoleModifiers.Alt;
+ }
+ if (control) {
+ modifiers |= ConsoleModifiers.Control;
+ }
+
+ return modifiers;
+ }
+
+ ///
+ /// Get the from a unicode character and modifiers (e.g. (Key)'a' and (Key)Key.CtrlMask).
+ ///
+ /// The key as a unicode codepoint.
+ /// The modifier keys.
+ /// The resulting scan code.
+ /// The .
+ static ConsoleKeyInfo GetConsoleKeyInfoFromKeyChar (uint keyValue, ConsoleModifiers modifiers, out uint scanCode)
+ {
+ scanCode = 0;
+ if (keyValue == 0) {
+ return new ConsoleKeyInfo ((char)keyValue, ConsoleKey.None, modifiers.HasFlag (ConsoleModifiers.Shift),
+ modifiers.HasFlag (ConsoleModifiers.Alt), modifiers.HasFlag (ConsoleModifiers.Control));
+ }
+
+ uint outputChar = keyValue;
+ uint consoleKey;
+ if (keyValue > byte.MaxValue) {
+ var sCode = _scanCodes.FirstOrDefault ((e) => e.UnicodeChar == keyValue);
+ if (sCode == null) {
+ consoleKey = (byte)(keyValue & byte.MaxValue);
+ sCode = _scanCodes.FirstOrDefault ((e) => e.VirtualKey == (VK)consoleKey);
+ if (sCode == null) {
+ consoleKey = 0;
+ outputChar = keyValue;
} else {
- // If the consoleKey is < 255, retain the lower 8 bits of the key value and set the upper bits to 0xff.
- // This is a shifted value that will be used by the GetKeyCharFromConsoleKey to do the correct action
- // because keyValue maybe a UnicodeChar or a ConsoleKey, e.g. for PageUp is passed the ConsoleKey.PageUp
- consoleKey = consoleKey < 0xff ? consoleKey & 0xff | 0xff << 8 : consoleKey;
- outputChar = GetKeyCharFromConsoleKey (consoleKey, modifiers, out consoleKey, out scanCode);
+ outputChar = (char)(keyValue >> 8);
}
} else {
- var mod = GetModifiers (modifiers);
- var scode = GetScanCode ("VirtualKey", consoleKey, mod);
- if (scode != null) {
- consoleKey = scode.VirtualKey;
- scanCode = scode.ScanCode;
- outputChar = scode.UnicodeChar;
- }
+ consoleKey = (byte)sCode.VirtualKey;
+ outputChar = keyValue;
}
+ } else {
+ consoleKey = (byte)keyValue;
+ outputChar = '\0';
+ }
- return new ConsoleKeyInfo ((char)outputChar, (ConsoleKey)consoleKey, modifiers.HasFlag (ConsoleModifiers.Shift),
- modifiers.HasFlag (ConsoleModifiers.Alt), modifiers.HasFlag (ConsoleModifiers.Control));
+ return new ConsoleKeyInfo ((char)outputChar, (ConsoleKey)consoleKey, modifiers.HasFlag (ConsoleModifiers.Shift),
+ modifiers.HasFlag (ConsoleModifiers.Alt), modifiers.HasFlag (ConsoleModifiers.Control));
+ }
+
+ // Used only by unit tests
+ internal static uint GetKeyChar (uint keyValue, ConsoleModifiers modifiers)
+ {
+ if (modifiers == ConsoleModifiers.Shift && keyValue - 32 is >= 'A' and <= 'Z') {
+ return keyValue - 32;
+ } else if (modifiers == ConsoleModifiers.None && keyValue is >= 'A' and <= 'Z') {
+ return keyValue + 32;
}
- ///
- /// Get the output character from the , the correct
- /// and the scan code used on .
- ///
- /// The unicode character.
- /// The modifiers keys.
- /// The resulting console key.
- /// The resulting scan code.
- /// The output character or the .
- static uint GetKeyCharFromConsoleKey (uint unicodeChar, ConsoleModifiers modifiers, out uint consoleKey, out uint scanCode)
- {
- uint decodedChar = unicodeChar >> 8 == 0xff ? unicodeChar & 0xff : unicodeChar;
- uint keyChar = decodedChar;
- consoleKey = 0;
- var mod = GetModifiers (modifiers);
- scanCode = 0;
- var scode = unicodeChar != 0 && unicodeChar >> 8 != 0xff ? GetScanCode ("VirtualKey", decodedChar, mod) : null;
+ if (modifiers == ConsoleModifiers.Shift && keyValue - 32 is >= 'À' and <= 'Ý') {
+ return keyValue - 32;
+ } else if (modifiers == ConsoleModifiers.None && keyValue is >= 'À' and <= 'Ý') {
+ return keyValue + 32;
+ }
+
+ if (modifiers.HasFlag (ConsoleModifiers.Shift) && keyValue is '0') {
+ return keyValue + 13;
+ } else if (modifiers == ConsoleModifiers.None && keyValue - 13 is '0') {
+ return keyValue - 13;
+ }
+
+ if (modifiers.HasFlag (ConsoleModifiers.Shift) && keyValue is >= '1' and <= '9' and not '7') {
+ return keyValue - 16;
+ } else if (modifiers == ConsoleModifiers.None && keyValue + 16 is >= '1' and <= '9' and not '7') {
+ return keyValue + 16;
+ }
+
+ if (modifiers.HasFlag (ConsoleModifiers.Shift) && keyValue is '7') {
+ return keyValue - 8;
+ } else if (modifiers == ConsoleModifiers.None && keyValue + 8 is '7') {
+ return keyValue + 8;
+ }
+
+ if (modifiers.HasFlag (ConsoleModifiers.Shift) && keyValue is '\'') {
+ return keyValue + 24;
+ } else if (modifiers == ConsoleModifiers.None && keyValue - 24 is '\'') {
+ return keyValue - 24;
+ }
+
+ if (modifiers.HasFlag (ConsoleModifiers.Shift) && keyValue is '«') {
+ return keyValue + 16;
+ } else if (modifiers == ConsoleModifiers.None && keyValue - 16 is '«') {
+ return keyValue - 16;
+ }
+
+ if (modifiers.HasFlag (ConsoleModifiers.Shift) && keyValue is '\\') {
+ return keyValue + 32;
+ } else if (modifiers == ConsoleModifiers.None && keyValue - 32 is '\\') {
+ return keyValue - 32;
+ }
+
+ if (modifiers.HasFlag (ConsoleModifiers.Shift) && keyValue is '+') {
+ return keyValue - 1;
+ } else if (modifiers == ConsoleModifiers.None && keyValue + 1 is '+') {
+ return keyValue + 1;
+ }
+
+ if (modifiers.HasFlag (ConsoleModifiers.Shift) && keyValue is '´') {
+ return keyValue - 84;
+ } else if (modifiers == ConsoleModifiers.None && keyValue + 84 is '´') {
+ return keyValue + 84;
+ }
+
+ if (modifiers.HasFlag (ConsoleModifiers.Shift) && keyValue is 'º') {
+ return keyValue - 16;
+ } else if (modifiers == ConsoleModifiers.None && keyValue + 16 is 'º') {
+ return keyValue + 16;
+ }
+
+ if (modifiers.HasFlag (ConsoleModifiers.Shift) && keyValue is '~') {
+ return keyValue - 32;
+ } else if (modifiers == ConsoleModifiers.None && keyValue + 32 is '~') {
+ return keyValue + 32;
+ }
+
+ if (modifiers.HasFlag (ConsoleModifiers.Shift) && keyValue is '<') {
+ return keyValue + 2;
+ } else if (modifiers == ConsoleModifiers.None && keyValue - 2 is '<') {
+ return keyValue - 2;
+ }
+
+ if (modifiers.HasFlag (ConsoleModifiers.Shift) && keyValue is ',') {
+ return keyValue + 15;
+ } else if (modifiers == ConsoleModifiers.None && keyValue - 15 is ',') {
+ return keyValue - 15;
+ }
+ if (modifiers.HasFlag (ConsoleModifiers.Shift) && keyValue is '.') {
+ return keyValue + 12;
+ } else if (modifiers == ConsoleModifiers.None && keyValue - 12 is '.') {
+ return keyValue - 12;
+ }
+
+ if (modifiers.HasFlag (ConsoleModifiers.Shift) && keyValue is '-') {
+ return keyValue + 50;
+ } else if (modifiers == ConsoleModifiers.None && keyValue - 50 is '-') {
+ return keyValue - 50;
+ }
+
+ return keyValue;
+ }
+
+ ///
+ /// Get the output character from the , with the correct
+ /// and the scan code used on .
+ ///
+ /// The unicode character.
+ /// The modifiers keys.
+ /// The resulting console key.
+ /// The resulting scan code.
+ /// Indicates if the is a .
+ /// The output character or the .
+ /// This is only used by the and by unit tests.
+ internal static uint GetKeyCharFromUnicodeChar (uint unicodeChar, ConsoleModifiers modifiers, out uint consoleKey, out uint scanCode, bool isConsoleKey = false)
+ {
+ uint decodedChar = unicodeChar >> 8 == 0xff ? unicodeChar & 0xff : unicodeChar;
+ uint keyChar = decodedChar;
+ consoleKey = 0;
+ var mod = GetModifiers (modifiers);
+ scanCode = 0;
+ ScanCodeMapping scode = null;
+ if (unicodeChar != 0 && unicodeChar >> 8 != 0xff && isConsoleKey) {
+ scode = GetScanCode ("VirtualKey", decodedChar, mod);
+ }
+ if (isConsoleKey && scode != null) {
+ consoleKey = (uint)scode.VirtualKey;
+ keyChar = scode.UnicodeChar;
+ scanCode = scode.ScanCode;
+ }
+ if (scode == null) {
+ scode = unicodeChar != 0 ? GetScanCode ("UnicodeChar", decodedChar, mod) : null;
if (scode != null) {
- consoleKey = scode.VirtualKey;
+ consoleKey = (uint)scode.VirtualKey;
keyChar = scode.UnicodeChar;
scanCode = scode.ScanCode;
}
- if (scode == null) {
- scode = unicodeChar != 0 ? GetScanCode ("UnicodeChar", decodedChar, mod) : null;
- if (scode != null) {
- consoleKey = scode.VirtualKey;
- keyChar = scode.UnicodeChar;
- scanCode = scode.ScanCode;
- }
- }
- if (decodedChar != 0 && scanCode == 0 && char.IsLetter ((char)decodedChar)) {
- string stFormD = ((char)decodedChar).ToString ().Normalize (System.Text.NormalizationForm.FormD);
- for (int i = 0; i < stFormD.Length; i++) {
- var uc = CharUnicodeInfo.GetUnicodeCategory (stFormD [i]);
- if (uc != UnicodeCategory.NonSpacingMark && uc != UnicodeCategory.OtherLetter) {
- consoleKey = char.ToUpper (stFormD [i]);
- scode = GetScanCode ("VirtualKey", char.ToUpper (stFormD [i]), 0);
- if (scode != null) {
- scanCode = scode.ScanCode;
- }
+ }
+ if (decodedChar != 0 && scanCode == 0 && char.IsLetter ((char)decodedChar)) {
+ string stFormD = ((char)decodedChar).ToString ().Normalize (System.Text.NormalizationForm.FormD);
+ for (int i = 0; i < stFormD.Length; i++) {
+ var uc = CharUnicodeInfo.GetUnicodeCategory (stFormD [i]);
+ if (uc != UnicodeCategory.NonSpacingMark && uc != UnicodeCategory.OtherLetter) {
+ consoleKey = char.ToUpper (stFormD [i]);
+ scode = GetScanCode ("VirtualKey", char.ToUpper (stFormD [i]), 0);
+ if (scode != null) {
+ scanCode = scode.ScanCode;
}
}
}
+ }
+ if (keyChar < 255 && consoleKey == 0 && scanCode == 0) {
+ scode = GetScanCode ("VirtualKey", keyChar, mod);
+ if (scode != null) {
+ consoleKey = (uint)scode.VirtualKey;
+ keyChar = scode.UnicodeChar;
+ scanCode = scode.ScanCode;
+ }
+ }
+
+ return keyChar;
+ }
+
+ ///
+ /// Maps a unicode character (e.g. (Key)'a') to a uint representing a .
+ ///
+ /// The key value.
+ /// Indicates if the is a .
+ /// means the return value is in the ConsoleKey enum.
+ /// means the return value can be mapped to a valid unicode character.
+ ///
+ /// The or the .
+ /// This is only used by the and by unit tests.
+ internal static uint MapKeyCodeToConsoleKey (KeyCode keyValue, out bool isConsoleKey)
+ {
+ isConsoleKey = true;
+ keyValue = keyValue & ~KeyCode.CtrlMask & ~KeyCode.ShiftMask & ~KeyCode.AltMask;
+
+ switch (keyValue) {
+ case KeyCode.Enter:
+ return (uint)ConsoleKey.Enter;
+ case KeyCode.CursorUp:
+ return (uint)ConsoleKey.UpArrow;
+ case KeyCode.CursorDown:
+ return (uint)ConsoleKey.DownArrow;
+ case KeyCode.CursorLeft:
+ return (uint)ConsoleKey.LeftArrow;
+ case KeyCode.CursorRight:
+ return (uint)ConsoleKey.RightArrow;
+ case KeyCode.PageUp:
+ return (uint)ConsoleKey.PageUp;
+ case KeyCode.PageDown:
+ return (uint)ConsoleKey.PageDown;
+ case KeyCode.Home:
+ return (uint)ConsoleKey.Home;
+ case KeyCode.End:
+ return (uint)ConsoleKey.End;
+ case KeyCode.Insert:
+ return (uint)ConsoleKey.Insert;
+ case KeyCode.Delete:
+ return (uint)ConsoleKey.Delete;
+ case KeyCode.F1:
+ return (uint)ConsoleKey.F1;
+ case KeyCode.F2:
+ return (uint)ConsoleKey.F2;
+ case KeyCode.F3:
+ return (uint)ConsoleKey.F3;
+ case KeyCode.F4:
+ return (uint)ConsoleKey.F4;
+ case KeyCode.F5:
+ return (uint)ConsoleKey.F5;
+ case KeyCode.F6:
+ return (uint)ConsoleKey.F6;
+ case KeyCode.F7:
+ return (uint)ConsoleKey.F7;
+ case KeyCode.F8:
+ return (uint)ConsoleKey.F8;
+ case KeyCode.F9:
+ return (uint)ConsoleKey.F9;
+ case KeyCode.F10:
+ return (uint)ConsoleKey.F10;
+ case KeyCode.F11:
+ return (uint)ConsoleKey.F11;
+ case KeyCode.F12:
+ return (uint)ConsoleKey.F12;
+ case KeyCode.F13:
+ return (uint)ConsoleKey.F13;
+ case KeyCode.F14:
+ return (uint)ConsoleKey.F14;
+ case KeyCode.F15:
+ return (uint)ConsoleKey.F15;
+ case KeyCode.F16:
+ return (uint)ConsoleKey.F16;
+ case KeyCode.F17:
+ return (uint)ConsoleKey.F17;
+ case KeyCode.F18:
+ return (uint)ConsoleKey.F18;
+ case KeyCode.F19:
+ return (uint)ConsoleKey.F19;
+ case KeyCode.F20:
+ return (uint)ConsoleKey.F20;
+ case KeyCode.F21:
+ return (uint)ConsoleKey.F21;
+ case KeyCode.F22:
+ return (uint)ConsoleKey.F22;
+ case KeyCode.F23:
+ return (uint)ConsoleKey.F23;
+ case KeyCode.F24:
+ return (uint)ConsoleKey.F24;
+ case KeyCode.Tab | KeyCode.ShiftMask:
+ return (uint)ConsoleKey.Tab;
+ }
+
+ isConsoleKey = false;
+ return (uint)keyValue;
+ }
+
+ ///
+ /// Maps a to a .
+ ///
+ /// The console key.
+ /// The or the .
+ public static KeyCode MapConsoleKeyInfoToKeyCode (ConsoleKeyInfo consoleKeyInfo)
+ {
+ KeyCode keyCode;
+
+ switch (consoleKeyInfo.Key) {
+ case ConsoleKey.Enter:
+ keyCode = KeyCode.Enter;
+ break;
+ case ConsoleKey.Delete:
+ keyCode = KeyCode.Delete;
+ break;
+ case ConsoleKey.UpArrow:
+ keyCode = KeyCode.CursorUp;
+ break;
+ case ConsoleKey.DownArrow:
+ keyCode = KeyCode.CursorDown;
+ break;
+ case ConsoleKey.LeftArrow:
+ keyCode = KeyCode.CursorLeft;
+ break;
+ case ConsoleKey.RightArrow:
+ keyCode = KeyCode.CursorRight;
+ break;
+ case ConsoleKey.PageUp:
+ keyCode = KeyCode.PageUp;
+ break;
+ case ConsoleKey.PageDown:
+ keyCode = KeyCode.PageDown;
+ break;
+ case ConsoleKey.Home:
+ keyCode = KeyCode.Home;
+ break;
+ case ConsoleKey.End:
+ keyCode = KeyCode.End;
+ break;
+ case ConsoleKey.Insert:
+ keyCode = KeyCode.Insert;
+ break;
+ case ConsoleKey.F1:
+ keyCode = KeyCode.F1;
+ break;
+ case ConsoleKey.F2:
+ keyCode = KeyCode.F2;
+ break;
+ case ConsoleKey.F3:
+ keyCode = KeyCode.F3;
+ break;
+ case ConsoleKey.F4:
+ keyCode = KeyCode.F4;
+ break;
+ case ConsoleKey.F5:
+ keyCode = KeyCode.F5;
+ break;
+ case ConsoleKey.F6:
+ keyCode = KeyCode.F6;
+ break;
+ case ConsoleKey.F7:
+ keyCode = KeyCode.F7;
+ break;
+ case ConsoleKey.F8:
+ keyCode = KeyCode.F8;
+ break;
+ case ConsoleKey.F9:
+ keyCode = KeyCode.F9;
+ break;
+ case ConsoleKey.F10:
+ keyCode = KeyCode.F10;
+ break;
+ case ConsoleKey.F11:
+ keyCode = KeyCode.F11;
+ break;
+ case ConsoleKey.F12:
+ keyCode = KeyCode.F12;
+ break;
+ case ConsoleKey.F13:
+ keyCode = KeyCode.F13;
+ break;
+ case ConsoleKey.F14:
+ keyCode = KeyCode.F14;
+ break;
+ case ConsoleKey.F15:
+ keyCode = KeyCode.F15;
+ break;
+ case ConsoleKey.F16:
+ keyCode = KeyCode.F16;
+ break;
+ case ConsoleKey.F17:
+ keyCode = KeyCode.F17;
+ break;
+ case ConsoleKey.F18:
+ keyCode = KeyCode.F18;
+ break;
+ case ConsoleKey.F19:
+ keyCode = KeyCode.F19;
+ break;
+ case ConsoleKey.F20:
+ keyCode = KeyCode.F20;
+ break;
+ case ConsoleKey.F21:
+ keyCode = KeyCode.F21;
+ break;
+ case ConsoleKey.F22:
+ keyCode = KeyCode.F22;
+ break;
+ case ConsoleKey.F23:
+ keyCode = KeyCode.F23;
+ break;
+ case ConsoleKey.F24:
+ keyCode = KeyCode.F24;
+ break;
+ case ConsoleKey.Tab:
+ keyCode = KeyCode.Tab;
+ break;
+ default:
+ keyCode = (KeyCode)consoleKeyInfo.KeyChar;
+ break;
+ }
+ keyCode |= MapToKeyCodeModifiers (consoleKeyInfo.Modifiers, keyCode);
+
+ return keyCode;
+ }
- return keyChar;
+ ///
+ /// Maps a to a .
+ ///
+ /// The console modifiers.
+ /// The key code.
+ /// The with or the
+ public static KeyCode MapToKeyCodeModifiers (ConsoleModifiers modifiers, KeyCode key)
+ {
+ var keyMod = new KeyCode ();
+ if ((modifiers & ConsoleModifiers.Shift) != 0) {
+ keyMod = KeyCode.ShiftMask;
+ }
+ if ((modifiers & ConsoleModifiers.Control) != 0) {
+ keyMod |= KeyCode.CtrlMask;
}
+ if ((modifiers & ConsoleModifiers.Alt) != 0) {
+ keyMod |= KeyCode.AltMask;
+ }
+
+ return keyMod != KeyCode.Null ? keyMod | key : key;
+ }
+ ///
+ /// Generated from winuser.h. See https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
+ ///
+ public enum VK : ushort {
///
- /// Maps a unicode character (e.g. (Key)'a') to a uint representing a .
+ /// Left mouse button.
///
- /// The key value.
- /// The modifiers keys.
- ///
- /// means the return value can be mapped to a valid unicode character.
- /// means the return value is in the ConsoleKey enum.
- ///
- /// The or the .
- public static ConsoleKey MapKeyToConsoleKey (KeyCode keyValue, ConsoleModifiers modifiers, out bool isMappable)
- {
- isMappable = false;
-
- switch (keyValue) {
- case KeyCode.Delete:
- return ConsoleKey.Delete;
- case KeyCode.CursorUp:
- return ConsoleKey.UpArrow;
- case KeyCode.CursorDown:
- return ConsoleKey.DownArrow;
- case KeyCode.CursorLeft:
- return ConsoleKey.LeftArrow;
- case KeyCode.CursorRight:
- return ConsoleKey.RightArrow;
- case KeyCode.PageUp:
- return ConsoleKey.PageUp;
- case KeyCode.PageDown:
- return ConsoleKey.PageDown;
- case KeyCode.Home:
- return ConsoleKey.Home;
- case KeyCode.End:
- return ConsoleKey.End;
- case KeyCode.InsertChar:
- return ConsoleKey.Insert;
- case KeyCode.DeleteChar:
- return ConsoleKey.Delete;
- case KeyCode.F1:
- return ConsoleKey.F1;
- case KeyCode.F2:
- return ConsoleKey.F2;
- case KeyCode.F3:
- return ConsoleKey.F3;
- case KeyCode.F4:
- return ConsoleKey.F4;
- case KeyCode.F5:
- return ConsoleKey.F5;
- case KeyCode.F6:
- return ConsoleKey.F6;
- case KeyCode.F7:
- return ConsoleKey.F7;
- case KeyCode.F8:
- return ConsoleKey.F8;
- case KeyCode.F9:
- return ConsoleKey.F9;
- case KeyCode.F10:
- return ConsoleKey.F10;
- case KeyCode.F11:
- return ConsoleKey.F11;
- case KeyCode.F12:
- return ConsoleKey.F12;
- case KeyCode.F13:
- return ConsoleKey.F13;
- case KeyCode.F14:
- return ConsoleKey.F14;
- case KeyCode.F15:
- return ConsoleKey.F15;
- case KeyCode.F16:
- return ConsoleKey.F16;
- case KeyCode.F17:
- return ConsoleKey.F17;
- case KeyCode.F18:
- return ConsoleKey.F18;
- case KeyCode.F19:
- return ConsoleKey.F19;
- case KeyCode.F20:
- return ConsoleKey.F20;
- case KeyCode.F21:
- return ConsoleKey.F21;
- case KeyCode.F22:
- return ConsoleKey.F22;
- case KeyCode.F23:
- return ConsoleKey.F23;
- case KeyCode.F24:
- return ConsoleKey.F24;
- case KeyCode.Tab | KeyCode.ShiftMask:
- return ConsoleKey.Tab;
- }
+ LBUTTON = 0x01,
- isMappable = true;
+ ///
+ /// Right mouse button.
+ ///
+ RBUTTON = 0x02,
- if (modifiers == ConsoleModifiers.Shift && keyValue - 32 is >= KeyCode.A and <= KeyCode.Z) {
- return (ConsoleKey)(keyValue - 32);
- } else if (modifiers == ConsoleModifiers.None && keyValue is >= KeyCode.A and <= KeyCode.Z) {
- return (ConsoleKey)(keyValue + 32);
- }
- if (modifiers == ConsoleModifiers.Shift && keyValue - 32 is >= (KeyCode)'À' and <= (KeyCode)'Ý') {
- return (ConsoleKey)(keyValue - 32);
- } else if (modifiers == ConsoleModifiers.None && keyValue is >= (KeyCode)'À' and <= (KeyCode)'Ý') {
- return (ConsoleKey)(keyValue + 32);
- }
+ ///
+ /// Control-break processing.
+ ///
+ CANCEL = 0x03,
- return (ConsoleKey)keyValue;
- }
+ ///
+ /// Middle mouse button (three-button mouse).
+ ///
+ MBUTTON = 0x04,
///
- /// Maps a to a .
+ /// X1 mouse button.
///
- /// The console key.
- /// If is mapped to a valid character, otherwise .
- /// The or the .
- public static KeyCode MapConsoleKeyToKey (ConsoleKey consoleKey, out bool isMappable)
- {
- isMappable = false;
-
- switch (consoleKey) {
- case ConsoleKey.Delete:
- return KeyCode.Delete;
- case ConsoleKey.UpArrow:
- return KeyCode.CursorUp;
- case ConsoleKey.DownArrow:
- return KeyCode.CursorDown;
- case ConsoleKey.LeftArrow:
- return KeyCode.CursorLeft;
- case ConsoleKey.RightArrow:
- return KeyCode.CursorRight;
- case ConsoleKey.PageUp:
- return KeyCode.PageUp;
- case ConsoleKey.PageDown:
- return KeyCode.PageDown;
- case ConsoleKey.Home:
- return KeyCode.Home;
- case ConsoleKey.End:
- return KeyCode.End;
- case ConsoleKey.Insert:
- return KeyCode.InsertChar;
- case ConsoleKey.F1:
- return KeyCode.F1;
- case ConsoleKey.F2:
- return KeyCode.F2;
- case ConsoleKey.F3:
- return KeyCode.F3;
- case ConsoleKey.F4:
- return KeyCode.F4;
- case ConsoleKey.F5:
- return KeyCode.F5;
- case ConsoleKey.F6:
- return KeyCode.F6;
- case ConsoleKey.F7:
- return KeyCode.F7;
- case ConsoleKey.F8:
- return KeyCode.F8;
- case ConsoleKey.F9:
- return KeyCode.F9;
- case ConsoleKey.F10:
- return KeyCode.F10;
- case ConsoleKey.F11:
- return KeyCode.F11;
- case ConsoleKey.F12:
- return KeyCode.F12;
- case ConsoleKey.F13:
- return KeyCode.F13;
- case ConsoleKey.F14:
- return KeyCode.F14;
- case ConsoleKey.F15:
- return KeyCode.F15;
- case ConsoleKey.F16:
- return KeyCode.F16;
- case ConsoleKey.F17:
- return KeyCode.F17;
- case ConsoleKey.F18:
- return KeyCode.F18;
- case ConsoleKey.F19:
- return KeyCode.F19;
- case ConsoleKey.F20:
- return KeyCode.F20;
- case ConsoleKey.F21:
- return KeyCode.F21;
- case ConsoleKey.F22:
- return KeyCode.F22;
- case ConsoleKey.F23:
- return KeyCode.F23;
- case ConsoleKey.F24:
- return KeyCode.F24;
- case ConsoleKey.Tab:
- return KeyCode.Tab;
- }
- isMappable = true;
+ XBUTTON1 = 0x05,
- if (consoleKey is >= ConsoleKey.A and <= ConsoleKey.Z) {
- return (KeyCode)(consoleKey + 32);
- }
+ ///
+ /// X2 mouse button.
+ ///
+ XBUTTON2 = 0x06,
- return (KeyCode)consoleKey;
- }
+ ///
+ /// BACKSPACE key.
+ ///
+ BACK = 0x08,
///
- /// Maps a to a .
+ /// TAB key.
///
- /// The console key info.
- /// The key.
- /// The with or the
- public static KeyCode MapKeyModifiers (ConsoleKeyInfo keyInfo, KeyCode key)
- {
- var keyMod = new KeyCode ();
- if ((keyInfo.Modifiers & ConsoleModifiers.Shift) != 0) {
- keyMod = KeyCode.ShiftMask;
- }
- if ((keyInfo.Modifiers & ConsoleModifiers.Control) != 0) {
- keyMod |= KeyCode.CtrlMask;
- }
- if ((keyInfo.Modifiers & ConsoleModifiers.Alt) != 0) {
- keyMod |= KeyCode.AltMask;
- }
+ TAB = 0x09,
- return keyMod != KeyCode.Null ? keyMod | key : key;
- }
-
- static HashSet scanCodes = new HashSet {
- new ScanCodeMapping (1, 27, 0, 27), // Escape
- new ScanCodeMapping (1, 27, ConsoleModifiers.Shift, 27),
- new ScanCodeMapping (2, 49, 0, 49), // D1
- new ScanCodeMapping (2, 49, ConsoleModifiers.Shift, 33),
- new ScanCodeMapping (3, 50, 0, 50), // D2
- new ScanCodeMapping (3, 50, ConsoleModifiers.Shift, 34),
- new ScanCodeMapping (3, 50, ConsoleModifiers.Alt | ConsoleModifiers.Control, 64),
- new ScanCodeMapping (4, 51, 0, 51), // D3
- new ScanCodeMapping (4, 51, ConsoleModifiers.Shift, 35),
- new ScanCodeMapping (4, 51, ConsoleModifiers.Alt | ConsoleModifiers.Control, 163),
- new ScanCodeMapping (5, 52, 0, 52), // D4
- new ScanCodeMapping (5, 52, ConsoleModifiers.Shift, 36),
- new ScanCodeMapping (5, 52, ConsoleModifiers.Alt | ConsoleModifiers.Control, 167),
- new ScanCodeMapping (6, 53, 0, 53), // D5
- new ScanCodeMapping (6, 53, ConsoleModifiers.Shift, 37),
- new ScanCodeMapping (6, 53, ConsoleModifiers.Alt | ConsoleModifiers.Control, 8364),
- new ScanCodeMapping (7, 54, 0, 54), // D6
- new ScanCodeMapping (7, 54, ConsoleModifiers.Shift, 38),
- new ScanCodeMapping (8, 55, 0, 55), // D7
- new ScanCodeMapping (8, 55, ConsoleModifiers.Shift, 47),
- new ScanCodeMapping (8, 55, ConsoleModifiers.Alt | ConsoleModifiers.Control, 123),
- new ScanCodeMapping (9, 56, 0, 56), // D8
- new ScanCodeMapping (9, 56, ConsoleModifiers.Shift, 40),
- new ScanCodeMapping (9, 56, ConsoleModifiers.Alt | ConsoleModifiers.Control, 91),
- new ScanCodeMapping (10, 57, 0, 57), // D9
- new ScanCodeMapping (10, 57, ConsoleModifiers.Shift, 41),
- new ScanCodeMapping (10, 57, ConsoleModifiers.Alt | ConsoleModifiers.Control, 93),
- new ScanCodeMapping (11, 48, 0, 48), // D0
- new ScanCodeMapping (11, 48, ConsoleModifiers.Shift, 61),
- new ScanCodeMapping (11, 48, ConsoleModifiers.Alt | ConsoleModifiers.Control, 125),
- new ScanCodeMapping (12, 219, 0, 39), // Oem4
- new ScanCodeMapping (12, 219, ConsoleModifiers.Shift, 63),
- new ScanCodeMapping (13, 221, 0, 171), // Oem6
- new ScanCodeMapping (13, 221, ConsoleModifiers.Shift, 187),
- new ScanCodeMapping (14, 8, 0, 8), // Backspace
- new ScanCodeMapping (14, 8, ConsoleModifiers.Shift, 8),
- new ScanCodeMapping (15, 9, 0, 9), // Tab
- new ScanCodeMapping (15, 9, ConsoleModifiers.Shift, 15),
- new ScanCodeMapping (16, 81, 0, 113), // Q
- new ScanCodeMapping (16, 81, ConsoleModifiers.Shift, 81),
- new ScanCodeMapping (17, 87, 0, 119), // W
- new ScanCodeMapping (17, 87, ConsoleModifiers.Shift, 87),
- new ScanCodeMapping (18, 69, 0, 101), // E
- new ScanCodeMapping (18, 69, ConsoleModifiers.Shift, 69),
- new ScanCodeMapping (19, 82, 0, 114), // R
- new ScanCodeMapping (19, 82, ConsoleModifiers.Shift, 82),
- new ScanCodeMapping (20, 84, 0, 116), // T
- new ScanCodeMapping (20, 84, ConsoleModifiers.Shift, 84),
- new ScanCodeMapping (21, 89, 0, 121), // Y
- new ScanCodeMapping (21, 89, ConsoleModifiers.Shift, 89),
- new ScanCodeMapping (22, 85, 0, 117), // U
- new ScanCodeMapping (22, 85, ConsoleModifiers.Shift, 85),
- new ScanCodeMapping (23, 73, 0, 105), // I
- new ScanCodeMapping (23, 73, ConsoleModifiers.Shift, 73),
- new ScanCodeMapping (24, 79, 0, 111), // O
- new ScanCodeMapping (24, 79, ConsoleModifiers.Shift, 79),
- new ScanCodeMapping (25, 80, 0, 112), // P
- new ScanCodeMapping (25, 80, ConsoleModifiers.Shift, 80),
- new ScanCodeMapping (26, 187, 0, 43), // OemPlus
- new ScanCodeMapping (26, 187, ConsoleModifiers.Shift, 42),
- new ScanCodeMapping (26, 187, ConsoleModifiers.Alt | ConsoleModifiers.Control, 168),
- new ScanCodeMapping (27, 186, 0, 180), // Oem1
- new ScanCodeMapping (27, 186, ConsoleModifiers.Shift, 96),
- new ScanCodeMapping (28, 13, 0, 13), // Enter
- new ScanCodeMapping (28, 13, ConsoleModifiers.Shift, 13),
- new ScanCodeMapping (29, 17, 0, 0), // Control
- new ScanCodeMapping (29, 17, ConsoleModifiers.Shift, 0),
- new ScanCodeMapping (scanCode: 30, virtualKey: 65, modifiers: 0, unicodeChar: 97), // VK = A, UC = 'a'
- new ScanCodeMapping (30, 65, ConsoleModifiers.Shift, 65), // VK = A | Shift, UC = 'A'
- new ScanCodeMapping (31, 83, 0, 115), // S
- new ScanCodeMapping (31, 83, ConsoleModifiers.Shift, 83),
- new ScanCodeMapping (32, 68, 0, 100), // D
- new ScanCodeMapping (32, 68, ConsoleModifiers.Shift, 68),
- new ScanCodeMapping (33, 70, 0, 102), // F
- new ScanCodeMapping (33, 70, ConsoleModifiers.Shift, 70),
- new ScanCodeMapping (34, 71, 0, 103), // G
- new ScanCodeMapping (34, 71, ConsoleModifiers.Shift, 71),
- new ScanCodeMapping (35, 72, 0, 104), // H
- new ScanCodeMapping (35, 72, ConsoleModifiers.Shift, 72),
- new ScanCodeMapping (36, 74, 0, 106), // J
- new ScanCodeMapping (36, 74, ConsoleModifiers.Shift, 74),
- new ScanCodeMapping (37, 75, 0, 107), // K
- new ScanCodeMapping (37, 75, ConsoleModifiers.Shift, 75),
- new ScanCodeMapping (38, 76, 0, 108), // L
- new ScanCodeMapping (38, 76, ConsoleModifiers.Shift, 76),
- new ScanCodeMapping (39, 192, 0, 231), // Oem3
- new ScanCodeMapping (39, 192, ConsoleModifiers.Shift, 199),
- new ScanCodeMapping (40, 222, 0, 186), // Oem7
- new ScanCodeMapping (40, 222, ConsoleModifiers.Shift, 170),
- new ScanCodeMapping (41, 220, 0, 92), // Oem5
- new ScanCodeMapping (41, 220, ConsoleModifiers.Shift, 124),
- new ScanCodeMapping (42, 16, 0, 0), // LShift
- new ScanCodeMapping (42, 16, ConsoleModifiers.Shift, 0),
- new ScanCodeMapping (43, 191, 0, 126), // Oem2
- new ScanCodeMapping (43, 191, ConsoleModifiers.Shift, 94),
- new ScanCodeMapping (44, 90, 0, 122), // Z
- new ScanCodeMapping (44, 90, ConsoleModifiers.Shift, 90),
- new ScanCodeMapping (45, 88, 0, 120), // X
- new ScanCodeMapping (45, 88, ConsoleModifiers.Shift, 88),
- new ScanCodeMapping (46, 67, 0, 99), // C
- new ScanCodeMapping (46, 67, ConsoleModifiers.Shift, 67),
- new ScanCodeMapping (47, 86, 0, 118), // V
- new ScanCodeMapping (47, 86, ConsoleModifiers.Shift, 86),
- new ScanCodeMapping (48, 66, 0, 98), // B
- new ScanCodeMapping (48, 66, ConsoleModifiers.Shift, 66),
- new ScanCodeMapping (49, 78, 0, 110), // N
- new ScanCodeMapping (49, 78, ConsoleModifiers.Shift, 78),
- new ScanCodeMapping (50, 77, 0, 109), // M
- new ScanCodeMapping (50, 77, ConsoleModifiers.Shift, 77),
- new ScanCodeMapping (51, 188, 0, 44), // OemComma
- new ScanCodeMapping (51, 188, ConsoleModifiers.Shift, 59),
- new ScanCodeMapping (52, 190, 0, 46), // OemPeriod
- new ScanCodeMapping (52, 190, ConsoleModifiers.Shift, 58),
- new ScanCodeMapping (53, 189, 0, 45), // OemMinus
- new ScanCodeMapping (53, 189, ConsoleModifiers.Shift, 95),
- new ScanCodeMapping (54, 16, 0, 0), // RShift
- new ScanCodeMapping (54, 16, ConsoleModifiers.Shift, 0),
- new ScanCodeMapping (55, 44, 0, 0), // PrintScreen
- new ScanCodeMapping (55, 44, ConsoleModifiers.Shift, 0),
- new ScanCodeMapping (56, 18, 0, 0), // Alt
- new ScanCodeMapping (56, 18, ConsoleModifiers.Shift, 0),
- new ScanCodeMapping (57, 32, 0, 32), // Spacebar
- new ScanCodeMapping (57, 32, ConsoleModifiers.Shift, 32),
- new ScanCodeMapping (58, 20, 0, 0), // Caps
- new ScanCodeMapping (58, 20, ConsoleModifiers.Shift, 0),
- new ScanCodeMapping (59, 112, 0, 0), // F1
- new ScanCodeMapping (59, 112, ConsoleModifiers.Shift, 0),
- new ScanCodeMapping (60, 113, 0, 0), // F2
- new ScanCodeMapping (60, 113, ConsoleModifiers.Shift, 0),
- new ScanCodeMapping (61, 114, 0, 0), // F3
- new ScanCodeMapping (61, 114, ConsoleModifiers.Shift, 0),
- new ScanCodeMapping (62, 115, 0, 0), // F4
- new ScanCodeMapping (62, 115, ConsoleModifiers.Shift, 0),
- new ScanCodeMapping (63, 116, 0, 0), // F5
- new ScanCodeMapping (63, 116, ConsoleModifiers.Shift, 0),
- new ScanCodeMapping (64, 117, 0, 0), // F6
- new ScanCodeMapping (64, 117, ConsoleModifiers.Shift, 0),
- new ScanCodeMapping (65, 118, 0, 0), // F7
- new ScanCodeMapping (65, 118, ConsoleModifiers.Shift, 0),
- new ScanCodeMapping (66, 119, 0, 0), // F8
- new ScanCodeMapping (66, 119, ConsoleModifiers.Shift, 0),
- new ScanCodeMapping (67, 120, 0, 0), // F9
- new ScanCodeMapping (67, 120, ConsoleModifiers.Shift, 0),
- new ScanCodeMapping (68, 121, 0, 0), // F10
- new ScanCodeMapping (68, 121, ConsoleModifiers.Shift, 0),
- new ScanCodeMapping (69, 144, 0, 0), // Num
- new ScanCodeMapping (69, 144, ConsoleModifiers.Shift, 0),
- new ScanCodeMapping (70, 145, 0, 0), // Scroll
- new ScanCodeMapping (70, 145, ConsoleModifiers.Shift, 0),
- new ScanCodeMapping (71, 36, 0, 0), // Home
- new ScanCodeMapping (71, 36, ConsoleModifiers.Shift, 0),
- new ScanCodeMapping (72, 38, 0, 0), // UpArrow
- new ScanCodeMapping (72, 38, ConsoleModifiers.Shift, 0),
- new ScanCodeMapping (73, 33, 0, 0), // PageUp
- new ScanCodeMapping (73, 33, ConsoleModifiers.Shift, 0),
- new ScanCodeMapping (74, 109, 0, 45), // Subtract
- new ScanCodeMapping (74, 109, ConsoleModifiers.Shift, 45),
- new ScanCodeMapping (75, 37, 0, 0), // LeftArrow
- new ScanCodeMapping (75, 37, ConsoleModifiers.Shift, 0),
- new ScanCodeMapping (76, 12, 0, 0), // Center
- new ScanCodeMapping (76, 12, ConsoleModifiers.Shift, 0),
- new ScanCodeMapping (77, 39, 0, 0), // RightArrow
- new ScanCodeMapping (77, 39, ConsoleModifiers.Shift, 0),
- new ScanCodeMapping (78, 107, 0, 43), // Add
- new ScanCodeMapping (78, 107, ConsoleModifiers.Shift, 43),
- new ScanCodeMapping (79, 35, 0, 0), // End
- new ScanCodeMapping (79, 35, ConsoleModifiers.Shift, 0),
- new ScanCodeMapping (80, 40, 0, 0), // DownArrow
- new ScanCodeMapping (80, 40, ConsoleModifiers.Shift, 0),
- new ScanCodeMapping (81, 34, 0, 0), // PageDown
- new ScanCodeMapping (81, 34, ConsoleModifiers.Shift, 0),
- new ScanCodeMapping (82, 45, 0, 0), // Insert
- new ScanCodeMapping (82, 45, ConsoleModifiers.Shift, 0),
- new ScanCodeMapping (83, 46, 0, 0), // Delete
- new ScanCodeMapping (83, 46, ConsoleModifiers.Shift, 0),
- new ScanCodeMapping (86, 226, 0, 60), // OEM 102
- new ScanCodeMapping (86, 226, ConsoleModifiers.Shift, 62),
- new ScanCodeMapping (87, 122, 0, 0), // F11
- new ScanCodeMapping (87, 122, ConsoleModifiers.Shift, 0),
- new ScanCodeMapping (88, 123, 0, 0), // F12
- new ScanCodeMapping (88, 123, ConsoleModifiers.Shift, 0)
- };
-
- ///
- /// Decode a that is using .
- ///
- /// The console key info.
- /// The decoded or the .
- /// If it's a the may be
- /// a or a value.
- ///
- public static ConsoleKeyInfo FromVKPacketToKConsoleKeyInfo (ConsoleKeyInfo consoleKeyInfo)
- {
- if (consoleKeyInfo.Key != ConsoleKey.Packet) {
- return consoleKeyInfo;
- }
+ ///
+ /// CLEAR key.
+ ///
+ CLEAR = 0x0C,
- return GetConsoleKeyFromKey (consoleKeyInfo.KeyChar, consoleKeyInfo.Modifiers, out _);
- }
+ ///
+ /// ENTER key.
+ ///
+ RETURN = 0x0D,
+
+ ///
+ /// SHIFT key.
+ ///
+ SHIFT = 0x10,
+
+ ///
+ /// CTRL key.
+ ///
+ CONTROL = 0x11,
+
+ ///
+ /// ALT key.
+ ///
+ MENU = 0x12,
+
+ ///
+ /// PAUSE key.
+ ///
+ PAUSE = 0x13,
+
+ ///
+ /// CAPS LOCK key.
+ ///
+ CAPITAL = 0x14,
+
+ ///
+ /// IME Kana mode.
+ ///
+ KANA = 0x15,
+
+ ///
+ /// IME Hangul mode.
+ ///
+ HANGUL = 0x15,
+
+ ///
+ /// IME Junja mode.
+ ///
+ JUNJA = 0x17,
+
+ ///
+ /// IME final mode.
+ ///
+ FINAL = 0x18,
+
+ ///
+ /// IME Hanja mode.
+ ///
+ HANJA = 0x19,
+
+ ///
+ /// IME Kanji mode.
+ ///
+ KANJI = 0x19,
+
+ ///
+ /// ESC key.
+ ///
+ ESCAPE = 0x1B,
+
+ ///
+ /// IME convert.
+ ///
+ CONVERT = 0x1C,
+
+ ///
+ /// IME nonconvert.
+ ///
+ NONCONVERT = 0x1D,
+
+ ///
+ /// IME accept.
+ ///
+ ACCEPT = 0x1E,
+
+ ///
+ /// IME mode change request.
+ ///
+ MODECHANGE = 0x1F,
+
+ ///
+ /// SPACEBAR.
+ ///
+ SPACE = 0x20,
+
+ ///
+ /// PAGE UP key.
+ ///
+ PRIOR = 0x21,
+
+ ///
+ /// PAGE DOWN key.
+ ///
+ NEXT = 0x22,
+
+ ///
+ /// END key.
+ ///
+ END = 0x23,
+
+ ///
+ /// HOME key.
+ ///
+ HOME = 0x24,
+
+ ///
+ /// LEFT ARROW key.
+ ///
+ LEFT = 0x25,
+
+ ///
+ /// UP ARROW key.
+ ///
+ UP = 0x26,
+
+ ///
+ /// RIGHT ARROW key.
+ ///
+ RIGHT = 0x27,
+
+ ///
+ /// DOWN ARROW key.
+ ///
+ DOWN = 0x28,
+
+ ///
+ /// SELECT key.
+ ///
+ SELECT = 0x29,
+
+ ///
+ /// PRINT key.
+ ///
+ PRINT = 0x2A,
+
+ ///
+ /// EXECUTE key
+ ///
+ EXECUTE = 0x2B,
+
+ ///
+ /// PRINT SCREEN key
+ ///
+ SNAPSHOT = 0x2C,
+
+ ///
+ /// INS key
+ ///
+ INSERT = 0x2D,
+
+ ///
+ /// DEL key
+ ///
+ DELETE = 0x2E,
+
+ ///
+ /// HELP key
+ ///
+ HELP = 0x2F,
+
+ ///
+ /// Left Windows key (Natural keyboard)
+ ///
+ LWIN = 0x5B,
+
+ ///
+ /// Right Windows key (Natural keyboard)
+ ///
+ RWIN = 0x5C,
+
+ ///
+ /// Applications key (Natural keyboard)
+ ///
+ APPS = 0x5D,
+
+ ///
+ /// Computer Sleep key
+ ///
+ SLEEP = 0x5F,
+
+ ///
+ /// Numeric keypad 0 key
+ ///
+ NUMPAD0 = 0x60,
+
+ ///
+ /// Numeric keypad 1 key
+ ///
+ NUMPAD1 = 0x61,
+
+ ///
+ /// Numeric keypad 2 key
+ ///
+ NUMPAD2 = 0x62,
+
+ ///
+ /// Numeric keypad 3 key
+ ///
+ NUMPAD3 = 0x63,
+
+ ///
+ /// Numeric keypad 4 key
+ ///
+ NUMPAD4 = 0x64,
+
+ ///
+ /// Numeric keypad 5 key
+ ///
+ NUMPAD5 = 0x65,
+
+ ///
+ /// Numeric keypad 6 key
+ ///
+ NUMPAD6 = 0x66,
+
+ ///
+ /// Numeric keypad 7 key
+ ///
+ NUMPAD7 = 0x67,
+
+ ///
+ /// Numeric keypad 8 key
+ ///
+ NUMPAD8 = 0x68,
+
+ ///
+ /// Numeric keypad 9 key
+ ///
+ NUMPAD9 = 0x69,
+
+ ///
+ /// Multiply key
+ ///
+ MULTIPLY = 0x6A,
+
+ ///
+ /// Add key
+ ///
+ ADD = 0x6B,
+
+ ///
+ /// Separator key
+ ///
+ SEPARATOR = 0x6C,
+
+ ///
+ /// Subtract key
+ ///
+ SUBTRACT = 0x6D,
+
+ ///
+ /// Decimal key
+ ///
+ DECIMAL = 0x6E,
+
+ ///
+ /// Divide key
+ ///
+ DIVIDE = 0x6F,
+
+ ///
+ /// F1 key
+ ///
+ F1 = 0x70,
+
+ ///
+ /// F2 key
+ ///
+ F2 = 0x71,
+
+ ///
+ /// F3 key
+ ///
+ F3 = 0x72,
+
+ ///
+ /// F4 key
+ ///
+ F4 = 0x73,
+
+ ///
+ /// F5 key
+ ///
+ F5 = 0x74,
+
+ ///
+ /// F6 key
+ ///
+ F6 = 0x75,
+
+ ///
+ /// F7 key
+ ///
+ F7 = 0x76,
+
+ ///
+ /// F8 key
+ ///
+ F8 = 0x77,
+
+ ///
+ /// F9 key
+ ///
+ F9 = 0x78,
+
+ ///
+ /// F10 key
+ ///
+ F10 = 0x79,
+
+ ///
+ /// F11 key
+ ///
+ F11 = 0x7A,
+
+ ///
+ /// F12 key
+ ///
+ F12 = 0x7B,
+
+ ///
+ /// F13 key
+ ///
+ F13 = 0x7C,
+
+ ///
+ /// F14 key
+ ///
+ F14 = 0x7D,
+
+ ///
+ /// F15 key
+ ///
+ F15 = 0x7E,
+
+ ///
+ /// F16 key
+ ///
+ F16 = 0x7F,
+
+ ///
+ /// F17 key
+ ///
+ F17 = 0x80,
+
+ ///
+ /// F18 key
+ ///
+ F18 = 0x81,
+
+ ///
+ /// F19 key
+ ///
+ F19 = 0x82,
+
+ ///
+ /// F20 key
+ ///
+ F20 = 0x83,
+
+ ///
+ /// F21 key
+ ///
+ F21 = 0x84,
+
+ ///
+ /// F22 key
+ ///
+ F22 = 0x85,
+
+ ///
+ /// F23 key
+ ///
+ F23 = 0x86,
+
+ ///
+ /// F24 key
+ ///
+ F24 = 0x87,
+
+ ///
+ /// NUM LOCK key
+ ///
+ NUMLOCK = 0x90,
+
+ ///
+ /// SCROLL LOCK key
+ ///
+ SCROLL = 0x91,
+
+ ///
+ /// NEC PC-9800 kbd definition: '=' key on numpad
+ ///
+ OEM_NEC_EQUAL = 0x92,
+
+ ///
+ /// Fujitsu/OASYS kbd definition: 'Dictionary' key
+ ///
+ OEM_FJ_JISHO = 0x92,
+
+ ///
+ /// Fujitsu/OASYS kbd definition: 'Unregister word' key
+ ///
+ OEM_FJ_MASSHOU = 0x93,
+
+ ///
+ /// Fujitsu/OASYS kbd definition: 'Register word' key
+ ///
+ OEM_FJ_TOUROKU = 0x94,
+
+ ///
+ /// Fujitsu/OASYS kbd definition: 'Left OYAYUBI' key
+ ///
+ OEM_FJ_LOYA = 0x95,
+
+ ///
+ /// Fujitsu/OASYS kbd definition: 'Right OYAYUBI' key
+ ///
+ OEM_FJ_ROYA = 0x96,
+
+ ///
+ /// Left SHIFT key
+ ///
+ LSHIFT = 0xA0,
+
+ ///
+ /// Right SHIFT key
+ ///
+ RSHIFT = 0xA1,
+
+ ///
+ /// Left CONTROL key
+ ///
+ LCONTROL = 0xA2,
+
+ ///
+ /// Right CONTROL key
+ ///
+ RCONTROL = 0xA3,
+
+ ///
+ /// Left MENU key (Left Alt key)
+ ///
+ LMENU = 0xA4,
+
+ ///
+ /// Right MENU key (Right Alt key)
+ ///
+ RMENU = 0xA5,
+
+ ///
+ /// Browser Back key
+ ///
+ BROWSER_BACK = 0xA6,
+
+ ///
+ /// Browser Forward key
+ ///
+ BROWSER_FORWARD = 0xA7,
+
+ ///
+ /// Browser Refresh key
+ ///
+ BROWSER_REFRESH = 0xA8,
+
+ ///
+ /// Browser Stop key
+ ///
+ BROWSER_STOP = 0xA9,
+
+ ///
+ /// Browser Search key
+ ///
+ BROWSER_SEARCH = 0xAA,
+
+ ///
+ /// Browser Favorites key
+ ///
+ BROWSER_FAVORITES = 0xAB,
+
+ ///
+ /// Browser Home key
+ ///
+ BROWSER_HOME = 0xAC,
+
+ ///
+ /// Volume Mute key
+ ///
+ VOLUME_MUTE = 0xAD,
+
+ ///
+ /// Volume Down key
+ ///
+ VOLUME_DOWN = 0xAE,
+
+ ///
+ /// Volume Up key
+ ///
+ VOLUME_UP = 0xAF,
+
+ ///
+ /// Next Track key
+ ///
+ MEDIA_NEXT_TRACK = 0xB0,
+
+ ///
+ /// Previous Track key
+ ///
+ MEDIA_PREV_TRACK = 0xB1,
+
+ ///
+ /// Stop Media key
+ ///
+ MEDIA_STOP = 0xB2,
+
+ ///
+ /// Play/Pause Media key
+ ///
+ MEDIA_PLAY_PAUSE = 0xB3,
+
+ ///
+ /// Start Mail key
+ ///
+ LAUNCH_MAIL = 0xB4,
+
+ ///
+ /// Select Media key
+ ///
+ LAUNCH_MEDIA_SELECT = 0xB5,
+
+ ///
+ /// Start Application 1 key
+ ///
+ LAUNCH_APP1 = 0xB6,
+
+ ///
+ /// Start Application 2 key
+ ///
+ LAUNCH_APP2 = 0xB7,
+
+ ///
+ /// Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the ';:' key
+ ///
+ OEM_1 = 0xBA,
+
+ ///
+ /// For any country/region, the '+' key
+ ///
+ OEM_PLUS = 0xBB,
+
+ ///
+ /// For any country/region, the ',' key
+ ///
+ OEM_COMMA = 0xBC,
+
+ ///
+ /// For any country/region, the '-' key
+ ///
+ OEM_MINUS = 0xBD,
+
+ ///
+ /// For any country/region, the '.' key
+ ///
+ OEM_PERIOD = 0xBE,
+
+ ///
+ /// Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the '/?' key
+ ///
+ OEM_2 = 0xBF,
+
+ ///
+ /// Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the '`~' key
+ ///
+ OEM_3 = 0xC0,
+
+ ///
+ /// Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the '[{' key
+ ///
+ OEM_4 = 0xDB,
+
+ ///
+ /// Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the '\|' key
+ ///
+ OEM_5 = 0xDC,
+
+ ///
+ /// Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the ']}' key
+ ///
+ OEM_6 = 0xDD,
+
+ ///
+ /// Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the 'single-quote/double-quote' key
+ ///
+ OEM_7 = 0xDE,
+
+ ///
+ /// Used for miscellaneous characters; it can vary by keyboard.
+ ///
+ OEM_8 = 0xDF,
+
+ ///
+ /// 'AX' key on Japanese AX kbd
+ ///
+ OEM_AX = 0xE1,
+
+ ///
+ /// Either the angle bracket key or the backslash key on the RT 102-key keyboard
+ ///
+ OEM_102 = 0xE2,
+
+ ///
+ /// Help key on ICO
+ ///
+ ICO_HELP = 0xE3,
+
+ ///
+ /// 00 key on ICO
+ ///
+ ICO_00 = 0xE4,
+
+ ///
+ /// Process key
+ ///
+ PROCESSKEY = 0xE5,
+
+ ///
+ /// Clear key on ICO
+ ///
+ ICO_CLEAR = 0xE6,
+
+ ///
+ /// Packet key to be used to pass Unicode characters as if they were keystrokes
+ ///
+ PACKET = 0xE7,
+
+ ///
+ /// Reset key
+ ///
+ OEM_RESET = 0xE9,
+
+ ///
+ /// Jump key
+ ///
+ OEM_JUMP = 0xEA,
+
+ ///
+ /// PA1 key
+ ///
+ OEM_PA1 = 0xEB,
+
+ ///
+ /// PA2 key
+ ///
+ OEM_PA2 = 0xEC,
+
+ ///
+ /// PA3 key
+ ///
+ OEM_PA3 = 0xED,
+
+ ///
+ /// WsCtrl key
+ ///
+ OEM_WSCTRL = 0xEE,
+
+ ///
+ /// CuSel key
+ ///
+ OEM_CUSEL = 0xEF,
+
+ ///
+ /// Attn key
+ ///
+ OEM_ATTN = 0xF0,
+
+ ///
+ /// Finish key
+ ///
+ OEM_FINISH = 0xF1,
+
+ ///
+ /// Copy key
+ ///
+ OEM_COPY = 0xF2,
+
+ ///
+ /// Auto key
+ ///
+ OEM_AUTO = 0xF3,
+
+ ///
+ /// Enlw key
+ ///
+ OEM_ENLW = 0xF4,
+
+ ///
+ /// BackTab key
+ ///
+ OEM_BACKTAB = 0xF5,
+
+ ///
+ /// Attn key
+ ///
+ ATTN = 0xF6,
+
+ ///
+ /// CrSel key
+ ///
+ CRSEL = 0xF7,
+
+ ///
+ /// ExSel key
+ ///
+ EXSEL = 0xF8,
+
+ ///
+ /// Erase EOF key
+ ///
+ EREOF = 0xF9,
+
+ ///
+ /// Play key
+ ///
+ PLAY = 0xFA,
+
+ ///
+ /// Zoom key
+ ///
+ ZOOM = 0xFB,
+
+ ///
+ /// Reserved
+ ///
+ NONAME = 0xFC,
+
+ ///
+ /// PA1 key
+ ///
+ PA1 = 0xFD,
+
+ ///
+ /// Clear key
+ ///
+ OEM_CLEAR = 0xFE
+ }
+
+ // BUGBUG: This database makes no sense. It is not possible to map a VK code to a character without knowing the keyboard layout
+ // It should be deleted.
+ static HashSet _scanCodes = new HashSet {
+ new (1, VK.ESCAPE, 0, '\u001B'), // Escape
+ new (1, VK.ESCAPE, ConsoleModifiers.Shift, '\u001B'),
+ new (2, (VK)'1', 0, '1'), // D1
+ new (2, (VK)'1', ConsoleModifiers.Shift, '!'),
+ new (3, (VK)'2', 0, '2'), // D2
+ new (3, (VK)'2', ConsoleModifiers.Shift, '\"'), // BUGBUG: This is true for Portugese keyboard, but not ENG (@) or DEU (")
+ new (3, (VK)'2', ConsoleModifiers.Alt | ConsoleModifiers.Control, '@'),
+ new (4, (VK)'3', 0, '3'), // D3
+ new (4, (VK)'3', ConsoleModifiers.Shift, '#'),
+ new (4, (VK)'3', ConsoleModifiers.Alt | ConsoleModifiers.Control, '£'),
+ new (5, (VK)'4', 0, '4'), // D4
+ new (5, (VK)'4', ConsoleModifiers.Shift, '$'),
+ new (5, (VK)'4', ConsoleModifiers.Alt | ConsoleModifiers.Control, '§'),
+ new (6, (VK)'5', 0, '5'), // D5
+ new (6, (VK)'5', ConsoleModifiers.Shift, '%'),
+ new (6, (VK)'5', ConsoleModifiers.Alt | ConsoleModifiers.Control, '€'),
+ new (7, (VK)'6', 0, '6'), // D6
+ new (7, (VK)'6', ConsoleModifiers.Shift, '&'),
+ new (8, (VK)'7', 0, '7'), // D7
+ new (8, (VK)'7', ConsoleModifiers.Shift, '/'),
+ new (8, (VK)'7', ConsoleModifiers.Alt | ConsoleModifiers.Control, '{'),
+ new (9, (VK)'8', 0, '8'), // D8
+ new (9, (VK)'8', ConsoleModifiers.Shift, '('),
+ new (9, (VK)'8', ConsoleModifiers.Alt | ConsoleModifiers.Control, '['),
+ new (10, (VK)'9', 0, '9'), // D9
+ new (10, (VK)'9', ConsoleModifiers.Shift, ')'),
+ new (10, (VK)'9', ConsoleModifiers.Alt | ConsoleModifiers.Control, ']'),
+ new (11, (VK)'0', 0, '0'), // D0
+ new (11, (VK)'0', ConsoleModifiers.Shift, '='),
+ new (11, (VK)'0', ConsoleModifiers.Alt | ConsoleModifiers.Control, '}'),
+ new (12, VK.OEM_4, 0, '\''), // Oem4
+ new (12, VK.OEM_4, ConsoleModifiers.Shift, '?'),
+ new (13, VK.OEM_6, 0, '+'), // Oem6
+ new (13, VK.OEM_6, ConsoleModifiers.Shift, '*'),
+ new (14, VK.BACK, 0, '\u0008'), // Backspace
+ new (14, VK.BACK, ConsoleModifiers.Shift, '\u0008'),
+ new (15, VK.TAB, 0, '\u0009'), // Tab
+ new (15, VK.TAB, ConsoleModifiers.Shift, '\u000F'),
+ new (16, (VK)'Q', 0, 'q'), // Q
+ new (16, (VK)'Q', ConsoleModifiers.Shift, 'Q'),
+ new (17, (VK)'W', 0, 'w'), // W
+ new (17, (VK)'W', ConsoleModifiers.Shift, 'W'),
+ new (18, (VK)'E', 0, 'e'), // E
+ new (18, (VK)'E', ConsoleModifiers.Shift, 'E'),
+ new (19, (VK)'R', 0, 'r'), // R
+ new (19, (VK)'R', ConsoleModifiers.Shift, 'R'),
+ new (20, (VK)'T', 0, 't'), // T
+ new (20, (VK)'T', ConsoleModifiers.Shift, 'T'),
+ new (21, (VK)'Y', 0, 'y'), // Y
+ new (21, (VK)'Y', ConsoleModifiers.Shift, 'Y'),
+ new (22, (VK)'U', 0, 'u'), // U
+ new (22, (VK)'U', ConsoleModifiers.Shift, 'U'),
+ new (23, (VK)'I', 0, 'i'), // I
+ new (23, (VK)'I', ConsoleModifiers.Shift, 'I'),
+ new (24, (VK)'O', 0, 'o'), // O
+ new (24, (VK)'O', ConsoleModifiers.Shift, 'O'),
+ new (25, (VK)'P', 0, 'p'), // P
+ new (25, (VK)'P', ConsoleModifiers.Shift, 'P'),
+ new (26, VK.OEM_PLUS, 0, '+'), // OemPlus
+ new (26, VK.OEM_PLUS, ConsoleModifiers.Shift, '*'),
+ new (26, VK.OEM_PLUS, ConsoleModifiers.Alt | ConsoleModifiers.Control, '¨'),
+ new (27, VK.OEM_1, 0, '´'), // Oem1
+ new (27, VK.OEM_1, ConsoleModifiers.Shift, '`'),
+ new (28, VK.RETURN, 0, '\u000D'), // Enter
+ new (28, VK.RETURN, ConsoleModifiers.Shift, '\u000D'),
+ new (29, VK.CONTROL, 0, '\0'), // Control
+ new (29, VK.CONTROL, ConsoleModifiers.Shift, '\0'),
+ new (30, (VK)'A', 0, 'a'), // A
+ new (30, (VK)'A', ConsoleModifiers.Shift, 'A'),
+ new (31, (VK)'S', 0, 's'), // S
+ new (31, (VK)'S', ConsoleModifiers.Shift, 'S'),
+ new (32, (VK)'D', 0, 'd'), // D
+ new (32, (VK)'D', ConsoleModifiers.Shift, 'D'),
+ new (33, (VK)'F', 0, 'f'), // F
+ new (33, (VK)'F', ConsoleModifiers.Shift, 'F'),
+ new (34, (VK)'G', 0, 'g'), // G
+ new (34, (VK)'G', ConsoleModifiers.Shift, 'G'),
+ new (35, (VK)'H', 0, 'h'), // H
+ new (35, (VK)'H', ConsoleModifiers.Shift, 'H'),
+ new (36, (VK)'J', 0, 'j'), // J
+ new (36, (VK)'J', ConsoleModifiers.Shift, 'J'),
+ new (37, (VK)'K', 0, 'k'), // K
+ new (37, (VK)'K', ConsoleModifiers.Shift, 'K'),
+ new (38, (VK)'L', 0, 'l'), // L
+ new (38, (VK)'L', ConsoleModifiers.Shift, 'L'),
+ new (39, VK.OEM_3, 0, '`'), // Oem3 (Backtick/Grave)
+ new (39, VK.OEM_3, ConsoleModifiers.Shift, '~'),
+ new (40, VK.OEM_7, 0, '\''), // Oem7 (Single Quote)
+ new (40, VK.OEM_7, ConsoleModifiers.Shift, '\"'),
+ new (41, VK.OEM_5, 0, '\\'), // Oem5 (Backslash)
+ new (41, VK.OEM_5, ConsoleModifiers.Shift, '|'),
+ new (42, VK.LSHIFT, 0, '\0'), // Left Shift
+ new (42, VK.LSHIFT, ConsoleModifiers.Shift, '\0'),
+ new (43, VK.OEM_2, 0, '/'), // Oem2 (Forward Slash)
+ new (43, VK.OEM_2, ConsoleModifiers.Shift, '?'),
+ new (44, (VK)'Z', 0, 'z'), // Z
+ new (44, (VK)'Z', ConsoleModifiers.Shift, 'Z'),
+ new (45, (VK)'X', 0, 'x'), // X
+ new (45, (VK)'X', ConsoleModifiers.Shift, 'X'),
+ new (46, (VK)'C', 0, 'c'), // C
+ new (46, (VK)'C', ConsoleModifiers.Shift, 'C'),
+ new (47, (VK)'V', 0, 'v'), // V
+ new (47, (VK)'V', ConsoleModifiers.Shift, 'V'),
+ new (48, (VK)'B', 0, 'b'), // B
+ new (48, (VK)'B', ConsoleModifiers.Shift, 'B'),
+ new (49, (VK)'N', 0, 'n'), // N
+ new (49, (VK)'N', ConsoleModifiers.Shift, 'N'),
+ new (50, (VK)'M', 0, 'm'), // M
+ new (50, (VK)'M', ConsoleModifiers.Shift, 'M'),
+ new (51, VK.OEM_COMMA, 0, ','), // OemComma
+ new (51, VK.OEM_COMMA, ConsoleModifiers.Shift, '<'),
+ new (52, VK.OEM_PERIOD, 0, '.'), // OemPeriod
+ new (52, VK.OEM_PERIOD, ConsoleModifiers.Shift, '>'),
+ new (53, VK.OEM_MINUS, 0, '-'), // OemMinus
+ new (53, VK.OEM_MINUS, ConsoleModifiers.Shift, '_'),
+ new (54, VK.RSHIFT, 0, '\0'), // Right Shift
+ new (54, VK.RSHIFT, ConsoleModifiers.Shift, '\0'),
+ new (55, VK.PRINT, 0, '\0'), // Print Screen
+ new (55, VK.PRINT, ConsoleModifiers.Shift, '\0'),
+ new (56, VK.LMENU, 0, '\0'), // Alt
+ new (56, VK.LMENU, ConsoleModifiers.Shift, '\0'),
+ new (57, VK.SPACE, 0, ' '), // Spacebar
+ new (57, VK.SPACE, ConsoleModifiers.Shift, ' '),
+ new (58, VK.CAPITAL, 0, '\0'), // Caps Lock
+ new (58, VK.CAPITAL, ConsoleModifiers.Shift, '\0'),
+ new (59, VK.F1, 0, '\0'), // F1
+ new (59, VK.F1, ConsoleModifiers.Shift, '\0'),
+ new (60, VK.F2, 0, '\0'), // F2
+ new (60, VK.F2, ConsoleModifiers.Shift, '\0'),
+ new (61, VK.F3, 0, '\0'), // F3
+ new (61, VK.F3, ConsoleModifiers.Shift, '\0'),
+ new (62, VK.F4, 0, '\0'), // F4
+ new (62, VK.F4, ConsoleModifiers.Shift, '\0'),
+ new (63, VK.F5, 0, '\0'), // F5
+ new (63, VK.F5, ConsoleModifiers.Shift, '\0'),
+ new (64, VK.F6, 0, '\0'), // F6
+ new (64, VK.F6, ConsoleModifiers.Shift, '\0'),
+ new (65, VK.F7, 0, '\0'), // F7
+ new (65, VK.F7, ConsoleModifiers.Shift, '\0'),
+ new (66, VK.F8, 0, '\0'), // F8
+ new (66, VK.F8, ConsoleModifiers.Shift, '\0'),
+ new (67, VK.F9, 0, '\0'), // F9
+ new (67, VK.F9, ConsoleModifiers.Shift, '\0'),
+ new (68, VK.F10, 0, '\0'), // F10
+ new (68, VK.F10, ConsoleModifiers.Shift, '\0'),
+ new (69, VK.NUMLOCK, 0, '\0'), // Num Lock
+ new (69, VK.NUMLOCK, ConsoleModifiers.Shift, '\0'),
+ new (70, VK.SCROLL, 0, '\0'), // Scroll Lock
+ new (70, VK.SCROLL, ConsoleModifiers.Shift, '\0'),
+ new (71, VK.HOME, 0, '\0'), // Home
+ new (71, VK.HOME, ConsoleModifiers.Shift, '\0'),
+ new (72, VK.UP, 0, '\0'), // Up Arrow
+ new (72, VK.UP, ConsoleModifiers.Shift, '\0'),
+ new (73, VK.PRIOR, 0, '\0'), // Page Up
+ new (73, VK.PRIOR, ConsoleModifiers.Shift, '\0'),
+ new (74, VK.SUBTRACT, 0, '-'), // Subtract (Num Pad '-')
+ new (74, VK.SUBTRACT, ConsoleModifiers.Shift, '-'),
+ new (75, VK.LEFT, 0, '\0'), // Left Arrow
+ new (75, VK.LEFT, ConsoleModifiers.Shift, '\0'),
+ new (76, VK.CLEAR, 0, '\0'), // Center key (Num Pad 5 with Num Lock off)
+ new (76, VK.CLEAR, ConsoleModifiers.Shift, '\0'),
+ new (77, VK.RIGHT, 0, '\0'), // Right Arrow
+ new (77, VK.RIGHT, ConsoleModifiers.Shift, '\0'),
+ new (78, VK.ADD, 0, '+'), // Add (Num Pad '+')
+ new (78, VK.ADD, ConsoleModifiers.Shift, '+'),
+ new (79, VK.END, 0, '\0'), // End
+ new (79, VK.END, ConsoleModifiers.Shift, '\0'),
+ new (80, VK.DOWN, 0, '\0'), // Down Arrow
+ new (80, VK.DOWN, ConsoleModifiers.Shift, '\0'),
+ new (81, VK.NEXT, 0, '\0'), // Page Down
+ new (81, VK.NEXT, ConsoleModifiers.Shift, '\0'),
+ new (82, VK.INSERT, 0, '\0'), // Insert
+ new (82, VK.INSERT, ConsoleModifiers.Shift, '\0'),
+ new (83, VK.DELETE, 0, '\0'), // Delete
+ new (83, VK.DELETE, ConsoleModifiers.Shift, '\0'),
+ new (86, VK.OEM_102, 0, '<'), // OEM 102 (Typically '<' or '|' key next to Left Shift)
+ new (86, VK.OEM_102, ConsoleModifiers.Shift, '>'),
+ new (87, VK.F11, 0, '\0'), // F11
+ new (87, VK.F11, ConsoleModifiers.Shift, '\0'),
+ new (88, VK.F12, 0, '\0'), // F12
+ new (88, VK.F12, ConsoleModifiers.Shift, '\0')
+ };
+
+ ///
+ /// Decode a that is using .
+ ///
+ /// The console key info.
+ /// The decoded or the .
+ /// If it's a the may be
+ /// a or a value.
+ ///
+ public static ConsoleKeyInfo DecodeVKPacketToKConsoleKeyInfo (ConsoleKeyInfo consoleKeyInfo)
+ {
+ if (consoleKeyInfo.Key != ConsoleKey.Packet) {
+ return consoleKeyInfo;
+ }
+
+ return GetConsoleKeyInfoFromKeyChar (consoleKeyInfo.KeyChar, consoleKeyInfo.Modifiers, out _);
+ }
+
+ ///
+ /// Encode the with the
+ /// if the first a byte length, otherwise only the KeyChar is considered and searched on the database.
+ ///
+ /// The console key info.
+ /// The encoded KeyChar with the Key if both can be shifted, otherwise only the KeyChar.
+ /// This is useful to use with the .
+ public static char EncodeKeyCharForVKPacket (ConsoleKeyInfo consoleKeyInfo)
+ {
+ char keyChar = consoleKeyInfo.KeyChar;
+ ConsoleKey consoleKey = consoleKeyInfo.Key;
+ if (keyChar != 0 && consoleKeyInfo.KeyChar < byte.MaxValue && consoleKey == ConsoleKey.None) {
+ // try to get the ConsoleKey
+ var scode = _scanCodes.FirstOrDefault ((e) => e.UnicodeChar == keyChar);
+ if (scode != null) {
+ consoleKey = (ConsoleKey)scode.VirtualKey;
+ }
+ }
+ if (keyChar < byte.MaxValue && consoleKey != ConsoleKey.None) {
+ keyChar = (char)(consoleKeyInfo.KeyChar << 8 | (byte)consoleKey);
+ }
+
+ return keyChar;
}
-}
\ No newline at end of file
+}
diff --git a/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs b/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs
index 5c39cadc61..c0b3db7daa 100644
--- a/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs
+++ b/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs
@@ -14,12 +14,12 @@ namespace Terminal.Gui;
///
/// This is the Curses driver for the gui.cs/Terminal framework.
///
-internal class CursesDriver : ConsoleDriver {
-
+class CursesDriver : ConsoleDriver {
public override int Cols {
get => Curses.Cols;
internal set => Curses.Cols = value;
}
+
public override int Rows {
get => Curses.Lines;
internal set => Curses.Lines = value;
@@ -30,6 +30,7 @@ public override int Rows {
public override string GetVersionInfo () => $"{Curses.curses_version ()}";
UnixMainLoop _mainLoopDriver = null;
+
public override bool SupportsTrueColor => false;
object _processInputToken;
@@ -132,11 +133,9 @@ public override void Move (int col, int row)
}
}
- public override bool IsRuneSupported (Rune rune)
- {
+ public override bool IsRuneSupported (Rune rune) =>
// See Issue #2615 - CursesDriver is broken with non-BMP characters
- return base.IsRuneSupported (rune) && rune.IsBmp;
- }
+ base.IsRuneSupported (rune) && rune.IsBmp;
public override void Refresh ()
{
@@ -153,7 +152,6 @@ internal void ProcessWinChange ()
}
#region Color Handling
-
///
/// Creates an Attribute from the provided curses-based foreground and background color numbers
///
@@ -162,16 +160,17 @@ internal void ProcessWinChange ()
///
static Attribute MakeColor (short foreground, short background)
{
- var v = (short)((int)foreground | background << 4);
+ short v = (short)((int)foreground | background << 4);
// TODO: for TrueColor - Use InitExtendedPair
Curses.InitColorPair (v, foreground, background);
return new Attribute (
- platformColor: Curses.ColorPair (v),
- foreground: CursesColorNumberToColorName (foreground),
- background: CursesColorNumberToColorName (background));
+ Curses.ColorPair (v),
+ CursesColorNumberToColorName (foreground),
+ CursesColorNumberToColorName (background));
}
+ ///
///
/// In the CursesDriver, colors are encoded as an int.
/// The foreground color is stored in the most significant 4 bits,
@@ -184,9 +183,9 @@ public override Attribute MakeColor (Color foreground, Color background)
return MakeColor (ColorNameToCursesColorNumber (foreground.ColorName), ColorNameToCursesColorNumber (background.ColorName));
} else {
return new Attribute (
- platformColor: 0,
- foreground: foreground,
- background: background);
+ 0,
+ foreground,
+ background);
}
}
@@ -267,7 +266,6 @@ static ColorName CursesColorNumberToColorName (short color)
}
throw new ArgumentException ("Invalid curses color code");
}
-
#endregion
public override void UpdateCursor ()
@@ -367,8 +365,8 @@ static KeyCode MapCursesKey (int cursesKey)
case Curses.KeyEnd: return KeyCode.End;
case Curses.KeyNPage: return KeyCode.PageDown;
case Curses.KeyPPage: return KeyCode.PageUp;
- case Curses.KeyDeleteChar: return KeyCode.DeleteChar;
- case Curses.KeyInsertChar: return KeyCode.InsertChar;
+ case Curses.KeyDeleteChar: return KeyCode.Delete;
+ case Curses.KeyInsertChar: return KeyCode.Insert;
case Curses.KeyTab: return KeyCode.Tab;
case Curses.KeyBackTab: return KeyCode.Tab | KeyCode.ShiftMask;
case Curses.KeyBackspace: return KeyCode.Backspace;
@@ -423,12 +421,12 @@ static KeyCode MapCursesKey (int cursesKey)
internal void ProcessInput ()
{
int wch;
- var code = Curses.get_wch (out wch);
+ int code = Curses.get_wch (out wch);
//System.Diagnostics.Debug.WriteLine ($"code: {code}; wch: {wch}");
if (code == Curses.ERR) {
return;
}
- KeyCode k = KeyCode.Null;
+ var k = KeyCode.Null;
if (code == Curses.KEY_CODE_YES) {
while (code == Curses.KEY_CODE_YES && wch == Curses.KeyResize) {
@@ -443,11 +441,11 @@ internal void ProcessInput ()
while (wch2 == Curses.KeyMouse) {
Key kea = null;
- ConsoleKeyInfo [] cki = new ConsoleKeyInfo [] {
- new ConsoleKeyInfo ((char)KeyCode.Esc, 0, false, false, false),
- new ConsoleKeyInfo ('[', 0, false, false, false),
- new ConsoleKeyInfo ('<', 0, false, false, false)
- };
+ var cki = new ConsoleKeyInfo [] {
+ new ((char)KeyCode.Esc, 0, false, false, false),
+ new ('[', 0, false, false, false),
+ new ('<', 0, false, false, false)
+ };
code = 0;
HandleEscSeqResponse (ref code, ref k, ref wch2, ref kea, ref cki);
}
@@ -503,27 +501,27 @@ internal void ProcessInput ()
} else if (wch2 >= (uint)KeyCode.D0 && wch2 <= (uint)KeyCode.D9) {
k = (KeyCode)((uint)KeyCode.AltMask + (uint)KeyCode.D0 + (wch2 - (uint)KeyCode.D0));
} else if (wch2 == Curses.KeyCSI) {
- ConsoleKeyInfo [] cki = new ConsoleKeyInfo [] {
- new ConsoleKeyInfo ((char)KeyCode.Esc, 0, false, false, false),
- new ConsoleKeyInfo ('[', 0, false, false, false)
- };
+ var cki = new ConsoleKeyInfo [] {
+ new ((char)KeyCode.Esc, 0, false, false, false),
+ new ('[', 0, false, false, false)
+ };
HandleEscSeqResponse (ref code, ref k, ref wch2, ref key, ref cki);
return;
} else {
// Unfortunately there are no way to differentiate Ctrl+Alt+alfa and Ctrl+Shift+Alt+alfa.
if (((KeyCode)wch2 & KeyCode.CtrlMask) != 0) {
- k = (KeyCode)((uint)KeyCode.CtrlMask + (wch2 & ~((int)KeyCode.CtrlMask)));
+ k = (KeyCode)((uint)KeyCode.CtrlMask + (wch2 & ~(int)KeyCode.CtrlMask));
}
if (wch2 == 0) {
k = KeyCode.CtrlMask | KeyCode.AltMask | KeyCode.Space;
} else if (wch >= (uint)KeyCode.A && wch <= (uint)KeyCode.Z) {
k = KeyCode.ShiftMask | KeyCode.AltMask | KeyCode.Space;
} else if (wch2 < 256) {
- k = (KeyCode)wch2 | KeyCode.AltMask;
+ k = (KeyCode)wch2;// | KeyCode.AltMask;
} else {
k = (KeyCode)((uint)(KeyCode.AltMask | KeyCode.CtrlMask) + wch2);
}
- }
+ }
key = new Key (k);
} else {
key = new Key (KeyCode.Esc);
@@ -545,9 +543,11 @@ internal void ProcessInput ()
}
} else if (wch >= (uint)KeyCode.A && wch <= (uint)KeyCode.Z) {
k = (KeyCode)wch | KeyCode.ShiftMask;
- } else if (wch <= 'z') {
- k = (KeyCode)wch & ~KeyCode.Space;
}
+
+ if (wch == '\n' || wch == '\r') {
+ k = KeyCode.Enter;
+ }
OnKeyDown (new Key (k));
OnKeyUp (new Key (k));
}
@@ -561,7 +561,7 @@ void HandleEscSeqResponse (ref int code, ref KeyCode k, ref int wch2, ref Key ke
code = Curses.get_wch (out wch2);
var consoleKeyInfo = new ConsoleKeyInfo ((char)wch2, 0, false, false, false);
if (wch2 == 0 || wch2 == 27 || wch2 == Curses.KeyMouse) {
- EscSeqUtils.DecodeEscSeq (null, ref consoleKeyInfo, ref ck, cki, ref mod, out _, out _, out _, out _, out bool isKeyMouse, out List mouseFlags, out Point pos, out _, ProcessMouseEvent);
+ EscSeqUtils.DecodeEscSeq (null, ref consoleKeyInfo, ref ck, cki, ref mod, out _, out _, out _, out _, out bool isKeyMouse, out var mouseFlags, out var pos, out _, ProcessMouseEvent);
if (isKeyMouse) {
foreach (var mf in mouseFlags) {
ProcessMouseEvent (mf, pos);
@@ -572,9 +572,8 @@ void HandleEscSeqResponse (ref int code, ref KeyCode k, ref int wch2, ref Key ke
false, false, false), cki);
}
} else {
- k = ConsoleKeyMapping.MapConsoleKeyToKey (consoleKeyInfo.Key, out _);
- k = ConsoleKeyMapping.MapKeyModifiers (consoleKeyInfo, k);
- keyEventArgs = new (k);
+ k = ConsoleKeyMapping.MapConsoleKeyInfoToKeyCode (consoleKeyInfo);
+ keyEventArgs = new Key (k);
OnKeyDown (keyEventArgs);
}
} else {
@@ -587,36 +586,27 @@ void HandleEscSeqResponse (ref int code, ref KeyCode k, ref int wch2, ref Key ke
void ProcessMouseEvent (MouseFlags mouseFlag, Point pos)
{
- bool WasButtonReleased (MouseFlags flag)
- {
- return flag.HasFlag (MouseFlags.Button1Released) ||
- flag.HasFlag (MouseFlags.Button2Released) ||
- flag.HasFlag (MouseFlags.Button3Released) ||
- flag.HasFlag (MouseFlags.Button4Released);
- }
-
- bool IsButtonNotPressed (MouseFlags flag)
- {
- return !flag.HasFlag (MouseFlags.Button1Pressed) &&
- !flag.HasFlag (MouseFlags.Button2Pressed) &&
- !flag.HasFlag (MouseFlags.Button3Pressed) &&
- !flag.HasFlag (MouseFlags.Button4Pressed);
- }
-
- bool IsButtonClickedOrDoubleClicked (MouseFlags flag)
- {
- return flag.HasFlag (MouseFlags.Button1Clicked) ||
- flag.HasFlag (MouseFlags.Button2Clicked) ||
- flag.HasFlag (MouseFlags.Button3Clicked) ||
- flag.HasFlag (MouseFlags.Button4Clicked) ||
- flag.HasFlag (MouseFlags.Button1DoubleClicked) ||
- flag.HasFlag (MouseFlags.Button2DoubleClicked) ||
- flag.HasFlag (MouseFlags.Button3DoubleClicked) ||
- flag.HasFlag (MouseFlags.Button4DoubleClicked);
- }
-
- if ((WasButtonReleased (mouseFlag) && IsButtonNotPressed (_lastMouseFlags)) ||
- (IsButtonClickedOrDoubleClicked (mouseFlag) && _lastMouseFlags == 0)) {
+ bool WasButtonReleased (MouseFlags flag) => flag.HasFlag (MouseFlags.Button1Released) ||
+ flag.HasFlag (MouseFlags.Button2Released) ||
+ flag.HasFlag (MouseFlags.Button3Released) ||
+ flag.HasFlag (MouseFlags.Button4Released);
+
+ bool IsButtonNotPressed (MouseFlags flag) => !flag.HasFlag (MouseFlags.Button1Pressed) &&
+ !flag.HasFlag (MouseFlags.Button2Pressed) &&
+ !flag.HasFlag (MouseFlags.Button3Pressed) &&
+ !flag.HasFlag (MouseFlags.Button4Pressed);
+
+ bool IsButtonClickedOrDoubleClicked (MouseFlags flag) => flag.HasFlag (MouseFlags.Button1Clicked) ||
+ flag.HasFlag (MouseFlags.Button2Clicked) ||
+ flag.HasFlag (MouseFlags.Button3Clicked) ||
+ flag.HasFlag (MouseFlags.Button4Clicked) ||
+ flag.HasFlag (MouseFlags.Button1DoubleClicked) ||
+ flag.HasFlag (MouseFlags.Button2DoubleClicked) ||
+ flag.HasFlag (MouseFlags.Button3DoubleClicked) ||
+ flag.HasFlag (MouseFlags.Button4DoubleClicked);
+
+ if (WasButtonReleased (mouseFlag) && IsButtonNotPressed (_lastMouseFlags) ||
+ IsButtonClickedOrDoubleClicked (mouseFlag) && _lastMouseFlags == 0) {
return;
}
@@ -638,7 +628,7 @@ public static bool Is_WSL_Platform ()
// // If xclip is installed on Linux under WSL, this will return true.
// return false;
//}
- var (exitCode, result) = ClipboardProcessRunner.Bash ("uname -a", waitForOutput: true);
+ (int exitCode, string result) = ClipboardProcessRunner.Bash ("uname -a", waitForOutput: true);
if (exitCode == 0 && result.Contains ("microsoft") && result.Contains ("WSL")) {
return true;
}
@@ -675,8 +665,9 @@ public override bool GetCursorVisibility (out CursorVisibility visibility)
{
visibility = CursorVisibility.Invisible;
- if (!_currentCursorVisibility.HasValue)
+ if (!_currentCursorVisibility.HasValue) {
return false;
+ }
visibility = _currentCursorVisibility.Value;
@@ -691,11 +682,11 @@ public override bool SetCursorVisibility (CursorVisibility visibility)
}
if (!RunningUnitTests) {
- Curses.curs_set (((int)visibility >> 16) & 0x000000FF);
+ Curses.curs_set ((int)visibility >> 16 & 0x000000FF);
}
if (visibility != CursorVisibility.Invisible) {
- Console.Out.Write (EscSeqUtils.CSI_SetCursorStyle ((EscSeqUtils.DECSCUSR_Style)(((int)visibility >> 24) & 0xFF)));
+ Console.Out.Write (EscSeqUtils.CSI_SetCursorStyle ((EscSeqUtils.DECSCUSR_Style)((int)visibility >> 24 & 0xFF)));
}
_currentCursorVisibility = visibility;
@@ -704,17 +695,14 @@ public override bool SetCursorVisibility (CursorVisibility visibility)
}
///
- public override bool EnsureCursorVisibility ()
- {
- return false;
- }
+ public override bool EnsureCursorVisibility () => false;
public override void SendKeys (char keyChar, ConsoleKey consoleKey, bool shift, bool alt, bool control)
{
KeyCode key;
if (consoleKey == ConsoleKey.Packet) {
- ConsoleModifiers mod = new ConsoleModifiers ();
+ var mod = new ConsoleModifiers ();
if (shift) {
mod |= ConsoleModifiers.Shift;
}
@@ -724,11 +712,9 @@ public override void SendKeys (char keyChar, ConsoleKey consoleKey, bool shift,
if (control) {
mod |= ConsoleModifiers.Control;
}
- var cKeyInfo = ConsoleKeyMapping.GetConsoleKeyFromKey (keyChar, mod, out _);
- key = ConsoleKeyMapping.MapConsoleKeyToKey ((ConsoleKey)cKeyInfo.Key, out bool mappable);
- if (mappable) {
- key = (KeyCode)cKeyInfo.KeyChar;
- }
+ var cKeyInfo = new ConsoleKeyInfo (keyChar, consoleKey, shift, alt, control);
+ cKeyInfo = ConsoleKeyMapping.DecodeVKPacketToKConsoleKeyInfo (cKeyInfo);
+ key = ConsoleKeyMapping.MapConsoleKeyInfoToKeyCode (cKeyInfo);
} else {
key = (KeyCode)keyChar;
}
@@ -737,16 +723,14 @@ public override void SendKeys (char keyChar, ConsoleKey consoleKey, bool shift,
OnKeyUp (new Key (key));
//OnKeyPressed (new KeyEventArgsEventArgs (key));
}
-
-
}
-internal static class Platform {
+static class Platform {
[DllImport ("libc")]
- static extern int uname (IntPtr buf);
+ extern static int uname (IntPtr buf);
[DllImport ("libc")]
- static extern int killpg (int pgrp, int pid);
+ extern static int killpg (int pgrp, int pid);
static int _suspendSignal;
@@ -793,7 +777,7 @@ static int GetSuspendSignal ()
/// Suspends the process by sending SIGTSTP to itself
///
/// The suspend.
- static public bool Suspend ()
+ public static bool Suspend ()
{
int signal = GetSuspendSignal ();
if (signal == -1) {
diff --git a/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeConsole.cs b/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeConsole.cs
index 4cec5cb019..5828f96c94 100644
--- a/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeConsole.cs
+++ b/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeConsole.cs
@@ -800,7 +800,7 @@ public static void PushMockKeyPress (KeyCode key)
{
MockKeyPresses.Push (new ConsoleKeyInfo (
(char)(key & ~KeyCode.CtrlMask & ~KeyCode.ShiftMask & ~KeyCode.AltMask),
- ConsoleKeyMapping.GetConsoleKeyFromKey (key).Key,
+ ConsoleKeyMapping.GetConsoleKeyInfoFromKeyCode (key).Key,
key.HasFlag (KeyCode.ShiftMask),
key.HasFlag (KeyCode.AltMask),
key.HasFlag (KeyCode.CtrlMask)));
diff --git a/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs b/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs
index 30ee5b5a4b..74a57dd805 100644
--- a/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs
+++ b/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs
@@ -205,39 +205,39 @@ KeyCode MapKey (ConsoleKeyInfo keyInfo)
{
switch (keyInfo.Key) {
case ConsoleKey.Escape:
- return ConsoleKeyMapping.MapKeyModifiers (keyInfo, KeyCode.Esc);
+ return ConsoleKeyMapping.MapToKeyCodeModifiers (keyInfo.Modifiers, KeyCode.Esc);
case ConsoleKey.Tab:
- return ConsoleKeyMapping.MapKeyModifiers (keyInfo, KeyCode.Tab);
+ return ConsoleKeyMapping.MapToKeyCodeModifiers (keyInfo.Modifiers, KeyCode.Tab);
case ConsoleKey.Clear:
- return ConsoleKeyMapping.MapKeyModifiers (keyInfo, KeyCode.Clear);
+ return ConsoleKeyMapping.MapToKeyCodeModifiers (keyInfo.Modifiers, KeyCode.Clear);
case ConsoleKey.Home:
- return ConsoleKeyMapping.MapKeyModifiers (keyInfo, KeyCode.Home);
+ return ConsoleKeyMapping.MapToKeyCodeModifiers (keyInfo.Modifiers, KeyCode.Home);
case ConsoleKey.End:
- return ConsoleKeyMapping.MapKeyModifiers (keyInfo, KeyCode.End);
+ return ConsoleKeyMapping.MapToKeyCodeModifiers (keyInfo.Modifiers, KeyCode.End);
case ConsoleKey.LeftArrow:
- return ConsoleKeyMapping.MapKeyModifiers (keyInfo, KeyCode.CursorLeft);
+ return ConsoleKeyMapping.MapToKeyCodeModifiers (keyInfo.Modifiers, KeyCode.CursorLeft);
case ConsoleKey.RightArrow:
- return ConsoleKeyMapping.MapKeyModifiers (keyInfo, KeyCode.CursorRight);
+ return ConsoleKeyMapping.MapToKeyCodeModifiers (keyInfo.Modifiers, KeyCode.CursorRight);
case ConsoleKey.UpArrow:
- return ConsoleKeyMapping.MapKeyModifiers (keyInfo, KeyCode.CursorUp);
+ return ConsoleKeyMapping.MapToKeyCodeModifiers (keyInfo.Modifiers, KeyCode.CursorUp);
case ConsoleKey.DownArrow:
- return ConsoleKeyMapping.MapKeyModifiers (keyInfo, KeyCode.CursorDown);
+ return ConsoleKeyMapping.MapToKeyCodeModifiers (keyInfo.Modifiers, KeyCode.CursorDown);
case ConsoleKey.PageUp:
- return ConsoleKeyMapping.MapKeyModifiers (keyInfo, KeyCode.PageUp);
+ return ConsoleKeyMapping.MapToKeyCodeModifiers (keyInfo.Modifiers, KeyCode.PageUp);
case ConsoleKey.PageDown:
- return ConsoleKeyMapping.MapKeyModifiers (keyInfo, KeyCode.PageDown);
+ return ConsoleKeyMapping.MapToKeyCodeModifiers (keyInfo.Modifiers, KeyCode.PageDown);
case ConsoleKey.Enter:
- return ConsoleKeyMapping.MapKeyModifiers (keyInfo, KeyCode.Enter);
+ return ConsoleKeyMapping.MapToKeyCodeModifiers (keyInfo.Modifiers, KeyCode.Enter);
case ConsoleKey.Spacebar:
- return ConsoleKeyMapping.MapKeyModifiers (keyInfo, keyInfo.KeyChar == 0 ? KeyCode.Space : (KeyCode)keyInfo.KeyChar);
+ return ConsoleKeyMapping.MapToKeyCodeModifiers (keyInfo.Modifiers, keyInfo.KeyChar == 0 ? KeyCode.Space : (KeyCode)keyInfo.KeyChar);
case ConsoleKey.Backspace:
- return ConsoleKeyMapping.MapKeyModifiers (keyInfo, KeyCode.Backspace);
+ return ConsoleKeyMapping.MapToKeyCodeModifiers (keyInfo.Modifiers, KeyCode.Backspace);
case ConsoleKey.Delete:
- return ConsoleKeyMapping.MapKeyModifiers (keyInfo, KeyCode.DeleteChar);
+ return ConsoleKeyMapping.MapToKeyCodeModifiers (keyInfo.Modifiers, KeyCode.Delete);
case ConsoleKey.Insert:
- return ConsoleKeyMapping.MapKeyModifiers (keyInfo, KeyCode.InsertChar);
+ return ConsoleKeyMapping.MapToKeyCodeModifiers (keyInfo.Modifiers, KeyCode.Insert);
case ConsoleKey.PrintScreen:
- return ConsoleKeyMapping.MapKeyModifiers (keyInfo, KeyCode.PrintScreen);
+ return ConsoleKeyMapping.MapToKeyCodeModifiers (keyInfo.Modifiers, KeyCode.PrintScreen);
case ConsoleKey.Oem1:
case ConsoleKey.Oem2:
@@ -256,25 +256,25 @@ KeyCode MapKey (ConsoleKeyInfo keyInfo)
return KeyCode.Null;
}
- return ConsoleKeyMapping.MapKeyModifiers (keyInfo, (KeyCode)((uint)keyInfo.KeyChar));
+ return ConsoleKeyMapping.MapToKeyCodeModifiers (keyInfo.Modifiers, (KeyCode)((uint)keyInfo.KeyChar));
}
var key = keyInfo.Key;
if (key >= ConsoleKey.A && key <= ConsoleKey.Z) {
var delta = key - ConsoleKey.A;
if (keyInfo.KeyChar != (uint)key) {
- return ConsoleKeyMapping.MapKeyModifiers (keyInfo, (KeyCode)keyInfo.KeyChar);
+ return ConsoleKeyMapping.MapToKeyCodeModifiers (keyInfo.Modifiers, (KeyCode)keyInfo.KeyChar);
}
if (keyInfo.Modifiers.HasFlag (ConsoleModifiers.Control)
|| keyInfo.Modifiers.HasFlag (ConsoleModifiers.Alt)
|| keyInfo.Modifiers.HasFlag (ConsoleModifiers.Shift)) {
- return ConsoleKeyMapping.MapKeyModifiers (keyInfo, (KeyCode)((uint)KeyCode.A + delta));
+ return ConsoleKeyMapping.MapToKeyCodeModifiers (keyInfo.Modifiers, (KeyCode)((uint)KeyCode.A + delta));
}
var alphaBase = ((keyInfo.Modifiers != ConsoleModifiers.Shift)) ? 'A' : 'a';
return (KeyCode)((uint)alphaBase + delta);
}
- return ConsoleKeyMapping.MapKeyModifiers (keyInfo, (KeyCode)((uint)keyInfo.KeyChar));
+ return ConsoleKeyMapping.MapToKeyCodeModifiers (keyInfo.Modifiers, (KeyCode)((uint)keyInfo.KeyChar));
}
private CursorVisibility _savedCursorVisibility;
@@ -282,7 +282,7 @@ KeyCode MapKey (ConsoleKeyInfo keyInfo)
void MockKeyPressedHandler (ConsoleKeyInfo consoleKeyInfo)
{
if (consoleKeyInfo.Key == ConsoleKey.Packet) {
- consoleKeyInfo = ConsoleKeyMapping.FromVKPacketToKConsoleKeyInfo (consoleKeyInfo);
+ consoleKeyInfo = ConsoleKeyMapping.DecodeVKPacketToKConsoleKeyInfo (consoleKeyInfo);
}
var map = MapKey (consoleKeyInfo);
diff --git a/Terminal.Gui/ConsoleDrivers/NetDriver.cs b/Terminal.Gui/ConsoleDrivers/NetDriver.cs
index 5aaff3439c..58eae6264f 100644
--- a/Terminal.Gui/ConsoleDrivers/NetDriver.cs
+++ b/Terminal.Gui/ConsoleDrivers/NetDriver.cs
@@ -7,13 +7,15 @@
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
+using System.Text;
using System.Threading;
using System.Threading.Tasks;
-using System.Text;
-using Terminal.Gui.ConsoleDrivers;
+using static Terminal.Gui.ConsoleDrivers.ConsoleKeyMapping;
using static Terminal.Gui.NetEvents;
+using static Terminal.Gui.WindowsConsole;
namespace Terminal.Gui;
+
class NetWinVTConsole {
IntPtr _inputHandle, _outputHandle, _errorHandle;
uint _originalInputConsoleMode, _originalOutputConsoleMode, _originalErrorConsoleMode;
@@ -49,7 +51,7 @@ public NetWinVTConsole ()
throw new ApplicationException ($"Failed to get error console mode, error code: {GetLastError ()}.");
}
_originalErrorConsoleMode = mode;
- if ((mode & (DISABLE_NEWLINE_AUTO_RETURN)) < DISABLE_NEWLINE_AUTO_RETURN) {
+ if ((mode & DISABLE_NEWLINE_AUTO_RETURN) < DISABLE_NEWLINE_AUTO_RETURN) {
mode |= DISABLE_NEWLINE_AUTO_RETURN;
if (!SetConsoleMode (_errorHandle, mode)) {
throw new ApplicationException ($"Failed to set error console mode, error code: {GetLastError ()}.");
@@ -93,28 +95,28 @@ public void Cleanup ()
const uint ENABLE_LVB_GRID_WORLDWIDE = 10;
[DllImport ("kernel32.dll", SetLastError = true)]
- static extern IntPtr GetStdHandle (int nStdHandle);
+ extern static IntPtr GetStdHandle (int nStdHandle);
[DllImport ("kernel32.dll")]
- static extern bool GetConsoleMode (IntPtr hConsoleHandle, out uint lpMode);
+ extern static bool GetConsoleMode (IntPtr hConsoleHandle, out uint lpMode);
[DllImport ("kernel32.dll")]
- static extern bool SetConsoleMode (IntPtr hConsoleHandle, uint dwMode);
+ extern static bool SetConsoleMode (IntPtr hConsoleHandle, uint dwMode);
[DllImport ("kernel32.dll")]
- static extern uint GetLastError ();
+ extern static uint GetLastError ();
}
-internal class NetEvents : IDisposable {
- readonly ManualResetEventSlim _inputReady = new ManualResetEventSlim (false);
+class NetEvents : IDisposable {
+ readonly ManualResetEventSlim _inputReady = new (false);
CancellationTokenSource _inputReadyCancellationTokenSource;
- readonly ManualResetEventSlim _waitForStart = new ManualResetEventSlim (false);
+ readonly ManualResetEventSlim _waitForStart = new (false);
//CancellationTokenSource _waitForStartCancellationTokenSource;
- readonly ManualResetEventSlim _winChange = new ManualResetEventSlim (false);
+ readonly ManualResetEventSlim _winChange = new (false);
- readonly Queue _inputQueue = new Queue ();
+ readonly Queue _inputQueue = new ();
readonly ConsoleDriver _consoleDriver;
ConsoleKeyInfo [] _cki;
@@ -123,7 +125,7 @@ internal class NetEvents : IDisposable {
#if PROCESS_REQUEST
bool _neededProcessRequest;
#endif
- public EscSeqRequests EscSeqRequests { get; } = new EscSeqRequests ();
+ public EscSeqRequests EscSeqRequests { get; } = new ();
public NetEvents (ConsoleDriver consoleDriver)
{
@@ -209,17 +211,19 @@ void ProcessInputQueue ()
} catch (OperationCanceledException) {
return;
}
- if ((consoleKeyInfo.KeyChar == (char)KeyCode.Esc && !_isEscSeq)
- || (consoleKeyInfo.KeyChar != (char)KeyCode.Esc && _isEscSeq)) {
+ if (consoleKeyInfo.KeyChar == (char)KeyCode.Esc && !_isEscSeq
+ || consoleKeyInfo.KeyChar != (char)KeyCode.Esc && _isEscSeq) {
if (_cki == null && consoleKeyInfo.KeyChar != (char)KeyCode.Esc && _isEscSeq) {
_cki = EscSeqUtils.ResizeArray (new ConsoleKeyInfo ((char)KeyCode.Esc, 0,
- false, false, false), _cki);
+ false, false, false), _cki);
}
_isEscSeq = true;
newConsoleKeyInfo = consoleKeyInfo;
_cki = EscSeqUtils.ResizeArray (consoleKeyInfo, _cki);
- if (Console.KeyAvailable) continue;
+ if (Console.KeyAvailable) {
+ continue;
+ }
ProcessRequestResponse (ref newConsoleKeyInfo, ref key, _cki, ref mod);
_cki = null;
_isEscSeq = false;
@@ -270,10 +274,10 @@ void RequestWindowSize (CancellationToken cancellationToken)
buffWidth = _consoleDriver.Cols;
}
if (EnqueueWindowSizeEvent (
- Math.Max (Console.WindowHeight, 0),
- Math.Max (Console.WindowWidth, 0),
- buffHeight,
- buffWidth)) {
+ Math.Max (Console.WindowHeight, 0),
+ Math.Max (Console.WindowWidth, 0),
+ buffHeight,
+ buffWidth)) {
return;
}
@@ -306,9 +310,11 @@ void RequestWindowSize (CancellationToken cancellationToken)
///
bool EnqueueWindowSizeEvent (int winHeight, int winWidth, int buffHeight, int buffWidth)
{
- if (winWidth == _consoleDriver.Cols && winHeight == _consoleDriver.Rows) return false;
- var w = Math.Max (winWidth, 0);
- var h = Math.Max (winHeight, 0);
+ if (winWidth == _consoleDriver.Cols && winHeight == _consoleDriver.Rows) {
+ return false;
+ }
+ int w = Math.Max (winWidth, 0);
+ int h = Math.Max (winHeight, 0);
_inputQueue.Enqueue (new InputResult () {
EventType = EventType.WindowSize,
WindowSizeEvent = new WindowSizeEvent () {
@@ -323,10 +329,10 @@ void ProcessRequestResponse (ref ConsoleKeyInfo newConsoleKeyInfo, ref ConsoleKe
{
// isMouse is true if it's CSI<, false otherwise
EscSeqUtils.DecodeEscSeq (EscSeqRequests, ref newConsoleKeyInfo, ref key, cki, ref mod,
- out var c1Control, out var code, out var values, out var terminating,
- out var isMouse, out var mouseFlags,
- out var pos, out var isReq,
- (f, p) => HandleMouseEvent (MapMouseFlags (f), p));
+ out string c1Control, out string code, out string [] values, out string terminating,
+ out bool isMouse, out var mouseFlags,
+ out var pos, out bool isReq,
+ (f, p) => HandleMouseEvent (MapMouseFlags (f), p));
if (isMouse) {
foreach (var mf in mouseFlags) {
@@ -343,7 +349,7 @@ void ProcessRequestResponse (ref ConsoleKeyInfo newConsoleKeyInfo, ref ConsoleKe
MouseButtonState MapMouseFlags (MouseFlags mouseFlags)
{
MouseButtonState mbs = default;
- foreach (var flag in Enum.GetValues (mouseFlags.GetType ())) {
+ foreach (object flag in Enum.GetValues (mouseFlags.GetType ())) {
if (mouseFlags.HasFlag ((MouseFlags)flag)) {
switch (flag) {
case MouseFlags.Button1Pressed:
@@ -446,7 +452,7 @@ void HandleRequestResponseEvent (string c1Control, string code, string [] values
switch (terminating) {
// BUGBUG: I can't find where we send a request for cursor position (ESC[?6n), so I'm not sure if this is needed.
case EscSeqUtils.CSI_RequestCursorPositionReport_Terminator:
- Point point = new Point {
+ var point = new Point {
X = int.Parse (values [1]) - 1,
Y = int.Parse (values [0]) - 1
};
@@ -469,10 +475,10 @@ void HandleRequestResponseEvent (string c1Control, string code, string [] values
switch (values [0]) {
case EscSeqUtils.CSI_ReportTerminalSizeInChars_ResponseValue:
EnqueueWindowSizeEvent (
- Math.Max (int.Parse (values [1]), 0),
- Math.Max (int.Parse (values [2]), 0),
- Math.Max (int.Parse (values [1]), 0),
- Math.Max (int.Parse (values [2]), 0));
+ Math.Max (int.Parse (values [1]), 0),
+ Math.Max (int.Parse (values [2]), 0),
+ Math.Max (int.Parse (values [1]), 0),
+ Math.Max (int.Parse (values [2]), 0));
break;
default:
EnqueueRequestResponseEvent (c1Control, code, values, terminating);
@@ -489,7 +495,7 @@ void HandleRequestResponseEvent (string c1Control, string code, string [] values
void EnqueueRequestResponseEvent (string c1Control, string code, string [] values, string terminating)
{
- EventType eventType = EventType.RequestResponse;
+ var eventType = EventType.RequestResponse;
var requestRespEv = new RequestResponseEvent () {
ResultTuple = (c1Control, code, values, terminating)
};
@@ -501,9 +507,9 @@ void EnqueueRequestResponseEvent (string c1Control, string code, string [] value
void HandleMouseEvent (MouseButtonState buttonState, Point pos)
{
- MouseEvent mouseEvent = new MouseEvent () {
+ var mouseEvent = new MouseEvent () {
Position = pos,
- ButtonState = buttonState,
+ ButtonState = buttonState
};
_inputQueue.Enqueue (new InputResult () {
@@ -581,11 +587,40 @@ public struct InputResult {
public WindowSizeEvent WindowSizeEvent;
public WindowPositionEvent WindowPositionEvent;
public RequestResponseEvent RequestResponseEvent;
+
+ public override readonly string ToString ()
+ {
+ return EventType switch {
+ EventType.Key => ToString (ConsoleKeyInfo),
+ EventType.Mouse => MouseEvent.ToString (),
+ //EventType.WindowSize => WindowSize.ToString (),
+ //EventType.RequestResponse => RequestResponse.ToString (),
+ _ => "Unknown event type: " + EventType
+ };
+ }
+
+ ///
+ /// Prints a ConsoleKeyInfoEx structure
+ ///
+ ///
+ ///
+ public readonly string ToString (ConsoleKeyInfo cki)
+ {
+ var ke = new Key ((KeyCode)cki.KeyChar);
+ var sb = new StringBuilder ();
+ sb.Append ($"Key: {(KeyCode)cki.Key} ({cki.Key})");
+ sb.Append ((cki.Modifiers & ConsoleModifiers.Shift) != 0 ? " | Shift" : string.Empty);
+ sb.Append ((cki.Modifiers & ConsoleModifiers.Control) != 0 ? " | Control" : string.Empty);
+ sb.Append ((cki.Modifiers & ConsoleModifiers.Alt) != 0 ? " | Alt" : string.Empty);
+ sb.Append ($", KeyChar: {ke.AsRune.MakePrintable ()} ({(uint)cki.KeyChar}) ");
+ var s = sb.ToString ().TrimEnd (',').TrimEnd (' ');
+ return $"[ConsoleKeyInfo({s})]";
+ }
}
void HandleKeyboardEvent (ConsoleKeyInfo cki)
{
- InputResult inputResult = new InputResult {
+ var inputResult = new InputResult {
EventType = EventType.Key,
ConsoleKeyInfo = cki
};
@@ -611,7 +646,7 @@ public void Dispose ()
}
}
-internal class NetDriver : ConsoleDriver {
+class NetDriver : ConsoleDriver {
const int COLOR_BLACK = 30;
const int COLOR_RED = 31;
const int COLOR_GREEN = 32;
@@ -631,9 +666,10 @@ internal class NetDriver : ConsoleDriver {
NetMainLoop _mainLoopDriver = null;
- public override bool SupportsTrueColor => Environment.OSVersion.Platform == PlatformID.Unix || (IsWinPlatform && Environment.OSVersion.Version.Build >= 14931);
+ public override bool SupportsTrueColor => Environment.OSVersion.Platform == PlatformID.Unix || IsWinPlatform && Environment.OSVersion.Version.Build >= 14931;
public NetWinVTConsole NetWinConsole { get; private set; }
+
public bool IsWinPlatform { get; private set; }
internal override MainLoop Init ()
@@ -709,6 +745,21 @@ internal override void End ()
}
}
+
+ #region Size and Position Handling
+ volatile bool _winSizeChanging;
+
+ void SetWindowPosition (int col, int row)
+ {
+ if (!RunningUnitTests) {
+ Top = Console.WindowTop;
+ Left = Console.WindowLeft;
+ } else {
+ Top = row;
+ Left = col;
+ }
+ }
+
public virtual void ResizeScreen ()
{
// Not supported on Unix.
@@ -727,7 +778,7 @@ public virtual void ResizeScreen ()
Console.SetBufferSize (Cols, Rows);
}
#pragma warning restore CA1416
- } catch (System.IO.IOException) {
+ } catch (IOException) {
Clip = new Rect (0, 0, Cols, Rows);
} catch (ArgumentOutOfRangeException) {
Clip = new Rect (0, 0, Cols, Rows);
@@ -739,6 +790,7 @@ public virtual void ResizeScreen ()
Clip = new Rect (0, 0, Cols, Rows);
}
+ #endregion
public override void Refresh ()
{
@@ -752,18 +804,18 @@ public override void UpdateScreen ()
return;
}
- var top = 0;
- var left = 0;
- var rows = Rows;
- var cols = Cols;
- System.Text.StringBuilder output = new System.Text.StringBuilder ();
- Attribute redrawAttr = new Attribute ();
- var lastCol = -1;
+ int top = 0;
+ int left = 0;
+ int rows = Rows;
+ int cols = Cols;
+ var output = new StringBuilder ();
+ var redrawAttr = new Attribute ();
+ int lastCol = -1;
var savedVisibitity = _cachedCursorVisibility;
SetCursorVisibility (CursorVisibility.Invisible);
- for (var row = top; row < rows; row++) {
+ for (int row = top; row < rows; row++) {
if (Console.WindowHeight < 1) {
return;
}
@@ -775,9 +827,9 @@ public override void UpdateScreen ()
}
_dirtyLines [row] = false;
output.Clear ();
- for (var col = left; col < cols; col++) {
+ for (int col = left; col < cols; col++) {
lastCol = -1;
- var outputWidth = 0;
+ int outputWidth = 0;
for (; col < cols; col++) {
if (!Contents [row, col].IsDirty) {
if (output.Length > 0) {
@@ -795,7 +847,7 @@ public override void UpdateScreen ()
lastCol = col;
}
- Attribute attr = Contents [row, col].Attribute.Value;
+ var attr = Contents [row, col].Attribute.Value;
// Performance: Only send the escape sequence if the attribute has changed.
if (attr != redrawAttr) {
redrawAttr = attr;
@@ -823,7 +875,7 @@ public override void UpdateScreen ()
// output.Append (combMark);
//}
// WriteToConsole (output, ref lastCol, row, ref outputWidth);
- } else if ((rune.IsSurrogatePair () && rune.GetColumns () < 2)) {
+ } else if (rune.IsSurrogatePair () && rune.GetColumns () < 2) {
WriteToConsole (output, ref lastCol, row, ref outputWidth);
SetCursorPosition (col - 1, row);
}
@@ -850,37 +902,33 @@ void WriteToConsole (StringBuilder output, ref int lastCol, int row, ref int out
}
#region Color Handling
-
// Cache the list of ConsoleColor values.
- private static readonly HashSet ConsoleColorValues = new HashSet (
- Enum.GetValues (typeof (ConsoleColor)).OfType ().Select (c => (int)c)
+ static readonly HashSet ConsoleColorValues = new (
+ Enum.GetValues (typeof (ConsoleColor)).OfType ().Select (c => (int)c)
);
// Dictionary for mapping ConsoleColor values to the values used by System.Net.Console.
- private static Dictionary colorMap = new Dictionary {
- { ConsoleColor.Black, COLOR_BLACK },
- { ConsoleColor.DarkBlue, COLOR_BLUE },
- { ConsoleColor.DarkGreen, COLOR_GREEN },
- { ConsoleColor.DarkCyan, COLOR_CYAN },
- { ConsoleColor.DarkRed, COLOR_RED },
- { ConsoleColor.DarkMagenta, COLOR_MAGENTA },
- { ConsoleColor.DarkYellow, COLOR_YELLOW },
- { ConsoleColor.Gray, COLOR_WHITE },
- { ConsoleColor.DarkGray, COLOR_BRIGHT_BLACK },
- { ConsoleColor.Blue, COLOR_BRIGHT_BLUE },
- { ConsoleColor.Green, COLOR_BRIGHT_GREEN },
- { ConsoleColor.Cyan, COLOR_BRIGHT_CYAN },
- { ConsoleColor.Red, COLOR_BRIGHT_RED },
- { ConsoleColor.Magenta, COLOR_BRIGHT_MAGENTA },
- { ConsoleColor.Yellow, COLOR_BRIGHT_YELLOW },
- { ConsoleColor.White, COLOR_BRIGHT_WHITE }
- };
+ static Dictionary colorMap = new () {
+ { ConsoleColor.Black, COLOR_BLACK },
+ { ConsoleColor.DarkBlue, COLOR_BLUE },
+ { ConsoleColor.DarkGreen, COLOR_GREEN },
+ { ConsoleColor.DarkCyan, COLOR_CYAN },
+ { ConsoleColor.DarkRed, COLOR_RED },
+ { ConsoleColor.DarkMagenta, COLOR_MAGENTA },
+ { ConsoleColor.DarkYellow, COLOR_YELLOW },
+ { ConsoleColor.Gray, COLOR_WHITE },
+ { ConsoleColor.DarkGray, COLOR_BRIGHT_BLACK },
+ { ConsoleColor.Blue, COLOR_BRIGHT_BLUE },
+ { ConsoleColor.Green, COLOR_BRIGHT_GREEN },
+ { ConsoleColor.Cyan, COLOR_BRIGHT_CYAN },
+ { ConsoleColor.Red, COLOR_BRIGHT_RED },
+ { ConsoleColor.Magenta, COLOR_BRIGHT_MAGENTA },
+ { ConsoleColor.Yellow, COLOR_BRIGHT_YELLOW },
+ { ConsoleColor.White, COLOR_BRIGHT_WHITE }
+ };
// Map a ConsoleColor to a platform dependent value.
- int MapColors (ConsoleColor color, bool isForeground = true)
- {
- return colorMap.TryGetValue (color, out var colorValue) ? colorValue + (isForeground ? 0 : 10) : 0;
- }
+ int MapColors (ConsoleColor color, bool isForeground = true) => colorMap.TryGetValue (color, out int colorValue) ? colorValue + (isForeground ? 0 : 10) : 0;
/////
///// In the NetDriver, colors are encoded as an int.
@@ -938,7 +986,7 @@ public override bool GetCursorVisibility (out CursorVisibility visibility)
public override bool SetCursorVisibility (CursorVisibility visibility)
{
_cachedCursorVisibility = visibility;
- var isVisible = RunningUnitTests ? visibility == CursorVisibility.Default : Console.CursorVisible = visibility == CursorVisibility.Default;
+ bool isVisible = RunningUnitTests ? visibility == CursorVisibility.Default : Console.CursorVisible = visibility == CursorVisibility.Default;
Console.Out.Write (isVisible ? EscSeqUtils.CSI_ShowCursor : EscSeqUtils.CSI_HideCursor);
return isVisible;
}
@@ -946,7 +994,7 @@ public override bool SetCursorVisibility (CursorVisibility visibility)
public override bool EnsureCursorVisibility ()
{
if (!(Col >= 0 && Row >= 0 && Col < Cols && Row < Rows)) {
- GetCursorVisibility (out CursorVisibility cursorVisibility);
+ GetCursorVisibility (out var cursorVisibility);
_cachedCursorVisibility = cursorVisibility;
SetCursorVisibility (CursorVisibility.Invisible);
return false;
@@ -957,22 +1005,7 @@ public override bool EnsureCursorVisibility ()
}
#endregion
- #region Size and Position Handling
-
- void SetWindowPosition (int col, int row)
- {
- if (!RunningUnitTests) {
- Top = Console.WindowTop;
- Left = Console.WindowLeft;
- } else {
- Top = row;
- Left = col;
- }
- }
-
- #endregion
-
-
+ #region Mouse Handling
public void StartReportingMouseMoves ()
{
if (!RunningUnitTests) {
@@ -987,6 +1020,106 @@ public void StopReportingMouseMoves ()
}
}
+ MouseEvent ToDriverMouse (NetEvents.MouseEvent me)
+ {
+ //System.Diagnostics.Debug.WriteLine ($"X: {me.Position.X}; Y: {me.Position.Y}; ButtonState: {me.ButtonState}");
+
+ MouseFlags mouseFlag = 0;
+
+ if ((me.ButtonState & MouseButtonState.Button1Pressed) != 0) {
+ mouseFlag |= MouseFlags.Button1Pressed;
+ }
+ if ((me.ButtonState & MouseButtonState.Button1Released) != 0) {
+ mouseFlag |= MouseFlags.Button1Released;
+ }
+ if ((me.ButtonState & MouseButtonState.Button1Clicked) != 0) {
+ mouseFlag |= MouseFlags.Button1Clicked;
+ }
+ if ((me.ButtonState & MouseButtonState.Button1DoubleClicked) != 0) {
+ mouseFlag |= MouseFlags.Button1DoubleClicked;
+ }
+ if ((me.ButtonState & MouseButtonState.Button1TripleClicked) != 0) {
+ mouseFlag |= MouseFlags.Button1TripleClicked;
+ }
+ if ((me.ButtonState & MouseButtonState.Button2Pressed) != 0) {
+ mouseFlag |= MouseFlags.Button2Pressed;
+ }
+ if ((me.ButtonState & MouseButtonState.Button2Released) != 0) {
+ mouseFlag |= MouseFlags.Button2Released;
+ }
+ if ((me.ButtonState & MouseButtonState.Button2Clicked) != 0) {
+ mouseFlag |= MouseFlags.Button2Clicked;
+ }
+ if ((me.ButtonState & MouseButtonState.Button2DoubleClicked) != 0) {
+ mouseFlag |= MouseFlags.Button2DoubleClicked;
+ }
+ if ((me.ButtonState & MouseButtonState.Button2TripleClicked) != 0) {
+ mouseFlag |= MouseFlags.Button2TripleClicked;
+ }
+ if ((me.ButtonState & MouseButtonState.Button3Pressed) != 0) {
+ mouseFlag |= MouseFlags.Button3Pressed;
+ }
+ if ((me.ButtonState & MouseButtonState.Button3Released) != 0) {
+ mouseFlag |= MouseFlags.Button3Released;
+ }
+ if ((me.ButtonState & MouseButtonState.Button3Clicked) != 0) {
+ mouseFlag |= MouseFlags.Button3Clicked;
+ }
+ if ((me.ButtonState & MouseButtonState.Button3DoubleClicked) != 0) {
+ mouseFlag |= MouseFlags.Button3DoubleClicked;
+ }
+ if ((me.ButtonState & MouseButtonState.Button3TripleClicked) != 0) {
+ mouseFlag |= MouseFlags.Button3TripleClicked;
+ }
+ if ((me.ButtonState & MouseButtonState.ButtonWheeledUp) != 0) {
+ mouseFlag |= MouseFlags.WheeledUp;
+ }
+ if ((me.ButtonState & MouseButtonState.ButtonWheeledDown) != 0) {
+ mouseFlag |= MouseFlags.WheeledDown;
+ }
+ if ((me.ButtonState & MouseButtonState.ButtonWheeledLeft) != 0) {
+ mouseFlag |= MouseFlags.WheeledLeft;
+ }
+ if ((me.ButtonState & MouseButtonState.ButtonWheeledRight) != 0) {
+ mouseFlag |= MouseFlags.WheeledRight;
+ }
+ if ((me.ButtonState & MouseButtonState.Button4Pressed) != 0) {
+ mouseFlag |= MouseFlags.Button4Pressed;
+ }
+ if ((me.ButtonState & MouseButtonState.Button4Released) != 0) {
+ mouseFlag |= MouseFlags.Button4Released;
+ }
+ if ((me.ButtonState & MouseButtonState.Button4Clicked) != 0) {
+ mouseFlag |= MouseFlags.Button4Clicked;
+ }
+ if ((me.ButtonState & MouseButtonState.Button4DoubleClicked) != 0) {
+ mouseFlag |= MouseFlags.Button4DoubleClicked;
+ }
+ if ((me.ButtonState & MouseButtonState.Button4TripleClicked) != 0) {
+ mouseFlag |= MouseFlags.Button4TripleClicked;
+ }
+ if ((me.ButtonState & MouseButtonState.ReportMousePosition) != 0) {
+ mouseFlag |= MouseFlags.ReportMousePosition;
+ }
+ if ((me.ButtonState & MouseButtonState.ButtonShift) != 0) {
+ mouseFlag |= MouseFlags.ButtonShift;
+ }
+ if ((me.ButtonState & MouseButtonState.ButtonCtrl) != 0) {
+ mouseFlag |= MouseFlags.ButtonCtrl;
+ }
+ if ((me.ButtonState & MouseButtonState.ButtonAlt) != 0) {
+ mouseFlag |= MouseFlags.ButtonAlt;
+ }
+
+ return new MouseEvent () {
+ X = me.Position.X,
+ Y = me.Position.Y,
+ Flags = mouseFlag
+ };
+ }
+ #endregion Mouse Handling
+
+ #region Keyboard Handling
ConsoleKeyInfo FromVKPacketToKConsoleKeyInfo (ConsoleKeyInfo consoleKeyInfo)
{
if (consoleKeyInfo.Key != ConsoleKey.Packet) {
@@ -994,11 +1127,11 @@ ConsoleKeyInfo FromVKPacketToKConsoleKeyInfo (ConsoleKeyInfo consoleKeyInfo)
}
var mod = consoleKeyInfo.Modifiers;
- var shift = (mod & ConsoleModifiers.Shift) != 0;
- var alt = (mod & ConsoleModifiers.Alt) != 0;
- var control = (mod & ConsoleModifiers.Control) != 0;
+ bool shift = (mod & ConsoleModifiers.Shift) != 0;
+ bool alt = (mod & ConsoleModifiers.Alt) != 0;
+ bool control = (mod & ConsoleModifiers.Control) != 0;
- var cKeyInfo = ConsoleKeyMapping.GetConsoleKeyFromKey (consoleKeyInfo.KeyChar, consoleKeyInfo.Modifiers, out _);
+ var cKeyInfo = DecodeVKPacketToKConsoleKeyInfo (consoleKeyInfo);
return new ConsoleKeyInfo (cKeyInfo.KeyChar, cKeyInfo.Key, shift, alt, control);
}
@@ -1006,37 +1139,11 @@ ConsoleKeyInfo FromVKPacketToKConsoleKeyInfo (ConsoleKeyInfo consoleKeyInfo)
KeyCode MapKey (ConsoleKeyInfo keyInfo)
{
switch (keyInfo.Key) {
- case ConsoleKey.Escape:
- return ConsoleKeyMapping.MapKeyModifiers (keyInfo, KeyCode.Esc);
- case ConsoleKey.Tab:
- return ConsoleKeyMapping.MapKeyModifiers (keyInfo, KeyCode.Tab);
- case ConsoleKey.Home:
- return ConsoleKeyMapping.MapKeyModifiers (keyInfo, KeyCode.Home);
- case ConsoleKey.End:
- return ConsoleKeyMapping.MapKeyModifiers (keyInfo, KeyCode.End);
- case ConsoleKey.LeftArrow:
- return ConsoleKeyMapping.MapKeyModifiers (keyInfo, KeyCode.CursorLeft);
- case ConsoleKey.RightArrow:
- return ConsoleKeyMapping.MapKeyModifiers (keyInfo, KeyCode.CursorRight);
- case ConsoleKey.UpArrow:
- return ConsoleKeyMapping.MapKeyModifiers (keyInfo, KeyCode.CursorUp);
- case ConsoleKey.DownArrow:
- return ConsoleKeyMapping.MapKeyModifiers (keyInfo, KeyCode.CursorDown);
- case ConsoleKey.PageUp:
- return ConsoleKeyMapping.MapKeyModifiers (keyInfo, KeyCode.PageUp);
- case ConsoleKey.PageDown:
- return ConsoleKeyMapping.MapKeyModifiers (keyInfo, KeyCode.PageDown);
- case ConsoleKey.Enter:
- return ConsoleKeyMapping.MapKeyModifiers (keyInfo, KeyCode.Enter);
- case ConsoleKey.Spacebar:
- return ConsoleKeyMapping.MapKeyModifiers (keyInfo, keyInfo.KeyChar == 0 ? KeyCode.Space : (KeyCode)keyInfo.KeyChar);
- case ConsoleKey.Backspace:
- return ConsoleKeyMapping.MapKeyModifiers (keyInfo, KeyCode.Backspace);
- case ConsoleKey.Delete:
- return ConsoleKeyMapping.MapKeyModifiers (keyInfo, KeyCode.DeleteChar);
- case ConsoleKey.Insert:
- return ConsoleKeyMapping.MapKeyModifiers (keyInfo, KeyCode.InsertChar);
-
+ case ConsoleKey.OemPeriod:
+ case ConsoleKey.OemComma:
+ case ConsoleKey.OemPlus:
+ case ConsoleKey.OemMinus:
+ case ConsoleKey.Packet:
case ConsoleKey.Oem1:
case ConsoleKey.Oem2:
case ConsoleKey.Oem3:
@@ -1046,99 +1153,78 @@ KeyCode MapKey (ConsoleKeyInfo keyInfo)
case ConsoleKey.Oem7:
case ConsoleKey.Oem8:
case ConsoleKey.Oem102:
- var ret = ConsoleKeyMapping.MapKeyModifiers (keyInfo, (KeyCode)((uint)keyInfo.KeyChar));
- if (ret.HasFlag (KeyCode.ShiftMask)) {
- ret &= ~KeyCode.ShiftMask;
+ if (keyInfo.KeyChar == 0) {
+ // If the keyChar is 0, keyInfo.Key value is not a printable character.
+
+ return KeyCode.Null;// MapToKeyCodeModifiers (keyInfo.Modifiers, KeyCode)keyInfo.Key);
+ } else {
+ if (keyInfo.Modifiers != ConsoleModifiers.Shift) {
+ // If Shift wasn't down we don't need to do anything but return the keyInfo.KeyChar
+ return MapToKeyCodeModifiers (keyInfo.Modifiers, (KeyCode)(keyInfo.KeyChar));
+ }
+
+ // Strip off Shift - We got here because they KeyChar from Windows is the shifted char (e.g. "Ç")
+ // and passing on Shift would be redundant.
+ return MapToKeyCodeModifiers (keyInfo.Modifiers & ~ConsoleModifiers.Shift, (KeyCode)keyInfo.KeyChar);
}
- return ret;
+ break;
- case ConsoleKey.OemPeriod:
- case ConsoleKey.OemComma:
- case ConsoleKey.OemPlus:
- case ConsoleKey.OemMinus:
- return (KeyCode)((uint)keyInfo.KeyChar);
+
+ return (KeyCode)(uint)keyInfo.KeyChar;
}
var key = keyInfo.Key;
- if (key is >= ConsoleKey.A and <= ConsoleKey.Z) {
- var delta = key - ConsoleKey.A;
- if (keyInfo.Modifiers == ConsoleModifiers.Control) {
- return (KeyCode)(((uint)KeyCode.CtrlMask) | ((uint)KeyCode.A + delta));
- }
- if (keyInfo.Modifiers == ConsoleModifiers.Alt) {
- return (KeyCode)(((uint)KeyCode.AltMask) | ((uint)KeyCode.A + delta));
- }
- if (keyInfo.Modifiers == (ConsoleModifiers.Shift | ConsoleModifiers.Alt)) {
- return ConsoleKeyMapping.MapKeyModifiers (keyInfo, (KeyCode)((uint)KeyCode.A + delta));
- }
- if ((keyInfo.Modifiers & (ConsoleModifiers.Alt | ConsoleModifiers.Control)) != 0) {
- if (keyInfo.KeyChar == 0 || (keyInfo.KeyChar != 0 && keyInfo.KeyChar >= 1 && keyInfo.KeyChar <= 26)) {
- return ConsoleKeyMapping.MapKeyModifiers (keyInfo, (KeyCode)((uint)KeyCode.A + delta));
- }
+ // A..Z are special cased:
+ // - Alone, they represent lowercase a...z
+ // - With ShiftMask they are A..Z
+ // - If CapsLock is on the above is reversed.
+ // - If Alt and/or Ctrl are present, treat as upper case
+ if (keyInfo.Key is >= ConsoleKey.A and <= ConsoleKey.Z) {
+ if (keyInfo.Modifiers.HasFlag (ConsoleModifiers.Alt) || keyInfo.Modifiers.HasFlag (ConsoleModifiers.Control)) {
+ return MapToKeyCodeModifiers (keyInfo.Modifiers, (KeyCode)(uint)keyInfo.Key);
}
- if (((keyInfo.Modifiers == ConsoleModifiers.Shift) /*^ (keyInfoEx.CapsLock)*/)) {
- if (keyInfo.KeyChar <= (uint)KeyCode.Z) {
- return (KeyCode)((uint)KeyCode.A + delta) | KeyCode.ShiftMask;
+ if (keyInfo.Modifiers == ConsoleModifiers.Shift) {
+ // If ShiftMask is on add the ShiftMask
+ if (char.IsUpper (keyInfo.KeyChar)) {
+ return (KeyCode)((uint)keyInfo.Key) | KeyCode.ShiftMask;
}
}
- // This is buggy because is converting a lower case to a upper case and mustn't
- //if (((KeyCode)((uint)keyInfo.KeyChar) & KeyCode.Space) == KeyCode.Space) {
- // return (KeyCode)((uint)keyInfo.KeyChar) & ~KeyCode.Space;
- //}
return (KeyCode)(uint)keyInfo.KeyChar;
}
- if (key is >= ConsoleKey.D0 and <= ConsoleKey.D9) {
- var delta = key - ConsoleKey.D0;
- if (keyInfo.Modifiers == ConsoleModifiers.Alt) {
- return (KeyCode)(((uint)KeyCode.AltMask) | ((uint)KeyCode.D0 + delta));
- }
- if (keyInfo.Modifiers == ConsoleModifiers.Control) {
- return (KeyCode)(((uint)KeyCode.CtrlMask) | ((uint)KeyCode.D0 + delta));
- }
- if ((keyInfo.Modifiers & (ConsoleModifiers.Alt | ConsoleModifiers.Control)) != 0) {
- if (keyInfo.KeyChar == 0 || keyInfo.KeyChar == 30 || keyInfo.KeyChar == ((uint)KeyCode.D0 + delta)) {
- return ConsoleKeyMapping.MapKeyModifiers (keyInfo, (KeyCode)((uint)KeyCode.D0 + delta));
- }
- }
- return (KeyCode)((uint)keyInfo.KeyChar);
- }
- if (key is >= ConsoleKey.F1 and <= ConsoleKey.F12) {
- var delta = key - ConsoleKey.F1;
- if ((keyInfo.Modifiers & (ConsoleModifiers.Shift | ConsoleModifiers.Alt | ConsoleModifiers.Control)) != 0) {
- return ConsoleKeyMapping.MapKeyModifiers (keyInfo, (KeyCode)((uint)KeyCode.F1 + delta));
- }
- return (KeyCode)((uint)KeyCode.F1 + delta);
+ // Handle control keys whose VK codes match the related ASCII value (those below ASCII 33) like ESC
+ if (keyInfo.Key != ConsoleKey.None && Enum.IsDefined (typeof (KeyCode), (uint)keyInfo.Key)) {
+ return MapToKeyCodeModifiers (keyInfo.Modifiers, (KeyCode)(keyInfo.Key));
}
- // Is it a key between a..z?
- if ((char)keyInfo.KeyChar is >= 'a' and <= 'z') {
- // 'a' should be Key.A
- return (KeyCode)((uint)keyInfo.KeyChar) & ~KeyCode.Space;
+ // Handle control keys (e.g. CursorUp)
+ if (keyInfo.Key != ConsoleKey.None && Enum.IsDefined (typeof (KeyCode), ((uint)keyInfo.Key + (uint)KeyCode.MaxCodePoint))) {
+ return MapToKeyCodeModifiers (keyInfo.Modifiers, (KeyCode)((uint)keyInfo.Key + (uint)KeyCode.MaxCodePoint));
}
- // Is it a key between A..Z?
- if (((KeyCode)((uint)keyInfo.KeyChar) & ~KeyCode.Space) is >= KeyCode.A and <= KeyCode.Z) {
- // It's Key.A...Z. Make it Key.A | Key.ShiftMask
- return (KeyCode)((uint)keyInfo.KeyChar) & ~KeyCode.Space | KeyCode.ShiftMask;
- }
return (KeyCode)(uint)keyInfo.KeyChar;
}
+ #endregion Keyboard Handling
- volatile bool _winSizeChanging;
-
- void ProcessInput (NetEvents.InputResult inputEvent)
+ void ProcessInput (InputResult inputEvent)
{
switch (inputEvent.EventType) {
case NetEvents.EventType.Key:
- ConsoleKeyInfo consoleKeyInfo = inputEvent.ConsoleKeyInfo;
- if (consoleKeyInfo.Key == ConsoleKey.Packet) {
- consoleKeyInfo = FromVKPacketToKConsoleKeyInfo (consoleKeyInfo);
- }
+ var consoleKeyInfo = inputEvent.ConsoleKeyInfo;
+ //if (consoleKeyInfo.Key == ConsoleKey.Packet) {
+ // consoleKeyInfo = FromVKPacketToKConsoleKeyInfo (consoleKeyInfo);
+ //}
+
+ //Debug.WriteLine ($"event: {inputEvent}");
+
var map = MapKey (consoleKeyInfo);
+ if (map == KeyCode.Null) {
+ break;
+ }
+
OnKeyDown (new Key (map));
OnKeyUp (new Key (map));
break;
@@ -1150,16 +1236,14 @@ void ProcessInput (NetEvents.InputResult inputEvent)
Top = 0;
Left = 0;
Cols = inputEvent.WindowSizeEvent.Size.Width;
- Rows = Math.Max (inputEvent.WindowSizeEvent.Size.Height, 0); ;
+ Rows = Math.Max (inputEvent.WindowSizeEvent.Size.Height, 0);
+ ;
ResizeScreen ();
ClearContents ();
_winSizeChanging = false;
OnSizeChanged (new SizeChangedEventArgs (new Size (Cols, Rows)));
break;
case NetEvents.EventType.RequestResponse:
- // BUGBUG: What is this for? It does not seem to be used anywhere.
- // It is also not clear what it does. View.Data is documented as "This property is not used internally"
- Application.Top.Data = inputEvent.RequestResponseEvent.ResultTuple;
break;
case NetEvents.EventType.WindowPosition:
break;
@@ -1168,107 +1252,9 @@ void ProcessInput (NetEvents.InputResult inputEvent)
}
}
- MouseEvent ToDriverMouse (NetEvents.MouseEvent me)
- {
- //System.Diagnostics.Debug.WriteLine ($"X: {me.Position.X}; Y: {me.Position.Y}; ButtonState: {me.ButtonState}");
-
- MouseFlags mouseFlag = 0;
-
- if ((me.ButtonState & NetEvents.MouseButtonState.Button1Pressed) != 0) {
- mouseFlag |= MouseFlags.Button1Pressed;
- }
- if ((me.ButtonState & NetEvents.MouseButtonState.Button1Released) != 0) {
- mouseFlag |= MouseFlags.Button1Released;
- }
- if ((me.ButtonState & NetEvents.MouseButtonState.Button1Clicked) != 0) {
- mouseFlag |= MouseFlags.Button1Clicked;
- }
- if ((me.ButtonState & NetEvents.MouseButtonState.Button1DoubleClicked) != 0) {
- mouseFlag |= MouseFlags.Button1DoubleClicked;
- }
- if ((me.ButtonState & NetEvents.MouseButtonState.Button1TripleClicked) != 0) {
- mouseFlag |= MouseFlags.Button1TripleClicked;
- }
- if ((me.ButtonState & NetEvents.MouseButtonState.Button2Pressed) != 0) {
- mouseFlag |= MouseFlags.Button2Pressed;
- }
- if ((me.ButtonState & NetEvents.MouseButtonState.Button2Released) != 0) {
- mouseFlag |= MouseFlags.Button2Released;
- }
- if ((me.ButtonState & NetEvents.MouseButtonState.Button2Clicked) != 0) {
- mouseFlag |= MouseFlags.Button2Clicked;
- }
- if ((me.ButtonState & NetEvents.MouseButtonState.Button2DoubleClicked) != 0) {
- mouseFlag |= MouseFlags.Button2DoubleClicked;
- }
- if ((me.ButtonState & NetEvents.MouseButtonState.Button2TripleClicked) != 0) {
- mouseFlag |= MouseFlags.Button2TripleClicked;
- }
- if ((me.ButtonState & NetEvents.MouseButtonState.Button3Pressed) != 0) {
- mouseFlag |= MouseFlags.Button3Pressed;
- }
- if ((me.ButtonState & NetEvents.MouseButtonState.Button3Released) != 0) {
- mouseFlag |= MouseFlags.Button3Released;
- }
- if ((me.ButtonState & NetEvents.MouseButtonState.Button3Clicked) != 0) {
- mouseFlag |= MouseFlags.Button3Clicked;
- }
- if ((me.ButtonState & NetEvents.MouseButtonState.Button3DoubleClicked) != 0) {
- mouseFlag |= MouseFlags.Button3DoubleClicked;
- }
- if ((me.ButtonState & NetEvents.MouseButtonState.Button3TripleClicked) != 0) {
- mouseFlag |= MouseFlags.Button3TripleClicked;
- }
- if ((me.ButtonState & NetEvents.MouseButtonState.ButtonWheeledUp) != 0) {
- mouseFlag |= MouseFlags.WheeledUp;
- }
- if ((me.ButtonState & NetEvents.MouseButtonState.ButtonWheeledDown) != 0) {
- mouseFlag |= MouseFlags.WheeledDown;
- }
- if ((me.ButtonState & NetEvents.MouseButtonState.ButtonWheeledLeft) != 0) {
- mouseFlag |= MouseFlags.WheeledLeft;
- }
- if ((me.ButtonState & NetEvents.MouseButtonState.ButtonWheeledRight) != 0) {
- mouseFlag |= MouseFlags.WheeledRight;
- }
- if ((me.ButtonState & NetEvents.MouseButtonState.Button4Pressed) != 0) {
- mouseFlag |= MouseFlags.Button4Pressed;
- }
- if ((me.ButtonState & NetEvents.MouseButtonState.Button4Released) != 0) {
- mouseFlag |= MouseFlags.Button4Released;
- }
- if ((me.ButtonState & NetEvents.MouseButtonState.Button4Clicked) != 0) {
- mouseFlag |= MouseFlags.Button4Clicked;
- }
- if ((me.ButtonState & NetEvents.MouseButtonState.Button4DoubleClicked) != 0) {
- mouseFlag |= MouseFlags.Button4DoubleClicked;
- }
- if ((me.ButtonState & NetEvents.MouseButtonState.Button4TripleClicked) != 0) {
- mouseFlag |= MouseFlags.Button4TripleClicked;
- }
- if ((me.ButtonState & NetEvents.MouseButtonState.ReportMousePosition) != 0) {
- mouseFlag |= MouseFlags.ReportMousePosition;
- }
- if ((me.ButtonState & NetEvents.MouseButtonState.ButtonShift) != 0) {
- mouseFlag |= MouseFlags.ButtonShift;
- }
- if ((me.ButtonState & NetEvents.MouseButtonState.ButtonCtrl) != 0) {
- mouseFlag |= MouseFlags.ButtonCtrl;
- }
- if ((me.ButtonState & NetEvents.MouseButtonState.ButtonAlt) != 0) {
- mouseFlag |= MouseFlags.ButtonAlt;
- }
-
- return new MouseEvent () {
- X = me.Position.X,
- Y = me.Position.Y,
- Flags = mouseFlag
- };
- }
-
public override void SendKeys (char keyChar, ConsoleKey key, bool shift, bool alt, bool control)
{
- NetEvents.InputResult input = new NetEvents.InputResult {
+ var input = new InputResult {
EventType = NetEvents.EventType.Key,
ConsoleKeyInfo = new ConsoleKeyInfo (keyChar, key, shift, alt, control)
};
@@ -1280,12 +1266,8 @@ public override void SendKeys (char keyChar, ConsoleKey key, bool shift, bool al
#region Not Implemented
- public override void Suspend ()
- {
- throw new NotImplementedException ();
- }
+ public override void Suspend () => throw new NotImplementedException ();
#endregion
-
}
///
@@ -1296,19 +1278,19 @@ public override void Suspend ()
///
/// This implementation is used for NetDriver.
///
-internal class NetMainLoop : IMainLoopDriver {
- readonly ManualResetEventSlim _eventReady = new ManualResetEventSlim (false);
- readonly ManualResetEventSlim _waitForProbe = new ManualResetEventSlim (false);
- readonly Queue _resultQueue = new Queue ();
+class NetMainLoop : IMainLoopDriver {
+ readonly ManualResetEventSlim _eventReady = new (false);
+ readonly ManualResetEventSlim _waitForProbe = new (false);
+ readonly Queue _resultQueue = new ();
MainLoop _mainLoop;
- CancellationTokenSource _eventReadyTokenSource = new CancellationTokenSource ();
- readonly CancellationTokenSource _inputHandlerTokenSource = new CancellationTokenSource ();
+ CancellationTokenSource _eventReadyTokenSource = new ();
+ readonly CancellationTokenSource _inputHandlerTokenSource = new ();
internal NetEvents _netEvents;
///
/// Invoked when a Key is pressed.
///
- internal Action ProcessInput;
+ internal Action ProcessInput;
///
/// Initializes the class with the console driver.
@@ -1367,16 +1349,13 @@ void IMainLoopDriver.Setup (MainLoop mainLoop)
Task.Run (NetInputHandler, _inputHandlerTokenSource.Token);
}
- void IMainLoopDriver.Wakeup ()
- {
- _eventReady.Set ();
- }
+ void IMainLoopDriver.Wakeup () => _eventReady.Set ();
bool IMainLoopDriver.EventsPending ()
{
_waitForProbe.Set ();
- if (_mainLoop.CheckTimersAndIdleHandlers (out var waitTimeout)) {
+ if (_mainLoop.CheckTimersAndIdleHandlers (out int waitTimeout)) {
return true;
}
diff --git a/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs b/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs
index f9915d7952..c6baab686b 100644
--- a/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs
+++ b/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs
@@ -24,6 +24,7 @@
using System.Diagnostics;
using Terminal.Gui.ConsoleDrivers;
using static Unix.Terminal.Delegates;
+using static Terminal.Gui.ConsoleDrivers.ConsoleKeyMapping;
namespace Terminal.Gui;
@@ -371,7 +372,7 @@ public struct KeyEventRecord {
[FieldOffset (4), MarshalAs (UnmanagedType.U2)]
public ushort wRepeatCount;
[FieldOffset (6), MarshalAs (UnmanagedType.U2)]
- public ushort wVirtualKeyCode;
+ public VK wVirtualKeyCode;
[FieldOffset (8), MarshalAs (UnmanagedType.U2)]
public ushort wVirtualScanCode;
[FieldOffset (10)]
@@ -901,66 +902,31 @@ private void ChangeWin (Object s, SizeChangedEventArgs e)
}
#endif
+
KeyCode MapKey (WindowsConsole.ConsoleKeyInfoEx keyInfoEx)
{
var keyInfo = keyInfoEx.ConsoleKeyInfo;
switch (keyInfo.Key) {
- case ConsoleKey.Escape:
- return ConsoleKeyMapping.MapKeyModifiers (keyInfo, KeyCode.Esc);
- case ConsoleKey.Tab:
- return ConsoleKeyMapping.MapKeyModifiers (keyInfo, KeyCode.Tab);
- case ConsoleKey.Clear:
- return ConsoleKeyMapping.MapKeyModifiers (keyInfo, KeyCode.Clear);
- case ConsoleKey.Home:
- return ConsoleKeyMapping.MapKeyModifiers (keyInfo, KeyCode.Home);
- case ConsoleKey.End:
- return ConsoleKeyMapping.MapKeyModifiers (keyInfo, KeyCode.End);
- case ConsoleKey.LeftArrow:
- return ConsoleKeyMapping.MapKeyModifiers (keyInfo, KeyCode.CursorLeft);
- case ConsoleKey.RightArrow:
- return ConsoleKeyMapping.MapKeyModifiers (keyInfo, KeyCode.CursorRight);
- case ConsoleKey.UpArrow:
- return ConsoleKeyMapping.MapKeyModifiers (keyInfo, KeyCode.CursorUp);
- case ConsoleKey.DownArrow:
- return ConsoleKeyMapping.MapKeyModifiers (keyInfo, KeyCode.CursorDown);
- case ConsoleKey.PageUp:
- return ConsoleKeyMapping.MapKeyModifiers (keyInfo, KeyCode.PageUp);
- case ConsoleKey.PageDown:
- return ConsoleKeyMapping.MapKeyModifiers (keyInfo, KeyCode.PageDown);
- case ConsoleKey.Enter:
- return ConsoleKeyMapping.MapKeyModifiers (keyInfo, KeyCode.Enter);
- case ConsoleKey.Spacebar:
- return ConsoleKeyMapping.MapKeyModifiers (keyInfo, keyInfo.KeyChar == 0 ? KeyCode.Space : (KeyCode)keyInfo.KeyChar);
- case ConsoleKey.Backspace:
- return ConsoleKeyMapping.MapKeyModifiers (keyInfo, KeyCode.Backspace);
- case ConsoleKey.Delete:
- return ConsoleKeyMapping.MapKeyModifiers (keyInfo, KeyCode.DeleteChar);
- case ConsoleKey.Insert:
- return ConsoleKeyMapping.MapKeyModifiers (keyInfo, KeyCode.InsertChar);
- case ConsoleKey.PrintScreen:
- return ConsoleKeyMapping.MapKeyModifiers (keyInfo, KeyCode.PrintScreen);
-
- //case ConsoleKey.NumPad0:
- // return keyInfoEx.NumLock ? Key.D0 : Key.InsertChar;
- //case ConsoleKey.NumPad1:
- // return keyInfoEx.NumLock ? Key.D1 : Key.End;
- //case ConsoleKey.NumPad2:
- // return keyInfoEx.NumLock ? Key.D2 : Key.CursorDown;
- //case ConsoleKey.NumPad3:
- // return keyInfoEx.NumLock ? Key.D3 : Key.PageDown;
- //case ConsoleKey.NumPad4:
- // return keyInfoEx.NumLock ? Key.D4 : Key.CursorLeft;
- //case ConsoleKey.NumPad5:
- // return keyInfoEx.NumLock ? Key.D5 : (Key)((uint)keyInfo.KeyChar);
- //case ConsoleKey.NumPad6:
- // return keyInfoEx.NumLock ? Key.D6 : Key.CursorRight;
- //case ConsoleKey.NumPad7:
- // return keyInfoEx.NumLock ? Key.D7 : Key.Home;
- //case ConsoleKey.NumPad8:
- // return keyInfoEx.NumLock ? Key.D8 : Key.CursorUp;
- //case ConsoleKey.NumPad9:
- // return keyInfoEx.NumLock ? Key.D9 : Key.PageUp;
-
+ case ConsoleKey.D0:
+ case ConsoleKey.D1:
+ case ConsoleKey.D2:
+ case ConsoleKey.D3:
+ case ConsoleKey.D4:
+ case ConsoleKey.D5:
+ case ConsoleKey.D6:
+ case ConsoleKey.D7:
+ case ConsoleKey.D8:
+ case ConsoleKey.D9:
+ case ConsoleKey.NumPad0:
+ case ConsoleKey.NumPad1:
+ case ConsoleKey.NumPad2:
+ case ConsoleKey.NumPad3:
+ case ConsoleKey.NumPad4:
+ case ConsoleKey.NumPad5:
+ case ConsoleKey.NumPad6:
+ case ConsoleKey.NumPad7:
+ case ConsoleKey.NumPad8:
+ case ConsoleKey.NumPad9:
case ConsoleKey.Oem1:
case ConsoleKey.Oem2:
case ConsoleKey.Oem3:
@@ -970,148 +936,168 @@ KeyCode MapKey (WindowsConsole.ConsoleKeyInfoEx keyInfoEx)
case ConsoleKey.Oem7:
case ConsoleKey.Oem8:
case ConsoleKey.Oem102:
- var ret = ConsoleKeyMapping.MapKeyModifiers (keyInfo, (KeyCode)((uint)keyInfo.KeyChar));
- if (ret.HasFlag (KeyCode.ShiftMask)) {
- ret &= ~KeyCode.ShiftMask;
- }
- return ret;
-
+ case ConsoleKey.Multiply:
+ case ConsoleKey.Add:
+ case ConsoleKey.Separator:
+ case ConsoleKey.Subtract:
+ case ConsoleKey.Decimal:
+ case ConsoleKey.Divide:
case ConsoleKey.OemPeriod:
case ConsoleKey.OemComma:
case ConsoleKey.OemPlus:
case ConsoleKey.OemMinus:
- return (KeyCode)((uint)keyInfo.KeyChar);
- }
-
- var key = keyInfo.Key;
-
- if (key >= ConsoleKey.A && key <= ConsoleKey.Z) {
- var delta = key - ConsoleKey.A;
- if (keyInfo.Modifiers == ConsoleModifiers.Control) {
- return (KeyCode)(((uint)KeyCode.CtrlMask) | ((uint)KeyCode.A + delta));
- }
- if (keyInfo.Modifiers == ConsoleModifiers.Alt) {
- return (KeyCode)(((uint)KeyCode.AltMask) | ((uint)KeyCode.A + delta));
- }
- if (keyInfo.Modifiers == (ConsoleModifiers.Shift | ConsoleModifiers.Alt)) {
- return ConsoleKeyMapping.MapKeyModifiers (keyInfo, (KeyCode)((uint)KeyCode.A + delta));
- }
- if ((keyInfo.Modifiers & (ConsoleModifiers.Alt | ConsoleModifiers.Control)) != 0) {
- if (keyInfo.KeyChar == 0 || (keyInfo.KeyChar != 0 && keyInfo.KeyChar >= 1 && keyInfo.KeyChar <= 26)) {
- return ConsoleKeyMapping.MapKeyModifiers (keyInfo, (KeyCode)((uint)KeyCode.A + delta));
- }
+ // These virtual key codes are mapped differently depending on the keyboard layout in use.
+ // We use the Win32 API to map them to the correct character.
+ var mapResult = MapVKtoChar ((VK)keyInfo.Key);
+ if (mapResult == 0) {
+ // There is no mapping - this should not happen
+ Debug.Assert (mapResult != 0, $@"Unable to map the virtual key code {keyInfo.Key}.");
+ return KeyCode.Null;
}
- if (((keyInfo.Modifiers == ConsoleModifiers.Shift) ^ (keyInfoEx.CapsLock))) {
- if (keyInfo.KeyChar <= (uint)KeyCode.Z) {
- return (KeyCode)((uint)KeyCode.A + delta) | KeyCode.ShiftMask;
+ // An un-shifted character value is in the low order word of the return value.
+ var mappedChar = (char)(mapResult & 0x0000FFFF);
+
+ if (keyInfo.KeyChar == 0) {
+ // If the keyChar is 0, keyInfo.Key value is not a printable character.
+
+ // Dead keys (diacritics) are indicated by setting the top bit of the return value.
+ if ((mapResult & 0x80000000) != 0) {
+ // Dead key (e.g. Oem2 '~'/'^' on POR keyboard)
+ // Option 1: Throw it out.
+ // - Apps will never see the dead keys
+ // - If user presses a key that can be combined with the dead key ('a'), the right thing happens (app will see '').
+ // - NOTE: With Dead Keys, KeyDown != KeyUp. The KeyUp event will have just the base char ('a').
+ // - If user presses dead key again, the right thing happens (app will see `~~`)
+ // - This is what Notepad etc... appear to do
+ // Option 2: Expand the API to indicate the KeyCode is a dead key
+ // - Enables apps to do their own dead key processing
+ // - Adds complexity; no dev has asked for this (yet).
+ // We choose Option 1 for now.
+ return KeyCode.Null;
+
+ // Note: Ctrl-Deadkey (like Oem3 '`'/'~` on ENG) can't be supported.
+ // Sadly, the charVal is just the deadkey and subsequent key events do not contain
+ // any info that the previous event was a deadkey.
+ // Note WT does not support Ctrl-Deadkey either.
}
- }
- if (((KeyCode)((uint)keyInfo.KeyChar) & KeyCode.Space) == 0) {
- return (KeyCode)((uint)keyInfo.KeyChar) & ~KeyCode.Space;
- }
+ if (keyInfo.Modifiers != 0) {
+ // These Oem keys have well defined chars. We ensure the representative char is used.
+ // If we don't do this, then on some keyboard layouts the wrong char is
+ // returned (e.g. on ENG OemPlus un-shifted is =, not +). This is important
+ // for key persistence ("Ctrl++" vs. "Ctrl+=").
+ mappedChar = keyInfo.Key switch {
+ ConsoleKey.OemPeriod => '.',
+ ConsoleKey.OemComma => ',',
+ ConsoleKey.OemPlus => '+',
+ ConsoleKey.OemMinus => '-',
+ _ => mappedChar
+ };
+ }
- if (((KeyCode)((uint)keyInfo.KeyChar) & KeyCode.Space) != 0) {
- if (((KeyCode)((uint)keyInfo.KeyChar) & ~KeyCode.Space) == (KeyCode)keyInfo.Key) {
- return (KeyCode)((uint)keyInfo.KeyChar) & ~KeyCode.Space;
+ // Return the mappedChar with they modifiers. Because mappedChar is un-shifted, if Shift was down
+ // we should keep it
+ return MapToKeyCodeModifiers (keyInfo.Modifiers, (KeyCode)mappedChar);
+ } else {
+ // KeyChar is printable
+ if (keyInfo.Modifiers.HasFlag (ConsoleModifiers.Alt) && keyInfo.Modifiers.HasFlag (ConsoleModifiers.Control)) {
+ // AltGr support - AltGr is equivalent to Ctrl+Alt - the correct char is in KeyChar
+ return (KeyCode)keyInfo.KeyChar;
}
- return (KeyCode)((uint)keyInfo.KeyChar);
- }
- return (KeyCode)(uint)keyInfo.KeyChar;
+ if (keyInfo.Modifiers != ConsoleModifiers.Shift) {
+ // If Shift wasn't down we don't need to do anything but return the mappedChar
+ return MapToKeyCodeModifiers (keyInfo.Modifiers, (KeyCode)(mappedChar));
+ }
+ // Strip off Shift - We got here because they KeyChar from Windows is the shifted char (e.g. "")
+ // and passing on Shift would be redundant.
+ return MapToKeyCodeModifiers (keyInfo.Modifiers & ~ConsoleModifiers.Shift, (KeyCode)keyInfo.KeyChar);
+ }
}
- if (key >= ConsoleKey.D0 && key <= ConsoleKey.D9) {
- var delta = key - ConsoleKey.D0;
- if (keyInfo.Modifiers == ConsoleModifiers.Alt) {
- return (KeyCode)(((uint)KeyCode.AltMask) | ((uint)KeyCode.D0 + delta));
- }
- if (keyInfo.Modifiers == ConsoleModifiers.Control) {
- return (KeyCode)(((uint)KeyCode.CtrlMask) | ((uint)KeyCode.D0 + delta));
+ // A..Z are special cased:
+ // - Alone, they represent lowercase a...z
+ // - With ShiftMask they are A..Z
+ // - If CapsLock is on the above is reversed.
+ // - If Alt and/or Ctrl are present, treat as upper case
+ if (keyInfo.Key is >= ConsoleKey.A and <= ConsoleKey.Z) {
+ if (keyInfo.KeyChar == 0) {
+ // KeyChar is not printable - possibly an AltGr key?
+ // AltGr support - AltGr is equivalent to Ctrl+Alt
+ if (keyInfo.Modifiers.HasFlag (ConsoleModifiers.Alt) && keyInfo.Modifiers.HasFlag (ConsoleModifiers.Control)) {
+ return MapToKeyCodeModifiers (keyInfo.Modifiers, (KeyCode)(uint)keyInfo.Key);
+ }
}
- if (keyInfo.Modifiers == (ConsoleModifiers.Shift | ConsoleModifiers.Alt)) {
- return ConsoleKeyMapping.MapKeyModifiers (keyInfo, (KeyCode)((uint)KeyCode.D0 + delta));
+
+ if (keyInfo.Modifiers.HasFlag (ConsoleModifiers.Alt) || keyInfo.Modifiers.HasFlag (ConsoleModifiers.Control)) {
+ return MapToKeyCodeModifiers (keyInfo.Modifiers, (KeyCode)(uint)keyInfo.Key);
}
- if ((keyInfo.Modifiers & (ConsoleModifiers.Alt | ConsoleModifiers.Control)) != 0) {
- if (keyInfo.KeyChar == 0 || keyInfo.KeyChar == 30 || keyInfo.KeyChar == ((uint)KeyCode.D0 + delta)) {
- return ConsoleKeyMapping.MapKeyModifiers (keyInfo, (KeyCode)((uint)KeyCode.D0 + delta));
+
+ if (((keyInfo.Modifiers == ConsoleModifiers.Shift) ^ (keyInfoEx.CapsLock))) {
+ // If (ShiftMask is on and CapsLock is off) or (ShiftMask is off and CapsLock is on) add the ShiftMask
+ if (char.IsUpper (keyInfo.KeyChar)) {
+ return (KeyCode)((uint)keyInfo.Key) | KeyCode.ShiftMask;
}
}
- return (KeyCode)((uint)keyInfo.KeyChar);
+ return (KeyCode)(uint)keyInfo.KeyChar;
}
- if (key >= ConsoleKey.F1 && key <= ConsoleKey.F12) {
- var delta = key - ConsoleKey.F1;
- if ((keyInfo.Modifiers & (ConsoleModifiers.Shift | ConsoleModifiers.Alt | ConsoleModifiers.Control)) != 0) {
- return ConsoleKeyMapping.MapKeyModifiers (keyInfo, (KeyCode)((uint)KeyCode.F1 + delta));
+ // Handle control keys whose VK codes match the related ASCII value (those below ASCII 33) like ESC
+ if (Enum.IsDefined (typeof (KeyCode), (uint)keyInfo.Key)) {
+ // If the key is JUST a modifier, return it as just that key
+ if (keyInfo.Key == (ConsoleKey)VK.SHIFT) { // Shift 16
+ return KeyCode.ShiftMask;
}
- return (KeyCode)((uint)KeyCode.F1 + delta);
- }
+ if (keyInfo.Key == (ConsoleKey)VK.CONTROL) { // Ctrl 17
+ return KeyCode.CtrlMask;
+ }
- // If the key is JUST a modifier, return it as that key
- if (key == (ConsoleKey)16) { // Shift
- return KeyCode.ShiftKey;
- }
+ if (keyInfo.Key == (ConsoleKey)VK.MENU) { // Alt 18
+ return KeyCode.AltMask;
+ }
- if (key == (ConsoleKey)17) { // Ctrl
- return KeyCode.CtrlKey;
+ if (keyInfo.KeyChar == 0) {
+ return MapToKeyCodeModifiers (keyInfo.Modifiers, (KeyCode)(keyInfo.KeyChar));
+ } else {
+ return MapToKeyCodeModifiers (keyInfo.Modifiers & ~ConsoleModifiers.Shift, (KeyCode)(keyInfo.KeyChar));
+ }
}
- if (key == (ConsoleKey)18) { // Alt
- return KeyCode.AltKey;
+ // Handle control keys (e.g. CursorUp)
+ if (Enum.IsDefined (typeof (KeyCode), ((uint)keyInfo.Key + (uint)KeyCode.MaxCodePoint))) {
+ return MapToKeyCodeModifiers (keyInfo.Modifiers, (KeyCode)((uint)keyInfo.Key + (uint)KeyCode.MaxCodePoint));
}
- return ConsoleKeyMapping.MapKeyModifiers (keyInfo, (KeyCode)((uint)keyInfo.KeyChar));
+ return MapToKeyCodeModifiers (keyInfo.Modifiers, (KeyCode)(keyInfo.KeyChar));
}
- bool _altDown = false;
-
internal void ProcessInput (WindowsConsole.InputRecord inputEvent)
{
switch (inputEvent.EventType) {
case WindowsConsole.EventType.Key:
- var fromPacketKey = inputEvent.KeyEvent.wVirtualKeyCode == (uint)ConsoleKey.Packet;
- if (fromPacketKey) {
+ if (inputEvent.KeyEvent.wVirtualKeyCode == (VK)ConsoleKey.Packet) {
+ // Used to pass Unicode characters as if they were keystrokes.
+ // The VK_PACKET key is the low word of a 32-bit
+ // Virtual Key value used for non-keyboard input methods.
inputEvent.KeyEvent = FromVKPacketToKeyEventRecord (inputEvent.KeyEvent);
}
var keyInfo = ToConsoleKeyInfoEx (inputEvent.KeyEvent);
- //Debug.WriteLine ($"event: {inputEvent.ToString ()} {keyInfo.ToString (keyInfo)}");
-
+ //Debug.WriteLine ($"event: KBD: {GetKeyboardLayoutName()} {inputEvent.ToString ()} {keyInfo.ToString (keyInfo)}");
var map = MapKey (keyInfo);
+ if (map == KeyCode.Null) {
+ break;
+ }
+
if (inputEvent.KeyEvent.bKeyDown) {
- _altDown = keyInfo.ConsoleKeyInfo.Modifiers == ConsoleModifiers.Alt;
- // Avoid sending repeat keydowns
+ // Avoid sending repeat key down events
OnKeyDown (new Key (map));
} else {
- var keyPressedEventArgs = new Key (map);
-
- // PROTOTYPE: This logic enables `Alt` key presses (down, up, pressed).
- // However, if while the 'Alt' key is down, if another key is pressed and
- // released, there will be a keypressed event for that and the
- // keypressed event for just `Alt` will be suppressed.
- // This allows MenuBar to have `Alt` as a keybinding
- if (map != KeyCode.AltMask) {
- if (keyInfo.ConsoleKeyInfo.Modifiers.HasFlag (ConsoleModifiers.Alt)) {
- if (_altDown) {
- _altDown = false;
- OnKeyUp (new Key (map));
- }
-
- }
- _altDown = false;
- // KeyUp of an Alt-key press.
- OnKeyUp (keyPressedEventArgs);
- } else {
- OnKeyUp (keyPressedEventArgs);
- if (_altDown) {
- _altDown = false;
- }
- }
+ OnKeyUp (new Key (map));
}
break;
@@ -1422,7 +1408,7 @@ public WindowsConsole.ConsoleKeyInfoEx ToConsoleKeyInfoEx (WindowsConsole.KeyEve
public WindowsConsole.KeyEventRecord FromVKPacketToKeyEventRecord (WindowsConsole.KeyEventRecord keyEvent)
{
- if (keyEvent.wVirtualKeyCode != (uint)ConsoleKey.Packet) {
+ if (keyEvent.wVirtualKeyCode != (VK)ConsoleKey.Packet) {
return keyEvent;
}
@@ -1438,14 +1424,17 @@ public WindowsConsole.KeyEventRecord FromVKPacketToKeyEventRecord (WindowsConsol
keyEvent.dwControlKeyState.HasFlag (WindowsConsole.ControlKeyState.RightControlPressed)) {
mod |= ConsoleModifiers.Control;
}
- var cKeyInfo = ConsoleKeyMapping.GetConsoleKeyFromKey (keyEvent.UnicodeChar, mod, out uint scanCode);
+ var cKeyInfo = new ConsoleKeyInfo (keyEvent.UnicodeChar, (ConsoleKey)keyEvent.wVirtualKeyCode,
+ mod.HasFlag (ConsoleModifiers.Shift), mod.HasFlag (ConsoleModifiers.Alt), mod.HasFlag (ConsoleModifiers.Control));
+ cKeyInfo = DecodeVKPacketToKConsoleKeyInfo (cKeyInfo);
+ var scanCode = GetScanCodeFromConsoleKeyInfo (cKeyInfo);
return new WindowsConsole.KeyEventRecord {
UnicodeChar = cKeyInfo.KeyChar,
bKeyDown = keyEvent.bKeyDown,
dwControlKeyState = keyEvent.dwControlKeyState,
wRepeatCount = keyEvent.wRepeatCount,
- wVirtualKeyCode = (ushort)cKeyInfo.Key,
+ wVirtualKeyCode = (VK)cKeyInfo.Key,
wVirtualScanCode = (ushort)scanCode
};
}
@@ -1591,19 +1580,19 @@ public override void SendKeys (char keyChar, ConsoleKey key, bool shift, bool al
if (shift) {
controlKey |= WindowsConsole.ControlKeyState.ShiftPressed;
keyEvent.UnicodeChar = '\0';
- keyEvent.wVirtualKeyCode = 16;
+ keyEvent.wVirtualKeyCode = VK.SHIFT;
}
if (alt) {
controlKey |= WindowsConsole.ControlKeyState.LeftAltPressed;
controlKey |= WindowsConsole.ControlKeyState.RightAltPressed;
keyEvent.UnicodeChar = '\0';
- keyEvent.wVirtualKeyCode = 18;
+ keyEvent.wVirtualKeyCode = VK.MENU;
}
if (control) {
controlKey |= WindowsConsole.ControlKeyState.LeftControlPressed;
controlKey |= WindowsConsole.ControlKeyState.RightControlPressed;
keyEvent.UnicodeChar = '\0';
- keyEvent.wVirtualKeyCode = 17;
+ keyEvent.wVirtualKeyCode = VK.CONTROL;
}
keyEvent.dwControlKeyState = controlKey;
@@ -1614,11 +1603,12 @@ public override void SendKeys (char keyChar, ConsoleKey key, bool shift, bool al
}
keyEvent.UnicodeChar = keyChar;
- if ((uint)key < 255) {
- keyEvent.wVirtualKeyCode = (ushort)key;
- } else {
- keyEvent.wVirtualKeyCode = '\0';
- }
+ //if ((uint)key < 255) {
+ // keyEvent.wVirtualKeyCode = (ushort)key;
+ //} else {
+ // keyEvent.wVirtualKeyCode = '\0';
+ //}
+ keyEvent.wVirtualKeyCode = (VK)key;
input.KeyEvent = keyEvent;
diff --git a/Terminal.Gui/Input/Key.cs b/Terminal.Gui/Input/Key.cs
index c3498931b8..63cb98b87b 100644
--- a/Terminal.Gui/Input/Key.cs
+++ b/Terminal.Gui/Input/Key.cs
@@ -132,7 +132,8 @@ public Key (string str)
/// The encoded key value.
///
///
- /// IMPORTANT: Lowercase alpha keys are encoded (in ) as values between 65 and 90 corresponding to the un-shifted A to Z keys on a keyboard. Enum values
+ /// IMPORTANT: Lowercase alpha keys are encoded (in ) 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. , , etc.). Even though the values are the same as the ASCII
/// values for uppercase characters, these enum values represent *lowercase*, un-shifted characters.
///
@@ -147,24 +148,36 @@ public Key (string str)
public KeyBindingScope Scope { get; set; } = KeyBindingScope.Focused;
///
- /// The key value as a Rune. This is the actual value of the key pressed, and is independent of the modifiers.
+ /// The key value as a Rune. This is the actual value of the key pressed, and is independent of the modifiers. Useful
+ /// for determining if a key represents is a printable character.
///
///
///
- /// If the key is a letter (a-z or A-Z), the Rune be the upper or lower case letter depending on whether
- /// the shift key was pressed.
+ /// Keys with Ctrl or Alt modifiers will return .
+ ///
+ ///
+ /// If the key is a letter key (A-Z), the Rune will be the upper or lower case letter depending on whether
+ /// is set.
+ ///
+ ///
/// If the key is outside of the range, the returned Rune will be .
///
///
public Rune AsRune => ToRune (KeyCode);
///
- /// Converts a to a .
+ /// Converts a to a . Useful
+ /// for determining if a key represents is a printable character.
///
///
///
- /// If the key is a letter (a-z or A-Z), the Rune be the upper or lower case letter depending on whether
- /// the shift key was pressed.
+ /// Keys with Ctrl or Alt modifiers will return .
+ ///
+ ///
+ /// If the key is a letter key (A-Z), the Rune will be the upper or lower case letter depending on whether
+ /// is set.
+ ///
+ ///
/// If the key is outside of the range, the returned Rune will be .
///
///
@@ -176,23 +189,26 @@ public static Rune ToRune (KeyCode key)
return default;
}
- // Extract the base key (removing modifier flags)
- var baseKey = key & ~KeyCode.CtrlMask & ~KeyCode.AltMask & ~KeyCode.ShiftMask;
+ // Extract the base key code
+ var baseKey = key;
+ if (baseKey.HasFlag(KeyCode.ShiftMask)) {
+ baseKey &= ~KeyCode.ShiftMask;
+ }
switch (baseKey) {
case >= KeyCode.A and <= KeyCode.Z when !key.HasFlag (KeyCode.ShiftMask):
- return new Rune ((char)(baseKey + 32));
- case >= KeyCode.A and <= KeyCode.Z:
- return new Rune ((char)baseKey);
+ return new Rune ((uint)(baseKey + 32));
+ case >= KeyCode.A and <= KeyCode.Z when key.HasFlag (KeyCode.ShiftMask):
+ return new Rune ((uint)baseKey);
case > KeyCode.Null and < KeyCode.A:
- return new Rune ((char)baseKey);
+ return new Rune ((uint)baseKey);
}
if (Enum.IsDefined (typeof (KeyCode), baseKey)) {
return default;
}
- return new Rune ((char)baseKey);
+ return new Rune ((uint)baseKey);
}
///
@@ -214,7 +230,9 @@ public static Rune ToRune (KeyCode key)
public bool IsCtrl => (KeyCode & KeyCode.CtrlMask) != 0;
///
- /// Gets a value indicating whether the KeyCode is composed of a lower case letter from 'a' to 'z', independent of the shift key.
+ /// Gets a value indicating whether the key represents a key in the range of to ,
+ /// regardless of the . This is useful for testing if a key is based on these keys which are
+ /// special cased.
///
///
/// IMPORTANT: Lowercase alpha keys are encoded in as values between 65 and 90 corresponding to
@@ -224,7 +242,9 @@ public static Rune ToRune (KeyCode key)
public bool IsKeyCodeAtoZ => GetIsKeyCodeAtoZ (KeyCode);
///
- /// Tests if a KeyCode is composed of a lower case letter from 'a' to 'z', independent of the shift key.
+ /// Tests if a KeyCode represents a key in the range of to ,
+ /// regardless of the . This is useful for testing if a key is based on these keys which are
+ /// special cased.
///
///
/// IMPORTANT: Lowercase alpha keys are encoded in as values between 65 and 90 corresponding to
@@ -303,7 +323,8 @@ public static bool GetIsKeyCodeAtoZ (KeyCode keyCode)
#region Operators
///
- /// Explicitly cast a to a . The conversion is lossy.
+ /// Explicitly cast a to a . The conversion is lossy because properties
+ /// such as are not encoded in .
///
///
/// Uses .
@@ -311,14 +332,17 @@ public static bool GetIsKeyCodeAtoZ (KeyCode keyCode)
///
public static explicit operator Rune (Key kea) => kea.AsRune;
+ // BUGBUG: (Tig) I do not think this cast operator is really needed.
///
- /// Explicitly cast to a . The conversion is lossy.
+ /// Explicitly cast to a . The conversion is lossy because properties
+ /// such as are not encoded in .
///
///
- public static explicit operator char (Key kea) => (char)kea.AsRune.Value;
+ public static explicit operator uint (Key kea) => (uint)kea.KeyCode;
///
- /// Explicitly cast to a . The conversion is lossy.
+ /// Explicitly cast to a . The conversion is lossy because properties
+ /// such as are not encoded in .
///
///
public static explicit operator KeyCode (Key key) => key.KeyCode;
@@ -365,6 +389,7 @@ public static bool GetIsKeyCodeAtoZ (KeyCode keyCode)
public override int GetHashCode () => (int)KeyCode;
///
+ /// Compares two s for equality.
///
///
///
@@ -372,6 +397,7 @@ public static bool GetIsKeyCodeAtoZ (KeyCode keyCode)
public static bool operator == (Key a, Key b) => a?.KeyCode == b?.KeyCode;
///
+ /// Compares two s for not equality.
///
///
///
@@ -427,15 +453,15 @@ static string GetKeyString (KeyCode key)
var baseKey = key & ~KeyCode.CtrlMask & ~KeyCode.AltMask & ~KeyCode.ShiftMask;
if (!key.HasFlag (KeyCode.ShiftMask) && baseKey is >= KeyCode.A and <= KeyCode.Z) {
- return ((char)(key + 32)).ToString ();
+ return ((Rune)(uint)(key + 32)).ToString ();
}
- if (key is >= KeyCode.Space and < KeyCode.A) {
- return ((char)key).ToString ();
+ if (key is > KeyCode.Space and < KeyCode.A) {
+ return ((Rune)(uint)key).ToString ();
}
string keyName = Enum.GetName (typeof (KeyCode), key);
- return !string.IsNullOrEmpty (keyName) ? keyName : ((char)key).ToString ();
+ return !string.IsNullOrEmpty (keyName) ? keyName : ((Rune)(uint)key).ToString ();
}
@@ -454,7 +480,7 @@ static string GetKeyString (KeyCode key)
/// The formatted string. If the key is a printable character, it will be returned as a string. Otherwise, the key name will be returned.
public static string ToString (KeyCode key, Rune separator)
{
- if (key is KeyCode.Null || (key & ~KeyCode.CtrlMask & ~KeyCode.AltMask & ~KeyCode.ShiftMask) == 0) {
+ if (key is KeyCode.Null) {
// Same as Key.IsValid
return @"Null";
}
@@ -489,21 +515,19 @@ public static string ToString (KeyCode key, Rune separator)
}
}
- string result = sb.ToString ();
- result = TrimEndRune (result, separator);
- return result;
+ return TrimEndSeparator (sb.ToString (), separator);
}
- static string TrimEndRune (string input, Rune runeToTrim)
+ static string TrimEndSeparator (string input, Rune separator)
{
- // Convert the Rune to a string (which may be one or two chars)
- string runeString = runeToTrim.ToString ();
+ // Trim the trailing separator (+). Unless there are two separators at the end.
+ // "+" (don't trim)
+ // "Ctrl+" (trim)
+ // "Ctrl++" (trim)
- if (input.EndsWith (runeString)) {
- // Remove the rune from the end of the string
- return input.Substring (0, input.Length - runeString.Length);
+ if (input.Length > 1 && new Rune(input [^1]) == separator && new Rune(input [^2]) != separator) {
+ return input [..^1];
}
-
return input;
}
@@ -543,13 +567,13 @@ public static bool TryParse (string text, [NotNullWhen (true)] out Key key)
if (parts.Length == 1) {
switch (parts [0]) {
case "Ctrl":
- key = new Key (KeyCode.CtrlKey);
+ key = new Key (KeyCode.CtrlMask);
return true;
case "Alt":
- key = new Key (KeyCode.AltKey);
+ key = new Key (KeyCode.AltMask);
return true;
case "Shift":
- key = new Key (KeyCode.ShiftKey);
+ key = new Key (KeyCode.ShiftMask);
return true;
}
}
@@ -655,26 +679,6 @@ public static bool TryParse (string text, [NotNullWhen (true)] out Key key)
///
public static Key Clear => new (KeyCode.Clear);
- ///
- /// The object for the Shift key.
- ///
- public static Key Shift => new (KeyCode.ShiftKey);
-
- ///
- /// The object for the Ctrl key.
- ///
- public static Key Ctrl => new (KeyCode.CtrlKey);
-
- ///
- /// The object for the Alt key.
- ///
- public static Key Alt => new (KeyCode.AltKey);
-
- ///
- /// The object for the CapsLock key.
- ///
- public static Key CapsLock => new (KeyCode.CapsLock);
-
///
/// The object for the Escape key.
///
@@ -913,12 +917,12 @@ public static bool TryParse (string text, [NotNullWhen (true)] out Key key)
///
/// The object for Insert Character key.
///
- public static Key InsertChar => new (KeyCode.InsertChar);
+ public static Key InsertChar => new (KeyCode.Insert);
///
/// The object for Delete Character key.
///
- public static Key DeleteChar => new (KeyCode.DeleteChar);
+ public static Key DeleteChar => new (KeyCode.Delete);
///
/// The object for Print Screen key.
diff --git a/Terminal.Gui/Terminal.Gui.csproj b/Terminal.Gui/Terminal.Gui.csproj
index a73a949234..af906ecf74 100644
--- a/Terminal.Gui/Terminal.Gui.csproj
+++ b/Terminal.Gui/Terminal.Gui.csproj
@@ -113,5 +113,6 @@
true
Miguel de Icaza, Tig Kindel (@tig), @BDisp
+ true
diff --git a/Terminal.Gui/Text/CollectionNavigatorBase.cs b/Terminal.Gui/Text/CollectionNavigatorBase.cs
index 64161ebca5..165215fc0b 100644
--- a/Terminal.Gui/Text/CollectionNavigatorBase.cs
+++ b/Terminal.Gui/Text/CollectionNavigatorBase.cs
@@ -1,217 +1,214 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Text;
+
+namespace Terminal.Gui;
+
+///
+/// Navigates a collection of items using keystrokes. The keystrokes are used to build a search string.
+/// The is used to find the next item in the collection that matches the search string
+/// when is called.
+///
+/// If the user types keystrokes that can't be found in the collection,
+/// the search string is cleared and the next item is found that starts with the last keystroke.
+///
+///
+/// If the user pauses keystrokes for a short time (see ), the search string is cleared.
+///
+///
+public abstract class CollectionNavigatorBase {
+ DateTime _lastKeystroke = DateTime.Now;
-namespace Terminal.Gui {
///
- /// Navigates a collection of items using keystrokes. The keystrokes are used to build a search string.
- /// The is used to find the next item in the collection that matches the search string
- /// when is called.
- ///
- /// If the user types keystrokes that can't be found in the collection,
- /// the search string is cleared and the next item is found that starts with the last keystroke.
- ///
- ///
- /// If the user pauses keystrokes for a short time (see ), the search string is cleared.
- ///
+ /// Gets or sets the number of milliseconds to delay before clearing the search string. The delay is
+ /// reset on each call to . The default is 500ms.
///
- public abstract class CollectionNavigatorBase {
-
- DateTime lastKeystroke = DateTime.Now;
- ///
- /// Gets or sets the number of milliseconds to delay before clearing the search string. The delay is
- /// reset on each call to . The default is 500ms.
- ///
- public int TypingDelay { get; set; } = 500;
-
- ///
- /// The compararer function to use when searching the collection.
- ///
- public StringComparer Comparer { get; set; } = StringComparer.InvariantCultureIgnoreCase;
-
- ///
- /// This event is invoked when changes. Useful for debugging.
- ///
- public event EventHandler SearchStringChanged;
-
- private string _searchString = "";
- ///
- /// Gets the current search string. This includes the set of keystrokes that have been pressed
- /// since the last unsuccessful match or after ) milliseconds. Useful for debugging.
- ///
- public string SearchString {
- get => _searchString;
- private set {
- _searchString = value;
- OnSearchStringChanged (new KeystrokeNavigatorEventArgs (value));
- }
- }
+ public int TypingDelay { get; set; } = 500;
- ///
- /// Invoked when the changes. Useful for debugging. Invokes the event.
- ///
- ///
- public virtual void OnSearchStringChanged (KeystrokeNavigatorEventArgs e)
- {
- SearchStringChanged?.Invoke (this, e);
- }
+ ///
+ /// The comparer function to use when searching the collection.
+ ///
+ public StringComparer Comparer { get; set; } = StringComparer.InvariantCultureIgnoreCase;
- ///
- /// Gets the index of the next item in the collection that matches the current plus the provided character (typically
- /// from a key press).
- ///
- /// The index in the collection to start the search from.
- /// The character of the key the user pressed.
- /// The index of the item that matches what the user has typed.
- /// Returns if no item in the collection matched.
- public int GetNextMatchingItem (int currentIndex, char keyStruck)
- {
- if (!char.IsControl (keyStruck)) {
-
- // maybe user pressed 'd' and now presses 'd' again.
- // a candidate search is things that begin with "dd"
- // but if we find none then we must fallback on cycling
- // d instead and discard the candidate state
- string candidateState = "";
-
- // is it a second or third (etc) keystroke within a short time
- if (SearchString.Length > 0 && DateTime.Now - lastKeystroke < TimeSpan.FromMilliseconds (TypingDelay)) {
- // "dd" is a candidate
- candidateState = SearchString + keyStruck;
- } else {
- // its a fresh keystroke after some time
- // or its first ever key press
- SearchString = new string (keyStruck, 1);
- }
+ ///
+ /// This event is invoked when changes. Useful for debugging.
+ ///
+ public event EventHandler SearchStringChanged;
- var idxCandidate = GetNextMatchingItem (currentIndex, candidateState,
- // prefer not to move if there are multiple characters e.g. "ca" + 'r' should stay on "car" and not jump to "cart"
- candidateState.Length > 1);
+ string _searchString = "";
- if (idxCandidate != -1) {
- // found "dd" so candidate searchstring is accepted
- lastKeystroke = DateTime.Now;
- SearchString = candidateState;
- return idxCandidate;
- }
+ ///
+ /// Gets the current search string. This includes the set of keystrokes that have been pressed
+ /// since the last unsuccessful match or after ) milliseconds. Useful for debugging.
+ ///
+ public string SearchString {
+ get => _searchString;
+ private set {
+ _searchString = value;
+ OnSearchStringChanged (new KeystrokeNavigatorEventArgs (value));
+ }
+ }
- //// nothing matches "dd" so discard it as a candidate
- //// and just cycle "d" instead
- lastKeystroke = DateTime.Now;
- idxCandidate = GetNextMatchingItem (currentIndex, candidateState);
-
- // if a match wasn't found, the user typed a 'wrong' key in their search ("can" + 'z'
- // instead of "can" + 'd').
- if (SearchString.Length > 1 && idxCandidate == -1) {
- // ignore it since we're still within the typing delay
- // don't add it to SearchString either
- return currentIndex;
- }
+ ///
+ /// Invoked when the changes. Useful for debugging. Invokes the event.
+ ///
+ ///
+ public virtual void OnSearchStringChanged (KeystrokeNavigatorEventArgs e) => SearchStringChanged?.Invoke (this, e);
- // if no changes to current state manifested
- if (idxCandidate == currentIndex || idxCandidate == -1) {
- // clear history and treat as a fresh letter
- ClearSearchString ();
+ ///
+ /// Gets the index of the next item in the collection that matches the current plus the provided character (typically
+ /// from a key press).
+ ///
+ /// The index in the collection to start the search from.
+ /// The character of the key the user pressed.
+ /// The index of the item that matches what the user has typed.
+ /// Returns if no item in the collection matched.
+ public int GetNextMatchingItem (int currentIndex, char keyStruck)
+ {
+ if (!char.IsControl (keyStruck)) {
+
+ // maybe user pressed 'd' and now presses 'd' again.
+ // a candidate search is things that begin with "dd"
+ // but if we find none then we must fallback on cycling
+ // d instead and discard the candidate state
+ string candidateState = "";
+
+ // is it a second or third (etc) keystroke within a short time
+ if (SearchString.Length > 0 && DateTime.Now - _lastKeystroke < TimeSpan.FromMilliseconds (TypingDelay)) {
+ // "dd" is a candidate
+ candidateState = SearchString + keyStruck;
+ } else {
+ // its a fresh keystroke after some time
+ // or its first ever key press
+ SearchString = new string (keyStruck, 1);
+ }
- // match on the fresh letter alone
- SearchString = new string (keyStruck, 1);
- idxCandidate = GetNextMatchingItem (currentIndex, SearchString);
- return idxCandidate == -1 ? currentIndex : idxCandidate;
- }
+ int idxCandidate = GetNextMatchingItem (currentIndex, candidateState,
+ // prefer not to move if there are multiple characters e.g. "ca" + 'r' should stay on "car" and not jump to "cart"
+ candidateState.Length > 1);
- // Found another "d" or just leave index as it was
+ if (idxCandidate != -1) {
+ // found "dd" so candidate search string is accepted
+ _lastKeystroke = DateTime.Now;
+ SearchString = candidateState;
return idxCandidate;
+ }
- } else {
- // clear state because keypress was a control char
- ClearSearchString ();
+ //// nothing matches "dd" so discard it as a candidate
+ //// and just cycle "d" instead
+ _lastKeystroke = DateTime.Now;
+ idxCandidate = GetNextMatchingItem (currentIndex, candidateState);
- // control char indicates no selection
- return -1;
+ // if a match wasn't found, the user typed a 'wrong' key in their search ("can" + 'z'
+ // instead of "can" + 'd').
+ if (SearchString.Length > 1 && idxCandidate == -1) {
+ // ignore it since we're still within the typing delay
+ // don't add it to SearchString either
+ return currentIndex;
}
- }
- ///
- /// Gets the index of the next item in the collection that matches .
- ///
- /// The index in the collection to start the search from.
- /// The search string to use.
- /// Set to to stop the search on the first match
- /// if there are multiple matches for .
- /// e.g. "ca" + 'r' should stay on "car" and not jump to "cart". If (the default),
- /// the next matching item will be returned, even if it is above in the collection.
- ///
- /// The index of the next matching item or if no match was found.
- internal int GetNextMatchingItem (int currentIndex, string search, bool minimizeMovement = false)
- {
- if (string.IsNullOrEmpty (search)) {
- return -1;
+ // if no changes to current state manifested
+ if (idxCandidate == currentIndex || idxCandidate == -1) {
+ // clear history and treat as a fresh letter
+ ClearSearchString ();
+
+ // match on the fresh letter alone
+ SearchString = new string (keyStruck, 1);
+ idxCandidate = GetNextMatchingItem (currentIndex, SearchString);
+ return idxCandidate == -1 ? currentIndex : idxCandidate;
}
- var collectionLength = GetCollectionLength ();
+ // Found another "d" or just leave index as it was
+ return idxCandidate;
- if (currentIndex != -1 && currentIndex < collectionLength && IsMatch (search, ElementAt (currentIndex))) {
- // we are already at a match
- if (minimizeMovement) {
- // if we would rather not jump around (e.g. user is typing lots of text to get this match)
- return currentIndex;
- }
+ } else {
+ // clear state because keypress was a control char
+ ClearSearchString ();
- for (int i = 1; i < collectionLength; i++) {
- //circular
- var idxCandidate = (i + currentIndex) % collectionLength;
- if (IsMatch (search, ElementAt (idxCandidate))) {
- return idxCandidate;
- }
- }
+ // control char indicates no selection
+ return -1;
+ }
+ }
+
+ ///
+ /// Gets the index of the next item in the collection that matches .
+ ///
+ /// The index in the collection to start the search from.
+ /// The search string to use.
+ /// Set to to stop the search on the first match
+ /// if there are multiple matches for .
+ /// e.g. "ca" + 'r' should stay on "car" and not jump to "cart". If (the default),
+ /// the next matching item will be returned, even if it is above in the collection.
+ ///
+ /// The index of the next matching item or if no match was found.
+ internal int GetNextMatchingItem (int currentIndex, string search, bool minimizeMovement = false)
+ {
+ if (string.IsNullOrEmpty (search)) {
+ return -1;
+ }
- // nothing else starts with the search term
+ int collectionLength = GetCollectionLength ();
+
+ if (currentIndex != -1 && currentIndex < collectionLength && IsMatch (search, ElementAt (currentIndex))) {
+ // we are already at a match
+ if (minimizeMovement) {
+ // if we would rather not jump around (e.g. user is typing lots of text to get this match)
return currentIndex;
- } else {
- // search terms no longer match the current selection or there is none
- for (int i = 0; i < collectionLength; i++) {
- if (IsMatch (search, ElementAt (i))) {
- return i;
- }
+ }
+
+ for (int i = 1; i < collectionLength; i++) {
+ //circular
+ int idxCandidate = (i + currentIndex) % collectionLength;
+ if (IsMatch (search, ElementAt (idxCandidate))) {
+ return idxCandidate;
}
+ }
- // Nothing matches
- return -1;
+ // nothing else starts with the search term
+ return currentIndex;
+ } else {
+ // search terms no longer match the current selection or there is none
+ for (int i = 0; i < collectionLength; i++) {
+ if (IsMatch (search, ElementAt (i))) {
+ return i;
+ }
}
+
+ // Nothing matches
+ return -1;
}
+ }
- ///
- /// Return the number of elements in the collection
- ///
- protected abstract int GetCollectionLength ();
+ ///
+ /// Return the number of elements in the collection
+ ///
+ protected abstract int GetCollectionLength ();
- private bool IsMatch (string search, object value)
- {
- return value?.ToString ().StartsWith (search, StringComparison.InvariantCultureIgnoreCase) ?? false;
- }
+ bool IsMatch (string search, object value) => value?.ToString ().StartsWith (search, StringComparison.InvariantCultureIgnoreCase) ?? false;
- ///
- /// Returns the collection being navigated element at .
- ///
- ///
- protected abstract object ElementAt (int idx);
+ ///
+ /// Returns the collection being navigated element at .
+ ///
+ ///
+ protected abstract object ElementAt (int idx);
- private void ClearSearchString ()
- {
- SearchString = "";
- lastKeystroke = DateTime.Now;
- }
+ void ClearSearchString ()
+ {
+ SearchString = "";
+ _lastKeystroke = DateTime.Now;
+ }
- ///
- /// Returns true if is a searchable key
- /// (e.g. letters, numbers, etc) that are valid to pass to this
- /// class for search filtering.
- ///
- ///
- ///
- public static bool IsCompatibleKey (Key a)
- {
- return !a.IsAlt && !a.IsCtrl;
- }
+ ///
+ /// Returns true if is a searchable key
+ /// (e.g. letters, numbers, etc) that are valid to pass to this
+ /// class for search filtering.
+ ///
+ ///
+ ///
+ public static bool IsCompatibleKey (Key a)
+ {
+ var rune = a.AsRune;
+ return rune != default && !Rune.IsControl (rune);
}
-}
+}
\ No newline at end of file
diff --git a/Terminal.Gui/View/ViewKeyboard.cs b/Terminal.Gui/View/ViewKeyboard.cs
index 27b79fbcfb..6caccdac4b 100644
--- a/Terminal.Gui/View/ViewKeyboard.cs
+++ b/Terminal.Gui/View/ViewKeyboard.cs
@@ -330,6 +330,10 @@ public bool NewKeyDownEvent (Key keyEvent)
}
// During (this is what can be cancelled)
+ InvokingKeyBindings?.Invoke (this, keyEvent);
+ if (keyEvent.Handled) {
+ return true;
+ }
var handled = OnInvokingKeyBindings (keyEvent);
if (handled != null && (bool)handled) {
return true;
@@ -553,9 +557,11 @@ public virtual bool OnKeyUp (Key keyEvent)
{
// fire event
// BUGBUG: KeyEventArgs doesn't include scope, so the event never sees it.
- InvokingKeyBindings?.Invoke (this, keyEvent);
- if (keyEvent.Handled) {
- return true;
+ if (keyEvent.Scope == KeyBindingScope.Application || keyEvent.Scope == KeyBindingScope.HotKey) {
+ InvokingKeyBindings?.Invoke (this, keyEvent);
+ if (keyEvent.Handled) {
+ return true;
+ }
}
// * If no key binding was found, `InvokeKeyBindings` returns `null`.
diff --git a/Terminal.Gui/Views/DateField.cs b/Terminal.Gui/Views/DateField.cs
index 56ed3d8b1a..4511f1bfd7 100644
--- a/Terminal.Gui/Views/DateField.cs
+++ b/Terminal.Gui/Views/DateField.cs
@@ -92,7 +92,7 @@ void Initialize (DateTime date, bool isShort = false)
AddCommand (Command.Right, () => MoveRight ());
// Default keybindings for this view
- KeyBindings.Add (KeyCode.DeleteChar, Command.DeleteCharRight);
+ KeyBindings.Add (KeyCode.Delete, Command.DeleteCharRight);
KeyBindings.Add (Key.D.WithCtrl, Command.DeleteCharRight);
KeyBindings.Add (Key.Delete, Command.DeleteCharLeft);
diff --git a/Terminal.Gui/Views/FileDialog.cs b/Terminal.Gui/Views/FileDialog.cs
index 9a5daabe13..4f8bb4bf1a 100644
--- a/Terminal.Gui/Views/FileDialog.cs
+++ b/Terminal.Gui/Views/FileDialog.cs
@@ -963,7 +963,7 @@ private bool TableView_KeyUp (Key keyEvent)
return this.history.Forward ();
}
- if (keyEvent.KeyCode == KeyCode.DeleteChar) {
+ if (keyEvent.KeyCode == KeyCode.Delete) {
Delete ();
return true;
diff --git a/Terminal.Gui/Views/TextField.cs b/Terminal.Gui/Views/TextField.cs
index ea737be7e9..acaf46fdbb 100644
--- a/Terminal.Gui/Views/TextField.cs
+++ b/Terminal.Gui/Views/TextField.cs
@@ -143,10 +143,9 @@ void SetInitialProperties (string text, int w)
// Default keybindings for this view
// We follow this as closely as possible: https://en.wikipedia.org/wiki/Table_of_keyboard_shortcuts
- KeyBindings.Add (KeyCode.DeleteChar, Command.DeleteCharRight);
+ KeyBindings.Add (KeyCode.Delete, Command.DeleteCharRight);
KeyBindings.Add (KeyCode.D | KeyCode.CtrlMask, Command.DeleteCharRight);
- KeyBindings.Add (KeyCode.Delete, Command.DeleteCharLeft);
KeyBindings.Add (KeyCode.Backspace, Command.DeleteCharLeft);
KeyBindings.Add (KeyCode.Home | KeyCode.ShiftMask, Command.LeftHomeExtend);
@@ -201,9 +200,9 @@ void SetInitialProperties (string text, int w)
KeyBindings.Add (KeyCode.CursorDown | KeyCode.CtrlMask, Command.WordRight);
KeyBindings.Add ((KeyCode)((int)'F' + KeyCode.AltMask), Command.WordRight);
- KeyBindings.Add (KeyCode.DeleteChar | KeyCode.CtrlMask, Command.KillWordForwards);
+ KeyBindings.Add (KeyCode.Delete | KeyCode.CtrlMask, Command.KillWordForwards);
KeyBindings.Add (KeyCode.Backspace | KeyCode.CtrlMask, Command.KillWordBackwards);
- KeyBindings.Add (KeyCode.InsertChar, Command.ToggleOverwrite);
+ KeyBindings.Add (KeyCode.Insert, Command.ToggleOverwrite);
KeyBindings.Add (KeyCode.C | KeyCode.CtrlMask, Command.Copy);
KeyBindings.Add (KeyCode.X | KeyCode.CtrlMask, Command.Cut);
KeyBindings.Add (KeyCode.V | KeyCode.CtrlMask, Command.Paste);
diff --git a/Terminal.Gui/Views/TextValidateField.cs b/Terminal.Gui/Views/TextValidateField.cs
index 7f3f74d349..4b967eda02 100644
--- a/Terminal.Gui/Views/TextValidateField.cs
+++ b/Terminal.Gui/Views/TextValidateField.cs
@@ -404,7 +404,7 @@ void Initialize ()
KeyBindings.Add (KeyCode.End, Command.RightEnd);
KeyBindings.Add (KeyCode.Delete, Command.DeleteCharRight);
- KeyBindings.Add (KeyCode.DeleteChar, Command.DeleteCharRight);
+ KeyBindings.Add (KeyCode.Delete, Command.DeleteCharRight);
KeyBindings.Add (KeyCode.Backspace, Command.DeleteCharLeft);
KeyBindings.Add (KeyCode.CursorLeft, Command.Left);
diff --git a/Terminal.Gui/Views/TextView.cs b/Terminal.Gui/Views/TextView.cs
index b5a2f71c9a..0626c6ea73 100644
--- a/Terminal.Gui/Views/TextView.cs
+++ b/Terminal.Gui/Views/TextView.cs
@@ -13,1611 +13,1601 @@
using System.Threading;
using Terminal.Gui.Resources;
-namespace Terminal.Gui {
+namespace Terminal.Gui;
+
+///
+/// Represents a single row/column within the . Includes the glyph and the foreground/background colors.
+///
+[DebuggerDisplay ("{DebuggerDisplay}")]
+public class RuneCell : IEquatable {
///
- /// Represents a single row/column within the . Includes the glyph and the foreground/background colors.
+ /// The glyph to draw.
///
- [DebuggerDisplay ("{DebuggerDisplay}")]
- public class RuneCell : IEquatable {
- ///
- /// The glyph to draw.
- ///
- [JsonConverter (typeof (RuneJsonConverter))]
- public Rune Rune { get; set; }
+ [JsonConverter (typeof (RuneJsonConverter))]
+ public Rune Rune { get; set; }
- ///
- /// The color sets to draw the glyph with.
- ///
- [JsonConverter (typeof (ColorSchemeJsonConverter))]
- public ColorScheme? ColorScheme { get; set; }
-
- /// Indicates whether the current object is equal to another object of the same type.
- /// An object to compare with this object.
- ///
- /// if the current object is equal to the parameter;
- /// otherwise, .
- public bool Equals (RuneCell? other)
- {
- return other != null &&
- Rune.Equals (other.Rune) &&
- ColorScheme == other.ColorScheme;
- }
+ ///
+ /// The color sets to draw the glyph with.
+ ///
+ [JsonConverter (typeof (ColorSchemeJsonConverter))]
+ public ColorScheme? ColorScheme { get; set; }
+
+ /// Indicates whether the current object is equal to another object of the same type.
+ /// An object to compare with this object.
+ ///
+ /// if the current object is equal to the parameter;
+ /// otherwise, .
+ public bool Equals (RuneCell? other) => other != null &&
+ Rune.Equals (other.Rune) &&
+ ColorScheme == other.ColorScheme;
+
+ /// Returns a string that represents the current object.
+ /// A string that represents the current object.
+ public override string ToString ()
+ {
+ string colorSchemeStr = ColorSchemeDebuggerDisplay ();
+ return DebuggerDisplay;
+ }
- /// Returns a string that represents the current object.
- /// A string that represents the current object.
- public override string ToString ()
- {
- string colorSchemeStr = ColorSchemeDebuggerDisplay ();
- return DebuggerDisplay;
+ string ColorSchemeDebuggerDisplay ()
+ {
+ string colorSchemeStr = "null";
+ if (ColorScheme != null) {
+ colorSchemeStr = $"Normal: {ColorScheme.Normal.Foreground},{ColorScheme.Normal.Background}; " +
+ $"Focus: {ColorScheme.Focus.Foreground},{ColorScheme.Focus.Background}; " +
+ $"HotNormal: {ColorScheme.HotNormal.Foreground},{ColorScheme.HotNormal.Background}; " +
+ $"HotFocus: {ColorScheme.HotFocus.Foreground},{ColorScheme.HotFocus.Background}; " +
+ $"Disabled: {ColorScheme.Disabled.Foreground},{ColorScheme.Disabled.Background}";
}
- private string ColorSchemeDebuggerDisplay ()
- {
- var colorSchemeStr = "null";
- if (ColorScheme != null) {
- colorSchemeStr = $"Normal: {ColorScheme.Normal.Foreground},{ColorScheme.Normal.Background}; " +
- $"Focus: {ColorScheme.Focus.Foreground},{ColorScheme.Focus.Background}; " +
- $"HotNormal: {ColorScheme.HotNormal.Foreground},{ColorScheme.HotNormal.Background}; " +
- $"HotFocus: {ColorScheme.HotFocus.Foreground},{ColorScheme.HotFocus.Background}; " +
- $"Disabled: {ColorScheme.Disabled.Foreground},{ColorScheme.Disabled.Background}";
- }
-
- return colorSchemeStr;
- }
+ return colorSchemeStr;
+ }
- private string DebuggerDisplay {
- get {
- string colorSchemeStr = ColorSchemeDebuggerDisplay ();
- return $"U+{Rune.Value:X4} '{Rune.ToString ()}'; {colorSchemeStr}";
- }
+ string DebuggerDisplay {
+ get {
+ string colorSchemeStr = ColorSchemeDebuggerDisplay ();
+ return $"U+{Rune.Value:X4} '{Rune.ToString ()}'; {colorSchemeStr}";
}
}
+}
- class TextModel {
- List> _lines = new List> ();
-
- public event EventHandler? LinesLoaded;
-
- public bool LoadFile (string file)
- {
- FilePath = file ?? throw new ArgumentNullException (nameof (file));
+class TextModel {
+ List> _lines = new ();
- using (var stream = File.OpenRead (file)) {
- LoadStream (stream);
- return true;
- }
- }
+ public event EventHandler? LinesLoaded;
- public bool CloseFile ()
- {
- if (FilePath == null)
- throw new ArgumentNullException (nameof (FilePath));
+ public bool LoadFile (string file)
+ {
+ FilePath = file ?? throw new ArgumentNullException (nameof (file));
- FilePath = null;
- _lines = new List> ();
+ using (var stream = File.OpenRead (file)) {
+ LoadStream (stream);
return true;
}
+ }
- // Turns the string into cells, this does not split the
- // contents on a newline if it is present.
- internal static List StringToRuneCells (string str, ColorScheme? colorScheme = null)
- {
- List cells = new List ();
- foreach (var rune in str.ToRunes ()) {
- cells.Add (new RuneCell { Rune = rune, ColorScheme = colorScheme });
- }
- return cells;
+ public bool CloseFile ()
+ {
+ if (FilePath == null) {
+ throw new ArgumentNullException (nameof (FilePath));
}
- internal static List ToRuneCells (IEnumerable runes, ColorScheme? colorScheme = null)
- {
- List cells = new List ();
- foreach (var rune in runes) {
- cells.Add (new RuneCell { Rune = rune, ColorScheme = colorScheme });
- }
- return cells;
+ FilePath = null;
+ _lines = new List> ();
+ return true;
+ }
+
+ // Turns the string into cells, this does not split the
+ // contents on a newline if it is present.
+ internal static List StringToRuneCells (string str, ColorScheme? colorScheme = null)
+ {
+ var cells = new List ();
+ foreach (var rune in str.ToRunes ()) {
+ cells.Add (new RuneCell { Rune = rune, ColorScheme = colorScheme });
}
+ return cells;
+ }
- private static List> ToRuneCells (List cells)
- {
- return SplitNewLines (cells);
+ internal static List ToRuneCells (IEnumerable runes, ColorScheme? colorScheme = null)
+ {
+ var cells = new List ();
+ foreach (var rune in runes) {
+ cells.Add (new RuneCell { Rune = rune, ColorScheme = colorScheme });
}
+ return cells;
+ }
- // Splits a string into a List that contains a List for each line
- public static List> StringToLinesOfRuneCells (string content, ColorScheme? colorScheme = null)
- {
- var cells = content.EnumerateRunes ().Select (x => new RuneCell () { Rune = x, ColorScheme = colorScheme }).ToList ();
+ static List> ToRuneCells (List cells) => SplitNewLines (cells);
- return SplitNewLines (cells);
- }
+ // Splits a string into a List that contains a List for each line
+ public static List> StringToLinesOfRuneCells (string content, ColorScheme? colorScheme = null)
+ {
+ var cells = content.EnumerateRunes ().Select (x => new RuneCell () { Rune = x, ColorScheme = colorScheme }).ToList ();
- private static List> SplitNewLines (List cells)
- {
- var lines = new List> ();
- int start = 0, i = 0;
- var hasCR = false;
- // ASCII code 13 = Carriage Return.
- // ASCII code 10 = Line Feed.
- for (; i < cells.Count; i++) {
- if (cells [i].Rune.Value == 13) {
- hasCR = true;
- continue;
- }
- if (cells [i].Rune.Value == 10) {
- if (i - start > 0)
- lines.Add (cells.GetRange (start, hasCR ? i - 1 - start : i - start));
- else
- lines.Add (StringToRuneCells (string.Empty));
- start = i + 1;
- hasCR = false;
+ return SplitNewLines (cells);
+ }
+
+ static List> SplitNewLines (List cells)
+ {
+ var lines = new List> ();
+ int start = 0, i = 0;
+ bool hasCR = false;
+ // ASCII code 13 = Carriage Return.
+ // ASCII code 10 = Line Feed.
+ for (; i < cells.Count; i++) {
+ if (cells [i].Rune.Value == 13) {
+ hasCR = true;
+ continue;
+ }
+ if (cells [i].Rune.Value == 10) {
+ if (i - start > 0) {
+ lines.Add (cells.GetRange (start, hasCR ? i - 1 - start : i - start));
+ } else {
+ lines.Add (StringToRuneCells (string.Empty));
}
+ start = i + 1;
+ hasCR = false;
}
- if (i - start >= 0)
- lines.Add (cells.GetRange (start, i - start));
- return lines;
}
+ if (i - start >= 0) {
+ lines.Add (cells.GetRange (start, i - start));
+ }
+ return lines;
+ }
- void Append (List line)
- {
- var str = StringExtensions.ToString (line.ToArray ());
- _lines.Add (StringToRuneCells (str));
+ void Append (List line)
+ {
+ string str = StringExtensions.ToString (line.ToArray ());
+ _lines.Add (StringToRuneCells (str));
+ }
+
+ public void LoadStream (Stream input)
+ {
+ if (input == null) {
+ throw new ArgumentNullException (nameof (input));
}
- public void LoadStream (Stream input)
- {
- if (input == null)
- throw new ArgumentNullException (nameof (input));
-
- _lines = new List> ();
- var buff = new BufferedStream (input);
- int v;
- var line = new List ();
- var wasNewLine = false;
- while ((v = buff.ReadByte ()) != -1) {
- if (v == 13) {
- continue;
- }
- if (v == 10) {
- Append (line);
- line.Clear ();
- wasNewLine = true;
- continue;
- }
- line.Add ((byte)v);
- wasNewLine = false;
+ _lines = new List> ();
+ var buff = new BufferedStream (input);
+ int v;
+ var line = new List ();
+ bool wasNewLine = false;
+ while ((v = buff.ReadByte ()) != -1) {
+ if (v == 13) {
+ continue;
}
- if (line.Count > 0 || wasNewLine)
+ if (v == 10) {
Append (line);
- buff.Dispose ();
-
- OnLinesLoaded ();
+ line.Clear ();
+ wasNewLine = true;
+ continue;
+ }
+ line.Add ((byte)v);
+ wasNewLine = false;
+ }
+ if (line.Count > 0 || wasNewLine) {
+ Append (line);
}
+ buff.Dispose ();
- public void LoadString (string content)
- {
- _lines = StringToLinesOfRuneCells (content);
+ OnLinesLoaded ();
+ }
- OnLinesLoaded ();
- }
+ public void LoadString (string content)
+ {
+ _lines = StringToLinesOfRuneCells (content);
- public void LoadRuneCells (List cells, ColorScheme? colorScheme)
- {
- _lines = ToRuneCells (cells);
- SetColorSchemes (colorScheme);
- OnLinesLoaded ();
- }
+ OnLinesLoaded ();
+ }
- public void LoadListRuneCells (List> cellsList, ColorScheme? colorScheme)
- {
- _lines = cellsList;
- SetColorSchemes (colorScheme);
- OnLinesLoaded ();
- }
+ public void LoadRuneCells (List cells, ColorScheme? colorScheme)
+ {
+ _lines = ToRuneCells (cells);
+ SetColorSchemes (colorScheme);
+ OnLinesLoaded ();
+ }
- private void SetColorSchemes (ColorScheme? colorScheme)
- {
- foreach (var line in _lines) {
- foreach (var cell in line) {
- if (cell.ColorScheme == null) {
- cell.ColorScheme = colorScheme;
- }
+ public void LoadListRuneCells (List> cellsList, ColorScheme? colorScheme)
+ {
+ _lines = cellsList;
+ SetColorSchemes (colorScheme);
+ OnLinesLoaded ();
+ }
+
+ void SetColorSchemes (ColorScheme? colorScheme)
+ {
+ foreach (var line in _lines) {
+ foreach (var cell in line) {
+ if (cell.ColorScheme == null) {
+ cell.ColorScheme = colorScheme;
}
}
}
+ }
- void OnLinesLoaded ()
- {
- LinesLoaded?.Invoke (this, EventArgs.Empty);
- }
+ void OnLinesLoaded () => LinesLoaded?.Invoke (this, EventArgs.Empty);
- public override string ToString ()
- {
- var sb = new StringBuilder ();
- for (int i = 0; i < _lines.Count; i++) {
- sb.Append (ToString (_lines [i]));
- if ((i + 1) < _lines.Count) {
- sb.AppendLine ();
- }
+ public override string ToString ()
+ {
+ var sb = new StringBuilder ();
+ for (int i = 0; i < _lines.Count; i++) {
+ sb.Append (ToString (_lines [i]));
+ if (i + 1 < _lines.Count) {
+ sb.AppendLine ();
}
- return sb.ToString ();
}
+ return sb.ToString ();
+ }
- public string? FilePath { get; set; }
+ public string? FilePath { get; set; }
- ///
- /// The number of text lines in the model
- ///
- public int Count => _lines.Count;
+ ///
+ /// The number of text lines in the model
+ ///
+ public int Count => _lines.Count;
- ///
- /// Returns the specified line as a List of Rune
- ///
- /// The line.
- /// Line number to retrieve.
- public List GetLine (int line)
- {
- if (_lines.Count > 0) {
- if (line < Count) {
- return _lines [line];
- } else {
- return _lines [Count - 1];
- }
+ ///
+ /// Returns the specified line as a List of Rune
+ ///
+ /// The line.
+ /// Line number to retrieve.
+ public List GetLine (int line)
+ {
+ if (_lines.Count > 0) {
+ if (line < Count) {
+ return _lines [line];
} else {
- _lines.Add (new List ());
- return _lines [0];
+ return _lines [Count - 1];
}
+ } else {
+ _lines.Add (new List ());
+ return _lines [0];
}
+ }
- public List> GetAllLines () => _lines;
+ public List> GetAllLines () => _lines;
- ///
- /// Adds a line to the model at the specified position.
- ///
- /// Line number where the line will be inserted.
- /// The line of text and color, as a List of RuneCell.
- public void AddLine (int pos, List cells)
- {
- _lines.Insert (pos, cells);
- }
+ ///
+ /// Adds a line to the model at the specified position.
+ ///
+ /// Line number where the line will be inserted.
+ /// The line of text and color, as a List of RuneCell.
+ public void AddLine (int pos, List cells) => _lines.Insert (pos, cells);
- ///
- /// Removes the line at the specified position
- ///
- /// Position.
- public void RemoveLine (int pos)
- {
- if (_lines.Count > 0) {
- if (_lines.Count == 1 && _lines [0].Count == 0) {
- return;
- }
- _lines.RemoveAt (pos);
+ ///
+ /// Removes the line at the specified position
+ ///
+ /// Position.
+ public void RemoveLine (int pos)
+ {
+ if (_lines.Count > 0) {
+ if (_lines.Count == 1 && _lines [0].Count == 0) {
+ return;
}
+ _lines.RemoveAt (pos);
}
+ }
- public void ReplaceLine (int pos, List runes)
- {
- if (_lines.Count > 0 && pos < _lines.Count) {
- _lines [pos] = new List (runes);
- } else if (_lines.Count == 0 || (_lines.Count > 0 && pos >= _lines.Count)) {
- _lines.Add (runes);
- }
+ public void ReplaceLine (int pos, List runes)
+ {
+ if (_lines.Count > 0 && pos < _lines.Count) {
+ _lines [pos] = new List (runes);
+ } else if (_lines.Count == 0 || _lines.Count > 0 && pos >= _lines.Count) {
+ _lines.Add (runes);
}
+ }
- ///
- /// Returns the maximum line length of the visible lines.
- ///
- /// The first line.
- /// The last line.
- /// The tab width.
- public int GetMaxVisibleLine (int first, int last, int tabWidth)
- {
- int maxLength = 0;
- last = last < _lines.Count ? last : _lines.Count;
- for (int i = first; i < last; i++) {
- var line = GetLine (i);
- var tabSum = line.Sum (c => c.Rune.Value == '\t' ? Math.Max (tabWidth - 1, 0) : 0);
- var l = line.Count + tabSum;
- if (l > maxLength) {
- maxLength = l;
- }
- }
+ ///
+ /// Returns the maximum line length of the visible lines.
+ ///
+ /// The first line.
+ /// The last line.
+ /// The tab width.
+ public int GetMaxVisibleLine (int first, int last, int tabWidth)
+ {
+ int maxLength = 0;
+ last = last < _lines.Count ? last : _lines.Count;
+ for (int i = first; i < last; i++) {
+ var line = GetLine (i);
+ int tabSum = line.Sum (c => c.Rune.Value == '\t' ? Math.Max (tabWidth - 1, 0) : 0);
+ int l = line.Count + tabSum;
+ if (l > maxLength) {
+ maxLength = l;
+ }
+ }
+
+ return maxLength;
+ }
- return maxLength;
+ internal static bool SetCol (ref int col, int width, int cols)
+ {
+ if (col + cols <= width) {
+ col += cols;
+ return true;
}
- internal static bool SetCol (ref int col, int width, int cols)
- {
- if (col + cols <= width) {
- col += cols;
- return true;
- }
+ return false;
+ }
- return false;
+ internal static int GetColFromX (List t, int start, int x, int tabWidth = 0)
+ {
+ var runes = new List ();
+ foreach (var cell in t) {
+ runes.Add (cell.Rune);
}
+ return GetColFromX (runes, start, x, tabWidth);
+ }
- internal static int GetColFromX (List t, int start, int x, int tabWidth = 0)
- {
- var runes = new List ();
- foreach (var cell in t) {
- runes.Add (cell.Rune);
+ internal static int GetColFromX (List t, int start, int x, int tabWidth = 0)
+ {
+ if (x < 0) {
+ return x;
+ }
+ int size = start;
+ int pX = x + start;
+ for (int i = start; i < t.Count; i++) {
+ var r = t [i];
+ size += r.GetColumns ();
+ if (r.Value == '\t') {
+ size += tabWidth + 1;
+ }
+ if (i == pX || size > pX) {
+ return i - start;
}
- return GetColFromX (runes, start, x, tabWidth);
}
+ return t.Count - start;
+ }
- internal static int GetColFromX (List t, int start, int x, int tabWidth = 0)
- {
- if (x < 0) {
- return x;
- }
- int size = start;
- var pX = x + start;
- for (int i = start; i < t.Count; i++) {
- var r = t [i];
- size += r.GetColumns ();
- if (r.Value == '\t') {
- size += tabWidth + 1;
- }
- if (i == pX || (size > pX)) {
- return i - start;
- }
- }
- return t.Count - start;
+ internal static (int size, int length) DisplaySize (List t, int start = -1, int end = -1,
+ bool checkNextRune = true, int tabWidth = 0)
+ {
+ var runes = new List ();
+ foreach (var cell in t) {
+ runes.Add (cell.Rune);
}
+ return DisplaySize (runes, start, end, checkNextRune, tabWidth);
+ }
- internal static (int size, int length) DisplaySize (List t, int start = -1, int end = -1,
- bool checkNextRune = true, int tabWidth = 0)
- {
- List runes = new List ();
- foreach (var cell in t) {
- runes.Add (cell.Rune);
+ // Returns the size and length in a range of the string.
+ internal static (int size, int length) DisplaySize (List t, int start = -1, int end = -1,
+ bool checkNextRune = true, int tabWidth = 0)
+ {
+ if (t == null || t.Count == 0) {
+ return (0, 0);
+ }
+ int size = 0;
+ int len = 0;
+ int tcount = end == -1 ? t.Count : end > t.Count ? t.Count : end;
+ int i = start == -1 ? 0 : start;
+ for (; i < tcount; i++) {
+ var rune = t [i];
+ size += rune.GetColumns ();
+ len += rune.GetEncodingLength (Encoding.Unicode);
+ if (rune.Value == '\t') {
+ size += tabWidth + 1;
+ len += tabWidth - 1;
+ }
+ if (checkNextRune && i == tcount - 1 && t.Count > tcount
+ && IsWideRune (t [i + 1], tabWidth, out int s, out int l)) {
+ size += s;
+ len += l;
}
- return DisplaySize (runes, start, end, checkNextRune, tabWidth);
}
- // Returns the size and length in a range of the string.
- internal static (int size, int length) DisplaySize (List t, int start = -1, int end = -1,
- bool checkNextRune = true, int tabWidth = 0)
+ bool IsWideRune (Rune r, int tWidth, out int s, out int l)
{
- if (t == null || t.Count == 0) {
- return (0, 0);
- }
- int size = 0;
- int len = 0;
- int tcount = end == -1 ? t.Count : end > t.Count ? t.Count : end;
- int i = start == -1 ? 0 : start;
- for (; i < tcount; i++) {
- var rune = t [i];
- size += rune.GetColumns ();
- len += rune.GetEncodingLength (Encoding.Unicode);
- if (rune.Value == '\t') {
- size += tabWidth + 1;
- len += tabWidth - 1;
- }
- if (checkNextRune && i == tcount - 1 && t.Count > tcount
- && IsWideRune (t [i + 1], tabWidth, out int s, out int l)) {
- size += s;
- len += l;
- }
+ s = r.GetColumns ();
+ l = r.GetEncodingLength ();
+ if (r.Value == '\t') {
+ s += tWidth + 1;
+ l += tWidth - 1;
}
- bool IsWideRune (Rune r, int tWidth, out int s, out int l)
- {
- s = r.GetColumns ();
- l = r.GetEncodingLength ();
- if (r.Value == '\t') {
- s += tWidth + 1;
- l += tWidth - 1;
- }
+ return s > 1;
+ }
- return s > 1;
- }
+ return (size, len);
+ }
- return (size, len);
+ internal static int CalculateLeftColumn (List t, int start, int end, int width, int tabWidth = 0)
+ {
+ var runes = new List ();
+ foreach (var cell in t) {
+ runes.Add (cell.Rune);
}
+ return CalculateLeftColumn (runes, start, end, width, tabWidth);
+ }
- internal static int CalculateLeftColumn (List t, int start, int end, int width, int tabWidth = 0)
- {
- List runes = new List ();
- foreach (var cell in t) {
- runes.Add (cell.Rune);
- }
- return CalculateLeftColumn (runes, start, end, width, tabWidth);
+ // Returns the left column in a range of the string.
+ internal static int CalculateLeftColumn (List t, int start, int end, int width, int tabWidth = 0)
+ {
+ if (t == null || t.Count == 0) {
+ return 0;
}
+ int size = 0;
+ int tcount = end > t.Count - 1 ? t.Count - 1 : end;
+ int col = 0;
- // Returns the left column in a range of the string.
- internal static int CalculateLeftColumn (List t, int start, int end, int width, int tabWidth = 0)
- {
- if (t == null || t.Count == 0) {
- return 0;
+ for (int i = tcount; i >= 0; i--) {
+ var rune = t [i];
+ size += rune.GetColumns ();
+ if (rune.Value == '\t') {
+ size += tabWidth + 1;
}
- int size = 0;
- int tcount = end > t.Count - 1 ? t.Count - 1 : end;
- int col = 0;
-
- for (int i = tcount; i >= 0; i--) {
- var rune = t [i];
- size += rune.GetColumns ();
- if (rune.Value == '\t') {
- size += tabWidth + 1;
- }
- if (size > width) {
- if (col + width == end) {
- col++;
- }
- break;
- } else if ((end < t.Count && col > 0 && start < end && col == start) || (end - col == width - 1)) {
- break;
+ if (size > width) {
+ if (col + width == end) {
+ col++;
}
- col = i;
+ break;
+ } else if (end < t.Count && col > 0 && start < end && col == start || end - col == width - 1) {
+ break;
}
-
- return col;
+ col = i;
}
- (Point startPointToFind, Point currentPointToFind, bool found) _toFind;
+ return col;
+ }
- internal (Point current, bool found) FindNextText (string text, out bool gaveFullTurn, bool matchCase = false, bool matchWholeWord = false)
- {
- if (text == null || _lines.Count == 0) {
- gaveFullTurn = false;
- return (Point.Empty, false);
- }
+ (Point startPointToFind, Point currentPointToFind, bool found) _toFind;
- if (_toFind.found) {
- _toFind.currentPointToFind.X++;
- }
- var foundPos = GetFoundNextTextPoint (text, _lines.Count, matchCase, matchWholeWord, _toFind.currentPointToFind);
- if (!foundPos.found && _toFind.currentPointToFind != _toFind.startPointToFind) {
- foundPos = GetFoundNextTextPoint (text, _toFind.startPointToFind.Y + 1, matchCase, matchWholeWord, Point.Empty);
- }
- gaveFullTurn = ApplyToFind (foundPos);
+ internal (Point current, bool found) FindNextText (string text, out bool gaveFullTurn, bool matchCase = false, bool matchWholeWord = false)
+ {
+ if (text == null || _lines.Count == 0) {
+ gaveFullTurn = false;
+ return (Point.Empty, false);
+ }
- return foundPos;
+ if (_toFind.found) {
+ _toFind.currentPointToFind.X++;
}
+ var foundPos = GetFoundNextTextPoint (text, _lines.Count, matchCase, matchWholeWord, _toFind.currentPointToFind);
+ if (!foundPos.found && _toFind.currentPointToFind != _toFind.startPointToFind) {
+ foundPos = GetFoundNextTextPoint (text, _toFind.startPointToFind.Y + 1, matchCase, matchWholeWord, Point.Empty);
+ }
+ gaveFullTurn = ApplyToFind (foundPos);
- internal (Point current, bool found) FindPreviousText (string text, out bool gaveFullTurn, bool matchCase = false, bool matchWholeWord = false)
- {
- if (text == null || _lines.Count == 0) {
- gaveFullTurn = false;
- return (Point.Empty, false);
- }
+ return foundPos;
+ }
- if (_toFind.found) {
- _toFind.currentPointToFind.X++;
- }
- var linesCount = _toFind.currentPointToFind.IsEmpty ? _lines.Count - 1 : _toFind.currentPointToFind.Y;
- var foundPos = GetFoundPreviousTextPoint (text, linesCount, matchCase, matchWholeWord, _toFind.currentPointToFind);
- if (!foundPos.found && _toFind.currentPointToFind != _toFind.startPointToFind) {
- foundPos = GetFoundPreviousTextPoint (text, _lines.Count - 1, matchCase, matchWholeWord,
- new Point (_lines [_lines.Count - 1].Count, _lines.Count));
- }
- gaveFullTurn = ApplyToFind (foundPos);
+ internal (Point current, bool found) FindPreviousText (string text, out bool gaveFullTurn, bool matchCase = false, bool matchWholeWord = false)
+ {
+ if (text == null || _lines.Count == 0) {
+ gaveFullTurn = false;
+ return (Point.Empty, false);
+ }
- return foundPos;
+ if (_toFind.found) {
+ _toFind.currentPointToFind.X++;
}
+ int linesCount = _toFind.currentPointToFind.IsEmpty ? _lines.Count - 1 : _toFind.currentPointToFind.Y;
+ var foundPos = GetFoundPreviousTextPoint (text, linesCount, matchCase, matchWholeWord, _toFind.currentPointToFind);
+ if (!foundPos.found && _toFind.currentPointToFind != _toFind.startPointToFind) {
+ foundPos = GetFoundPreviousTextPoint (text, _lines.Count - 1, matchCase, matchWholeWord,
+ new Point (_lines [_lines.Count - 1].Count, _lines.Count));
+ }
+ gaveFullTurn = ApplyToFind (foundPos);
- internal (Point current, bool found) ReplaceAllText (string text, bool matchCase = false, bool matchWholeWord = false, string? textToReplace = null)
- {
- bool found = false;
- Point pos = Point.Empty;
-
- for (int i = 0; i < _lines.Count; i++) {
- var x = _lines [i];
- var txt = GetText (x);
- var matchText = !matchCase ? text.ToUpper () : text;
- var col = txt.IndexOf (matchText);
- while (col > -1) {
- if (matchWholeWord && !MatchWholeWord (txt, matchText, col)) {
- if (col + 1 > txt.Length) {
- break;
- }
- col = txt.IndexOf (matchText, col + 1);
- continue;
- }
- if (col > -1) {
- if (!found) {
- found = true;
- }
- _lines [i] = ToRuneCellList (ReplaceText (x, textToReplace!, matchText, col));
- x = _lines [i];
- txt = GetText (x);
- pos = new Point (col, i);
- col += (textToReplace!.Length - matchText.Length);
- }
- if (col < 0 || col + 1 > txt.Length) {
+ return foundPos;
+ }
+
+ internal (Point current, bool found) ReplaceAllText (string text, bool matchCase = false, bool matchWholeWord = false, string? textToReplace = null)
+ {
+ bool found = false;
+ var pos = Point.Empty;
+
+ for (int i = 0; i < _lines.Count; i++) {
+ var x = _lines [i];
+ string txt = GetText (x);
+ string matchText = !matchCase ? text.ToUpper () : text;
+ int col = txt.IndexOf (matchText);
+ while (col > -1) {
+ if (matchWholeWord && !MatchWholeWord (txt, matchText, col)) {
+ if (col + 1 > txt.Length) {
break;
}
col = txt.IndexOf (matchText, col + 1);
+ continue;
}
- }
-
- string GetText (List x)
- {
- var txt = ToString (x);
- if (!matchCase) {
- txt = txt.ToUpper ();
- }
- return txt;
- }
-
- return (pos, found);
- }
-
- string ReplaceText (List source, string textToReplace, string matchText, int col)
- {
- var origTxt = ToString (source);
- (int _, int len) = TextModel.DisplaySize (source, 0, col, false);
- (int _, int len2) = TextModel.DisplaySize (source, col, col + matchText.Length, false);
- (int _, int len3) = TextModel.DisplaySize (source, col + matchText.Length, origTxt.GetRuneCount (), false);
-
- return origTxt [..len] +
- textToReplace +
- origTxt.Substring (len + len2, len3);
- }
-
- bool ApplyToFind ((Point current, bool found) foundPos)
- {
- bool gaveFullTurn = false;
- if (foundPos.found) {
- _toFind.currentPointToFind = foundPos.current;
- if (_toFind.found && _toFind.currentPointToFind == _toFind.startPointToFind) {
- gaveFullTurn = true;
+ if (col > -1) {
+ if (!found) {
+ found = true;
+ }
+ _lines [i] = ToRuneCellList (ReplaceText (x, textToReplace!, matchText, col));
+ x = _lines [i];
+ txt = GetText (x);
+ pos = new Point (col, i);
+ col += textToReplace!.Length - matchText.Length;
}
- if (!_toFind.found) {
- _toFind.startPointToFind = _toFind.currentPointToFind = foundPos.current;
- _toFind.found = foundPos.found;
+ if (col < 0 || col + 1 > txt.Length) {
+ break;
}
+ col = txt.IndexOf (matchText, col + 1);
}
-
- return gaveFullTurn;
}
- (Point current, bool found) GetFoundNextTextPoint (string text, int linesCount, bool matchCase, bool matchWholeWord, Point start)
+ string GetText (List x)
{
- for (int i = start.Y; i < linesCount; i++) {
- var x = _lines [i];
- var txt = ToString (x);
- if (!matchCase) {
- txt = txt.ToUpper ();
- }
- var matchText = !matchCase ? text.ToUpper () : text;
- var col = txt.IndexOf (matchText, Math.Min (start.X, txt.Length));
- if (col > -1 && matchWholeWord && !MatchWholeWord (txt, matchText, col)) {
- continue;
- }
- if (col > -1 && ((i == start.Y && col >= start.X)
- || i > start.Y)
- && txt.Contains (matchText)) {
- return (new Point (col, i), true);
- } else if (col == -1 && start.X > 0) {
- start.X = 0;
- }
+ string txt = ToString (x);
+ if (!matchCase) {
+ txt = txt.ToUpper ();
}
-
- return (Point.Empty, false);
+ return txt;
}
- (Point current, bool found) GetFoundPreviousTextPoint (string text, int linesCount, bool matchCase, bool matchWholeWord, Point start)
- {
- for (int i = linesCount; i >= 0; i--) {
- var x = _lines [i];
- var txt = ToString (x);
- if (!matchCase) {
- txt = txt.ToUpper ();
- }
- if (start.Y != i) {
- start.X = Math.Max (x.Count - 1, 0);
- }
- var matchText = !matchCase ? text.ToUpper () : text;
- var col = txt.LastIndexOf (matchText, _toFind.found ? start.X - 1 : start.X);
- if (col > -1 && matchWholeWord && !MatchWholeWord (txt, matchText, col)) {
- continue;
- }
- if (col > -1 && ((i <= linesCount && col <= start.X)
- || i < start.Y)
- && txt.Contains (matchText)) {
- return (new Point (col, i), true);
- }
- }
-
- return (Point.Empty, false);
- }
+ return (pos, found);
+ }
- bool MatchWholeWord (string source, string matchText, int index = 0)
- {
- if (string.IsNullOrEmpty (source) || string.IsNullOrEmpty (matchText)) {
- return false;
- }
+ string ReplaceText (List source, string textToReplace, string matchText, int col)
+ {
+ string origTxt = ToString (source);
+ (int _, int len) = DisplaySize (source, 0, col, false);
+ (int _, int len2) = DisplaySize (source, col, col + matchText.Length, false);
+ (int _, int len3) = DisplaySize (source, col + matchText.Length, origTxt.GetRuneCount (), false);
- var txt = matchText.Trim ();
- var start = index > 0 ? index - 1 : 0;
- var end = index + txt.Length;
+ return origTxt [..len] +
+ textToReplace +
+ origTxt.Substring (len + len2, len3);
+ }
- if ((start == 0 || Rune.IsWhiteSpace ((Rune)source [start]))
- && (end == source.Length || Rune.IsWhiteSpace ((Rune)source [end]))) {
- return true;
+ bool ApplyToFind ((Point current, bool found) foundPos)
+ {
+ bool gaveFullTurn = false;
+ if (foundPos.found) {
+ _toFind.currentPointToFind = foundPos.current;
+ if (_toFind.found && _toFind.currentPointToFind == _toFind.startPointToFind) {
+ gaveFullTurn = true;
+ }
+ if (!_toFind.found) {
+ _toFind.startPointToFind = _toFind.currentPointToFind = foundPos.current;
+ _toFind.found = foundPos.found;
}
-
- return false;
}
- ///
- /// Redefine column and line tracking.
- ///
- /// Contains the column and line.
- internal void ResetContinuousFind (Point point)
- {
- _toFind.startPointToFind = _toFind.currentPointToFind = point;
- _toFind.found = false;
- }
+ return gaveFullTurn;
+ }
- RuneCell RuneAt (int col, int row)
- {
- var line = GetLine (row);
- if (line.Count > 0) {
- return line [col > line.Count - 1 ? line.Count - 1 : col];
- } else {
- return default!;
+ (Point current, bool found) GetFoundNextTextPoint (string text, int linesCount, bool matchCase, bool matchWholeWord, Point start)
+ {
+ for (int i = start.Y; i < linesCount; i++) {
+ var x = _lines [i];
+ string txt = ToString (x);
+ if (!matchCase) {
+ txt = txt.ToUpper ();
}
- }
-
- bool MoveNext (ref int col, ref int row, out Rune rune)
- {
- var line = GetLine (row);
- if (col + 1 < line.Count) {
- col++;
- rune = line [col].Rune;
- if (col + 1 == line.Count && !Rune.IsLetterOrDigit (rune)
- && !Rune.IsWhiteSpace (line [col - 1].Rune)) {
- col++;
- }
- return true;
- } else if (col + 1 == line.Count) {
- col++;
+ string matchText = !matchCase ? text.ToUpper () : text;
+ int col = txt.IndexOf (matchText, Math.Min (start.X, txt.Length));
+ if (col > -1 && matchWholeWord && !MatchWholeWord (txt, matchText, col)) {
+ continue;
}
- while (row + 1 < Count) {
- col = 0;
- row++;
- line = GetLine (row);
- if (line.Count > 0) {
- rune = line [0].Rune;
- return true;
- }
+ if (col > -1 && (i == start.Y && col >= start.X
+ || i > start.Y)
+ && txt.Contains (matchText)) {
+ return (new Point (col, i), true);
+ } else if (col == -1 && start.X > 0) {
+ start.X = 0;
}
- rune = default;
- return false;
}
- bool MovePrev (ref int col, ref int row, out Rune rune)
- {
- var line = GetLine (row);
+ return (Point.Empty, false);
+ }
- if (col > 0) {
- col--;
- rune = line [col].Rune;
- return true;
+ (Point current, bool found) GetFoundPreviousTextPoint (string text, int linesCount, bool matchCase, bool matchWholeWord, Point start)
+ {
+ for (int i = linesCount; i >= 0; i--) {
+ var x = _lines [i];
+ string txt = ToString (x);
+ if (!matchCase) {
+ txt = txt.ToUpper ();
}
- if (row == 0) {
- rune = default;
- return false;
+ if (start.Y != i) {
+ start.X = Math.Max (x.Count - 1, 0);
}
- while (row > 0) {
- row--;
- line = GetLine (row);
- col = line.Count - 1;
- if (col >= 0) {
- rune = line [col].Rune;
- return true;
- }
+ string matchText = !matchCase ? text.ToUpper () : text;
+ int col = txt.LastIndexOf (matchText, _toFind.found ? start.X - 1 : start.X);
+ if (col > -1 && matchWholeWord && !MatchWholeWord (txt, matchText, col)) {
+ continue;
+ }
+ if (col > -1 && (i <= linesCount && col <= start.X
+ || i < start.Y)
+ && txt.Contains (matchText)) {
+ return (new Point (col, i), true);
}
- rune = default;
- return false;
}
- enum RuneType {
- IsSymbol,
- IsWhiteSpace,
- IsLetterOrDigit,
- IsPunctuation,
- IsUnknow
+ return (Point.Empty, false);
+ }
+
+ bool MatchWholeWord (string source, string matchText, int index = 0)
+ {
+ if (string.IsNullOrEmpty (source) || string.IsNullOrEmpty (matchText)) {
+ return false;
}
- RuneType GetRuneType (Rune rune)
- {
- if (Rune.IsSymbol (rune)) {
- return RuneType.IsSymbol;
- } else if (Rune.IsWhiteSpace (rune)) {
- return RuneType.IsWhiteSpace;
- } else if (Rune.IsLetterOrDigit (rune)) {
- return RuneType.IsLetterOrDigit;
- } else if (Rune.IsPunctuation (rune)) {
- return RuneType.IsPunctuation;
+ string txt = matchText.Trim ();
+ int start = index > 0 ? index - 1 : 0;
+ int end = index + txt.Length;
+
+ if ((start == 0 || Rune.IsWhiteSpace ((Rune)source [start]))
+ && (end == source.Length || Rune.IsWhiteSpace ((Rune)source [end]))) {
+ return true;
+ }
+
+ return false;
+ }
+
+ ///
+ /// Redefine column and line tracking.
+ ///
+ /// Contains the column and line.
+ internal void ResetContinuousFind (Point point)
+ {
+ _toFind.startPointToFind = _toFind.currentPointToFind = point;
+ _toFind.found = false;
+ }
+
+ RuneCell RuneAt (int col, int row)
+ {
+ var line = GetLine (row);
+ if (line.Count > 0) {
+ return line [col > line.Count - 1 ? line.Count - 1 : col];
+ } else {
+ return default!;
+ }
+ }
+
+ bool MoveNext (ref int col, ref int row, out Rune rune)
+ {
+ var line = GetLine (row);
+ if (col + 1 < line.Count) {
+ col++;
+ rune = line [col].Rune;
+ if (col + 1 == line.Count && !Rune.IsLetterOrDigit (rune)
+ && !Rune.IsWhiteSpace (line [col - 1].Rune)) {
+ col++;
+ }
+ return true;
+ } else if (col + 1 == line.Count) {
+ col++;
+ }
+ while (row + 1 < Count) {
+ col = 0;
+ row++;
+ line = GetLine (row);
+ if (line.Count > 0) {
+ rune = line [0].Rune;
+ return true;
}
- return RuneType.IsUnknow;
}
+ rune = default;
+ return false;
+ }
- bool IsSameRuneType (Rune newRune, RuneType runeType)
- {
- var rt = GetRuneType (newRune);
- return rt == runeType;
+ bool MovePrev (ref int col, ref int row, out Rune rune)
+ {
+ var line = GetLine (row);
+
+ if (col > 0) {
+ col--;
+ rune = line [col].Rune;
+ return true;
+ }
+ if (row == 0) {
+ rune = default;
+ return false;
+ }
+ while (row > 0) {
+ row--;
+ line = GetLine (row);
+ col = line.Count - 1;
+ if (col >= 0) {
+ rune = line [col].Rune;
+ return true;
+ }
}
+ rune = default;
+ return false;
+ }
- public (int col, int row)? WordForward (int fromCol, int fromRow)
- {
- if (fromRow == _lines.Count - 1 && fromCol == GetLine (_lines.Count - 1).Count)
- return null;
+ enum RuneType {
+ IsSymbol,
+ IsWhiteSpace,
+ IsLetterOrDigit,
+ IsPunctuation,
+ IsUnknow
+ }
- var col = fromCol;
- var row = fromRow;
- try {
- var rune = RuneAt (col, row).Rune;
- var runeType = GetRuneType (rune);
- int lastValidCol = IsSameRuneType (rune, runeType) && (Rune.IsLetterOrDigit (rune) || Rune.IsPunctuation (rune) || Rune.IsSymbol (rune)) ? col : -1;
-
- void ProcMoveNext (ref int nCol, ref int nRow, Rune nRune)
- {
- if (Rune.IsWhiteSpace (nRune)) {
- while (MoveNext (ref nCol, ref nRow, out nRune)) {
- if (Rune.IsLetterOrDigit (nRune) || Rune.IsPunctuation (nRune) || Rune.IsSymbol (nRune)) {
- lastValidCol = nCol;
- return;
- }
- }
- if (nRow != fromRow && (Rune.IsLetterOrDigit (nRune) || Rune.IsPunctuation (nRune) || Rune.IsSymbol (nRune))) {
- if (lastValidCol > -1) {
- nCol = lastValidCol;
- }
+ RuneType GetRuneType (Rune rune)
+ {
+ if (Rune.IsSymbol (rune)) {
+ return RuneType.IsSymbol;
+ } else if (Rune.IsWhiteSpace (rune)) {
+ return RuneType.IsWhiteSpace;
+ } else if (Rune.IsLetterOrDigit (rune)) {
+ return RuneType.IsLetterOrDigit;
+ } else if (Rune.IsPunctuation (rune)) {
+ return RuneType.IsPunctuation;
+ }
+ return RuneType.IsUnknow;
+ }
+
+ bool IsSameRuneType (Rune newRune, RuneType runeType)
+ {
+ var rt = GetRuneType (newRune);
+ return rt == runeType;
+ }
+
+ public (int col, int row)? WordForward (int fromCol, int fromRow)
+ {
+ if (fromRow == _lines.Count - 1 && fromCol == GetLine (_lines.Count - 1).Count) {
+ return null;
+ }
+
+ int col = fromCol;
+ int row = fromRow;
+ try {
+ var rune = RuneAt (col, row).Rune;
+ var runeType = GetRuneType (rune);
+ int lastValidCol = IsSameRuneType (rune, runeType) && (Rune.IsLetterOrDigit (rune) || Rune.IsPunctuation (rune) || Rune.IsSymbol (rune)) ? col : -1;
+
+ void ProcMoveNext (ref int nCol, ref int nRow, Rune nRune)
+ {
+ if (Rune.IsWhiteSpace (nRune)) {
+ while (MoveNext (ref nCol, ref nRow, out nRune)) {
+ if (Rune.IsLetterOrDigit (nRune) || Rune.IsPunctuation (nRune) || Rune.IsSymbol (nRune)) {
+ lastValidCol = nCol;
return;
}
- while (MoveNext (ref nCol, ref nRow, out nRune)) {
- if (!Rune.IsLetterOrDigit (nRune) && !Rune.IsPunctuation (nRune) && !Rune.IsSymbol (nRune))
- break;
- if (nRow != fromRow) {
- break;
- }
- lastValidCol = IsSameRuneType (nRune, runeType) && Rune.IsLetterOrDigit (nRune) || Rune.IsPunctuation (nRune) || Rune.IsSymbol (nRune) ? nCol : lastValidCol;
- }
+ }
+ if (nRow != fromRow && (Rune.IsLetterOrDigit (nRune) || Rune.IsPunctuation (nRune) || Rune.IsSymbol (nRune))) {
if (lastValidCol > -1) {
nCol = lastValidCol;
- nRow = fromRow;
}
- } else {
- if (!MoveNext (ref nCol, ref nRow, out nRune)) {
- return;
- }
- if (!IsSameRuneType (nRune, runeType) && !Rune.IsWhiteSpace (nRune)) {
- return;
+ return;
+ }
+ while (MoveNext (ref nCol, ref nRow, out nRune)) {
+ if (!Rune.IsLetterOrDigit (nRune) && !Rune.IsPunctuation (nRune) && !Rune.IsSymbol (nRune)) {
+ break;
}
- var line = GetLine (nRow);
- if (nCol == line.Count && nRow == fromRow && (Rune.IsLetterOrDigit (line [0].Rune) || Rune.IsPunctuation (line [0].Rune) || Rune.IsSymbol (line [0].Rune))) {
- return;
+ if (nRow != fromRow) {
+ break;
}
lastValidCol = IsSameRuneType (nRune, runeType) && Rune.IsLetterOrDigit (nRune) || Rune.IsPunctuation (nRune) || Rune.IsSymbol (nRune) ? nCol : lastValidCol;
- if (fromRow != nRow) {
- nCol = 0;
- return;
- }
- ProcMoveNext (ref nCol, ref nRow, nRune);
}
+ if (lastValidCol > -1) {
+ nCol = lastValidCol;
+ nRow = fromRow;
+ }
+ } else {
+ if (!MoveNext (ref nCol, ref nRow, out nRune)) {
+ return;
+ }
+ if (!IsSameRuneType (nRune, runeType) && !Rune.IsWhiteSpace (nRune)) {
+ return;
+ }
+ var line = GetLine (nRow);
+ if (nCol == line.Count && nRow == fromRow && (Rune.IsLetterOrDigit (line [0].Rune) || Rune.IsPunctuation (line [0].Rune) || Rune.IsSymbol (line [0].Rune))) {
+ return;
+ }
+ lastValidCol = IsSameRuneType (nRune, runeType) && Rune.IsLetterOrDigit (nRune) || Rune.IsPunctuation (nRune) || Rune.IsSymbol (nRune) ? nCol : lastValidCol;
+ if (fromRow != nRow) {
+ nCol = 0;
+ return;
+ }
+ ProcMoveNext (ref nCol, ref nRow, nRune);
}
+ }
- ProcMoveNext (ref col, ref row, rune);
+ ProcMoveNext (ref col, ref row, rune);
- if (fromCol != col || fromRow != row)
- return (col, row);
- return null;
- } catch (Exception) {
- return null;
+ if (fromCol != col || fromRow != row) {
+ return (col, row);
}
+ return null;
+ } catch (Exception) {
+ return null;
}
+ }
- public (int col, int row)? WordBackward (int fromCol, int fromRow)
- {
- if (fromRow == 0 && fromCol == 0)
- return null;
+ public (int col, int row)? WordBackward (int fromCol, int fromRow)
+ {
+ if (fromRow == 0 && fromCol == 0) {
+ return null;
+ }
- var col = Math.Max (fromCol - 1, 0);
- var row = fromRow;
- try {
- RuneCell cell = RuneAt (col, row);
- Rune rune;
- if (cell != null) {
- rune = cell.Rune;
+ int col = Math.Max (fromCol - 1, 0);
+ int row = fromRow;
+ try {
+ var cell = RuneAt (col, row);
+ Rune rune;
+ if (cell != null) {
+ rune = cell.Rune;
+ } else {
+ if (col > 0) {
+ return (col, row);
+ } else if (col == 0 && row > 0) {
+ row--;
+ var line = GetLine (row);
+ return (line.Count, row);
} else {
- if (col > 0) {
- return (col, row);
- } else if (col == 0 && row > 0) {
- row--;
- var line = GetLine (row);
- return (line.Count, row);
- } else {
- return null;
- }
+ return null;
}
- var runeType = GetRuneType (rune);
- int lastValidCol = IsSameRuneType (rune, runeType) && (Rune.IsLetterOrDigit (rune) || Rune.IsPunctuation (rune) || Rune.IsSymbol (rune)) ? col : -1;
-
- void ProcMovePrev (ref int nCol, ref int nRow, Rune nRune)
- {
- if (Rune.IsWhiteSpace (nRune)) {
- while (MovePrev (ref nCol, ref nRow, out nRune)) {
- if (Rune.IsLetterOrDigit (nRune) || Rune.IsPunctuation (nRune) || Rune.IsSymbol (nRune)) {
- lastValidCol = nCol;
- if (runeType == RuneType.IsWhiteSpace || runeType == RuneType.IsUnknow) {
- runeType = GetRuneType (nRune);
- }
- break;
- }
- }
- if (nRow != fromRow && (Rune.IsLetterOrDigit (nRune) || Rune.IsPunctuation (nRune) || Rune.IsSymbol (nRune))) {
- if (lastValidCol > -1) {
- nCol = lastValidCol;
- }
- return;
- }
- while (MovePrev (ref nCol, ref nRow, out nRune)) {
- if (!Rune.IsLetterOrDigit (nRune) && !Rune.IsPunctuation (nRune) && !Rune.IsSymbol (nRune))
- break;
- if (nRow != fromRow) {
- break;
+ }
+ var runeType = GetRuneType (rune);
+ int lastValidCol = IsSameRuneType (rune, runeType) && (Rune.IsLetterOrDigit (rune) || Rune.IsPunctuation (rune) || Rune.IsSymbol (rune)) ? col : -1;
+
+ void ProcMovePrev (ref int nCol, ref int nRow, Rune nRune)
+ {
+ if (Rune.IsWhiteSpace (nRune)) {
+ while (MovePrev (ref nCol, ref nRow, out nRune)) {
+ if (Rune.IsLetterOrDigit (nRune) || Rune.IsPunctuation (nRune) || Rune.IsSymbol (nRune)) {
+ lastValidCol = nCol;
+ if (runeType == RuneType.IsWhiteSpace || runeType == RuneType.IsUnknow) {
+ runeType = GetRuneType (nRune);
}
- lastValidCol = IsSameRuneType (nRune, runeType) && Rune.IsLetterOrDigit (nRune) || Rune.IsPunctuation (nRune) || Rune.IsSymbol (nRune) ? nCol : lastValidCol;
+ break;
}
+ }
+ if (nRow != fromRow && (Rune.IsLetterOrDigit (nRune) || Rune.IsPunctuation (nRune) || Rune.IsSymbol (nRune))) {
if (lastValidCol > -1) {
nCol = lastValidCol;
- nRow = fromRow;
}
- } else {
- if (!MovePrev (ref nCol, ref nRow, out nRune)) {
- return;
+ return;
+ }
+ while (MovePrev (ref nCol, ref nRow, out nRune)) {
+ if (!Rune.IsLetterOrDigit (nRune) && !Rune.IsPunctuation (nRune) && !Rune.IsSymbol (nRune)) {
+ break;
}
-
- var line = GetLine (nRow);
- if (nCol == 0 && nRow == fromRow && (Rune.IsLetterOrDigit (line [0].Rune) || Rune.IsPunctuation (line [0].Rune) || Rune.IsSymbol (line [0].Rune))) {
- return;
+ if (nRow != fromRow) {
+ break;
}
lastValidCol = IsSameRuneType (nRune, runeType) && Rune.IsLetterOrDigit (nRune) || Rune.IsPunctuation (nRune) || Rune.IsSymbol (nRune) ? nCol : lastValidCol;
- if (lastValidCol > -1 && Rune.IsWhiteSpace (nRune)) {
- nCol = lastValidCol;
- return;
- }
- if (fromRow != nRow) {
- nCol = line.Count;
- return;
- }
- ProcMovePrev (ref nCol, ref nRow, nRune);
}
- }
-
- ProcMovePrev (ref col, ref row, rune);
+ if (lastValidCol > -1) {
+ nCol = lastValidCol;
+ nRow = fromRow;
+ }
+ } else {
+ if (!MovePrev (ref nCol, ref nRow, out nRune)) {
+ return;
+ }
- if (fromCol != col || fromRow != row)
- return (col, row);
- return null;
- } catch (Exception) {
- return null;
+ var line = GetLine (nRow);
+ if (nCol == 0 && nRow == fromRow && (Rune.IsLetterOrDigit (line [0].Rune) || Rune.IsPunctuation (line [0].Rune) || Rune.IsSymbol (line [0].Rune))) {
+ return;
+ }
+ lastValidCol = IsSameRuneType (nRune, runeType) && Rune.IsLetterOrDigit (nRune) || Rune.IsPunctuation (nRune) || Rune.IsSymbol (nRune) ? nCol : lastValidCol;
+ if (lastValidCol > -1 && Rune.IsWhiteSpace (nRune)) {
+ nCol = lastValidCol;
+ return;
+ }
+ if (fromRow != nRow) {
+ nCol = line.Count;
+ return;
+ }
+ ProcMovePrev (ref nCol, ref nRow, nRune);
+ }
}
- }
- ///
- /// Converts the string into a .
- ///
- /// The string to convert.
- /// The to use.
- ///
- public static List ToRuneCellList (string str, ColorScheme? colorScheme = null)
- {
- var cells = new List ();
- foreach (var rune in str.EnumerateRunes ()) {
- cells.Add (new RuneCell { Rune = rune, ColorScheme = colorScheme });
+ ProcMovePrev (ref col, ref row, rune);
+
+ if (fromCol != col || fromRow != row) {
+ return (col, row);
}
- return cells;
+ return null;
+ } catch (Exception) {
+ return null;
}
+ }
- ///
- /// Converts a generic collection into a string.
- ///
- /// The enumerable cell to convert.
- ///
- public static string ToString (IEnumerable cells)
- {
- var str = string.Empty;
+ ///
+ /// Converts the string into a .
+ ///
+ /// The string to convert.
+ /// The to use.
+ ///
+ public static List ToRuneCellList (string str, ColorScheme? colorScheme = null)
+ {
+ var cells = new List ();
+ foreach (var rune in str.EnumerateRunes ()) {
+ cells.Add (new RuneCell { Rune = rune, ColorScheme = colorScheme });
+ }
+ return cells;
+ }
- foreach (var cell in cells) {
- str += cell.Rune.ToString ();
- }
+ ///
+ /// Converts a generic collection into a string.
+ ///
+ /// The enumerable cell to convert.
+ ///
+ public static string ToString (IEnumerable cells)
+ {
+ string str = string.Empty;
- return str;
+ foreach (var cell in cells) {
+ str += cell.Rune.ToString ();
}
- }
- partial class HistoryText {
- public enum LineStatus {
- Original,
- Replaced,
- Removed,
- Added
- }
+ return str;
+ }
+}
- List _historyTextItems = new List ();
- int _idxHistoryText = -1;
- string? _originalText;
+partial class HistoryText {
+ public enum LineStatus {
+ Original,
+ Replaced,
+ Removed,
+ Added
+ }
- public bool IsFromHistory { get; private set; }
+ List _historyTextItems = new ();
+ int _idxHistoryText = -1;
+ string? _originalText;
- public bool HasHistoryChanges => _idxHistoryText > -1;
+ public bool IsFromHistory { get; private set; }
- public event EventHandler? ChangeText;
+ public bool HasHistoryChanges => _idxHistoryText > -1;
- public void Add (List> lines, Point curPos, LineStatus lineStatus = LineStatus.Original)
- {
- if (lineStatus == LineStatus.Original && _historyTextItems.Count > 0
- && _historyTextItems.Last ().LineStatus == LineStatus.Original) {
- return;
- }
- if (lineStatus == LineStatus.Replaced && _historyTextItems.Count > 0
- && _historyTextItems.Last ().LineStatus == LineStatus.Replaced) {
- return;
- }
+ public event EventHandler? ChangeText;
- if (_historyTextItems.Count == 0 && lineStatus != LineStatus.Original)
- throw new ArgumentException ("The first item must be the original.");
+ public void Add (List> lines, Point curPos, LineStatus lineStatus = LineStatus.Original)
+ {
+ if (lineStatus == LineStatus.Original && _historyTextItems.Count > 0
+ && _historyTextItems.Last ().LineStatus == LineStatus.Original) {
+ return;
+ }
+ if (lineStatus == LineStatus.Replaced && _historyTextItems.Count > 0
+ && _historyTextItems.Last ().LineStatus == LineStatus.Replaced) {
+ return;
+ }
- if (_idxHistoryText >= 0 && _idxHistoryText + 1 < _historyTextItems.Count)
- _historyTextItems.RemoveRange (_idxHistoryText + 1, _historyTextItems.Count - _idxHistoryText - 1);
+ if (_historyTextItems.Count == 0 && lineStatus != LineStatus.Original) {
+ throw new ArgumentException ("The first item must be the original.");
+ }
- _historyTextItems.Add (new HistoryTextItem (lines, curPos, lineStatus));
- _idxHistoryText++;
+ if (_idxHistoryText >= 0 && _idxHistoryText + 1 < _historyTextItems.Count) {
+ _historyTextItems.RemoveRange (_idxHistoryText + 1, _historyTextItems.Count - _idxHistoryText - 1);
}
- public void ReplaceLast (List> lines, Point curPos, LineStatus lineStatus)
- {
- var found = _historyTextItems.FindLast (x => x.LineStatus == lineStatus);
- if (found != null) {
- found.Lines = lines;
- found.CursorPosition = curPos;
- }
+ _historyTextItems.Add (new HistoryTextItem (lines, curPos, lineStatus));
+ _idxHistoryText++;
+ }
+
+ public void ReplaceLast (List> lines, Point curPos, LineStatus lineStatus)
+ {
+ var found = _historyTextItems.FindLast (x => x.LineStatus == lineStatus);
+ if (found != null) {
+ found.Lines = lines;
+ found.CursorPosition = curPos;
}
+ }
- public void Undo ()
- {
- if (_historyTextItems?.Count > 0 && _idxHistoryText > 0) {
- IsFromHistory = true;
+ public void Undo ()
+ {
+ if (_historyTextItems?.Count > 0 && _idxHistoryText > 0) {
+ IsFromHistory = true;
- _idxHistoryText--;
+ _idxHistoryText--;
- var historyTextItem = new HistoryTextItem (_historyTextItems [_idxHistoryText]) {
- IsUndoing = true
- };
+ var historyTextItem = new HistoryTextItem (_historyTextItems [_idxHistoryText]) {
+ IsUndoing = true
+ };
- ProcessChanges (ref historyTextItem);
+ ProcessChanges (ref historyTextItem);
- IsFromHistory = false;
- }
+ IsFromHistory = false;
}
+ }
- public void Redo ()
- {
- if (_historyTextItems?.Count > 0 && _idxHistoryText < _historyTextItems.Count - 1) {
- IsFromHistory = true;
+ public void Redo ()
+ {
+ if (_historyTextItems?.Count > 0 && _idxHistoryText < _historyTextItems.Count - 1) {
+ IsFromHistory = true;
- _idxHistoryText++;
+ _idxHistoryText++;
- var historyTextItem = new HistoryTextItem (_historyTextItems [_idxHistoryText]) {
- IsUndoing = false
- };
+ var historyTextItem = new HistoryTextItem (_historyTextItems [_idxHistoryText]) {
+ IsUndoing = false
+ };
- ProcessChanges (ref historyTextItem);
+ ProcessChanges (ref historyTextItem);
- IsFromHistory = false;
- }
+ IsFromHistory = false;
}
+ }
- void ProcessChanges (ref HistoryTextItem historyTextItem)
- {
- if (historyTextItem.IsUndoing) {
- if (_idxHistoryText - 1 > -1 && ((_historyTextItems [_idxHistoryText - 1].LineStatus == LineStatus.Added)
- || _historyTextItems [_idxHistoryText - 1].LineStatus == LineStatus.Removed
- || (historyTextItem.LineStatus == LineStatus.Replaced &&
- _historyTextItems [_idxHistoryText - 1].LineStatus == LineStatus.Original))) {
+ void ProcessChanges (ref HistoryTextItem historyTextItem)
+ {
+ if (historyTextItem.IsUndoing) {
+ if (_idxHistoryText - 1 > -1 && (_historyTextItems [_idxHistoryText - 1].LineStatus == LineStatus.Added
+ || _historyTextItems [_idxHistoryText - 1].LineStatus == LineStatus.Removed
+ || historyTextItem.LineStatus == LineStatus.Replaced &&
+ _historyTextItems [_idxHistoryText - 1].LineStatus == LineStatus.Original)) {
- _idxHistoryText--;
+ _idxHistoryText--;
- while (_historyTextItems [_idxHistoryText].LineStatus == LineStatus.Added
- && _historyTextItems [_idxHistoryText - 1].LineStatus == LineStatus.Removed) {
+ while (_historyTextItems [_idxHistoryText].LineStatus == LineStatus.Added
+ && _historyTextItems [_idxHistoryText - 1].LineStatus == LineStatus.Removed) {
- _idxHistoryText--;
- }
- historyTextItem = new HistoryTextItem (_historyTextItems [_idxHistoryText]);
- historyTextItem.IsUndoing = true;
- historyTextItem.FinalCursorPosition = historyTextItem.CursorPosition;
+ _idxHistoryText--;
}
+ historyTextItem = new HistoryTextItem (_historyTextItems [_idxHistoryText]);
+ historyTextItem.IsUndoing = true;
+ historyTextItem.FinalCursorPosition = historyTextItem.CursorPosition;
+ }
- if (historyTextItem.LineStatus == LineStatus.Removed && _historyTextItems [_idxHistoryText + 1].LineStatus == LineStatus.Added) {
- historyTextItem.RemovedOnAdded = new HistoryTextItem (_historyTextItems [_idxHistoryText + 1]);
- }
+ if (historyTextItem.LineStatus == LineStatus.Removed && _historyTextItems [_idxHistoryText + 1].LineStatus == LineStatus.Added) {
+ historyTextItem.RemovedOnAdded = new HistoryTextItem (_historyTextItems [_idxHistoryText + 1]);
+ }
- if ((historyTextItem.LineStatus == LineStatus.Added && _historyTextItems [_idxHistoryText - 1].LineStatus == LineStatus.Original)
- || (historyTextItem.LineStatus == LineStatus.Removed && _historyTextItems [_idxHistoryText - 1].LineStatus == LineStatus.Original)
- || (historyTextItem.LineStatus == LineStatus.Added && _historyTextItems [_idxHistoryText - 1].LineStatus == LineStatus.Removed)) {
+ if (historyTextItem.LineStatus == LineStatus.Added && _historyTextItems [_idxHistoryText - 1].LineStatus == LineStatus.Original
+ || historyTextItem.LineStatus == LineStatus.Removed && _historyTextItems [_idxHistoryText - 1].LineStatus == LineStatus.Original
+ || historyTextItem.LineStatus == LineStatus.Added && _historyTextItems [_idxHistoryText - 1].LineStatus == LineStatus.Removed) {
- if (!historyTextItem.Lines [0].SequenceEqual (_historyTextItems [_idxHistoryText - 1].Lines [0])
- && historyTextItem.CursorPosition == _historyTextItems [_idxHistoryText - 1].CursorPosition) {
- historyTextItem.Lines [0] = new List (_historyTextItems [_idxHistoryText - 1].Lines [0]);
- }
- if (historyTextItem.LineStatus == LineStatus.Added && _historyTextItems [_idxHistoryText - 1].LineStatus == LineStatus.Removed) {
- historyTextItem.FinalCursorPosition = _historyTextItems [_idxHistoryText - 2].CursorPosition;
- } else {
- historyTextItem.FinalCursorPosition = _historyTextItems [_idxHistoryText - 1].CursorPosition;
- }
+ if (!historyTextItem.Lines [0].SequenceEqual (_historyTextItems [_idxHistoryText - 1].Lines [0])
+ && historyTextItem.CursorPosition == _historyTextItems [_idxHistoryText - 1].CursorPosition) {
+ historyTextItem.Lines [0] = new List (_historyTextItems [_idxHistoryText - 1].Lines [0]);
+ }
+ if (historyTextItem.LineStatus == LineStatus.Added && _historyTextItems [_idxHistoryText - 1].LineStatus == LineStatus.Removed) {
+ historyTextItem.FinalCursorPosition = _historyTextItems [_idxHistoryText - 2].CursorPosition;
} else {
- historyTextItem.FinalCursorPosition = historyTextItem.CursorPosition;
+ historyTextItem.FinalCursorPosition = _historyTextItems [_idxHistoryText - 1].CursorPosition;
}
+ } else {
+ historyTextItem.FinalCursorPosition = historyTextItem.CursorPosition;
+ }
- OnChangeText (historyTextItem);
- while (_historyTextItems [_idxHistoryText].LineStatus == LineStatus.Removed
- || _historyTextItems [_idxHistoryText].LineStatus == LineStatus.Added) {
-
- _idxHistoryText--;
- }
- } else if (!historyTextItem.IsUndoing) {
- if (_idxHistoryText + 1 < _historyTextItems.Count && (historyTextItem.LineStatus == LineStatus.Original
- || _historyTextItems [_idxHistoryText + 1].LineStatus == LineStatus.Added
- || _historyTextItems [_idxHistoryText + 1].LineStatus == LineStatus.Removed)) {
-
- _idxHistoryText++;
- historyTextItem = new HistoryTextItem (_historyTextItems [_idxHistoryText]);
- historyTextItem.IsUndoing = false;
- historyTextItem.FinalCursorPosition = historyTextItem.CursorPosition;
- }
+ OnChangeText (historyTextItem);
+ while (_historyTextItems [_idxHistoryText].LineStatus == LineStatus.Removed
+ || _historyTextItems [_idxHistoryText].LineStatus == LineStatus.Added) {
- if (historyTextItem.LineStatus == LineStatus.Added && _historyTextItems [_idxHistoryText - 1].LineStatus == LineStatus.Removed) {
- historyTextItem.RemovedOnAdded = new HistoryTextItem (_historyTextItems [_idxHistoryText - 1]);
- }
+ _idxHistoryText--;
+ }
+ } else if (!historyTextItem.IsUndoing) {
+ if (_idxHistoryText + 1 < _historyTextItems.Count && (historyTextItem.LineStatus == LineStatus.Original
+ || _historyTextItems [_idxHistoryText + 1].LineStatus == LineStatus.Added
+ || _historyTextItems [_idxHistoryText + 1].LineStatus == LineStatus.Removed)) {
- if ((historyTextItem.LineStatus == LineStatus.Removed && _historyTextItems [_idxHistoryText + 1].LineStatus == LineStatus.Replaced)
- || (historyTextItem.LineStatus == LineStatus.Removed && _historyTextItems [_idxHistoryText + 1].LineStatus == LineStatus.Original)
- || (historyTextItem.LineStatus == LineStatus.Added && _historyTextItems [_idxHistoryText + 1].LineStatus == LineStatus.Replaced)) {
+ _idxHistoryText++;
+ historyTextItem = new HistoryTextItem (_historyTextItems [_idxHistoryText]);
+ historyTextItem.IsUndoing = false;
+ historyTextItem.FinalCursorPosition = historyTextItem.CursorPosition;
+ }
- if (historyTextItem.LineStatus == LineStatus.Removed
- && !historyTextItem.Lines [0].SequenceEqual (_historyTextItems [_idxHistoryText + 1].Lines [0])) {
- historyTextItem.Lines [0] = new List (_historyTextItems [_idxHistoryText + 1].Lines [0]);
- }
- historyTextItem.FinalCursorPosition = _historyTextItems [_idxHistoryText + 1].CursorPosition;
- } else {
- historyTextItem.FinalCursorPosition = historyTextItem.CursorPosition;
- }
+ if (historyTextItem.LineStatus == LineStatus.Added && _historyTextItems [_idxHistoryText - 1].LineStatus == LineStatus.Removed) {
+ historyTextItem.RemovedOnAdded = new HistoryTextItem (_historyTextItems [_idxHistoryText - 1]);
+ }
- OnChangeText (historyTextItem);
- while (_historyTextItems [_idxHistoryText].LineStatus == LineStatus.Removed
- || _historyTextItems [_idxHistoryText].LineStatus == LineStatus.Added) {
+ if (historyTextItem.LineStatus == LineStatus.Removed && _historyTextItems [_idxHistoryText + 1].LineStatus == LineStatus.Replaced
+ || historyTextItem.LineStatus == LineStatus.Removed && _historyTextItems [_idxHistoryText + 1].LineStatus == LineStatus.Original
+ || historyTextItem.LineStatus == LineStatus.Added && _historyTextItems [_idxHistoryText + 1].LineStatus == LineStatus.Replaced) {
- _idxHistoryText++;
+ if (historyTextItem.LineStatus == LineStatus.Removed
+ && !historyTextItem.Lines [0].SequenceEqual (_historyTextItems [_idxHistoryText + 1].Lines [0])) {
+ historyTextItem.Lines [0] = new List (_historyTextItems [_idxHistoryText + 1].Lines [0]);
}
+ historyTextItem.FinalCursorPosition = _historyTextItems [_idxHistoryText + 1].CursorPosition;
+ } else {
+ historyTextItem.FinalCursorPosition = historyTextItem.CursorPosition;
}
- }
-
- void OnChangeText (HistoryTextItem? lines)
- {
- ChangeText?.Invoke (this, lines!);
- }
- public void Clear (string text)
- {
- _historyTextItems.Clear ();
- _idxHistoryText = -1;
- _originalText = text;
- OnChangeText (null);
- }
+ OnChangeText (historyTextItem);
+ while (_historyTextItems [_idxHistoryText].LineStatus == LineStatus.Removed
+ || _historyTextItems [_idxHistoryText].LineStatus == LineStatus.Added) {
- public bool IsDirty (string text)
- {
- return _originalText != text;
+ _idxHistoryText++;
+ }
}
}
- class WordWrapManager {
- class WrappedLine {
- public int ModelLine;
- public int Row;
- public int RowIndex;
- public int ColWidth;
- }
+ void OnChangeText (HistoryTextItem? lines) => ChangeText?.Invoke (this, lines!);
- List _wrappedModelLines = new List ();
- int _frameWidth;
- bool _isWrapModelRefreshing;
+ public void Clear (string text)
+ {
+ _historyTextItems.Clear ();
+ _idxHistoryText = -1;
+ _originalText = text;
+ OnChangeText (null);
+ }
- public TextModel Model { get; private set; }
+ public bool IsDirty (string text) => _originalText != text;
+}
- public WordWrapManager (TextModel model)
- {
- Model = model;
- }
+class WordWrapManager {
+ class WrappedLine {
+ public int ModelLine;
+ public int Row;
+ public int RowIndex;
+ public int ColWidth;
+ }
- public TextModel WrapModel (int width, out int nRow, out int nCol, out int nStartRow, out int nStartCol,
- int row = 0, int col = 0, int startRow = 0, int startCol = 0, int tabWidth = 0, bool preserveTrailingSpaces = true)
- {
- _frameWidth = width;
-
- var modelRow = _isWrapModelRefreshing ? row : GetModelLineFromWrappedLines (row);
- var modelCol = _isWrapModelRefreshing ? col : GetModelColFromWrappedLines (row, col);
- var modelStartRow = _isWrapModelRefreshing ? startRow : GetModelLineFromWrappedLines (startRow);
- var modelStartCol = _isWrapModelRefreshing ? startCol : GetModelColFromWrappedLines (startRow, startCol);
- var wrappedModel = new TextModel ();
- int lines = 0;
- nRow = 0;
- nCol = 0;
- nStartRow = 0;
- nStartCol = 0;
- bool isRowAndColSetted = row == 0 && col == 0;
- bool isStartRowAndColSetted = startRow == 0 && startCol == 0;
- List wModelLines = new List ();
-
- for (int i = 0; i < Model.Count; i++) {
- var line = Model.GetLine (i);
- var wrappedLines = ToListRune (
- TextFormatter.Format (TextModel.ToString (line), width, TextAlignment.Left, true, preserveTrailingSpaces, tabWidth));
- int sumColWidth = 0;
- for (int j = 0; j < wrappedLines.Count; j++) {
- var wrapLine = wrappedLines [j];
- if (!isRowAndColSetted && modelRow == i) {
- if (nCol + wrapLine.Count <= modelCol) {
- nCol += wrapLine.Count;
- nRow = lines;
- if (nCol == modelCol) {
- nCol = wrapLine.Count;
- isRowAndColSetted = true;
- } else if (j == wrappedLines.Count - 1) {
- nCol = wrapLine.Count - j + modelCol - nCol;
- isRowAndColSetted = true;
- }
- } else {
- var offset = nCol + wrapLine.Count - modelCol;
- nCol = wrapLine.Count - offset;
- nRow = lines;
+ List _wrappedModelLines = new ();
+ int _frameWidth;
+ bool _isWrapModelRefreshing;
+
+ public TextModel Model { get; private set; }
+
+ public WordWrapManager (TextModel model) => Model = model;
+
+ public TextModel WrapModel (int width, out int nRow, out int nCol, out int nStartRow, out int nStartCol,
+ int row = 0, int col = 0, int startRow = 0, int startCol = 0, int tabWidth = 0, bool preserveTrailingSpaces = true)
+ {
+ _frameWidth = width;
+
+ int modelRow = _isWrapModelRefreshing ? row : GetModelLineFromWrappedLines (row);
+ int modelCol = _isWrapModelRefreshing ? col : GetModelColFromWrappedLines (row, col);
+ int modelStartRow = _isWrapModelRefreshing ? startRow : GetModelLineFromWrappedLines (startRow);
+ int modelStartCol = _isWrapModelRefreshing ? startCol : GetModelColFromWrappedLines (startRow, startCol);
+ var wrappedModel = new TextModel ();
+ int lines = 0;
+ nRow = 0;
+ nCol = 0;
+ nStartRow = 0;
+ nStartCol = 0;
+ bool isRowAndColSetted = row == 0 && col == 0;
+ bool isStartRowAndColSetted = startRow == 0 && startCol == 0;
+ var wModelLines = new List ();
+
+ for (int i = 0; i < Model.Count; i++) {
+ var line = Model.GetLine (i);
+ var wrappedLines = ToListRune (
+ TextFormatter.Format (TextModel.ToString (line), width, TextAlignment.Left, true, preserveTrailingSpaces, tabWidth));
+ int sumColWidth = 0;
+ for (int j = 0; j < wrappedLines.Count; j++) {
+ var wrapLine = wrappedLines [j];
+ if (!isRowAndColSetted && modelRow == i) {
+ if (nCol + wrapLine.Count <= modelCol) {
+ nCol += wrapLine.Count;
+ nRow = lines;
+ if (nCol == modelCol) {
+ nCol = wrapLine.Count;
+ isRowAndColSetted = true;
+ } else if (j == wrappedLines.Count - 1) {
+ nCol = wrapLine.Count - j + modelCol - nCol;
isRowAndColSetted = true;
}
+ } else {
+ int offset = nCol + wrapLine.Count - modelCol;
+ nCol = wrapLine.Count - offset;
+ nRow = lines;
+ isRowAndColSetted = true;
}
- if (!isStartRowAndColSetted && modelStartRow == i) {
- if (nStartCol + wrapLine.Count <= modelStartCol) {
- nStartCol += wrapLine.Count;
- nStartRow = lines;
- if (nStartCol == modelStartCol) {
- nStartCol = wrapLine.Count;
- isStartRowAndColSetted = true;
- } else if (j == wrappedLines.Count - 1) {
- nStartCol = wrapLine.Count - j + modelStartCol - nStartCol;
- isStartRowAndColSetted = true;
- }
- } else {
- var offset = nStartCol + wrapLine.Count - modelStartCol;
- nStartCol = wrapLine.Count - offset;
- nStartRow = lines;
+ }
+ if (!isStartRowAndColSetted && modelStartRow == i) {
+ if (nStartCol + wrapLine.Count <= modelStartCol) {
+ nStartCol += wrapLine.Count;
+ nStartRow = lines;
+ if (nStartCol == modelStartCol) {
+ nStartCol = wrapLine.Count;
+ isStartRowAndColSetted = true;
+ } else if (j == wrappedLines.Count - 1) {
+ nStartCol = wrapLine.Count - j + modelStartCol - nStartCol;
isStartRowAndColSetted = true;
}
+ } else {
+ int offset = nStartCol + wrapLine.Count - modelStartCol;
+ nStartCol = wrapLine.Count - offset;
+ nStartRow = lines;
+ isStartRowAndColSetted = true;
}
- for (int k = j; k < wrapLine.Count; k++) {
- wrapLine [k].ColorScheme = line [k].ColorScheme;
- }
- wrappedModel.AddLine (lines, wrapLine);
- sumColWidth += wrapLine.Count;
- var wrappedLine = new WrappedLine () {
- ModelLine = i,
- Row = lines,
- RowIndex = j,
- ColWidth = wrapLine.Count,
- };
- wModelLines.Add (wrappedLine);
- lines++;
}
+ for (int k = j; k < wrapLine.Count; k++) {
+ wrapLine [k].ColorScheme = line [k].ColorScheme;
+ }
+ wrappedModel.AddLine (lines, wrapLine);
+ sumColWidth += wrapLine.Count;
+ var wrappedLine = new WrappedLine () {
+ ModelLine = i,
+ Row = lines,
+ RowIndex = j,
+ ColWidth = wrapLine.Count
+ };
+ wModelLines.Add (wrappedLine);
+ lines++;
}
- _wrappedModelLines = wModelLines;
+ }
+ _wrappedModelLines = wModelLines;
+
+ return wrappedModel;
+ }
+
+ public List> ToListRune (List textList)
+ {
+ var runesList = new List> ();
- return wrappedModel;
+ foreach (string text in textList) {
+ runesList.Add (TextModel.ToRuneCellList (text));
}
- public List> ToListRune (List textList)
- {
- var runesList = new List> ();
+ return runesList;
+ }
- foreach (var text in textList) {
- runesList.Add (TextModel.ToRuneCellList (text));
- }
+ public int GetModelLineFromWrappedLines (int line) => _wrappedModelLines.Count > 0
+ ? _wrappedModelLines [Math.Min (line, _wrappedModelLines.Count - 1)].ModelLine
+ : 0;
- return runesList;
+ public int GetModelColFromWrappedLines (int line, int col)
+ {
+ if (_wrappedModelLines?.Count == 0) {
+ return 0;
}
- public int GetModelLineFromWrappedLines (int line) => _wrappedModelLines.Count > 0
- ? _wrappedModelLines [Math.Min (line, _wrappedModelLines.Count - 1)].ModelLine
- : 0;
+ int modelLine = GetModelLineFromWrappedLines (line);
+ int firstLine = _wrappedModelLines.IndexOf (r => r.ModelLine == modelLine);
+ int modelCol = 0;
- public int GetModelColFromWrappedLines (int line, int col)
- {
- if (_wrappedModelLines?.Count == 0) {
- return 0;
+ for (int i = firstLine; i <= Math.Min (line, _wrappedModelLines!.Count - 1); i++) {
+ var wLine = _wrappedModelLines [i];
+
+ if (i < line) {
+ modelCol += wLine.ColWidth;
+ } else {
+ modelCol += col;
}
+ }
+
+ return modelCol;
+ }
- var modelLine = GetModelLineFromWrappedLines (line);
- var firstLine = _wrappedModelLines.IndexOf (r => r.ModelLine == modelLine);
- int modelCol = 0;
+ List GetCurrentLine (int row) => Model.GetLine (row);
+
+ public void AddLine (int row, int col)
+ {
+ int modelRow = GetModelLineFromWrappedLines (row);
+ int modelCol = GetModelColFromWrappedLines (row, col);
+ var line = GetCurrentLine (modelRow);
+ int restCount = line.Count - modelCol;
+ var rest = line.GetRange (modelCol, restCount);
+ line.RemoveRange (modelCol, restCount);
+ Model.AddLine (modelRow + 1, rest);
+ _isWrapModelRefreshing = true;
+ WrapModel (_frameWidth, out _, out _, out _, out _, modelRow + 1, 0);
+ _isWrapModelRefreshing = false;
+ }
- for (int i = firstLine; i <= Math.Min (line, _wrappedModelLines!.Count - 1); i++) {
- var wLine = _wrappedModelLines [i];
+ public bool Insert (int row, int col, RuneCell cell)
+ {
+ var line = GetCurrentLine (GetModelLineFromWrappedLines (row));
+ line.Insert (GetModelColFromWrappedLines (row, col), cell);
+ if (line.Count > _frameWidth) {
+ return true;
+ } else {
+ return false;
+ }
+ }
- if (i < line) {
- modelCol += wLine.ColWidth;
- } else {
- modelCol += col;
- }
- }
+ public bool RemoveAt (int row, int col)
+ {
+ int modelRow = GetModelLineFromWrappedLines (row);
+ var line = GetCurrentLine (modelRow);
+ int modelCol = GetModelColFromWrappedLines (row, col);
- return modelCol;
+ if (modelCol > line.Count) {
+ Model.RemoveLine (modelRow);
+ RemoveAt (row, 0);
+ return false;
+ }
+ if (modelCol < line.Count) {
+ line.RemoveAt (modelCol);
+ }
+ if (line.Count > _frameWidth || row + 1 < _wrappedModelLines.Count
+ && _wrappedModelLines [row + 1].ModelLine == modelRow) {
+ return true;
}
- List GetCurrentLine (int row) => Model.GetLine (row);
+ return false;
+ }
- public void AddLine (int row, int col)
- {
- var modelRow = GetModelLineFromWrappedLines (row);
- var modelCol = GetModelColFromWrappedLines (row, col);
- var line = GetCurrentLine (modelRow);
- var restCount = line.Count - modelCol;
- var rest = line.GetRange (modelCol, restCount);
- line.RemoveRange (modelCol, restCount);
- Model.AddLine (modelRow + 1, rest);
- _isWrapModelRefreshing = true;
- WrapModel (_frameWidth, out _, out _, out _, out _, modelRow + 1, 0);
- _isWrapModelRefreshing = false;
- }
-
- public bool Insert (int row, int col, RuneCell cell)
- {
- var line = GetCurrentLine (GetModelLineFromWrappedLines (row));
- line.Insert (GetModelColFromWrappedLines (row, col), cell);
- if (line.Count > _frameWidth) {
+ public bool RemoveLine (int row, int col, out bool lineRemoved, bool forward = true)
+ {
+ lineRemoved = false;
+ int modelRow = GetModelLineFromWrappedLines (row);
+ var line = GetCurrentLine (modelRow);
+ int modelCol = GetModelColFromWrappedLines (row, col);
+
+ if (modelCol == 0 && line.Count == 0) {
+ Model.RemoveLine (modelRow);
+ return false;
+ } else if (modelCol < line.Count) {
+ if (forward) {
+ line.RemoveAt (modelCol);
+ return true;
+ } else if (modelCol - 1 > -1) {
+ line.RemoveAt (modelCol - 1);
return true;
- } else {
- return false;
}
}
-
- public bool RemoveAt (int row, int col)
- {
- var modelRow = GetModelLineFromWrappedLines (row);
- var line = GetCurrentLine (modelRow);
- var modelCol = GetModelColFromWrappedLines (row, col);
-
- if (modelCol > line.Count) {
- Model.RemoveLine (modelRow);
- RemoveAt (row, 0);
+ lineRemoved = true;
+ if (forward) {
+ if (modelRow + 1 == Model.Count) {
return false;
}
- if (modelCol < line.Count)
- line.RemoveAt (modelCol);
- if (line.Count > _frameWidth || (row + 1 < _wrappedModelLines.Count
- && _wrappedModelLines [row + 1].ModelLine == modelRow)) {
+
+ var nextLine = Model.GetLine (modelRow + 1);
+ line.AddRange (nextLine);
+ Model.RemoveLine (modelRow + 1);
+ if (line.Count > _frameWidth) {
return true;
}
+ } else {
+ if (modelRow == 0) {
+ return false;
+ }
- return false;
- }
-
- public bool RemoveLine (int row, int col, out bool lineRemoved, bool forward = true)
- {
- lineRemoved = false;
- var modelRow = GetModelLineFromWrappedLines (row);
- var line = GetCurrentLine (modelRow);
- var modelCol = GetModelColFromWrappedLines (row, col);
-
- if (modelCol == 0 && line.Count == 0) {
- Model.RemoveLine (modelRow);
- return false;
- } else if (modelCol < line.Count) {
- if (forward) {
- line.RemoveAt (modelCol);
- return true;
- } else if (modelCol - 1 > -1) {
- line.RemoveAt (modelCol - 1);
- return true;
- }
+ var prevLine = Model.GetLine (modelRow - 1);
+ prevLine.AddRange (line);
+ Model.RemoveLine (modelRow);
+ if (prevLine.Count > _frameWidth) {
+ return true;
}
- lineRemoved = true;
- if (forward) {
- if (modelRow + 1 == Model.Count) {
- return false;
- }
+ }
- var nextLine = Model.GetLine (modelRow + 1);
- line.AddRange (nextLine);
- Model.RemoveLine (modelRow + 1);
- if (line.Count > _frameWidth) {
- return true;
- }
- } else {
- if (modelRow == 0) {
- return false;
- }
+ return false;
+ }
- var prevLine = Model.GetLine (modelRow - 1);
- prevLine.AddRange (line);
- Model.RemoveLine (modelRow);
- if (prevLine.Count > _frameWidth) {
- return true;
- }
- }
+ public bool RemoveRange (int row, int index, int count)
+ {
+ int modelRow = GetModelLineFromWrappedLines (row);
+ var line = GetCurrentLine (modelRow);
+ int modelCol = GetModelColFromWrappedLines (row, index);
+ try {
+ line.RemoveRange (modelCol, count);
+ } catch (Exception) {
return false;
}
- public bool RemoveRange (int row, int index, int count)
- {
- var modelRow = GetModelLineFromWrappedLines (row);
- var line = GetCurrentLine (modelRow);
- var modelCol = GetModelColFromWrappedLines (row, index);
-
- try {
- line.RemoveRange (modelCol, count);
- } catch (Exception) {
- return false;
- }
+ return true;
+ }
- return true;
- }
+ public void UpdateModel (TextModel model, out int nRow, out int nCol, out int nStartRow, out int nStartCol,
+ int row, int col, int startRow, int startCol, bool preserveTrailingSpaces)
+ {
+ _isWrapModelRefreshing = true;
+ Model = model;
+ WrapModel (_frameWidth, out nRow, out nCol, out nStartRow, out nStartCol, row, col, startRow, startCol, 0, preserveTrailingSpaces);
+ _isWrapModelRefreshing = false;
+ }
- public void UpdateModel (TextModel model, out int nRow, out int nCol, out int nStartRow, out int nStartCol,
- int row, int col, int startRow, int startCol, bool preserveTrailingSpaces)
- {
- _isWrapModelRefreshing = true;
- Model = model;
- WrapModel (_frameWidth, out nRow, out nCol, out nStartRow, out nStartCol, row, col, startRow, startCol, tabWidth: 0, preserveTrailingSpaces);
- _isWrapModelRefreshing = false;
+ public int GetWrappedLineColWidth (int line, int col, WordWrapManager wrapManager)
+ {
+ if (_wrappedModelLines?.Count == 0) {
+ return 0;
}
- public int GetWrappedLineColWidth (int line, int col, WordWrapManager wrapManager)
- {
- if (_wrappedModelLines?.Count == 0)
- return 0;
-
- var wModelLines = wrapManager._wrappedModelLines;
- var modelLine = GetModelLineFromWrappedLines (line);
- var firstLine = _wrappedModelLines.IndexOf (r => r.ModelLine == modelLine);
- int modelCol = 0;
- int colWidthOffset = 0;
- int i = firstLine;
+ var wModelLines = wrapManager._wrappedModelLines;
+ int modelLine = GetModelLineFromWrappedLines (line);
+ int firstLine = _wrappedModelLines.IndexOf (r => r.ModelLine == modelLine);
+ int modelCol = 0;
+ int colWidthOffset = 0;
+ int i = firstLine;
- while (modelCol < col) {
- var wLine = _wrappedModelLines! [i];
- var wLineToCompare = wModelLines [i];
-
- if (wLine.ModelLine != modelLine || wLineToCompare.ModelLine != modelLine)
- break;
+ while (modelCol < col) {
+ var wLine = _wrappedModelLines! [i];
+ var wLineToCompare = wModelLines [i];
- modelCol += Math.Max (wLine.ColWidth, wLineToCompare.ColWidth);
- colWidthOffset += wLine.ColWidth - wLineToCompare.ColWidth;
- if (modelCol > col) {
- modelCol += col - modelCol;
- }
- i++;
+ if (wLine.ModelLine != modelLine || wLineToCompare.ModelLine != modelLine) {
+ break;
}
- return modelCol - colWidthOffset;
+ modelCol += Math.Max (wLine.ColWidth, wLineToCompare.ColWidth);
+ colWidthOffset += wLine.ColWidth - wLineToCompare.ColWidth;
+ if (modelCol > col) {
+ modelCol += col - modelCol;
+ }
+ i++;
}
+
+ return modelCol - colWidthOffset;
}
+}
+
+///
+/// Multi-line text editing .
+///
+///
+///
+/// provides a multi-line text editor. Users interact
+/// with it with the standard Windows, Mac, and Linux (Emacs) commands.
+///
+///
+///
+/// Shortcut
+/// Action performed
+///
+/// -
+/// Left cursor, Control-b
+///
+/// Moves the editing point left.
+///
+///
+/// -
+/// Right cursor, Control-f
+///
+/// Moves the editing point right.
+///
+///
+/// -
+/// Alt-b
+///
+/// Moves one word back.
+///
+///
+/// -
+/// Alt-f
+///
+/// Moves one word forward.
+///
+///
+/// -
+/// Up cursor, Control-p
+///
+/// Moves the editing point one line up.
+///
+///
+/// -
+/// Down cursor, Control-n
+///
+/// Moves the editing point one line down
+///
+///
+/// -
+/// Home key, Control-a
+///
+/// Moves the cursor to the beginning of the line.
+///
+///
+/// -
+/// End key, Control-e
+///
+/// Moves the cursor to the end of the line.
+///
+///
+/// -
+/// Control-Home
+///
+/// Scrolls to the first line and moves the cursor there.
+///
+///
+/// -
+/// Control-End
+///
+/// Scrolls to the last line and moves the cursor there.
+///
+///
+/// -
+/// Delete, Control-d
+///
+/// Deletes the character in front of the cursor.
+///
+///
+/// -
+/// Backspace
+///
+/// Deletes the character behind the cursor.
+///
+///
+/// -
+/// Control-k
+///
+/// Deletes the text until the end of the line and replaces the kill buffer
+/// with the deleted text. You can paste this text in a different place by
+/// using Control-y.
+///
+///
+/// -
+/// Control-y
+///
+/// Pastes the content of the kill ring into the current position.
+///
+///
+/// -
+/// Alt-d
+///
+/// Deletes the word above the cursor and adds it to the kill ring. You
+/// can paste the contents of the kill ring with Control-y.
+///
+///
+/// -
+/// Control-q
+///
+/// Quotes the next input character, to prevent the normal processing of
+/// key handling to take place.
+///
+///
+///
+///
+public class TextView : View {
+ TextModel _model = new ();
+ int _topRow;
+ int _leftColumn;
+ int _currentRow;
+ int _currentColumn;
+ int _selectionStartColumn, _selectionStartRow;
+ bool _selecting;
+ bool _wordWrap;
+ WordWrapManager? _wrapManager;
+ bool _continuousFind;
+ int _bottomOffset, _rightOffset;
+ int _tabWidth = 4;
+ bool _allowsTab = true;
+ bool _allowsReturn = true;
+ bool _multiline = true;
+ HistoryText _historyText = new ();
+ CultureInfo? _currentCulture;
///
- /// Multi-line text editing .
+ /// Raised when the property of the changes.
///
///
- ///
- /// provides a multi-line text editor. Users interact
- /// with it with the standard Windows, Mac, and Linux (Emacs) commands.
- ///
- ///
- ///
- /// Shortcut
- /// Action performed
- ///
- /// -
- /// Left cursor, Control-b
- ///
- /// Moves the editing point left.
- ///
- ///
- /// -
- /// Right cursor, Control-f
- ///
- /// Moves the editing point right.
- ///
- ///
- /// -
- /// Alt-b
- ///
- /// Moves one word back.
- ///
- ///
- /// -
- /// Alt-f
- ///
- /// Moves one word forward.
- ///
- ///
- /// -
- /// Up cursor, Control-p
- ///
- /// Moves the editing point one line up.
- ///
- ///
- /// -
- /// Down cursor, Control-n
- ///
- /// Moves the editing point one line down
- ///
- ///
- /// -
- /// Home key, Control-a
- ///
- /// Moves the cursor to the beginning of the line.
- ///
- ///
- /// -
- /// End key, Control-e
- ///
- /// Moves the cursor to the end of the line.
- ///
- ///
- /// -
- /// Control-Home
- ///
- /// Scrolls to the first line and moves the cursor there.
- ///
- ///
- /// -
- /// Control-End
- ///
- /// Scrolls to the last line and moves the cursor there.
- ///
- ///
- /// -
- /// Delete, Control-d
- ///
- /// Deletes the character in front of the cursor.
- ///
- ///
- /// -
- /// Backspace
- ///
- /// Deletes the character behind the cursor.
- ///
- ///
- /// -
- /// Control-k
- ///
- /// Deletes the text until the end of the line and replaces the kill buffer
- /// with the deleted text. You can paste this text in a different place by
- /// using Control-y.
- ///
- ///
- /// -
- /// Control-y
- ///
- /// Pastes the content of the kill ring into the current position.
- ///
- ///
- /// -
- /// Alt-d
- ///
- /// Deletes the word above the cursor and adds it to the kill ring. You
- /// can paste the contents of the kill ring with Control-y.
- ///
- ///
- /// -
- /// Control-q
- ///
- /// Quotes the next input character, to prevent the normal processing of
- /// key handling to take place.
- ///
- ///
- ///
+ /// The property of only changes when it is explicitly
+ /// set, not as the user types. To be notified as the user changes the contents of the TextView
+ /// see .
///
- public class TextView : View {
- TextModel _model = new TextModel ();
- int _topRow;
- int _leftColumn;
- int _currentRow;
- int _currentColumn;
- int _selectionStartColumn, _selectionStartRow;
- bool _selecting;
- bool _wordWrap;
- WordWrapManager? _wrapManager;
- bool _continuousFind;
- int _bottomOffset, _rightOffset;
- int _tabWidth = 4;
- bool _allowsTab = true;
- bool _allowsReturn = true;
- bool _multiline = true;
- HistoryText _historyText = new HistoryText ();
- CultureInfo? _currentCulture;
-
- ///
- /// Raised when the property of the changes.
- ///
- ///
- /// The property of only changes when it is explicitly
- /// set, not as the user types. To be notified as the user changes the contents of the TextView
- /// see .
- ///
- public event EventHandler? TextChanged;
+ public event EventHandler? TextChanged;
- ///
- /// Raised when the contents of the are changed.
- ///
- ///
- /// Unlike the event, this event is raised whenever the user types or
- /// otherwise changes the contents of the .
- ///
- public event EventHandler? ContentsChanged;
+ ///
+ /// Raised when the contents of the are changed.
+ ///
+ ///
+ /// Unlike the event, this event is raised whenever the user types or
+ /// otherwise changes the contents of the .
+ ///
+ public event EventHandler? ContentsChanged;
- ///
- /// Invoked with the unwrapped .
- ///
- public event EventHandler? UnwrappedCursorPosition;
+ ///
+ /// Invoked with the unwrapped .
+ ///
+ public event EventHandler? UnwrappedCursorPosition;
- ///
- /// Invoked when the normal color is drawn.
- ///
- public event EventHandler? DrawNormalColor;
+ ///
+ /// Invoked when the normal color is drawn.
+ ///
+ public event EventHandler? DrawNormalColor;
- ///
- /// Invoked when the selection color is drawn.
- ///
- public event EventHandler? DrawSelectionColor;
+ ///
+ /// Invoked when the selection color is drawn.
+ ///
+ public event EventHandler? DrawSelectionColor;
- ///
- /// Invoked when the ready only color is drawn.
- ///
- public event EventHandler? DrawReadOnlyColor;
+ ///
+ /// Invoked when the ready only color is drawn.
+ ///
+ public event EventHandler? DrawReadOnlyColor;
- ///
- /// Invoked when the used color is drawn. The Used Color is used to indicate
- /// if the was pressed and enabled.
- ///
- public event EventHandler? DrawUsedColor;
+ ///
+ /// Invoked when the used color is drawn. The Used Color is used to indicate
+ /// if the was pressed and enabled.
+ ///
+ public event EventHandler? DrawUsedColor;
- ///
- /// Provides autocomplete context menu based on suggestions at the current cursor
- /// position. Configure to enable this feature
- ///
- public IAutocomplete Autocomplete { get; protected set; } = new TextViewAutocomplete ();
+ ///
+ /// Provides autocomplete context menu based on suggestions at the current cursor
+ /// position. Configure to enable this feature
+ ///
+ public IAutocomplete Autocomplete { get; protected set; } = new TextViewAutocomplete ();
- ///
- /// Initializes a on the specified area, with absolute position and size.
- ///
- ///
- ///
- public TextView (Rect frame) : base (frame)
- {
- SetInitialProperties ();
- }
+ ///
+ /// Initializes a on the specified area, with absolute position and size.
+ ///
+ ///
+ ///
+ public TextView (Rect frame) : base (frame) => SetInitialProperties ();
- ///
- /// Initializes a on the specified area,
- /// with dimensions controlled with the X, Y, Width and Height properties.
- ///
- public TextView () : base ()
- {
- SetInitialProperties ();
- }
+ ///
+ /// Initializes a on the specified area,
+ /// with dimensions controlled with the X, Y, Width and Height properties.
+ ///
+ public TextView () : base () => SetInitialProperties ();
- void SetInitialProperties ()
- {
- CanFocus = true;
- Used = true;
+ void SetInitialProperties ()
+ {
+ CanFocus = true;
+ Used = true;
- _model.LinesLoaded += Model_LinesLoaded!;
- _historyText.ChangeText += HistoryText_ChangeText!;
+ _model.LinesLoaded += Model_LinesLoaded!;
+ _historyText.ChangeText += HistoryText_ChangeText!;
- Initialized += TextView_Initialized!;
+ Initialized += TextView_Initialized!;
// Things this view knows how to do
AddCommand (Command.PageDown, () => { ProcessPageDown (); return true; });
@@ -1672,1413 +1662,1388 @@ void SetInitialProperties ()
return true;
});
- // Default keybindings for this view
- KeyBindings.Add (KeyCode.PageDown, Command.PageDown);
- KeyBindings.Add (KeyCode.V | KeyCode.CtrlMask, Command.PageDown);
+ // Default keybindings for this view
+ KeyBindings.Add (KeyCode.PageDown, Command.PageDown);
+ KeyBindings.Add (KeyCode.V | KeyCode.CtrlMask, Command.PageDown);
- KeyBindings.Add (KeyCode.PageDown | KeyCode.ShiftMask, Command.PageDownExtend);
+ KeyBindings.Add (KeyCode.PageDown | KeyCode.ShiftMask, Command.PageDownExtend);
- KeyBindings.Add (KeyCode.PageUp, Command.PageUp);
- KeyBindings.Add (((int)'V' + KeyCode.AltMask), Command.PageUp);
+ KeyBindings.Add (KeyCode.PageUp, Command.PageUp);
+ KeyBindings.Add ((int)'V' + KeyCode.AltMask, Command.PageUp);
- KeyBindings.Add (KeyCode.PageUp | KeyCode.ShiftMask, Command.PageUpExtend);
+ KeyBindings.Add (KeyCode.PageUp | KeyCode.ShiftMask, Command.PageUpExtend);
- KeyBindings.Add (KeyCode.N | KeyCode.CtrlMask, Command.LineDown);
- KeyBindings.Add (KeyCode.CursorDown, Command.LineDown);
+ KeyBindings.Add (KeyCode.N | KeyCode.CtrlMask, Command.LineDown);
+ KeyBindings.Add (KeyCode.CursorDown, Command.LineDown);
- KeyBindings.Add (KeyCode.CursorDown | KeyCode.ShiftMask, Command.LineDownExtend);
+ KeyBindings.Add (KeyCode.CursorDown | KeyCode.ShiftMask, Command.LineDownExtend);
- KeyBindings.Add (KeyCode.P | KeyCode.CtrlMask, Command.LineUp);
- KeyBindings.Add (KeyCode.CursorUp, Command.LineUp);
+ KeyBindings.Add (KeyCode.P | KeyCode.CtrlMask, Command.LineUp);
+ KeyBindings.Add (KeyCode.CursorUp, Command.LineUp);
- KeyBindings.Add (KeyCode.CursorUp | KeyCode.ShiftMask, Command.LineUpExtend);
+ KeyBindings.Add (KeyCode.CursorUp | KeyCode.ShiftMask, Command.LineUpExtend);
- KeyBindings.Add (KeyCode.F | KeyCode.CtrlMask, Command.Right);
- KeyBindings.Add (KeyCode.CursorRight, Command.Right);
+ KeyBindings.Add (KeyCode.F | KeyCode.CtrlMask, Command.Right);
+ KeyBindings.Add (KeyCode.CursorRight, Command.Right);
- KeyBindings.Add (KeyCode.CursorRight | KeyCode.ShiftMask, Command.RightExtend);
+ KeyBindings.Add (KeyCode.CursorRight | KeyCode.ShiftMask, Command.RightExtend);
- KeyBindings.Add (KeyCode.B | KeyCode.CtrlMask, Command.Left);
- KeyBindings.Add (KeyCode.CursorLeft, Command.Left);
+ KeyBindings.Add (KeyCode.B | KeyCode.CtrlMask, Command.Left);
+ KeyBindings.Add (KeyCode.CursorLeft, Command.Left);
- KeyBindings.Add (KeyCode.CursorLeft | KeyCode.ShiftMask, Command.LeftExtend);
+ KeyBindings.Add (KeyCode.CursorLeft | KeyCode.ShiftMask, Command.LeftExtend);
- KeyBindings.Add (KeyCode.Delete, Command.DeleteCharLeft);
- KeyBindings.Add (KeyCode.Backspace, Command.DeleteCharLeft);
+ KeyBindings.Add (KeyCode.Backspace, Command.DeleteCharLeft);
- KeyBindings.Add (KeyCode.Home, Command.StartOfLine);
- KeyBindings.Add (KeyCode.A | KeyCode.CtrlMask, Command.StartOfLine);
+ KeyBindings.Add (KeyCode.Home, Command.StartOfLine);
+ KeyBindings.Add (KeyCode.A | KeyCode.CtrlMask, Command.StartOfLine);
- KeyBindings.Add (KeyCode.Home | KeyCode.ShiftMask, Command.StartOfLineExtend);
+ KeyBindings.Add (KeyCode.Home | KeyCode.ShiftMask, Command.StartOfLineExtend);
- KeyBindings.Add (KeyCode.DeleteChar, Command.DeleteCharRight);
- KeyBindings.Add (KeyCode.D | KeyCode.CtrlMask, Command.DeleteCharRight);
+ KeyBindings.Add (KeyCode.Delete, Command.DeleteCharRight);
+ KeyBindings.Add (KeyCode.D | KeyCode.CtrlMask, Command.DeleteCharRight);
- KeyBindings.Add (KeyCode.End, Command.EndOfLine);
- KeyBindings.Add (KeyCode.E | KeyCode.CtrlMask, Command.EndOfLine);
+ KeyBindings.Add (KeyCode.End, Command.EndOfLine);
+ KeyBindings.Add (KeyCode.E | KeyCode.CtrlMask, Command.EndOfLine);
- KeyBindings.Add (KeyCode.End | KeyCode.ShiftMask, Command.EndOfLineExtend);
+ KeyBindings.Add (KeyCode.End | KeyCode.ShiftMask, Command.EndOfLineExtend);
- KeyBindings.Add (KeyCode.K | KeyCode.CtrlMask, Command.CutToEndLine); // kill-to-end
- KeyBindings.Add (KeyCode.DeleteChar | KeyCode.CtrlMask | KeyCode.ShiftMask, Command.CutToEndLine); // kill-to-end
+ KeyBindings.Add (KeyCode.K | KeyCode.CtrlMask, Command.CutToEndLine); // kill-to-end
+ KeyBindings.Add (KeyCode.Delete | KeyCode.CtrlMask | KeyCode.ShiftMask, Command.CutToEndLine); // kill-to-end
- KeyBindings.Add (KeyCode.K | KeyCode.AltMask, Command.CutToStartLine); // kill-to-start
- KeyBindings.Add (KeyCode.Backspace | KeyCode.CtrlMask | KeyCode.ShiftMask, Command.CutToStartLine); // kill-to-start
+ KeyBindings.Add (KeyCode.K | KeyCode.AltMask, Command.CutToStartLine); // kill-to-start
+ KeyBindings.Add (KeyCode.Backspace | KeyCode.CtrlMask | KeyCode.ShiftMask, Command.CutToStartLine); // kill-to-start
- KeyBindings.Add (KeyCode.Y | KeyCode.CtrlMask, Command.Paste); // Control-y, yank
- KeyBindings.Add (KeyCode.Space | KeyCode.CtrlMask, Command.ToggleExtend);
+ KeyBindings.Add (KeyCode.Y | KeyCode.CtrlMask, Command.Paste); // Control-y, yank
+ KeyBindings.Add (KeyCode.Space | KeyCode.CtrlMask, Command.ToggleExtend);
- KeyBindings.Add (((int)'C' + KeyCode.AltMask), Command.Copy);
- KeyBindings.Add (KeyCode.C | KeyCode.CtrlMask, Command.Copy);
+ KeyBindings.Add ((int)'C' + KeyCode.AltMask, Command.Copy);
+ KeyBindings.Add (KeyCode.C | KeyCode.CtrlMask, Command.Copy);
- KeyBindings.Add (((int)'W' + KeyCode.AltMask), Command.Cut);
- KeyBindings.Add (KeyCode.W | KeyCode.CtrlMask, Command.Cut);
- KeyBindings.Add (KeyCode.X | KeyCode.CtrlMask, Command.Cut);
+ KeyBindings.Add ((int)'W' + KeyCode.AltMask, Command.Cut);
+ KeyBindings.Add (KeyCode.W | KeyCode.CtrlMask, Command.Cut);
+ KeyBindings.Add (KeyCode.X | KeyCode.CtrlMask, Command.Cut);
- KeyBindings.Add (KeyCode.CursorLeft | KeyCode.CtrlMask, Command.WordLeft);
- KeyBindings.Add ((KeyCode)((int)'B' + KeyCode.AltMask), Command.WordLeft);
+ KeyBindings.Add (KeyCode.CursorLeft | KeyCode.CtrlMask, Command.WordLeft);
+ KeyBindings.Add ((KeyCode)((int)'B' + KeyCode.AltMask), Command.WordLeft);
- KeyBindings.Add (KeyCode.CursorLeft | KeyCode.CtrlMask | KeyCode.ShiftMask, Command.WordLeftExtend);
+ KeyBindings.Add (KeyCode.CursorLeft | KeyCode.CtrlMask | KeyCode.ShiftMask, Command.WordLeftExtend);
- KeyBindings.Add (KeyCode.CursorRight | KeyCode.CtrlMask, Command.WordRight);
- KeyBindings.Add ((KeyCode)((int)'F' + KeyCode.AltMask), Command.WordRight);
+ KeyBindings.Add (KeyCode.CursorRight | KeyCode.CtrlMask, Command.WordRight);
+ KeyBindings.Add ((KeyCode)((int)'F' + KeyCode.AltMask), Command.WordRight);
- KeyBindings.Add (KeyCode.CursorRight | KeyCode.CtrlMask | KeyCode.ShiftMask, Command.WordRightExtend);
- KeyBindings.Add (KeyCode.DeleteChar | KeyCode.CtrlMask, Command.KillWordForwards); // kill-word-forwards
- KeyBindings.Add (KeyCode.Backspace | KeyCode.CtrlMask, Command.KillWordBackwards); // kill-word-backwards
+ KeyBindings.Add (KeyCode.CursorRight | KeyCode.CtrlMask | KeyCode.ShiftMask, Command.WordRightExtend);
+ KeyBindings.Add (KeyCode.Delete | KeyCode.CtrlMask, Command.KillWordForwards); // kill-word-forwards
+ KeyBindings.Add (KeyCode.Backspace | KeyCode.CtrlMask, Command.KillWordBackwards); // kill-word-backwards
- // BUGBUG: If AllowsReturn is false, Key.Enter should not be bound (so that Toplevel can cause Command.Accept).
- KeyBindings.Add (KeyCode.Enter, Command.NewLine);
- KeyBindings.Add (KeyCode.End | KeyCode.CtrlMask, Command.BottomEnd);
- KeyBindings.Add (KeyCode.End | KeyCode.CtrlMask | KeyCode.ShiftMask, Command.BottomEndExtend);
- KeyBindings.Add (KeyCode.Home | KeyCode.CtrlMask, Command.TopHome);
- KeyBindings.Add (KeyCode.Home | KeyCode.CtrlMask | KeyCode.ShiftMask, Command.TopHomeExtend);
- KeyBindings.Add (KeyCode.T | KeyCode.CtrlMask, Command.SelectAll);
- KeyBindings.Add (KeyCode.InsertChar, Command.ToggleOverwrite);
- KeyBindings.Add (KeyCode.Tab, Command.Tab);
- KeyBindings.Add (KeyCode.Tab | KeyCode.ShiftMask, Command.BackTab);
+ // BUGBUG: If AllowsReturn is false, Key.Enter should not be bound (so that Toplevel can cause Command.Accept).
+ KeyBindings.Add (KeyCode.Enter, Command.NewLine);
+ KeyBindings.Add (KeyCode.End | KeyCode.CtrlMask, Command.BottomEnd);
+ KeyBindings.Add (KeyCode.End | KeyCode.CtrlMask | KeyCode.ShiftMask, Command.BottomEndExtend);
+ KeyBindings.Add (KeyCode.Home | KeyCode.CtrlMask, Command.TopHome);
+ KeyBindings.Add (KeyCode.Home | KeyCode.CtrlMask | KeyCode.ShiftMask, Command.TopHomeExtend);
+ KeyBindings.Add (KeyCode.T | KeyCode.CtrlMask, Command.SelectAll);
+ KeyBindings.Add (KeyCode.Insert, Command.ToggleOverwrite);
+ KeyBindings.Add (KeyCode.Tab, Command.Tab);
+ KeyBindings.Add (KeyCode.Tab | KeyCode.ShiftMask, Command.BackTab);
- KeyBindings.Add (KeyCode.Tab | KeyCode.CtrlMask, Command.NextView);
- KeyBindings.Add ((KeyCode)Application.AlternateForwardKey, Command.NextView);
+ KeyBindings.Add (KeyCode.Tab | KeyCode.CtrlMask, Command.NextView);
+ KeyBindings.Add ((KeyCode)Application.AlternateForwardKey, Command.NextView);
- KeyBindings.Add (KeyCode.Tab | KeyCode.CtrlMask | KeyCode.ShiftMask, Command.PreviousView);
- KeyBindings.Add ((KeyCode)Application.AlternateBackwardKey, Command.PreviousView);
+ KeyBindings.Add (KeyCode.Tab | KeyCode.CtrlMask | KeyCode.ShiftMask, Command.PreviousView);
+ KeyBindings.Add ((KeyCode)Application.AlternateBackwardKey, Command.PreviousView);
- KeyBindings.Add (KeyCode.Z | KeyCode.CtrlMask, Command.Undo);
- KeyBindings.Add (KeyCode.R | KeyCode.CtrlMask, Command.Redo);
+ KeyBindings.Add (KeyCode.Z | KeyCode.CtrlMask, Command.Undo);
+ KeyBindings.Add (KeyCode.R | KeyCode.CtrlMask, Command.Redo);
- KeyBindings.Add (KeyCode.G | KeyCode.CtrlMask, Command.DeleteAll);
- KeyBindings.Add (KeyCode.D | KeyCode.CtrlMask | KeyCode.ShiftMask, Command.DeleteAll);
+ KeyBindings.Add (KeyCode.G | KeyCode.CtrlMask, Command.DeleteAll);
+ KeyBindings.Add (KeyCode.D | KeyCode.CtrlMask | KeyCode.ShiftMask, Command.DeleteAll);
- _currentCulture = Thread.CurrentThread.CurrentUICulture;
+ _currentCulture = Thread.CurrentThread.CurrentUICulture;
- ContextMenu = new ContextMenu () { MenuItems = BuildContextMenuBarItem () };
- ContextMenu.KeyChanged += ContextMenu_KeyChanged!;
+ ContextMenu = new ContextMenu () { MenuItems = BuildContextMenuBarItem () };
+ ContextMenu.KeyChanged += ContextMenu_KeyChanged!;
KeyBindings.Add ((KeyCode)ContextMenu.Key, KeyBindingScope.HotKey, Command.ShowContextMenu);
}
- private MenuBarItem BuildContextMenuBarItem ()
- {
- return new MenuBarItem (new MenuItem [] {
- new MenuItem (Strings.ctxSelectAll, "", () => SelectAll (), null, null, (KeyCode)KeyBindings.GetKeyFromCommands (Command.SelectAll)),
- new MenuItem (Strings.ctxDeleteAll, "", () => DeleteAll (), null, null, (KeyCode)KeyBindings.GetKeyFromCommands (Command.DeleteAll)),
- new MenuItem (Strings.ctxCopy, "", () => Copy (), null, null, (KeyCode)KeyBindings.GetKeyFromCommands (Command.Copy)),
- new MenuItem (Strings.ctxCut, "", () => Cut (), null, null, (KeyCode)KeyBindings.GetKeyFromCommands (Command.Cut)),
- new MenuItem (Strings.ctxPaste, "", () => Paste (), null, null, (KeyCode)KeyBindings.GetKeyFromCommands (Command.Paste)),
- new MenuItem (Strings.ctxUndo, "", () => Undo (), null, null, (KeyCode)KeyBindings.GetKeyFromCommands (Command.Undo)),
- new MenuItem (Strings.ctxRedo, "", () => Redo (), null, null, (KeyCode)KeyBindings.GetKeyFromCommands (Command.Redo)),
- });
- }
+ MenuBarItem BuildContextMenuBarItem () => new (new MenuItem [] {
+ new (Strings.ctxSelectAll, "", () => SelectAll (), null, null, (KeyCode)KeyBindings.GetKeyFromCommands (Command.SelectAll)),
+ new (Strings.ctxDeleteAll, "", () => DeleteAll (), null, null, (KeyCode)KeyBindings.GetKeyFromCommands (Command.DeleteAll)),
+ new (Strings.ctxCopy, "", () => Copy (), null, null, (KeyCode)KeyBindings.GetKeyFromCommands (Command.Copy)),
+ new (Strings.ctxCut, "", () => Cut (), null, null, (KeyCode)KeyBindings.GetKeyFromCommands (Command.Cut)),
+ new (Strings.ctxPaste, "", () => Paste (), null, null, (KeyCode)KeyBindings.GetKeyFromCommands (Command.Paste)),
+ new (Strings.ctxUndo, "", () => Undo (), null, null, (KeyCode)KeyBindings.GetKeyFromCommands (Command.Undo)),
+ new (Strings.ctxRedo, "", () => Redo (), null, null, (KeyCode)KeyBindings.GetKeyFromCommands (Command.Redo))
+ });
- private void ContextMenu_KeyChanged (object sender, KeyChangedEventArgs e)
- {
- KeyBindings.Replace ((KeyCode)e.OldKey, (KeyCode)e.NewKey);
- }
+ void ContextMenu_KeyChanged (object sender, KeyChangedEventArgs e) => KeyBindings.Replace ((KeyCode)e.OldKey, (KeyCode)e.NewKey);
- private void Model_LinesLoaded (object sender, EventArgs e)
- {
- // This call is not needed. Model_LinesLoaded gets invoked when
- // model.LoadString (value) is called. LoadString is called from one place
- // (Text.set) and historyText.Clear() is called immediately after.
- // If this call happens, HistoryText_ChangeText will get called multiple times
- // when Text is set, which is wrong.
- //historyText.Clear (Text);
+ void Model_LinesLoaded (object sender, EventArgs e)
+ {
+ // This call is not needed. Model_LinesLoaded gets invoked when
+ // model.LoadString (value) is called. LoadString is called from one place
+ // (Text.set) and historyText.Clear() is called immediately after.
+ // If this call happens, HistoryText_ChangeText will get called multiple times
+ // when Text is set, which is wrong.
+ //historyText.Clear (Text);
- if (!_multiline && !IsInitialized) {
- _currentColumn = Text.GetRuneCount ();
- _leftColumn = _currentColumn > Frame.Width + 1 ? _currentColumn - Frame.Width + 1 : 0;
- }
+ if (!_multiline && !IsInitialized) {
+ _currentColumn = Text.GetRuneCount ();
+ _leftColumn = _currentColumn > Frame.Width + 1 ? _currentColumn - Frame.Width + 1 : 0;
}
+ }
- private void HistoryText_ChangeText (object sender, HistoryText.HistoryTextItem obj)
- {
- SetWrapModel ();
+ void HistoryText_ChangeText (object sender, HistoryText.HistoryTextItem obj)
+ {
+ SetWrapModel ();
- if (obj != null) {
- var startLine = obj.CursorPosition.Y;
+ if (obj != null) {
+ int startLine = obj.CursorPosition.Y;
- if (obj.RemovedOnAdded != null) {
- int offset;
- if (obj.IsUndoing) {
- offset = Math.Max (obj.RemovedOnAdded.Lines.Count - obj.Lines.Count, 1);
+ if (obj.RemovedOnAdded != null) {
+ int offset;
+ if (obj.IsUndoing) {
+ offset = Math.Max (obj.RemovedOnAdded.Lines.Count - obj.Lines.Count, 1);
+ } else {
+ offset = obj.RemovedOnAdded.Lines.Count - 1;
+ }
+ for (int i = 0; i < offset; i++) {
+ if (Lines > obj.RemovedOnAdded.CursorPosition.Y) {
+ _model.RemoveLine (obj.RemovedOnAdded.CursorPosition.Y);
} else {
- offset = obj.RemovedOnAdded.Lines.Count - 1;
- }
- for (int i = 0; i < offset; i++) {
- if (Lines > obj.RemovedOnAdded.CursorPosition.Y) {
- _model.RemoveLine (obj.RemovedOnAdded.CursorPosition.Y);
- } else {
- break;
- }
+ break;
}
}
+ }
- for (int i = 0; i < obj.Lines.Count; i++) {
- if (i == 0) {
- _model.ReplaceLine (startLine, obj.Lines [i]);
- } else if ((obj.IsUndoing && obj.LineStatus == HistoryText.LineStatus.Removed)
- || !obj.IsUndoing && obj.LineStatus == HistoryText.LineStatus.Added) {
- _model.AddLine (startLine, obj.Lines [i]);
- } else if (Lines > obj.CursorPosition.Y + 1) {
- _model.RemoveLine (obj.CursorPosition.Y + 1);
- }
- startLine++;
+ for (int i = 0; i < obj.Lines.Count; i++) {
+ if (i == 0) {
+ _model.ReplaceLine (startLine, obj.Lines [i]);
+ } else if (obj.IsUndoing && obj.LineStatus == HistoryText.LineStatus.Removed
+ || !obj.IsUndoing && obj.LineStatus == HistoryText.LineStatus.Added) {
+ _model.AddLine (startLine, obj.Lines [i]);
+ } else if (Lines > obj.CursorPosition.Y + 1) {
+ _model.RemoveLine (obj.CursorPosition.Y + 1);
}
-
- CursorPosition = obj.FinalCursorPosition;
+ startLine++;
}
- UpdateWrapModel ();
-
- Adjust ();
- OnContentsChanged ();
+ CursorPosition = obj.FinalCursorPosition;
}
- void TextView_Initialized (object sender, EventArgs e)
- {
- Autocomplete.HostControl = this;
- if (Application.Top != null) {
- Application.Top.AlternateForwardKeyChanged += Top_AlternateForwardKeyChanged!;
- Application.Top.AlternateBackwardKeyChanged += Top_AlternateBackwardKeyChanged!;
- }
- OnContentsChanged ();
- }
+ UpdateWrapModel ();
- void Top_AlternateBackwardKeyChanged (object sender, KeyChangedEventArgs e)
- {
- KeyBindings.Replace ((KeyCode)e.OldKey, (KeyCode)e.NewKey);
- }
+ Adjust ();
+ OnContentsChanged ();
+ }
- void Top_AlternateForwardKeyChanged (object sender, KeyChangedEventArgs e)
- {
- KeyBindings.Replace ((KeyCode)e.OldKey, (KeyCode)e.NewKey);
+ void TextView_Initialized (object sender, EventArgs e)
+ {
+ Autocomplete.HostControl = this;
+ if (Application.Top != null) {
+ Application.Top.AlternateForwardKeyChanged += Top_AlternateForwardKeyChanged!;
+ Application.Top.AlternateBackwardKeyChanged += Top_AlternateBackwardKeyChanged!;
}
+ OnContentsChanged ();
+ }
- ///
- /// Tracks whether the text view should be considered "used", that is, that the user has moved in the entry,
- /// so new input should be appended at the cursor position, rather than clearing the entry
- ///
- public bool Used { get; set; }
+ void Top_AlternateBackwardKeyChanged (object sender, KeyChangedEventArgs e) => KeyBindings.Replace ((KeyCode)e.OldKey, (KeyCode)e.NewKey);
- void ResetPosition ()
- {
- _topRow = _leftColumn = _currentRow = _currentColumn = 0;
- StopSelecting ();
- ResetCursorVisibility ();
- }
+ void Top_AlternateForwardKeyChanged (object sender, KeyChangedEventArgs e) => KeyBindings.Replace ((KeyCode)e.OldKey, (KeyCode)e.NewKey);
- ///
- /// Sets or gets the text in the .
- ///
- ///
- /// The event is fired whenever this property is set. Note, however,
- /// that Text is not set by as the user types.
- ///
- public override string Text {
- get {
- if (_wordWrap) {
- return _wrapManager!.Model.ToString ();
- } else {
- return _model.ToString ();
- }
- }
+ ///
+ /// Tracks whether the text view should be considered "used", that is, that the user has moved in the entry,
+ /// so new input should be appended at the cursor position, rather than clearing the entry
+ ///
+ public bool Used { get; set; }
- set {
- ResetPosition ();
- _model.LoadString (value);
- if (_wordWrap) {
- _wrapManager = new WordWrapManager (_model);
- _model = _wrapManager.WrapModel (_frameWidth, out _, out _, out _, out _);
- }
- TextChanged?.Invoke (this, EventArgs.Empty);
- SetNeedsDisplay ();
+ void ResetPosition ()
+ {
+ _topRow = _leftColumn = _currentRow = _currentColumn = 0;
+ StopSelecting ();
+ ResetCursorVisibility ();
+ }
- _historyText.Clear (Text);
+ ///
+ /// Sets or gets the text in the .
+ ///
+ ///
+ /// The event is fired whenever this property is set. Note, however,
+ /// that Text is not set by as the user types.
+ ///
+ public override string Text {
+ get {
+ if (_wordWrap) {
+ return _wrapManager!.Model.ToString ();
+ } else {
+ return _model.ToString ();
}
}
- ///
- public override Rect Frame {
- get => base.Frame;
- set {
- base.Frame = value;
- if (IsInitialized) {
- WrapTextModel ();
- Adjust ();
- }
+ set {
+ ResetPosition ();
+ _model.LoadString (value);
+ if (_wordWrap) {
+ _wrapManager = new WordWrapManager (_model);
+ _model = _wrapManager.WrapModel (_frameWidth, out _, out _, out _, out _);
}
+ TextChanged?.Invoke (this, EventArgs.Empty);
+ SetNeedsDisplay ();
+
+ _historyText.Clear (Text);
}
+ }
- void WrapTextModel ()
- {
- if (_wordWrap && _wrapManager != null) {
- _model = _wrapManager.WrapModel (_frameWidth,
- out int nRow, out int nCol,
- out int nStartRow, out int nStartCol,
- _currentRow, _currentColumn,
- _selectionStartRow, _selectionStartColumn,
- _tabWidth, preserveTrailingSpaces: true);
- _currentRow = nRow;
- _currentColumn = nCol;
- _selectionStartRow = nStartRow;
- _selectionStartColumn = nStartCol;
- SetNeedsDisplay ();
+ ///
+ public override Rect Frame {
+ get => base.Frame;
+ set {
+ base.Frame = value;
+ if (IsInitialized) {
+ WrapTextModel ();
+ Adjust ();
}
}
+ }
- int _frameWidth => Math.Max (Frame.Width - (RightOffset != 0 ? 2 : 1), 0);
+ void WrapTextModel ()
+ {
+ if (_wordWrap && _wrapManager != null) {
+ _model = _wrapManager.WrapModel (_frameWidth,
+ out int nRow, out int nCol,
+ out int nStartRow, out int nStartCol,
+ _currentRow, _currentColumn,
+ _selectionStartRow, _selectionStartColumn,
+ _tabWidth, true);
+ _currentRow = nRow;
+ _currentColumn = nCol;
+ _selectionStartRow = nStartRow;
+ _selectionStartColumn = nStartCol;
+ SetNeedsDisplay ();
+ }
+ }
- ///
- /// Gets or sets the top row.
- ///
- public int TopRow { get => _topRow; set => _topRow = Math.Max (Math.Min (value, Lines - 1), 0); }
+ int _frameWidth => Math.Max (Frame.Width - (RightOffset != 0 ? 2 : 1), 0);
- ///
- /// Gets or sets the left column.
- ///
- public int LeftColumn {
- get => _leftColumn;
- set {
- if (value > 0 && _wordWrap)
- return;
- _leftColumn = Math.Max (Math.Min (value, Maxlength - 1), 0);
+ ///
+ /// Gets or sets the top row.
+ ///
+ public int TopRow { get => _topRow; set => _topRow = Math.Max (Math.Min (value, Lines - 1), 0); }
+
+ ///
+ /// Gets or sets the left column.
+ ///
+ public int LeftColumn {
+ get => _leftColumn;
+ set {
+ if (value > 0 && _wordWrap) {
+ return;
}
+ _leftColumn = Math.Max (Math.Min (value, Maxlength - 1), 0);
}
+ }
- ///
- /// Gets the maximum visible length line.
- ///
- public int Maxlength => _model.GetMaxVisibleLine (_topRow, _topRow + Frame.Height, TabWidth);
+ ///
+ /// Gets the maximum visible length line.
+ ///
+ public int Maxlength => _model.GetMaxVisibleLine (_topRow, _topRow + Frame.Height, TabWidth);
- ///
- /// Gets the number of lines.
- ///
- public int Lines => _model.Count;
+ ///
+ /// Gets the number of lines.
+ ///
+ public int Lines => _model.Count;
- ///
- /// Sets or gets the current cursor position.
- ///
- public Point CursorPosition {
- get => new Point (_currentColumn, _currentRow);
- set {
- var line = _model.GetLine (Math.Max (Math.Min (value.Y, _model.Count - 1), 0));
- _currentColumn = value.X < 0 ? 0 : value.X > line.Count ? line.Count : value.X;
- _currentRow = value.Y < 0 ? 0 : value.Y > _model.Count - 1
- ? Math.Max (_model.Count - 1, 0) : value.Y;
- SetNeedsDisplay ();
- Adjust ();
- }
+ ///
+ /// Sets or gets the current cursor position.
+ ///
+ public Point CursorPosition {
+ get => new (_currentColumn, _currentRow);
+ set {
+ var line = _model.GetLine (Math.Max (Math.Min (value.Y, _model.Count - 1), 0));
+ _currentColumn = value.X < 0 ? 0 : value.X > line.Count ? line.Count : value.X;
+ _currentRow = value.Y < 0 ? 0 : value.Y > _model.Count - 1
+ ? Math.Max (_model.Count - 1, 0) : value.Y;
+ SetNeedsDisplay ();
+ Adjust ();
}
+ }
- ///
- /// Start column position of the selected text.
- ///
- public int SelectionStartColumn {
- get => _selectionStartColumn;
- set {
- var line = _model.GetLine (_selectionStartRow);
- _selectionStartColumn = value < 0 ? 0 : value > line.Count ? line.Count : value;
- _selecting = true;
- SetNeedsDisplay ();
- Adjust ();
- }
+ ///
+ /// Start column position of the selected text.
+ ///
+ public int SelectionStartColumn {
+ get => _selectionStartColumn;
+ set {
+ var line = _model.GetLine (_selectionStartRow);
+ _selectionStartColumn = value < 0 ? 0 : value > line.Count ? line.Count : value;
+ _selecting = true;
+ SetNeedsDisplay ();
+ Adjust ();
}
+ }
- ///
- /// Start row position of the selected text.
- ///
- public int SelectionStartRow {
- get => _selectionStartRow;
- set {
- _selectionStartRow = value < 0 ? 0 : value > _model.Count - 1
- ? Math.Max (_model.Count - 1, 0) : value;
- _selecting = true;
- SetNeedsDisplay ();
- Adjust ();
- }
+ ///
+ /// Start row position of the selected text.
+ ///
+ public int SelectionStartRow {
+ get => _selectionStartRow;
+ set {
+ _selectionStartRow = value < 0 ? 0 : value > _model.Count - 1
+ ? Math.Max (_model.Count - 1, 0) : value;
+ _selecting = true;
+ SetNeedsDisplay ();
+ Adjust ();
}
+ }
- ///
- /// The selected text.
- ///
- public string SelectedText {
- get {
- if (!_selecting || (_model.Count == 1 && _model.GetLine (0).Count == 0)) {
- return string.Empty;
- }
-
- return GetSelectedRegion ();
+ ///
+ /// The selected text.
+ ///
+ public string SelectedText {
+ get {
+ if (!_selecting || _model.Count == 1 && _model.GetLine (0).Count == 0) {
+ return string.Empty;
}
+
+ return GetSelectedRegion ();
}
+ }
- ///
- /// Length of the selected text.
- ///
- public int SelectedLength => GetSelectedLength ();
+ ///
+ /// Length of the selected text.
+ ///
+ public int SelectedLength => GetSelectedLength ();
- ///
- /// Get or sets the selecting.
- ///
- public bool Selecting {
- get => _selecting;
- set => _selecting = value;
- }
- ///
- /// Allows word wrap the to fit the available container width.
- ///
- public bool WordWrap {
- get => _wordWrap;
- set {
- if (value == _wordWrap) {
- return;
- }
- if (value && !_multiline) {
- return;
- }
- _wordWrap = value;
- ResetPosition ();
- if (_wordWrap) {
- _wrapManager = new WordWrapManager (_model);
- _model = _wrapManager.WrapModel (_frameWidth, out _, out _, out _, out _);
- } else if (!_wordWrap && _wrapManager != null) {
- _model = _wrapManager.Model;
- }
- SetNeedsDisplay ();
+ ///
+ /// Get or sets the selecting.
+ ///
+ public bool Selecting {
+ get => _selecting;
+ set => _selecting = value;
+ }
+
+ ///
+ /// Allows word wrap the to fit the available container width.
+ ///
+ public bool WordWrap {
+ get => _wordWrap;
+ set {
+ if (value == _wordWrap) {
+ return;
+ }
+ if (value && !_multiline) {
+ return;
}
+ _wordWrap = value;
+ ResetPosition ();
+ if (_wordWrap) {
+ _wrapManager = new WordWrapManager (_model);
+ _model = _wrapManager.WrapModel (_frameWidth, out _, out _, out _, out _);
+ } else if (!_wordWrap && _wrapManager != null) {
+ _model = _wrapManager.Model;
+ }
+ SetNeedsDisplay ();
}
+ }
- ///
- /// The bottom offset needed to use a horizontal scrollbar or for another reason.
- /// This is only needed with the keyboard navigation.
- ///
- public int BottomOffset {
- get => _bottomOffset;
- set {
- if (_currentRow == Lines - 1 && _bottomOffset > 0 && value == 0) {
- _topRow = Math.Max (_topRow - _bottomOffset, 0);
- }
- _bottomOffset = value;
- Adjust ();
+ ///
+ /// The bottom offset needed to use a horizontal scrollbar or for another reason.
+ /// This is only needed with the keyboard navigation.
+ ///
+ public int BottomOffset {
+ get => _bottomOffset;
+ set {
+ if (_currentRow == Lines - 1 && _bottomOffset > 0 && value == 0) {
+ _topRow = Math.Max (_topRow - _bottomOffset, 0);
}
+ _bottomOffset = value;
+ Adjust ();
}
+ }
- ///
- /// The right offset needed to use a vertical scrollbar or for another reason.
- /// This is only needed with the keyboard navigation.
- ///
- public int RightOffset {
- get => _rightOffset;
- set {
- if (!_wordWrap && _currentColumn == GetCurrentLine ().Count && _rightOffset > 0 && value == 0) {
- _leftColumn = Math.Max (_leftColumn - _rightOffset, 0);
- }
- _rightOffset = value;
- Adjust ();
+ ///
+ /// The right offset needed to use a vertical scrollbar or for another reason.
+ /// This is only needed with the keyboard navigation.
+ ///
+ public int RightOffset {
+ get => _rightOffset;
+ set {
+ if (!_wordWrap && _currentColumn == GetCurrentLine ().Count && _rightOffset > 0 && value == 0) {
+ _leftColumn = Math.Max (_leftColumn - _rightOffset, 0);
}
+ _rightOffset = value;
+ Adjust ();
}
+ }
- ///
- /// Gets or sets a value indicating whether pressing ENTER in a
- /// creates a new line of text in the view or activates the default button for the Toplevel.
- ///
- public bool AllowsReturn {
- get => _allowsReturn;
- set {
- _allowsReturn = value;
- if (_allowsReturn && !_multiline) {
- Multiline = true;
- }
- if (!_allowsReturn && _multiline) {
- Multiline = false;
- AllowsTab = false;
- }
- SetNeedsDisplay ();
+ ///
+ /// Gets or sets a value indicating whether pressing ENTER in a
+ /// creates a new line of text in the view or activates the default button for the Toplevel.
+ ///
+ public bool AllowsReturn {
+ get => _allowsReturn;
+ set {
+ _allowsReturn = value;
+ if (_allowsReturn && !_multiline) {
+ Multiline = true;
+ }
+ if (!_allowsReturn && _multiline) {
+ Multiline = false;
+ AllowsTab = false;
}
+ SetNeedsDisplay ();
}
+ }
- ///
- /// Gets or sets whether the inserts a tab character into the text or ignores
- /// tab input. If set to `false` and the user presses the tab key (or shift-tab) the focus will move to the
- /// next view (or previous with shift-tab). The default is `true`; if the user presses the tab key, a tab
- /// character will be inserted into the text.
- ///
- public bool AllowsTab {
- get => _allowsTab;
- set {
- _allowsTab = value;
- if (_allowsTab && _tabWidth == 0) {
- _tabWidth = 4;
- }
- if (_allowsTab && !_multiline) {
- Multiline = true;
- }
- if (!_allowsTab && _tabWidth > 0) {
- _tabWidth = 0;
- }
- SetNeedsDisplay ();
+ ///
+ /// Gets or sets whether the inserts a tab character into the text or ignores
+ /// tab input. If set to `false` and the user presses the tab key (or shift-tab) the focus will move to the
+ /// next view (or previous with shift-tab). The default is `true`; if the user presses the tab key, a tab
+ /// character will be inserted into the text.
+ ///
+ public bool AllowsTab {
+ get => _allowsTab;
+ set {
+ _allowsTab = value;
+ if (_allowsTab && _tabWidth == 0) {
+ _tabWidth = 4;
}
+ if (_allowsTab && !_multiline) {
+ Multiline = true;
+ }
+ if (!_allowsTab && _tabWidth > 0) {
+ _tabWidth = 0;
+ }
+ SetNeedsDisplay ();
}
+ }
- ///
- /// Gets or sets a value indicating the number of whitespace when pressing the TAB key.
- ///
- public int TabWidth {
- get => _tabWidth;
- set {
- _tabWidth = Math.Max (value, 0);
- if (_tabWidth > 0 && !AllowsTab) {
- AllowsTab = true;
- }
- SetNeedsDisplay ();
+ ///
+ /// Gets or sets a value indicating the number of whitespace when pressing the TAB key.
+ ///
+ public int TabWidth {
+ get => _tabWidth;
+ set {
+ _tabWidth = Math.Max (value, 0);
+ if (_tabWidth > 0 && !AllowsTab) {
+ AllowsTab = true;
}
+ SetNeedsDisplay ();
}
+ }
- Dim? savedHeight = null;
+ Dim? savedHeight = null;
- ///
- /// Gets or sets a value indicating whether this is a multiline text view.
- ///
- public bool Multiline {
- get => _multiline;
- set {
- _multiline = value;
- if (_multiline && !_allowsTab) {
- AllowsTab = true;
+ ///
+ /// Gets or sets a value indicating whether this is a multiline text view.
+ ///
+ public bool Multiline {
+ get => _multiline;
+ set {
+ _multiline = value;
+ if (_multiline && !_allowsTab) {
+ AllowsTab = true;
+ }
+ if (_multiline && !_allowsReturn) {
+ AllowsReturn = true;
+ }
+
+ if (!_multiline) {
+ AllowsReturn = false;
+ AllowsTab = false;
+ WordWrap = false;
+ _currentColumn = 0;
+ _currentRow = 0;
+ savedHeight = Height;
+ var prevLayoutStyle = LayoutStyle;
+ if (LayoutStyle == LayoutStyle.Computed) {
+ LayoutStyle = LayoutStyle.Absolute;
}
- if (_multiline && !_allowsReturn) {
- AllowsReturn = true;
+ Height = 1;
+ LayoutStyle = prevLayoutStyle;
+ if (!IsInitialized) {
+ _model.LoadString (Text);
}
-
- if (!_multiline) {
- AllowsReturn = false;
- AllowsTab = false;
- WordWrap = false;
- _currentColumn = 0;
- _currentRow = 0;
- savedHeight = Height;
- var prevLayoutStyle = LayoutStyle;
- if (LayoutStyle == LayoutStyle.Computed) {
- LayoutStyle = LayoutStyle.Absolute;
- }
- Height = 1;
- LayoutStyle = prevLayoutStyle;
- if (!IsInitialized) {
- _model.LoadString (Text);
- }
- SetNeedsDisplay ();
- } else if (_multiline && savedHeight != null) {
- var lyout = LayoutStyle;
- if (LayoutStyle == LayoutStyle.Computed) {
- LayoutStyle = LayoutStyle.Absolute;
- }
- Height = savedHeight;
- LayoutStyle = lyout;
- SetNeedsDisplay ();
+ SetNeedsDisplay ();
+ } else if (_multiline && savedHeight != null) {
+ var lyout = LayoutStyle;
+ if (LayoutStyle == LayoutStyle.Computed) {
+ LayoutStyle = LayoutStyle.Absolute;
}
+ Height = savedHeight;
+ LayoutStyle = lyout;
+ SetNeedsDisplay ();
}
}
+ }
- ///
- /// Indicates whatever the text was changed or not.
- /// if the text was changed otherwise.
- ///
- public bool IsDirty {
- get {
- return _historyText.IsDirty (Text);
- }
- set {
- _historyText.Clear (Text);
- }
- }
-
- ///
- /// Indicates whatever the text has history changes or not.
- /// if the text has history changes otherwise.
- ///
- public bool HasHistoryChanges => _historyText.HasHistoryChanges;
+ ///
+ /// Indicates whatever the text was changed or not.
+ /// if the text was changed otherwise.
+ ///
+ public bool IsDirty {
+ get => _historyText.IsDirty (Text);
+ set => _historyText.Clear (Text);
+ }
- ///
- /// Get the for this view.
- ///
- public ContextMenu? ContextMenu { get; private set; }
+ ///
+ /// Indicates whatever the text has history changes or not.
+ /// if the text has history changes otherwise.
+ ///
+ public bool HasHistoryChanges => _historyText.HasHistoryChanges;
- ///
- /// If and the current is null
- /// will inherit from the previous, otherwise if (default) do nothing.
- /// If the text is load with this
- /// property is automatically sets to .
- ///
- public bool InheritsPreviousColorScheme { get; set; }
+ ///
+ /// Get the for this view.
+ ///
+ public ContextMenu? ContextMenu { get; private set; }
- int GetSelectedLength ()
- {
- return SelectedText.Length;
- }
+ ///
+ /// If and the current is null
+ /// will inherit from the previous, otherwise if (default) do nothing.
+ /// If the text is load with this
+ /// property is automatically sets to .
+ ///
+ public bool InheritsPreviousColorScheme { get; set; }
- CursorVisibility _savedCursorVisibility;
+ int GetSelectedLength () => SelectedText.Length;
- void SaveCursorVisibility ()
- {
- if (_desiredCursorVisibility != CursorVisibility.Invisible) {
- if (_savedCursorVisibility == 0) {
- _savedCursorVisibility = _desiredCursorVisibility;
- }
- DesiredCursorVisibility = CursorVisibility.Invisible;
- }
- }
+ CursorVisibility _savedCursorVisibility;
- void ResetCursorVisibility ()
- {
- if (_savedCursorVisibility != 0) {
- DesiredCursorVisibility = _savedCursorVisibility;
- _savedCursorVisibility = 0;
+ void SaveCursorVisibility ()
+ {
+ if (_desiredCursorVisibility != CursorVisibility.Invisible) {
+ if (_savedCursorVisibility == 0) {
+ _savedCursorVisibility = _desiredCursorVisibility;
}
+ DesiredCursorVisibility = CursorVisibility.Invisible;
}
+ }
- ///
- /// Loads the contents of the file into the .
- ///
- /// true, if file was loaded, false otherwise.
- /// Path to the file to load.
- public bool Load (string path)
- {
- SetWrapModel ();
- bool res;
- try {
- SetWrapModel ();
- res = _model.LoadFile (path);
- _historyText.Clear (Text);
- ResetPosition ();
- } catch (Exception) {
- throw;
- } finally {
- UpdateWrapModel ();
- SetNeedsDisplay ();
- Adjust ();
- }
- UpdateWrapModel ();
- return res;
+ void ResetCursorVisibility ()
+ {
+ if (_savedCursorVisibility != 0) {
+ DesiredCursorVisibility = _savedCursorVisibility;
+ _savedCursorVisibility = 0;
}
+ }
- ///
- /// Loads the contents of the stream into the .
- ///
- /// true, if stream was loaded, false otherwise.
- /// Stream to load the contents from.
- public void Load (Stream stream)
- {
+ ///
+ /// Loads the contents of the file into the .
+ ///
+ /// true, if file was loaded, false otherwise.
+ /// Path to the file to load.
+ public bool Load (string path)
+ {
+ SetWrapModel ();
+ bool res;
+ try {
SetWrapModel ();
- _model.LoadStream (stream);
+ res = _model.LoadFile (path);
_historyText.Clear (Text);
ResetPosition ();
- SetNeedsDisplay ();
+ } catch (Exception) {
+ throw;
+ } finally {
UpdateWrapModel ();
- }
-
- ///
- /// Loads the contents of the list into the .
- ///
- /// Rune cells list to load the contents from.
- public void Load (List cells)
- {
- SetWrapModel ();
- _model.LoadRuneCells (cells, ColorScheme);
- _historyText.Clear (Text);
- ResetPosition ();
SetNeedsDisplay ();
- UpdateWrapModel ();
- InheritsPreviousColorScheme = true;
+ Adjust ();
}
+ UpdateWrapModel ();
+ return res;
+ }
- ///
- /// Loads the contents of the list of list into the .
- ///
- /// List of rune cells list to load the contents from.
- public void Load (List> cellsList)
- {
- SetWrapModel ();
- InheritsPreviousColorScheme = true;
- _model.LoadListRuneCells (cellsList, ColorScheme);
- _historyText.Clear (Text);
- ResetPosition ();
- SetNeedsDisplay ();
- UpdateWrapModel ();
- }
+ ///
+ /// Loads the contents of the stream into the .
+ ///
+ /// true, if stream was loaded, false otherwise.
+ /// Stream to load the contents from.
+ public void Load (Stream stream)
+ {
+ SetWrapModel ();
+ _model.LoadStream (stream);
+ _historyText.Clear (Text);
+ ResetPosition ();
+ SetNeedsDisplay ();
+ UpdateWrapModel ();
+ }
- ///
- /// Closes the contents of the stream into the .
- ///
- /// true, if stream was closed, false otherwise.
- public bool CloseFile ()
- {
- SetWrapModel ();
- var res = _model.CloseFile ();
- ResetPosition ();
- SetNeedsDisplay ();
- UpdateWrapModel ();
- return res;
- }
+ ///
+ /// Loads the contents of the list into the .
+ ///
+ /// Rune cells list to load the contents from.
+ public void Load (List cells)
+ {
+ SetWrapModel ();
+ _model.LoadRuneCells (cells, ColorScheme);
+ _historyText.Clear (Text);
+ ResetPosition ();
+ SetNeedsDisplay ();
+ UpdateWrapModel ();
+ InheritsPreviousColorScheme = true;
+ }
- ///
- /// Gets the current cursor row.
- ///
- public int CurrentRow => _currentRow;
+ ///
+ /// Loads the contents of the list of list into the .
+ ///
+ /// List of rune cells list to load the contents from.
+ public void Load (List> cellsList)
+ {
+ SetWrapModel ();
+ InheritsPreviousColorScheme = true;
+ _model.LoadListRuneCells (cellsList, ColorScheme);
+ _historyText.Clear (Text);
+ ResetPosition ();
+ SetNeedsDisplay ();
+ UpdateWrapModel ();
+ }
- ///
- /// Gets the cursor column.
- ///
- /// The cursor column.
- public int CurrentColumn => _currentColumn;
+ ///
+ /// Closes the contents of the stream into the .
+ ///
+ /// true, if stream was closed, false otherwise.
+ public bool CloseFile ()
+ {
+ SetWrapModel ();
+ bool res = _model.CloseFile ();
+ ResetPosition ();
+ SetNeedsDisplay ();
+ UpdateWrapModel ();
+ return res;
+ }
- ///
- /// Positions the cursor on the current row and column
- ///
- public override void PositionCursor ()
- {
- ProcessAutocomplete ();
+ ///
+ /// Gets the current cursor row.
+ ///
+ public int CurrentRow => _currentRow;
- if (!CanFocus || !Enabled || Application.Driver == null) {
- return;
- }
+ ///
+ /// Gets the cursor column.
+ ///
+ /// The cursor column.
+ public int CurrentColumn => _currentColumn;
- if (_selecting) {
- // BUGBUG: customized rect aren't supported now because the Redraw isn't using the Intersect method.
- //var minRow = Math.Min (Math.Max (Math.Min (selectionStartRow, currentRow) - topRow, 0), Frame.Height);
- //var maxRow = Math.Min (Math.Max (Math.Max (selectionStartRow, currentRow) - topRow, 0), Frame.Height);
- //SetNeedsDisplay (new Rect (0, minRow, Frame.Width, maxRow));
- SetNeedsDisplay ();
- }
- var line = _model.GetLine (_currentRow);
- var col = 0;
- if (line.Count > 0) {
- for (int idx = _leftColumn; idx < line.Count; idx++) {
- if (idx >= _currentColumn)
- break;
- var cols = line [idx].Rune.GetColumns ();
- if (line [idx].Rune.Value == '\t') {
- cols += TabWidth + 1;
- }
- if (!TextModel.SetCol (ref col, Frame.Width, cols)) {
- col = _currentColumn;
- break;
- }
+ ///
+ /// Positions the cursor on the current row and column
+ ///
+ public override void PositionCursor ()
+ {
+ ProcessAutocomplete ();
+
+ if (!CanFocus || !Enabled || Application.Driver == null) {
+ return;
+ }
+
+ if (_selecting) {
+ // BUGBUG: customized rect aren't supported now because the Redraw isn't using the Intersect method.
+ //var minRow = Math.Min (Math.Max (Math.Min (selectionStartRow, currentRow) - topRow, 0), Frame.Height);
+ //var maxRow = Math.Min (Math.Max (Math.Max (selectionStartRow, currentRow) - topRow, 0), Frame.Height);
+ //SetNeedsDisplay (new Rect (0, minRow, Frame.Width, maxRow));
+ SetNeedsDisplay ();
+ }
+ var line = _model.GetLine (_currentRow);
+ int col = 0;
+ if (line.Count > 0) {
+ for (int idx = _leftColumn; idx < line.Count; idx++) {
+ if (idx >= _currentColumn) {
+ break;
+ }
+ int cols = line [idx].Rune.GetColumns ();
+ if (line [idx].Rune.Value == '\t') {
+ cols += TabWidth + 1;
+ }
+ if (!TextModel.SetCol (ref col, Frame.Width, cols)) {
+ col = _currentColumn;
+ break;
}
}
- var posX = _currentColumn - _leftColumn;
- var posY = _currentRow - _topRow;
- if (posX > -1 && col >= posX && posX < Frame.Width - RightOffset
- && _topRow <= _currentRow && posY < Frame.Height - BottomOffset) {
- ResetCursorVisibility ();
- Move (col, _currentRow - _topRow);
- } else {
- SaveCursorVisibility ();
- }
}
+ int posX = _currentColumn - _leftColumn;
+ int posY = _currentRow - _topRow;
+ if (posX > -1 && col >= posX && posX < Frame.Width - RightOffset
+ && _topRow <= _currentRow && posY < Frame.Height - BottomOffset) {
+ ResetCursorVisibility ();
+ Move (col, _currentRow - _topRow);
+ } else {
+ SaveCursorVisibility ();
+ }
+ }
- void ClearRegion (int left, int top, int right, int bottom)
- {
- for (int row = top; row < bottom; row++) {
- Move (left, row);
- for (int col = left; col < right; col++)
- AddRune (col, row, (Rune)' ');
+ void ClearRegion (int left, int top, int right, int bottom)
+ {
+ for (int row = top; row < bottom; row++) {
+ Move (left, row);
+ for (int col = left; col < right; col++) {
+ AddRune (col, row, (Rune)' ');
}
}
+ }
- ///
- public override Attribute GetNormalColor ()
- {
- ColorScheme cs = ColorScheme;
- if (ColorScheme == null) {
- cs = new ColorScheme ();
- }
- return Enabled ? cs.Focus : cs.Disabled;
+ ///
+ public override Attribute GetNormalColor ()
+ {
+ var cs = ColorScheme;
+ if (ColorScheme == null) {
+ cs = new ColorScheme ();
}
+ return Enabled ? cs.Focus : cs.Disabled;
+ }
- ///
- /// Sets the driver to the default color for the control where no text is being rendered. Defaults to .
- ///
- protected virtual void SetNormalColor ()
- {
+ ///
+ /// Sets the driver to the default color for the control where no text is being rendered. Defaults to .
+ ///
+ protected virtual void SetNormalColor () => Driver.SetAttribute (GetNormalColor ());
+
+ ///
+ /// Sets the to an appropriate color for rendering the given of the
+ /// current . Override to provide custom coloring by calling
+ /// Defaults to .
+ ///
+ /// The line.
+ /// The col index.
+ /// The row index.
+ protected virtual void OnDrawNormalColor (List line, int idxCol, int idxRow)
+ {
+ var unwrappedPos = GetUnwrappedPosition (idxRow, idxCol);
+ var ev = new RuneCellEventArgs (line, idxCol, unwrappedPos);
+ DrawNormalColor?.Invoke (this, ev);
+
+ if (line [idxCol].ColorScheme != null) {
+ var colorScheme = line [idxCol].ColorScheme;
+ Driver.SetAttribute (Enabled ? colorScheme!.Focus : colorScheme!.Disabled);
+ } else {
Driver.SetAttribute (GetNormalColor ());
}
+ }
- ///
- /// Sets the to an appropriate color for rendering the given of the
- /// current . Override to provide custom coloring by calling
- /// Defaults to .
- ///
- /// The line.
- /// The col index.
- /// The row index.
- protected virtual void OnDrawNormalColor (List line, int idxCol, int idxRow)
- {
- var unwrappedPos = GetUnwrappedPosition (idxRow, idxCol);
- var ev = new RuneCellEventArgs (line, idxCol, unwrappedPos);
- DrawNormalColor?.Invoke (this, ev);
-
- if (line [idxCol].ColorScheme != null) {
- var colorScheme = line [idxCol].ColorScheme;
- Driver.SetAttribute (Enabled ? colorScheme!.Focus : colorScheme!.Disabled);
- } else {
- Driver.SetAttribute (GetNormalColor ());
- }
+ ///
+ /// Sets the to an appropriate color for rendering the given of the
+ /// current . Override to provide custom coloring by calling
+ /// Defaults to .
+ ///
+ /// The line.
+ /// The col index.
+ /// /// The row index.
+ protected virtual void OnDrawSelectionColor (List line, int idxCol, int idxRow)
+ {
+ var unwrappedPos = GetUnwrappedPosition (idxRow, idxCol);
+ var ev = new RuneCellEventArgs (line, idxCol, unwrappedPos);
+ DrawSelectionColor?.Invoke (this, ev);
+
+ if (line [idxCol].ColorScheme != null) {
+ var colorScheme = line [idxCol].ColorScheme;
+ Driver.SetAttribute (new Attribute (colorScheme!.Focus.Background, colorScheme.Focus.Foreground));
+ } else {
+ Driver.SetAttribute (new Attribute (ColorScheme.Focus.Background, ColorScheme.Focus.Foreground));
}
+ }
- ///
- /// Sets the to an appropriate color for rendering the given of the
- /// current . Override to provide custom coloring by calling
- /// Defaults to .
- ///
- /// The line.
- /// The col index.
- /// /// The row index.
- protected virtual void OnDrawSelectionColor (List line, int idxCol, int idxRow)
- {
- var unwrappedPos = GetUnwrappedPosition (idxRow, idxCol);
- var ev = new RuneCellEventArgs (line, idxCol, unwrappedPos);
- DrawSelectionColor?.Invoke (this, ev);
+ ///
+ /// Sets the to an appropriate color for rendering the given of the
+ /// current . Override to provide custom coloring by calling
+ /// Defaults to .
+ ///
+ /// The line.
+ /// The col index.
+ /// /// The row index.
+ protected virtual void OnDrawReadOnlyColor (List line, int idxCol, int idxRow)
+ {
+ var unwrappedPos = GetUnwrappedPosition (idxRow, idxCol);
+ var ev = new RuneCellEventArgs (line, idxCol, unwrappedPos);
+ DrawReadOnlyColor?.Invoke (this, ev);
+
+ var colorScheme = line [idxCol].ColorScheme != null ? line [idxCol].ColorScheme : ColorScheme;
+ Attribute attribute;
+ if (colorScheme!.Disabled.Foreground == colorScheme.Focus.Background) {
+ attribute = new Attribute (colorScheme.Focus.Foreground, colorScheme.Focus.Background);
+ } else {
+ attribute = new Attribute (colorScheme.Disabled.Foreground, colorScheme.Focus.Background);
+ }
+ Driver.SetAttribute (attribute);
+ }
- if (line [idxCol].ColorScheme != null) {
- var colorScheme = line [idxCol].ColorScheme;
- Driver.SetAttribute (new Attribute (colorScheme!.Focus.Background, colorScheme.Focus.Foreground));
- } else {
- Driver.SetAttribute (new Attribute (ColorScheme.Focus.Background, ColorScheme.Focus.Foreground));
- }
+ ///
+ /// Sets the to an appropriate color for rendering the given of the
+ /// current . Override to provide custom coloring by calling
+ /// Defaults to .
+ ///
+ /// The line.
+ /// The col index.
+ /// /// The row index.
+ protected virtual void OnDrawUsedColor (List line, int idxCol, int idxRow)
+ {
+ var unwrappedPos = GetUnwrappedPosition (idxRow, idxCol);
+ var ev = new RuneCellEventArgs (line, idxCol, unwrappedPos);
+ DrawUsedColor?.Invoke (this, ev);
+
+ if (line [idxCol].ColorScheme != null) {
+ var colorScheme = line [idxCol].ColorScheme;
+ SetValidUsedColor (colorScheme!);
+ } else {
+ SetValidUsedColor (ColorScheme);
}
+ }
- ///
- /// Sets the to an appropriate color for rendering the given of the
- /// current . Override to provide custom coloring by calling
- /// Defaults to .
- ///
- /// The line.
- /// The col index.
- /// /// The row index.
- protected virtual void OnDrawReadOnlyColor (List line, int idxCol, int idxRow)
- {
- var unwrappedPos = GetUnwrappedPosition (idxRow, idxCol);
- var ev = new RuneCellEventArgs (line, idxCol, unwrappedPos);
- DrawReadOnlyColor?.Invoke (this, ev);
-
- var colorScheme = line [idxCol].ColorScheme != null ? line [idxCol].ColorScheme : ColorScheme;
- Attribute attribute;
- if (colorScheme!.Disabled.Foreground == colorScheme.Focus.Background) {
- attribute = new Attribute (colorScheme.Focus.Foreground, colorScheme.Focus.Background);
- } else {
- attribute = new Attribute (colorScheme.Disabled.Foreground, colorScheme.Focus.Background);
+ static void SetValidUsedColor (ColorScheme colorScheme) =>
+ // BUGBUG: (v2 truecolor) This code depends on 8-bit color names; disabling for now
+ //if ((colorScheme!.HotNormal.Foreground & colorScheme.Focus.Background) == colorScheme.Focus.Foreground) {
+ Driver.SetAttribute (new Attribute (colorScheme.Focus.Background, colorScheme.Focus.Foreground));
+
+ //} else {
+ //Driver.SetAttribute (new Attribute (colorScheme!.HotNormal.Foreground & colorScheme.Focus.Background, colorScheme.Focus.Foreground));
+ //}
+ bool _isReadOnly = false;
+
+ ///
+ /// Gets or sets whether the is in read-only mode or not
+ ///
+ /// Boolean value(Default false)
+ public bool ReadOnly {
+ get => _isReadOnly;
+ set {
+ if (value != _isReadOnly) {
+ _isReadOnly = value;
+
+ SetNeedsDisplay ();
+ Adjust ();
}
- Driver.SetAttribute (attribute);
}
+ }
- ///
- /// Sets the to an appropriate color for rendering the given of the
- /// current . Override to provide custom coloring by calling
- /// Defaults to .
- ///
- /// The line.
- /// The col index.
- /// /// The row index.
- protected virtual void OnDrawUsedColor (List line, int idxCol, int idxRow)
- {
- var unwrappedPos = GetUnwrappedPosition (idxRow, idxCol);
- var ev = new RuneCellEventArgs (line, idxCol, unwrappedPos);
- DrawUsedColor?.Invoke (this, ev);
+ CursorVisibility _desiredCursorVisibility = CursorVisibility.Default;
- if (line [idxCol].ColorScheme != null) {
- var colorScheme = line [idxCol].ColorScheme;
- SetValidUsedColor (colorScheme!);
- } else {
- SetValidUsedColor (ColorScheme);
+ ///
+ /// Get / Set the wished cursor when the field is focused
+ ///
+ public CursorVisibility DesiredCursorVisibility {
+ get => _desiredCursorVisibility;
+ set {
+ if (HasFocus) {
+ Application.Driver.SetCursorVisibility (value);
}
- }
- private static void SetValidUsedColor (ColorScheme colorScheme)
- {
- // BUGBUG: (v2 truecolor) This code depends on 8-bit color names; disabling for now
- //if ((colorScheme!.HotNormal.Foreground & colorScheme.Focus.Background) == colorScheme.Focus.Foreground) {
- Driver.SetAttribute (new Attribute (colorScheme.Focus.Background, colorScheme.Focus.Foreground));
- //} else {
- //Driver.SetAttribute (new Attribute (colorScheme!.HotNormal.Foreground & colorScheme.Focus.Background, colorScheme.Focus.Foreground));
- //}
+ _desiredCursorVisibility = value;
+ SetNeedsDisplay ();
}
+ }
- bool _isReadOnly = false;
+ ///
+ public override bool OnEnter (View view)
+ {
+ //TODO: Improve it by handling read only mode of the text field
+ Application.Driver.SetCursorVisibility (DesiredCursorVisibility);
- ///
- /// Gets or sets whether the is in read-only mode or not
- ///
- /// Boolean value(Default false)
- public bool ReadOnly {
- get => _isReadOnly;
- set {
- if (value != _isReadOnly) {
- _isReadOnly = value;
+ return base.OnEnter (view);
+ }
- SetNeedsDisplay ();
- Adjust ();
- }
- }
+ ///
+ public override bool OnLeave (View view)
+ {
+ if (Application.MouseGrabView != null && Application.MouseGrabView == this) {
+ Application.UngrabMouse ();
}
- CursorVisibility _desiredCursorVisibility = CursorVisibility.Default;
-
- ///
- /// Get / Set the wished cursor when the field is focused
- ///
- public CursorVisibility DesiredCursorVisibility {
- get => _desiredCursorVisibility;
- set {
- if (HasFocus) {
- Application.Driver.SetCursorVisibility (value);
- }
+ return base.OnLeave (view);
+ }
- _desiredCursorVisibility = value;
- SetNeedsDisplay ();
- }
+ // Returns an encoded region start..end (top 32 bits are the row, low32 the column)
+ void GetEncodedRegionBounds (out long start, out long end,
+ int? startRow = null, int? startCol = null, int? cRow = null, int? cCol = null)
+ {
+ long selection;
+ long point;
+ if (startRow == null || startCol == null || cRow == null || cCol == null) {
+ selection = (long)(uint)_selectionStartRow << 32 | (uint)_selectionStartColumn;
+ point = (long)(uint)_currentRow << 32 | (uint)_currentColumn;
+ } else {
+ selection = (long)(uint)startRow << 32 | (uint)startCol;
+ point = (long)(uint)cRow << 32 | (uint)cCol;
+ }
+ if (selection > point) {
+ start = point;
+ end = selection;
+ } else {
+ start = selection;
+ end = point;
}
+ }
- ///
- public override bool OnEnter (View view)
- {
- //TODO: Improve it by handling read only mode of the text field
- Application.Driver.SetCursorVisibility (DesiredCursorVisibility);
+ bool PointInSelection (int col, int row)
+ {
+ long start, end;
+ GetEncodedRegionBounds (out start, out end);
+ long q = (long)(uint)row << 32 | (uint)col;
+ return q >= start && q <= end - 1;
+ }
- return base.OnEnter (view);
+ //
+ // Returns a string with the text in the selected
+ // region.
+ //
+ string GetRegion (int? sRow = null, int? sCol = null, int? cRow = null, int? cCol = null, TextModel? model = null)
+ {
+ long start, end;
+ GetEncodedRegionBounds (out start, out end, sRow, sCol, cRow, cCol);
+ if (start == end) {
+ return string.Empty;
}
+ int startRow = (int)(start >> 32);
+ int maxrow = (int)(end >> 32);
+ int startCol = (int)(start & 0xffffffff);
+ int endCol = (int)(end & 0xffffffff);
+ var line = model == null ? _model.GetLine (startRow) : model.GetLine (startRow);
- ///
- public override bool OnLeave (View view)
- {
- if (Application.MouseGrabView != null && Application.MouseGrabView == this) {
- Application.UngrabMouse ();
- }
+ if (startRow == maxrow) {
+ return StringFromRunes (line.GetRange (startCol, endCol - startCol));
+ }
+
+ string res = StringFromRunes (line.GetRange (startCol, line.Count - startCol));
- return base.OnLeave (view);
+ for (int row = startRow + 1; row < maxrow; row++) {
+ res = res + Environment.NewLine + StringFromRunes (model == null
+ ? _model.GetLine (row) : model.GetLine (row));
}
+ line = model == null ? _model.GetLine (maxrow) : model.GetLine (maxrow);
+ res = res + Environment.NewLine + StringFromRunes (line.GetRange (0, endCol));
+ return res;
+ }
- // Returns an encoded region start..end (top 32 bits are the row, low32 the column)
- void GetEncodedRegionBounds (out long start, out long end,
- int? startRow = null, int? startCol = null, int? cRow = null, int? cCol = null)
- {
- long selection;
- long point;
- if (startRow == null || startCol == null || cRow == null || cCol == null) {
- selection = ((long)(uint)_selectionStartRow << 32) | (uint)_selectionStartColumn;
- point = ((long)(uint)_currentRow << 32) | (uint)_currentColumn;
- } else {
- selection = ((long)(uint)startRow << 32) | (uint)startCol;
- point = ((long)(uint)cRow << 32) | (uint)cCol;
- }
- if (selection > point) {
- start = point;
- end = selection;
- } else {
- start = selection;
- end = point;
- }
- }
+ //
+ // Clears the contents of the selected region
+ //
+ void ClearRegion ()
+ {
+ SetWrapModel ();
- bool PointInSelection (int col, int row)
- {
- long start, end;
- GetEncodedRegionBounds (out start, out end);
- var q = ((long)(uint)row << 32) | (uint)col;
- return q >= start && q <= end - 1;
- }
+ long start, end;
+ long currentEncoded = (long)(uint)_currentRow << 32 | (uint)_currentColumn;
+ GetEncodedRegionBounds (out start, out end);
+ int startRow = (int)(start >> 32);
+ int maxrow = (int)(end >> 32);
+ int startCol = (int)(start & 0xffffffff);
+ int endCol = (int)(end & 0xffffffff);
+ var line = _model.GetLine (startRow);
- //
- // Returns a string with the text in the selected
- // region.
- //
- string GetRegion (int? sRow = null, int? sCol = null, int? cRow = null, int? cCol = null, TextModel? model = null)
- {
- long start, end;
- GetEncodedRegionBounds (out start, out end, sRow, sCol, cRow, cCol);
- if (start == end) {
- return string.Empty;
- }
- int startRow = (int)(start >> 32);
- var maxrow = ((int)(end >> 32));
- int startCol = (int)(start & 0xffffffff);
- var endCol = (int)(end & 0xffffffff);
- var line = model == null ? this._model.GetLine (startRow) : model.GetLine (startRow);
+ _historyText.Add (new List> () { new (line) }, new Point (startCol, startRow));
- if (startRow == maxrow)
- return StringFromRunes (line.GetRange (startCol, endCol - startCol));
+ var removedLines = new List> ();
- string res = StringFromRunes (line.GetRange (startCol, line.Count - startCol));
+ if (startRow == maxrow) {
+ removedLines.Add (new List (line));
- for (int row = startRow + 1; row < maxrow; row++) {
- res = res + Environment.NewLine + StringFromRunes (model == null
- ? this._model.GetLine (row) : model.GetLine (row));
+ line.RemoveRange (startCol, endCol - startCol);
+ _currentColumn = startCol;
+ if (_wordWrap) {
+ SetNeedsDisplay ();
+ } else {
+ // BUGBUG: customized rect aren't supported now because the Redraw isn't using the Intersect method.
+ //SetNeedsDisplay (new Rect (0, startRow - topRow, Frame.Width, startRow - topRow + 1));
+ SetNeedsDisplay ();
}
- line = model == null ? this._model.GetLine (maxrow) : model.GetLine (maxrow);
- res = res + Environment.NewLine + StringFromRunes (line.GetRange (0, endCol));
- return res;
- }
-
- //
- // Clears the contents of the selected region
- //
- void ClearRegion ()
- {
- SetWrapModel ();
- long start, end;
- long currentEncoded = ((long)(uint)_currentRow << 32) | (uint)_currentColumn;
- GetEncodedRegionBounds (out start, out end);
- int startRow = (int)(start >> 32);
- var maxrow = ((int)(end >> 32));
- int startCol = (int)(start & 0xffffffff);
- var endCol = (int)(end & 0xffffffff);
- var line = _model.GetLine (startRow);
+ _historyText.Add (new List> (removedLines), CursorPosition, HistoryText.LineStatus.Removed);
- _historyText.Add (new List> () { new List (line) }, new Point (startCol, startRow));
+ UpdateWrapModel ();
- List> removedLines = new List> ();
+ return;
+ }
- if (startRow == maxrow) {
- removedLines.Add (new List (line));
+ removedLines.Add (new List (line));
- line.RemoveRange (startCol, endCol - startCol);
- _currentColumn = startCol;
- if (_wordWrap) {
- SetNeedsDisplay ();
- } else {
- // BUGBUG: customized rect aren't supported now because the Redraw isn't using the Intersect method.
- //SetNeedsDisplay (new Rect (0, startRow - topRow, Frame.Width, startRow - topRow + 1));
- SetNeedsDisplay ();
- }
+ line.RemoveRange (startCol, line.Count - startCol);
+ var line2 = _model.GetLine (maxrow);
+ line.AddRange (line2.Skip (endCol));
+ for (int row = startRow + 1; row <= maxrow; row++) {
- _historyText.Add (new List> (removedLines), CursorPosition, HistoryText.LineStatus.Removed);
+ removedLines.Add (new List (_model.GetLine (startRow + 1)));
- UpdateWrapModel ();
+ _model.RemoveLine (startRow + 1);
+ }
+ if (currentEncoded == end) {
+ _currentRow -= maxrow - startRow;
+ }
+ _currentColumn = startCol;
- return;
- }
+ _historyText.Add (new List> (removedLines), CursorPosition,
+ HistoryText.LineStatus.Removed);
- removedLines.Add (new List (line));
+ UpdateWrapModel ();
- line.RemoveRange (startCol, line.Count - startCol);
- var line2 = _model.GetLine (maxrow);
- line.AddRange (line2.Skip (endCol));
- for (int row = startRow + 1; row <= maxrow; row++) {
+ SetNeedsDisplay ();
+ }
- removedLines.Add (new List (_model.GetLine (startRow + 1)));
+ ///
+ /// Select all text.
+ ///
+ public void SelectAll ()
+ {
+ if (_model.Count == 0) {
+ return;
+ }
+
+ StartSelecting ();
+ _selectionStartColumn = 0;
+ _selectionStartRow = 0;
+ _currentColumn = _model.GetLine (_model.Count - 1).Count;
+ _currentRow = _model.Count - 1;
+ SetNeedsDisplay ();
+ }
- _model.RemoveLine (startRow + 1);
- }
- if (currentEncoded == end) {
- _currentRow -= maxrow - (startRow);
- }
- _currentColumn = startCol;
+ ///
+ /// Find the next text based on the match case with the option to replace it.
+ ///
+ /// The text to find.
+ /// trueIf all the text was forward searched.falseotherwise.
+ /// The match case setting.
+ /// The match whole word setting.
+ /// The text to replace.
+ /// trueIf is replacing.falseotherwise.
+ /// trueIf the text was found.falseotherwise.
+ public bool FindNextText (string textToFind, out bool gaveFullTurn, bool matchCase = false,
+ bool matchWholeWord = false, string? textToReplace = null, bool replace = false)
+ {
+ if (_model.Count == 0) {
+ gaveFullTurn = false;
+ return false;
+ }
- _historyText.Add (new List> (removedLines), CursorPosition,
- HistoryText.LineStatus.Removed);
+ SetWrapModel ();
+ ResetContinuousFind ();
+ var foundPos = _model.FindNextText (textToFind, out gaveFullTurn, matchCase, matchWholeWord);
- UpdateWrapModel ();
+ return SetFoundText (textToFind, foundPos, textToReplace, replace);
+ }
- SetNeedsDisplay ();
+ ///
+ /// Find the previous text based on the match case with the option to replace it.
+ ///
+ /// The text to find.
+ /// trueIf all the text was backward searched.falseotherwise.
+ /// The match case setting.
+ /// The match whole word setting.
+ /// The text to replace.
+ /// trueIf the text was found.falseotherwise.
+ /// trueIf the text was found.falseotherwise.
+ public bool FindPreviousText (string textToFind, out bool gaveFullTurn, bool matchCase = false,
+ bool matchWholeWord = false, string? textToReplace = null, bool replace = false)
+ {
+ if (_model.Count == 0) {
+ gaveFullTurn = false;
+ return false;
}
- ///
- /// Select all text.
- ///
- public void SelectAll ()
- {
- if (_model.Count == 0) {
- return;
- }
-
- StartSelecting ();
- _selectionStartColumn = 0;
- _selectionStartRow = 0;
- _currentColumn = _model.GetLine (_model.Count - 1).Count;
- _currentRow = _model.Count - 1;
- SetNeedsDisplay ();
- }
+ SetWrapModel ();
+ ResetContinuousFind ();
+ var foundPos = _model.FindPreviousText (textToFind, out gaveFullTurn, matchCase, matchWholeWord);
- ///
- /// Find the next text based on the match case with the option to replace it.
- ///
- /// The text to find.
- /// trueIf all the text was forward searched.falseotherwise.
- /// The match case setting.
- /// The match whole word setting.
- /// The text to replace.
- /// trueIf is replacing.falseotherwise.
- /// trueIf the text was found.falseotherwise.
- public bool FindNextText (string textToFind, out bool gaveFullTurn, bool matchCase = false,
- bool matchWholeWord = false, string? textToReplace = null, bool replace = false)
- {
- if (_model.Count == 0) {
- gaveFullTurn = false;
- return false;
- }
+ return SetFoundText (textToFind, foundPos, textToReplace, replace);
+ }
- SetWrapModel ();
- ResetContinuousFind ();
- var foundPos = _model.FindNextText (textToFind, out gaveFullTurn, matchCase, matchWholeWord);
+ ///
+ /// Reset the flag to stop continuous find.
+ ///
+ public void FindTextChanged () => _continuousFind = false;
- return SetFoundText (textToFind, foundPos, textToReplace, replace);
+ ///
+ /// Replaces all the text based on the match case.
+ ///
+ /// The text to find.
+ /// The match case setting.
+ /// The match whole word setting.
+ /// The text to replace.
+ /// trueIf the text was found.falseotherwise.
+ public bool ReplaceAllText (string textToFind, bool matchCase = false, bool matchWholeWord = false,
+ string? textToReplace = null)
+ {
+ if (_isReadOnly || _model.Count == 0) {
+ return false;
}
- ///
- /// Find the previous text based on the match case with the option to replace it.
- ///
- /// The text to find.
- /// trueIf all the text was backward searched.falseotherwise.
- /// The match case setting.
- /// The match whole word setting.
- /// The text to replace.
- /// trueIf the text was found.falseotherwise.
- /// trueIf the text was found.falseotherwise.
- public bool FindPreviousText (string textToFind, out bool gaveFullTurn, bool matchCase = false,
- bool matchWholeWord = false, string? textToReplace = null, bool replace = false)
- {
- if (_model.Count == 0) {
- gaveFullTurn = false;
- return false;
- }
+ SetWrapModel ();
+ ResetContinuousFind ();
+ var foundPos = _model.ReplaceAllText (textToFind, matchCase, matchWholeWord, textToReplace);
- SetWrapModel ();
- ResetContinuousFind ();
- var foundPos = _model.FindPreviousText (textToFind, out gaveFullTurn, matchCase, matchWholeWord);
+ return SetFoundText (textToFind, foundPos, textToReplace, false, true);
+ }
- return SetFoundText (textToFind, foundPos, textToReplace, replace);
+ bool SetFoundText (string text, (Point current, bool found) foundPos,
+ string? textToReplace = null, bool replace = false, bool replaceAll = false)
+ {
+ if (foundPos.found) {
+ StartSelecting ();
+ _selectionStartColumn = foundPos.current.X;
+ _selectionStartRow = foundPos.current.Y;
+ if (!replaceAll) {
+ _currentColumn = _selectionStartColumn + text.GetRuneCount ();
+ } else {
+ _currentColumn = _selectionStartColumn + textToReplace!.GetRuneCount ();
+ }
+ _currentRow = foundPos.current.Y;
+ if (!_isReadOnly && replace) {
+ Adjust ();
+ ClearSelectedRegion ();
+ InsertAllText (textToReplace!);
+ StartSelecting ();
+ _selectionStartColumn = _currentColumn - textToReplace!.GetRuneCount ();
+ } else {
+ UpdateWrapModel ();
+ SetNeedsDisplay ();
+ Adjust ();
+ }
+ _continuousFind = true;
+ return foundPos.found;
}
+ UpdateWrapModel ();
+ _continuousFind = false;
- ///
- /// Reset the flag to stop continuous find.
- ///
- public void FindTextChanged ()
- {
- _continuousFind = false;
- }
+ return foundPos.found;
+ }
- ///
- /// Replaces all the text based on the match case.
- ///
- /// The text to find.
- /// The match case setting.
- /// The match whole word setting.
- /// The text to replace.
- /// trueIf the text was found.falseotherwise.
- public bool ReplaceAllText (string textToFind, bool matchCase = false, bool matchWholeWord = false,
- string? textToReplace = null)
- {
- if (_isReadOnly || _model.Count == 0) {
- return false;
- }
+ void ResetContinuousFind ()
+ {
+ if (!_continuousFind) {
+ int col = _selecting ? _selectionStartColumn : _currentColumn;
+ int row = _selecting ? _selectionStartRow : _currentRow;
+ _model.ResetContinuousFind (new Point (col, row));
+ }
+ }
- SetWrapModel ();
- ResetContinuousFind ();
- var foundPos = _model.ReplaceAllText (textToFind, matchCase, matchWholeWord, textToReplace);
+ string? _currentCaller;
- return SetFoundText (textToFind, foundPos, textToReplace, false, true);
+ ///
+ /// Restore from original model.
+ ///
+ void SetWrapModel ([CallerMemberName] string? caller = null)
+ {
+ if (_currentCaller != null) {
+ return;
}
- bool SetFoundText (string text, (Point current, bool found) foundPos,
- string? textToReplace = null, bool replace = false, bool replaceAll = false)
- {
- if (foundPos.found) {
- StartSelecting ();
- _selectionStartColumn = foundPos.current.X;
- _selectionStartRow = foundPos.current.Y;
- if (!replaceAll) {
- _currentColumn = _selectionStartColumn + text.GetRuneCount ();
- } else {
- _currentColumn = _selectionStartColumn + textToReplace!.GetRuneCount ();
- }
- _currentRow = foundPos.current.Y;
- if (!_isReadOnly && replace) {
- Adjust ();
- ClearSelectedRegion ();
- InsertAllText (textToReplace!);
- StartSelecting ();
- _selectionStartColumn = _currentColumn - textToReplace!.GetRuneCount ();
- } else {
- UpdateWrapModel ();
- SetNeedsDisplay ();
- Adjust ();
- }
- _continuousFind = true;
- return foundPos.found;
- }
- UpdateWrapModel ();
- _continuousFind = false;
+ if (_wordWrap) {
+ _currentCaller = caller;
- return foundPos.found;
+ _currentColumn = _wrapManager!.GetModelColFromWrappedLines (_currentRow, _currentColumn);
+ _currentRow = _wrapManager.GetModelLineFromWrappedLines (_currentRow);
+ _selectionStartColumn = _wrapManager.GetModelColFromWrappedLines (_selectionStartRow, _selectionStartColumn);
+ _selectionStartRow = _wrapManager.GetModelLineFromWrappedLines (_selectionStartRow);
+ _model = _wrapManager.Model;
}
+ }
- void ResetContinuousFind ()
- {
- if (!_continuousFind) {
- var col = _selecting ? _selectionStartColumn : _currentColumn;
- var row = _selecting ? _selectionStartRow : _currentRow;
- _model.ResetContinuousFind (new Point (col, row));
- }
+ ///
+ /// Update the original model.
+ ///
+ void UpdateWrapModel ([CallerMemberName] string? caller = null)
+ {
+ if (_currentCaller != null && _currentCaller != caller) {
+ return;
}
- string? _currentCaller;
-
- ///
- /// Restore from original model.
- ///
- void SetWrapModel ([CallerMemberName] string? caller = null)
- {
- if (_currentCaller != null)
- return;
+ if (_wordWrap) {
+ _currentCaller = null;
- if (_wordWrap) {
- _currentCaller = caller;
+ _wrapManager!.UpdateModel (_model, out int nRow, out int nCol,
+ out int nStartRow, out int nStartCol,
+ _currentRow, _currentColumn,
+ _selectionStartRow, _selectionStartColumn, true);
+ _currentRow = nRow;
+ _currentColumn = nCol;
+ _selectionStartRow = nStartRow;
+ _selectionStartColumn = nStartCol;
+ _wrapNeeded = true;
- _currentColumn = _wrapManager!.GetModelColFromWrappedLines (_currentRow, _currentColumn);
- _currentRow = _wrapManager.GetModelLineFromWrappedLines (_currentRow);
- _selectionStartColumn = _wrapManager.GetModelColFromWrappedLines (_selectionStartRow, _selectionStartColumn);
- _selectionStartRow = _wrapManager.GetModelLineFromWrappedLines (_selectionStartRow);
- _model = _wrapManager.Model;
- }
+ SetNeedsDisplay ();
}
+ if (_currentCaller != null) {
+ throw new InvalidOperationException ($"WordWrap settings was changed after the {_currentCaller} call.");
+ }
+ }
- ///
- /// Update the original model.
- ///
- void UpdateWrapModel ([CallerMemberName] string? caller = null)
- {
- if (_currentCaller != null && _currentCaller != caller)
- return;
-
- if (_wordWrap) {
- _currentCaller = null;
-
- _wrapManager!.UpdateModel (_model, out int nRow, out int nCol,
- out int nStartRow, out int nStartCol,
- _currentRow, _currentColumn,
- _selectionStartRow, _selectionStartColumn, preserveTrailingSpaces: true);
- _currentRow = nRow;
- _currentColumn = nCol;
- _selectionStartRow = nStartRow;
- _selectionStartColumn = nStartCol;
- _wrapNeeded = true;
+ ///
+ /// Invoke the event with the unwrapped .
+ ///
+ public virtual void OnUnwrappedCursorPosition (int? cRow = null, int? cCol = null)
+ {
+ int? row = cRow == null ? _currentRow : cRow;
+ int? col = cCol == null ? _currentColumn : cCol;
+ if (cRow == null && cCol == null && _wordWrap) {
+ row = _wrapManager!.GetModelLineFromWrappedLines (_currentRow);
+ col = _wrapManager.GetModelColFromWrappedLines (_currentRow, _currentColumn);
+ }
+ UnwrappedCursorPosition?.Invoke (this, new PointEventArgs (new Point ((int)col, (int)row)));
+ }
- SetNeedsDisplay ();
- }
- if (_currentCaller != null)
- throw new InvalidOperationException ($"WordWrap settings was changed after the {_currentCaller} call.");
- }
+ string GetSelectedRegion ()
+ {
+ int cRow = _currentRow;
+ int cCol = _currentColumn;
+ int startRow = _selectionStartRow;
+ int startCol = _selectionStartColumn;
+ var model = _model;
+ if (_wordWrap) {
+ cRow = _wrapManager!.GetModelLineFromWrappedLines (_currentRow);
+ cCol = _wrapManager.GetModelColFromWrappedLines (_currentRow, _currentColumn);
+ startRow = _wrapManager.GetModelLineFromWrappedLines (_selectionStartRow);
+ startCol = _wrapManager.GetModelColFromWrappedLines (_selectionStartRow, _selectionStartColumn);
+ model = _wrapManager.Model;
+ }
+ OnUnwrappedCursorPosition (cRow, cCol);
+ return GetRegion (startRow, startCol, cRow, cCol, model);
+ }
- ///
- /// Invoke the event with the unwrapped .
- ///
- public virtual void OnUnwrappedCursorPosition (int? cRow = null, int? cCol = null)
- {
- var row = cRow == null ? _currentRow : cRow;
- var col = cCol == null ? _currentColumn : cCol;
- if (cRow == null && cCol == null && _wordWrap) {
- row = _wrapManager!.GetModelLineFromWrappedLines (_currentRow);
- col = _wrapManager.GetModelColFromWrappedLines (_currentRow, _currentColumn);
- }
- UnwrappedCursorPosition?.Invoke (this, new PointEventArgs (new Point ((int)col, (int)row)));
- }
+ bool _isDrawing = false;
- string GetSelectedRegion ()
- {
- var cRow = _currentRow;
- var cCol = _currentColumn;
- var startRow = _selectionStartRow;
- var startCol = _selectionStartColumn;
- var model = this._model;
- if (_wordWrap) {
- cRow = _wrapManager!.GetModelLineFromWrappedLines (_currentRow);
- cCol = _wrapManager.GetModelColFromWrappedLines (_currentRow, _currentColumn);
- startRow = _wrapManager.GetModelLineFromWrappedLines (_selectionStartRow);
- startCol = _wrapManager.GetModelColFromWrappedLines (_selectionStartRow, _selectionStartColumn);
- model = _wrapManager.Model;
- }
- OnUnwrappedCursorPosition (cRow, cCol);
- return GetRegion (startRow, startCol, cRow, cCol, model);
- }
+ ///
+ public override void OnDrawContent (Rect contentArea)
+ {
+ _isDrawing = true;
- bool _isDrawing = false;
+ SetNormalColor ();
- ///
- public override void OnDrawContent (Rect contentArea)
- {
- _isDrawing = true;
+ var offB = OffSetBackground ();
+ int right = Frame.Width + offB.width + RightOffset;
+ int bottom = Frame.Height + offB.height + BottomOffset;
+ int row = 0;
+ for (int idxRow = _topRow; idxRow < _model.Count; idxRow++) {
+ var line = _model.GetLine (idxRow);
+ int lineRuneCount = line.Count;
+ int col = 0;
- SetNormalColor ();
+ Move (0, row);
+ for (int idxCol = _leftColumn; idxCol < lineRuneCount; idxCol++) {
+ var rune = idxCol >= lineRuneCount ? (Rune)' ' : line [idxCol].Rune;
+ int cols = rune.GetColumns ();
+ if (idxCol < line.Count && _selecting && PointInSelection (idxCol, idxRow)) {
+ OnDrawSelectionColor (line, idxCol, idxRow);
+ } else if (idxCol == _currentColumn && idxRow == _currentRow && !_selecting && !Used
+ && HasFocus && idxCol < lineRuneCount) {
+ OnDrawUsedColor (line, idxCol, idxRow);
+ } else if (ReadOnly) {
+ OnDrawReadOnlyColor (line, idxCol, idxRow);
+ } else {
+ OnDrawNormalColor (line, idxCol, idxRow);
+ }
- var offB = OffSetBackground ();
- int right = Frame.Width + offB.width + RightOffset;
- int bottom = Frame.Height + offB.height + BottomOffset;
- var row = 0;
- for (int idxRow = _topRow; idxRow < _model.Count; idxRow++) {
- var line = _model.GetLine (idxRow);
- int lineRuneCount = line.Count;
- var col = 0;
-
- Move (0, row);
- for (int idxCol = _leftColumn; idxCol < lineRuneCount; idxCol++) {
- var rune = idxCol >= lineRuneCount ? (Rune)' ' : line [idxCol].Rune;
- var cols = rune.GetColumns ();
- if (idxCol < line.Count && _selecting && PointInSelection (idxCol, idxRow)) {
- OnDrawSelectionColor (line, idxCol, idxRow);
- } else if (idxCol == _currentColumn && idxRow == _currentRow && !_selecting && !Used
- && HasFocus && idxCol < lineRuneCount) {
- OnDrawUsedColor (line, idxCol, idxRow);
- } else if (ReadOnly) {
- OnDrawReadOnlyColor (line, idxCol, idxRow);
- } else {
- OnDrawNormalColor (line, idxCol, idxRow);
+ if (rune.Value == '\t') {
+ cols += TabWidth + 1;
+ if (col + cols > right) {
+ cols = right - col;
}
-
- if (rune.Value == '\t') {
- cols += TabWidth + 1;
- if (col + cols > right) {
- cols = right - col;
- }
- for (int i = 0; i < cols; i++) {
- if (col + i < right) {
- AddRune (col + i, row, (Rune)' ');
- }
+ for (int i = 0; i < cols; i++) {
+ if (col + i < right) {
+ AddRune (col + i, row, (Rune)' ');
}
- } else {
- AddRune (col, row, rune);
- }
- if (!TextModel.SetCol (ref col, contentArea.Right, cols)) {
- break;
- }
- if (idxCol + 1 < lineRuneCount && col + line [idxCol + 1].Rune.GetColumns () > right) {
- break;
}
+ } else {
+ AddRune (col, row, rune);
+ }
+ if (!TextModel.SetCol (ref col, contentArea.Right, cols)) {
+ break;
}
- if (col < right) {
- SetNormalColor ();
- ClearRegion (col, row, right, row + 1);
+ if (idxCol + 1 < lineRuneCount && col + line [idxCol + 1].Rune.GetColumns () > right) {
+ break;
}
- row++;
}
- if (row < bottom) {
+ if (col < right) {
SetNormalColor ();
- ClearRegion (contentArea.Left, row, right, bottom);
+ ClearRegion (col, row, right, row + 1);
}
-
- PositionCursor ();
-
- _isDrawing = false;
+ row++;
}
-
- private (int Row, int Col) GetUnwrappedPosition (int line, int col)
- {
- if (WordWrap) {
- return new (_wrapManager!.GetModelLineFromWrappedLines (line), _wrapManager.GetModelColFromWrappedLines (line, col));
- }
- return new (line, col);
+ if (row < bottom) {
+ SetNormalColor ();
+ ClearRegion (contentArea.Left, row, right, bottom);
}
- private void ProcessAutocomplete ()
- {
- if (_isDrawing) {
- return;
- }
- if (_clickWithSelecting) {
- _clickWithSelecting = false;
- return;
- }
- if (SelectedLength > 0)
- return;
-
- // draw autocomplete
- GenerateSuggestions ();
+ PositionCursor ();
- var renderAt = new Point (
- Autocomplete.Context.CursorPosition,
- Autocomplete.PopupInsideContainer
- ? (CursorPosition.Y + 1) - TopRow
- : 0);
+ _isDrawing = false;
+ }
- Autocomplete.RenderOverlay (renderAt);
+ (int Row, int Col) GetUnwrappedPosition (int line, int col)
+ {
+ if (WordWrap) {
+ return new ValueTuple (_wrapManager!.GetModelLineFromWrappedLines (line), _wrapManager.GetModelColFromWrappedLines (line, col));
}
+ return new ValueTuple (line, col);
+ }
- private void GenerateSuggestions ()
- {
- var currentLine = this.GetCurrentLine ();
- var cursorPosition = Math.Min (this.CurrentColumn, currentLine.Count);
- Autocomplete.Context = new AutocompleteContext (currentLine, cursorPosition,
- Autocomplete.Context != null ? Autocomplete.Context.Canceled : false);
- Autocomplete.GenerateSuggestions (
- Autocomplete.Context);
+ void ProcessAutocomplete ()
+ {
+ if (_isDrawing) {
+ return;
}
-
- ///
- public override bool CanFocus {
- get => base.CanFocus;
- set { base.CanFocus = value; }
+ if (_clickWithSelecting) {
+ _clickWithSelecting = false;
+ return;
}
-
- void SetClipboard (string text)
- {
- if (text != null) {
- Clipboard.Contents = text;
- }
+ if (SelectedLength > 0) {
+ return;
}
- void AppendClipboard (string text)
- {
- Clipboard.Contents += text;
- }
+ // draw autocomplete
+ GenerateSuggestions ();
- ///
- /// Inserts the given text at the current cursor position
- /// exactly as if the user had just typed it
- ///
- /// Text to add
- public void InsertText (string toAdd)
- {
- foreach (var ch in toAdd) {
+ var renderAt = new Point (
+ Autocomplete.Context.CursorPosition,
+ Autocomplete.PopupInsideContainer
+ ? CursorPosition.Y + 1 - TopRow
+ : 0);
- KeyCode key;
+ Autocomplete.RenderOverlay (renderAt);
+ }
- try {
- key = (KeyCode)ch;
- } catch (Exception) {
+ void GenerateSuggestions ()
+ {
+ var currentLine = this.GetCurrentLine ();
+ var cursorPosition = Math.Min (CurrentColumn, currentLine.Count);
+ Autocomplete.Context = new AutocompleteContext (currentLine, cursorPosition,
+ Autocomplete.Context != null ? Autocomplete.Context.Canceled : false);
+ Autocomplete.GenerateSuggestions (
+ Autocomplete.Context);
+ }
- throw new ArgumentException ($"Cannot insert character '{ch}' because it does not map to a Key");
- }
+ ///
+ public override bool CanFocus {
+ get => base.CanFocus;
+ set => base.CanFocus = value;
+ }
+
+ void SetClipboard (string text)
+ {
+ if (text != null) {
+ Clipboard.Contents = text;
+ }
+ }
+
+ void AppendClipboard (string text) => Clipboard.Contents += text;
- InsertText (new Key () { KeyCode = key });
+ ///
+ /// Inserts the given text at the current cursor position
+ /// exactly as if the user had just typed it
+ ///
+ /// Text to add
+ public void InsertText (string toAdd)
+ {
+ foreach (char ch in toAdd) {
+ KeyCode key;
+ try {
+ key = (KeyCode)ch;
+ } catch (Exception) {
+ throw new ArgumentException ($"Cannot insert character '{ch}' because it does not map to a Key");
}
+ InsertText (new Key (key));
+
if (NeedsDisplay) {
Adjust ();
} else {
PositionCursor ();
}
}
+ }
- void Insert (RuneCell cell)
+ void Insert (RuneCell cell)
{
var line = GetCurrentLine ();
if (Used) {
@@ -3089,7 +3054,7 @@ void Insert (RuneCell cell)
}
line.Insert (Math.Min (_currentColumn, line.Count), cell);
}
- var prow = _currentRow - _topRow;
+ int prow = _currentRow - _topRow;
if (!_wrapNeeded) {
// BUGBUG: customized rect aren't supported now because the Redraw isn't using the Intersect method.
//SetNeedsDisplay (new Rect (0, prow, Math.Max (Frame.Width, 0), Math.Max (prow + 1, 0)));
@@ -3099,13 +3064,14 @@ void Insert (RuneCell cell)
string StringFromRunes (List cells)
{
- if (cells == null)
+ if (cells == null) {
throw new ArgumentNullException (nameof (cells));
+ }
int size = 0;
foreach (var cell in cells) {
size += cell.Rune.GetEncodingLength ();
}
- var encoded = new byte [size];
+ byte [] encoded = new byte [size];
int offset = 0;
foreach (var cell in cells) {
offset += cell.Rune.Encode (encoded, offset);
@@ -3150,15 +3116,15 @@ void InsertAllText (string text)
var line = GetCurrentLine ();
- _historyText.Add (new List> () { new List (line) }, CursorPosition);
+ _historyText.Add (new List> () { new (line) }, CursorPosition);
// Optimize single line
if (lines.Count == 1) {
line.InsertRange (_currentColumn, lines [0]);
_currentColumn += lines [0].Count;
- _historyText.Add (new List> () { new List (line) }, CursorPosition,
- HistoryText.LineStatus.Replaced);
+ _historyText.Add (new List> () { new (line) }, CursorPosition,
+ HistoryText.LineStatus.Replaced);
if (!_wordWrap && _currentColumn - _leftColumn > Frame.Width) {
_leftColumn = Math.Max (_currentColumn - Frame.Width + 1, 0);
@@ -3183,7 +3149,7 @@ void InsertAllText (string text)
if (_model.Count > 0 && line.Count > 0 && !_copyWithoutSelection) {
// Keep a copy of the rest of the line
- var restCount = line.Count - _currentColumn;
+ int restCount = line.Count - _currentColumn;
rest = line.GetRange (_currentColumn, restCount);
line.RemoveRange (_currentColumn, restCount);
}
@@ -3192,7 +3158,7 @@ void InsertAllText (string text)
line.InsertRange (_currentColumn, lines [0]);
//model.AddLine (currentRow, lines [0]);
- var addedLines = new List> () { new List (line) };
+ var addedLines = new List> () { new (line) };
for (int i = 1; i < lines.Count; i++) {
_model.AddLine (_currentRow + i, lines [i]);
@@ -3215,8 +3181,8 @@ void InsertAllText (string text)
_currentColumn = rest != null ? lastp : lines [lines.Count - 1].Count;
Adjust ();
- _historyText.Add (new List> () { new List (line) }, CursorPosition,
- HistoryText.LineStatus.Replaced);
+ _historyText.Add (new List> () { new (line) }, CursorPosition,
+ HistoryText.LineStatus.Replaced);
UpdateWrapModel ();
OnContentsChanged ();
@@ -3230,12 +3196,13 @@ void TrackColumn ()
{
// Now track the column
var line = GetCurrentLine ();
- if (line.Count < _columnTrack)
+ if (line.Count < _columnTrack) {
_currentColumn = line.Count;
- else if (_columnTrack != -1)
+ } else if (_columnTrack != -1) {
_currentColumn = _columnTrack;
- else if (_currentColumn > line.Count)
+ } else if (_currentColumn > line.Count) {
_currentColumn = line.Count;
+ }
Adjust ();
}
@@ -3250,12 +3217,12 @@ void Adjust ()
_leftColumn = _currentColumn;
need = true;
} else if (!_wordWrap && (_currentColumn - _leftColumn + RightOffset > Frame.Width + offB.width
- || dSize.size + RightOffset >= Frame.Width + offB.width)) {
+ || dSize.size + RightOffset >= Frame.Width + offB.width)) {
_leftColumn = TextModel.CalculateLeftColumn (line, _leftColumn, _currentColumn,
- Frame.Width + offB.width - RightOffset, TabWidth);
+ Frame.Width + offB.width - RightOffset, TabWidth);
need = true;
- } else if ((_wordWrap && _leftColumn > 0) || (dSize.size + RightOffset < Frame.Width + offB.width
- && tSize.size + RightOffset < Frame.Width + offB.width)) {
+ } else if (_wordWrap && _leftColumn > 0 || dSize.size + RightOffset < Frame.Width + offB.width
+ && tSize.size + RightOffset < Frame.Width + offB.width) {
if (_leftColumn > 0) {
_leftColumn = 0;
need = true;
@@ -3285,1680 +3252,1679 @@ void Adjust ()
OnUnwrappedCursorPosition ();
}
- ///
- /// Called when the contents of the TextView change. E.g. when the user types text or deletes text. Raises
- /// the event.
- ///
- public virtual void OnContentsChanged ()
- {
- ContentsChanged?.Invoke (this, new ContentsChangedEventArgs (CurrentRow, CurrentColumn));
+ ///
+ /// Called when the contents of the TextView change. E.g. when the user types text or deletes text. Raises
+ /// the event.
+ ///
+ public virtual void OnContentsChanged ()
+ {
+ ContentsChanged?.Invoke (this, new ContentsChangedEventArgs (CurrentRow, CurrentColumn));
+
+ ProcessInheritsPreviousColorScheme (CurrentRow, CurrentColumn);
+ ProcessAutocomplete ();
+ }
- ProcessInheritsPreviousColorScheme (CurrentRow, CurrentColumn);
- ProcessAutocomplete ();
+ // If InheritsPreviousColorScheme is enabled this method will check if the rune cell on
+ // the row and col location and around has a not null color scheme. If it's null will set it with
+ // the very most previous valid color scheme.
+ void ProcessInheritsPreviousColorScheme (int row, int col)
+ {
+ if (!InheritsPreviousColorScheme || Lines == 1 && GetLine (Lines).Count == 0) {
+ return;
}
- // If InheritsPreviousColorScheme is enabled this method will check if the rune cell on
- // the row and col location and around has a not null color scheme. If it's null will set it with
- // the very most previous valid color scheme.
- private void ProcessInheritsPreviousColorScheme (int row, int col)
- {
- if (!InheritsPreviousColorScheme || (Lines == 1 && GetLine (Lines).Count == 0)) {
+ var line = GetLine (row);
+ var lineToSet = line;
+ while (line.Count == 0) {
+ if (row == 0 && line.Count == 0) {
return;
}
+ row--;
+ line = GetLine (row);
+ lineToSet = line;
+ }
+ int colWithColor = Math.Max (Math.Min (col - 2, line.Count - 1), 0);
+ var cell = line [colWithColor];
+ int colWithoutColor = Math.Max (col - 1, 0);
- var line = GetLine (row);
- var lineToSet = line;
- while (line.Count == 0) {
- if (row == 0 && line.Count == 0) {
- return;
- }
- row--;
- line = GetLine (row);
- lineToSet = line;
- }
- var colWithColor = Math.Max (Math.Min (col - 2, line.Count - 1), 0);
- var cell = line [colWithColor];
- var colWithoutColor = Math.Max (col - 1, 0);
-
- if (cell.ColorScheme != null && colWithColor == 0 && lineToSet [colWithoutColor].ColorScheme != null) {
- for (int r = row - 1; r > -1; r--) {
- var l = GetLine (r);
- for (int c = l.Count - 1; c > -1; c--) {
- if (l [c].ColorScheme == null) {
- l [c].ColorScheme = cell.ColorScheme;
- } else {
- return;
- }
+ if (cell.ColorScheme != null && colWithColor == 0 && lineToSet [colWithoutColor].ColorScheme != null) {
+ for (int r = row - 1; r > -1; r--) {
+ var l = GetLine (r);
+ for (int c = l.Count - 1; c > -1; c--) {
+ if (l [c].ColorScheme == null) {
+ l [c].ColorScheme = cell.ColorScheme;
+ } else {
+ return;
}
}
- return;
- } else if (cell.ColorScheme == null) {
- for (int r = row; r > -1; r--) {
- var l = GetLine (r);
- colWithColor = l.FindLastIndex (colWithColor > -1 ? colWithColor : l.Count - 1, rc => rc.ColorScheme != null);
- if (colWithColor > -1 && l [colWithColor].ColorScheme != null) {
- cell = l [colWithColor];
- break;
- }
+ }
+ return;
+ } else if (cell.ColorScheme == null) {
+ for (int r = row; r > -1; r--) {
+ var l = GetLine (r);
+ colWithColor = l.FindLastIndex (colWithColor > -1 ? colWithColor : l.Count - 1, rc => rc.ColorScheme != null);
+ if (colWithColor > -1 && l [colWithColor].ColorScheme != null) {
+ cell = l [colWithColor];
+ break;
}
- } else {
- var cRow = row;
- while (cell.ColorScheme == null) {
- if ((colWithColor == 0 || cell.ColorScheme == null) && cRow > 0) {
- line = GetLine (--cRow);
- colWithColor = line.Count - 1;
- cell = line [colWithColor];
- } else if (cRow == 0 && colWithColor < line.Count) {
- cell = line [colWithColor + 1];
- }
+ }
+ } else {
+ int cRow = row;
+ while (cell.ColorScheme == null) {
+ if ((colWithColor == 0 || cell.ColorScheme == null) && cRow > 0) {
+ line = GetLine (--cRow);
+ colWithColor = line.Count - 1;
+ cell = line [colWithColor];
+ } else if (cRow == 0 && colWithColor < line.Count) {
+ cell = line [colWithColor + 1];
}
}
- if (cell.ColorScheme != null && colWithColor > -1 && colWithoutColor < lineToSet.Count && lineToSet [colWithoutColor].ColorScheme == null) {
- while (lineToSet [colWithoutColor].ColorScheme == null) {
- lineToSet [colWithoutColor].ColorScheme = cell.ColorScheme;
- colWithoutColor--;
- if (colWithoutColor == -1 && row > 0) {
- lineToSet = GetLine (--row);
- colWithoutColor = lineToSet.Count - 1;
- }
+ }
+ if (cell.ColorScheme != null && colWithColor > -1 && colWithoutColor < lineToSet.Count && lineToSet [colWithoutColor].ColorScheme == null) {
+ while (lineToSet [colWithoutColor].ColorScheme == null) {
+ lineToSet [colWithoutColor].ColorScheme = cell.ColorScheme;
+ colWithoutColor--;
+ if (colWithoutColor == -1 && row > 0) {
+ lineToSet = GetLine (--row);
+ colWithoutColor = lineToSet.Count - 1;
}
}
}
+ }
- (int width, int height) OffSetBackground ()
- {
- int w = 0;
- int h = 0;
- if (SuperView?.Frame.Right - Frame.Right < 0) {
- w = SuperView!.Frame.Right - Frame.Right - 1;
- }
- if (SuperView?.Frame.Bottom - Frame.Bottom < 0) {
- h = SuperView!.Frame.Bottom - Frame.Bottom - 1;
- }
- return (w, h);
+ (int width, int height) OffSetBackground ()
+ {
+ int w = 0;
+ int h = 0;
+ if (SuperView?.Frame.Right - Frame.Right < 0) {
+ w = SuperView!.Frame.Right - Frame.Right - 1;
+ }
+ if (SuperView?.Frame.Bottom - Frame.Bottom < 0) {
+ h = SuperView!.Frame.Bottom - Frame.Bottom - 1;
}
+ return (w, h);
+ }
- ///
- /// Will scroll the to display the specified row at the top if is true or
- /// will scroll the to display the specified column at the left if is false.
- ///
- /// Row that should be displayed at the top or Column that should be displayed at the left,
- /// if the value is negative it will be reset to zero
- /// If true (default) the is a row, column otherwise.
- public void ScrollTo (int idx, bool isRow = true)
- {
- if (idx < 0) {
- idx = 0;
- }
- if (isRow) {
- _topRow = Math.Max (idx > _model.Count - 1 ? _model.Count - 1 : idx, 0);
- } else if (!_wordWrap) {
- var maxlength = _model.GetMaxVisibleLine (_topRow, _topRow + Frame.Height + RightOffset, TabWidth);
- _leftColumn = Math.Max (!_wordWrap && idx > maxlength - 1 ? maxlength - 1 : idx, 0);
- }
- SetNeedsDisplay ();
- }
+ ///
+ /// Will scroll the to display the specified row at the top if is true or
+ /// will scroll the to display the specified column at the left if is false.
+ ///
+ /// Row that should be displayed at the top or Column that should be displayed at the left,
+ /// if the value is negative it will be reset to zero
+ /// If true (default) the is a row, column otherwise.
+ public void ScrollTo (int idx, bool isRow = true)
+ {
+ if (idx < 0) {
+ idx = 0;
+ }
+ if (isRow) {
+ _topRow = Math.Max (idx > _model.Count - 1 ? _model.Count - 1 : idx, 0);
+ } else if (!_wordWrap) {
+ int maxlength = _model.GetMaxVisibleLine (_topRow, _topRow + Frame.Height + RightOffset, TabWidth);
+ _leftColumn = Math.Max (!_wordWrap && idx > maxlength - 1 ? maxlength - 1 : idx, 0);
+ }
+ SetNeedsDisplay ();
+ }
- bool _lastWasKill;
- bool _wrapNeeded;
- bool _shiftSelecting;
+ bool _lastWasKill;
+ bool _wrapNeeded;
+ bool _shiftSelecting;
- ///
- public override bool? OnInvokingKeyBindings (Key a)
- {
- // Give autocomplete first opportunity to respond to key presses
- if (SelectedLength == 0 && Autocomplete.Suggestions.Count > 0 && Autocomplete.ProcessKey (a)) {
- return true;
- }
- return base.OnInvokingKeyBindings (a);
+ ///
+ public override bool? OnInvokingKeyBindings (Key a)
+ {
+ // Give autocomplete first opportunity to respond to key presses
+ if (SelectedLength == 0 && Autocomplete.Suggestions.Count > 0 && Autocomplete.ProcessKey (a)) {
+ return true;
}
+ return base.OnInvokingKeyBindings (a);
+ }
- ///
- public override bool OnProcessKeyDown (Key a)
- {
- if (!CanFocus) {
- return true;
- }
+ ///
+ public override bool OnProcessKeyDown (Key a)
+ {
+ if (!CanFocus) {
+ return true;
+ }
- ResetColumnTrack ();
+ ResetColumnTrack ();
- // Ignore control characters and other special keys
- if (!a.IsKeyCodeAtoZ && (a.KeyCode < KeyCode.Space || a.KeyCode > KeyCode.CharMask)) {
- return false;
- }
+ // Ignore control characters and other special keys
+ if (!a.IsKeyCodeAtoZ && (a.KeyCode < KeyCode.Space || a.KeyCode > KeyCode.CharMask)) {
+ return false;
+ }
- InsertText (a);
- DoNeededAction ();
+ InsertText (a);
+ DoNeededAction ();
- return true;
+ return true;
+ }
+
+ ///
+ /// Redoes the latest changes.
+ ///
+ public void Redo ()
+ {
+ if (ReadOnly) {
+ return;
}
- ///
- /// Redoes the latest changes.
- ///
- public void Redo ()
- {
- if (ReadOnly) {
- return;
- }
+ _historyText.Redo ();
+ }
- _historyText.Redo ();
+ ///
+ /// Undoes the latest changes.
+ ///
+ public void Undo ()
+ {
+ if (ReadOnly) {
+ return;
}
- ///
- /// Undoes the latest changes.
- ///
- public void Undo ()
- {
- if (ReadOnly) {
- return;
- }
+ _historyText.Undo ();
+ }
- _historyText.Undo ();
- }
+ bool ProcessMovePreviousView ()
+ {
+ ResetColumnTrack ();
+ return MovePreviousView ();
+ }
- bool ProcessMovePreviousView ()
- {
- ResetColumnTrack ();
- return MovePreviousView ();
- }
+ bool ProcessMoveNextView ()
+ {
+ ResetColumnTrack ();
+ return MoveNextView ();
+ }
- bool ProcessMoveNextView ()
- {
- ResetColumnTrack ();
- return MoveNextView ();
- }
+ void ProcessSetOverwrite ()
+ {
+ ResetColumnTrack ();
+ SetOverwrite (!Used);
+ }
- void ProcessSetOverwrite ()
- {
- ResetColumnTrack ();
- SetOverwrite (!Used);
- }
+ void ProcessSelectAll ()
+ {
+ ResetColumnTrack ();
+ SelectAll ();
+ }
- void ProcessSelectAll ()
- {
- ResetColumnTrack ();
- SelectAll ();
- }
+ void MoveTopHomeExtend ()
+ {
+ ResetColumnTrack ();
+ StartSelecting ();
+ MoveHome ();
+ }
- void MoveTopHomeExtend ()
- {
- ResetColumnTrack ();
- StartSelecting ();
- MoveHome ();
+ void MoveTopHome ()
+ {
+ ResetAllTrack ();
+ if (_shiftSelecting && _selecting) {
+ StopSelecting ();
}
+ MoveHome ();
+ }
- void MoveTopHome ()
- {
- ResetAllTrack ();
- if (_shiftSelecting && _selecting) {
- StopSelecting ();
- }
- MoveHome ();
- }
+ void MoveBottomEndExtend ()
+ {
+ ResetAllTrack ();
+ StartSelecting ();
+ MoveEnd ();
+ }
- void MoveBottomEndExtend ()
- {
- ResetAllTrack ();
- StartSelecting ();
- MoveEnd ();
+ void MoveBottomEnd ()
+ {
+ ResetAllTrack ();
+ if (_shiftSelecting && _selecting) {
+ StopSelecting ();
}
+ MoveEnd ();
+ }
- void MoveBottomEnd ()
- {
- ResetAllTrack ();
- if (_shiftSelecting && _selecting) {
- StopSelecting ();
- }
- MoveEnd ();
- }
+ void ProcessKillWordBackward ()
+ {
+ ResetColumnTrack ();
+ KillWordBackward ();
+ }
- void ProcessKillWordBackward ()
- {
- ResetColumnTrack ();
- KillWordBackward ();
- }
+ void ProcessKillWordForward ()
+ {
+ ResetColumnTrack ();
+ KillWordForward ();
+ }
- void ProcessKillWordForward ()
- {
- ResetColumnTrack ();
- KillWordForward ();
- }
+ void ProcessMoveWordForwardExtend ()
+ {
+ ResetAllTrack ();
+ StartSelecting ();
+ MoveWordForward ();
+ }
- void ProcessMoveWordForwardExtend ()
- {
- ResetAllTrack ();
- StartSelecting ();
- MoveWordForward ();
+ void ProcessMoveWordForward ()
+ {
+ ResetAllTrack ();
+ if (_shiftSelecting && _selecting) {
+ StopSelecting ();
}
+ MoveWordForward ();
+ }
- void ProcessMoveWordForward ()
- {
- ResetAllTrack ();
- if (_shiftSelecting && _selecting) {
- StopSelecting ();
- }
- MoveWordForward ();
- }
+ void ProcessMoveWordBackwardExtend ()
+ {
+ ResetAllTrack ();
+ StartSelecting ();
+ MoveWordBackward ();
+ }
- void ProcessMoveWordBackwardExtend ()
- {
- ResetAllTrack ();
- StartSelecting ();
- MoveWordBackward ();
+ void ProcessMoveWordBackward ()
+ {
+ ResetAllTrack ();
+ if (_shiftSelecting && _selecting) {
+ StopSelecting ();
}
+ MoveWordBackward ();
+ }
- void ProcessMoveWordBackward ()
- {
- ResetAllTrack ();
- if (_shiftSelecting && _selecting) {
- StopSelecting ();
- }
- MoveWordBackward ();
- }
+ void ProcessCut ()
+ {
+ ResetColumnTrack ();
+ Cut ();
+ }
- void ProcessCut ()
- {
- ResetColumnTrack ();
- Cut ();
- }
+ void ProcessCopy ()
+ {
+ ResetColumnTrack ();
+ Copy ();
+ }
- void ProcessCopy ()
- {
- ResetColumnTrack ();
- Copy ();
- }
+ void ToggleSelecting ()
+ {
+ ResetColumnTrack ();
+ _selecting = !_selecting;
+ _selectionStartColumn = _currentColumn;
+ _selectionStartRow = _currentRow;
+ }
- void ToggleSelecting ()
- {
- ResetColumnTrack ();
- _selecting = !_selecting;
- _selectionStartColumn = _currentColumn;
- _selectionStartRow = _currentRow;
+ void ProcessPaste ()
+ {
+ ResetColumnTrack ();
+ if (_isReadOnly) {
+ return;
}
+ Paste ();
+ }
- void ProcessPaste ()
- {
- ResetColumnTrack ();
- if (_isReadOnly)
- return;
- Paste ();
- }
+ void ProcessMoveEndOfLineExtend ()
+ {
+ ResetAllTrack ();
+ StartSelecting ();
+ MoveEndOfLine ();
+ }
- void ProcessMoveEndOfLineExtend ()
- {
- ResetAllTrack ();
- StartSelecting ();
- MoveEndOfLine ();
+ void ProcessMoveEndOfLine ()
+ {
+ ResetAllTrack ();
+ if (_shiftSelecting && _selecting) {
+ StopSelecting ();
}
+ MoveEndOfLine ();
+ }
- void ProcessMoveEndOfLine ()
- {
- ResetAllTrack ();
- if (_shiftSelecting && _selecting) {
- StopSelecting ();
- }
- MoveEndOfLine ();
- }
+ void ProcessDeleteCharRight ()
+ {
+ ResetColumnTrack ();
+ DeleteCharRight ();
+ }
- void ProcessDeleteCharRight ()
- {
- ResetColumnTrack ();
- DeleteCharRight ();
- }
+ void ProcessMoveStartOfLineExtend ()
+ {
+ ResetAllTrack ();
+ StartSelecting ();
+ MoveStartOfLine ();
+ }
- void ProcessMoveStartOfLineExtend ()
- {
- ResetAllTrack ();
- StartSelecting ();
- MoveStartOfLine ();
+ void ProcessMoveStartOfLine ()
+ {
+ ResetAllTrack ();
+ if (_shiftSelecting && _selecting) {
+ StopSelecting ();
}
+ MoveStartOfLine ();
+ }
- void ProcessMoveStartOfLine ()
- {
- ResetAllTrack ();
- if (_shiftSelecting && _selecting) {
- StopSelecting ();
- }
- MoveStartOfLine ();
- }
+ void ProcessDeleteCharLeft ()
+ {
+ ResetColumnTrack ();
+ DeleteCharLeft ();
+ }
- void ProcessDeleteCharLeft ()
- {
- ResetColumnTrack ();
- DeleteCharLeft ();
+ void ProcessMoveLeftExtend ()
+ {
+ ResetAllTrack ();
+ StartSelecting ();
+ MoveLeft ();
+ }
+
+ bool ProcessMoveLeft ()
+ {
+ // if the user presses Left (without any control keys) and they are at the start of the text
+ if (_currentColumn == 0 && _currentRow == 0) {
+ // do not respond (this lets the key press fall through to navigation system - which usually changes focus backward)
+ return false;
}
- void ProcessMoveLeftExtend ()
- {
- ResetAllTrack ();
- StartSelecting ();
- MoveLeft ();
+ ResetAllTrack ();
+ if (_shiftSelecting && _selecting) {
+ StopSelecting ();
}
+ MoveLeft ();
+ return true;
+ }
- bool ProcessMoveLeft ()
- {
- // if the user presses Left (without any control keys) and they are at the start of the text
- if (_currentColumn == 0 && _currentRow == 0) {
- // do not respond (this lets the key press fall through to navigation system - which usually changes focus backward)
- return false;
- }
+ void ProcessMoveRightExtend ()
+ {
+ ResetAllTrack ();
+ StartSelecting ();
+ MoveRight ();
+ }
- ResetAllTrack ();
- if (_shiftSelecting && _selecting) {
- StopSelecting ();
- }
- MoveLeft ();
- return true;
- }
+ bool ProcessMoveRight ()
+ {
+ // if the user presses Right (without any control keys)
+ // determine where the last cursor position in the text is
+ int lastRow = _model.Count - 1;
+ int lastCol = _model.GetLine (lastRow).Count;
- void ProcessMoveRightExtend ()
- {
- ResetAllTrack ();
- StartSelecting ();
- MoveRight ();
+ // if they are at the very end of all the text do not respond (this lets the key press fall through to navigation system - which usually changes focus forward)
+ if (_currentColumn == lastCol && _currentRow == lastRow) {
+ return false;
}
- bool ProcessMoveRight ()
- {
- // if the user presses Right (without any control keys)
- // determine where the last cursor position in the text is
- var lastRow = _model.Count - 1;
- var lastCol = _model.GetLine (lastRow).Count;
+ ResetAllTrack ();
+ if (_shiftSelecting && _selecting) {
+ StopSelecting ();
+ }
+ MoveRight ();
+ return true;
+ }
- // if they are at the very end of all the text do not respond (this lets the key press fall through to navigation system - which usually changes focus forward)
- if (_currentColumn == lastCol && _currentRow == lastRow) {
- return false;
- }
+ void ProcessMoveUpExtend ()
+ {
+ ResetColumnTrack ();
+ StartSelecting ();
+ MoveUp ();
+ }
- ResetAllTrack ();
- if (_shiftSelecting && _selecting) {
- StopSelecting ();
- }
- MoveRight ();
- return true;
+ void ProcessMoveUp ()
+ {
+ ResetContinuousFindTrack ();
+ if (_shiftSelecting && _selecting) {
+ StopSelecting ();
}
+ MoveUp ();
+ }
- void ProcessMoveUpExtend ()
- {
- ResetColumnTrack ();
- StartSelecting ();
- MoveUp ();
- }
+ void ProcessMoveDownExtend ()
+ {
+ ResetColumnTrack ();
+ StartSelecting ();
+ MoveDown ();
+ }
- void ProcessMoveUp ()
- {
- ResetContinuousFindTrack ();
- if (_shiftSelecting && _selecting) {
- StopSelecting ();
- }
- MoveUp ();
+ void ProcessMoveDown ()
+ {
+ ResetContinuousFindTrack ();
+ if (_shiftSelecting && _selecting) {
+ StopSelecting ();
}
+ MoveDown ();
+ }
- void ProcessMoveDownExtend ()
- {
- ResetColumnTrack ();
- StartSelecting ();
- MoveDown ();
+ void ProcessPageUpExtend ()
+ {
+ ResetColumnTrack ();
+ StartSelecting ();
+ MovePageUp ();
+ }
+
+ void ProcessPageUp ()
+ {
+ ResetColumnTrack ();
+ if (_shiftSelecting && _selecting) {
+ StopSelecting ();
}
+ MovePageUp ();
+ }
- void ProcessMoveDown ()
- {
- ResetContinuousFindTrack ();
- if (_shiftSelecting && _selecting) {
- StopSelecting ();
- }
- MoveDown ();
+ void ProcessPageDownExtend ()
+ {
+ ResetColumnTrack ();
+ StartSelecting ();
+ MovePageDown ();
+ }
+
+ void ProcessPageDown ()
+ {
+ ResetColumnTrack ();
+ if (_shiftSelecting && _selecting) {
+ StopSelecting ();
}
+ MovePageDown ();
+ }
- void ProcessPageUpExtend ()
- {
- ResetColumnTrack ();
- StartSelecting ();
- MovePageUp ();
+ bool MovePreviousView ()
+ {
+ if (Application.OverlappedTop != null) {
+ return SuperView?.FocusPrev () == true;
}
- void ProcessPageUp ()
- {
- ResetColumnTrack ();
- if (_shiftSelecting && _selecting) {
- StopSelecting ();
- }
- MovePageUp ();
+ return false;
+ }
+
+ bool MoveNextView ()
+ {
+ if (Application.OverlappedTop != null) {
+ return SuperView?.FocusNext () == true;
}
- void ProcessPageDownExtend ()
- {
- ResetColumnTrack ();
- StartSelecting ();
- MovePageDown ();
+ return false;
+ }
+
+ bool ProcessBackTab ()
+ {
+ ResetColumnTrack ();
+
+ if (!AllowsTab || _isReadOnly) {
+ return ProcessMovePreviousView ();
}
+ if (_currentColumn > 0) {
+ SetWrapModel ();
- void ProcessPageDown ()
- {
- ResetColumnTrack ();
- if (_shiftSelecting && _selecting) {
- StopSelecting ();
+ var currentLine = GetCurrentLine ();
+ if (currentLine.Count > 0 && currentLine [_currentColumn - 1].Rune.Value == '\t') {
+
+ _historyText.Add (new List> () { new List (currentLine) }, CursorPosition);
+
+ currentLine.RemoveAt (_currentColumn - 1);
+ _currentColumn--;
+
+ _historyText.Add (new List> () { new List (GetCurrentLine ()) }, CursorPosition,
+ HistoryText.LineStatus.Replaced);
}
- MovePageDown ();
+
+ UpdateWrapModel ();
}
+ DoNeededAction ();
+ return true;
+ }
- bool MovePreviousView ()
- {
- if (Application.OverlappedTop != null) {
- return SuperView?.FocusPrev () == true;
- }
+ bool ProcessTab ()
+ {
+ ResetColumnTrack ();
- return false;
+ if (!AllowsTab || _isReadOnly) {
+ return ProcessMoveNextView ();
}
+ InsertText (new Key ((KeyCode)'\t'));
+ DoNeededAction ();
+ return true;
+ }
- bool MoveNextView ()
- {
- if (Application.OverlappedTop != null) {
- return SuperView?.FocusNext () == true;
- }
+ void SetOverwrite (bool overwrite)
+ {
+ Used = overwrite;
+ SetNeedsDisplay ();
+ DoNeededAction ();
+ }
+
+ bool ProcessReturn ()
+ {
+ ResetColumnTrack ();
+ if (!AllowsReturn || _isReadOnly) {
return false;
}
- bool ProcessBackTab ()
- {
- ResetColumnTrack ();
+ SetWrapModel ();
- if (!AllowsTab || _isReadOnly) {
- return ProcessMovePreviousView ();
- }
- if (_currentColumn > 0) {
- SetWrapModel ();
+ var currentLine = GetCurrentLine ();
- var currentLine = GetCurrentLine ();
- if (currentLine.Count > 0 && currentLine [_currentColumn - 1].Rune.Value == '\t') {
+ _historyText.Add (new List> () { new List (currentLine) }, CursorPosition);
- _historyText.Add (new List> () { new List (currentLine) }, CursorPosition);
+ if (_selecting) {
+ ClearSelectedRegion ();
+ currentLine = GetCurrentLine ();
+ }
+ int restCount = currentLine.Count - _currentColumn;
+ var rest = currentLine.GetRange (_currentColumn, restCount);
+ currentLine.RemoveRange (_currentColumn, restCount);
- currentLine.RemoveAt (_currentColumn - 1);
- _currentColumn--;
+ var addedLines = new List> () { new List (currentLine) };
- _historyText.Add (new List> () { new List (GetCurrentLine ()) }, CursorPosition,
- HistoryText.LineStatus.Replaced);
- }
+ _model.AddLine (_currentRow + 1, rest);
- UpdateWrapModel ();
- }
- DoNeededAction ();
- return true;
+ addedLines.Add (new List (_model.GetLine (_currentRow + 1)));
+
+ _historyText.Add (addedLines, CursorPosition, HistoryText.LineStatus.Added);
+
+ _currentRow++;
+
+ bool fullNeedsDisplay = false;
+ if (_currentRow >= _topRow + Frame.Height) {
+ _topRow++;
+ fullNeedsDisplay = true;
}
+ _currentColumn = 0;
- bool ProcessTab ()
- {
- ResetColumnTrack ();
+ _historyText.Add (new List> () { new List (GetCurrentLine ()) }, CursorPosition,
+ HistoryText.LineStatus.Replaced);
- if (!AllowsTab || _isReadOnly) {
- return ProcessMoveNextView ();
- }
- InsertText (new Key ((KeyCode)'\t'));
- DoNeededAction ();
- return true;
+ if (!_wordWrap && _currentColumn < _leftColumn) {
+ fullNeedsDisplay = true;
+ _leftColumn = 0;
}
- void SetOverwrite (bool overwrite)
- {
- Used = overwrite;
+ if (fullNeedsDisplay) {
+ SetNeedsDisplay ();
+ } else {
+ // BUGBUG: customized rect aren't supported now because the Redraw isn't using the Intersect method.
+ //SetNeedsDisplay (new Rect (0, currentRow - topRow, 2, Frame.Height));
SetNeedsDisplay ();
- DoNeededAction ();
}
- bool ProcessReturn ()
- {
- ResetColumnTrack ();
-
- if (!AllowsReturn || _isReadOnly) {
- return false;
- }
-
- SetWrapModel ();
+ UpdateWrapModel ();
- var currentLine = GetCurrentLine ();
+ DoNeededAction ();
+ OnContentsChanged ();
+ return true;
+ }
- _historyText.Add (new List> () { new List (currentLine) }, CursorPosition);
+ void KillWordBackward ()
+ {
+ if (_isReadOnly) {
+ return;
+ }
- if (_selecting) {
- ClearSelectedRegion ();
- currentLine = GetCurrentLine ();
- }
- var restCount = currentLine.Count - _currentColumn;
- var rest = currentLine.GetRange (_currentColumn, restCount);
- currentLine.RemoveRange (_currentColumn, restCount);
+ SetWrapModel ();
- var addedLines = new List> () { new List (currentLine) };
+ var currentLine = GetCurrentLine ();
- _model.AddLine (_currentRow + 1, rest);
+ _historyText.Add (new List> () { new List (GetCurrentLine ()) }, CursorPosition);
- addedLines.Add (new List (_model.GetLine (_currentRow + 1)));
+ if (_currentColumn == 0) {
+ DeleteTextBackwards ();
- _historyText.Add (addedLines, CursorPosition, HistoryText.LineStatus.Added);
+ _historyText.ReplaceLast (new List> () { new List (GetCurrentLine ()) }, CursorPosition,
+ HistoryText.LineStatus.Replaced);
- _currentRow++;
+ UpdateWrapModel ();
- bool fullNeedsDisplay = false;
- if (_currentRow >= _topRow + Frame.Height) {
- _topRow++;
- fullNeedsDisplay = true;
+ return;
+ }
+ var newPos = _model.WordBackward (_currentColumn, _currentRow);
+ if (newPos.HasValue && _currentRow == newPos.Value.row) {
+ int restCount = _currentColumn - newPos.Value.col;
+ currentLine.RemoveRange (newPos.Value.col, restCount);
+ if (_wordWrap) {
+ _wrapNeeded = true;
}
- _currentColumn = 0;
-
- _historyText.Add (new List> () { new List (GetCurrentLine ()) }, CursorPosition,
- HistoryText.LineStatus.Replaced);
-
- if (!_wordWrap && _currentColumn < _leftColumn) {
- fullNeedsDisplay = true;
- _leftColumn = 0;
- }
-
- if (fullNeedsDisplay) {
- SetNeedsDisplay ();
- } else {
- // BUGBUG: customized rect aren't supported now because the Redraw isn't using the Intersect method.
- //SetNeedsDisplay (new Rect (0, currentRow - topRow, 2, Frame.Height));
- SetNeedsDisplay ();
+ _currentColumn = newPos.Value.col;
+ } else if (newPos.HasValue) {
+ int restCount = currentLine.Count - _currentColumn;
+ currentLine.RemoveRange (_currentColumn, restCount);
+ if (_wordWrap) {
+ _wrapNeeded = true;
}
-
- UpdateWrapModel ();
-
- DoNeededAction ();
- OnContentsChanged ();
- return true;
+ _currentColumn = newPos.Value.col;
+ _currentRow = newPos.Value.row;
}
- void KillWordBackward ()
- {
- if (_isReadOnly)
- return;
+ _historyText.Add (new List> () { new List (GetCurrentLine ()) }, CursorPosition,
+ HistoryText.LineStatus.Replaced);
- SetWrapModel ();
+ UpdateWrapModel ();
- var currentLine = GetCurrentLine ();
+ DoSetNeedsDisplay (new Rect (0, _currentRow - _topRow, Frame.Width, Frame.Height));
+ DoNeededAction ();
+ }
- _historyText.Add (new List> () { new List (GetCurrentLine ()) }, CursorPosition);
+ void KillWordForward ()
+ {
+ if (_isReadOnly) {
+ return;
+ }
- if (_currentColumn == 0) {
- DeleteTextBackwards ();
+ SetWrapModel ();
- _historyText.ReplaceLast (new List> () { new List (GetCurrentLine ()) }, CursorPosition,
- HistoryText.LineStatus.Replaced);
+ var currentLine = GetCurrentLine ();
- UpdateWrapModel ();
+ _historyText.Add (new List> () { new List (GetCurrentLine ()) }, CursorPosition);
- return;
- }
- var newPos = _model.WordBackward (_currentColumn, _currentRow);
- if (newPos.HasValue && _currentRow == newPos.Value.row) {
- var restCount = _currentColumn - newPos.Value.col;
- currentLine.RemoveRange (newPos.Value.col, restCount);
- if (_wordWrap) {
- _wrapNeeded = true;
- }
- _currentColumn = newPos.Value.col;
- } else if (newPos.HasValue) {
- var restCount = currentLine.Count - _currentColumn;
- currentLine.RemoveRange (_currentColumn, restCount);
- if (_wordWrap) {
- _wrapNeeded = true;
- }
- _currentColumn = newPos.Value.col;
- _currentRow = newPos.Value.row;
- }
+ if (currentLine.Count == 0 || _currentColumn == currentLine.Count) {
+ DeleteTextForwards ();
- _historyText.Add (new List> () { new List (GetCurrentLine ()) }, CursorPosition,
- HistoryText.LineStatus.Replaced);
+ _historyText.ReplaceLast (new List> () { new List (GetCurrentLine ()) }, CursorPosition,
+ HistoryText.LineStatus.Replaced);
UpdateWrapModel ();
- DoSetNeedsDisplay (new Rect (0, _currentRow - _topRow, Frame.Width, Frame.Height));
- DoNeededAction ();
+ return;
+ }
+ var newPos = _model.WordForward (_currentColumn, _currentRow);
+ int restCount = 0;
+ if (newPos.HasValue && _currentRow == newPos.Value.row) {
+ restCount = newPos.Value.col - _currentColumn;
+ currentLine.RemoveRange (_currentColumn, restCount);
+ } else if (newPos.HasValue) {
+ restCount = currentLine.Count - _currentColumn;
+ currentLine.RemoveRange (_currentColumn, restCount);
+ }
+ if (_wordWrap) {
+ _wrapNeeded = true;
}
- void KillWordForward ()
- {
- if (_isReadOnly)
- return;
-
- SetWrapModel ();
-
- var currentLine = GetCurrentLine ();
-
- _historyText.Add (new List> () { new List (GetCurrentLine ()) }, CursorPosition);
-
- if (currentLine.Count == 0 || _currentColumn == currentLine.Count) {
- DeleteTextForwards ();
-
- _historyText.ReplaceLast (new List> () { new List (GetCurrentLine ()) }, CursorPosition,
- HistoryText.LineStatus.Replaced);
-
- UpdateWrapModel ();
-
- return;
- }
- var newPos = _model.WordForward (_currentColumn, _currentRow);
- var restCount = 0;
- if (newPos.HasValue && _currentRow == newPos.Value.row) {
- restCount = newPos.Value.col - _currentColumn;
- currentLine.RemoveRange (_currentColumn, restCount);
- } else if (newPos.HasValue) {
- restCount = currentLine.Count - _currentColumn;
- currentLine.RemoveRange (_currentColumn, restCount);
- }
- if (_wordWrap) {
- _wrapNeeded = true;
- }
+ _historyText.Add (new List> () { new List (GetCurrentLine ()) }, CursorPosition,
+ HistoryText.LineStatus.Replaced);
- _historyText.Add (new List> () { new List (GetCurrentLine ()) }, CursorPosition,
- HistoryText.LineStatus.Replaced);
+ UpdateWrapModel ();
- UpdateWrapModel ();
+ DoSetNeedsDisplay (new Rect (0, _currentRow - _topRow, Frame.Width, Frame.Height));
+ DoNeededAction ();
+ }
- DoSetNeedsDisplay (new Rect (0, _currentRow - _topRow, Frame.Width, Frame.Height));
- DoNeededAction ();
+ void MoveWordForward ()
+ {
+ var newPos = _model.WordForward (_currentColumn, _currentRow);
+ if (newPos.HasValue) {
+ _currentColumn = newPos.Value.col;
+ _currentRow = newPos.Value.row;
}
+ Adjust ();
+ DoNeededAction ();
+ }
- void MoveWordForward ()
- {
- var newPos = _model.WordForward (_currentColumn, _currentRow);
- if (newPos.HasValue) {
- _currentColumn = newPos.Value.col;
- _currentRow = newPos.Value.row;
- }
- Adjust ();
- DoNeededAction ();
+ void MoveWordBackward ()
+ {
+ var newPos = _model.WordBackward (_currentColumn, _currentRow);
+ if (newPos.HasValue) {
+ _currentColumn = newPos.Value.col;
+ _currentRow = newPos.Value.row;
}
+ Adjust ();
+ DoNeededAction ();
+ }
- void MoveWordBackward ()
- {
- var newPos = _model.WordBackward (_currentColumn, _currentRow);
- if (newPos.HasValue) {
- _currentColumn = newPos.Value.col;
- _currentRow = newPos.Value.row;
- }
- Adjust ();
- DoNeededAction ();
+ void KillToStartOfLine ()
+ {
+ if (_isReadOnly) {
+ return;
+ }
+ if (_model.Count == 1 && GetCurrentLine ().Count == 0) {
+ // Prevents from adding line feeds if there is no more lines.
+ return;
}
- void KillToStartOfLine ()
- {
- if (_isReadOnly)
- return;
- if (_model.Count == 1 && GetCurrentLine ().Count == 0) {
- // Prevents from adding line feeds if there is no more lines.
- return;
- }
-
- SetWrapModel ();
+ SetWrapModel ();
- var currentLine = GetCurrentLine ();
- var setLastWasKill = true;
- if (currentLine.Count > 0 && _currentColumn == 0) {
- UpdateWrapModel ();
+ var currentLine = GetCurrentLine ();
+ bool setLastWasKill = true;
+ if (currentLine.Count > 0 && _currentColumn == 0) {
+ UpdateWrapModel ();
- DeleteTextBackwards ();
- return;
- }
+ DeleteTextBackwards ();
+ return;
+ }
- _historyText.Add (new List> () { new List (currentLine) }, CursorPosition);
+ _historyText.Add (new List> () { new List (currentLine) }, CursorPosition);
- if (currentLine.Count == 0) {
- if (_currentRow > 0) {
- _model.RemoveLine (_currentRow);
+ if (currentLine.Count == 0) {
+ if (_currentRow > 0) {
+ _model.RemoveLine (_currentRow);
- if (_model.Count > 0 || _lastWasKill) {
- var val = Environment.NewLine;
- if (_lastWasKill) {
- AppendClipboard (val);
- } else {
- SetClipboard (val);
- }
- }
- if (_model.Count == 0) {
- // Prevents from adding line feeds if there is no more lines.
- setLastWasKill = false;
+ if (_model.Count > 0 || _lastWasKill) {
+ string val = Environment.NewLine;
+ if (_lastWasKill) {
+ AppendClipboard (val);
+ } else {
+ SetClipboard (val);
}
+ }
+ if (_model.Count == 0) {
+ // Prevents from adding line feeds if there is no more lines.
+ setLastWasKill = false;
+ }
- _currentRow--;
- currentLine = _model.GetLine (_currentRow);
+ _currentRow--;
+ currentLine = _model.GetLine (_currentRow);
- var removedLine = new List> () { new List (currentLine) };
+ var removedLine = new List> () { new List (currentLine) };
- removedLine.Add (new List ());
+ removedLine.Add (new List ());
- _historyText.Add (new List> (removedLine), CursorPosition, HistoryText.LineStatus.Removed);
+ _historyText.Add (new List> (removedLine), CursorPosition, HistoryText.LineStatus.Removed);
- _currentColumn = currentLine.Count;
- }
+ _currentColumn = currentLine.Count;
+ }
+ } else {
+ int restCount = _currentColumn;
+ var rest = currentLine.GetRange (0, restCount);
+ string val = string.Empty;
+ val += StringFromRunes (rest);
+ if (_lastWasKill) {
+ AppendClipboard (val);
} else {
- var restCount = _currentColumn;
- var rest = currentLine.GetRange (0, restCount);
- var val = string.Empty;
- val += StringFromRunes (rest);
- if (_lastWasKill) {
- AppendClipboard (val);
- } else {
- SetClipboard (val);
- }
- currentLine.RemoveRange (0, restCount);
- _currentColumn = 0;
+ SetClipboard (val);
}
+ currentLine.RemoveRange (0, restCount);
+ _currentColumn = 0;
+ }
- _historyText.Add (new List> () { new List (GetCurrentLine ()) }, CursorPosition,
- HistoryText.LineStatus.Replaced);
+ _historyText.Add (new List> () { new List (GetCurrentLine ()) }, CursorPosition,
+ HistoryText.LineStatus.Replaced);
- UpdateWrapModel ();
+ UpdateWrapModel ();
- DoSetNeedsDisplay (new Rect (0, _currentRow - _topRow, Frame.Width, Frame.Height));
+ DoSetNeedsDisplay (new Rect (0, _currentRow - _topRow, Frame.Width, Frame.Height));
- _lastWasKill = setLastWasKill;
- DoNeededAction ();
- }
+ _lastWasKill = setLastWasKill;
+ DoNeededAction ();
+ }
- void KillToEndOfLine ()
- {
- if (_isReadOnly)
- return;
- if (_model.Count == 1 && GetCurrentLine ().Count == 0) {
- // Prevents from adding line feeds if there is no more lines.
- return;
- }
+ void KillToEndOfLine ()
+ {
+ if (_isReadOnly) {
+ return;
+ }
+ if (_model.Count == 1 && GetCurrentLine ().Count == 0) {
+ // Prevents from adding line feeds if there is no more lines.
+ return;
+ }
- SetWrapModel ();
+ SetWrapModel ();
- var currentLine = GetCurrentLine ();
- var setLastWasKill = true;
- if (currentLine.Count > 0 && _currentColumn == currentLine.Count) {
- UpdateWrapModel ();
+ var currentLine = GetCurrentLine ();
+ bool setLastWasKill = true;
+ if (currentLine.Count > 0 && _currentColumn == currentLine.Count) {
+ UpdateWrapModel ();
- DeleteTextForwards ();
- return;
- }
+ DeleteTextForwards ();
+ return;
+ }
- _historyText.Add (new List> () { new List