Kawe Mazidjatari 3e9f405474 Fix MSVC error 'C2280' and 'C2955'
Fix 'attempting to reference a deleted function'.
Fix 'use of class requires a template argument list'.
2023-03-19 17:58:01 +01:00

564 lines
15 KiB
C++

#include "stdafx.h"
#include "Console.h"
#include "ConsoleStream.h"
namespace System
{
// This holds the global std handle for the input stream
__ConsoleInit Console::ConsoleInstance /*= __ConsoleInit()*/;
enum class ControlKeyState
{
RightAltPressed = 0x0001,
LeftAltPressed = 0x0002,
RightCtrlPressed = 0x0004,
LeftCtrlPressed = 0x0008,
ShiftPressed = 0x0010,
NumLockOn = 0x0020,
ScrollLockOn = 0x0040,
CapsLockOn = 0x0080,
EnhancedKey = 0x0100
};
void Console::Beep()
{
::Beep(800, 200);
}
void Console::Beep(uint32_t Frequency, uint32_t Duration)
{
::Beep(Frequency, Duration);
}
void Console::Clear()
{
auto hStdOut = ((IO::ConsoleStream*)ConsoleInstance.Out.GetBaseStream())->GetStreamHandle();
CONSOLE_SCREEN_BUFFER_INFO cSBI{};
GetConsoleScreenBufferInfo(hStdOut, &cSBI);
COORD cScreen{};
int conSize = (cSBI.dwSize.X * cSBI.dwSize.Y);
DWORD nCellsWritten = 0;
FillConsoleOutputCharacterA(hStdOut, ' ', conSize, cScreen, &nCellsWritten);
nCellsWritten = 0;
FillConsoleOutputAttribute(hStdOut, FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED, conSize, cScreen, &nCellsWritten);
SetConsoleCursorPosition(hStdOut, cScreen);
}
void Console::ClearLine()
{
auto hStdOut = ((IO::ConsoleStream*)ConsoleInstance.Out.GetBaseStream())->GetStreamHandle();
CONSOLE_SCREEN_BUFFER_INFO cSBI{};
GetConsoleScreenBufferInfo(hStdOut, &cSBI);
cSBI.dwCursorPosition.X = 0;
DWORD nCellsWritten = 0;
FillConsoleOutputCharacterA(hStdOut, ' ', cSBI.dwSize.X, cSBI.dwCursorPosition, &nCellsWritten);
SetConsoleCursorPosition(hStdOut, cSBI.dwCursorPosition);
}
void Console::ResetColor()
{
Console::SetColors(ConsoleColor::Gray, ConsoleColor::Black);
}
void Console::SetForegroundColor(ConsoleColor Color)
{
auto hStdOut = ((IO::ConsoleStream*)ConsoleInstance.Out.GetBaseStream())->GetStreamHandle();
CONSOLE_SCREEN_BUFFER_INFO cSBI{};
GetConsoleScreenBufferInfo(hStdOut, &cSBI);
auto nColor = Console::ConsoleColorToColorAttribute(Color, false);
int16_t Attrs = cSBI.wAttributes;
Attrs &= ~((int16_t)Console::ForegroundMask);
Attrs = (int16_t)(((uint32_t)(uint16_t)Attrs) | ((uint32_t)(uint16_t)nColor));
SetConsoleTextAttribute(hStdOut, Attrs);
}
void Console::SetBackgroundColor(ConsoleColor Color)
{
auto hStdOut = ((IO::ConsoleStream*)ConsoleInstance.Out.GetBaseStream())->GetStreamHandle();
CONSOLE_SCREEN_BUFFER_INFO cSBI{};
GetConsoleScreenBufferInfo(hStdOut, &cSBI);
auto nColor = Console::ConsoleColorToColorAttribute(Color, true);
int16_t Attrs = cSBI.wAttributes;
Attrs &= ~((int16_t)Console::BackgroundMask);
Attrs = (int16_t)(((uint32_t)(uint16_t)Attrs) | ((uint32_t)(uint16_t)nColor));
SetConsoleTextAttribute(hStdOut, Attrs);
}
void Console::SetColors(ConsoleColor Foreground, ConsoleColor Background)
{
auto hStdOut = ((IO::ConsoleStream*)ConsoleInstance.Out.GetBaseStream())->GetStreamHandle();
CONSOLE_SCREEN_BUFFER_INFO cSBI{};
GetConsoleScreenBufferInfo(hStdOut, &cSBI);
auto nColor = Console::ConsoleColorToColorAttribute(Foreground, false);
auto nColor2 = Console::ConsoleColorToColorAttribute(Background, true);
int16_t Attrs = cSBI.wAttributes;
Attrs &= ~((int16_t)Console::ForegroundMask);
Attrs = (int16_t)(((uint32_t)(uint16_t)Attrs) | ((uint32_t)(uint16_t)nColor));
Attrs &= ~((int16_t)Console::BackgroundMask);
Attrs = (int16_t)(((uint32_t)(uint16_t)Attrs) | ((uint32_t)(uint16_t)nColor2));
SetConsoleTextAttribute(hStdOut, Attrs);
}
void Console::SetBufferSize(uint32_t Width, uint32_t Height)
{
COORD cScreen;
cScreen.X = (SHORT)Width;
cScreen.Y = (SHORT)Height;
SetConsoleScreenBufferSize(((IO::ConsoleStream*)ConsoleInstance.Out.GetBaseStream())->GetStreamHandle(), cScreen);
}
void Console::SetCursorPosition(uint32_t Left, uint32_t Right)
{
auto hStdOut = ((IO::ConsoleStream*)ConsoleInstance.Out.GetBaseStream())->GetStreamHandle();
COORD cScreen;
cScreen.X = (SHORT)Left;
cScreen.Y = (SHORT)Right;
SetConsoleCursorPosition(hStdOut, cScreen);
}
void Console::SetWindowSize(uint32_t Width, uint32_t Height)
{
auto hStdOut = ((IO::ConsoleStream*)ConsoleInstance.Out.GetBaseStream())->GetStreamHandle();
CONSOLE_SCREEN_BUFFER_INFO cSBI{};
GetConsoleScreenBufferInfo(hStdOut, &cSBI);
COORD cScreen;
cScreen.X = cSBI.dwSize.X;
cScreen.Y = cSBI.dwSize.Y;
bool nBufferResize = false;
if (cSBI.dwSize.X < (SHORT)(cSBI.srWindow.Left + Width))
{
cScreen.X = (SHORT)(cSBI.srWindow.Left + Width);
nBufferResize = true;
}
if (cSBI.dwSize.Y < (SHORT)(cSBI.srWindow.Top + Height))
{
cScreen.Y = (SHORT)(cSBI.srWindow.Top + Height);
nBufferResize = true;
}
if (nBufferResize)
SetConsoleScreenBufferSize(hStdOut, cScreen);
SMALL_RECT srWindow = cSBI.srWindow;
srWindow.Bottom = (SHORT)(srWindow.Top + Height - 1);
srWindow.Right = (SHORT)(srWindow.Left + Width - 1);
auto hResult = SetConsoleWindowInfo(hStdOut, true, &srWindow);
if (!hResult)
SetConsoleScreenBufferSize(hStdOut, cSBI.dwSize);
}
void Console::SetWindowPosition(uint32_t Left, uint32_t Top)
{
auto hStdOut = ((IO::ConsoleStream*)ConsoleInstance.Out.GetBaseStream())->GetStreamHandle();
CONSOLE_SCREEN_BUFFER_INFO cSBI{};
GetConsoleScreenBufferInfo(hStdOut, &cSBI);
SMALL_RECT srWindow = cSBI.srWindow;
srWindow.Bottom -= (SHORT)(srWindow.Top - Top);
srWindow.Right -= (SHORT)(srWindow.Left - Left);
srWindow.Left = (SHORT)Left;
srWindow.Top = (SHORT)Top;
SetConsoleWindowInfo(hStdOut, TRUE, &srWindow);
}
void Console::SetFontSize(uint32_t Width, uint32_t Height, uint32_t Weight)
{
auto hStdOut = ((IO::ConsoleStream*)ConsoleInstance.Out.GetBaseStream())->GetStreamHandle();
CONSOLE_FONT_INFOEX cFont;
cFont.cbSize = sizeof(cFont);
GetCurrentConsoleFontEx(hStdOut, false, &cFont);
cFont.dwFontSize.X = Width;
cFont.dwFontSize.Y = Height;
cFont.FontWeight = Weight;
SetCurrentConsoleFontEx(hStdOut, false, &cFont);
}
void Console::SetTitle(const String& Value)
{
SetConsoleTitleA((const char*)Value);
}
void Console::SetTitle(const char* Value)
{
SetConsoleTitleA(Value);
}
void Console::SetCursorVisible(bool Visible)
{
auto hStdOut = ((IO::ConsoleStream*)ConsoleInstance.Out.GetBaseStream())->GetStreamHandle();
CONSOLE_CURSOR_INFO cCI{};
GetConsoleCursorInfo(hStdOut, &cCI);
cCI.bVisible = Visible;
SetConsoleCursorInfo(hStdOut, &cCI);
}
void Console::MoveBufferArea(uint32_t SourceLeft, uint32_t SourceTop, uint32_t SourceWidth, uint32_t SourceHeight, uint32_t TargetLeft, uint32_t TargetTop, char SourceChar, ConsoleColor SourceForeColor, ConsoleColor SourceBackColor)
{
auto hStdOut = ((IO::ConsoleStream*)ConsoleInstance.Out.GetBaseStream())->GetStreamHandle();
CONSOLE_SCREEN_BUFFER_INFO cSBI{};
GetConsoleScreenBufferInfo(hStdOut, &cSBI);
COORD BufferSize = cSBI.dwSize;
COORD BufferCoord{};
SMALL_RECT ReadRegion{};
if (SourceWidth == 0 || SourceHeight == 0)
return;
auto CharBuffer = std::make_unique<CHAR_INFO[]>(SourceWidth * SourceHeight);
BufferSize.X = (SHORT)SourceWidth;
BufferSize.Y = (SHORT)SourceHeight;
ReadRegion.Left = (SHORT)SourceLeft;
ReadRegion.Right = (SHORT)(SourceLeft + SourceWidth - 1);
ReadRegion.Top = (SHORT)SourceTop;
ReadRegion.Bottom = (SHORT)(SourceTop + SourceHeight - 1);
ReadConsoleOutput(hStdOut, CharBuffer.get(), BufferSize, BufferCoord, &ReadRegion);
COLORREF NativeColor = (Console::ConsoleColorToColorAttribute(SourceBackColor, true) | Console::ConsoleColorToColorAttribute(SourceForeColor, false));
DWORD nWrite = 0;
COORD WriteCoord{};
WriteCoord.X = (SHORT)SourceLeft;
SHORT Attr = (SHORT)NativeColor;
for (uint32_t i = SourceTop; i < (SourceTop + SourceHeight); i++)
{
WriteCoord.Y = (SHORT)i;
FillConsoleOutputCharacterA(hStdOut, SourceChar, SourceWidth, WriteCoord, &nWrite);
FillConsoleOutputAttribute(hStdOut, Attr, SourceWidth, WriteCoord, &nWrite);
}
SMALL_RECT WriteRegion{};
WriteRegion.Left = (SHORT)TargetLeft;
WriteRegion.Right = (SHORT)(TargetLeft + SourceWidth);
WriteRegion.Top = (SHORT)TargetTop;
WriteRegion.Bottom = (SHORT)(TargetTop + SourceHeight);
WriteConsoleOutput(hStdOut, CharBuffer.get(), BufferSize, BufferCoord, &WriteRegion);
}
void Console::SetMaximizeBoxVisible(bool Visible)
{
auto hConsole = GetConsoleWindow();
auto Style = GetWindowLong(hConsole, GWL_STYLE);
if (Visible)
Style |= WS_MAXIMIZEBOX;
else
Style &= ~WS_MAXIMIZEBOX;
SetWindowLong(hConsole, GWL_STYLE, Style);
}
void Console::SetMinimizeBoxVisible(bool Visible)
{
auto hConsole = GetConsoleWindow();
auto Style = GetWindowLong(hConsole, GWL_STYLE);
if (Visible)
Style |= WS_MINIMIZEBOX;
else
Style &= ~WS_MINIMIZEBOX;
SetWindowLong(hConsole, GWL_STYLE, Style);
}
void Console::SetWindowResizable(bool Resizable)
{
auto hConsole = GetConsoleWindow();
auto Style = GetWindowLong(hConsole, GWL_STYLE);
if (Resizable)
Style |= WS_SIZEBOX;
else
Style &= ~WS_SIZEBOX;
SetWindowLong(hConsole, GWL_STYLE, Style);
}
void Console::CenterWindow()
{
auto hConsole = GetConsoleWindow();
auto hMonitor = MonitorFromWindow(hConsole, MONITOR_DEFAULTTONEAREST);
if (hMonitor)
{
MONITORINFO Info;
Info.cbSize = sizeof(Info);
if (GetMonitorInfo(hMonitor, &Info))
{
RECT cRect{};
GetWindowRect(hConsole, &cRect);
auto Width = (cRect.right - cRect.left);
auto Height = (cRect.bottom - cRect.top);
auto X = (Info.rcWork.left + Info.rcWork.right) / 2 - Width / 2;
auto Y = (Info.rcWork.top + Info.rcWork.bottom) / 2 - Height / 2;
SetWindowPos(hConsole, NULL, X, Y, 0, 0, SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOSIZE);
}
}
}
void Console::RemapConsoleColor(ConsoleColor Source, uint8_t R, uint8_t G, uint8_t B)
{
auto hStdOut = ((IO::ConsoleStream*)ConsoleInstance.Out.GetBaseStream())->GetStreamHandle();
CONSOLE_SCREEN_BUFFER_INFOEX cBuffer;
cBuffer.cbSize = sizeof(cBuffer);
GetConsoleScreenBufferInfoEx(hStdOut, &cBuffer);
// GetConsoleScreenBufferInfoEx returns one short here, so we keep resizing each time...
cBuffer.srWindow.Bottom++;
cBuffer.srWindow.Right++;
cBuffer.ColorTable[(int8_t)Source] = RGB(R, G, B);
SetConsoleScreenBufferInfoEx(hStdOut, &cBuffer);
}
void Console::RemapAllConsoleColors(std::initializer_list<System::ConsoleColor> Colors)
{
static_assert(sizeof(Colors) == 16, "You must specify all 16 colors");
auto hStdOut = ((IO::ConsoleStream*)ConsoleInstance.Out.GetBaseStream())->GetStreamHandle();
CONSOLE_SCREEN_BUFFER_INFOEX cBuffer;
cBuffer.cbSize = sizeof(cBuffer);
GetConsoleScreenBufferInfoEx(hStdOut, &cBuffer);
// GetConsoleScreenBufferInfoEx returns one short here, so we keep resizing each time...
cBuffer.srWindow.Bottom++;
cBuffer.srWindow.Right++;
std::memcpy(cBuffer.ColorTable, Colors.begin(), sizeof(uint32_t) * 16);
SetConsoleScreenBufferInfoEx(hStdOut, &cBuffer);
}
String Console::GetTitle()
{
char Buffer[2048]{};
GetConsoleTitleA(Buffer, 2048); // Honestly it would be too big at 256...
return String(Buffer);
}
bool Console::GetCursorVisible()
{
auto hStdOut = ((IO::ConsoleStream*)ConsoleInstance.Out.GetBaseStream())->GetStreamHandle();
CONSOLE_CURSOR_INFO cCI{};
GetConsoleCursorInfo(hStdOut, &cCI);
return cCI.bVisible;
}
ConsoleColor Console::GetForegroundColor()
{
auto hStdOut = ((IO::ConsoleStream*)ConsoleInstance.Out.GetBaseStream())->GetStreamHandle();
CONSOLE_SCREEN_BUFFER_INFO cSBI{};
GetConsoleScreenBufferInfo(hStdOut, &cSBI);
return Console::ColorAttributeToConsoleColor((int16_t)(cSBI.wAttributes & Console::ForegroundMask));
}
ConsoleColor Console::GetBackgroundColor()
{
auto hStdOut = ((IO::ConsoleStream*)ConsoleInstance.Out.GetBaseStream())->GetStreamHandle();
CONSOLE_SCREEN_BUFFER_INFO cSBI{};
GetConsoleScreenBufferInfo(hStdOut, &cSBI);
return Console::ColorAttributeToConsoleColor((int16_t)(cSBI.wAttributes & Console::BackgroundMask));
}
void Console::Header(const char* Heading, ConsoleColor Color)
{
Console::SetColors(Color, ConsoleColor::DarkGray);
auto sLen = strlen(Heading);
char HeaderBuffer[21];
std::memset(HeaderBuffer + 1, ' ', 19);
HeaderBuffer[0] = '[';
HeaderBuffer[20] = (char)0;
HeaderBuffer[sLen + 1] = ']';
std::memcpy(HeaderBuffer + 1, Heading, sLen);
ConsoleInstance.Out.Write((const char*)HeaderBuffer);
Console::ResetColor();
ConsoleInstance.Out.Write(": ");
}
void Console::Progress(const char* Heading, ConsoleColor Color, uint32_t Width, uint32_t Progress)
{
Progress = min(Progress, 100);
ConsoleInstance.Out.Write("\r");
Console::Header(Heading, Color);
String Buffer(Width + 2, '\0', false);
Buffer.Append("[");
uint32_t Blocks = min((uint32_t)((Progress / 100.f) * Width), Width);
for (uint32_t i = 0; i < Width; i++)
{
if (i < Blocks)
Buffer.Append("=");
else if (i == Blocks)
Buffer.Append(">");
else
Buffer.Append(" ");
}
Buffer.Append("]");
ConsoleInstance.Out.Write(Buffer);
}
int32_t Console::Read()
{
return ConsoleInstance.In.Read();
}
ConsoleKeyInfo Console::ReadKey(bool Intercept)
{
INPUT_RECORD iRecord{};
DWORD rRead = 0;
auto hStdIn = ((IO::ConsoleStream*)ConsoleInstance.In.GetBaseStream())->GetStreamHandle();
while (true)
{
ReadConsoleInputA(hStdIn, &iRecord, 1, &rRead);
int16_t kCode = iRecord.Event.KeyEvent.wVirtualKeyCode;
if (!IsKeyDownEvent(iRecord))
if (kCode != AltVKCode)
continue;
char Ch = (char)iRecord.Event.KeyEvent.uChar.AsciiChar;
if (Ch == 0)
if (IsModKey(iRecord))
continue;
ConsoleKey key = (ConsoleKey)kCode;
if (IsAltKeyDown(iRecord) && ((key >= ConsoleKey::NumPad0 && key <= ConsoleKey::NumPad9) || (key == ConsoleKey::Clear) || (key == ConsoleKey::Insert) || (key >= ConsoleKey::PageUp && key <= ConsoleKey::DownArrow)))
continue;
// We passed all checks
break;
}
// Calculate key status
auto State = iRecord.Event.KeyEvent.dwControlKeyState;
bool Shift = (State & (uint32_t)ControlKeyState::ShiftPressed) != 0;
bool Alt = (State & ((uint32_t)ControlKeyState::LeftAltPressed | (uint32_t)ControlKeyState::RightAltPressed)) != 0;
bool Control = (State & ((uint32_t)ControlKeyState::LeftCtrlPressed | (uint32_t)ControlKeyState::RightCtrlPressed)) != 0;
if (!Intercept)
{
char iBuffer[] = { iRecord.Event.KeyEvent.uChar.AsciiChar, 0 };
Console::Write(iBuffer);
}
return ConsoleKeyInfo((char)iRecord.Event.KeyEvent.uChar.AsciiChar, (ConsoleKey)iRecord.Event.KeyEvent.wVirtualKeyCode, Shift, Alt, Control);
}
String Console::ReadLine()
{
return ConsoleInstance.In.ReadLine();
}
bool Console::IsKeyDownEvent(INPUT_RECORD iRecord)
{
return (iRecord.EventType == KEY_EVENT && iRecord.Event.KeyEvent.bKeyDown);
}
bool Console::IsModKey(INPUT_RECORD iRecord)
{
int16_t keyCode = iRecord.Event.KeyEvent.wVirtualKeyCode;
return ((keyCode >= 0x10 && keyCode <= 0x12) || keyCode == 0x14 || keyCode == 0x90 || keyCode == 0x91);
}
bool Console::IsAltKeyDown(INPUT_RECORD iRecord)
{
return ((iRecord.Event.KeyEvent.dwControlKeyState) & ((uint32_t)ControlKeyState::LeftAltPressed | (uint32_t)ControlKeyState::RightAltPressed)) != 0;
}
ConsoleColor Console::ColorAttributeToConsoleColor(int16_t Attribute)
{
if ((Attribute & Console::BackgroundMask) != 0)
Attribute = (int32_t)(((int32_t)Attribute) >> 4);
return ConsoleColor(Attribute);
}
int16_t Console::ConsoleColorToColorAttribute(ConsoleColor Color, bool isBackground)
{
auto Result = (int16_t)Color;
if (isBackground)
Result = (int16_t)((int32_t)Result << 4);
return Result;
}
}