diff --git a/Easy2D/base/logs.cpp b/Easy2D/base/logs.cpp index 24a34544..599aa21d 100644 --- a/Easy2D/base/logs.cpp +++ b/Easy2D/base/logs.cpp @@ -19,6 +19,7 @@ // THE SOFTWARE. #include "logs.h" +#include namespace easy2d { @@ -68,21 +69,48 @@ namespace easy2d } Logger::Logger() + : enabled_(true) + , has_console_(false) + , default_stdout_color_(0) + , default_stderr_color_(0) + , output_stream_(std::wcout.rdbuf()) + , error_stream_(std::wcerr.rdbuf()) { - enabled_ = ::GetConsoleWindow() != nullptr; - default_stdout_color_ = default_stderr_color_ = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY; + ResetOutputStream(); + } - CONSOLE_SCREEN_BUFFER_INFO stdout_info; - if (::GetConsoleScreenBufferInfo(::GetStdHandle(STD_OUTPUT_HANDLE), &stdout_info)) + void Logger::ResetOutputStream() + { + has_console_ = ::GetConsoleWindow() != nullptr; + if (has_console_) { - default_stdout_color_ = stdout_info.wAttributes; - } + default_stdout_color_ = default_stderr_color_ = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY; - CONSOLE_SCREEN_BUFFER_INFO stderr_info; - if (::GetConsoleScreenBufferInfo(::GetStdHandle(STD_ERROR_HANDLE), &stderr_info)) - { - default_stderr_color_ = stderr_info.wAttributes; + CONSOLE_SCREEN_BUFFER_INFO stdout_info; + if (::GetConsoleScreenBufferInfo(::GetStdHandle(STD_OUTPUT_HANDLE), &stdout_info)) + { + default_stdout_color_ = stdout_info.wAttributes; + } + + CONSOLE_SCREEN_BUFFER_INFO stderr_info; + if (::GetConsoleScreenBufferInfo(::GetStdHandle(STD_ERROR_HANDLE), &stderr_info)) + { + default_stderr_color_ = stderr_info.wAttributes; + } + + RedirectOutputStreamBuffer(std::wcout.rdbuf()); + RedirectErrorStreamBuffer(std::wcerr.rdbuf()); } } + std::wstreambuf* Logger::RedirectOutputStreamBuffer(std::wstreambuf* buf) + { + return output_stream_.rdbuf(buf); + } + + std::wstreambuf* Logger::RedirectErrorStreamBuffer(std::wstreambuf* buf) + { + return error_stream_.rdbuf(buf); + } + } diff --git a/Easy2D/base/logs.h b/Easy2D/base/logs.h index c1ced9f2..33e16a9d 100644 --- a/Easy2D/base/logs.h +++ b/Easy2D/base/logs.h @@ -23,7 +23,6 @@ #include "../common/Singleton.hpp" #include #include -#include #include #ifndef E2D_LOG @@ -44,10 +43,81 @@ namespace easy2d { + class E2D_API Logger + : public Singleton + { + E2D_DECLARE_SINGLETON(Logger); + + public: + void Enable(); + + void Disable(); + + template + void Print(const wchar_t* format, _Args&&... args); + + template + void Println(const wchar_t* format, _Args&&... args); + + template + void Message(const wchar_t * format, _Args&&... args); + + template + void Messageln(const wchar_t * format, _Args&&... args); + + template + void Warning(const wchar_t* format, _Args&&... args); + + template + void Warningln(const wchar_t* format, _Args&&... args); + + template + void Error(const wchar_t* format, _Args&&... args); + + template + void Errorln(const wchar_t* format, _Args&&... args); + + std::wstreambuf* RedirectOutputStreamBuffer(std::wstreambuf* buf); + + std::wstreambuf* RedirectErrorStreamBuffer(std::wstreambuf* buf); + + void ResetOutputStream(); + + private: + Logger(); + + template + void OutputLine(std::wostream& os, std::wostream&(*color)(std::wostream&), const wchar_t* prompt, const wchar_t* format, _Args&&... args) const; + + template + void Output(std::wostream& os, std::wostream&(*color)(std::wostream&), const wchar_t* prompt, const wchar_t* format, _Args&&... args) const; + + template + std::wstring MakeOutputString(const wchar_t* prompt, const wchar_t* format, _Args&&... args) const; + + void ResetConsoleColor() const; + + static std::wostream& DefaultOutputColor(std::wostream& out); + + static std::wostream& OutPrefix(std::wostream& out); + + private: + bool enabled_; + bool has_console_; + WORD default_stdout_color_; + WORD default_stderr_color_; + + std::wostream output_stream_; + std::wostream error_stream_; + }; + + + // + // details of Logger + // + namespace __console_colors { - using ConsoleColor = std::wostream&(*)(std::wostream&); - #define DECLARE_COLOR(COLOR)\ extern std::wostream&(stdout_##COLOR)(std::wostream&);\ extern std::wostream&(stderr_##COLOR)(std::wostream&); @@ -73,146 +143,136 @@ namespace easy2d #undef DECLARE_BG_COLOR } - class E2D_API Logger - : public Singleton + + inline void Logger::Enable() { - E2D_DECLARE_SINGLETON(Logger); + enabled_ = true; + } - public: - inline void Enable() + inline void Logger::Disable() + { + enabled_ = false; + } + + template + inline void Logger::Print(const wchar_t* format, _Args&&... args) + { + Output(output_stream_, Logger::DefaultOutputColor, nullptr, format, std::forward<_Args>(args)...); + } + + template + inline void Logger::Println(const wchar_t* format, _Args&&... args) + { + OutputLine(output_stream_, Logger::DefaultOutputColor, nullptr, format, std::forward<_Args>(args)...); + } + + template + inline void Logger::Message(const wchar_t * format, _Args&&... args) + { + using namespace __console_colors; + Output(output_stream_, stdout_blue, nullptr, format, std::forward<_Args>(args)...); + } + + template + inline void Logger::Messageln(const wchar_t * format, _Args&&... args) + { + using namespace __console_colors; + OutputLine(output_stream_, stdout_blue, nullptr, format, std::forward<_Args>(args)...); + } + + template + inline void Logger::Warning(const wchar_t* format, _Args&&... args) + { + using namespace __console_colors; + Output(output_stream_, stdout_yellow_bg, L"Warning: ", format, std::forward<_Args>(args)...); + } + + template + inline void Logger::Warningln(const wchar_t* format, _Args&&... args) + { + using namespace __console_colors; + OutputLine(output_stream_, stdout_yellow_bg, L"Warning: ", format, std::forward<_Args>(args)...); + } + + template + inline void Logger::Error(const wchar_t* format, _Args&&... args) + { + using namespace __console_colors; + Output(error_stream_, stderr_red_bg, L"Error: ", format, std::forward<_Args>(args)...); + } + + template + inline void Logger::Errorln(const wchar_t* format, _Args&&... args) + { + using namespace __console_colors; + OutputLine(error_stream_, stderr_red_bg, L"Error: ", format, std::forward<_Args>(args)...); + } + + template + inline void Logger::OutputLine(std::wostream& os, std::wostream&(*color)(std::wostream&), const wchar_t* prompt, const wchar_t* format, _Args&&... args) const + { + if (enabled_ && has_console_) { - enabled_ = true; - } - - inline void Disable() - { - enabled_ = false; - } - - template - inline void Print(const wchar_t* format, _Args&&... args) const - { - using namespace __console_colors; - Output(std::wcout, stdout_white, nullptr, format, std::forward<_Args>(args)...); - } - - template - inline void Println(const wchar_t* format, _Args&&... args) const - { - using namespace __console_colors; - OutputLine(std::wcout, stdout_white, nullptr, format, std::forward<_Args>(args)...); - } - - template - inline void Message(const wchar_t * format, _Args&&... args) const - { - using namespace __console_colors; - Output(std::wcout, stdout_blue, nullptr, format, std::forward<_Args>(args)...); - } - - template - inline void Messageln(const wchar_t * format, _Args&&... args) const - { - using namespace __console_colors; - OutputLine(std::wcout, stdout_blue, nullptr, format, std::forward<_Args>(args)...); - } - - template - inline void Warning(const wchar_t* format, _Args&&... args) const - { - using namespace __console_colors; - Output(std::wcerr, stdout_yellow_bg, L"Warning: ", format, std::forward<_Args>(args)...); - } - - template - inline void Warningln(const wchar_t* format, _Args&&... args) const - { - using namespace __console_colors; - OutputLine(std::wcerr, stdout_yellow_bg, L"Warning: ", format, std::forward<_Args>(args)...); - } - - template - inline void Error(const wchar_t* format, _Args&&... args) const - { - using namespace __console_colors; - Output(std::wcerr, stderr_red_bg, L"Error: ", format, std::forward<_Args>(args)...); - } - - template - inline void Errorln(const wchar_t* format, _Args&&... args) const - { - using namespace __console_colors; - OutputLine(std::wcerr, stderr_red_bg, L"Error: ", format, std::forward<_Args>(args)...); - } - - private: - Logger(); - - template - inline void OutputLine(std::wostream& os, __console_colors::ConsoleColor color, const wchar_t* prompt, const wchar_t* format, _Args&&... args) const - { - if (!enabled_) - return; - Output(os, color, prompt, format, std::forward<_Args>(args)...); os << std::endl; ::OutputDebugStringW(L"\r\n"); } + } - template - inline void Output(std::wostream& os, __console_colors::ConsoleColor color, const wchar_t* prompt, const wchar_t* format, _Args&&... args) const + template + inline void Logger::Output(std::wostream& os, std::wostream&(*color)(std::wostream&), const wchar_t* prompt, const wchar_t* format, _Args&&... args) const + { + if (enabled_ && has_console_) { - if (!enabled_) - return; - std::wstring output = MakeOutputString(prompt, format, std::forward<_Args>(args)...); os << color << output; ::OutputDebugStringW(output.c_str()); - ResetColor(); + ResetConsoleColor(); } + } - template - inline std::wstring MakeOutputString(const wchar_t* prompt, const wchar_t* format, _Args&&... args) const - { - static wchar_t temp_buffer[1024 * 3 + 1]; + template + inline std::wstring Logger::MakeOutputString(const wchar_t* prompt, const wchar_t* format, _Args&&... args) const + { + static wchar_t temp_buffer[1024 * 3 + 1]; - const auto len = ::_scwprintf(format, std::forward<_Args>(args)...); - ::swprintf_s(temp_buffer, len + 1, format, std::forward<_Args>(args)...); + const auto len = ::_scwprintf(format, std::forward<_Args>(args)...); + ::swprintf_s(temp_buffer, len + 1, format, std::forward<_Args>(args)...); - std::wstringstream ss; - ss << Logger::OutPrefix; + std::wstringstream ss; + ss << Logger::OutPrefix; - if (prompt) - ss << prompt; + if (prompt) + ss << prompt; - ss << temp_buffer; + ss << temp_buffer; - return ss.str(); - } + return ss.str(); + } - inline void ResetColor() const - { - ::SetConsoleTextAttribute(::GetStdHandle(STD_OUTPUT_HANDLE), default_stdout_color_); - ::SetConsoleTextAttribute(::GetStdHandle(STD_ERROR_HANDLE), default_stderr_color_); - } + inline void Logger::ResetConsoleColor() const + { + ::SetConsoleTextAttribute(::GetStdHandle(STD_OUTPUT_HANDLE), default_stdout_color_); + ::SetConsoleTextAttribute(::GetStdHandle(STD_ERROR_HANDLE), default_stderr_color_); + } - static inline std::wostream& OutPrefix(std::wostream& out) - { - std::time_t unix = std::time(nullptr); - std::tm tmbuf; - localtime_s(&tmbuf, &unix); - out << std::put_time(&tmbuf, L"[easy2d] %H:%M:%S "); - return out; - } + inline std::wostream& Logger::DefaultOutputColor(std::wostream& out) + { + ::SetConsoleTextAttribute(::GetStdHandle(STD_OUTPUT_HANDLE), Logger::Instance().default_stdout_color_); + return out; + } - private: - bool enabled_; - WORD default_stdout_color_; - WORD default_stderr_color_; - }; + inline std::wostream& Logger::OutPrefix(std::wostream& out) + { + std::time_t unix = std::time(nullptr); + std::tm tmbuf; + localtime_s(&tmbuf, &unix); + out << std::put_time(&tmbuf, L"[easy2d] %H:%M:%S "); + return out; + } } namespace easy2d diff --git a/Easy2D/platform/Application.cpp b/Easy2D/platform/Application.cpp index a06e7c62..b2de0c87 100644 --- a/Easy2D/platform/Application.cpp +++ b/Easy2D/platform/Application.cpp @@ -31,9 +31,98 @@ #include #include #include +#include #pragma comment(lib, "imm32.lib") +namespace +{ + std::streambuf *cin_buffer, *cout_buffer, *cerr_buffer; + std::fstream console_input, console_output, console_error; + + std::wstreambuf *wcin_buffer, *wcout_buffer, *wcerr_buffer; + std::wfstream wconsole_input, wconsole_output, wconsole_error; + + void RedirectStdIO() + { + cin_buffer = std::cin.rdbuf(); + cout_buffer = std::cout.rdbuf(); + cerr_buffer = std::cerr.rdbuf(); + wcin_buffer = std::wcin.rdbuf(); + wcout_buffer = std::wcout.rdbuf(); + wcerr_buffer = std::wcerr.rdbuf(); + + console_input.open("CONIN$", std::ios::in); + console_output.open("CONOUT$", std::ios::out); + console_error.open("CONOUT$", std::ios::out); + wconsole_input.open("CONIN$", std::ios::in); + wconsole_output.open("CONOUT$", std::ios::out); + wconsole_error.open("CONOUT$", std::ios::out); + + std::cin.rdbuf(console_input.rdbuf()); + std::cout.rdbuf(console_output.rdbuf()); + std::cerr.rdbuf(console_error.rdbuf()); + std::wcin.rdbuf(wconsole_input.rdbuf()); + std::wcout.rdbuf(wconsole_output.rdbuf()); + std::wcerr.rdbuf(wconsole_error.rdbuf()); + } + + void ResetStdIO() + { + console_input.close(); + console_output.close(); + console_error.close(); + wconsole_input.close(); + wconsole_output.close(); + wconsole_error.close(); + + std::cin.rdbuf(cin_buffer); + std::cout.rdbuf(cout_buffer); + std::cerr.rdbuf(cerr_buffer); + std::wcin.rdbuf(wcin_buffer); + std::wcout.rdbuf(wcout_buffer); + std::wcerr.rdbuf(wcerr_buffer); + + cin_buffer = nullptr; + cout_buffer = nullptr; + cerr_buffer = nullptr; + wcin_buffer = nullptr; + wcout_buffer = nullptr; + wcerr_buffer = nullptr; + } + + HWND allocated_console = nullptr; + + HWND AllocateConsole() + { + if (::AllocConsole()) + { + allocated_console = ::GetConsoleWindow(); + + if (allocated_console) + { + RedirectStdIO(); + } + } + return allocated_console; + } + + void FreeAllocatedConsole() + { + if (allocated_console) + { + ResetStdIO(); + ::FreeConsole(); + allocated_console = nullptr; + } + } + + HWND GetAllocatedConsole() + { + return allocated_console; + } +} + namespace easy2d { Application::Application() @@ -51,6 +140,8 @@ namespace easy2d { Destroy(); + FreeAllocatedConsole(); + ::CoUninitialize(); } @@ -321,8 +412,6 @@ namespace easy2d void Application::ShowConsole(bool show) { - static HWND allocated_console = nullptr; - HWND current_console = ::GetConsoleWindow(); if (show) { @@ -332,33 +421,16 @@ namespace easy2d } else { - if (!::AllocConsole()) + HWND console = ::AllocateConsole(); + if (!console) { E2D_WARNING_LOG(L"AllocConsole failed"); } else { - allocated_console = ::GetConsoleWindow(); - - if (allocated_console) - { - FILE * dummy; - freopen_s(&dummy, "CONOUT$", "w+t", stdout); - freopen_s(&dummy, "CONIN$", "r+t", stdin); - freopen_s(&dummy, "CONOUT$", "w+t", stderr); - (void)dummy; - - std::cout.clear(); - std::wcout.clear(); - std::cin.clear(); - std::wcin.clear(); - std::cerr.clear(); - std::wcerr.clear(); - - // disable the close button of console - HMENU hmenu = ::GetSystemMenu(allocated_console, FALSE); - ::RemoveMenu(hmenu, SC_CLOSE, MF_BYCOMMAND); - } + // disable the close button of console + HMENU hmenu = ::GetSystemMenu(console, FALSE); + ::RemoveMenu(hmenu, SC_CLOSE, MF_BYCOMMAND); } } } @@ -366,10 +438,9 @@ namespace easy2d { if (current_console) { - if (current_console == allocated_console) + if (current_console == GetAllocatedConsole()) { - ::FreeConsole(); - allocated_console = nullptr; + FreeAllocatedConsole(); } else { @@ -377,6 +448,8 @@ namespace easy2d } } } + + Logger::Instance().ResetOutputStream(); } LRESULT CALLBACK Application::WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) @@ -526,8 +599,6 @@ namespace easy2d { bool active = (LOWORD(wparam) != WA_INACTIVE); - E2D_LOG(active ? L"Window activated" : L"Window deactivated"); - app->GetWindow()->SetActive(active); if (app->curr_scene_)