Log: Enable virtual terminal processing on Win32
This way we don't need to set the registry value.
This commit is contained in:
parent
b0398f5aa7
commit
9951921a6d
|
@ -158,7 +158,8 @@ static void StandardOutputLogCallback(void* pUserParam, const char* channelName,
|
||||||
"\033[0;34m", // TRACE
|
"\033[0;34m", // TRACE
|
||||||
};
|
};
|
||||||
|
|
||||||
if (int outputFd = (level <= LOGLEVEL_WARNING) ? STDERR_FILENO : STDOUT_FILENO; outputFd >= 0) {
|
if (int outputFd = (level <= LOGLEVEL_WARNING) ? STDERR_FILENO : STDOUT_FILENO; outputFd >= 0)
|
||||||
|
{
|
||||||
write(outputFd, colorCodes[level], std::strlen(colorCodes[level]));
|
write(outputFd, colorCodes[level], std::strlen(colorCodes[level]));
|
||||||
|
|
||||||
Log::FormatLogMessageForDisplay(
|
Log::FormatLogMessageForDisplay(
|
||||||
|
@ -171,7 +172,6 @@ static void StandardOutputLogCallback(void* pUserParam, const char* channelName,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
static bool s_msw_console_allocated = false;
|
static bool s_msw_console_allocated = false;
|
||||||
static HANDLE s_msw_prev_stdin = {};
|
static HANDLE s_msw_prev_stdin = {};
|
||||||
|
@ -180,7 +180,7 @@ static HANDLE s_msw_prev_stderr = {};
|
||||||
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
|
||||||
void msw_ReopenStandardPipes()
|
static void msw_ReopenStandardPipes()
|
||||||
{
|
{
|
||||||
if (s_msw_console_allocated)
|
if (s_msw_console_allocated)
|
||||||
return;
|
return;
|
||||||
|
@ -195,9 +195,18 @@ void msw_ReopenStandardPipes()
|
||||||
|
|
||||||
// open outputs as binary to suppress Windows newline corruption (\r mess)
|
// open outputs as binary to suppress Windows newline corruption (\r mess)
|
||||||
std::FILE* fp;
|
std::FILE* fp;
|
||||||
if (!s_msw_prev_stdin ) { freopen_s(&fp, "CONIN$", "r" , stdin ); }
|
if (!s_msw_prev_stdin)
|
||||||
if (!s_msw_prev_stdout ) { freopen_s(&fp, "CONOUT$", "wb", stdout); }
|
{
|
||||||
if (!s_msw_prev_stderr ) { freopen_s(&fp, "CONOUT$", "wb", stderr); }
|
freopen_s(&fp, "CONIN$", "r", stdin);
|
||||||
|
}
|
||||||
|
if (!s_msw_prev_stdout)
|
||||||
|
{
|
||||||
|
freopen_s(&fp, "CONOUT$", "wb", stdout);
|
||||||
|
}
|
||||||
|
if (!s_msw_prev_stderr)
|
||||||
|
{
|
||||||
|
freopen_s(&fp, "CONOUT$", "wb", stderr);
|
||||||
|
}
|
||||||
|
|
||||||
// Windows Console Oddities - The only way to get windows built-in console is to render UTF chars from
|
// Windows Console Oddities - The only way to get windows built-in console is to render UTF chars from
|
||||||
// the correct alt. fonts is to set either _O_U8TEXT or _O_U16TEXT. However, this imposes a requirement
|
// the correct alt. fonts is to set either _O_U8TEXT or _O_U16TEXT. However, this imposes a requirement
|
||||||
|
@ -213,7 +222,7 @@ void msw_ReopenStandardPipes()
|
||||||
//_setmode(_fileno(stderr), _O_U8TEXT);
|
//_setmode(_fileno(stderr), _O_U8TEXT);
|
||||||
}
|
}
|
||||||
|
|
||||||
void msw_FreeLegacyConsole()
|
static void msw_FreeLegacyConsole()
|
||||||
{
|
{
|
||||||
if (!s_msw_console_allocated)
|
if (!s_msw_console_allocated)
|
||||||
return;
|
return;
|
||||||
|
@ -228,20 +237,38 @@ void msw_FreeLegacyConsole()
|
||||||
::FreeConsole();
|
::FreeConsole();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool msw_AttachLegacyConsole()
|
static bool msw_AttachLegacyConsole()
|
||||||
{
|
{
|
||||||
if (::AttachConsole(ATTACH_PARENT_PROCESS))
|
if (::AttachConsole(ATTACH_PARENT_PROCESS))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// ERROR_ACCESS_DENIED means a windows Console is already attached.
|
// ERROR_ACCESS_DENIED means a windows Console is already attached.
|
||||||
if (auto err = ::GetLastError(); err == ERROR_ACCESS_DENIED) {
|
if (auto err = ::GetLastError(); err == ERROR_ACCESS_DENIED)
|
||||||
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool msw_EnableVirtualTerminalProcessing()
|
||||||
|
{
|
||||||
|
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||||
|
if (!hConsole)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
DWORD old_mode;
|
||||||
|
if (!GetConsoleMode(hConsole, &old_mode))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// already enabled?
|
||||||
|
if (old_mode & ENABLE_VIRTUAL_TERMINAL_PROCESSING)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return SetConsoleMode(hConsole, old_mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
|
||||||
|
}
|
||||||
|
|
||||||
// Creates an old-fashioned console window.
|
// Creates an old-fashioned console window.
|
||||||
bool msw_AllocLegacyConsole()
|
static bool msw_AllocLegacyConsole()
|
||||||
{
|
{
|
||||||
// A potentially fancy solution which I haven't had time to experiment with yet is to spawn our own
|
// A potentially fancy solution which I haven't had time to experiment with yet is to spawn our own
|
||||||
// terminal application and bind our standard pipes to it, instead of using AllocConsole(). This would
|
// terminal application and bind our standard pipes to it, instead of using AllocConsole(). This would
|
||||||
|
@ -249,13 +276,15 @@ bool msw_AllocLegacyConsole()
|
||||||
// than the windows legacy console (but would also depend on the user having them installed and PATH
|
// than the windows legacy console (but would also depend on the user having them installed and PATH
|
||||||
// accessible, so definitely not without annoying caveats) --jstine
|
// accessible, so definitely not without annoying caveats) --jstine
|
||||||
|
|
||||||
if (!::AllocConsole()) {
|
if (!::AllocConsole())
|
||||||
|
{
|
||||||
// Console could fail to allocate on an Appveyor/Jenkins environment, for example, because
|
// Console could fail to allocate on an Appveyor/Jenkins environment, for example, because
|
||||||
// when being run as a service the console may be unable to bind itself to a user login session.
|
// when being run as a service the console may be unable to bind itself to a user login session.
|
||||||
// It may also fail if a console is already allocated <-- this is a problem since in this case
|
// It may also fail if a console is already allocated <-- this is a problem since in this case
|
||||||
// we still want to set
|
// we still want to set
|
||||||
|
|
||||||
if (auto err = ::GetLastError(); err == ERROR_ACCESS_DENIED) {
|
if (auto err = ::GetLastError(); err == ERROR_ACCESS_DENIED)
|
||||||
|
{
|
||||||
// ERROR_ACCESS_DENIED means a windows Console is already attached.
|
// ERROR_ACCESS_DENIED means a windows Console is already attached.
|
||||||
// whatever the console is, who knows, so let's early-out, and not mess with its font settings.
|
// whatever the console is, who knows, so let's early-out, and not mess with its font settings.
|
||||||
return true;
|
return true;
|
||||||
|
@ -265,8 +294,8 @@ bool msw_AllocLegacyConsole()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void msw_DebugOutputLogCallback(void* pUserParam, const char* channelName, const char* functionName, LOGLEVEL level,
|
static void msw_DebugOutputLogCallback(void* pUserParam, const char* channelName, const char* functionName,
|
||||||
const char* message)
|
LOGLEVEL level, const char* message)
|
||||||
{
|
{
|
||||||
FormatLogMessageForDisplay(
|
FormatLogMessageForDisplay(
|
||||||
channelName, functionName, level, message, [](const char* text, void*) { OutputDebugStringA(text); }, nullptr);
|
channelName, functionName, level, message, [](const char* text, void*) { OutputDebugStringA(text); }, nullptr);
|
||||||
|
@ -276,8 +305,8 @@ static void msw_DebugOutputLogCallback(void* pUserParam, const char* channelName
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__ANDROID__)
|
#if defined(__ANDROID__)
|
||||||
static void android_DebugOutputLogCallback(void* pUserParam, const char* channelName, const char* functionName, LOGLEVEL level,
|
static void android_DebugOutputLogCallback(void* pUserParam, const char* channelName, const char* functionName,
|
||||||
const char* message)
|
LOGLEVEL level, const char* message)
|
||||||
{
|
{
|
||||||
static const int logPriority[LOGLEVEL_COUNT] = {
|
static const int logPriority[LOGLEVEL_COUNT] = {
|
||||||
ANDROID_LOG_INFO, // NONE
|
ANDROID_LOG_INFO, // NONE
|
||||||
|
@ -311,7 +340,6 @@ static void DebugOutputLogCallback(void* pUserParam, const char* channelName, co
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void SetConsoleOutputParams(bool Enabled, const char* ChannelFilter, LOGLEVEL LevelFilter)
|
void SetConsoleOutputParams(bool Enabled, const char* ChannelFilter, LOGLEVEL LevelFilter)
|
||||||
{
|
{
|
||||||
s_consoleOutputChannelFilter = (ChannelFilter != NULL) ? ChannelFilter : "";
|
s_consoleOutputChannelFilter = (ChannelFilter != NULL) ? ChannelFilter : "";
|
||||||
|
@ -328,7 +356,8 @@ void SetConsoleOutputParams(bool Enabled, const char* ChannelFilter, LOGLEVEL Le
|
||||||
UnregisterCallback(StandardOutputLogCallback, NULL);
|
UnregisterCallback(StandardOutputLogCallback, NULL);
|
||||||
|
|
||||||
#if defined(_WIN32) && !defined(_CONSOLE)
|
#if defined(_WIN32) && !defined(_CONSOLE)
|
||||||
if (Enabled) {
|
if (Enabled)
|
||||||
|
{
|
||||||
// Windows Console behavior is very tricky, and depends on:
|
// Windows Console behavior is very tricky, and depends on:
|
||||||
// - Whether the application is built with defined(_CONSOLE) or not.
|
// - Whether the application is built with defined(_CONSOLE) or not.
|
||||||
// - Whether the application is started via a Microsoft shell (Cmd.exe) or a Unix'y shell
|
// - Whether the application is started via a Microsoft shell (Cmd.exe) or a Unix'y shell
|
||||||
|
@ -360,8 +389,11 @@ void SetConsoleOutputParams(bool Enabled, const char* ChannelFilter, LOGLEVEL Le
|
||||||
s_msw_prev_stdout = ::GetStdHandle(STD_OUTPUT_HANDLE);
|
s_msw_prev_stdout = ::GetStdHandle(STD_OUTPUT_HANDLE);
|
||||||
s_msw_prev_stderr = ::GetStdHandle(STD_ERROR_HANDLE);
|
s_msw_prev_stderr = ::GetStdHandle(STD_ERROR_HANDLE);
|
||||||
|
|
||||||
if (!s_msw_prev_stdout || !s_msw_prev_stdin) {
|
if (!s_msw_prev_stdout || !s_msw_prev_stdin)
|
||||||
if (msw_AttachLegacyConsole() || msw_AllocLegacyConsole()) {
|
{
|
||||||
|
if (msw_AttachLegacyConsole() || msw_AllocLegacyConsole())
|
||||||
|
{
|
||||||
|
msw_EnableVirtualTerminalProcessing();
|
||||||
msw_ReopenStandardPipes();
|
msw_ReopenStandardPipes();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue