#include "Miscellaneous/Console.h" #include #if PLATFORM_WINDOWS # undef TEXT # include #elif PLATFORM_LINUX # include # include #endif NAMESPACE_REDCRAFT_BEGIN NAMESPACE_MODULE_BEGIN(Redcraft) NAMESPACE_MODULE_BEGIN(Utility) #if PLATFORM_WINDOWS NODISCARD bool InitANSIConsole() { static bool bResult = [] { HANDLE Console = GetStdHandle(STD_OUTPUT_HANDLE); if (Console == INVALID_HANDLE_VALUE) return false; DWORD ConsoleMode = 0; if (!GetConsoleMode(Console, &ConsoleMode)) return false; ConsoleMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; if (!SetConsoleMode(Console, ConsoleMode)) return false; return true; } (); return bResult; } #endif EColor GForegroundColor = EColor::Default; EColor GBackgroundColor = EColor::Default; EColor GetForegroundColor() { # if PLATFORM_WINDOWS { if (InitANSIConsole()) return GForegroundColor; const HANDLE Console = GetStdHandle(STD_OUTPUT_HANDLE); if (Console == INVALID_HANDLE_VALUE) return EColor::Default; CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo; if (!GetConsoleScreenBufferInfo(Console, &ConsoleInfo)) return EColor::Default; const WORD Color = ConsoleInfo.wAttributes; EColor Result = EColor::Black; if (Color & FOREGROUND_RED) Result |= EColor::Red; if (Color & FOREGROUND_GREEN) Result |= EColor::Green; if (Color & FOREGROUND_BLUE) Result |= EColor::Blue; if (Color & FOREGROUND_INTENSITY) Result |= EColor::Intensity; return Result; } # endif return GForegroundColor; } EColor GetBackgroundColor() { # if PLATFORM_WINDOWS { if (InitANSIConsole()) return GBackgroundColor; const HANDLE Console = GetStdHandle(STD_OUTPUT_HANDLE); if (Console == INVALID_HANDLE_VALUE) return EColor::Default; CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo; if (!GetConsoleScreenBufferInfo(Console, &ConsoleInfo)) return EColor::Default; const WORD Color = ConsoleInfo.wAttributes; EColor Result = EColor::Black; if (Color & BACKGROUND_RED) Result |= EColor::Red; if (Color & BACKGROUND_GREEN) Result |= EColor::Green; if (Color & BACKGROUND_BLUE) Result |= EColor::Blue; if (Color & BACKGROUND_INTENSITY) Result |= EColor::Intensity; return Result; } # endif return GBackgroundColor; } EColor SetForegroundColor(EColor InColor) { if (IsOutputRedirected()) return GetForegroundColor(); # if PLATFORM_WINDOWS { if (!InitANSIConsole()) { const HANDLE Console = GetStdHandle(STD_OUTPUT_HANDLE); if (Console == INVALID_HANDLE_VALUE) return GetForegroundColor(); CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo; if (!GetConsoleScreenBufferInfo(Console, &ConsoleInfo)) return GetForegroundColor(); WORD Color = ConsoleInfo.wAttributes & ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY); if (InColor == EColor::Default) InColor = EColor::White; if (!!(InColor & EColor::Red)) Color |= FOREGROUND_RED; if (!!(InColor & EColor::Green)) Color |= FOREGROUND_GREEN; if (!!(InColor & EColor::Blue)) Color |= FOREGROUND_BLUE; if (!!(InColor & EColor::Intensity)) Color |= FOREGROUND_INTENSITY; if (!SetConsoleTextAttribute(Console, Color)) return GetForegroundColor(); return InColor; } } # endif # if PLATFORM_WINDOWS || PLATFORM_LINUX { int Result; switch (InColor) { case EColor::Black: Result = std::fputs("\033[30m", stdout); break; case EColor::Red: Result = std::fputs("\033[31m", stdout); break; case EColor::Green: Result = std::fputs("\033[32m", stdout); break; case EColor::Yellow: Result = std::fputs("\033[33m", stdout); break; case EColor::Blue: Result = std::fputs("\033[34m", stdout); break; case EColor::Magenta: Result = std::fputs("\033[35m", stdout); break; case EColor::Cyan: Result = std::fputs("\033[36m", stdout); break; case EColor::White: Result = std::fputs("\033[37m", stdout); break; case EColor::BrightBlack: Result = std::fputs("\033[90m", stdout); break; case EColor::BrightRed: Result = std::fputs("\033[91m", stdout); break; case EColor::BrightGreen: Result = std::fputs("\033[92m", stdout); break; case EColor::BrightYellow: Result = std::fputs("\033[93m", stdout); break; case EColor::BrightBlue: Result = std::fputs("\033[94m", stdout); break; case EColor::BrightMagenta: Result = std::fputs("\033[95m", stdout); break; case EColor::BrightCyan: Result = std::fputs("\033[96m", stdout); break; case EColor::BrightWhite: Result = std::fputs("\033[97m", stdout); break; default: Result = std::fputs("\033[39m", stdout); break; } if (Result == EOF) return GetForegroundColor(); return GForegroundColor = InColor; } # endif return GetForegroundColor(); } EColor SetBackgroundColor(EColor InColor) { if (IsOutputRedirected()) return GetBackgroundColor(); # if PLATFORM_WINDOWS { if (!InitANSIConsole()) { const HANDLE Console = GetStdHandle(STD_OUTPUT_HANDLE); if (Console == INVALID_HANDLE_VALUE) return GetBackgroundColor(); CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo; if (!GetConsoleScreenBufferInfo(Console, &ConsoleInfo)) return GetBackgroundColor(); WORD Color = ConsoleInfo.wAttributes & ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY); if (InColor == EColor::Default) InColor = EColor::Black; if (!!(InColor & EColor::Red)) Color |= BACKGROUND_RED; if (!!(InColor & EColor::Green)) Color |= BACKGROUND_GREEN; if (!!(InColor & EColor::Blue)) Color |= BACKGROUND_BLUE; if (!!(InColor & EColor::Intensity)) Color |= BACKGROUND_INTENSITY; if (!SetConsoleTextAttribute(Console, Color)) return GetBackgroundColor(); return InColor; } } # endif # if PLATFORM_WINDOWS || PLATFORM_LINUX { int Result; switch (InColor) { case EColor::Black: Result = std::fputs("\033[40m", stdout); break; case EColor::Red: Result = std::fputs("\033[41m", stdout); break; case EColor::Green: Result = std::fputs("\033[42m", stdout); break; case EColor::Yellow: Result = std::fputs("\033[43m", stdout); break; case EColor::Blue: Result = std::fputs("\033[44m", stdout); break; case EColor::Magenta: Result = std::fputs("\033[45m", stdout); break; case EColor::Cyan: Result = std::fputs("\033[46m", stdout); break; case EColor::White: Result = std::fputs("\033[47m", stdout); break; case EColor::BrightBlack: Result = std::fputs("\033[100m", stdout); break; case EColor::BrightRed: Result = std::fputs("\033[101m", stdout); break; case EColor::BrightGreen: Result = std::fputs("\033[102m", stdout); break; case EColor::BrightYellow: Result = std::fputs("\033[103m", stdout); break; case EColor::BrightBlue: Result = std::fputs("\033[104m", stdout); break; case EColor::BrightMagenta: Result = std::fputs("\033[105m", stdout); break; case EColor::BrightCyan: Result = std::fputs("\033[106m", stdout); break; case EColor::BrightWhite: Result = std::fputs("\033[107m", stdout); break; default: Result = std::fputs("\033[49m", stdout); break; } if (Result == EOF) return GetBackgroundColor(); return GBackgroundColor = InColor; } # endif return GetBackgroundColor(); } uint GetWindowWidth() { # if PLATFORM_WINDOWS { const HANDLE Console = GetStdHandle(STD_OUTPUT_HANDLE); if (Console == INVALID_HANDLE_VALUE) return static_cast(-1); CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo; if (!GetConsoleScreenBufferInfo(Console, &ConsoleInfo)) return static_cast(-1); return static_cast(ConsoleInfo.srWindow.Right - ConsoleInfo.srWindow.Left + 1); } # elif PLATFORM_LINUX { winsize Size; if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &Size) == -1) return static_cast(-1); return static_cast(Size.ws_col); } # endif return static_cast(-1); } uint GetWindowHeight() { # if PLATFORM_WINDOWS { const HANDLE Console = GetStdHandle(STD_OUTPUT_HANDLE); if (Console == INVALID_HANDLE_VALUE) return static_cast(-1); CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo; if (!GetConsoleScreenBufferInfo(Console, &ConsoleInfo)) return static_cast(-1); return static_cast(ConsoleInfo.srWindow.Bottom - ConsoleInfo.srWindow.Top + 1); } # elif PLATFORM_LINUX { winsize Size; if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &Size) == -1) return static_cast(-1); return static_cast(Size.ws_row); } # endif return static_cast(-1); } bool IsInputRedirected() { # if PLATFORM_WINDOWS { const HANDLE StandardInput = GetStdHandle(STD_INPUT_HANDLE); if (StandardInput == INVALID_HANDLE_VALUE) return false; DWORD FileType = GetFileType(StandardInput); return FileType != FILE_TYPE_CHAR; } # elif PLATFORM_LINUX { return isatty(fileno(stdin)) == 0; } # endif return false; } bool IsOutputRedirected() { # if PLATFORM_WINDOWS { const HANDLE StandardOutput = GetStdHandle(STD_OUTPUT_HANDLE); if (StandardOutput == INVALID_HANDLE_VALUE) return false; DWORD FileType = GetFileType(StandardOutput); return FileType != FILE_TYPE_CHAR; } # elif PLATFORM_LINUX { return isatty(fileno(stdout)) == 0; } # endif return false; } bool IsErrorRedirected() { # if PLATFORM_WINDOWS { const HANDLE StandardError = GetStdHandle(STD_ERROR_HANDLE); if (StandardError == INVALID_HANDLE_VALUE) return false; DWORD FileType = GetFileType(StandardError); return FileType != FILE_TYPE_CHAR; } # elif PLATFORM_LINUX { return isatty(fileno(stderr)) == 0; } # endif return false; } void Clear() { if (IsOutputRedirected()) return; # if PLATFORM_WINDOWS { std::system("cls"); } # elif PLATFORM_LINUX { Ignore = std::fputs("\033[2J\033[1;1H", stdout); } # endif } char Input(bool bEcho) { if (bEcho || IsOutputRedirected()) { const int Result = std::getchar(); if (Result == EOF) return static_cast(-1); return static_cast(Result); } # if PLATFORM_WINDOWS { const HANDLE Console = GetStdHandle(STD_INPUT_HANDLE); if (Console == INVALID_HANDLE_VALUE) return static_cast(-1); DWORD ConsoleMode = 0; GetConsoleMode(Console, &ConsoleMode); SetConsoleMode(Console, ConsoleMode & ~ENABLE_ECHO_INPUT); const char Result = Input(); SetConsoleMode(Console, ConsoleMode); return Result; } # elif PLATFORM_LINUX { } # endif return static_cast(-1); } FString InputLn(bool bEcho) { if (bEcho || IsOutputRedirected()) { FString Result; while (true) { const int Char = std::getchar(); if (Char == EOF || Char == '\n') break; Result.PushBack(static_cast(Char)); } return Result; } # if PLATFORM_WINDOWS { const HANDLE Console = GetStdHandle(STD_INPUT_HANDLE); if (Console == INVALID_HANDLE_VALUE) return ""; DWORD ConsoleMode = 0; GetConsoleMode(Console, &ConsoleMode); SetConsoleMode(Console, ConsoleMode & ~ENABLE_ECHO_INPUT); const FString Result = InputLn(); SetConsoleMode(Console, ConsoleMode); return Result; } # elif PLATFORM_LINUX { } # endif return ""; } bool Print(char Char) { return std::putchar(Char) != EOF; } bool Error(char Char) { return std::fputc(Char, stderr) != EOF; } NAMESPACE_MODULE_END(Utility) NAMESPACE_MODULE_END(Redcraft) NAMESPACE_REDCRAFT_END