#nullable enable
using System.Runtime.InteropServices;
// ReSharper disable InconsistentNaming
namespace Terminal.Gui.Drivers;
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
///
/// Definitions for Windows Console API structures and constants.
///
public class WindowsConsole
{
///
/// Standard input handle constant.
///
public const int STD_INPUT_HANDLE = -10;
///
/// Windows Console mode flags.
///
[Flags]
public enum ConsoleModes : uint
{
EnableProcessedInput = 1,
EnableVirtualTerminalProcessing = 4,
EnableMouseInput = 16,
EnableQuickEditMode = 64,
EnableExtendedFlags = 128
}
///
/// Key event record structure.
///
[StructLayout (LayoutKind.Explicit, CharSet = CharSet.Unicode)]
public struct KeyEventRecord
{
[FieldOffset (0)]
[MarshalAs (UnmanagedType.Bool)]
public bool bKeyDown;
[FieldOffset (4)]
[MarshalAs (UnmanagedType.U2)]
public ushort wRepeatCount;
[FieldOffset (6)]
[MarshalAs (UnmanagedType.U2)]
public ConsoleKeyMapping.VK wVirtualKeyCode;
[FieldOffset (8)]
[MarshalAs (UnmanagedType.U2)]
public ushort wVirtualScanCode;
[FieldOffset (10)]
public char UnicodeChar;
[FieldOffset (12)]
[MarshalAs (UnmanagedType.U4)]
public ControlKeyState dwControlKeyState;
public readonly override string ToString ()
{
return
$"[KeyEventRecord({(bKeyDown ? "down" : "up")},{wRepeatCount},{wVirtualKeyCode},{wVirtualScanCode},{new Rune (UnicodeChar).MakePrintable ()},{dwControlKeyState})]";
}
}
[Flags]
public enum ButtonState
{
NoButtonPressed = 0,
Button1Pressed = 1,
Button2Pressed = 4,
Button3Pressed = 8,
Button4Pressed = 16,
RightmostButtonPressed = 2
}
[Flags]
public enum ControlKeyState
{
NoControlKeyPressed = 0,
RightAltPressed = 1,
LeftAltPressed = 2,
RightControlPressed = 4,
LeftControlPressed = 8,
ShiftPressed = 16,
NumlockOn = 32,
ScrolllockOn = 64,
CapslockOn = 128,
EnhancedKey = 256
}
[Flags]
public enum EventFlags
{
NoEvent = 0,
MouseMoved = 1,
DoubleClick = 2,
MouseWheeled = 4,
MouseHorizontalWheeled = 8
}
[StructLayout (LayoutKind.Explicit)]
public struct MouseEventRecord
{
[FieldOffset (0)]
public Coord MousePosition;
[FieldOffset (4)]
public ButtonState ButtonState;
[FieldOffset (8)]
public ControlKeyState ControlKeyState;
[FieldOffset (12)]
public EventFlags EventFlags;
public readonly override string ToString () { return $"[Mouse{MousePosition},{ButtonState},{ControlKeyState},{EventFlags}]"; }
}
public struct WindowBufferSizeRecord (short x, short y)
{
public Coord _size = new (x, y);
public readonly override string ToString () { return $"[WindowBufferSize{_size}"; }
}
[StructLayout (LayoutKind.Sequential)]
public struct MenuEventRecord
{
public uint dwCommandId;
}
[StructLayout (LayoutKind.Sequential)]
public struct FocusEventRecord
{
public uint bSetFocus;
}
public enum EventType : ushort
{
Focus = 0x10,
Key = 0x1,
Menu = 0x8,
Mouse = 2,
WindowBufferSize = 4
}
[StructLayout (LayoutKind.Explicit)]
public struct InputRecord
{
[FieldOffset (0)]
public EventType EventType;
[FieldOffset (4)]
public KeyEventRecord KeyEvent;
[FieldOffset (4)]
public MouseEventRecord MouseEvent;
[FieldOffset (4)]
public WindowBufferSizeRecord WindowBufferSizeEvent;
[FieldOffset (4)]
public MenuEventRecord MenuEvent;
[FieldOffset (4)]
public FocusEventRecord FocusEvent;
public readonly override string ToString ()
{
return (EventType switch
{
EventType.Focus => FocusEvent.ToString (),
EventType.Key => KeyEvent.ToString (),
EventType.Menu => MenuEvent.ToString (),
EventType.Mouse => MouseEvent.ToString (),
EventType.WindowBufferSize => WindowBufferSizeEvent.ToString (),
_ => "Unknown event type: " + EventType
})!;
}
}
[StructLayout (LayoutKind.Sequential)]
public struct Coord
{
public short X;
public short Y;
public Coord (short x, short y)
{
X = x;
Y = y;
}
public readonly override string ToString () { return $"({X},{Y})"; }
}
[StructLayout (LayoutKind.Explicit, CharSet = CharSet.Unicode)]
public struct CharUnion
{
[FieldOffset (0)]
public char UnicodeChar;
[FieldOffset (0)]
public byte AsciiChar;
}
[StructLayout (LayoutKind.Explicit, CharSet = CharSet.Unicode)]
public struct CharInfo
{
[FieldOffset (0)]
public CharUnion Char;
[FieldOffset (2)]
public ushort Attributes;
}
[StructLayout (LayoutKind.Sequential)]
public struct SmallRect
{
public short Left;
public short Top;
public short Right;
public short Bottom;
public SmallRect (short left, short top, short right, short bottom)
{
Left = left;
Top = top;
Right = right;
Bottom = bottom;
}
public static void MakeEmpty (ref SmallRect rect) { rect.Left = -1; }
public static void Update (ref SmallRect rect, short col, short row)
{
if (rect.Left == -1)
{
rect.Left = rect.Right = col;
rect.Bottom = rect.Top = row;
return;
}
if (col >= rect.Left && col <= rect.Right && row >= rect.Top && row <= rect.Bottom)
{
return;
}
if (col < rect.Left)
{
rect.Left = col;
}
if (col > rect.Right)
{
rect.Right = col;
}
if (row < rect.Top)
{
rect.Top = row;
}
if (row > rect.Bottom)
{
rect.Bottom = row;
}
}
public readonly override string ToString () { return $"Left={Left},Top={Top},Right={Right},Bottom={Bottom}"; }
}
[StructLayout (LayoutKind.Sequential)]
public struct ConsoleKeyInfoEx
{
public ConsoleKeyInfo ConsoleKeyInfo;
public bool CapsLock;
public bool NumLock;
public bool ScrollLock;
public ConsoleKeyInfoEx (ConsoleKeyInfo consoleKeyInfo, bool capslock, bool numlock, bool scrolllock)
{
ConsoleKeyInfo = consoleKeyInfo;
CapsLock = capslock;
NumLock = numlock;
ScrollLock = scrolllock;
}
///
/// Prints a ConsoleKeyInfoEx structure
///
///
///
public readonly string ToString (ConsoleKeyInfoEx ex)
{
var ke = new Key ((KeyCode)ex.ConsoleKeyInfo.KeyChar);
var sb = new StringBuilder ();
sb.Append ($"Key: {(KeyCode)ex.ConsoleKeyInfo.Key} ({ex.ConsoleKeyInfo.Key})");
sb.Append ((ex.ConsoleKeyInfo.Modifiers & ConsoleModifiers.Shift) != 0 ? " | Shift" : string.Empty);
sb.Append ((ex.ConsoleKeyInfo.Modifiers & ConsoleModifiers.Control) != 0 ? " | Control" : string.Empty);
sb.Append ((ex.ConsoleKeyInfo.Modifiers & ConsoleModifiers.Alt) != 0 ? " | Alt" : string.Empty);
sb.Append ($", KeyChar: {ke.AsRune.MakePrintable ()} ({(uint)ex.ConsoleKeyInfo.KeyChar}) ");
sb.Append (ex.CapsLock ? "caps," : string.Empty);
sb.Append (ex.NumLock ? "num," : string.Empty);
sb.Append (ex.ScrollLock ? "scroll," : string.Empty);
string s = sb.ToString ().TrimEnd (',').TrimEnd (' ');
return $"[ConsoleKeyInfoEx({s})]";
}
}
[StructLayout (LayoutKind.Sequential)]
public struct ConsoleCursorInfo
{
///
/// The percentage of the character cell that is filled by the cursor.This value is between 1 and 100.
/// The cursor appearance varies, ranging from completely filling the cell to showing up as a horizontal
/// line at the bottom of the cell.
///
public uint dwSize;
public bool bVisible;
}
// See: https://github.com/gui-cs/Terminal.Gui/issues/357
[StructLayout (LayoutKind.Sequential)]
public struct CONSOLE_SCREEN_BUFFER_INFOEX
{
public uint cbSize;
public Coord dwSize;
public Coord dwCursorPosition;
public ushort wAttributes;
public SmallRect srWindow;
public Coord dwMaximumWindowSize;
public ushort wPopupAttributes;
public bool bFullscreenSupported;
[MarshalAs (UnmanagedType.ByValArray, SizeConst = 16)]
public COLORREF [] ColorTable;
}
[StructLayout (LayoutKind.Explicit, Size = 4)]
public struct COLORREF
{
public COLORREF (byte r, byte g, byte b)
{
Value = 0;
R = r;
G = g;
B = b;
}
public COLORREF (uint value)
{
R = 0;
G = 0;
B = 0;
Value = value & 0x00FFFFFF;
}
[FieldOffset (0)]
public byte R;
[FieldOffset (1)]
public byte G;
[FieldOffset (2)]
public byte B;
[FieldOffset (0)]
public uint Value;
}
}