mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2025-12-26 15:57:56 +01:00
* Fixes #4196. Application.Begin doesn't refresh the screen at start * Fixes #4198. Application.Invoke isn't wakeup the driver if idle * Reformatting to run CI again * Revert "Reformatting to run CI again" This reverts commitef639c1e64. * Trying fix an issue where sometimes subview variable is null running unit tests * Replace ExtendedCharInfo.Char with char array * Replace IsWindowsTerminal with IsVirtualTerminal * Add a lastSize parameter to process resize automatically * Handling surrogate pairs in input * Implement SetConsoleTextAttribute * Prevent select true color is not supported * Fix null exception * Revert GetWindowSize and add SetWindowSize * Fix unit tests * Revert all v2 changes except the one related with the ExtendedCharInfo * Revert newlines and FakeOutput * Prevents null reference * Add gnome-terminal to launch settings * Fixes issue on restore window size after maximize causing width shrinking * Add ; exec bash to stay in terminal * Fixes issue on restore window size after maximize causing width shrinking * Tidying up input and output console modes * Fixes uninitialized screen buffer. * Revert "Fixes issue on restore window size after maximize causing width shrinking" This reverts commite5edad79f6. * Reset console after sending escape sequences * Remove unnecessary code only for buggy VSDebugConsole * Fix more annoying exceptions * Ensure flush the input buffer before reset the console * Remove unnecessary ENABLE_VIRTUAL_TERMINAL_INPUT * Remove unnecessary error handles * Fix CI warnings * Fix more CI warnings * Fix more CI warnings * Fixes #2796. CursesDriver doesn't render wide codepoints correctly --------- Co-authored-by: Tig <tig@users.noreply.github.com>
This commit is contained in:
@@ -48,6 +48,30 @@
|
||||
"commandLineArgs": "dotnet UICatalog.dll --driver v2net",
|
||||
"distributionName": ""
|
||||
},
|
||||
"WSL-Gnome: UICatalog": {
|
||||
"commandName": "Executable",
|
||||
"executablePath": "wsl",
|
||||
"commandLineArgs": "bash -c 'while [ ! -e \"$XDG_RUNTIME_DIR/bus\" ]; do sleep 0.1; done; gnome-terminal --wait -- bash -l -c \"dotnet UICatalog.dll; exec bash\"'",
|
||||
"distributionName": ""
|
||||
},
|
||||
"WSL-Gnome: UICatalog --driver NetDriver": {
|
||||
"commandName": "Executable",
|
||||
"executablePath": "wsl",
|
||||
"commandLineArgs": "bash -c 'while [ ! -e \"$XDG_RUNTIME_DIR/bus\" ]; do sleep 0.1; done; gnome-terminal --wait -- bash -l -c \"dotnet UICatalog.dll --driver NetDriver; exec bash\"'",
|
||||
"distributionName": ""
|
||||
},
|
||||
"WSL-Gnome: UICatalog --driver v2": {
|
||||
"commandName": "Executable",
|
||||
"executablePath": "wsl",
|
||||
"commandLineArgs": "bash -c 'while [ ! -e \"$XDG_RUNTIME_DIR/bus\" ]; do sleep 0.1; done; gnome-terminal --wait -- bash -l -c \"dotnet UICatalog.dll --driver v2; exec bash\"'",
|
||||
"distributionName": ""
|
||||
},
|
||||
"WSL-Gnome: UICatalog --driver v2net": {
|
||||
"commandName": "Executable",
|
||||
"executablePath": "wsl",
|
||||
"commandLineArgs": "bash -c 'while [ ! -e \"$XDG_RUNTIME_DIR/bus\" ]; do sleep 0.1; done; gnome-terminal --wait -- bash -l -c \"dotnet UICatalog.dll --driver v2net; exec bash\"'",
|
||||
"distributionName": ""
|
||||
},
|
||||
"Benchmark All": {
|
||||
"commandName": "Project",
|
||||
"commandLineArgs": "--benchmark"
|
||||
|
||||
@@ -252,7 +252,7 @@ internal class NumericUpDownEditor<T> : View where T : notnull
|
||||
{
|
||||
X = Pos.Center (),
|
||||
Y = Pos.Bottom (_increment) + 1,
|
||||
Increment = NumericUpDown<int>.TryConvert (1, out T? increment) ? increment : default,
|
||||
Increment = NumericUpDown<int>.TryConvert (1, out T? increment) ? increment : default (T?),
|
||||
};
|
||||
|
||||
_numericUpDown.ValueChanged += NumericUpDownOnValueChanged;
|
||||
|
||||
@@ -166,6 +166,16 @@ public class UICatalogTop : Toplevel
|
||||
CheckedState = Application.Force16Colors ? CheckState.Checked : CheckState.UnChecked
|
||||
};
|
||||
|
||||
_force16ColorsMenuItemCb.CheckedStateChanging += (sender, args) =>
|
||||
{
|
||||
if (Application.Force16Colors
|
||||
&& args.Result == CheckState.UnChecked
|
||||
&& !Application.Driver!.SupportsTrueColor)
|
||||
{
|
||||
args.Handled = true;
|
||||
}
|
||||
};
|
||||
|
||||
_force16ColorsMenuItemCb.CheckedStateChanged += (sender, args) =>
|
||||
{
|
||||
Application.Force16Colors = args.Value == CheckState.Checked;
|
||||
@@ -609,8 +619,19 @@ public class UICatalogTop : Toplevel
|
||||
|
||||
_force16ColorsShortcutCb.CheckedStateChanging += (sender, args) =>
|
||||
{
|
||||
Application.Force16Colors = args.Result == CheckState.Checked;
|
||||
_force16ColorsMenuItemCb!.CheckedState = args.Result;
|
||||
if (Application.Force16Colors
|
||||
&& args.Result == CheckState.UnChecked
|
||||
&& !Application.Driver!.SupportsTrueColor)
|
||||
{
|
||||
// If the driver does not support TrueColor, we cannot disable 16 colors
|
||||
args.Handled = true;
|
||||
}
|
||||
};
|
||||
|
||||
_force16ColorsShortcutCb.CheckedStateChanged += (sender, args) =>
|
||||
{
|
||||
Application.Force16Colors = args.Value == CheckState.Checked;
|
||||
_force16ColorsMenuItemCb!.CheckedState = args.Value;
|
||||
Application.LayoutAndDraw ();
|
||||
};
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ public class SixelSupportDetector
|
||||
public void Detect (Action<SixelSupportResult> resultCallback)
|
||||
{
|
||||
var result = new SixelSupportResult ();
|
||||
result.SupportsTransparency = IsWindowsTerminal () || IsXtermWithTransparency ();
|
||||
result.SupportsTransparency = IsVirtualTerminal () || IsXtermWithTransparency ();
|
||||
IsSixelSupportedByDar (result, resultCallback);
|
||||
}
|
||||
|
||||
@@ -142,7 +142,7 @@ public class SixelSupportDetector
|
||||
|
||||
private static bool ResponseIndicatesSupport (string response) { return response.Split (';').Contains ("4"); }
|
||||
|
||||
private static bool IsWindowsTerminal ()
|
||||
private static bool IsVirtualTerminal ()
|
||||
{
|
||||
return !string.IsNullOrWhiteSpace (Environment.GetEnvironmentVariable ("WT_SESSION"));
|
||||
|
||||
|
||||
@@ -269,7 +269,7 @@ public abstract class ConsoleDriver : IConsoleDriver
|
||||
if (Contents [Row, Col - 1].Rune.GetColumns () > 1)
|
||||
{
|
||||
// Invalidate cell to left
|
||||
Contents [Row, Col - 1].Rune = Rune.ReplacementChar;
|
||||
Contents [Row, Col - 1].Rune = (Rune)'\0';
|
||||
Contents [Row, Col - 1].IsDirty = true;
|
||||
}
|
||||
}
|
||||
@@ -308,7 +308,7 @@ public abstract class ConsoleDriver : IConsoleDriver
|
||||
{
|
||||
// Invalidate cell to right so that it doesn't get drawn
|
||||
// TODO: Figure out if it is better to show a replacement character or ' '
|
||||
Contents [Row, Col + 1].Rune = Rune.ReplacementChar;
|
||||
Contents [Row, Col + 1].Rune = (Rune)'\0';
|
||||
Contents [Row, Col + 1].IsDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,12 +123,6 @@ internal class CursesDriver : ConsoleDriver
|
||||
if (!RunningUnitTests)
|
||||
{
|
||||
Platform.Suspend ();
|
||||
|
||||
if (Force16Colors)
|
||||
{
|
||||
Curses.Window.Standard.redrawwin ();
|
||||
Curses.refresh ();
|
||||
}
|
||||
}
|
||||
|
||||
StartReportingMouseMoves ();
|
||||
@@ -139,90 +133,17 @@ internal class CursesDriver : ConsoleDriver
|
||||
EnsureCursorVisibility ();
|
||||
|
||||
if (!RunningUnitTests && Col >= 0 && Col < Cols && Row >= 0 && Row < Rows)
|
||||
{
|
||||
if (Force16Colors)
|
||||
{
|
||||
Curses.move (Row, Col);
|
||||
|
||||
Curses.raw ();
|
||||
Curses.noecho ();
|
||||
Curses.refresh ();
|
||||
}
|
||||
else
|
||||
{
|
||||
_mainLoopDriver?.WriteRaw (EscSeqUtils.CSI_SetCursorPosition (Row + 1, Col + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override bool UpdateScreen ()
|
||||
{
|
||||
bool updated = false;
|
||||
if (Force16Colors)
|
||||
{
|
||||
for (var row = 0; row < Rows; row++)
|
||||
{
|
||||
if (!_dirtyLines! [row])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
_dirtyLines [row] = false;
|
||||
|
||||
for (var col = 0; col < Cols; col++)
|
||||
{
|
||||
if (Contents! [row, col].IsDirty == false)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (RunningUnitTests)
|
||||
{
|
||||
// In unit tests, we don't want to actually write to the screen.
|
||||
continue;
|
||||
}
|
||||
|
||||
Curses.attrset (Contents [row, col].Attribute.GetValueOrDefault ().PlatformColor);
|
||||
|
||||
Rune rune = Contents [row, col].Rune;
|
||||
|
||||
if (rune.IsBmp)
|
||||
{
|
||||
// BUGBUG: CursesDriver doesn't render CharMap correctly for wide chars (and other Unicode) - Curses is doing something funky with glyphs that report GetColums() of 1 yet are rendered wide. E.g. 0x2064 (invisible times) is reported as 1 column but is rendered as 2. WindowsDriver & NetDriver correctly render this as 1 column, overlapping the next cell.
|
||||
if (rune.GetColumns () < 2)
|
||||
{
|
||||
Curses.mvaddch (row, col, rune.Value);
|
||||
}
|
||||
else /*if (col + 1 < Cols)*/
|
||||
{
|
||||
Curses.mvaddwstr (row, col, rune.ToString ());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Curses.mvaddwstr (row, col, rune.ToString ());
|
||||
|
||||
if (rune.GetColumns () > 1 && col + 1 < Cols)
|
||||
{
|
||||
// TODO: This is a hack to deal with non-BMP and wide characters.
|
||||
//col++;
|
||||
Curses.mvaddch (row, ++col, '*');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!RunningUnitTests)
|
||||
{
|
||||
Curses.move (Row, Col);
|
||||
_window?.wrefresh ();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (RunningUnitTests
|
||||
|| Console.WindowHeight < 1
|
||||
|| Contents!.Length != Rows * Cols
|
||||
|| Contents?.Length != Rows * Cols
|
||||
|| Rows != Console.WindowHeight)
|
||||
{
|
||||
return updated;
|
||||
@@ -256,6 +177,7 @@ internal class CursesDriver : ConsoleDriver
|
||||
return updated;
|
||||
}
|
||||
|
||||
updated = true;
|
||||
_dirtyLines [row] = false;
|
||||
output.Clear ();
|
||||
|
||||
@@ -266,7 +188,6 @@ internal class CursesDriver : ConsoleDriver
|
||||
|
||||
for (; col < cols; col++)
|
||||
{
|
||||
updated = true;
|
||||
if (!Contents [row, col].IsDirty)
|
||||
{
|
||||
if (output.Length > 0)
|
||||
@@ -298,6 +219,13 @@ internal class CursesDriver : ConsoleDriver
|
||||
{
|
||||
redrawAttr = attr;
|
||||
|
||||
if (Force16Colors)
|
||||
{
|
||||
output.Append (EscSeqUtils.CSI_SetForegroundColor (attr.Foreground.GetAnsiColorCode ()));
|
||||
output.Append (EscSeqUtils.CSI_SetBackgroundColor (attr.Background.GetAnsiColorCode ()));
|
||||
}
|
||||
else
|
||||
{
|
||||
output.Append (
|
||||
EscSeqUtils.CSI_SetForegroundColorRGB (
|
||||
attr.Foreground.R,
|
||||
@@ -314,6 +242,7 @@ internal class CursesDriver : ConsoleDriver
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
outputWidth++;
|
||||
Rune rune = Contents [row, col].Rune;
|
||||
@@ -347,14 +276,16 @@ internal class CursesDriver : ConsoleDriver
|
||||
SetCursorPosition (lastCol, row);
|
||||
Console.Write (output);
|
||||
}
|
||||
}
|
||||
|
||||
// SIXELS
|
||||
foreach (SixelToRender s in Application.Sixel)
|
||||
foreach (var s in Application.Sixel)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace (s.SixelData))
|
||||
{
|
||||
SetCursorPosition (s.ScreenPosition.X, s.ScreenPosition.Y);
|
||||
Console.Write (s.SixelData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SetCursorPosition (0, 0);
|
||||
|
||||
@@ -368,7 +299,6 @@ internal class CursesDriver : ConsoleDriver
|
||||
lastCol += outputWidth;
|
||||
outputWidth = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return updated;
|
||||
}
|
||||
@@ -396,29 +326,6 @@ internal class CursesDriver : ConsoleDriver
|
||||
);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
/// <remarks>
|
||||
/// In the CursesDriver, colors are encoded as an int. The foreground color is stored in the most significant 4
|
||||
/// bits, and the background color is stored in the least significant 4 bits. The Terminal.GUi Color values are
|
||||
/// converted to curses color encoding before being encoded.
|
||||
/// </remarks>
|
||||
public override Attribute MakeColor (in Color foreground, in Color background)
|
||||
{
|
||||
if (!RunningUnitTests && Force16Colors)
|
||||
{
|
||||
return MakeColor (
|
||||
ColorNameToCursesColorNumber (foreground.GetClosestNamedColor16 ()),
|
||||
ColorNameToCursesColorNumber (background.GetClosestNamedColor16 ())
|
||||
);
|
||||
}
|
||||
|
||||
return new (
|
||||
0,
|
||||
foreground,
|
||||
background
|
||||
);
|
||||
}
|
||||
|
||||
private static short ColorNameToCursesColorNumber (ColorName16 color)
|
||||
{
|
||||
switch (color)
|
||||
|
||||
@@ -223,7 +223,7 @@ internal class NetDriver : ConsoleDriver
|
||||
|
||||
// BUGBUG: Fix this nullable issue.
|
||||
/// <inheritdoc />
|
||||
internal override IAnsiResponseParser GetParser () => _mainLoopDriver._netEvents.Parser;
|
||||
internal override IAnsiResponseParser GetParser () => _mainLoopDriver!._netEvents!.Parser;
|
||||
internal NetMainLoop? _mainLoopDriver;
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -356,11 +356,6 @@ internal class NetDriver : ConsoleDriver
|
||||
}
|
||||
public override void End ()
|
||||
{
|
||||
if (IsWinPlatform)
|
||||
{
|
||||
NetWinConsole?.Cleanup ();
|
||||
}
|
||||
|
||||
StopReportingMouseMoves ();
|
||||
|
||||
if (!RunningUnitTests)
|
||||
@@ -373,6 +368,11 @@ internal class NetDriver : ConsoleDriver
|
||||
//Set cursor key to cursor.
|
||||
Console.Out.Write (EscSeqUtils.CSI_ShowCursor);
|
||||
Console.Out.Close ();
|
||||
|
||||
// Reset the console to its original state
|
||||
// after sending the escape sequences to restore
|
||||
// alternative buffer and cursor visibility.
|
||||
NetWinConsole?.Cleanup ();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -746,47 +746,6 @@ internal class NetDriver : ConsoleDriver
|
||||
|
||||
public virtual void ResizeScreen ()
|
||||
{
|
||||
// Not supported on Unix.
|
||||
if (IsWinPlatform)
|
||||
{
|
||||
// Can raise an exception while is still resizing.
|
||||
try
|
||||
{
|
||||
#pragma warning disable CA1416
|
||||
if (Console.WindowHeight > 0)
|
||||
{
|
||||
Console.CursorTop = 0;
|
||||
Console.CursorLeft = 0;
|
||||
Console.WindowTop = 0;
|
||||
Console.WindowLeft = 0;
|
||||
|
||||
if (Console.WindowHeight > Rows)
|
||||
{
|
||||
Console.SetWindowSize (Cols, Rows);
|
||||
}
|
||||
|
||||
Console.SetBufferSize (Cols, Rows);
|
||||
}
|
||||
#pragma warning restore CA1416
|
||||
}
|
||||
// INTENT: Why are these eating the exceptions?
|
||||
// Comments would be good here.
|
||||
catch (IOException)
|
||||
{
|
||||
// CONCURRENCY: Unsynchronized access to Clip is not safe.
|
||||
Clip = new (Screen);
|
||||
}
|
||||
catch (ArgumentOutOfRangeException)
|
||||
{
|
||||
// CONCURRENCY: Unsynchronized access to Clip is not safe.
|
||||
Clip = new (Screen);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.Out.Write (EscSeqUtils.CSI_SetTerminalWindowSize (Rows, Cols));
|
||||
}
|
||||
|
||||
// CONCURRENCY: Unsynchronized access to Clip is not safe.
|
||||
Clip = new (Screen);
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ internal class NetEvents : IDisposable
|
||||
return Console.ReadKey (intercept);
|
||||
}
|
||||
|
||||
while (!_netEventsDisposed.IsCancellationRequested)
|
||||
while (!_netEventsDisposed!.IsCancellationRequested)
|
||||
{
|
||||
Task.Delay (100, _netEventsDisposed.Token).Wait (_netEventsDisposed.Token);
|
||||
|
||||
@@ -113,11 +113,11 @@ internal class NetEvents : IDisposable
|
||||
|
||||
private void ProcessInputQueue ()
|
||||
{
|
||||
while (!_netEventsDisposed.IsCancellationRequested)
|
||||
while (_netEventsDisposed is { IsCancellationRequested: false })
|
||||
{
|
||||
if (_inputQueue.Count == 0)
|
||||
{
|
||||
while (!_netEventsDisposed.IsCancellationRequested)
|
||||
while (_netEventsDisposed is { IsCancellationRequested: false })
|
||||
{
|
||||
ConsoleKeyInfo consoleKeyInfo;
|
||||
|
||||
@@ -147,7 +147,7 @@ internal class NetEvents : IDisposable
|
||||
{
|
||||
void RequestWindowSize ()
|
||||
{
|
||||
while (!_netEventsDisposed.IsCancellationRequested)
|
||||
while (_netEventsDisposed is { IsCancellationRequested: false })
|
||||
{
|
||||
// Wait for a while then check if screen has changed sizes
|
||||
Task.Delay (500, _netEventsDisposed.Token).Wait (_netEventsDisposed.Token);
|
||||
@@ -179,7 +179,7 @@ internal class NetEvents : IDisposable
|
||||
_netEventsDisposed.Token.ThrowIfCancellationRequested ();
|
||||
}
|
||||
|
||||
while (!_netEventsDisposed.IsCancellationRequested)
|
||||
while (!_netEventsDisposed!.IsCancellationRequested)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -434,10 +434,6 @@ internal class NetEvents : IDisposable
|
||||
new InputResult { EventType = eventType, WindowPositionEvent = winPositionEv }
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
@@ -563,7 +559,7 @@ internal class NetEvents : IDisposable
|
||||
|
||||
public readonly override string ToString ()
|
||||
{
|
||||
return EventType switch
|
||||
return (EventType switch
|
||||
{
|
||||
EventType.Key => ToString (ConsoleKeyInfo),
|
||||
EventType.Mouse => MouseEvent.ToString (),
|
||||
@@ -571,7 +567,7 @@ internal class NetEvents : IDisposable
|
||||
//EventType.WindowSize => WindowSize.ToString (),
|
||||
//EventType.RequestResponse => RequestResponse.ToString (),
|
||||
_ => "Unknown event type: " + EventType
|
||||
};
|
||||
})!;
|
||||
}
|
||||
|
||||
/// <summary>Prints a ConsoleKeyInfoEx structure</summary>
|
||||
|
||||
@@ -5,31 +5,31 @@ namespace Terminal.Gui.Drivers;
|
||||
|
||||
internal class NetWinVTConsole
|
||||
{
|
||||
private const uint DISABLE_NEWLINE_AUTO_RETURN = 8;
|
||||
private const uint ENABLE_ECHO_INPUT = 4;
|
||||
private const uint ENABLE_EXTENDED_FLAGS = 128;
|
||||
private const uint ENABLE_INSERT_MODE = 32;
|
||||
private const uint ENABLE_LINE_INPUT = 2;
|
||||
private const uint ENABLE_LVB_GRID_WORLDWIDE = 10;
|
||||
private const uint ENABLE_MOUSE_INPUT = 16;
|
||||
|
||||
// Input modes.
|
||||
private const uint ENABLE_PROCESSED_INPUT = 1;
|
||||
private const uint ENABLE_LINE_INPUT = 2;
|
||||
private const uint ENABLE_ECHO_INPUT = 4;
|
||||
private const uint ENABLE_WINDOW_INPUT = 8;
|
||||
private const uint ENABLE_MOUSE_INPUT = 16;
|
||||
private const uint ENABLE_INSERT_MODE = 32;
|
||||
private const uint ENABLE_QUICK_EDIT_MODE = 64;
|
||||
private const uint ENABLE_EXTENDED_FLAGS = 128;
|
||||
private const uint ENABLE_VIRTUAL_TERMINAL_INPUT = 512;
|
||||
|
||||
// Output modes.
|
||||
private const uint ENABLE_PROCESSED_OUTPUT = 1;
|
||||
private const uint ENABLE_QUICK_EDIT_MODE = 64;
|
||||
private const uint ENABLE_VIRTUAL_TERMINAL_INPUT = 512;
|
||||
private const uint ENABLE_VIRTUAL_TERMINAL_PROCESSING = 4;
|
||||
private const uint ENABLE_WINDOW_INPUT = 8;
|
||||
private const uint ENABLE_WRAP_AT_EOL_OUTPUT = 2;
|
||||
private const uint ENABLE_VIRTUAL_TERMINAL_PROCESSING = 4;
|
||||
private const uint DISABLE_NEWLINE_AUTO_RETURN = 8;
|
||||
private const uint ENABLE_LVB_GRID_WORLDWIDE = 10;
|
||||
|
||||
// Standard handles.
|
||||
private const int STD_ERROR_HANDLE = -12;
|
||||
private const int STD_INPUT_HANDLE = -10;
|
||||
private const int STD_OUTPUT_HANDLE = -11;
|
||||
|
||||
private readonly nint _errorHandle;
|
||||
// Handles and original console modes.
|
||||
private readonly nint _inputHandle;
|
||||
private readonly uint _originalErrorConsoleMode;
|
||||
private readonly uint _originalInputConsoleMode;
|
||||
private readonly uint _originalOutputConsoleMode;
|
||||
private readonly nint _outputHandle;
|
||||
@@ -45,7 +45,7 @@ internal class NetWinVTConsole
|
||||
|
||||
_originalInputConsoleMode = mode;
|
||||
|
||||
if ((mode & ENABLE_VIRTUAL_TERMINAL_INPUT) < ENABLE_VIRTUAL_TERMINAL_INPUT)
|
||||
if ((mode & ENABLE_VIRTUAL_TERMINAL_INPUT) == 0)
|
||||
{
|
||||
mode |= ENABLE_VIRTUAL_TERMINAL_INPUT;
|
||||
|
||||
@@ -64,34 +64,15 @@ internal class NetWinVTConsole
|
||||
|
||||
_originalOutputConsoleMode = mode;
|
||||
|
||||
if ((mode & (ENABLE_VIRTUAL_TERMINAL_PROCESSING | DISABLE_NEWLINE_AUTO_RETURN)) < DISABLE_NEWLINE_AUTO_RETURN)
|
||||
if ((mode & ENABLE_VIRTUAL_TERMINAL_PROCESSING) == 0)
|
||||
{
|
||||
mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING | DISABLE_NEWLINE_AUTO_RETURN;
|
||||
mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
||||
|
||||
if (!SetConsoleMode (_outputHandle, mode))
|
||||
{
|
||||
throw new ApplicationException ($"Failed to set output console mode, error code: {GetLastError ()}.");
|
||||
}
|
||||
}
|
||||
|
||||
_errorHandle = GetStdHandle (STD_ERROR_HANDLE);
|
||||
|
||||
if (!GetConsoleMode (_errorHandle, out mode))
|
||||
{
|
||||
throw new ApplicationException ($"Failed to get error console mode, error code: {GetLastError ()}.");
|
||||
}
|
||||
|
||||
_originalErrorConsoleMode = mode;
|
||||
|
||||
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 ()}.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Cleanup ()
|
||||
@@ -110,11 +91,6 @@ internal class NetWinVTConsole
|
||||
{
|
||||
throw new ApplicationException ($"Failed to restore output console mode, error code: {GetLastError ()}.");
|
||||
}
|
||||
|
||||
if (!SetConsoleMode (_errorHandle, _originalErrorConsoleMode))
|
||||
{
|
||||
throw new ApplicationException ($"Failed to restore error console mode, error code: {GetLastError ()}.");
|
||||
}
|
||||
}
|
||||
|
||||
[DllImport ("kernel32.dll")]
|
||||
|
||||
@@ -234,7 +234,7 @@ internal partial class WindowsOutput : OutputBase, IConsoleOutput
|
||||
public override void Write (IOutputBuffer outputBuffer)
|
||||
{
|
||||
_force16Colors = Application.Driver!.Force16Colors;
|
||||
_everythingStringBuilder = new StringBuilder ();
|
||||
_everythingStringBuilder.Clear ();
|
||||
|
||||
// for 16 color mode we will write to a backing buffer then flip it to the active one at the end to avoid jitter.
|
||||
_consoleBuffer = 0;
|
||||
@@ -485,7 +485,7 @@ internal partial class WindowsOutput : OutputBase, IConsoleOutput
|
||||
private bool _isDisposed;
|
||||
private bool _force16Colors;
|
||||
private nint _consoleBuffer;
|
||||
private StringBuilder _everythingStringBuilder;
|
||||
private StringBuilder _everythingStringBuilder = new ();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose ()
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.InteropServices;
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
#pragma warning disable IDE1006// Naming rule violation: Prefix '_' is not expected
|
||||
|
||||
namespace Terminal.Gui.Drivers;
|
||||
|
||||
@@ -35,10 +37,69 @@ public partial class WindowsConsole
|
||||
newConsoleMode &= ~(uint)ConsoleModes.EnableProcessedInput;
|
||||
ConsoleMode = newConsoleMode;
|
||||
|
||||
IsVirtualTerminal = GetConsoleMode (_outputHandle, out uint mode) && (mode & (uint)ConsoleModes.EnableVirtualTerminalProcessing) != 0;
|
||||
|
||||
if (!IsVirtualTerminal)
|
||||
{
|
||||
CreateConsoleScreenBuffer ();
|
||||
Size bufferSize = GetConsoleBufferWindow (out _);
|
||||
SmallRect window = new ()
|
||||
{
|
||||
Top = 0,
|
||||
Left = 0,
|
||||
Bottom = (short)bufferSize.Height,
|
||||
Right = (short)bufferSize.Width
|
||||
};
|
||||
|
||||
ReadFromConsoleOutput (bufferSize, new ((short)bufferSize.Width, (short)bufferSize.Height), ref window);
|
||||
|
||||
if (!GetConsoleMode (_screenBuffer, out mode))
|
||||
{
|
||||
throw new ApplicationException ($"Failed to get screenBuffer console mode, error code: {Marshal.GetLastWin32Error ()}.");
|
||||
}
|
||||
|
||||
const uint ENABLE_WRAP_AT_EOL_OUTPUT = 0x0002;
|
||||
|
||||
mode &= ~ENABLE_WRAP_AT_EOL_OUTPUT; // Disable wrap
|
||||
|
||||
if (!SetConsoleMode (_screenBuffer, mode))
|
||||
{
|
||||
throw new ApplicationException ($"Failed to set screenBuffer console mode, error code: {Marshal.GetLastWin32Error ()}.");
|
||||
}
|
||||
}
|
||||
|
||||
SetInitialCursorVisibility ();
|
||||
|
||||
_inputReadyCancellationTokenSource = new ();
|
||||
Task.Run (ProcessInputQueue, _inputReadyCancellationTokenSource.Token);
|
||||
}
|
||||
|
||||
private void CreateConsoleScreenBuffer ()
|
||||
{
|
||||
_screenBuffer = CreateConsoleScreenBuffer (
|
||||
DesiredAccess.GenericRead | DesiredAccess.GenericWrite,
|
||||
ShareMode.FileShareRead | ShareMode.FileShareWrite,
|
||||
nint.Zero,
|
||||
1,
|
||||
nint.Zero
|
||||
);
|
||||
|
||||
if (_screenBuffer == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
int err = Marshal.GetLastWin32Error ();
|
||||
|
||||
if (err != 0)
|
||||
{
|
||||
throw new Win32Exception (err);
|
||||
}
|
||||
}
|
||||
|
||||
if (!SetConsoleActiveScreenBuffer (_screenBuffer))
|
||||
{
|
||||
throw new Win32Exception (Marshal.GetLastWin32Error ());
|
||||
}
|
||||
}
|
||||
|
||||
public InputRecord? DequeueInput ()
|
||||
{
|
||||
while (_inputReadyCancellationTokenSource is { })
|
||||
@@ -146,35 +207,138 @@ public partial class WindowsConsole
|
||||
|
||||
private CharInfo []? _originalStdOutChars;
|
||||
|
||||
private struct Run
|
||||
{
|
||||
public ushort attr;
|
||||
public string text;
|
||||
|
||||
public Run (ushort attr, string text)
|
||||
{
|
||||
this.attr = attr;
|
||||
this.text = text;
|
||||
}
|
||||
}
|
||||
|
||||
public bool WriteToConsole (Size size, ExtendedCharInfo [] charInfoBuffer, Coord bufferSize, SmallRect window, bool force16Colors)
|
||||
{
|
||||
//Debug.WriteLine ("WriteToConsole");
|
||||
|
||||
if (!IsWindowsTerminal && _screenBuffer == nint.Zero)
|
||||
{
|
||||
ReadFromConsoleOutput (size, bufferSize, ref window);
|
||||
}
|
||||
|
||||
SetInitialCursorVisibility ();
|
||||
|
||||
Attribute? prev = null;
|
||||
var result = false;
|
||||
|
||||
if (force16Colors)
|
||||
{
|
||||
_stringBuilder.Clear ();
|
||||
|
||||
var i = 0;
|
||||
CharInfo [] ci = new CharInfo [charInfoBuffer.Length];
|
||||
List<Run> runs = [];
|
||||
Run? current = null;
|
||||
SetCursorPosition (new Coord (0, 0));
|
||||
|
||||
foreach (ExtendedCharInfo info in charInfoBuffer)
|
||||
{
|
||||
ci [i++] = new CharInfo
|
||||
if (IsVirtualTerminal)
|
||||
{
|
||||
Char = new CharUnion { UnicodeChar = info.Char },
|
||||
Attributes =
|
||||
(ushort)((int)info.Attribute.Foreground.GetClosestNamedColor16 () | ((int)info.Attribute.Background.GetClosestNamedColor16 () << 4))
|
||||
};
|
||||
Attribute attr = info.Attribute;
|
||||
AnsiColorCode fgColor = info.Attribute.Foreground.GetAnsiColorCode ();
|
||||
AnsiColorCode bgColor = info.Attribute.Background.GetAnsiColorCode ();
|
||||
|
||||
if (attr != prev)
|
||||
{
|
||||
prev = attr;
|
||||
_stringBuilder.Append (EscSeqUtils.CSI_SetForegroundColor (fgColor));
|
||||
_stringBuilder.Append (EscSeqUtils.CSI_SetBackgroundColor (bgColor));
|
||||
|
||||
EscSeqUtils.CSI_AppendTextStyleChange (_stringBuilder, _redrawTextStyle, attr.Style);
|
||||
_redrawTextStyle = attr.Style;
|
||||
}
|
||||
|
||||
result = WriteConsoleOutput (IsWindowsTerminal ? _outputHandle : _screenBuffer, ci, bufferSize, new Coord { X = window.Left, Y = window.Top }, ref window);
|
||||
if (info.Char [0] != '\x1b')
|
||||
{
|
||||
if (!info.Empty)
|
||||
{
|
||||
_stringBuilder.Append (info.Char);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_stringBuilder.Append (' ');
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (info.Empty)
|
||||
{
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!info.Empty)
|
||||
{
|
||||
var attr = (ushort)((int)info.Attribute.Foreground.GetClosestNamedColor16 ()
|
||||
| ((int)info.Attribute.Background.GetClosestNamedColor16 () << 4));
|
||||
|
||||
// Start new run if needed
|
||||
if (current == null || attr != current.Value.attr)
|
||||
{
|
||||
if (current != null)
|
||||
{
|
||||
runs.Add (new (current.Value.attr, _stringBuilder.ToString ()));
|
||||
}
|
||||
|
||||
_stringBuilder.Clear ();
|
||||
current = new Run (attr, "");
|
||||
}
|
||||
|
||||
_stringBuilder!.Append (info.Char);
|
||||
}
|
||||
|
||||
i++;
|
||||
|
||||
if (i > 0 && i <= charInfoBuffer.Length && i % bufferSize.X == 0)
|
||||
{
|
||||
if (i < charInfoBuffer.Length)
|
||||
{
|
||||
_stringBuilder.AppendLine ();
|
||||
}
|
||||
|
||||
runs.Add (new (current!.Value.attr, _stringBuilder.ToString ()));
|
||||
_stringBuilder.Clear ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (IsVirtualTerminal)
|
||||
{
|
||||
_stringBuilder.Append (EscSeqUtils.CSI_RestoreCursorPosition);
|
||||
_stringBuilder.Append (EscSeqUtils.CSI_HideCursor);
|
||||
|
||||
var s = _stringBuilder.ToString ();
|
||||
|
||||
// TODO: requires extensive testing if we go down this route
|
||||
// If console output has changed
|
||||
if (s != _lastWrite)
|
||||
{
|
||||
// supply console with the new content
|
||||
result = WriteConsole (_outputHandle, s, (uint)s.Length, out uint _, nint.Zero);
|
||||
}
|
||||
|
||||
_lastWrite = s;
|
||||
|
||||
foreach (var sixel in Application.Sixel)
|
||||
{
|
||||
SetCursorPosition (new Coord ((short)sixel.ScreenPosition.X, (short)sixel.ScreenPosition.Y));
|
||||
WriteConsole (IsVirtualTerminal ? _outputHandle : _screenBuffer, sixel.SixelData, (uint)sixel.SixelData.Length, out uint _, nint.Zero);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var run in runs)
|
||||
{
|
||||
SetConsoleTextAttribute (IsVirtualTerminal ? _outputHandle : _screenBuffer, run.attr);
|
||||
result = WriteConsole (IsVirtualTerminal ? _outputHandle : _screenBuffer, run.text, (uint)run.text.Length, out _, nint.Zero);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -183,8 +347,6 @@ public partial class WindowsConsole
|
||||
_stringBuilder.Append (EscSeqUtils.CSI_SaveCursorPosition);
|
||||
EscSeqUtils.CSI_AppendCursorPosition (_stringBuilder, 0, 0);
|
||||
|
||||
Attribute? prev = null;
|
||||
|
||||
foreach (ExtendedCharInfo info in charInfoBuffer)
|
||||
{
|
||||
Attribute attr = info.Attribute;
|
||||
@@ -198,7 +360,7 @@ public partial class WindowsConsole
|
||||
_redrawTextStyle = attr.Style;
|
||||
}
|
||||
|
||||
if (info.Char != '\x1b')
|
||||
if (info.Char [0] != '\x1b')
|
||||
{
|
||||
if (!info.Empty)
|
||||
{
|
||||
@@ -229,7 +391,7 @@ public partial class WindowsConsole
|
||||
foreach (var sixel in Application.Sixel)
|
||||
{
|
||||
SetCursorPosition (new Coord ((short)sixel.ScreenPosition.X, (short)sixel.ScreenPosition.Y));
|
||||
WriteConsole (IsWindowsTerminal ? _outputHandle : _screenBuffer, sixel.SixelData, (uint)sixel.SixelData.Length, out uint _, nint.Zero);
|
||||
WriteConsole (IsVirtualTerminal ? _outputHandle : _screenBuffer, sixel.SixelData, (uint)sixel.SixelData.Length, out uint _, nint.Zero);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -259,29 +421,6 @@ public partial class WindowsConsole
|
||||
|
||||
public void ReadFromConsoleOutput (Size size, Coord coords, ref SmallRect window)
|
||||
{
|
||||
_screenBuffer = CreateConsoleScreenBuffer (
|
||||
DesiredAccess.GenericRead | DesiredAccess.GenericWrite,
|
||||
ShareMode.FileShareRead | ShareMode.FileShareWrite,
|
||||
nint.Zero,
|
||||
1,
|
||||
nint.Zero
|
||||
);
|
||||
|
||||
if (_screenBuffer == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
int err = Marshal.GetLastWin32Error ();
|
||||
|
||||
if (err != 0)
|
||||
{
|
||||
throw new Win32Exception (err);
|
||||
}
|
||||
}
|
||||
|
||||
if (!SetConsoleActiveScreenBuffer (_screenBuffer))
|
||||
{
|
||||
throw new Win32Exception (Marshal.GetLastWin32Error ());
|
||||
}
|
||||
|
||||
_originalStdOutChars = new CharInfo [size.Height * size.Width];
|
||||
|
||||
if (!ReadConsoleOutput (_screenBuffer, _originalStdOutChars, coords, new Coord { X = 0, Y = 0 }, ref window))
|
||||
@@ -292,7 +431,7 @@ public partial class WindowsConsole
|
||||
|
||||
public bool SetCursorPosition (Coord position)
|
||||
{
|
||||
return SetConsoleCursorPosition (IsWindowsTerminal ? _outputHandle : _screenBuffer, position);
|
||||
return SetConsoleCursorPosition (IsVirtualTerminal ? _outputHandle : _screenBuffer, position);
|
||||
}
|
||||
|
||||
public void SetInitialCursorVisibility ()
|
||||
@@ -305,14 +444,14 @@ public partial class WindowsConsole
|
||||
|
||||
public bool GetCursorVisibility (out CursorVisibility visibility)
|
||||
{
|
||||
if ((IsWindowsTerminal ? _outputHandle : _screenBuffer) == nint.Zero)
|
||||
if ((IsVirtualTerminal ? _outputHandle : _screenBuffer) == nint.Zero)
|
||||
{
|
||||
visibility = CursorVisibility.Invisible;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!GetConsoleCursorInfo (IsWindowsTerminal ? _outputHandle : _screenBuffer, out ConsoleCursorInfo info))
|
||||
if (!GetConsoleCursorInfo (IsVirtualTerminal ? _outputHandle : _screenBuffer, out ConsoleCursorInfo info))
|
||||
{
|
||||
int err = Marshal.GetLastWin32Error ();
|
||||
|
||||
@@ -380,7 +519,7 @@ public partial class WindowsConsole
|
||||
bVisible = ((uint)visibility & 0xFF00) != 0
|
||||
};
|
||||
|
||||
if (!SetConsoleCursorInfo (IsWindowsTerminal ? _outputHandle : _screenBuffer, ref info))
|
||||
if (!SetConsoleCursorInfo (IsVirtualTerminal ? _outputHandle : _screenBuffer, ref info))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -430,7 +569,7 @@ public partial class WindowsConsole
|
||||
|
||||
internal Size GetConsoleBufferWindow (out Point position)
|
||||
{
|
||||
if ((IsWindowsTerminal ? _outputHandle : _screenBuffer) == nint.Zero)
|
||||
if ((IsVirtualTerminal ? _outputHandle : _screenBuffer) == nint.Zero)
|
||||
{
|
||||
position = Point.Empty;
|
||||
|
||||
@@ -440,7 +579,7 @@ public partial class WindowsConsole
|
||||
var csbi = new CONSOLE_SCREEN_BUFFER_INFOEX ();
|
||||
csbi.cbSize = (uint)Marshal.SizeOf (csbi);
|
||||
|
||||
if (!GetConsoleScreenBufferInfoEx (IsWindowsTerminal ? _outputHandle : _screenBuffer, ref csbi))
|
||||
if (!GetConsoleScreenBufferInfoEx (IsVirtualTerminal ? _outputHandle : _screenBuffer, ref csbi))
|
||||
{
|
||||
//throw new System.ComponentModel.Win32Exception (Marshal.GetLastWin32Error ());
|
||||
position = Point.Empty;
|
||||
@@ -479,19 +618,19 @@ public partial class WindowsConsole
|
||||
var csbi = new CONSOLE_SCREEN_BUFFER_INFOEX ();
|
||||
csbi.cbSize = (uint)Marshal.SizeOf (csbi);
|
||||
|
||||
if (!GetConsoleScreenBufferInfoEx (IsWindowsTerminal ? _outputHandle : _screenBuffer, ref csbi))
|
||||
if (!GetConsoleScreenBufferInfoEx (IsVirtualTerminal ? _outputHandle : _screenBuffer, ref csbi))
|
||||
{
|
||||
throw new Win32Exception (Marshal.GetLastWin32Error ());
|
||||
}
|
||||
|
||||
Coord maxWinSize = GetLargestConsoleWindowSize (IsWindowsTerminal ? _outputHandle : _screenBuffer);
|
||||
Coord maxWinSize = GetLargestConsoleWindowSize (IsVirtualTerminal ? _outputHandle : _screenBuffer);
|
||||
short newCols = Math.Min (cols, maxWinSize.X);
|
||||
short newRows = Math.Min (rows, maxWinSize.Y);
|
||||
csbi.dwSize = new Coord (newCols, Math.Max (newRows, (short)1));
|
||||
csbi.srWindow = new SmallRect (0, 0, newCols, newRows);
|
||||
csbi.dwMaximumWindowSize = new Coord (newCols, newRows);
|
||||
|
||||
if (!SetConsoleScreenBufferInfoEx (IsWindowsTerminal ? _outputHandle : _screenBuffer, ref csbi))
|
||||
if (!SetConsoleScreenBufferInfoEx (IsVirtualTerminal ? _outputHandle : _screenBuffer, ref csbi))
|
||||
{
|
||||
throw new Win32Exception (Marshal.GetLastWin32Error ());
|
||||
}
|
||||
@@ -509,11 +648,18 @@ public partial class WindowsConsole
|
||||
return new (winRect.Right + 1, newRows - 1 < 0 ? 0 : winRect.Bottom + 1);
|
||||
}
|
||||
|
||||
internal Size GetLargestConsoleWindowSize ()
|
||||
{
|
||||
Coord maxWinSize = GetLargestConsoleWindowSize (IsVirtualTerminal ? _outputHandle : _screenBuffer);
|
||||
|
||||
return new (maxWinSize.X, maxWinSize.Y);
|
||||
}
|
||||
|
||||
private void SetConsoleOutputWindow (CONSOLE_SCREEN_BUFFER_INFOEX csbi)
|
||||
{
|
||||
if ((IsWindowsTerminal
|
||||
if ((IsVirtualTerminal
|
||||
? _outputHandle
|
||||
: _screenBuffer) != nint.Zero && !SetConsoleScreenBufferInfoEx (IsWindowsTerminal ? _outputHandle : _screenBuffer, ref csbi))
|
||||
: _screenBuffer) != nint.Zero && !SetConsoleScreenBufferInfoEx (IsVirtualTerminal ? _outputHandle : _screenBuffer, ref csbi))
|
||||
{
|
||||
throw new Win32Exception (Marshal.GetLastWin32Error ());
|
||||
}
|
||||
@@ -521,7 +667,7 @@ public partial class WindowsConsole
|
||||
|
||||
internal Size SetConsoleOutputWindow (out Point position)
|
||||
{
|
||||
if ((IsWindowsTerminal ? _outputHandle : _screenBuffer) == nint.Zero)
|
||||
if ((IsVirtualTerminal ? _outputHandle : _screenBuffer) == nint.Zero)
|
||||
{
|
||||
position = Point.Empty;
|
||||
|
||||
@@ -531,7 +677,7 @@ public partial class WindowsConsole
|
||||
var csbi = new CONSOLE_SCREEN_BUFFER_INFOEX ();
|
||||
csbi.cbSize = (uint)Marshal.SizeOf (csbi);
|
||||
|
||||
if (!GetConsoleScreenBufferInfoEx (IsWindowsTerminal ? _outputHandle : _screenBuffer, ref csbi))
|
||||
if (!GetConsoleScreenBufferInfoEx (IsVirtualTerminal ? _outputHandle : _screenBuffer, ref csbi))
|
||||
{
|
||||
throw new Win32Exception (Marshal.GetLastWin32Error ());
|
||||
}
|
||||
@@ -556,7 +702,7 @@ public partial class WindowsConsole
|
||||
return sz;
|
||||
}
|
||||
|
||||
internal bool IsWindowsTerminal { get; set; }
|
||||
internal bool IsVirtualTerminal { get; init; }
|
||||
|
||||
private uint ConsoleMode
|
||||
{
|
||||
@@ -573,6 +719,7 @@ public partial class WindowsConsole
|
||||
public enum ConsoleModes : uint
|
||||
{
|
||||
EnableProcessedInput = 1,
|
||||
EnableVirtualTerminalProcessing = 4,
|
||||
EnableMouseInput = 16,
|
||||
EnableQuickEditMode = 64,
|
||||
EnableExtendedFlags = 128
|
||||
@@ -791,11 +938,11 @@ public partial class WindowsConsole
|
||||
|
||||
public struct ExtendedCharInfo
|
||||
{
|
||||
public char Char { get; set; }
|
||||
public char [] Char { get; set; }
|
||||
public Attribute Attribute { get; set; }
|
||||
public bool Empty { get; set; } // TODO: Temp hack until virtual terminal sequences
|
||||
|
||||
public ExtendedCharInfo (char character, Attribute attribute)
|
||||
public ExtendedCharInfo (char [] character, Attribute attribute)
|
||||
{
|
||||
Char = character;
|
||||
Attribute = attribute;
|
||||
@@ -946,7 +1093,13 @@ public partial class WindowsConsole
|
||||
);
|
||||
|
||||
[DllImport ("kernel32.dll", SetLastError = true)]
|
||||
static extern bool FlushFileBuffers (nint hFile);
|
||||
private static extern bool SetConsoleTextAttribute (
|
||||
nint hConsoleOutput,
|
||||
ushort wAttributes
|
||||
);
|
||||
|
||||
[DllImport ("kernel32.dll", SetLastError = true)]
|
||||
private static extern bool FlushFileBuffers (nint hFile);
|
||||
|
||||
[DllImport ("kernel32.dll")]
|
||||
private static extern bool SetConsoleCursorPosition (nint hConsoleOutput, Coord dwCursorPosition);
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace Terminal.Gui.Drivers;
|
||||
|
||||
internal class WindowsDriver : ConsoleDriver
|
||||
{
|
||||
private readonly bool _isWindowsTerminal;
|
||||
private readonly bool _isVirtualTerminal;
|
||||
|
||||
private WindowsConsole.SmallRect _damageRegion;
|
||||
private bool _isButtonDoubleClicked;
|
||||
@@ -57,18 +57,16 @@ internal class WindowsDriver : ConsoleDriver
|
||||
// force 16color mode (.e.g ConEmu which really doesn't work well at all).
|
||||
if (!RunningUnitTests)
|
||||
{
|
||||
WinConsole!.IsWindowsTerminal = _isWindowsTerminal =
|
||||
Environment.GetEnvironmentVariable ("WT_SESSION") is { }
|
||||
|| Environment.GetEnvironmentVariable ("VSAPPIDNAME") != null;
|
||||
_isVirtualTerminal = WinConsole!.IsVirtualTerminal;
|
||||
}
|
||||
|
||||
if (!_isWindowsTerminal)
|
||||
if (!_isVirtualTerminal)
|
||||
{
|
||||
Force16Colors = true;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool SupportsTrueColor => RunningUnitTests || (Environment.OSVersion.Version.Build >= 14931 && _isWindowsTerminal);
|
||||
public override bool SupportsTrueColor => RunningUnitTests || (Environment.OSVersion.Version.Build >= 14931 && _isVirtualTerminal);
|
||||
|
||||
public WindowsConsole? WinConsole { get; private set; }
|
||||
|
||||
@@ -337,7 +335,7 @@ internal class WindowsDriver : ConsoleDriver
|
||||
if (Contents [row, col].IsDirty == false)
|
||||
{
|
||||
_outputBuffer [position].Empty = true;
|
||||
_outputBuffer [position].Char = (char)Rune.ReplacementChar.Value;
|
||||
_outputBuffer [position].Char = [(char)Contents [row, col].Rune.Value];
|
||||
|
||||
continue;
|
||||
}
|
||||
@@ -346,12 +344,12 @@ internal class WindowsDriver : ConsoleDriver
|
||||
|
||||
if (Contents [row, col].Rune.IsBmp)
|
||||
{
|
||||
_outputBuffer [position].Char = (char)Contents [row, col].Rune.Value;
|
||||
_outputBuffer [position].Char = [(char)Contents [row, col].Rune.Value];
|
||||
}
|
||||
else
|
||||
{
|
||||
//_outputBuffer [position].Empty = true;
|
||||
_outputBuffer [position].Char = (char)Rune.ReplacementChar.Value;
|
||||
_outputBuffer [position].Char = [(char)Contents [row, col].Rune.ToString () [0],
|
||||
(char)Contents [row, col].Rune.ToString () [1]];
|
||||
|
||||
if (Contents [row, col].Rune.GetColumns () > 1 && col + 1 < Cols)
|
||||
{
|
||||
@@ -359,7 +357,7 @@ internal class WindowsDriver : ConsoleDriver
|
||||
col++;
|
||||
position = row * Cols + col;
|
||||
_outputBuffer [position].Empty = false;
|
||||
_outputBuffer [position].Char = ' ';
|
||||
_outputBuffer [position].Char = ['\0'];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -396,7 +394,7 @@ internal class WindowsDriver : ConsoleDriver
|
||||
{
|
||||
#if HACK_CHECK_WINCHANGED
|
||||
|
||||
_mainLoopDriver.WinChanged -= ChangeWin;
|
||||
_mainLoopDriver.WinChanged -= ChangeWin!;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -405,7 +403,7 @@ internal class WindowsDriver : ConsoleDriver
|
||||
WinConsole?.Cleanup ();
|
||||
WinConsole = null;
|
||||
|
||||
if (!RunningUnitTests && _isWindowsTerminal)
|
||||
if (!RunningUnitTests && _isVirtualTerminal)
|
||||
{
|
||||
// Disable alternative screen buffer.
|
||||
Console.Out.Write (EscSeqUtils.CSI_RestoreCursorAndRestoreAltBufferWithBackscroll);
|
||||
@@ -422,9 +420,9 @@ internal class WindowsDriver : ConsoleDriver
|
||||
{
|
||||
if (WinConsole is { })
|
||||
{
|
||||
// BUGBUG: The results from GetConsoleOutputWindow are incorrect when called from Init.
|
||||
// Our thread in WindowsMainLoop.CheckWin will get the correct results. See #if HACK_CHECK_WINCHANGED
|
||||
Size winSize = WinConsole.GetConsoleOutputWindow (out _);
|
||||
// The results from GetConsoleBufferWindow are correct when called from Init.
|
||||
// Our thread in WindowsMainLoop.CheckWin will get the resize event. See #if HACK_CHECK_WINCHANGED
|
||||
Size winSize = WinConsole.GetConsoleBufferWindow (out _);
|
||||
Cols = winSize.Width;
|
||||
Rows = winSize.Height;
|
||||
OnSizeChanged (new SizeChangedEventArgs (new (Cols, Rows)));
|
||||
@@ -432,7 +430,7 @@ internal class WindowsDriver : ConsoleDriver
|
||||
|
||||
WindowsConsole.SmallRect.MakeEmpty (ref _damageRegion);
|
||||
|
||||
if (_isWindowsTerminal)
|
||||
if (_isVirtualTerminal)
|
||||
{
|
||||
Console.Out.Write (EscSeqUtils.CSI_SaveCursorAndActivateAltBufferNoBackscroll);
|
||||
}
|
||||
@@ -463,7 +461,7 @@ internal class WindowsDriver : ConsoleDriver
|
||||
ClearContents ();
|
||||
|
||||
#if HACK_CHECK_WINCHANGED
|
||||
_mainLoopDriver.WinChanged = ChangeWin;
|
||||
_mainLoopDriver.WinChanged = ChangeWin!;
|
||||
#endif
|
||||
|
||||
if (!RunningUnitTests)
|
||||
@@ -604,13 +602,6 @@ internal class WindowsDriver : ConsoleDriver
|
||||
return;
|
||||
}
|
||||
|
||||
int w = e.Size.Value.Width;
|
||||
|
||||
if (w == Cols - 3 && e.Size.Value.Height < Rows)
|
||||
{
|
||||
w += 3;
|
||||
}
|
||||
|
||||
Left = 0;
|
||||
Top = 0;
|
||||
Cols = e.Size.Value.Width;
|
||||
@@ -618,8 +609,8 @@ internal class WindowsDriver : ConsoleDriver
|
||||
|
||||
if (!RunningUnitTests)
|
||||
{
|
||||
Size newSize = WinConsole.SetConsoleWindow (
|
||||
(short)Math.Max (w, 16),
|
||||
Size newSize = WinConsole!.SetConsoleWindow (
|
||||
(short)Math.Max (e.Size.Value.Width, 16),
|
||||
(short)Math.Max (e.Size.Value.Height, 0));
|
||||
|
||||
Cols = newSize.Width;
|
||||
|
||||
@@ -220,6 +220,7 @@ internal class WindowsMainLoop : IMainLoopDriver
|
||||
private readonly ManualResetEventSlim _winChange = new (false);
|
||||
private bool _winChanged;
|
||||
private Size _windowSize;
|
||||
private Size? _lastWindowSizeBeforeMaximized = null;
|
||||
private void CheckWinChange ()
|
||||
{
|
||||
while (_mainLoop is { })
|
||||
@@ -232,7 +233,22 @@ internal class WindowsMainLoop : IMainLoopDriver
|
||||
while (_mainLoop is { })
|
||||
{
|
||||
Task.Delay (500).Wait ();
|
||||
_windowSize = _winConsole.GetConsoleBufferWindow (out _);
|
||||
Size largestWindowSize = _winConsole!.GetLargestConsoleWindowSize ();
|
||||
_windowSize = _winConsole!.GetConsoleBufferWindow (out _);
|
||||
|
||||
if (_lastWindowSizeBeforeMaximized is null && _windowSize == largestWindowSize)
|
||||
{
|
||||
_lastWindowSizeBeforeMaximized = new (_consoleDriver.Cols, _consoleDriver.Rows);
|
||||
}
|
||||
else if (_lastWindowSizeBeforeMaximized is { } && _windowSize != largestWindowSize)
|
||||
{
|
||||
if (_windowSize != _lastWindowSizeBeforeMaximized)
|
||||
{
|
||||
_windowSize = _lastWindowSizeBeforeMaximized.Value;
|
||||
}
|
||||
|
||||
_lastWindowSizeBeforeMaximized = null;
|
||||
}
|
||||
|
||||
if (_windowSize != Size.Empty
|
||||
&& (_windowSize.Width != _consoleDriver.Cols
|
||||
|
||||
@@ -111,7 +111,7 @@ public class ComboBox : View, IDesignable
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override bool OnSettingScheme (ValueChangingEventArgs<Scheme?> args)
|
||||
protected override bool OnSettingScheme (ValueChangingEventArgs<Scheme> args)
|
||||
{
|
||||
_listview.SetScheme(args.NewValue);
|
||||
return base.OnSettingScheme (args);
|
||||
|
||||
@@ -115,7 +115,7 @@ public class FileDialog : Dialog, IDesignable
|
||||
_btnUp.Text = GetUpButtonText ();
|
||||
_btnUp.Accepting += (s, e) =>
|
||||
{
|
||||
_history.Up ();
|
||||
_history?.Up ();
|
||||
e.Handled = true;
|
||||
};
|
||||
|
||||
@@ -123,7 +123,7 @@ public class FileDialog : Dialog, IDesignable
|
||||
_btnBack.Text = GetBackButtonText ();
|
||||
_btnBack.Accepting += (s, e) =>
|
||||
{
|
||||
_history.Back ();
|
||||
_history?.Back ();
|
||||
e.Handled = true;
|
||||
};
|
||||
|
||||
@@ -131,7 +131,7 @@ public class FileDialog : Dialog, IDesignable
|
||||
_btnForward.Text = GetForwardButtonText ();
|
||||
_btnForward.Accepting += (s, e) =>
|
||||
{
|
||||
_history.Forward ();
|
||||
_history?.Forward ();
|
||||
e.Handled = true;
|
||||
};
|
||||
|
||||
@@ -605,7 +605,7 @@ public class FileDialog : Dialog, IDesignable
|
||||
bool addCurrentStateToHistory,
|
||||
bool setPathText = true,
|
||||
bool clearForward = true,
|
||||
string pathText = null
|
||||
string? pathText = null
|
||||
)
|
||||
{
|
||||
// no change of state
|
||||
@@ -1109,7 +1109,7 @@ public class FileDialog : Dialog, IDesignable
|
||||
bool addCurrentStateToHistory,
|
||||
bool setPathText = true,
|
||||
bool clearForward = true,
|
||||
string pathText = null
|
||||
string? pathText = null
|
||||
)
|
||||
{
|
||||
if (State is SearchState search)
|
||||
|
||||
@@ -264,28 +264,28 @@ public class NumericUpDown<T> : View where T : notnull
|
||||
protected override bool OnDrawingText () { return true; }
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to convert the specified <paramref name="value"/> to type <typeparamref name="T"/>.
|
||||
/// Attempts to convert the specified <paramref name="value"/> to type <typeparamref name="TValue"/>.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type to which the value should be converted.</typeparam>
|
||||
/// <typeparam name="TValue">The type to which the value should be converted.</typeparam>
|
||||
/// <param name="value">The value to convert.</param>
|
||||
/// <param name="result">
|
||||
/// When this method returns, contains the converted value if the conversion succeeded,
|
||||
/// or the default value of <typeparamref name="T"/> if the conversion failed.
|
||||
/// or the default value of <typeparamref name="TValue"/> if the conversion failed.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if the conversion was successful; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public static bool TryConvert<T> (object value, out T? result)
|
||||
public static bool TryConvert<TValue> (object value, out TValue? result)
|
||||
{
|
||||
try
|
||||
{
|
||||
result = (T)Convert.ChangeType (value, typeof (T));
|
||||
result = (TValue)Convert.ChangeType (value, typeof (TValue));
|
||||
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
result = default (T);
|
||||
result = default (TValue);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Drawing;
|
||||
using TerminalGuiFluentTesting;
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
|
||||
namespace Terminal.Gui.Drivers;
|
||||
|
||||
@@ -15,26 +16,26 @@ public class FakeApplicationFactory
|
||||
{
|
||||
var cts = new CancellationTokenSource ();
|
||||
var fakeInput = new FakeNetInput (cts.Token);
|
||||
FakeOutput _output = new ();
|
||||
_output.Size = new (25, 25);
|
||||
FakeOutput output = new ();
|
||||
output.Size = new (25, 25);
|
||||
|
||||
|
||||
IApplication origApp = ApplicationImpl.Instance;
|
||||
|
||||
var sizeMonitor = new FakeSizeMonitor ();
|
||||
|
||||
var v2 = new ApplicationV2 (new FakeNetComponentFactory (fakeInput, _output, sizeMonitor));
|
||||
var v2 = new ApplicationV2 (new FakeNetComponentFactory (fakeInput, output, sizeMonitor));
|
||||
|
||||
ApplicationImpl.ChangeInstance (v2);
|
||||
v2.Init (null,"v2net");
|
||||
|
||||
var d = (ConsoleDriverFacade<ConsoleKeyInfo>)Application.Driver;
|
||||
var d = (ConsoleDriverFacade<ConsoleKeyInfo>)Application.Driver!;
|
||||
sizeMonitor.SizeChanging += (_, e) =>
|
||||
{
|
||||
if (e.Size != null)
|
||||
{
|
||||
var s = e.Size.Value;
|
||||
_output.Size = s;
|
||||
output.Size = s;
|
||||
d.OutputBuffer.SetWindowSize (s.Width, s.Height);
|
||||
}
|
||||
};
|
||||
@@ -95,7 +96,7 @@ class FakeDriverV2 : ConsoleDriverFacade<ConsoleKeyInfo>, IFakeDriverV2
|
||||
{
|
||||
public ConcurrentQueue<ConsoleKeyInfo> InputBuffer { get; }
|
||||
public FakeSizeMonitor SizeMonitor { get; }
|
||||
public OutputBuffer OutputBuffer { get; }
|
||||
public new OutputBuffer OutputBuffer { get; }
|
||||
|
||||
public IConsoleOutput ConsoleOutput { get; }
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Drawing;
|
||||
using System.Text;
|
||||
using Microsoft.Extensions.Logging;
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
|
||||
namespace TerminalGuiFluentTesting;
|
||||
|
||||
@@ -386,7 +387,7 @@ public class GuiTestContext : IDisposable
|
||||
{
|
||||
case V2TestDriver.V2Win:
|
||||
|
||||
_winInput.InputBuffer.Enqueue (
|
||||
_winInput.InputBuffer!.Enqueue (
|
||||
new ()
|
||||
{
|
||||
EventType = WindowsConsole.EventType.Mouse,
|
||||
@@ -410,7 +411,6 @@ public class GuiTestContext : IDisposable
|
||||
|
||||
return WaitUntil (() => _winInput.InputBuffer.IsEmpty);
|
||||
|
||||
break;
|
||||
case V2TestDriver.V2Net:
|
||||
|
||||
int netButton = btn switch
|
||||
@@ -471,8 +471,6 @@ public class GuiTestContext : IDisposable
|
||||
}
|
||||
|
||||
return WaitIteration ();
|
||||
|
||||
;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -699,7 +697,7 @@ public class GuiTestContext : IDisposable
|
||||
down.bKeyDown = true;
|
||||
up.bKeyDown = false;
|
||||
|
||||
_winInput.InputBuffer.Enqueue (
|
||||
_winInput.InputBuffer!.Enqueue (
|
||||
new ()
|
||||
{
|
||||
EventType = WindowsConsole.EventType.Key,
|
||||
@@ -718,7 +716,7 @@ public class GuiTestContext : IDisposable
|
||||
|
||||
private void SendNetKey (ConsoleKeyInfo consoleKeyInfo, bool wait = true)
|
||||
{
|
||||
_netInput.InputBuffer.Enqueue (consoleKeyInfo);
|
||||
_netInput.InputBuffer!.Enqueue (consoleKeyInfo);
|
||||
|
||||
if (wait)
|
||||
{
|
||||
@@ -732,7 +730,7 @@ public class GuiTestContext : IDisposable
|
||||
/// <param name="specialKey"></param>
|
||||
private void SendWindowsKey (ConsoleKeyMapping.VK specialKey)
|
||||
{
|
||||
_winInput.InputBuffer.Enqueue (
|
||||
_winInput.InputBuffer!.Enqueue (
|
||||
new ()
|
||||
{
|
||||
EventType = WindowsConsole.EventType.Key,
|
||||
|
||||
@@ -4,7 +4,7 @@ namespace TerminalGuiFluentTesting;
|
||||
|
||||
internal class TextWriterLogger (TextWriter writer) : ILogger
|
||||
{
|
||||
public IDisposable? BeginScope<TState> (TState state) { return null; }
|
||||
public IDisposable? BeginScope<TState> (TState state) where TState : notnull { return null; }
|
||||
|
||||
public bool IsEnabled (LogLevel logLevel) { return true; }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user