Files
Terminal.Gui/Terminal.Gui/Drivers/NetDriver/NetWinVTConsole.cs
Thomas Nind ab49fb8b43 Fixes 4191 - Rewrite WindowsOutput (#4193)
* Consider width2 chars that are not IsBmp

* Apply same fix in WindowsDriver

* Explicitly use type of local variable

* Revert changes to WindowsDriver

* Assume we are running in a terminal that supports true color by default unless user explicitly forces 16

* Switch to SetAttribute and WriteConsole instead of WriteConsoleOutput for 16 color mode

* Fix some cursor issues (WIP)

* Remove concept of 'dirty rows' from v2 as its never actually used

* Remove damageRegion as it does nothing

* Make string builder to console writing simpler

* Radically simplify Write method

* Simplify conditional logic

* Simplify restoring cursor position

* Reference local variable for console buffer

* Reduce calls to ConsoleWrite by accumulating till attribute changes

* When resizing v2 16 color mode on windows, recreate the back buffer to match its size

* Fixes for VTS enabled

* Fix _lastSize never being assigned

* Fixes VTS for Force16Colors

* Fixes force16Colors in VTS

* Fixes escape sequences always echoing in non-VTS

* Force Force16Colors in non-VTS. It have a bug in adding a newline in the last line

* WIP Add base class for NetOutput

* Abstract away how we change attribute

* WIP - Make WindowsOutput use base class

* WIP working to fix set cursor position

* Remove commented out code

* Fixes legacy output mode

* Fixes size with no alt buffer supported on VTS and size restore after maximized.

* Fix set cursor which also fixes the broken surrogate pairs

* Add force parameter

* Fixes an issue that only happens with Windows Terminal when paste surrogate pairs by press Ctrl+V

* In Windows escape sequences must be sent during the lifetime of the console which is created in input handle

* Ensure flush the input buffer before reset the console

* Flush input buffer before reset console in v2win

* Fixes issue in v2net not being refreshing the menu bar at start

* Only force layout and draw on size changed.

* Fix v2net issue not draw first line by forcing set cursor position

* Set _lastCursorPosition nullable and remove bool force from set cursor position

* Remove force parameter

* Cleanup code

---------

Co-authored-by: BDisp <bd.bdisp@gmail.com>
2025-08-31 09:41:09 -06:00

135 lines
4.7 KiB
C#

#nullable enable
using System.Runtime.InteropServices;
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;
// 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 int STD_ERROR_HANDLE = -12;
private const int STD_INPUT_HANDLE = -10;
private const int STD_OUTPUT_HANDLE = -11;
private readonly nint _errorHandle;
private readonly nint _inputHandle;
private readonly uint _originalErrorConsoleMode;
private readonly uint _originalInputConsoleMode;
private readonly uint _originalOutputConsoleMode;
private readonly nint _outputHandle;
public NetWinVTConsole ()
{
_inputHandle = GetStdHandle (STD_INPUT_HANDLE);
if (!GetConsoleMode (_inputHandle, out uint mode))
{
throw new ApplicationException ($"Failed to get input console mode, error code: {GetLastError ()}.");
}
_originalInputConsoleMode = mode;
if ((mode & ENABLE_VIRTUAL_TERMINAL_INPUT) < ENABLE_VIRTUAL_TERMINAL_INPUT)
{
mode |= ENABLE_VIRTUAL_TERMINAL_INPUT;
if (!SetConsoleMode (_inputHandle, mode))
{
throw new ApplicationException ($"Failed to set input console mode, error code: {GetLastError ()}.");
}
}
_outputHandle = GetStdHandle (STD_OUTPUT_HANDLE);
if (!GetConsoleMode (_outputHandle, out mode))
{
throw new ApplicationException ($"Failed to get output console mode, error code: {GetLastError ()}.");
}
_originalOutputConsoleMode = mode;
if ((mode & (ENABLE_VIRTUAL_TERMINAL_PROCESSING | DISABLE_NEWLINE_AUTO_RETURN)) < DISABLE_NEWLINE_AUTO_RETURN)
{
mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING | DISABLE_NEWLINE_AUTO_RETURN;
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 ()
{
if (!FlushConsoleInputBuffer (_inputHandle))
{
throw new ApplicationException ($"Failed to flush input buffer, error code: {GetLastError ()}.");
}
if (!SetConsoleMode (_inputHandle, _originalInputConsoleMode))
{
throw new ApplicationException ($"Failed to restore input console mode, error code: {GetLastError ()}.");
}
if (!SetConsoleMode (_outputHandle, _originalOutputConsoleMode))
{
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")]
private static extern bool GetConsoleMode (nint hConsoleHandle, out uint lpMode);
[DllImport ("kernel32.dll")]
private static extern uint GetLastError ();
[DllImport ("kernel32.dll", SetLastError = true)]
private static extern nint GetStdHandle (int nStdHandle);
[DllImport ("kernel32.dll")]
private static extern bool SetConsoleMode (nint hConsoleHandle, uint dwMode);
[DllImport ("kernel32.dll", SetLastError = true)]
private static extern bool FlushConsoleInputBuffer (nint hConsoleInput);
}