diff options
Diffstat (limited to 'src/common/console_listener.cpp')
-rw-r--r-- | src/common/console_listener.cpp | 337 |
1 files changed, 337 insertions, 0 deletions
diff --git a/src/common/console_listener.cpp b/src/common/console_listener.cpp new file mode 100644 index 00000000..270ad9ce --- /dev/null +++ b/src/common/console_listener.cpp @@ -0,0 +1,337 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include <algorithm> // min +#include <string> // System: To be able to add strings with "+" +#include <stdio.h> +#include <math.h> +#ifdef _WIN32 +#include <windows.h> +#include <array> +#else +#include <stdarg.h> +#endif + +#include "common.h" +#include "log_manager.h" // Common +#include "console_listener.h" // Common + +ConsoleListener::ConsoleListener() +{ +#ifdef _WIN32 + hConsole = NULL; + bUseColor = true; +#else + bUseColor = isatty(fileno(stdout)); +#endif +} + +ConsoleListener::~ConsoleListener() +{ + Close(); +} + +// 100, 100, "Dolphin Log Console" +// Open console window - width and height is the size of console window +// Name is the window title +void ConsoleListener::Open(bool Hidden, int Width, int Height, const char *Title) +{ +#ifdef _WIN32 + if (!GetConsoleWindow()) + { + // Open the console window and create the window handle for GetStdHandle() + AllocConsole(); + // Hide + if (Hidden) ShowWindow(GetConsoleWindow(), SW_HIDE); + // Save the window handle that AllocConsole() created + hConsole = GetStdHandle(STD_OUTPUT_HANDLE); + // Set the console window title + SetConsoleTitle(UTF8ToTStr(Title).c_str()); + // Set letter space + LetterSpace(80, 4000); + //MoveWindow(GetConsoleWindow(), 200,200, 800,800, true); + } + else + { + hConsole = GetStdHandle(STD_OUTPUT_HANDLE); + } +#endif +} + +void ConsoleListener::UpdateHandle() +{ +#ifdef _WIN32 + hConsole = GetStdHandle(STD_OUTPUT_HANDLE); +#endif +} + +// Close the console window and close the eventual file handle +void ConsoleListener::Close() +{ +#ifdef _WIN32 + if (hConsole == NULL) + return; + FreeConsole(); + hConsole = NULL; +#else + fflush(NULL); +#endif +} + +bool ConsoleListener::IsOpen() +{ +#ifdef _WIN32 + return (hConsole != NULL); +#else + return true; +#endif +} + +/* + LetterSpace: SetConsoleScreenBufferSize and SetConsoleWindowInfo are + dependent on each other, that's the reason for the additional checks. +*/ +void ConsoleListener::BufferWidthHeight(int BufferWidth, int BufferHeight, int ScreenWidth, int ScreenHeight, bool BufferFirst) +{ +#ifdef _WIN32 + BOOL SB, SW; + if (BufferFirst) + { + // Change screen buffer size + COORD Co = {BufferWidth, BufferHeight}; + SB = SetConsoleScreenBufferSize(hConsole, Co); + // Change the screen buffer window size + SMALL_RECT coo = {0,0,ScreenWidth, ScreenHeight}; // top, left, right, bottom + SW = SetConsoleWindowInfo(hConsole, TRUE, &coo); + } + else + { + // Change the screen buffer window size + SMALL_RECT coo = {0,0, ScreenWidth, ScreenHeight}; // top, left, right, bottom + SW = SetConsoleWindowInfo(hConsole, TRUE, &coo); + // Change screen buffer size + COORD Co = {BufferWidth, BufferHeight}; + SB = SetConsoleScreenBufferSize(hConsole, Co); + } +#endif +} +void ConsoleListener::LetterSpace(int Width, int Height) +{ +#ifdef _WIN32 + // Get console info + CONSOLE_SCREEN_BUFFER_INFO ConInfo; + GetConsoleScreenBufferInfo(hConsole, &ConInfo); + + // + int OldBufferWidth = ConInfo.dwSize.X; + int OldBufferHeight = ConInfo.dwSize.Y; + int OldScreenWidth = (ConInfo.srWindow.Right - ConInfo.srWindow.Left); + int OldScreenHeight = (ConInfo.srWindow.Bottom - ConInfo.srWindow.Top); + // + int NewBufferWidth = Width; + int NewBufferHeight = Height; + int NewScreenWidth = NewBufferWidth - 1; + int NewScreenHeight = OldScreenHeight; + + // Width + BufferWidthHeight(NewBufferWidth, OldBufferHeight, NewScreenWidth, OldScreenHeight, (NewBufferWidth > OldScreenWidth-1)); + // Height + BufferWidthHeight(NewBufferWidth, NewBufferHeight, NewScreenWidth, NewScreenHeight, (NewBufferHeight > OldScreenHeight-1)); + + // Resize the window too + //MoveWindow(GetConsoleWindow(), 200,200, (Width*8 + 50),(NewScreenHeight*12 + 200), true); +#endif +} +#ifdef _WIN32 +COORD ConsoleListener::GetCoordinates(int BytesRead, int BufferWidth) +{ + COORD Ret = {0, 0}; + // Full rows + int Step = (int)floor((float)BytesRead / (float)BufferWidth); + Ret.Y += Step; + // Partial row + Ret.X = BytesRead - (BufferWidth * Step); + return Ret; +} +#endif +void ConsoleListener::PixelSpace(int Left, int Top, int Width, int Height, bool Resize) +{ +#ifdef _WIN32 + // Check size + if (Width < 8 || Height < 12) return; + + bool DBef = true; + bool DAft = true; + std::string SLog = ""; + + const HWND hWnd = GetConsoleWindow(); + const HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); + + // Get console info + CONSOLE_SCREEN_BUFFER_INFO ConInfo; + GetConsoleScreenBufferInfo(hConsole, &ConInfo); + DWORD BufferSize = ConInfo.dwSize.X * ConInfo.dwSize.Y; + + // --------------------------------------------------------------------- + // Save the current text + // ------------------------ + DWORD cCharsRead = 0; + COORD coordScreen = { 0, 0 }; + + static const int MAX_BYTES = 1024 * 16; + + std::vector<std::array<TCHAR, MAX_BYTES>> Str; + std::vector<std::array<WORD, MAX_BYTES>> Attr; + + // ReadConsoleOutputAttribute seems to have a limit at this level + static const int ReadBufferSize = MAX_BYTES - 32; + + DWORD cAttrRead = ReadBufferSize; + DWORD BytesRead = 0; + while (BytesRead < BufferSize) + { + Str.resize(Str.size() + 1); + if (!ReadConsoleOutputCharacter(hConsole, Str.back().data(), ReadBufferSize, coordScreen, &cCharsRead)) + SLog += StringFromFormat("WriteConsoleOutputCharacter error"); + + Attr.resize(Attr.size() + 1); + if (!ReadConsoleOutputAttribute(hConsole, Attr.back().data(), ReadBufferSize, coordScreen, &cAttrRead)) + SLog += StringFromFormat("WriteConsoleOutputAttribute error"); + + // Break on error + if (cAttrRead == 0) break; + BytesRead += cAttrRead; + coordScreen = GetCoordinates(BytesRead, ConInfo.dwSize.X); + } + // Letter space + int LWidth = (int)(floor((float)Width / 8.0f) - 1.0f); + int LHeight = (int)(floor((float)Height / 12.0f) - 1.0f); + int LBufWidth = LWidth + 1; + int LBufHeight = (int)floor((float)BufferSize / (float)LBufWidth); + // Change screen buffer size + LetterSpace(LBufWidth, LBufHeight); + + + ClearScreen(true); + coordScreen.Y = 0; + coordScreen.X = 0; + DWORD cCharsWritten = 0; + + int BytesWritten = 0; + DWORD cAttrWritten = 0; + for (size_t i = 0; i < Attr.size(); i++) + { + if (!WriteConsoleOutputCharacter(hConsole, Str[i].data(), ReadBufferSize, coordScreen, &cCharsWritten)) + SLog += StringFromFormat("WriteConsoleOutputCharacter error"); + if (!WriteConsoleOutputAttribute(hConsole, Attr[i].data(), ReadBufferSize, coordScreen, &cAttrWritten)) + SLog += StringFromFormat("WriteConsoleOutputAttribute error"); + + BytesWritten += cAttrWritten; + coordScreen = GetCoordinates(BytesWritten, LBufWidth); + } + + const int OldCursor = ConInfo.dwCursorPosition.Y * ConInfo.dwSize.X + ConInfo.dwCursorPosition.X; + COORD Coo = GetCoordinates(OldCursor, LBufWidth); + SetConsoleCursorPosition(hConsole, Coo); + + if (SLog.length() > 0) Log(LogTypes::LNOTICE, SLog.c_str()); + + // Resize the window too + if (Resize) MoveWindow(GetConsoleWindow(), Left,Top, (Width + 100),Height, true); +#endif +} + +void ConsoleListener::Log(LogTypes::LOG_LEVELS Level, const char *Text) +{ +#if defined(_WIN32) + /* + const int MAX_BYTES = 1024*10; + char Str[MAX_BYTES]; + va_list ArgPtr; + int Cnt; + va_start(ArgPtr, Text); + Cnt = vsnprintf(Str, MAX_BYTES, Text, ArgPtr); + va_end(ArgPtr); + */ + DWORD cCharsWritten; + WORD Color; + + switch (Level) + { + case NOTICE_LEVEL: // light green + Color = FOREGROUND_GREEN | FOREGROUND_INTENSITY; + break; + case ERROR_LEVEL: // light red + Color = FOREGROUND_RED | FOREGROUND_INTENSITY; + break; + case WARNING_LEVEL: // light yellow + Color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY; + break; + case INFO_LEVEL: // cyan + Color = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY; + break; + case DEBUG_LEVEL: // gray + Color = FOREGROUND_INTENSITY; + break; + default: // off-white + Color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; + break; + } + if (strlen(Text) > 10) + { + // First 10 chars white + SetConsoleTextAttribute(hConsole, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY); + WriteConsole(hConsole, Text, 10, &cCharsWritten, NULL); + Text += 10; + } + SetConsoleTextAttribute(hConsole, Color); + WriteConsole(hConsole, Text, (DWORD)strlen(Text), &cCharsWritten, NULL); +#else + char ColorAttr[16] = ""; + char ResetAttr[16] = ""; + + if (bUseColor) + { + strcpy(ResetAttr, "\033[0m"); + switch (Level) + { + case NOTICE_LEVEL: // light green + strcpy(ColorAttr, "\033[92m"); + break; + case ERROR_LEVEL: // light red + strcpy(ColorAttr, "\033[91m"); + break; + case WARNING_LEVEL: // light yellow + strcpy(ColorAttr, "\033[93m"); + break; + default: + break; + } + } + fprintf(stderr, "%s%s%s", ColorAttr, Text, ResetAttr); +#endif +} +// Clear console screen +void ConsoleListener::ClearScreen(bool Cursor) +{ +#if defined(_WIN32) + COORD coordScreen = { 0, 0 }; + DWORD cCharsWritten; + CONSOLE_SCREEN_BUFFER_INFO csbi; + DWORD dwConSize; + + HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); + + GetConsoleScreenBufferInfo(hConsole, &csbi); + dwConSize = csbi.dwSize.X * csbi.dwSize.Y; + // Write space to the entire console + FillConsoleOutputCharacter(hConsole, TEXT(' '), dwConSize, coordScreen, &cCharsWritten); + GetConsoleScreenBufferInfo(hConsole, &csbi); + FillConsoleOutputAttribute(hConsole, csbi.wAttributes, dwConSize, coordScreen, &cCharsWritten); + // Reset cursor + if (Cursor) SetConsoleCursorPosition(hConsole, coordScreen); +#endif +} + + |