mirror of https://github.com/PCSX2/pcsx2.git
Qt: Move logging setup into core
Sharable between frontends this way.
This commit is contained in:
parent
e415251f30
commit
a07ef0f5ee
|
@ -26,12 +26,13 @@
|
|||
|
||||
#include "CDVD/CDVD.h"
|
||||
#include "Frontend/GameList.h"
|
||||
#include "Frontend/LogSink.h"
|
||||
|
||||
#include "common/CrashHandler.h"
|
||||
|
||||
static void PrintCommandLineVersion()
|
||||
{
|
||||
QtHost::InitializeEarlyConsole();
|
||||
Host::InitializeEarlyConsole();
|
||||
std::fprintf(stderr, "%s\n", (QtHost::GetAppNameAndVersion() + QtHost::GetAppConfigSuffix()).toUtf8().constData());
|
||||
std::fprintf(stderr, "https://pcsx2.net/\n");
|
||||
std::fprintf(stderr, "\n");
|
||||
|
@ -143,7 +144,7 @@ static bool ParseCommandLineOptions(int argc, char* argv[], std::shared_ptr<VMBo
|
|||
}
|
||||
else if (CHECK_ARG("-earlyconsolelog"))
|
||||
{
|
||||
QtHost::InitializeEarlyConsole();
|
||||
Host::InitializeEarlyConsole();
|
||||
continue;
|
||||
}
|
||||
else if (CHECK_ARG("--"))
|
||||
|
@ -153,7 +154,7 @@ static bool ParseCommandLineOptions(int argc, char* argv[], std::shared_ptr<VMBo
|
|||
}
|
||||
else if (argv[i][0] == '-')
|
||||
{
|
||||
QtHost::InitializeEarlyConsole();
|
||||
Host::InitializeEarlyConsole();
|
||||
std::fprintf(stderr, "Unknown parameter: '%s'", argv[i]);
|
||||
return false;
|
||||
}
|
||||
|
@ -172,7 +173,7 @@ static bool ParseCommandLineOptions(int argc, char* argv[], std::shared_ptr<VMBo
|
|||
// or disc, we don't want to actually start.
|
||||
if (autoboot && !autoboot->source_type.has_value() && autoboot->filename.empty() && autoboot->elf_override.empty())
|
||||
{
|
||||
QtHost::InitializeEarlyConsole();
|
||||
Host::InitializeEarlyConsole();
|
||||
Console.Warning("Skipping autoboot due to no boot parameters.");
|
||||
autoboot.reset();
|
||||
}
|
||||
|
@ -181,7 +182,7 @@ static bool ParseCommandLineOptions(int argc, char* argv[], std::shared_ptr<VMBo
|
|||
// scanning the game list).
|
||||
if (QtHost::InBatchMode() && !autoboot)
|
||||
{
|
||||
QtHost::InitializeEarlyConsole();
|
||||
Host::InitializeEarlyConsole();
|
||||
Console.Warning("Disabling batch mode, because we have no autoboot.");
|
||||
QtHost::SetBatchMode(false);
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
|
||||
#include "pcsx2/CDVD/CDVDaccess.h"
|
||||
#include "pcsx2/Frontend/GameList.h"
|
||||
#include "pcsx2/Frontend/LogSink.h"
|
||||
#include "pcsx2/GSDumpReplayer.h"
|
||||
#include "pcsx2/HostDisplay.h"
|
||||
#include "pcsx2/HostSettings.h"
|
||||
|
@ -1252,7 +1253,7 @@ void MainWindow::onThemeChangedFromSettings()
|
|||
|
||||
void MainWindow::onLoggingOptionChanged()
|
||||
{
|
||||
QtHost::UpdateLogging();
|
||||
Host::UpdateLogging();
|
||||
}
|
||||
|
||||
void MainWindow::onInputRecNewActionTriggered()
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include "pcsx2/DebugTools/Debug.h"
|
||||
#include "pcsx2/Frontend/GameList.h"
|
||||
#include "pcsx2/Frontend/INISettingsInterface.h"
|
||||
#include "pcsx2/Frontend/LogSink.h"
|
||||
#include "pcsx2/HostSettings.h"
|
||||
#include "pcsx2/PAD/Host/PAD.h"
|
||||
|
||||
|
@ -260,7 +261,7 @@ bool QtHost::InitializeConfig()
|
|||
// TODO: Handle reset to defaults if load fails.
|
||||
EmuFolders::LoadConfig(*s_base_settings_interface.get());
|
||||
EmuFolders::EnsureFoldersExist();
|
||||
QtHost::UpdateLogging();
|
||||
Host::UpdateLogging();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -511,359 +512,3 @@ void QtHost::HookSignals()
|
|||
std::signal(SIGINT, SignalHandler);
|
||||
std::signal(SIGTERM, SignalHandler);
|
||||
}
|
||||
|
||||
// Used on both Windows and Linux.
|
||||
#ifdef _WIN32
|
||||
static const wchar_t s_console_colors[][ConsoleColors_Count] = {
|
||||
#define CC(x) L ## x
|
||||
#else
|
||||
static const char s_console_colors[][ConsoleColors_Count] = {
|
||||
#define CC(x) x
|
||||
#endif
|
||||
CC("\033[0m"), // default
|
||||
CC("\033[30m\033[1m"), // black
|
||||
CC("\033[32m"), // green
|
||||
CC("\033[31m"), // red
|
||||
CC("\033[34m"), // blue
|
||||
CC("\033[35m"), // magenta
|
||||
CC("\033[35m"), // orange (FIXME)
|
||||
CC("\033[37m"), // gray
|
||||
CC("\033[36m"), // cyan
|
||||
CC("\033[33m"), // yellow
|
||||
CC("\033[37m"), // white
|
||||
CC("\033[30m\033[1m"), // strong black
|
||||
CC("\033[31m\033[1m"), // strong red
|
||||
CC("\033[32m\033[1m"), // strong green
|
||||
CC("\033[34m\033[1m"), // strong blue
|
||||
CC("\033[35m\033[1m"), // strong magenta
|
||||
CC("\033[35m\033[1m"), // strong orange (FIXME)
|
||||
CC("\033[37m\033[1m"), // strong gray
|
||||
CC("\033[36m\033[1m"), // strong cyan
|
||||
CC("\033[33m\033[1m"), // strong yellow
|
||||
CC("\033[37m\033[1m") // strong white
|
||||
};
|
||||
#undef CC
|
||||
|
||||
static Common::Timer::Value s_log_start_timestamp = Common::Timer::GetCurrentValue();
|
||||
static bool s_log_timestamps = false;
|
||||
static std::mutex s_log_mutex;
|
||||
|
||||
// Replacement for Console so we actually get output to our console window on Windows.
|
||||
#ifdef _WIN32
|
||||
|
||||
static bool s_debugger_attached = false;
|
||||
static bool s_console_handle_set = false;
|
||||
static bool s_console_allocated = false;
|
||||
static HANDLE s_console_handle = INVALID_HANDLE_VALUE;
|
||||
static HANDLE s_old_console_stdin = NULL;
|
||||
static HANDLE s_old_console_stdout = NULL;
|
||||
static HANDLE s_old_console_stderr = NULL;
|
||||
|
||||
static BOOL WINAPI ConsoleCtrlHandler(DWORD dwCtrlType)
|
||||
{
|
||||
Console.WriteLn("Handler %u", dwCtrlType);
|
||||
if (dwCtrlType != CTRL_C_EVENT)
|
||||
return FALSE;
|
||||
|
||||
SignalHandler(SIGTERM);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static bool EnableVirtualTerminalProcessing(HANDLE hConsole)
|
||||
{
|
||||
if (hConsole == INVALID_HANDLE_VALUE)
|
||||
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);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void ConsoleQt_SetTitle(const char* title)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
SetConsoleTitleW(StringUtil::UTF8StringToWideString(title).c_str());
|
||||
#else
|
||||
std::fprintf(stdout, "\033]0;%s\007", title);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void ConsoleQt_DoSetColor(ConsoleColors color)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (s_console_handle == INVALID_HANDLE_VALUE)
|
||||
return;
|
||||
|
||||
const wchar_t* colortext = s_console_colors[static_cast<u32>(color)];
|
||||
DWORD written;
|
||||
WriteConsoleW(s_console_handle, colortext, std::wcslen(colortext), &written, nullptr);
|
||||
#else
|
||||
const char* colortext = s_console_colors[static_cast<u32>(color)];
|
||||
std::fputs(colortext, stdout);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void ConsoleQt_DoWrite(const char* fmt)
|
||||
{
|
||||
std::unique_lock lock(s_log_mutex);
|
||||
|
||||
#ifdef _WIN32
|
||||
if (s_console_handle != INVALID_HANDLE_VALUE || s_debugger_attached)
|
||||
{
|
||||
// TODO: Put this on the stack.
|
||||
std::wstring wfmt(StringUtil::UTF8StringToWideString(fmt));
|
||||
|
||||
if (s_debugger_attached)
|
||||
OutputDebugStringW(wfmt.c_str());
|
||||
|
||||
if (s_console_handle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
DWORD written;
|
||||
WriteConsoleW(s_console_handle, wfmt.c_str(), static_cast<DWORD>(wfmt.length()), &written, nullptr);
|
||||
}
|
||||
}
|
||||
#else
|
||||
std::fputs(fmt, stdout);
|
||||
std::fputc('\n', stdout);
|
||||
#endif
|
||||
|
||||
if (emuLog)
|
||||
{
|
||||
std::fputs(fmt, emuLog);
|
||||
}
|
||||
}
|
||||
|
||||
static void ConsoleQt_DoWriteLn(const char* fmt)
|
||||
{
|
||||
std::unique_lock lock(s_log_mutex);
|
||||
|
||||
// find time since start of process, but save a syscall if we're not writing timestamps
|
||||
float message_time = s_log_timestamps ?
|
||||
static_cast<float>(
|
||||
Common::Timer::ConvertValueToSeconds(Common::Timer::GetCurrentValue() - s_log_start_timestamp)) :
|
||||
0.0f;
|
||||
|
||||
// split newlines up
|
||||
const char* start = fmt;
|
||||
do
|
||||
{
|
||||
const char* end = std::strchr(start, '\n');
|
||||
|
||||
std::string_view line;
|
||||
if (end)
|
||||
{
|
||||
line = std::string_view(start, end - start);
|
||||
start = end + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
line = std::string_view(start);
|
||||
start = nullptr;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
if (s_console_handle != INVALID_HANDLE_VALUE || s_debugger_attached)
|
||||
{
|
||||
// TODO: Put this on the stack.
|
||||
std::wstring wfmt(StringUtil::UTF8StringToWideString(line));
|
||||
|
||||
if (s_debugger_attached)
|
||||
{
|
||||
// VS already timestamps logs (at least with the productivity power tools).
|
||||
if (!wfmt.empty())
|
||||
OutputDebugStringW(wfmt.c_str());
|
||||
OutputDebugStringW(L"\n");
|
||||
}
|
||||
|
||||
if (s_console_handle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
DWORD written;
|
||||
if (s_log_timestamps)
|
||||
{
|
||||
wchar_t timestamp_text[128];
|
||||
const int timestamp_len = _swprintf(timestamp_text, L"[%10.4f] ", message_time);
|
||||
WriteConsoleW(s_console_handle, timestamp_text, static_cast<DWORD>(timestamp_len), &written, nullptr);
|
||||
}
|
||||
|
||||
if (!wfmt.empty())
|
||||
WriteConsoleW(s_console_handle, wfmt.c_str(), static_cast<DWORD>(wfmt.length()), &written, nullptr);
|
||||
|
||||
WriteConsoleW(s_console_handle, L"\n", 1, &written, nullptr);
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (s_log_timestamps)
|
||||
{
|
||||
std::fprintf(stdout, "[%10.4f] %.*s\n", message_time, static_cast<int>(line.length()), line.data());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!line.empty())
|
||||
std::fwrite(line.data(), line.length(), 1, stdout);
|
||||
std::fputc('\n', stdout);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (emuLog)
|
||||
{
|
||||
if (s_log_timestamps)
|
||||
{
|
||||
std::fprintf(emuLog, "[%10.4f] %.*s\n", message_time, static_cast<int>(line.length()), line.data());
|
||||
}
|
||||
else
|
||||
{
|
||||
std::fwrite(line.data(), line.length(), 1, emuLog);
|
||||
std::fputc('\n', emuLog);
|
||||
}
|
||||
}
|
||||
} while (start);
|
||||
}
|
||||
|
||||
static void ConsoleQt_Newline()
|
||||
{
|
||||
ConsoleQt_DoWriteLn("");
|
||||
}
|
||||
|
||||
static const IConsoleWriter ConsoleWriter_WinQt =
|
||||
{
|
||||
ConsoleQt_DoWrite,
|
||||
ConsoleQt_DoWriteLn,
|
||||
ConsoleQt_DoSetColor,
|
||||
|
||||
ConsoleQt_DoWrite,
|
||||
ConsoleQt_Newline,
|
||||
ConsoleQt_SetTitle,
|
||||
};
|
||||
|
||||
static void UpdateLoggingSinks(bool system_console, bool file_log)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
const bool debugger_attached = IsDebuggerPresent();
|
||||
s_debugger_attached = debugger_attached;
|
||||
if (system_console)
|
||||
{
|
||||
if (!s_console_handle_set)
|
||||
{
|
||||
s_old_console_stdin = GetStdHandle(STD_INPUT_HANDLE);
|
||||
s_old_console_stdout = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
s_old_console_stderr = GetStdHandle(STD_ERROR_HANDLE);
|
||||
|
||||
bool handle_valid = (GetConsoleWindow() != NULL);
|
||||
if (!handle_valid)
|
||||
{
|
||||
s_console_allocated = AttachConsole(ATTACH_PARENT_PROCESS) || AllocConsole();
|
||||
handle_valid = (GetConsoleWindow() != NULL);
|
||||
}
|
||||
|
||||
if (handle_valid)
|
||||
{
|
||||
s_console_handle = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
if (s_console_handle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
s_console_handle_set = true;
|
||||
SetConsoleCtrlHandler(ConsoleCtrlHandler, TRUE);
|
||||
|
||||
// This gets us unix-style coloured output.
|
||||
EnableVirtualTerminalProcessing(GetStdHandle(STD_OUTPUT_HANDLE));
|
||||
EnableVirtualTerminalProcessing(GetStdHandle(STD_ERROR_HANDLE));
|
||||
|
||||
// Redirect stdout/stderr.
|
||||
std::FILE* fp;
|
||||
freopen_s(&fp, "CONIN$", "r", stdin);
|
||||
freopen_s(&fp, "CONOUT$", "w", stdout);
|
||||
freopen_s(&fp, "CONOUT$", "w", stderr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// just in case it fails
|
||||
system_console = s_console_handle_set;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (s_console_handle_set)
|
||||
{
|
||||
s_console_handle_set = false;
|
||||
SetConsoleCtrlHandler(ConsoleCtrlHandler, FALSE);
|
||||
|
||||
// redirect stdout/stderr back to null.
|
||||
std::FILE* fp;
|
||||
freopen_s(&fp, "NUL:", "w", stderr);
|
||||
freopen_s(&fp, "NUL:", "w", stdout);
|
||||
freopen_s(&fp, "NUL:", "w", stdin);
|
||||
|
||||
// release console and restore state
|
||||
SetStdHandle(STD_INPUT_HANDLE, s_old_console_stdin);
|
||||
SetStdHandle(STD_OUTPUT_HANDLE, s_old_console_stdout);
|
||||
SetStdHandle(STD_ERROR_HANDLE, s_old_console_stderr);
|
||||
s_old_console_stdin = NULL;
|
||||
s_old_console_stdout = NULL;
|
||||
s_old_console_stderr = NULL;
|
||||
if (s_console_allocated)
|
||||
{
|
||||
s_console_allocated = false;
|
||||
FreeConsole();
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
const bool debugger_attached = false;
|
||||
#endif
|
||||
|
||||
if (file_log)
|
||||
{
|
||||
if (!emuLog)
|
||||
{
|
||||
emuLogName = Path::Combine(EmuFolders::Logs, "emulog.txt");
|
||||
emuLog = FileSystem::OpenCFile(emuLogName.c_str(), "wb");
|
||||
file_log = (emuLog != nullptr);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (emuLog)
|
||||
{
|
||||
std::fclose(emuLog);
|
||||
emuLog = nullptr;
|
||||
emuLogName = {};
|
||||
}
|
||||
}
|
||||
|
||||
// Discard logs completely if there's no sinks.
|
||||
if (debugger_attached || system_console || file_log)
|
||||
Console_SetActiveHandler(ConsoleWriter_WinQt);
|
||||
else
|
||||
Console_SetActiveHandler(ConsoleWriter_Null);
|
||||
}
|
||||
|
||||
void QtHost::InitializeEarlyConsole()
|
||||
{
|
||||
UpdateLoggingSinks(true, false);
|
||||
}
|
||||
|
||||
void QtHost::UpdateLogging()
|
||||
{
|
||||
const bool system_console_enabled = Host::GetBaseBoolSettingValue("Logging", "EnableSystemConsole", false);
|
||||
const bool file_logging_enabled = Host::GetBaseBoolSettingValue("Logging", "EnableFileLogging", false);
|
||||
|
||||
s_log_timestamps = Host::GetBaseBoolSettingValue("Logging", "EnableTimestamps", true);
|
||||
|
||||
const bool any_logging_sinks = system_console_enabled || file_logging_enabled;
|
||||
DevConWriterEnabled = any_logging_sinks && (IsDevBuild || Host::GetBaseBoolSettingValue("Logging", "EnableVerbose", false));
|
||||
SysConsole.eeConsole.Enabled = any_logging_sinks && Host::GetBaseBoolSettingValue("Logging", "EnableEEConsole", false);
|
||||
SysConsole.iopConsole.Enabled = any_logging_sinks && Host::GetBaseBoolSettingValue("Logging", "EnableIOPConsole", false);
|
||||
|
||||
// Input Recording Logs
|
||||
SysConsole.recordingConsole.Enabled = any_logging_sinks && Host::GetBaseBoolSettingValue("Logging", "EnableInputRecordingLogs", true);
|
||||
SysConsole.controlInfo.Enabled = any_logging_sinks && Host::GetBaseBoolSettingValue("Logging", "EnableControllerLogs", false);
|
||||
|
||||
UpdateLoggingSinks(system_console_enabled, file_logging_enabled);
|
||||
}
|
||||
|
|
|
@ -41,10 +41,6 @@ namespace QtHost
|
|||
void Shutdown();
|
||||
|
||||
void UpdateFolders();
|
||||
void UpdateLogging();
|
||||
|
||||
/// Initializes early console logging (for printing command line arguments).
|
||||
void InitializeEarlyConsole();
|
||||
|
||||
/// Sets batch mode (exit after game shutdown).
|
||||
bool InBatchMode();
|
||||
|
|
|
@ -1069,6 +1069,7 @@ if(PCSX2_CORE)
|
|||
Frontend/InputManager.cpp
|
||||
Frontend/InputSource.cpp
|
||||
Frontend/LayeredSettingsInterface.cpp
|
||||
Frontend/LogSink.cpp
|
||||
GSDumpReplayer.cpp
|
||||
HostSettings.cpp
|
||||
VMManager.cpp
|
||||
|
@ -1079,6 +1080,7 @@ if(PCSX2_CORE)
|
|||
Frontend/InputManager.h
|
||||
Frontend/InputSource.h
|
||||
Frontend/LayeredSettingsInterface.h
|
||||
Frontend/LogSink.h
|
||||
GSDumpReplayer.h
|
||||
HostSettings.h
|
||||
VMManager.h)
|
||||
|
|
|
@ -0,0 +1,390 @@
|
|||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2022 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include "DebugTools/Debug.h"
|
||||
#include "Frontend/LogSink.h"
|
||||
#include "HostSettings.h"
|
||||
|
||||
#include "common/Assertions.h"
|
||||
#include "common/Console.h"
|
||||
#include "common/FileSystem.h"
|
||||
#include "common/Path.h"
|
||||
#include "common/StringUtil.h"
|
||||
#include "common/Timer.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "common/RedtapeWindows.h"
|
||||
#endif
|
||||
|
||||
#include "fmt/core.h"
|
||||
#include <csignal>
|
||||
|
||||
// Used on both Windows and Linux.
|
||||
#ifdef _WIN32
|
||||
static const wchar_t s_console_colors[][ConsoleColors_Count] = {
|
||||
#define CC(x) L ## x
|
||||
#else
|
||||
static const char s_console_colors[][ConsoleColors_Count] = {
|
||||
#define CC(x) x
|
||||
#endif
|
||||
CC("\033[0m"), // default
|
||||
CC("\033[30m\033[1m"), // black
|
||||
CC("\033[32m"), // green
|
||||
CC("\033[31m"), // red
|
||||
CC("\033[34m"), // blue
|
||||
CC("\033[35m"), // magenta
|
||||
CC("\033[35m"), // orange (FIXME)
|
||||
CC("\033[37m"), // gray
|
||||
CC("\033[36m"), // cyan
|
||||
CC("\033[33m"), // yellow
|
||||
CC("\033[37m"), // white
|
||||
CC("\033[30m\033[1m"), // strong black
|
||||
CC("\033[31m\033[1m"), // strong red
|
||||
CC("\033[32m\033[1m"), // strong green
|
||||
CC("\033[34m\033[1m"), // strong blue
|
||||
CC("\033[35m\033[1m"), // strong magenta
|
||||
CC("\033[35m\033[1m"), // strong orange (FIXME)
|
||||
CC("\033[37m\033[1m"), // strong gray
|
||||
CC("\033[36m\033[1m"), // strong cyan
|
||||
CC("\033[33m\033[1m"), // strong yellow
|
||||
CC("\033[37m\033[1m") // strong white
|
||||
};
|
||||
#undef CC
|
||||
|
||||
static Common::Timer::Value s_log_start_timestamp = Common::Timer::GetCurrentValue();
|
||||
static bool s_log_timestamps = false;
|
||||
static std::mutex s_log_mutex;
|
||||
|
||||
// Replacement for Console so we actually get output to our console window on Windows.
|
||||
#ifdef _WIN32
|
||||
|
||||
static bool s_debugger_attached = false;
|
||||
static bool s_console_handle_set = false;
|
||||
static bool s_console_allocated = false;
|
||||
static HANDLE s_console_handle = INVALID_HANDLE_VALUE;
|
||||
static HANDLE s_old_console_stdin = NULL;
|
||||
static HANDLE s_old_console_stdout = NULL;
|
||||
static HANDLE s_old_console_stderr = NULL;
|
||||
|
||||
static BOOL WINAPI ConsoleCtrlHandler(DWORD dwCtrlType)
|
||||
{
|
||||
Console.WriteLn("Handler %u", dwCtrlType);
|
||||
if (dwCtrlType != CTRL_C_EVENT)
|
||||
return FALSE;
|
||||
|
||||
::raise(SIGTERM);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static bool EnableVirtualTerminalProcessing(HANDLE hConsole)
|
||||
{
|
||||
if (hConsole == INVALID_HANDLE_VALUE)
|
||||
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);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void ConsoleQt_SetTitle(const char* title)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
SetConsoleTitleW(StringUtil::UTF8StringToWideString(title).c_str());
|
||||
#else
|
||||
std::fprintf(stdout, "\033]0;%s\007", title);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void ConsoleQt_DoSetColor(ConsoleColors color)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (s_console_handle == INVALID_HANDLE_VALUE)
|
||||
return;
|
||||
|
||||
const wchar_t* colortext = s_console_colors[static_cast<u32>(color)];
|
||||
DWORD written;
|
||||
WriteConsoleW(s_console_handle, colortext, std::wcslen(colortext), &written, nullptr);
|
||||
#else
|
||||
const char* colortext = s_console_colors[static_cast<u32>(color)];
|
||||
std::fputs(colortext, stdout);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void ConsoleQt_DoWrite(const char* fmt)
|
||||
{
|
||||
std::unique_lock lock(s_log_mutex);
|
||||
|
||||
#ifdef _WIN32
|
||||
if (s_console_handle != INVALID_HANDLE_VALUE || s_debugger_attached)
|
||||
{
|
||||
// TODO: Put this on the stack.
|
||||
std::wstring wfmt(StringUtil::UTF8StringToWideString(fmt));
|
||||
|
||||
if (s_debugger_attached)
|
||||
OutputDebugStringW(wfmt.c_str());
|
||||
|
||||
if (s_console_handle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
DWORD written;
|
||||
WriteConsoleW(s_console_handle, wfmt.c_str(), static_cast<DWORD>(wfmt.length()), &written, nullptr);
|
||||
}
|
||||
}
|
||||
#else
|
||||
std::fputs(fmt, stdout);
|
||||
std::fputc('\n', stdout);
|
||||
#endif
|
||||
|
||||
if (emuLog)
|
||||
{
|
||||
std::fputs(fmt, emuLog);
|
||||
}
|
||||
}
|
||||
|
||||
static void ConsoleQt_DoWriteLn(const char* fmt)
|
||||
{
|
||||
std::unique_lock lock(s_log_mutex);
|
||||
|
||||
// find time since start of process, but save a syscall if we're not writing timestamps
|
||||
float message_time = s_log_timestamps ?
|
||||
static_cast<float>(
|
||||
Common::Timer::ConvertValueToSeconds(Common::Timer::GetCurrentValue() - s_log_start_timestamp)) :
|
||||
0.0f;
|
||||
|
||||
// split newlines up
|
||||
const char* start = fmt;
|
||||
do
|
||||
{
|
||||
const char* end = std::strchr(start, '\n');
|
||||
|
||||
std::string_view line;
|
||||
if (end)
|
||||
{
|
||||
line = std::string_view(start, end - start);
|
||||
start = end + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
line = std::string_view(start);
|
||||
start = nullptr;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
if (s_console_handle != INVALID_HANDLE_VALUE || s_debugger_attached)
|
||||
{
|
||||
// TODO: Put this on the stack.
|
||||
std::wstring wfmt(StringUtil::UTF8StringToWideString(line));
|
||||
|
||||
if (s_debugger_attached)
|
||||
{
|
||||
// VS already timestamps logs (at least with the productivity power tools).
|
||||
if (!wfmt.empty())
|
||||
OutputDebugStringW(wfmt.c_str());
|
||||
OutputDebugStringW(L"\n");
|
||||
}
|
||||
|
||||
if (s_console_handle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
DWORD written;
|
||||
if (s_log_timestamps)
|
||||
{
|
||||
wchar_t timestamp_text[128];
|
||||
const int timestamp_len = _swprintf(timestamp_text, L"[%10.4f] ", message_time);
|
||||
WriteConsoleW(s_console_handle, timestamp_text, static_cast<DWORD>(timestamp_len), &written, nullptr);
|
||||
}
|
||||
|
||||
if (!wfmt.empty())
|
||||
WriteConsoleW(s_console_handle, wfmt.c_str(), static_cast<DWORD>(wfmt.length()), &written, nullptr);
|
||||
|
||||
WriteConsoleW(s_console_handle, L"\n", 1, &written, nullptr);
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (s_log_timestamps)
|
||||
{
|
||||
std::fprintf(stdout, "[%10.4f] %.*s\n", message_time, static_cast<int>(line.length()), line.data());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!line.empty())
|
||||
std::fwrite(line.data(), line.length(), 1, stdout);
|
||||
std::fputc('\n', stdout);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (emuLog)
|
||||
{
|
||||
if (s_log_timestamps)
|
||||
{
|
||||
std::fprintf(emuLog, "[%10.4f] %.*s\n", message_time, static_cast<int>(line.length()), line.data());
|
||||
}
|
||||
else
|
||||
{
|
||||
std::fwrite(line.data(), line.length(), 1, emuLog);
|
||||
std::fputc('\n', emuLog);
|
||||
}
|
||||
}
|
||||
} while (start);
|
||||
}
|
||||
|
||||
static void ConsoleQt_Newline()
|
||||
{
|
||||
ConsoleQt_DoWriteLn("");
|
||||
}
|
||||
|
||||
static const IConsoleWriter ConsoleWriter_WinQt =
|
||||
{
|
||||
ConsoleQt_DoWrite,
|
||||
ConsoleQt_DoWriteLn,
|
||||
ConsoleQt_DoSetColor,
|
||||
|
||||
ConsoleQt_DoWrite,
|
||||
ConsoleQt_Newline,
|
||||
ConsoleQt_SetTitle,
|
||||
};
|
||||
|
||||
static void UpdateLoggingSinks(bool system_console, bool file_log)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
const bool debugger_attached = IsDebuggerPresent();
|
||||
s_debugger_attached = debugger_attached;
|
||||
if (system_console)
|
||||
{
|
||||
if (!s_console_handle_set)
|
||||
{
|
||||
s_old_console_stdin = GetStdHandle(STD_INPUT_HANDLE);
|
||||
s_old_console_stdout = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
s_old_console_stderr = GetStdHandle(STD_ERROR_HANDLE);
|
||||
|
||||
bool handle_valid = (GetConsoleWindow() != NULL);
|
||||
if (!handle_valid)
|
||||
{
|
||||
s_console_allocated = AttachConsole(ATTACH_PARENT_PROCESS) || AllocConsole();
|
||||
handle_valid = (GetConsoleWindow() != NULL);
|
||||
}
|
||||
|
||||
if (handle_valid)
|
||||
{
|
||||
s_console_handle = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
if (s_console_handle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
s_console_handle_set = true;
|
||||
SetConsoleCtrlHandler(ConsoleCtrlHandler, TRUE);
|
||||
|
||||
// This gets us unix-style coloured output.
|
||||
EnableVirtualTerminalProcessing(GetStdHandle(STD_OUTPUT_HANDLE));
|
||||
EnableVirtualTerminalProcessing(GetStdHandle(STD_ERROR_HANDLE));
|
||||
|
||||
// Redirect stdout/stderr.
|
||||
std::FILE* fp;
|
||||
freopen_s(&fp, "CONIN$", "r", stdin);
|
||||
freopen_s(&fp, "CONOUT$", "w", stdout);
|
||||
freopen_s(&fp, "CONOUT$", "w", stderr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// just in case it fails
|
||||
system_console = s_console_handle_set;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (s_console_handle_set)
|
||||
{
|
||||
s_console_handle_set = false;
|
||||
SetConsoleCtrlHandler(ConsoleCtrlHandler, FALSE);
|
||||
|
||||
// redirect stdout/stderr back to null.
|
||||
std::FILE* fp;
|
||||
freopen_s(&fp, "NUL:", "w", stderr);
|
||||
freopen_s(&fp, "NUL:", "w", stdout);
|
||||
freopen_s(&fp, "NUL:", "w", stdin);
|
||||
|
||||
// release console and restore state
|
||||
SetStdHandle(STD_INPUT_HANDLE, s_old_console_stdin);
|
||||
SetStdHandle(STD_OUTPUT_HANDLE, s_old_console_stdout);
|
||||
SetStdHandle(STD_ERROR_HANDLE, s_old_console_stderr);
|
||||
s_old_console_stdin = NULL;
|
||||
s_old_console_stdout = NULL;
|
||||
s_old_console_stderr = NULL;
|
||||
if (s_console_allocated)
|
||||
{
|
||||
s_console_allocated = false;
|
||||
FreeConsole();
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
const bool debugger_attached = false;
|
||||
#endif
|
||||
|
||||
if (file_log)
|
||||
{
|
||||
if (!emuLog)
|
||||
{
|
||||
emuLogName = Path::Combine(EmuFolders::Logs, "emulog.txt");
|
||||
emuLog = FileSystem::OpenCFile(emuLogName.c_str(), "wb");
|
||||
file_log = (emuLog != nullptr);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (emuLog)
|
||||
{
|
||||
std::fclose(emuLog);
|
||||
emuLog = nullptr;
|
||||
emuLogName = {};
|
||||
}
|
||||
}
|
||||
|
||||
// Discard logs completely if there's no sinks.
|
||||
if (debugger_attached || system_console || file_log)
|
||||
Console_SetActiveHandler(ConsoleWriter_WinQt);
|
||||
else
|
||||
Console_SetActiveHandler(ConsoleWriter_Null);
|
||||
}
|
||||
|
||||
void Host::InitializeEarlyConsole()
|
||||
{
|
||||
UpdateLoggingSinks(true, false);
|
||||
}
|
||||
|
||||
void Host::UpdateLogging()
|
||||
{
|
||||
const bool system_console_enabled = Host::GetBaseBoolSettingValue("Logging", "EnableSystemConsole", false);
|
||||
const bool file_logging_enabled = Host::GetBaseBoolSettingValue("Logging", "EnableFileLogging", false);
|
||||
|
||||
s_log_timestamps = Host::GetBaseBoolSettingValue("Logging", "EnableTimestamps", true);
|
||||
|
||||
const bool any_logging_sinks = system_console_enabled || file_logging_enabled;
|
||||
DevConWriterEnabled = any_logging_sinks && (IsDevBuild || Host::GetBaseBoolSettingValue("Logging", "EnableVerbose", false));
|
||||
SysConsole.eeConsole.Enabled = any_logging_sinks && Host::GetBaseBoolSettingValue("Logging", "EnableEEConsole", false);
|
||||
SysConsole.iopConsole.Enabled = any_logging_sinks && Host::GetBaseBoolSettingValue("Logging", "EnableIOPConsole", false);
|
||||
|
||||
// Input Recording Logs
|
||||
SysConsole.recordingConsole.Enabled = any_logging_sinks && Host::GetBaseBoolSettingValue("Logging", "EnableInputRecordingLogs", true);
|
||||
SysConsole.controlInfo.Enabled = any_logging_sinks && Host::GetBaseBoolSettingValue("Logging", "EnableControllerLogs", false);
|
||||
|
||||
UpdateLoggingSinks(system_console_enabled, file_logging_enabled);
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2022 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace Host
|
||||
{
|
||||
/// Updates the Console handler based on the current configuration.
|
||||
void UpdateLogging();
|
||||
|
||||
/// Initializes early console logging (for printing command line arguments).
|
||||
void InitializeEarlyConsole();
|
||||
}
|
|
@ -198,6 +198,7 @@
|
|||
<ClCompile Include="Frontend\InputManager.cpp" />
|
||||
<ClCompile Include="Frontend\InputSource.cpp" />
|
||||
<ClCompile Include="Frontend\LayeredSettingsInterface.cpp" />
|
||||
<ClCompile Include="Frontend\LogSink.cpp" />
|
||||
<ClCompile Include="Frontend\OpenGLHostDisplay.cpp" />
|
||||
<ClCompile Include="Frontend\SDLInputSource.cpp" />
|
||||
<ClCompile Include="Frontend\VulkanHostDisplay.cpp" />
|
||||
|
@ -517,6 +518,7 @@
|
|||
<ClInclude Include="Frontend\InputManager.h" />
|
||||
<ClInclude Include="Frontend\InputSource.h" />
|
||||
<ClInclude Include="Frontend\LayeredSettingsInterface.h" />
|
||||
<ClInclude Include="Frontend\LogSink.h" />
|
||||
<ClInclude Include="Frontend\OpenGLHostDisplay.h" />
|
||||
<ClInclude Include="Frontend\SDLInputSource.h" />
|
||||
<ClInclude Include="Frontend\VulkanHostDisplay.h" />
|
||||
|
|
|
@ -1272,6 +1272,9 @@
|
|||
<ClCompile Include="Recording\PadData.cpp">
|
||||
<Filter>Tools\Input Recording</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Frontend\LogSink.cpp">
|
||||
<Filter>Host</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Patch.h">
|
||||
|
@ -2113,6 +2116,9 @@
|
|||
<ClInclude Include="Recording\PadData.h">
|
||||
<Filter>Tools\Input Recording</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Frontend\LogSink.h">
|
||||
<Filter>Host</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<CustomBuildStep Include="rdebug\deci2.h">
|
||||
|
@ -2137,4 +2143,4 @@
|
|||
<Filter>System\Ps2\Debug\rdebug</Filter>
|
||||
</CustomBuildStep>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
Loading…
Reference in New Issue