From 6b27bbf76d8ece3886a8644c85f896d6f112f580 Mon Sep 17 00:00:00 2001 From: prifio Date: Sat, 9 Jun 2018 11:31:19 +0300 Subject: [PATCH 1/5] Add FullColor class Add FullColor class. Add GetCode(color) and GetColor(code) methods. Add FullAttribute --- Terminal.Gui/Drivers/ConsoleDriver.cs | 97 ++++++++++++++++++++++++++- 1 file changed, 95 insertions(+), 2 deletions(-) diff --git a/Terminal.Gui/Drivers/ConsoleDriver.cs b/Terminal.Gui/Drivers/ConsoleDriver.cs index c7c36f2abe..180c74b3b9 100644 --- a/Terminal.Gui/Drivers/ConsoleDriver.cs +++ b/Terminal.Gui/Drivers/ConsoleDriver.cs @@ -82,7 +82,82 @@ public enum Color { /// White } - + + /// + /// 24bit color. Support translate it to 4bit(Windows) and 8bit(Linux) color + /// + public class FullColor { + public int R { get; private set; } + public int G { get; private set; } + public int B { get; private set; } + public FullColor(int r, int g, int b) { + R = r; + G = g; + B = b; + } + + public static FullColor LinuxColor(int code) { + if (code == 7) + code = 8; + else if (code == 8) + code = 7; + if (code == 8) + return new FullColor(192, 192, 192); + if (code <= 15) { + int k = 128; + if (code >= 9) + k = 255; + return new FullColor(code % 2 * k, code / 2 % 2 * k, code / 4 % 2 * k); + } + if (code <= 231) { + code -= 16; + int b = code % 6 * 40; + if (b > 0) + b += 45; + int g = code / 6 % 6 * 40; + if (g > 0) + g += 45; + int r = code / 36 % 6 * 40; + if (r > 0) + r += 45; + return new FullColor(r, g, b); + } + { + code -= 231; + return new FullColor(8 + code * 10, 8 + code * 10, 8 + code * 10); + } + } + public static FullColor WindowsColor(int code) { + if (code == 7) + code = 8; + else if (code == 8) + code = 7; + if (code == 8) + return new FullColor(192, 192, 192); + int k = 128; + if (code >= 9) + k = 255; + return new FullColor(code / 4 % 2 * k, code / 2 % 2 * k, code % 2 * k); + } + public static int Dist(FullColor c1, FullColor c2) { + return (c1.R - c2.R) * (c1.R - c2.R) + (c1.G - c2.G) * (c1.G - c2.G) + (c1.B - c2.B) * (c1.B - c2.B); + } + public static int GetLinuxCode(FullColor c) { + int ans = 0; + for (int i = 1; i < 255; i++) + if (Dist(LinuxColor(i), c) < Dist(LinuxColor(ans), c)) + ans = i; + return ans; + } + public static int GetWindowsCode(FullColor c) { + int ans = 0; + for (int i = 1; i < 16; i++) + if (Dist(WindowsColor(i), c) < Dist(WindowsColor(ans), c)) + ans = i; + return ans; + } + } + /// /// Attributes are used as elements that contain both a foreground and a background or platform specific features /// @@ -91,7 +166,7 @@ public enum Color { /// scenarios, they encode both the foreground and the background color and are used in the ColorScheme /// class to define color schemes that can be used in your application. /// - public struct Attribute { + public class Attribute { internal int value; /// @@ -103,10 +178,28 @@ public Attribute (int value) this.value = value; } + public Attribute() { } + public static implicit operator int (Attribute c) => c.value; public static implicit operator Attribute (int v) => new Attribute (v); } + /// + /// Like attribute, but support 24bit color + /// + public class FullAttribute : Attribute { + public FullColor For { get; private set; } + public FullColor Back { get; private set; } + public int LinuxCode { get; private set; } + + public FullAttribute (FullColor For, FullColor Back) { + this.For = For; + this.Back = Back; + value = FullColor.GetWindowsCode(For) + FullColor.GetLinuxCode(Back) * 16; + LinuxCode = FullColor.GetLinuxCode(For) + FullColor.GetLinuxCode(Back) * 256; + } + } + /// /// Color scheme definitions, they cover some common scenarios and are used /// typically in toplevel containers to set the scheme that is used by all the From efa46201f53053336a968477ccbf047048aed523 Mon Sep 17 00:00:00 2001 From: prifio Date: Sat, 9 Jun 2018 15:26:00 +0300 Subject: [PATCH 2/5] Add Support24bit color Add WriteConsole form kernel32. Add FullWriteConsole. Change OutputBuffer in WindowsDriver. Change WriteToConsole (work in 4bit and 24bit situatoin) SetSupportFullColor DON'T IMPLEMENT --- Terminal.Gui/Drivers/ConsoleDriver.cs | 5 ++ Terminal.Gui/Drivers/WindowsDriver.cs | 94 +++++++++++++++++++++++---- 2 files changed, 87 insertions(+), 12 deletions(-) diff --git a/Terminal.Gui/Drivers/ConsoleDriver.cs b/Terminal.Gui/Drivers/ConsoleDriver.cs index 180c74b3b9..648d0149e0 100644 --- a/Terminal.Gui/Drivers/ConsoleDriver.cs +++ b/Terminal.Gui/Drivers/ConsoleDriver.cs @@ -156,6 +156,11 @@ public static int GetWindowsCode(FullColor c) { ans = i; return ans; } + public static int WinToLinux(int code) { + if (code == 0 || code == 7 || code == 8 || code == 15) + return code; + return (code & 8) + (code & 2) + 4 * (code & 1) + (code & 4) / 4; + } } /// diff --git a/Terminal.Gui/Drivers/WindowsDriver.cs b/Terminal.Gui/Drivers/WindowsDriver.cs index ca1b107fb1..1f4a7b4729 100644 --- a/Terminal.Gui/Drivers/WindowsDriver.cs +++ b/Terminal.Gui/Drivers/WindowsDriver.cs @@ -31,6 +31,8 @@ using System.Threading.Tasks; using Mono.Terminal; using NStack; +using Microsoft.Win32; +using System.Text; namespace Terminal.Gui { @@ -38,11 +40,19 @@ internal class WindowsConsole { public const int STD_OUTPUT_HANDLE = -11; public const int STD_INPUT_HANDLE = -10; public const int STD_ERROR_HANDLE = -12; - + internal IntPtr InputHandle, OutputHandle; IntPtr ScreenBuffer; uint originalConsoleMode; + public bool SupportFullColor { get; private set; } + + void SetSupportFullColor() { + SupportFullColor = true; + //string CurrentBuild = Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion", "CurrentBuild", "").ToString(); + //SupportFullColor = CurrentBuild != "" && int.Parse(CurrentBuild) >= 14931; + } + public WindowsConsole () { InputHandle = GetStdHandle (STD_INPUT_HANDLE); @@ -52,11 +62,14 @@ public WindowsConsole () newConsoleMode |= (uint)(ConsoleModes.EnableMouseInput | ConsoleModes.EnableExtendedFlags); newConsoleMode &= ~(uint)ConsoleModes.EnableQuickEditMode; ConsoleMode = newConsoleMode; + var ocm = OutputConsoleMode; + OutputConsoleMode = ocm | 7; + SetSupportFullColor(); } public CharInfo [] OriginalStdOutChars; - public bool WriteToConsole (CharInfo [] charInfoBuffer, Coord coords, SmallRect window) + public bool WriteToConsole (FullCharInfo [] charInfoBuffer, Coord coords, SmallRect window) { if (ScreenBuffer == IntPtr.Zero) { ScreenBuffer = CreateConsoleScreenBuffer ( @@ -82,10 +95,41 @@ public bool WriteToConsole (CharInfo [] charInfoBuffer, Coord coords, SmallRect ReadConsoleOutput (OutputHandle, OriginalStdOutChars, coords, new Coord () { X = 0, Y = 0 }, ref window); } - - return WriteConsoleOutput (ScreenBuffer, charInfoBuffer, coords, new Coord () { X = window.Left, Y = window.Top }, ref window); - } - + if (!SupportFullColor) { + CharInfo[] ci = new CharInfo[charInfoBuffer.Length]; + for (int i = 0; i < ci.Length; i++) { + ci[i].Char.UnicodeChar = charInfoBuffer[i].Char; + ci[i].Attributes = (ushort)(charInfoBuffer[i].Attributes); + } + return WriteConsoleOutput(ScreenBuffer, ci, coords, new Coord() { X = window.Left, Y = window.Top }, ref window); + } + return FullWriteConsole (charInfoBuffer); + } + + public bool FullWriteConsole(FullCharInfo[] Buffer) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < Buffer.Length; i++) { + if (Buffer[i].Attributes is FullAttribute) { + var a = (FullAttribute)(Buffer[i].Attributes); + sb.AppendFormat("\x1b[38;2;{0};{1};{2};48;2;{3};{4};{5}m", a.For.R, a.For.G, a.For.B, + a.Back.R, a.Back.G, a.Back.B); + } + else { + int a = (int)(Buffer[i].Attributes); + sb.AppendFormat("\x1b[38;5;{0};48;5;{1}m", FullColor.WinToLinux(a % 16), FullColor.WinToLinux(a / 16)); + } + if (Buffer[i].Char != '\x1b') + sb.Append(Buffer[i].Char); + else + sb.Append(' '); + } + SetCursorPosition(new Coord { X = 0, Y = 0 }); + uint trash; + string s = sb.ToString(); + WriteConsole(ScreenBuffer, s, (uint)(s.Length), out trash, null); + return true; + } + public bool SetCursorPosition (Coord position) { return SetConsoleCursorPosition (ScreenBuffer, position); @@ -115,6 +159,17 @@ public uint ConsoleMode { } } + public uint OutputConsoleMode { + get { + uint v; + GetConsoleMode(OutputHandle, out v); + return v; + } + set { + SetConsoleMode(OutputHandle, value); + } + } + [Flags] public enum ConsoleModes : uint { EnableMouseInput = 16, @@ -348,6 +403,15 @@ public override string ToString () } } + [DllImport("kernel32.dll", EntryPoint = "WriteConsole", SetLastError = true, CharSet = CharSet.Unicode)] + static extern bool WriteConsole( + IntPtr hConsoleOutput, + String lpbufer, + UInt32 NumberOfCharsToWriten, + out UInt32 lpNumberOfCharsWritten, + object lpReserved); + + [DllImport ("kernel32.dll", SetLastError = true)] static extern IntPtr GetStdHandle (int nStdHandle); @@ -412,20 +476,25 @@ public uint InputEventCount { } } + struct FullCharInfo { + public char Char { get; set; } + public Attribute Attributes { get; set; } + } + internal class WindowsDriver : ConsoleDriver, Mono.Terminal.IMainLoopDriver { static bool sync; AutoResetEvent eventReady = new AutoResetEvent (false); AutoResetEvent waitForProbe = new AutoResetEvent (false); MainLoop mainLoop; Action TerminalResized; - WindowsConsole.CharInfo [] OutputBuffer; + FullCharInfo [] OutputBuffer; int cols, rows; WindowsConsole winConsole; WindowsConsole.SmallRect damageRegion; public override int Cols => cols; public override int Rows => rows; - + public WindowsDriver () { winConsole = new WindowsConsole (); @@ -436,7 +505,8 @@ public WindowsDriver () ResizeScreen (); UpdateOffScreen (); - + winConsole.ConsoleMode = winConsole.ConsoleMode; + Task.Run ((Action)WindowsInputHandler); } @@ -721,7 +791,7 @@ public override void Init (Action terminalResized) void ResizeScreen () { - OutputBuffer = new WindowsConsole.CharInfo [Rows * Cols]; + OutputBuffer = new FullCharInfo [Rows * Cols]; Clip = new Rect (0, 0, Cols, Rows); damageRegion = new WindowsConsole.SmallRect () { Top = 0, @@ -737,7 +807,7 @@ void UpdateOffScreen () for (int col = 0; col < cols; col++) { int position = row * cols + col; OutputBuffer [position].Attributes = (ushort)MakeColor (ConsoleColor.White, ConsoleColor.Blue); - OutputBuffer [position].Char.UnicodeChar = ' '; + OutputBuffer [position].Char = ' '; } } @@ -754,7 +824,7 @@ public override void AddRune (Rune rune) if (Clip.Contains (ccol, crow)) { OutputBuffer [position].Attributes = (ushort)currentAttribute; - OutputBuffer [position].Char.UnicodeChar = (char)rune; + OutputBuffer [position].Char = (char)rune; WindowsConsole.SmallRect.Update (ref damageRegion, (short)ccol, (short)crow); } From 8d97f9792ecbecd323e1a8dd0ce7b82d1fd94e8e Mon Sep 17 00:00:00 2001 From: prifio Date: Sat, 9 Jun 2018 15:45:01 +0300 Subject: [PATCH 3/5] Chane example Add FullColor element to example. Fix setAttribute --- Example/demo.cs | 3 +++ Terminal.Gui/Drivers/WindowsDriver.cs | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Example/demo.cs b/Example/demo.cs index d1d562a6ec..86a194bb69 100644 --- a/Example/demo.cs +++ b/Example/demo.cs @@ -6,6 +6,9 @@ static class Demo { class Box10x : View { public Box10x (int x, int y) : base (new Rect (x, y, 10, 10)) { + ColorScheme = new ColorScheme(); + ColorScheme.Focus = new FullAttribute(new FullColor(0, 0, 0), + new FullColor(255, 177, 177)); } public override void Redraw (Rect region) diff --git a/Terminal.Gui/Drivers/WindowsDriver.cs b/Terminal.Gui/Drivers/WindowsDriver.cs index 1f4a7b4729..6bbccf6e2e 100644 --- a/Terminal.Gui/Drivers/WindowsDriver.cs +++ b/Terminal.Gui/Drivers/WindowsDriver.cs @@ -823,7 +823,7 @@ public override void AddRune (Rune rune) var position = crow * Cols + ccol; if (Clip.Contains (ccol, crow)) { - OutputBuffer [position].Attributes = (ushort)currentAttribute; + OutputBuffer [position].Attributes = currentAttribute; OutputBuffer [position].Char = (char)rune; WindowsConsole.SmallRect.Update (ref damageRegion, (short)ccol, (short)crow); } @@ -844,10 +844,10 @@ public override void AddStr (ustring str) AddRune (rune); } - int currentAttribute; + Attribute currentAttribute; public override void SetAttribute (Attribute c) { - currentAttribute = c.value; + currentAttribute = c; } private Attribute MakeColor (ConsoleColor f, ConsoleColor b) From d5eb021f34b7666086a47313669cdb9f41d25085 Mon Sep 17 00:00:00 2001 From: prifio Date: Fri, 15 Jun 2018 12:53:38 +0300 Subject: [PATCH 4/5] Polishing TrueColor Change FullColor to TrueColor. Change Windwos and Linux code to code4 and code8. Expand Attribute, remove FullAtribute. Back to struct Attibute. Add ConsoleModes (remove "| 7"). Fix cursor position after WriteConsole. Implement SetSupportTrueColor. Fix small tab --- Example/demo.cs | 6 +- Terminal.Gui/Drivers/ConsoleDriver.cs | 205 ++++++++++++++------------ Terminal.Gui/Drivers/WindowsDriver.cs | 120 ++++++++------- 3 files changed, 181 insertions(+), 150 deletions(-) diff --git a/Example/demo.cs b/Example/demo.cs index 86a194bb69..5254fb5bca 100644 --- a/Example/demo.cs +++ b/Example/demo.cs @@ -6,9 +6,9 @@ static class Demo { class Box10x : View { public Box10x (int x, int y) : base (new Rect (x, y, 10, 10)) { - ColorScheme = new ColorScheme(); - ColorScheme.Focus = new FullAttribute(new FullColor(0, 0, 0), - new FullColor(255, 177, 177)); + ColorScheme = new ColorScheme(); + ColorScheme.Focus = new Terminal.Gui.Attribute(new TrueColor(0, 0, 0), + new TrueColor(255, 177, 177)); } public override void Redraw (Rect region) diff --git a/Terminal.Gui/Drivers/ConsoleDriver.cs b/Terminal.Gui/Drivers/ConsoleDriver.cs index 648d0149e0..483fd00e9b 100644 --- a/Terminal.Gui/Drivers/ConsoleDriver.cs +++ b/Terminal.Gui/Drivers/ConsoleDriver.cs @@ -10,6 +10,7 @@ using Mono.Terminal; using NStack; using Unix.Terminal; +using System.Drawing; namespace Terminal.Gui { @@ -86,83 +87,101 @@ public enum Color { /// /// 24bit color. Support translate it to 4bit(Windows) and 8bit(Linux) color /// - public class FullColor { - public int R { get; private set; } - public int G { get; private set; } - public int B { get; private set; } - public FullColor(int r, int g, int b) { - R = r; - G = g; - B = b; - } - - public static FullColor LinuxColor(int code) { - if (code == 7) - code = 8; - else if (code == 8) - code = 7; - if (code == 8) - return new FullColor(192, 192, 192); - if (code <= 15) { - int k = 128; - if (code >= 9) - k = 255; - return new FullColor(code % 2 * k, code / 2 % 2 * k, code / 4 % 2 * k); + public class TrueColor { + public int R { get; private set; } + public int G { get; private set; } + public int B { get; private set; } + public TrueColor(int r, int g, int b) { + R = r; + G = g; + B = b; } - if (code <= 231) { - code -= 16; - int b = code % 6 * 40; - if (b > 0) - b += 45; - int g = code / 6 % 6 * 40; - if (g > 0) - g += 45; - int r = code / 36 % 6 * 40; - if (r > 0) - r += 45; - return new FullColor(r, g, b); + /// + /// Get color by code in 256 colors palette + /// + public static TrueColor Color8(int code) { + if (code == 7) + code = 8; + else if (code == 8) + code = 7; + if (code == 8) + return new TrueColor(192, 192, 192); + if (code <= 15) { + int k = 128; + if (code >= 9) + k = 255; + return new TrueColor(code % 2 * k, code / 2 % 2 * k, code / 4 % 2 * k); + } + if (code <= 231) { + code -= 16; + int b = code % 6 * 40; + if (b > 0) + b += 45; + int g = code / 6 % 6 * 40; + if (g > 0) + g += 45; + int r = code / 36 % 6 * 40; + if (r > 0) + r += 45; + return new TrueColor(r, g, b); + } + { + code -= 231; + return new TrueColor(8 + code * 10, 8 + code * 10, 8 + code * 10); + } } - { - code -= 231; - return new FullColor(8 + code * 10, 8 + code * 10, 8 + code * 10); + /// + /// Get color by 16 colors palette + /// + public static TrueColor Color4(int code) { + if (code == 7) + code = 8; + else if (code == 8) + code = 7; + if (code == 8) + return new TrueColor(192, 192, 192); + int k = 128; + if (code >= 9) + k = 255; + return new TrueColor(code / 4 % 2 * k, code / 2 % 2 * k, code % 2 * k); + } + /// + /// Return color diff + /// + public static int Diff(TrueColor c1, TrueColor c2) { + //TODO: upgrade to CIEDE2000 + return (c1.R - c2.R) * (c1.R - c2.R) + (c1.G - c2.G) * (c1.G - c2.G) + (c1.B - c2.B) * (c1.B - c2.B); + } + /// + /// Get color code in 256 colors palette (use approximation) + /// + public static int GetCode8(TrueColor c) { + int ans = 0; + for (int i = 1; i < 255; i++) + if (Diff(Color8(i), c) < Diff(Color8(ans), c)) + ans = i; + return ans; + } + /// + /// Get color code in 16 colors palette (use approximation) + /// + public static int GetCode4(TrueColor c) { + int ans = 0; + for (int i = 1; i < 16; i++) + if (Diff(Color4(i), c) < Diff(Color4(ans), c)) + ans = i; + return ans; + } + /// + /// Convert code in 16 colors palette to 256 colors palette + /// + public static int Code4ToCode8(int code) { + if (code == 0 || code == 7 || code == 8 || code == 15) + return code; + return (code & 8) + (code & 2) + 4 * (code & 1) + (code & 4) / 4; } - } - public static FullColor WindowsColor(int code) { - if (code == 7) - code = 8; - else if (code == 8) - code = 7; - if (code == 8) - return new FullColor(192, 192, 192); - int k = 128; - if (code >= 9) - k = 255; - return new FullColor(code / 4 % 2 * k, code / 2 % 2 * k, code % 2 * k); - } - public static int Dist(FullColor c1, FullColor c2) { - return (c1.R - c2.R) * (c1.R - c2.R) + (c1.G - c2.G) * (c1.G - c2.G) + (c1.B - c2.B) * (c1.B - c2.B); - } - public static int GetLinuxCode(FullColor c) { - int ans = 0; - for (int i = 1; i < 255; i++) - if (Dist(LinuxColor(i), c) < Dist(LinuxColor(ans), c)) - ans = i; - return ans; - } - public static int GetWindowsCode(FullColor c) { - int ans = 0; - for (int i = 1; i < 16; i++) - if (Dist(WindowsColor(i), c) < Dist(WindowsColor(ans), c)) - ans = i; - return ans; - } - public static int WinToLinux(int code) { - if (code == 0 || code == 7 || code == 8 || code == 15) - return code; - return (code & 8) + (code & 2) + 4 * (code & 1) + (code & 4) / 4; - } } - + /// /// Attributes are used as elements that contain both a foreground and a background or platform specific features /// @@ -171,9 +190,16 @@ public static int WinToLinux(int code) { /// scenarios, they encode both the foreground and the background color and are used in the ColorScheme /// class to define color schemes that can be used in your application. /// - public class Attribute { + public struct Attribute { internal int value; - + /// + /// Forground color + /// + public TrueColor Fg { get; private set; } + /// + /// Backgorund color + /// + public TrueColor Bg { get; private set; } /// /// Initializes a new instance of the struct. /// @@ -181,30 +207,25 @@ public class Attribute { public Attribute (int value) { this.value = value; + Fg = Bg = null; } - public Attribute() { } + /// + /// Build Attribute by two TrueColor + /// + /// Forground color + /// Background color + public Attribute(TrueColor fg, TrueColor bg) + { + value = TrueColor.GetCode4(fg) + TrueColor.GetCode4(bg) * 16; + Fg = fg; + Bg = bg; + } public static implicit operator int (Attribute c) => c.value; public static implicit operator Attribute (int v) => new Attribute (v); } - /// - /// Like attribute, but support 24bit color - /// - public class FullAttribute : Attribute { - public FullColor For { get; private set; } - public FullColor Back { get; private set; } - public int LinuxCode { get; private set; } - - public FullAttribute (FullColor For, FullColor Back) { - this.For = For; - this.Back = Back; - value = FullColor.GetWindowsCode(For) + FullColor.GetLinuxCode(Back) * 16; - LinuxCode = FullColor.GetLinuxCode(For) + FullColor.GetLinuxCode(Back) * 256; - } - } - /// /// Color scheme definitions, they cover some common scenarios and are used /// typically in toplevel containers to set the scheme that is used by all the diff --git a/Terminal.Gui/Drivers/WindowsDriver.cs b/Terminal.Gui/Drivers/WindowsDriver.cs index 6bbccf6e2e..2ddb030f2f 100644 --- a/Terminal.Gui/Drivers/WindowsDriver.cs +++ b/Terminal.Gui/Drivers/WindowsDriver.cs @@ -45,12 +45,14 @@ internal class WindowsConsole { IntPtr ScreenBuffer; uint originalConsoleMode; - public bool SupportFullColor { get; private set; } + public bool SupportTrueColor { get; private set; } - void SetSupportFullColor() { - SupportFullColor = true; - //string CurrentBuild = Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion", "CurrentBuild", "").ToString(); - //SupportFullColor = CurrentBuild != "" && int.Parse(CurrentBuild) >= 14931; + void SetSupportTrueColor() { + //work only for CMD + //TODO add supprot windows terminals + string ver = RuntimeInformation.OSDescription; + int num = int.Parse(ver.Substring(ver.LastIndexOf('.') + 1)); + SupportTrueColor = num >= 14931; } public WindowsConsole () @@ -62,9 +64,12 @@ public WindowsConsole () newConsoleMode |= (uint)(ConsoleModes.EnableMouseInput | ConsoleModes.EnableExtendedFlags); newConsoleMode &= ~(uint)ConsoleModes.EnableQuickEditMode; ConsoleMode = newConsoleMode; - var ocm = OutputConsoleMode; - OutputConsoleMode = ocm | 7; - SetSupportFullColor(); + uint ocm = OutputConsoleMode; + ocm = ocm | (uint)(ConsoleModes.EnableProcessedOutput | ConsoleModes.EnableVirtualTerminalProcessing + | ConsoleModes.DisableNewlineAutoReturn); + ocm -= ocm & (uint)(ConsoleModes.EnableWrapAtEolOutput); + OutputConsoleMode = ocm; + SetSupportTrueColor(); } public CharInfo [] OriginalStdOutChars; @@ -95,41 +100,42 @@ public bool WriteToConsole (FullCharInfo [] charInfoBuffer, Coord coords, SmallR ReadConsoleOutput (OutputHandle, OriginalStdOutChars, coords, new Coord () { X = 0, Y = 0 }, ref window); } - if (!SupportFullColor) { - CharInfo[] ci = new CharInfo[charInfoBuffer.Length]; - for (int i = 0; i < ci.Length; i++) { - ci[i].Char.UnicodeChar = charInfoBuffer[i].Char; - ci[i].Attributes = (ushort)(charInfoBuffer[i].Attributes); - } - return WriteConsoleOutput(ScreenBuffer, ci, coords, new Coord() { X = window.Left, Y = window.Top }, ref window); + if (!SupportTrueColor) { + CharInfo[] ci = new CharInfo[charInfoBuffer.Length]; + for (int i = 0; i < ci.Length; i++) { + ci[i].Char.UnicodeChar = charInfoBuffer[i].Char; + ci[i].Attributes = (ushort)(charInfoBuffer[i].Attributes); + } + return WriteConsoleOutput(ScreenBuffer, ci, coords, new Coord() { X = window.Left, Y = window.Top }, ref window); } - return FullWriteConsole (charInfoBuffer); + return WriteConsoleTrueColor (charInfoBuffer); } - public bool FullWriteConsole(FullCharInfo[] Buffer) { - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < Buffer.Length; i++) { - if (Buffer[i].Attributes is FullAttribute) { - var a = (FullAttribute)(Buffer[i].Attributes); - sb.AppendFormat("\x1b[38;2;{0};{1};{2};48;2;{3};{4};{5}m", a.For.R, a.For.G, a.For.B, - a.Back.R, a.Back.G, a.Back.B); - } - else { - int a = (int)(Buffer[i].Attributes); - sb.AppendFormat("\x1b[38;5;{0};48;5;{1}m", FullColor.WinToLinux(a % 16), FullColor.WinToLinux(a / 16)); + public bool WriteConsoleTrueColor(FullCharInfo[] Buffer) { + char esc = '\x1b'; + StringBuilder sb = new StringBuilder(); + //save cursor position (esc7) and move to (0,0) + sb.AppendFormat("{0}7{0}[0;0H", esc); + for (int i = 0; i < Buffer.Length; i++) { + var a = Buffer[i].Attributes; + if (Buffer[i].Attributes.Fg != null) { + sb.AppendFormat("{0}[38;2;{1};{2};{3};48;2;{4};{5};{6}m", esc, a.Fg.R, a.Fg.G, a.Fg.B, + a.Bg.R, a.Bg.G, a.Bg.B); + } + else { + sb.AppendFormat("{0}[38;5;{1};48;5;{2}m", esc, TrueColor.Code4ToCode8((int)a % 16), TrueColor.Code4ToCode8((int)a / 16)); + } + if (Buffer[i].Char != esc) + sb.Append(Buffer[i].Char); + else + sb.Append(' '); } - if (Buffer[i].Char != '\x1b') - sb.Append(Buffer[i].Char); - else - sb.Append(' '); - } - SetCursorPosition(new Coord { X = 0, Y = 0 }); - uint trash; - string s = sb.ToString(); - WriteConsole(ScreenBuffer, s, (uint)(s.Length), out trash, null); - return true; - } - + //restore cursore position + sb.AppendFormat("{0}8", esc); + string s = sb.ToString(); + return WriteConsole(ScreenBuffer, s, (uint)(s.Length), out uint _, null); + } + public bool SetCursorPosition (Coord position) { return SetConsoleCursorPosition (ScreenBuffer, position); @@ -160,14 +166,14 @@ public uint ConsoleMode { } public uint OutputConsoleMode { - get { - uint v; - GetConsoleMode(OutputHandle, out v); - return v; - } - set { - SetConsoleMode(OutputHandle, value); - } + get { + uint v; + GetConsoleMode(OutputHandle, out v); + return v; + } + set { + SetConsoleMode(OutputHandle, value); + } } [Flags] @@ -175,6 +181,10 @@ public enum ConsoleModes : uint { EnableMouseInput = 16, EnableQuickEditMode = 64, EnableExtendedFlags = 128, + EnableProcessedOutput = 1, + EnableWrapAtEolOutput = 2, + EnableVirtualTerminalProcessing = 4, + DisableNewlineAutoReturn = 8 } [StructLayout (LayoutKind.Explicit, CharSet = CharSet.Unicode)] @@ -405,11 +415,11 @@ public override string ToString () [DllImport("kernel32.dll", EntryPoint = "WriteConsole", SetLastError = true, CharSet = CharSet.Unicode)] static extern bool WriteConsole( - IntPtr hConsoleOutput, - String lpbufer, - UInt32 NumberOfCharsToWriten, - out UInt32 lpNumberOfCharsWritten, - object lpReserved); + IntPtr hConsoleOutput, + String lpbufer, + UInt32 NumberOfCharsToWriten, + out UInt32 lpNumberOfCharsWritten, + object lpReserved); [DllImport ("kernel32.dll", SetLastError = true)] @@ -477,8 +487,8 @@ public uint InputEventCount { } struct FullCharInfo { - public char Char { get; set; } - public Attribute Attributes { get; set; } + public char Char { get; set; } + public Attribute Attributes { get; set; } } internal class WindowsDriver : ConsoleDriver, Mono.Terminal.IMainLoopDriver { @@ -506,7 +516,7 @@ public WindowsDriver () ResizeScreen (); UpdateOffScreen (); winConsole.ConsoleMode = winConsole.ConsoleMode; - + Task.Run ((Action)WindowsInputHandler); } From 5fca380a559895e15bc165e15b5c0bb8261f9147 Mon Sep 17 00:00:00 2001 From: prifio Date: Wed, 25 Jul 2018 10:11:36 +0300 Subject: [PATCH 5/5] Remove using System.Drawing; --- Terminal.Gui/Drivers/ConsoleDriver.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Terminal.Gui/Drivers/ConsoleDriver.cs b/Terminal.Gui/Drivers/ConsoleDriver.cs index 483fd00e9b..11b5fe79bc 100644 --- a/Terminal.Gui/Drivers/ConsoleDriver.cs +++ b/Terminal.Gui/Drivers/ConsoleDriver.cs @@ -10,7 +10,6 @@ using Mono.Terminal; using NStack; using Unix.Terminal; -using System.Drawing; namespace Terminal.Gui {