This commit is contained in:
2026-06-08 15:49:35 +08:00
commit 39b1a2c30b
59 changed files with 53335 additions and 0 deletions
+6
View File
@@ -0,0 +1,6 @@
.vs/
bin/
configs/
# Debug logs
Rcjy/Logs/
+3
View File
@@ -0,0 +1,3 @@
# Rcjy
a Windows Client
+25
View File
@@ -0,0 +1,25 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.31515.178
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Rcjy", "Rcjy\Rcjy.vcxproj", "{B6318685-5E0B-4CCF-9E87-2AFDE1979B97}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{B6318685-5E0B-4CCF-9E87-2AFDE1979B97}.Debug|x64.ActiveCfg = Debug|x64
{B6318685-5E0B-4CCF-9E87-2AFDE1979B97}.Debug|x64.Build.0 = Debug|x64
{B6318685-5E0B-4CCF-9E87-2AFDE1979B97}.Release|x64.ActiveCfg = Release|x64
{B6318685-5E0B-4CCF-9E87-2AFDE1979B97}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {4237B551-CABE-49CA-B168-38B9AA76FB06}
EndGlobalSection
EndGlobal
+398
View File
@@ -0,0 +1,398 @@
#define _CRT_SECURE_NO_WARNINGS
#include "Config.h"
#include "../Utilities/Utilities.h"
#include "../../Backend/Globalincludes.h"
#include "../Main/Main.h"
#include <filesystem>
#include <array>
namespace {
std::string color_to_string(const int col[4]) {
return std::to_string(col[0]) + "," + std::to_string(col[1]) + "," + std::to_string(col[2]) + "," + std::to_string(col[3]);
}
std::array<int, 4> string_to_color(const std::string& s) {
static auto split = [](const std::string& str, const char* del) -> std::vector<std::string>
{
char* pTempStr = _strdup(str.c_str());
char* pWord = strtok(pTempStr, del);
std::vector<std::string> dest;
while (pWord != NULL)
{
dest.push_back(pWord);
pWord = strtok(NULL, del);
}
free(pTempStr);
return dest;
};
std::vector<std::string> col = split(s, ",");
return { std::stoi(col.at(0)), std::stoi(col.at(1)), std::stoi(col.at(2)), std::stoi(col.at(3)) };
}
}
void CConfig::GetFileName(char* _buffer, bool db) {
strcpy_s(_buffer, 255, this->s["config_name"]);
}
void CConfig::GetFilePath(char* _buffer, bool db) {
char buffer[MAX_PATH];
char filename[255];
GetFileName(filename);
GetCurrentDirectoryA(MAX_PATH, buffer);
if (!db)
sprintf_s(buffer, "%s\\configs\\%s.cfg", buffer, filename);
else
sprintf_s(buffer, "%s\\configs", buffer);
strcpy_s(_buffer, 260, buffer);
}
void CConfig::LoadDefaults() {
Refresh();
CConfig* cfg = CConfig::get();
{
cfg->b["isAdmin"] = IsRunningAsAdmin();
}
{
cfg->b["time"] = false;
cfg->i["time_format"] = 0;
cfg->b["text_border"] = false;
cfg->i["time_text_size"] = 45;
cfg->i["time_text_character_spacing"] = 0;
cfg->c["time_text_Color"][0] = 255;
cfg->c["time_text_Color"][1] = 255;
cfg->c["time_text_Color"][2] = 255;
cfg->c["time_text_Color"][3] = 255;
cfg->f["time_x_pos"] = 0.0f;
cfg->f["time_y_pos"] = 0.0f;
cfg->c["text_border_Color"][0] = 0;
cfg->c["text_border_Color"][1] = 0;
cfg->c["text_border_Color"][2] = 0;
cfg->c["text_border_Color"][3] = 255;
}
{
cfg->b["keyboard_control"] = false;
cfg->i["Caps_control"] = 0;
cfg->i["Num_control"] = 0;
strncpy_s(cfg->s["keyboard_whitelist"], 255, "", 254);
}
{
cfg->c["MenuColor"][0] = 163;
cfg->c["MenuColor"][1] = 212;
cfg->c["MenuColor"][2] = 31;
cfg->c["MenuColor"][3] = 255;
strncpy_s(cfg->s["menu_key_bind"], 255, "163,97", 254); // Ctrl + 1 (top row, NumLock-independent)
GamesenseMenuFramework::Globals::MultiKeyCache("menu_key_bind") = "163,97";
cfg->i["menu_keystyle"] = 4;
cfg->i["menu_key"] = VK_INSERT; // fallback single-key
cfg->i["menu_scale"] = 0;
cfg->b["lock_menu_layout"] = true;
cfg->b["show_console"] = true;
}
}
// --- menu.cfg tracking helpers (must be before Load/Save) ---
static void GetMenuCfgPath(char* buf, int bufSize) {
GetCurrentDirectoryA(bufSize, buf);
sprintf_s(buf, bufSize, "%s\\configs\\menu.configs", buf);
}
static void WriteMenuCfg(const char* configName, bool hasManual) {
char path[MAX_PATH];
GetMenuCfgPath(path, MAX_PATH);
WritePrivateProfileStringA("Config", "LastConfig", configName, path);
WritePrivateProfileStringA("Config", "HasManualSave", hasManual ? "1" : "0", path);
}
static void ReadMenuCfg(char* outName, int outSize, bool* outHasManual) {
char path[MAX_PATH];
GetMenuCfgPath(path, MAX_PATH);
GetPrivateProfileStringA("Config", "LastConfig", "", outName, outSize, path);
*outHasManual = GetPrivateProfileIntA("Config", "HasManualSave", 0, path) != 0;
}
// ---
void CConfig::AutoLoad() {
char lastConfig[255] = "";
bool hasManual;
ReadMenuCfg(lastConfig, sizeof(lastConfig), &hasManual);
this->hasManualSave = hasManual;
// Try the last known config first
if (lastConfig[0] != 0) {
strcpy_s(this->s["config_name"], lastConfig);
char filepath[MAX_PATH];
GetFilePath(filepath);
if (GetFileAttributesA(filepath) != INVALID_FILE_ATTRIBUTES) {
Load();
return;
}
}
// Fallback: find an existing profile-*.cfg
char configsPath[MAX_PATH];
GetFilePath(configsPath, true);
if (std::filesystem::exists(configsPath)) {
std::string bestDefault;
for (auto& entry : std::filesystem::directory_iterator(configsPath)) {
if (entry.path().extension() == ".cfg") {
std::string name = entry.path().stem().string();
if (name.find("profile-") == 0 && name > bestDefault)
bestDefault = name;
}
}
if (!bestDefault.empty()) {
strcpy_s(this->s["config_name"], bestDefault.c_str());
Load();
return;
}
}
// Nothing found — use in-memory defaults (already set by LoadDefaults)
this->s["config_name"][0] = 0;
}
void CConfig::AutoSave() {
if (this->hasManualSave) {
if (this->s["config_name"][0] != 0)
Save();
} else {
if (this->s["config_name"][0] == 0)
strcpy_s(this->s["config_name"], "profile-auto");
Save();
}
WriteMenuCfg(this->s["config_name"], this->hasManualSave);
}
void CConfig::Load() {
if (this->s["config_name"][0] == 0)
return;
this->Current = this->s["config_name"];
Refresh();
char file_path[MAX_PATH] = { 0 };
GetFilePath(file_path);
// Read b (bool) entries from INI
for (auto& e : b) {
if (e.first.find("_") == 0) continue;
e.second = GetPrivateProfileIntA("b", e.first.c_str(), e.second, file_path) != 0;
}
// Read i (int) entries from INI
for (auto& e : i) {
if (e.first.find("_") == 0) continue;
e.second = GetPrivateProfileIntA("i", e.first.c_str(), e.second, file_path);
}
// Read f (float) entries from INI
for (auto& e : f) {
if (e.first.find("_") == 0) continue;
char buffer[64] = { 0 };
GetPrivateProfileStringA("f", e.first.c_str(), "", buffer, 63, file_path);
if (buffer[0] != 0)
e.second = (float)atof(buffer);
}
// Read c (color) entries from INI
for (auto& e : c) {
if (e.first.find("_") == 0) continue;
char buffer[64] = { 0 };
GetPrivateProfileStringA("c", e.first.c_str(), "", buffer, 63, file_path);
if (buffer[0] != 0) {
auto col = string_to_color(buffer);
e.second[0] = col[0];
e.second[1] = col[1];
e.second[2] = col[2];
e.second[3] = col[3];
}
}
// Read m (map) entries from INI
for (auto& e : m) {
if (e.first.find("_") == 0) continue;
char buffer[4096] = { 0 };
GetPrivateProfileStringA("m", e.first.c_str(), "", buffer, 4095, file_path);
if (buffer[0] != 0) {
e.second.clear();
char* ctx = nullptr;
char* token = strtok_s(buffer, "|", &ctx);
while (token) {
int key = 0, val = 0;
if (sscanf_s(token, "%d:%d", &key, &val) == 2)
e.second[key] = val != 0;
token = strtok_s(nullptr, "|", &ctx);
}
}
}
// Read s (string) entries from INI
for (auto& e : s) {
if (e.first == "config_name") continue;
GetPrivateProfileStringA("s", e.first.c_str(), e.second, e.second, 255, file_path);
}
// Sync MultiKeyCache with loaded s values so IsBindActive uses the correct bindings
for (auto& e : s) {
if (e.first.size() > 5 && e.first.compare(e.first.size() - 5, 5, "_bind") == 0) {
GamesenseMenuFramework::Globals::MultiKeyCache(e.first) = e.second;
}
}
WriteMenuCfg(this->s["config_name"], this->hasManualSave);
}
void CConfig::Save() {
if (this->s["config_name"][0] == 0)
return;
char configs_path[260];
GetFilePath(configs_path, true);
std::filesystem::create_directories(configs_path);
char file_path[MAX_PATH] = { 0 };
GetFilePath(file_path);
Misc::Utilities->Console_Log("Saving config: %s", file_path);
for (auto e : b) {
if (!std::string(e.first).find("_")) continue;
char buffer[8] = { 0 }; _itoa(e.second, buffer, 10);
WritePrivateProfileStringA("b", e.first.c_str(), std::string(buffer).c_str(), file_path);
}
for (auto e : i) {
if (!std::string(e.first).find("_")) continue;
char buffer[32] = { 0 }; _itoa(e.second, buffer, 10);
WritePrivateProfileStringA("i", e.first.c_str(), std::string(buffer).c_str(), file_path);
}
for (auto e : f) {
if (!std::string(e.first).find("_")) continue;
char buffer[64] = { 0 }; sprintf(buffer, "%f", e.second);
WritePrivateProfileStringA("f", e.first.c_str(), std::string(buffer).c_str(), file_path);
}
for (auto e : c) {
if (!std::string(e.first).find("_")) continue;
WritePrivateProfileStringA("c", e.first.c_str(), color_to_string(e.second).c_str(), file_path);
}
for (auto e : m) {
if (!std::string(e.first).find("_")) continue;
std::string vs = "";
for (auto v : e.second)
vs += std::to_string(v.first) + ":" + std::to_string(v.second) + "|";
WritePrivateProfileStringA("m", e.first.c_str(), vs.c_str(), file_path);
}
for (auto e : s) {
if (e.first == "config_name") continue;
if (e.second[0] == 0) continue;
WritePrivateProfileStringA("s", e.first.c_str(), e.second, file_path);
}
this->hasManualSave = true;
WriteMenuCfg(this->s["config_name"], true);
Refresh();
}
void CConfig::Delete() {
if (this->s["config_name"][0] == 0)
return;
char path[260];
GetFilePath(path);
std::remove(path);
Refresh();
}
void CConfig::Refresh() {
this->List.clear();
char path[260];
GetFilePath(path, true);
if (!std::filesystem::exists(path))
return;
for (auto& entry : std::filesystem::directory_iterator(path)) {
if (entry.path().extension() == (".cfg")) {
auto path = entry.path();
auto path_text = entry.path().string();
auto filename = path.filename().string();
if (filename != "tempbuffer")
this->List.push_back(filename.substr(0, filename.length() - 4));
}
}
}
bool CConfig::IsBindActive(std::string key) {
auto g = GamesenseMenuFramework::Globals::Gui_Ctx;
if (!g) return false;
switch (this->i[key + "style"]) {
case 0:
// Always on
return true;
case 1:
// On hotkey (held)
return g->KeyState[this->i[key]];
case 2:
// Toggle (rising edge)
return g->KeyState[this->i[key]] && !g->PrevKeyState[this->i[key]];
case 3:
// Off hotkey (not held)
return !g->KeyState[this->i[key]];
case 4:
{
// Multi-key: all stored keys must be held simultaneously
std::string multiStr = GamesenseMenuFramework::Globals::MultiKeyCache(key + "_bind");
if (multiStr.empty()) {
multiStr = this->s[key + "_bind"];
if (!multiStr.empty() && multiStr[0] != 0)
GamesenseMenuFramework::Globals::MultiKeyCache(key + "_bind") = multiStr;
}
if (multiStr.empty() || multiStr[0] == 0) return false;
const char* p = multiStr.c_str();
while (*p) {
int vk = atoi(p);
if (vk > 0 && vk < 256) {
bool held = g->KeyState[vk];
if (!held) {
// Accept either left/right modifier
int pair = 0;
if (vk == 162) pair = 163;
else if (vk == 163) pair = 162;
else if (vk == 160) pair = 161;
else if (vk == 161) pair = 160;
else if (vk == 164) pair = 165;
else if (vk == 165) pair = 164;
if (pair) held = g->KeyState[pair];
}
if (!held) return false;
}
const char* comma = strchr(p, ',');
if (!comma) break;
p = comma + 1;
}
return true;
}
default:
return true;
}
}
+29
View File
@@ -0,0 +1,29 @@
#pragma once
#include "../../Backend/Misc/singleton.h"
#include "../../Frontend/Framework/MenuFramework.h"
#include <unordered_map>
class CConfig : public singleton<CConfig> {
public:
void GetFileName(char* _Buffer, bool db = false);
void GetFilePath(char* _Buffer, bool db = false);
void LoadDefaults();
void Load();
void Save();
void AutoSave();
void AutoLoad();
void Delete();
void Refresh();
bool IsBindActive(std::string key);
bool hasManualSave = false;
std::unordered_map<std::string, bool> b;
std::unordered_map<std::string, int> i;
std::unordered_map<std::string, float> f;
std::unordered_map<std::string, int[4]> c;
std::unordered_map<std::string, std::unordered_map<int, bool>> m;
std::unordered_map<std::string, char[255]> s;
std::vector<std::string> List;
std::string Current;
};
@@ -0,0 +1,79 @@
#define _CRT_SECURE_NO_WARNINGS
#include "MenuParams.h"
#include <algorithm>
#include <cstdio>
// 全局菜单参数实例
CMenuParams MenuParams;
void CMenuParams::GetFilePath(char* buf, int bufSize) const
{
GetCurrentDirectoryA(bufSize, buf);
sprintf_s(buf, bufSize, "%s\\configs\\menu.configs", buf);
}
void CMenuParams::Load()
{
// 读取 AutoLoad 开关
char path[MAX_PATH];
GetFilePath(path, MAX_PATH);
this->AutoLoad = GetPrivateProfileIntA("Menu", "AutoLoad", 1, path) != 0;
if (this->AutoLoad)
{
// 从 menu.cfg 读取布局参数
this->PosX = (float)GetPrivateProfileIntA("Menu", "PosX", 100, path);
this->PosY = (float)GetPrivateProfileIntA("Menu", "PosY", 100, path);
this->Width = (float)GetPrivateProfileIntA("Menu", "Width", 660, path);
this->Height = (float)GetPrivateProfileIntA("Menu", "Height", 560, path);
// 确保宽高合法
this->Width = std::max(this->Width, 200.0f);
this->Height = std::max(this->Height, 200.0f);
}
// AutoLoad=false: 使用类成员默认值 (PosX=100, PosY=100, Width=660, Height=560)
}
void CMenuParams::Save(const GamesenseMenuFramework::Vec2& pos, const GamesenseMenuFramework::Vec2& size)
{
char path[MAX_PATH];
GetFilePath(path, MAX_PATH);
char buf[32];
// AutoLoad 开关(仅变化时写入)
int oldAuto = GetPrivateProfileIntA("Menu", "AutoLoad", -1, path);
int newAuto = this->AutoLoad ? 1 : 0;
if (oldAuto != newAuto)
{
_itoa(newAuto, buf, 10);
WritePrivateProfileStringA("Menu", "AutoLoad", buf, path);
}
// 位置/大小(仅变化时写入,避免每帧无意义 IO)
int oldX = GetPrivateProfileIntA("Menu", "PosX", -1, path);
int oldY = GetPrivateProfileIntA("Menu", "PosY", -1, path);
int oldW = GetPrivateProfileIntA("Menu", "Width", -1, path);
int oldH = GetPrivateProfileIntA("Menu", "Height", -1, path);
if (oldX != (int)pos.x) { _itoa((int)pos.x, buf, 10); WritePrivateProfileStringA("Menu", "PosX", buf, path); }
if (oldY != (int)pos.y) { _itoa((int)pos.y, buf, 10); WritePrivateProfileStringA("Menu", "PosY", buf, path); }
if (oldW != (int)size.x) { _itoa((int)size.x, buf, 10); WritePrivateProfileStringA("Menu", "Width", buf, path); }
if (oldH != (int)size.y) { _itoa((int)size.y, buf, 10); WritePrivateProfileStringA("Menu", "Height", buf, path); }
// 同步到成员变量
this->PosX = pos.x;
this->PosY = pos.y;
this->Width = size.x;
this->Height = size.y;
}
GamesenseMenuFramework::Vec2 CMenuParams::GetSize() const
{
return GamesenseMenuFramework::Vec2(this->Width, this->Height);
}
GamesenseMenuFramework::Vec2 CMenuParams::GetPos() const
{
return GamesenseMenuFramework::Vec2(this->PosX, this->PosY);
}
@@ -0,0 +1,50 @@
#pragma once
#include "../../Backend/Globalincludes.h"
#include "../../Frontend/Framework/MenuFramework.h"
/// <summary>
/// 独立的菜单位置与大小参数
/// 读写 menu.cfg,与 configs/*.cfg 完全分离
/// </summary>
class CMenuParams
{
public:
// 菜单窗口大小 (逻辑像素)
float Width = 660.0f;
float Height = 560.0f;
// 菜单位置 (逻辑像素)
float PosX = 100.0f;
float PosY = 100.0f;
// 是否自动加载 menu.cfg 中的布局
bool AutoLoad = true;
/// <summary>
/// 从 menu.cfg 加载布局参数(AutoLoad=false 则使用类默认值)
/// </summary>
void Load();
/// <summary>
/// 将当前布局保存到 menu.cfg
/// </summary>
void Save(const GamesenseMenuFramework::Vec2& pos, const GamesenseMenuFramework::Vec2& size);
/// <summary>
/// 获取菜单窗口大小
/// </summary>
GamesenseMenuFramework::Vec2 GetSize() const;
/// <summary>
/// 获取菜单位置
/// </summary>
GamesenseMenuFramework::Vec2 GetPos() const;
private:
/// <summary>
/// 获取 menu.cfg 的完整路径
/// </summary>
void GetFilePath(char* buf, int bufSize) const;
};
extern CMenuParams MenuParams;
@@ -0,0 +1,9 @@
#include "Settings.h"
std::unique_ptr<CSettings> Settings = std::make_unique<CSettings>();
void CSettings::LoadDefaults()
{
this->UnloadCheat = false;
this->ResetLayout = false;
}
+14
View File
@@ -0,0 +1,14 @@
#pragma once
#include <memory>
class CSettings
{
public:
bool ShowConsole = false;
bool UnloadCheat = false;
bool ResetLayout = false;
void LoadDefaults();
};
extern std::unique_ptr<CSettings> Settings;
+370
View File
@@ -0,0 +1,370 @@
#include "Console.h"
#include "../../../resource.h"
#include <cstdio>
std::atomic<bool> Console::s_bOutputPending{false};
// ---------------------------------------------------------------------------
// Singleton
// ---------------------------------------------------------------------------
Console* Console::Get()
{
static Console instance;
return &instance;
}
Console::~Console()
{
Shutdown();
}
// ---------------------------------------------------------------------------
// Initialize / Shutdown
// ---------------------------------------------------------------------------
void Console::Initialize()
{
if (m_bInitialized)
return;
m_bInitialized = true;
// ---- Window identity ------------------------------------------------
SetConsoleTitleW(L"Rcjy");
m_originalTitle = L"Rcjy";
m_hConWnd = GetConsoleWindow();
if (m_hConWnd)
{
// Window icon
HICON hIcon = LoadIconW(GetModuleHandleW(NULL), MAKEINTRESOURCEW(IDI_MAIN_ICON));
if (hIcon)
SendMessageW(m_hConWnd, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
HardenWindow(m_hConWnd);
}
// ---- stderr redirect ------------------------------------------------
// Library output (libpng warnings etc.) goes to a log file so it never
// blocks the console during QuickEdit selection.
{
wchar_t path[MAX_PATH];
GetModuleFileNameW(NULL, path, MAX_PATH);
wchar_t* p = wcsrchr(path, L'\\');
if (p) *p = L'\0';
wcscat_s(path, L"\\Logs\\stderr.log");
#pragma warning(push)
#pragma warning(disable : 4996)
_wfreopen(path, L"a", stderr);
#pragma warning(pop)
}
// ---- Start guard thread ---------------------------------------------
// Create the wake event BEFORE the thread so it is always valid.
m_hWakeEvent = CreateEventW(NULL, FALSE, FALSE, NULL); // auto-reset
m_bRunning = true;
m_hThread = CreateThread(NULL, 0, GuardThreadProc, this, 0, NULL);
// ---- Block Ctrl+C / Ctrl+Break -------------------------------------
SetConsoleCtrlHandler(CtrlHandler, TRUE);
}
void Console::Shutdown()
{
if (m_hThread == NULL)
return;
// Tell the thread to exit and wake it if it's sleeping.
m_bRunning = false;
if (m_hWakeEvent)
SetEvent(m_hWakeEvent);
WaitForSingleObject(m_hThread, 5000);
CloseHandle(m_hThread);
m_hThread = NULL;
if (m_hWakeEvent)
{
CloseHandle(m_hWakeEvent);
m_hWakeEvent = NULL;
}
}
// ---------------------------------------------------------------------------
// Visibility
// ---------------------------------------------------------------------------
void Console::SetVisible(bool visible)
{
// Refresh the handle in case the window was recreated.
HWND hwnd = GetConsoleWindow();
if (hwnd)
m_hConWnd = hwnd;
if (m_hConWnd)
ShowWindow(m_hConWnd, visible ? SW_SHOW : SW_HIDE);
}
// ---------------------------------------------------------------------------
// One-shot selection cancel (called when menu opens)
// ---------------------------------------------------------------------------
void Console::CancelSelectionIfActive()
{
// Refresh HWND in case it changed
HWND hwnd = GetConsoleWindow();
if (hwnd)
m_hConWnd = hwnd;
if (!m_hConWnd)
return;
wchar_t buf[256];
if (GetWindowTextW(m_hConWnd, buf, 256) <= 0)
return;
// QuickEdit selection active?
// Chinese Windows : "选择 Rcjy"
// English Windows : "Select Rcjy"
if (wcsstr(buf, L"选择") == buf || wcsstr(buf, L"Select") == buf)
{
PostMessageW(m_hConWnd, WM_KEYDOWN, VK_ESCAPE, 0x00010001);
PostMessageW(m_hConWnd, WM_KEYUP, VK_ESCAPE, 0xC0010001);
SetConsoleTitleW(m_originalTitle.c_str());
}
}
// ---------------------------------------------------------------------------
// Output-pending flags (called by Log)
// ---------------------------------------------------------------------------
void Console::NotifyOutputPending()
{
s_bOutputPending.store(true, std::memory_order_release);
}
void Console::NotifyOutputDone()
{
s_bOutputPending.store(false, std::memory_order_release);
}
// ---------------------------------------------------------------------------
// Ctrl+C / Ctrl+Break suppression
// ---------------------------------------------------------------------------
// Return TRUE to swallow the event so the console process doesn't terminate.
// CTRL_CLOSE_EVENT is blocked to prevent taskbar "Close window" from killing
// the process. The console window may still be destroyed by conhost, but we
// survive and can be restarted from the overlay menu.
BOOL WINAPI Console::CtrlHandler(DWORD fdwCtrlType)
{
switch (fdwCtrlType)
{
case CTRL_C_EVENT:
case CTRL_BREAK_EVENT:
case CTRL_CLOSE_EVENT:
return TRUE;
default:
return FALSE;
}
}
// ---------------------------------------------------------------------------
// Periodic maintenance
// ---------------------------------------------------------------------------
void Console::HardenWindow(HWND hwnd)
{
// (1) Remove SC_CLOSE from the system menu → disables title-bar X,
// Alt+F4, and grays out taskbar "Close window" for most Windows
// versions. Conhost is a separate process so we cannot subclass
// its WndProc; we can only influence the system menu.
HMENU hMenu = GetSystemMenu(hwnd, FALSE);
DeleteMenu(hMenu, SC_CLOSE, MF_BYCOMMAND);
DrawMenuBar(hwnd);
// (2) Add WS_EX_TOOLWINDOW to hide the console from the taskbar
// entirely. No taskbar entry → no "Close window" to click.
// The window remains visible and accessible via Alt+Tab.
LONG_PTR exStyle = GetWindowLongPtrW(hwnd, GWL_EXSTYLE);
if (!(exStyle & WS_EX_TOOLWINDOW))
{
SetWindowLongPtrW(hwnd, GWL_EXSTYLE, exStyle | WS_EX_TOOLWINDOW);
// Force the window to re-read its extended styles
SetWindowPos(hwnd, NULL, 0, 0, 0, 0,
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER |
SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
}
}
// ---------------------------------------------------------------------------
// Periodic maintenance
// ---------------------------------------------------------------------------
void Console::RefreshConsoleHandle()
{
// Reacquire the console window handle.
// conhost.exe may recreate the window in rare edge cases (e.g. after
// the console is hidden/shown by an external tool).
HWND hwnd = GetConsoleWindow();
if (hwnd && hwnd != m_hConWnd)
{
m_hConWnd = hwnd;
HICON hIcon = LoadIconW(GetModuleHandleW(NULL), MAKEINTRESOURCEW(IDI_MAIN_ICON));
if (hIcon)
SendMessageW(m_hConWnd, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
HardenWindow(m_hConWnd);
}
else if (hwnd)
{
m_hConWnd = hwnd;
// Periodically re-apply hardening — belt and suspenders in case
// something (e.g. a Windows update) reverts our changes.
HardenWindow(m_hConWnd);
}
else if (m_hConWnd && !IsWindow(m_hConWnd))
{
// Console window was destroyed (e.g. external tool forcibly
// closed it). The process survived because of CTRL_CLOSE_EVENT.
m_hConWnd = NULL;
}
}
// ---------------------------------------------------------------------------
// Title monitoring (called every 100 ms from the guard thread)
// ---------------------------------------------------------------------------
// When the user starts a QuickEdit selection, conhost changes the console
// title to "选择 <app>" (Chinese) or "Select <app>" (English). We detect
// this and give the user a 500 ms grace period for short selections. If
// the selection persists longer, we send Esc to cancel it — this prevents
// the selection from blocking console output before any WriteConsoleW call
// gets stuck.
// ---------------------------------------------------------------------------
void Console::CheckAndRestoreTitle()
{
if (!m_hConWnd || m_originalTitle.empty())
return;
wchar_t buf[256];
if (GetWindowTextW(m_hConWnd, buf, 256) <= 0)
return;
// QuickEdit selection title?
// Chinese Windows : "选择 Rcjy"
// English Windows : "Select Rcjy"
if (wcsstr(buf, L"选择") == buf || wcsstr(buf, L"Select") == buf)
{
if (!m_bSelectionDetected)
{
m_bSelectionDetected = true;
m_nSelectionDelay = 5; // 5 × 100ms = 500ms grace period
}
return; // Don't restore yet — let the countdown run
}
m_bSelectionDetected = false;
// Any other external title change → restore immediately
if (wcscmp(buf, m_originalTitle.c_str()) != 0)
SetConsoleTitleW(m_originalTitle.c_str());
}
// ---------------------------------------------------------------------------
// Guard thread
// ---------------------------------------------------------------------------
// Two independent layers of QuickEdit protection:
//
// 1. TITLE-BASED (proactive) — conhost changes the title to "选择 Rcjy" /
// "Select Rcjy" the moment the user enters selection mode. We poll this
// every 100 ms and give a 500 ms grace period for short selections before
// cancelling with Esc. This catches selection BEFORE any output blocks.
//
// 2. OUTPUT-BASED (reactive) — if selection still slips through and
// WriteConsoleW gets stuck for >100 ms, we detect it via the
// s_bOutputPending flag and send Esc. This is the safety net.
//
// Both layers post Esc directly to conhost's window via PostMessageW, which
// bypasses the blocked console input queue because window messages are
// processed in conhost's own thread.
// ---------------------------------------------------------------------------
DWORD WINAPI Console::GuardThreadProc(LPVOID lpParam)
{
Console* self = static_cast<Console*>(lpParam);
if (!self)
return 0;
bool wasBlocked = false;
int tickCount = 0;
while (self->m_bRunning)
{
// Interruptible sleep — Shutdown() sets m_hWakeEvent to wake us.
WaitForSingleObject(self->m_hWakeEvent, 100);
if (!self->m_bRunning)
break;
// ---- Title check (every tick) -----------------------------------
self->CheckAndRestoreTitle();
// ---- Title-based selection countdown ----------------------------
if (self->m_bSelectionDetected)
{
if (--self->m_nSelectionDelay <= 0)
{
// Only cancel the selection if output is actually blocked.
// If nothing is waiting to write, let the user keep
// selecting (e.g. to copy text).
if (s_bOutputPending.load(std::memory_order_acquire) && self->m_hConWnd)
{
// lParam encodes repeat-count=1, scan-code=0x01, extended=1
PostMessageW(self->m_hConWnd, WM_KEYDOWN, VK_ESCAPE, 0x00010001);
PostMessageW(self->m_hConWnd, WM_KEYUP, VK_ESCAPE, 0xC0010001);
SetConsoleTitleW(self->m_originalTitle.c_str());
self->m_bSelectionDetected = false;
}
else
{
// No output pending yet — reset the grace period
self->m_nSelectionDelay = 5;
}
}
}
// ---- Periodic HWND refresh (every ~500 ms) ----------------------
if (++tickCount >= 5)
{
tickCount = 0;
self->RefreshConsoleHandle();
}
// ---- Output-based blocking detection (reactive safety net) ------
if (!s_bOutputPending.load(std::memory_order_acquire))
{
wasBlocked = false;
continue;
}
// Output is in flight. Give it 100 ms to finish normally.
WaitForSingleObject(self->m_hWakeEvent, 100);
if (!self->m_bRunning)
break;
if (s_bOutputPending.load(std::memory_order_acquire))
{
// Still pending → WriteConsoleW is stuck in QuickEdit selection.
// Post Esc to conhost's window to cancel the selection.
if (!wasBlocked && self->m_hConWnd)
{
PostMessageW(self->m_hConWnd, WM_KEYDOWN, VK_ESCAPE, 0x00010001);
PostMessageW(self->m_hConWnd, WM_KEYUP, VK_ESCAPE, 0xC0010001);
wasBlocked = true;
}
}
}
return 0;
}
+92
View File
@@ -0,0 +1,92 @@
#pragma once
#include <Windows.h>
#include <atomic>
#include <string>
/// Manages the console window lifecycle and guards against QuickEdit blocking.
///
/// QuickEdit selection (click-drag in conhost) blocks WriteConsoleW and stalls
/// ALL threads that try to write to stdout. The guard thread detects this and
/// cancels the selection by posting Esc directly to conhost's message queue.
///
/// Additionally monitors and restores the console title to prevent external
/// interference (e.g. other processes or conhost itself changing it).
class Console
{
public:
static Console* Get();
/// One-time setup: title, icon, close-button lock, stderr redirect,
/// and start of the background guard thread.
void Initialize();
/// Signal the guard thread to stop and wait for it to exit.
/// Safe to call multiple times; call before CRT handles become invalid.
void Shutdown();
/// Show or hide the console window.
void SetVisible(bool visible);
/// If the console is in QuickEdit selection mode (conhost changed the
/// title to "选择…" / "Select…"), send Esc immediately to cancel it.
/// Call this before showing UI that might trigger log output, so the
/// console doesn't get stuck waiting for selection to end.
void CancelSelectionIfActive();
// ---- Called by Log ---------------------------------------------------
/// Mark that a WriteConsoleW call is about to happen.
/// If the guard thread sees this flag stay set for >100 ms it knows
/// QuickEdit is blocking output and cancels the selection.
static void NotifyOutputPending();
/// Mark that WriteConsoleW has returned normally.
static void NotifyOutputDone();
private:
Console() = default;
~Console();
Console(const Console&) = delete;
Console& operator=(const Console&) = delete;
// Background thread entry point.
static DWORD WINAPI GuardThreadProc(LPVOID);
// Swallow Ctrl+C so the user can't accidentally kill the process
// from the console. Returns TRUE for CTRL_C_EVENT.
static BOOL WINAPI CtrlHandler(DWORD fdwCtrlType);
// Refresh the console HWND (in case conhost recreated the window).
void RefreshConsoleHandle();
// Remove the console window from the taskbar so "Close window" is
// not available. Also strips SC_CLOSE from the system menu.
// Called from Initialize() and periodically from the guard thread.
void HardenWindow(HWND hwnd);
// Check the console title every tick (100 ms).
// If conhost changed it to the QuickEdit "Select..." indicator
// ("选择 Rcjy" / "Select Rcjy"), begin a 500 ms countdown; when the
// countdown expires, send Esc to cancel selection mode and restore the
// original title. Other external title changes are restored immediately.
void CheckAndRestoreTitle();
// ---- thread / sync ---------------------------------------------------
HANDLE m_hThread = NULL;
HANDLE m_hWakeEvent = NULL; // auto-reset; set to interrupt the guard's wait
// ---- window ----------------------------------------------------------
HWND m_hConWnd = NULL;
std::wstring m_originalTitle;
// ---- state -----------------------------------------------------------
bool m_bInitialized = false;
std::atomic<bool> m_bRunning = false;
// Title-based selection detection (only touched by guard thread)
bool m_bSelectionDetected = false;
int m_nSelectionDelay = 0; // remaining 100ms ticks (>0 = counting)
// Shared with Log — set before WriteConsoleW, cleared after.
static std::atomic<bool> s_bOutputPending;
};
+121
View File
@@ -0,0 +1,121 @@
#include "Log.h"
#include "../Console.h"
#include "raylib.h"
#include <ctime>
#include <cwchar>
Log* Log::Get()
{
static Log instance;
return &instance;
}
Log::Log()
{
m_hOut = GetStdHandle(STD_OUTPUT_HANDLE);
InitializeCriticalSection(&m_cs);
// Create Log directory next to exe
wchar_t exePath[MAX_PATH];
GetModuleFileNameW(NULL, exePath, MAX_PATH);
wchar_t* p = wcsrchr(exePath, L'\\');
if (p) *p = L'\0';
wchar_t logDir[MAX_PATH];
swprintf_s(logDir, L"%s\\Logs", exePath);
CreateDirectoryW(logDir, NULL);
// Open dated log file: ./Logs/2026-06-04.log
SYSTEMTIME st;
GetLocalTime(&st);
wchar_t logPath[MAX_PATH];
swprintf_s(logPath, L"%s\\Rcjy %04u-%02u-%02u.log",
logDir, st.wYear, st.wMonth, st.wDay);
_wfopen_s(&m_fp, logPath, L"a");
}
Log::~Log()
{
if (m_fp) fclose(m_fp);
DeleteCriticalSection(&m_cs);
}
void Log::Info(const wchar_t* fmt, ...) { va_list a; va_start(a, fmt); Write(LogLevel::Info, fmt, a); va_end(a); }
void Log::Warning(const wchar_t* fmt, ...) { va_list a; va_start(a, fmt); Write(LogLevel::Warning, fmt, a); va_end(a); }
void Log::Error(const wchar_t* fmt, ...) { va_list a; va_start(a, fmt); Write(LogLevel::Error, fmt, a); va_end(a); }
void Log::Write(LogLevel level, const wchar_t* fmt, va_list args)
{
wchar_t msg[1024];
_vsnwprintf_s(msg, _countof(msg), _TRUNCATE, fmt, args);
WriteRaw(level, msg);
}
void Log::WriteRaw(LogLevel level, const wchar_t* msg)
{
EnterCriticalSection(&m_cs);
// Console: message only, with color
SetColor(level);
Console::NotifyOutputPending();
WriteConsoleW(m_hOut, msg, (DWORD)wcslen(msg), NULL, NULL);
WriteConsoleW(m_hOut, L"\n", 1, NULL, NULL);
Console::NotifyOutputDone();
ResetColor();
// File: timestamp + message
if (m_fp) {
SYSTEMTIME st;
GetLocalTime(&st);
fwprintf(m_fp, L"[%02u:%02u:%02u] %s\n", st.wHour, st.wMinute, st.wSecond, msg);
fflush(m_fp);
}
LeaveCriticalSection(&m_cs);
}
void Log::SetColor(LogLevel level)
{
if (!m_hOut) return;
WORD attr = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
switch (level)
{
case LogLevel::Info: break; // white
case LogLevel::Warning: attr = FOREGROUND_RED | FOREGROUND_GREEN; break; // yellow
case LogLevel::Error: attr = FOREGROUND_RED | FOREGROUND_INTENSITY; break; // bright red
}
SetConsoleTextAttribute(m_hOut, attr);
}
void Log::ResetColor()
{
if (m_hOut)
SetConsoleTextAttribute(m_hOut, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
}
void Log::RaylibTraceCallback(int logLevel, const char* text, va_list args)
{
// Format the ANSI message
char ansiMsg[1024];
vsnprintf(ansiMsg, sizeof(ansiMsg), text, args);
// Convert to wide string
wchar_t wideMsg[1024];
MultiByteToWideChar(CP_UTF8, 0, ansiMsg, -1, wideMsg, _countof(wideMsg));
// Map raylib log level to our LogLevel
LogLevel lvl;
switch (logLevel) {
case 0: /* LOG_INFO */ lvl = LogLevel::Info; break;
case 1: /* LOG_WARNING */ lvl = LogLevel::Warning; break;
case 2: /* LOG_ERROR */
case 3: /* LOG_FATAL */ lvl = LogLevel::Error; break;
default: return; // LOG_DEBUG / LOG_NONE — skip
}
Log::Get()->WriteRaw(lvl, wideMsg);
}
void Log::RedirectRaylibTrace()
{
RLSetTraceLogCallback(Log::RaylibTraceCallback);
}
+38
View File
@@ -0,0 +1,38 @@
#pragma once
#include <Windows.h>
#include <cstdarg>
#include <cstdio>
#include <string>
enum class LogLevel { Info, Warning, Error };
class Log
{
public:
static Log* Get();
void Info(const wchar_t* fmt, ...);
void Warning(const wchar_t* fmt, ...);
void Error(const wchar_t* fmt, ...);
// Redirect raylib trace logs through our Log so the console guard
// thread detects blocking on ALL output, not just our own.
static void RedirectRaylibTrace();
private:
Log();
~Log();
void Write(LogLevel level, const wchar_t* fmt, va_list args);
void WriteRaw(LogLevel level, const wchar_t* msg);
void SetColor(LogLevel level);
void ResetColor();
// Callback for RLSetTraceLogCallback — formats ANSI text, converts
// to wide, and routes through the normal Write path.
static void RaylibTraceCallback(int logLevel, const char* text, va_list args);
HANDLE m_hOut = NULL;
FILE* m_fp = NULL;
CRITICAL_SECTION m_cs;
};
+9
View File
@@ -0,0 +1,9 @@
#pragma once
#define NOMINMAX
#include <Windows.h>
#include <string>
#include <memory>
#include "raylib.h"
#include "rlgl.h"
@@ -0,0 +1,115 @@
#include "Get_screen_size.h"
#include <cfloat>
#ifdef _WIN32
#include <windows.h>
#endif
#include <raylib.h>
#include <stdio.h>
RLVector2 screenSize_ = { 0, 0 };
void GetWorkArea(RLVector2& screenSize)
{
// 调用新的GetScreenArea函数,使用工作区域模式
GetScreenArea(screenSize, SCREEN_WORK_AREA);
}
void GetScreenArea(RLVector2& screenSize, ScreenAreaType areaType)
{
RECT rc = {0};
HMONITOR hMonitor = NULL;
POINT pt = {0, 0};
hMonitor = MonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST);
if (hMonitor != NULL)
{
MONITORINFOEX mi;
mi.cbSize = sizeof(MONITORINFOEX);
if (GetMonitorInfo(hMonitor, (MONITORINFO*)&mi))
{
switch (areaType)
{
case SCREEN_WORK_AREA:
rc = mi.rcWork;
printf("GetScreenArea: 使用工作区域(排除任务栏)");
break;
case SCREEN_MONITOR_AREA:
rc = mi.rcMonitor;
printf("GetScreenArea: 使用完整显示器区域");
break;
case SCREEN_PHYSICAL_AREA:
// 获取物理分辨率
DEVMODE devMode;
devMode.dmSize = sizeof(DEVMODE);
if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &devMode))
{
rc.left = 0;
rc.top = 0;
rc.right = devMode.dmPelsWidth;
rc.bottom = devMode.dmPelsHeight;
printf("GetScreenArea: 使用物理分辨率 %dx%d", devMode.dmPelsWidth, devMode.dmPelsHeight);
}
else
{
printf("GetScreenArea: EnumDisplaySettings失败,使用显示器区域");
rc = mi.rcMonitor;
}
break;
}
// 记录详细信息
printf("GetScreenArea: 显示器 '%s'", mi.szDevice);
printf("GetScreenArea: 显示器完整区域: 位置(%d,%d) 大小(%dx%d)",
mi.rcMonitor.left, mi.rcMonitor.top,
mi.rcMonitor.right - mi.rcMonitor.left,
mi.rcMonitor.bottom - mi.rcMonitor.top);
printf("GetScreenArea: 工作区域: 位置(%d,%d) 大小(%dx%d)",
mi.rcWork.left, mi.rcWork.top,
mi.rcWork.right - mi.rcWork.left,
mi.rcWork.bottom - mi.rcWork.top);
// 获取DPI信息和缩放比例
HDC hdc = GetDC(NULL);
if (hdc)
{
int dpiX = GetDeviceCaps(hdc, LOGPIXELSX);
int dpiY = GetDeviceCaps(hdc, LOGPIXELSY);
float scaleX = (float)dpiX / 96.0f * 100.0f;
float scaleY = (float)dpiY / 96.0f * 100.0f;
printf("GetScreenArea: 系统DPI: X=%d, Y=%d (96 DPI为100%%)", dpiX, dpiY);
printf("GetScreenArea: 缩放比例: X=%.0f%%, Y=%.0f%%", scaleX, scaleY);
ReleaseDC(NULL, hdc);
}
}
else
{
// 如果获取失败,回退到 SystemParametersInfo
SystemParametersInfo(SPI_GETWORKAREA, 0, &rc, 0);
printf("GetScreenArea: GetMonitorInfo失败,使用SystemParametersInfo");
}
}
else
{
// 如果没有找到显示器,回退到 SystemParametersInfo
SystemParametersInfo(SPI_GETWORKAREA, 0, &rc, 0);
printf("GetScreenArea: MonitorFromPoint失败,使用SystemParametersInfo");
}
screenSize.x = rc.right - rc.left;
screenSize.y = rc.bottom - rc.top;
screenSize_.x = rc.right - rc.left;
screenSize_.y = rc.bottom - rc.top;
printf("GetScreenArea: 最终区域位置(%d,%d) 大小(%dx%d)", rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top);
}
RLVector2 GetScreenSize() {
return screenSize_;
}
@@ -0,0 +1,16 @@
#pragma once
#ifdef _WIN32
#include <windows.h>
#endif
#include <raylib.h>
// 屏幕区域类型枚举
enum ScreenAreaType {
SCREEN_WORK_AREA, // 工作区域(排除任务栏)
SCREEN_MONITOR_AREA, // 完整显示器区域
SCREEN_PHYSICAL_AREA // 物理分辨率(考虑DPI缩放)
};
void GetWorkArea(RLVector2& screenSize);
void GetScreenArea(RLVector2& screenSize, ScreenAreaType areaType = SCREEN_WORK_AREA);
RLVector2 GetScreenSize();
+118
View File
@@ -0,0 +1,118 @@
#include "../Globalincludes.h"
#include "../../Overlay/Overlay.h"
#include "../Config/Config.h"
#include "../Console/Console.h"
static HANDLE g_hSingleInstanceMutex = NULL;
bool IsRunningAsAdmin()
{
BOOL bIsAdmin = FALSE;
PSID pAdminGroup = NULL;
SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
if (AllocateAndInitializeSid(&NtAuthority, 2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0, &pAdminGroup))
{
CheckTokenMembership(NULL, pAdminGroup, &bIsAdmin);
FreeSid(pAdminGroup);
}
return (bIsAdmin != FALSE);
}
void ReleaseSingleInstanceMutex()
{
if (g_hSingleInstanceMutex)
{
ReleaseMutex(g_hSingleInstanceMutex);
CloseHandle(g_hSingleInstanceMutex);
g_hSingleInstanceMutex = NULL;
}
}
int main()
{
bool bUnelevated = (wcsstr(GetCommandLineW(), L"--unelevated") != NULL);
bool bConhost = (wcsstr(GetCommandLineW(), L"--conhost") != NULL);
// Restart via conhost.exe for classic console
if (!bConhost && !bUnelevated) {
wchar_t buf[2048];
swprintf_s(buf, L"conhost.exe %s --conhost", GetCommandLineW());
STARTUPINFOW si = { sizeof(si) };
PROCESS_INFORMATION pi = {};
if (CreateProcessW(NULL, buf, NULL, NULL, FALSE, 0,
NULL, NULL, &si, &pi)) {
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return 0;
}
}
// One-time console setup: title, icon, guard thread
Console::Get()->Initialize();
// Hide console immediately (avoids flash). Menu::Initialize() shows it if configured.
Console::Get()->SetVisible(false);
// When de-elevated via schtasks, CWD defaults to system32.
// Fix it to the exe's directory so configs/fonts load correctly.
if (bUnelevated) {
wchar_t exePath[MAX_PATH];
GetModuleFileNameW(NULL, exePath, MAX_PATH);
WCHAR* p = wcsrchr(exePath, L'\\');
if (p) { *p = L'\0'; SetCurrentDirectoryW(exePath); }
}
g_hSingleInstanceMutex = CreateMutexW(NULL, TRUE, L"Rcjy_SingleInstance_Mutex");
if (g_hSingleInstanceMutex && GetLastError() == ERROR_ALREADY_EXISTS)
{
CloseHandle(g_hSingleInstanceMutex);
g_hSingleInstanceMutex = NULL;
if (bUnelevated) {
// Wait for the old instance to release the mutex (max ~3 s)
for (int i = 0; i < 30; ++i) {
Sleep(100);
g_hSingleInstanceMutex = CreateMutexW(NULL, TRUE, L"Rcjy_SingleInstance_Mutex");
if (g_hSingleInstanceMutex && GetLastError() != ERROR_ALREADY_EXISTS)
break;
if (g_hSingleInstanceMutex) {
CloseHandle(g_hSingleInstanceMutex);
g_hSingleInstanceMutex = NULL;
}
}
if (!g_hSingleInstanceMutex) {
MessageBoxW(NULL, L"无法重启程序(旧实例未退出)", L"Rcjy", MB_OK | MB_ICONWARNING);
return 0;
}
} else {
MessageBoxW(NULL, L"程序已在运行中", L"Rcjy", MB_OK | MB_ICONINFORMATION);
return 0;
}
}
auto overlay = COverlay::Get();
if (!overlay->Initialize())
{
ReleaseSingleInstanceMutex();
return 1;
}
// Apply console visibility from saved config
Console::Get()->SetVisible(CConfig::get()->b["show_console"]);
while (overlay->IsRunning())
{
overlay->Render();
}
overlay->Shutdown();
Console::Get()->Shutdown();
ReleaseSingleInstanceMutex();
return 0;
}
+6
View File
@@ -0,0 +1,6 @@
#pragma once
#include "../Globalincludes.h"
float GetStandaloneDeltaTime();
bool IsRunningAsAdmin();
void ReleaseSingleInstanceMutex();
@@ -0,0 +1,183 @@
#include "FontManager.h"
#include "Fonts.h"
#include <cctype>
#ifdef _WIN32
#include <windows.h>
#include <Shlobj.h>
#undef DrawText // 防止 windows.h 的 DrawText 宏与 FontManager::DrawText 方法名冲突
#endif
// ============================================================================
// 单例
// ============================================================================
FontManager& FontManager::GetInstance() {
static FontManager instance;
return instance;
}
// ============================================================================
// 内部工具
// ============================================================================
std::vector<int> FontManager::ExtractCodepoints(const char* text) {
int count = 0;
int* cps = RLLoadCodepoints(text, &count);
std::vector<int> result(cps, cps + count);
RLUnloadCodepoints(cps);
return result;
}
// ============================================================================
// 字体重建
// ============================================================================
void FontManager::RebuildFont(FontEntry& entry) {
RLFont newFont;
float size = (float)(entry.baseSize) * m_dpiScale;
if (entry.fromMemory) {
newFont = RLLoadFontFromMemory(".ttf", entry.memData, entry.memSize,
(int)size, NULL, 0);
}
else {
std::vector<int> cps(entry.codepoints.begin(), entry.codepoints.end());
newFont = RLLoadFontEx(entry.path.c_str(), (int)size,
cps.empty() ? NULL : cps.data(), (int)cps.size());
}
if (newFont.texture.id == 0 || newFont.baseSize <= 0) return;
if (entry.font.texture.id != 0)
RLUnloadFont(entry.font);
entry.font = newFont;
RLSetTextureFilter(entry.font.texture, RL_E_TEXTURE_FILTER_BILINEAR);
}
// ============================================================================
// 注册命名字体
// ============================================================================
void FontManager::RegisterFont(const char* name, const char* path, int baseSize) {
if (m_fonts.find(name) != m_fonts.end()) return;
FontEntry entry;
entry.path = path;
entry.baseSize = baseSize;
entry.fromMemory = false;
// 预加载 ASCII 码点
auto initCps = ExtractCodepoints("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.,;:!?()-_=+[]{}|/\\\"'`~@#$%^&*<> ");
for (int cp : initCps) entry.codepoints.insert(cp);
m_fonts[name] = entry;
RebuildFont(m_fonts[name]);
}
void FontManager::RegisterFontFromMemory(const char* name, const unsigned char* data, int dataSize, int baseSize) {
if (m_fonts.find(name) != m_fonts.end()) return;
FontEntry entry;
entry.path = name; // use name as identifier
entry.baseSize = baseSize;
entry.fromMemory = true;
entry.memData = data;
entry.memSize = dataSize;
// Memory fonts use NULL codepoints for default character set
m_fonts[name] = entry;
RebuildFont(m_fonts[name]);
}
// ============================================================================
// 获取字体
// ============================================================================
RLFont& FontManager::GetFont(const char* name) {
auto it = m_fonts.find(name);
if (it != m_fonts.end())
return it->second.font;
static RLFont dummy = { 0 };
return dummy;
}
// ============================================================================
// 更新字体基础大小
// ============================================================================
void FontManager::SetFontBaseSize(const char* name, int baseSize) {
auto it = m_fonts.find(name);
if (it == m_fonts.end())
return;
FontEntry& entry = it->second;
if (entry.baseSize == baseSize)
return;
entry.baseSize = baseSize;
RebuildFont(entry);
}
// ============================================================================
// 确保码点已加载
// ============================================================================
void FontManager::EnsureText(const char* name, const char* text) {
auto it = m_fonts.find(name);
if (it == m_fonts.end()) return;
FontEntry& entry = it->second;
if (entry.fromMemory) return; // memory fonts use full default glyph set
auto cps = ExtractCodepoints(text);
bool needRebuild = false;
for (int cp : cps) {
// Skip ASCII (already loaded)
if (cp < 128) continue;
if (entry.codepoints.find(cp) == entry.codepoints.end()) {
entry.codepoints.insert(cp);
needRebuild = true;
}
}
if (needRebuild)
RebuildFont(entry);
}
// ============================================================================
// 绘制 & 测量
// ============================================================================
void FontManager::DrawText(const char* name, const char* text, int x, int y, int fontSize, RLColor color) {
EnsureText(name, text);
RLFont& font = GetFont(name);
if (font.texture.id != 0)
RLDrawTextEx(font, text, { (float)x, (float)y }, (float)fontSize, 1.0f, color);
}
RLVector2 FontManager::MeasureText(const char* name, const char* text, int fontSize) {
EnsureText(name, text);
RLFont& font = GetFont(name);
if (font.texture.id != 0)
return RLMeasureTextEx(font, text, (float)fontSize, 1.0f);
return { 0, 0 };
}
// ============================================================================
// DPI 缩放
// ============================================================================
void FontManager::SetDpiScale(float scale) {
if (scale == m_dpiScale) return;
m_dpiScale = scale;
for (auto& pair : m_fonts) {
if (pair.second.font.texture.id != 0)
RLUnloadFont(pair.second.font);
RebuildFont(pair.second);
}
}
// ============================================================================
// 释放所有字体
// ============================================================================
void FontManager::UnloadAll() {
for (auto& pair : m_fonts) {
if (pair.second.font.texture.id != 0)
RLUnloadFont(pair.second.font);
}
m_fonts.clear();
}
@@ -0,0 +1,68 @@
#pragma once
#include <vector>
#include <string>
#include <unordered_set>
#include <unordered_map>
#include "raylib.h"
#ifdef DrawText
#undef DrawText // windows.h 的 DrawText 宏会破坏方法名
#endif
// ============================================================================
// FontManager - 单例字体管理器
// 管理 Verdana / Tahombd / SmallFont / TabIcons / LegitTabIcons
// + CJK 中文回退字体,自动按需加载码点
// ============================================================================
class FontManager {
public:
static FontManager& GetInstance();
// 注册并加载命名字体(TTF 路径或内存字体,DPI 缩放后大小)
void RegisterFont(const char* name, const char* path, int baseSize);
void RegisterFontFromMemory(const char* name, const unsigned char* data, int dataSize, int baseSize);
// 获取已注册字体引用
RLFont& GetFont(const char* name);
// 更新已注册字体的基础大小并重建
void SetFontBaseSize(const char* name, int baseSize);
// 确保文本中所有码点已加载到对应字体中,必要时重建
void EnsureText(const char* name, const char* text);
// 绘制文本(自动确保码点)
void DrawText(const char* name, const char* text, int x, int y, int fontSize, RLColor color);
// 测量文本尺寸
RLVector2 MeasureText(const char* name, const char* text, int fontSize);
// DPI 缩放:重建所有注册的字体
float GetDpiScale() const { return m_dpiScale; }
void SetDpiScale(float scale);
// 释放所有字体资源
void UnloadAll();
private:
FontManager() = default;
~FontManager() = default;
FontManager(const FontManager&) = delete;
FontManager& operator=(const FontManager&) = delete;
struct FontEntry {
RLFont font = { 0 };
std::string path;
int baseSize = 12;
bool fromMemory = false;
const unsigned char* memData = nullptr;
int memSize = 0;
std::unordered_set<int> codepoints;
};
std::vector<int> ExtractCodepoints(const char* text);
void RebuildFont(FontEntry& entry);
std::unordered_map<std::string, FontEntry> m_fonts;
float m_dpiScale = 1.0f;
};
+459
View File
@@ -0,0 +1,459 @@
#include "Fonts.h"
BYTE FontsData::TabIcons[] = {
0x00, 0x01, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x80, 0x00, 0x03, 0x00, 0x60,
0x46, 0x46, 0x54, 0x4D, 0xA0, 0xB4, 0x87, 0x06, 0x00, 0x00, 0x15, 0x28,
0x00, 0x00, 0x00, 0x1C, 0x4F, 0x53, 0x2F, 0x32, 0x5A, 0x32, 0x53, 0x7B,
0x00, 0x00, 0x01, 0x68, 0x00, 0x00, 0x00, 0x60, 0x63, 0x6D, 0x61, 0x70,
0x2D, 0x93, 0x1C, 0xD8, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x01, 0x62,
0x63, 0x76, 0x74, 0x20, 0x00, 0x21, 0x02, 0x79, 0x00, 0x00, 0x03, 0x74,
0x00, 0x00, 0x00, 0x04, 0x67, 0x61, 0x73, 0x70, 0x00, 0x00, 0x00, 0x10,
0x00, 0x00, 0x15, 0x20, 0x00, 0x00, 0x00, 0x08, 0x67, 0x6C, 0x79, 0x66,
0x5F, 0xE5, 0x95, 0xCF, 0x00, 0x00, 0x03, 0x9C, 0x00, 0x00, 0x0F, 0x14,
0x68, 0x65, 0x61, 0x64, 0x1E, 0xAE, 0x12, 0xF7, 0x00, 0x00, 0x00, 0xEC,
0x00, 0x00, 0x00, 0x36, 0x68, 0x68, 0x65, 0x61, 0x07, 0x40, 0x03, 0xA5,
0x00, 0x00, 0x01, 0x24, 0x00, 0x00, 0x00, 0x24, 0x68, 0x6D, 0x74, 0x78,
0x28, 0x55, 0x03, 0x05, 0x00, 0x00, 0x01, 0xC8, 0x00, 0x00, 0x00, 0x40,
0x6C, 0x6F, 0x63, 0x61, 0x1C, 0x9C, 0x18, 0x20, 0x00, 0x00, 0x03, 0x78,
0x00, 0x00, 0x00, 0x22, 0x6D, 0x61, 0x78, 0x70, 0x00, 0x61, 0x01, 0x24,
0x00, 0x00, 0x01, 0x48, 0x00, 0x00, 0x00, 0x20, 0x6E, 0x61, 0x6D, 0x65,
0xDB, 0x92, 0x43, 0x67, 0x00, 0x00, 0x12, 0xB0, 0x00, 0x00, 0x02, 0x19,
0x70, 0x6F, 0x73, 0x74, 0x50, 0x45, 0x70, 0x4E, 0x00, 0x00, 0x14, 0xCC,
0x00, 0x00, 0x00, 0x52, 0x70, 0x72, 0x65, 0x70, 0x68, 0x06, 0x8C, 0x85,
0x00, 0x00, 0x03, 0x6C, 0x00, 0x00, 0x00, 0x07, 0x00, 0x01, 0x00, 0x00,
0x00, 0x01, 0x00, 0x00, 0x14, 0xC5, 0x89, 0x6A, 0x5F, 0x0F, 0x3C, 0xF5,
0x00, 0x0B, 0x03, 0xE8, 0x00, 0x00, 0x00, 0x00, 0xD5, 0x6E, 0x7C, 0x67,
0x00, 0x00, 0x00, 0x00, 0xE6, 0x38, 0x53, 0x0B, 0x00, 0x1E, 0xFF, 0xAB,
0x03, 0xCA, 0x02, 0xF5, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x1A, 0xFF, 0xAC,
0x00, 0x5A, 0x03, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x03, 0xCA, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x01, 0x21,
0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01,
0x00, 0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x04, 0x02, 0xAF, 0x01, 0x90, 0x00, 0x05, 0x00, 0x00, 0x02, 0x8A,
0x02, 0xBC, 0x00, 0x00, 0x00, 0x8C, 0x02, 0x8A, 0x02, 0xBC, 0x00, 0x00,
0x01, 0xE0, 0x00, 0x31, 0x01, 0x02, 0x00, 0x00, 0x02, 0x00, 0x05, 0x03,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x4C,
0x47, 0x52, 0x00, 0x40, 0x00, 0x00, 0x00, 0xA0, 0x03, 0x20, 0xFF, 0x38,
0x00, 0x5A, 0x03, 0x1A, 0x00, 0x54, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x02, 0x73, 0x00, 0x00, 0x00, 0x20, 0x00, 0x01,
0x01, 0x6C, 0x00, 0x21, 0x00, 0xFA, 0x00, 0x00, 0x01, 0x4D, 0x00, 0x00,
0x00, 0xFA, 0x00, 0x00, 0x00, 0xFA, 0x00, 0x00, 0x03, 0x06, 0x00, 0x48,
0x03, 0x92, 0x00, 0x46, 0x03, 0xA8, 0x00, 0x37, 0x03, 0x8F, 0x00, 0x34,
0x03, 0x5B, 0x00, 0x34, 0x03, 0x06, 0x00, 0x87, 0x03, 0x92, 0x00, 0x62,
0x03, 0x05, 0x00, 0x48, 0x03, 0x05, 0x00, 0x68, 0x03, 0xE8, 0x00, 0x1E,
0x00, 0xFA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03,
0x00, 0x00, 0x00, 0x1C, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5C,
0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x04, 0x00, 0x40,
0x00, 0x00, 0x00, 0x0C, 0x00, 0x08, 0x00, 0x02, 0x00, 0x04, 0x00, 0x00,
0x00, 0x0D, 0x00, 0x20, 0x00, 0x4A, 0x00, 0xA0, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0x00, 0x00, 0x0D, 0x00, 0x20, 0x00, 0x41, 0x00, 0xA0, 0xFF, 0xFF,
0x00, 0x01, 0xFF, 0xF6, 0xFF, 0xE4, 0xFF, 0xC4, 0xFF, 0x6F, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xB8, 0x01, 0xFF, 0x85, 0xB0, 0x04, 0x8D, 0x00, 0x00, 0x21, 0x02, 0x79,
0x00, 0x00, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14,
0x01, 0x20, 0x01, 0x7C, 0x02, 0x60, 0x03, 0xE0, 0x04, 0x48, 0x04, 0x8A,
0x06, 0x2C, 0x06, 0x74, 0x06, 0xF6, 0x07, 0x8A, 0x07, 0x8A, 0x00, 0x00,
0x00, 0x02, 0x00, 0x21, 0x00, 0x00, 0x01, 0x2A, 0x02, 0x9A, 0x00, 0x03,
0x00, 0x07, 0x00, 0x00, 0x33, 0x11, 0x21, 0x11, 0x27, 0x33, 0x11, 0x23,
0x21, 0x01, 0x09, 0xE8, 0xC7, 0xC7, 0x02, 0x9A, 0xFD, 0x66, 0x21, 0x02,
0x58, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x48, 0x00, 0x2D, 0x02, 0xDB,
0x02, 0x73, 0x00, 0x0A, 0x00, 0x1A, 0x00, 0x25, 0x00, 0x32, 0x00, 0x3D,
0x00, 0x4B, 0x00, 0x74, 0x00, 0xC9, 0x00, 0x00, 0x01, 0x36, 0x32, 0x16,
0x15, 0x14, 0x23, 0x22, 0x26, 0x35, 0x34, 0x37, 0x36, 0x33, 0x32, 0x17,
0x16, 0x15, 0x14, 0x07, 0x06, 0x23, 0x22, 0x27, 0x26, 0x35, 0x34, 0x37,
0x36, 0x33, 0x32, 0x15, 0x14, 0x07, 0x23, 0x22, 0x35, 0x34, 0x35, 0x36,
0x33, 0x32, 0x17, 0x14, 0x32, 0x15, 0x14, 0x06, 0x22, 0x35, 0x34, 0x27,
0x36, 0x33, 0x32, 0x15, 0x14, 0x07, 0x06, 0x23, 0x22, 0x34, 0x05, 0x26,
0x23, 0x22, 0x06, 0x15, 0x14, 0x16, 0x33, 0x32, 0x37, 0x36, 0x35, 0x34,
0x27, 0x26, 0x23, 0x0E, 0x03, 0x07, 0x06, 0x07, 0x06, 0x14, 0x0E, 0x01,
0x16, 0x33, 0x32, 0x17, 0x16, 0x33, 0x32, 0x37, 0x36, 0x17, 0x16, 0x36,
0x17, 0x16, 0x37, 0x36, 0x32, 0x27, 0x26, 0x37, 0x36, 0x35, 0x34, 0x26,
0x2B, 0x01, 0x06, 0x27, 0x3E, 0x01, 0x37, 0x33, 0x32, 0x1F, 0x01, 0x33,
0x32, 0x17, 0x16, 0x15, 0x14, 0x07, 0x06, 0x0F, 0x01, 0x17, 0x16, 0x1D,
0x01, 0x14, 0x0E, 0x01, 0x07, 0x0E, 0x01, 0x15, 0x14, 0x17, 0x16, 0x33,
0x32, 0x15, 0x14, 0x07, 0x06, 0x23, 0x22, 0x27, 0x26, 0x23, 0x22, 0x07,
0x06, 0x15, 0x14, 0x17, 0x16, 0x33, 0x32, 0x36, 0x33, 0x36, 0x33, 0x32,
0x15, 0x14, 0x06, 0x07, 0x06, 0x15, 0x14, 0x17, 0x16, 0x15, 0x14, 0x07,
0x06, 0x23, 0x22, 0x27, 0x2E, 0x01, 0x35, 0x34, 0x37, 0x36, 0x35, 0x34,
0x27, 0x26, 0x35, 0x34, 0x02, 0x7A, 0x03, 0x0A, 0x0A, 0x05, 0x07, 0x0C,
0x1B, 0x03, 0x02, 0x04, 0x0F, 0x10, 0x01, 0x03, 0x02, 0x04, 0x0F, 0x10,
0x08, 0x05, 0x13, 0x28, 0x1C, 0x0A, 0x1C, 0x0D, 0x06, 0x04, 0x04, 0x01,
0x1A, 0x10, 0x15, 0x05, 0x04, 0x0A, 0x04, 0x07, 0x07, 0x05, 0xFE, 0xF3,
0x08, 0x14, 0x13, 0x21, 0x14, 0x19, 0x12, 0x0C, 0x0C, 0x90, 0x03, 0x04,
0x03, 0x0F, 0x09, 0x0B, 0x02, 0x06, 0x0E, 0x0D, 0x0A, 0x02, 0x05, 0x05,
0x09, 0x0D, 0x0C, 0x0A, 0x03, 0x02, 0x0D, 0x0C, 0x0B, 0x1A, 0x06, 0x06,
0x08, 0x07, 0x14, 0x04, 0x03, 0x06, 0x01, 0x2C, 0x0E, 0x02, 0x0C, 0x66,
0x1D, 0x27, 0x33, 0x05, 0x50, 0x38, 0x1A, 0x59, 0x57, 0x18, 0x1A, 0x0E,
0x0E, 0x4C, 0x49, 0x02, 0x03, 0x03, 0x06, 0x08, 0x0C, 0x0F, 0x04, 0x07,
0x09, 0x15, 0x09, 0x0B, 0x05, 0x02, 0x0A, 0x09, 0x19, 0x22, 0x0F, 0x07,
0x0D, 0x0E, 0x13, 0x02, 0x0B, 0x03, 0x06, 0x0C, 0x10, 0x16, 0x0D, 0x0E,
0x01, 0x02, 0x10, 0x22, 0x26, 0x43, 0x59, 0x1F, 0x13, 0x05, 0x05, 0x0B,
0x0F, 0x01, 0xDE, 0x07, 0x0C, 0x08, 0x0F, 0x10, 0x08, 0x03, 0x15, 0x06,
0x0E, 0x10, 0x0A, 0x03, 0x02, 0x06, 0x0E, 0x10, 0x0A, 0x03, 0x24, 0x06,
0x0C, 0x0A, 0x01, 0x0B, 0x02, 0x36, 0x0D, 0x06, 0x01, 0x01, 0x08, 0x1B,
0x06, 0x08, 0x20, 0x05, 0x0D, 0x06, 0x04, 0x09, 0x17, 0xAB, 0x08, 0x10,
0x0C, 0x09, 0x14, 0x06, 0x08, 0x11, 0x0B, 0xA8, 0x05, 0x01, 0x03, 0x03,
0x06, 0x05, 0x0C, 0x02, 0x01, 0x1E, 0x06, 0x08, 0x05, 0x1D, 0x1B, 0x01,
0x04, 0x08, 0x07, 0x16, 0x03, 0x06, 0x0F, 0x0D, 0x0D, 0x0C, 0x0C, 0x01,
0x04, 0x0E, 0x2C, 0x04, 0x07, 0x1A, 0x0E, 0x02, 0x2F, 0x16, 0x0A, 0x0A,
0x08, 0x05, 0x09, 0x0B, 0x04, 0x04, 0x0F, 0x1B, 0x0F, 0x0A, 0x07, 0x07,
0x02, 0x01, 0x01, 0x10, 0x09, 0x07, 0x04, 0x09, 0x2D, 0x18, 0x18, 0x1B,
0x08, 0x09, 0x0F, 0x07, 0x03, 0x04, 0x0A, 0x0B, 0x01, 0x01, 0x03, 0x09,
0x2C, 0x0F, 0x12, 0x0C, 0x08, 0x04, 0x0A, 0x02, 0x0A, 0x0C, 0x18, 0x4F,
0x1B, 0x18, 0x10, 0x0A, 0x1C, 0x20, 0x0E, 0x17, 0x34, 0x47, 0x2D, 0x4B,
0x00, 0x08, 0x00, 0x46, 0xFF, 0xCA, 0x03, 0x60, 0x02, 0xE0, 0x00, 0x10,
0x00, 0x14, 0x00, 0x18, 0x00, 0x1C, 0x00, 0x20, 0x00, 0x24, 0x00, 0x28,
0x00, 0x39, 0x00, 0x00, 0x36, 0x34, 0x36, 0x37, 0x36, 0x32, 0x17, 0x16,
0x17, 0x16, 0x14, 0x06, 0x07, 0x06, 0x22, 0x26, 0x27, 0x37, 0x33, 0x15,
0x23, 0x37, 0x33, 0x15, 0x23, 0x25, 0x33, 0x15, 0x23, 0x25, 0x33, 0x15,
0x23, 0x01, 0x33, 0x15, 0x23, 0x11, 0x33, 0x15, 0x23, 0x00, 0x14, 0x17,
0x1E, 0x01, 0x32, 0x37, 0x3E, 0x01, 0x34, 0x27, 0x26, 0x27, 0x2E, 0x01,
0x07, 0x06, 0x74, 0x5D, 0x51, 0x52, 0xBE, 0x52, 0x51, 0x2F, 0x2E, 0x5D,
0x51, 0x52, 0xBE, 0xA3, 0x2F, 0xF7, 0x75, 0x75, 0x32, 0x10, 0x10, 0x01,
0x2B, 0x6A, 0x6A, 0xFD, 0x50, 0x6B, 0x6B, 0x01, 0x85, 0x10, 0x10, 0x10,
0x10, 0xFE, 0xB6, 0x2D, 0x2D, 0x9C, 0xB8, 0x4E, 0x4E, 0x5A, 0x2D, 0x2D,
0x4E, 0x4E, 0xB8, 0x4E, 0x4E, 0xF6, 0xBE, 0xA0, 0x30, 0x2E, 0x2E, 0x2F,
0x51, 0x50, 0xBE, 0xA1, 0x30, 0x2E, 0x5D, 0x51, 0xB9, 0x10, 0x43, 0x76,
0x43, 0x10, 0x10, 0x10, 0x01, 0x92, 0x69, 0xFD, 0xBD, 0x6A, 0x01, 0xE6,
0xB7, 0x4D, 0x4E, 0x5A, 0x2D, 0x2E, 0x9A, 0xB7, 0x4D, 0x4E, 0x2D, 0x2C,
0x01, 0x2D, 0x2E, 0x00, 0x00, 0x0A, 0x00, 0x37, 0xFF, 0xAB, 0x03, 0x73,
0x02, 0xF5, 0x00, 0x0F, 0x00, 0x1F, 0x00, 0x2E, 0x00, 0x3A, 0x00, 0x46,
0x00, 0x59, 0x00, 0x69, 0x00, 0x78, 0x00, 0x87, 0x00, 0x97, 0x00, 0x00,
0x25, 0x36, 0x33, 0x36, 0x1F, 0x01, 0x1D, 0x01, 0x07, 0x06, 0x27, 0x2E,
0x01, 0x35, 0x34, 0x3E, 0x02, 0x33, 0x32, 0x16, 0x17, 0x16, 0x17, 0x16,
0x06, 0x23, 0x22, 0x27, 0x2E, 0x01, 0x35, 0x05, 0x3E, 0x01, 0x33, 0x32,
0x15, 0x14, 0x06, 0x07, 0x06, 0x23, 0x22, 0x26, 0x37, 0x36, 0x01, 0x36,
0x32, 0x17, 0x16, 0x14, 0x07, 0x06, 0x22, 0x27, 0x26, 0x34, 0x25, 0x36,
0x32, 0x17, 0x16, 0x14, 0x07, 0x06, 0x22, 0x27, 0x26, 0x34, 0x25, 0x36,
0x17, 0x1E, 0x01, 0x17, 0x16, 0x07, 0x0E, 0x01, 0x07, 0x06, 0x26, 0x27,
0x2E, 0x01, 0x37, 0x3E, 0x01, 0x17, 0x26, 0x2F, 0x01, 0x1D, 0x01, 0x37,
0x36, 0x37, 0x3E, 0x01, 0x37, 0x36, 0x27, 0x2E, 0x01, 0x37, 0x36, 0x33,
0x32, 0x16, 0x07, 0x06, 0x07, 0x0E, 0x01, 0x23, 0x22, 0x35, 0x34, 0x36,
0x25, 0x36, 0x32, 0x17, 0x1E, 0x01, 0x15, 0x14, 0x23, 0x22, 0x26, 0x27,
0x26, 0x27, 0x26, 0x25, 0x36, 0x37, 0x32, 0x1F, 0x01, 0x1D, 0x01, 0x07,
0x06, 0x27, 0x2E, 0x01, 0x35, 0x34, 0x36, 0x01, 0xCF, 0x04, 0x03, 0x02,
0x06, 0x07, 0x07, 0x0C, 0x0C, 0x04, 0x02, 0x0A, 0xD2, 0x09, 0x08, 0x06,
0x0D, 0x18, 0x22, 0x03, 0x05, 0x0A, 0x0B, 0x07, 0x25, 0x1A, 0x0B, 0xFE,
0x36, 0x18, 0x0D, 0x06, 0x11, 0x0B, 0x1A, 0x25, 0x07, 0x0B, 0x0A, 0x05,
0x03, 0x02, 0x4B, 0x06, 0x65, 0x06, 0x07, 0x07, 0x06, 0x65, 0x06, 0x06,
0xFD, 0x49, 0x05, 0x66, 0x06, 0x06, 0x06, 0x06, 0x66, 0x05, 0x07, 0x01,
0x6D, 0x43, 0x43, 0x3D, 0x5B, 0x10, 0x12, 0x17, 0x16, 0x67, 0x44, 0x4E,
0x8E, 0x2F, 0x25, 0x12, 0x15, 0x17, 0x6A, 0xB0, 0x14, 0x0C, 0x0B, 0x0B,
0x22, 0x25, 0x22, 0x38, 0x0E, 0x22, 0x22, 0x13, 0x4C, 0x81, 0x25, 0x07,
0x0B, 0x0A, 0x05, 0x03, 0x22, 0x18, 0x0D, 0x06, 0x11, 0x0B, 0xFE, 0x0A,
0x05, 0x0E, 0x25, 0x1A, 0x0B, 0x11, 0x06, 0x0D, 0x18, 0x22, 0x03, 0x08,
0x01, 0x2A, 0x04, 0x03, 0x02, 0x06, 0x07, 0x07, 0x0C, 0x0C, 0x04, 0x02,
0x0A, 0x31, 0x01, 0x01, 0x07, 0x06, 0x34, 0x34, 0x07, 0x0C, 0x0E, 0x04,
0x0F, 0x25, 0x33, 0x0C, 0x50, 0x0A, 0x0B, 0x17, 0x22, 0x06, 0x0A, 0x11,
0x25, 0x1A, 0x0E, 0x06, 0x10, 0x17, 0x0B, 0x12, 0x06, 0x0E, 0x1A, 0x25,
0x11, 0x0A, 0x06, 0x01, 0x1A, 0x05, 0x05, 0x05, 0x11, 0x05, 0x05, 0x05,
0x05, 0x11, 0x05, 0x05, 0x05, 0x05, 0x11, 0x05, 0x05, 0x05, 0x05, 0x11,
0xF4, 0x0C, 0x16, 0x15, 0x60, 0x3E, 0x4A, 0x46, 0x42, 0x5C, 0x0E, 0x10,
0x36, 0x3F, 0x32, 0x80, 0x3C, 0x40, 0x5A, 0x1D, 0x06, 0x01, 0x02, 0xDC,
0xDC, 0x01, 0x05, 0x12, 0x11, 0x3C, 0x24, 0x53, 0x52, 0x2F, 0x44, 0x43,
0x25, 0x11, 0x09, 0x07, 0x21, 0x18, 0x0A, 0x11, 0x06, 0x0E, 0x3C, 0x03,
0x25, 0x1A, 0x0E, 0x06, 0x11, 0x0A, 0x18, 0x21, 0x07, 0x0E, 0x7F, 0x01,
0x01, 0x07, 0x06, 0x34, 0x34, 0x07, 0x0C, 0x0E, 0x04, 0x0F, 0x26, 0x32,
0x0C, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x34, 0xFF, 0xE1, 0x03, 0x56,
0x02, 0xC4, 0x00, 0x0D, 0x00, 0x4F, 0x00, 0x60, 0x00, 0xC9, 0x00, 0xD8,
0x01, 0x20, 0x00, 0x00, 0x25, 0x26, 0x23, 0x22, 0x06, 0x15, 0x14, 0x17,
0x16, 0x33, 0x32, 0x36, 0x35, 0x34, 0x27, 0x36, 0x33, 0x32, 0x17, 0x16,
0x33, 0x32, 0x3F, 0x01, 0x17, 0x16, 0x15, 0x14, 0x07, 0x06, 0x15, 0x14,
0x33, 0x32, 0x14, 0x23, 0x22, 0x15, 0x14, 0x17, 0x16, 0x15, 0x14, 0x0F,
0x01, 0x27, 0x26, 0x22, 0x07, 0x06, 0x23, 0x22, 0x27, 0x26, 0x35, 0x34,
0x37, 0x36, 0x35, 0x34, 0x27, 0x26, 0x23, 0x22, 0x35, 0x34, 0x36, 0x35,
0x3E, 0x01, 0x37, 0x36, 0x37, 0x36, 0x35, 0x34, 0x27, 0x26, 0x35, 0x34,
0x27, 0x26, 0x23, 0x22, 0x07, 0x06, 0x15, 0x14, 0x16, 0x33, 0x32, 0x36,
0x35, 0x34, 0x27, 0x2E, 0x01, 0x27, 0x36, 0x33, 0x32, 0x16, 0x17, 0x16,
0x17, 0x16, 0x33, 0x32, 0x37, 0x36, 0x33, 0x32, 0x17, 0x16, 0x14, 0x07,
0x06, 0x15, 0x14, 0x17, 0x1E, 0x01, 0x15, 0x14, 0x06, 0x15, 0x0E, 0x01,
0x07, 0x06, 0x07, 0x06, 0x15, 0x14, 0x17, 0x16, 0x15, 0x14, 0x06, 0x23,
0x22, 0x27, 0x26, 0x23, 0x22, 0x07, 0x0E, 0x01, 0x07, 0x06, 0x07, 0x06,
0x23, 0x22, 0x27, 0x2E, 0x01, 0x27, 0x26, 0x23, 0x22, 0x0F, 0x01, 0x27,
0x26, 0x35, 0x34, 0x37, 0x36, 0x35, 0x34, 0x27, 0x26, 0x23, 0x22, 0x26,
0x3D, 0x01, 0x3F, 0x01, 0x3E, 0x01, 0x37, 0x36, 0x35, 0x34, 0x27, 0x26,
0x35, 0x34, 0x37, 0x36, 0x33, 0x32, 0x17, 0x16, 0x33, 0x32, 0x37, 0x36,
0x35, 0x34, 0x25, 0x26, 0x23, 0x22, 0x07, 0x06, 0x15, 0x14, 0x17, 0x16,
0x33, 0x32, 0x36, 0x35, 0x34, 0x27, 0x36, 0x33, 0x32, 0x17, 0x16, 0x33,
0x32, 0x3F, 0x01, 0x17, 0x1E, 0x01, 0x15, 0x14, 0x06, 0x15, 0x06, 0x15,
0x14, 0x16, 0x1F, 0x01, 0x15, 0x07, 0x0E, 0x01, 0x15, 0x14, 0x17, 0x16,
0x15, 0x14, 0x07, 0x06, 0x23, 0x22, 0x27, 0x26, 0x23, 0x22, 0x07, 0x06,
0x23, 0x22, 0x27, 0x26, 0x2F, 0x01, 0x37, 0x36, 0x35, 0x34, 0x27, 0x2E,
0x01, 0x35, 0x34, 0x36, 0x35, 0x3E, 0x01, 0x37, 0x3E, 0x01, 0x35, 0x34,
0x27, 0x26, 0x35, 0x37, 0x36, 0x02, 0xD9, 0x10, 0x14, 0x15, 0x1F, 0x03,
0x0B, 0x2A, 0x15, 0x1A, 0x82, 0x16, 0x02, 0x01, 0x17, 0x16, 0x0B, 0x0C,
0x12, 0x13, 0x19, 0x17, 0x06, 0x01, 0x25, 0x20, 0x20, 0x25, 0x01, 0x06,
0x17, 0x19, 0x13, 0x12, 0x1C, 0x13, 0x11, 0x07, 0x06, 0x0A, 0x1E, 0x06,
0x08, 0x08, 0x0B, 0x12, 0x20, 0x01, 0x01, 0x07, 0x11, 0x17, 0x0C, 0x08,
0x08, 0x07, 0xD7, 0x1C, 0x1D, 0x2E, 0x21, 0x1A, 0x3C, 0x2F, 0x2B, 0x3E,
0x02, 0x04, 0x1B, 0x77, 0x0C, 0x23, 0x1F, 0x13, 0x05, 0x04, 0x06, 0x06,
0x0B, 0x11, 0x16, 0x15, 0x07, 0x08, 0x1E, 0x1B, 0x15, 0x07, 0x27, 0x1B,
0x0F, 0x01, 0x02, 0x0D, 0x1E, 0x1A, 0x08, 0x06, 0x0F, 0x14, 0x3C, 0x07,
0x03, 0x1B, 0x14, 0x0B, 0x07, 0x04, 0x0A, 0x08, 0x03, 0x04, 0x05, 0x04,
0x29, 0x2E, 0x05, 0x05, 0x08, 0x0F, 0x0A, 0x04, 0x08, 0x18, 0x1E, 0x20,
0x20, 0x10, 0x0F, 0x09, 0x08, 0x17, 0x18, 0x11, 0x02, 0x23, 0x16, 0x0F,
0x04, 0x02, 0x11, 0x0F, 0x21, 0x16, 0x0B, 0x08, 0x19, 0x14, 0x09, 0x02,
0x08, 0x17, 0x01, 0xD1, 0x13, 0x0E, 0x0A, 0x0E, 0x1D, 0x15, 0x10, 0x12,
0x15, 0x1E, 0x88, 0x11, 0x09, 0x0C, 0x10, 0x12, 0x0B, 0x0C, 0x13, 0x15,
0x18, 0x0E, 0x09, 0x01, 0x03, 0x0A, 0x15, 0x1F, 0x1A, 0x16, 0x11, 0x04,
0x07, 0x13, 0x13, 0x08, 0x0C, 0x10, 0x13, 0x0A, 0x0B, 0x12, 0x11, 0x0B,
0x04, 0x03, 0x13, 0x0C, 0x0E, 0x0C, 0x08, 0x21, 0x15, 0x0F, 0x01, 0x01,
0x08, 0x14, 0x16, 0x0F, 0x06, 0x08, 0x01, 0x03, 0xA0, 0x10, 0x1F, 0x15,
0x09, 0x09, 0x20, 0x1E, 0x14, 0x16, 0x78, 0x0C, 0x17, 0x16, 0x18, 0x18,
0x0E, 0x0E, 0x13, 0x0C, 0x17, 0x03, 0x05, 0x1C, 0x4C, 0x1C, 0x05, 0x03,
0x16, 0x0D, 0x13, 0x0E, 0x0E, 0x18, 0x17, 0x16, 0x14, 0x06, 0x10, 0x0F,
0x09, 0x0F, 0x13, 0x06, 0x04, 0x0A, 0x0D, 0x23, 0x01, 0x07, 0x02, 0x14,
0x08, 0x02, 0x02, 0x0C, 0x0A, 0x04, 0x05, 0x13, 0x13, 0x06, 0x0C, 0xB2,
0x11, 0x26, 0x1E, 0x27, 0x2B, 0x3F, 0x40, 0x2B, 0x05, 0x0C, 0x16, 0x27,
0xB3, 0x0C, 0x10, 0x1B, 0x1A, 0x06, 0x08, 0x10, 0x10, 0x20, 0x1B, 0x12,
0x21, 0x0B, 0x0B, 0x18, 0x06, 0x05, 0x0E, 0x17, 0x03, 0x0D, 0x04, 0x20,
0x11, 0x04, 0x05, 0x0E, 0x09, 0x05, 0x07, 0x13, 0x18, 0x0A, 0x08, 0x3E,
0x15, 0x10, 0x02, 0x04, 0x0D, 0x13, 0x1F, 0x05, 0x07, 0x08, 0x07, 0x34,
0x08, 0x05, 0x11, 0x15, 0x1F, 0x1E, 0x0B, 0x0A, 0x14, 0x15, 0x09, 0x08,
0x0E, 0x0E, 0x13, 0x1C, 0x0E, 0x2C, 0x07, 0x05, 0x08, 0x0A, 0x08, 0x04,
0x0B, 0x14, 0x12, 0x08, 0x09, 0x25, 0x18, 0x13, 0x10, 0x02, 0x08, 0x24,
0x11, 0x06, 0x10, 0x07, 0x0E, 0x20, 0x19, 0x11, 0x0D, 0x1F, 0x15, 0x17,
0x75, 0x0B, 0x15, 0x16, 0x17, 0x19, 0x0D, 0x08, 0x09, 0x09, 0x01, 0x06,
0x02, 0x1C, 0x0D, 0x0E, 0x07, 0x04, 0x07, 0x40, 0x06, 0x05, 0x0C, 0x0A,
0x04, 0x10, 0x19, 0x06, 0x0C, 0x0A, 0x0B, 0x15, 0x17, 0x18, 0x14, 0x01,
0x06, 0x0B, 0x0C, 0x1A, 0x12, 0x09, 0x13, 0x06, 0x03, 0x0D, 0x10, 0x02,
0x08, 0x03, 0x14, 0x09, 0x05, 0x06, 0x09, 0x0A, 0x09, 0x12, 0x15, 0x0A,
0x02, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x34, 0x00, 0x12, 0x03, 0x22,
0x02, 0xA7, 0x00, 0x0D, 0x00, 0x46, 0x00, 0x00, 0x25, 0x26, 0x23, 0x22,
0x07, 0x06, 0x15, 0x14, 0x17, 0x16, 0x33, 0x32, 0x36, 0x34, 0x01, 0x36,
0x33, 0x32, 0x17, 0x16, 0x17, 0x1E, 0x01, 0x1F, 0x02, 0x1E, 0x01, 0x33,
0x32, 0x17, 0x16, 0x33, 0x32, 0x37, 0x33, 0x32, 0x17, 0x16, 0x33, 0x32,
0x37, 0x36, 0x33, 0x32, 0x16, 0x17, 0x16, 0x17, 0x16, 0x17, 0x16, 0x15,
0x14, 0x0F, 0x01, 0x27, 0x2E, 0x01, 0x27, 0x2E, 0x01, 0x27, 0x2E, 0x01,
0x27, 0x26, 0x27, 0x26, 0x35, 0x34, 0x02, 0xDB, 0x12, 0x17, 0x16, 0x11,
0x08, 0x10, 0x10, 0x0F, 0x10, 0x26, 0xFD, 0x65, 0x0F, 0x03, 0x04, 0x04,
0x09, 0x20, 0x1A, 0x6E, 0x2C, 0x17, 0x03, 0x03, 0x1A, 0x21, 0x1F, 0x12,
0x13, 0x18, 0x0A, 0x07, 0x02, 0x0E, 0x13, 0x14, 0x11, 0x13, 0x1E, 0x1D,
0x1F, 0x14, 0x12, 0x0E, 0x15, 0x07, 0x07, 0x07, 0x06, 0x3C, 0x3B, 0x30,
0x60, 0xCB, 0x07, 0x04, 0x3D, 0x18, 0x12, 0x1A, 0x19, 0x51, 0x15, 0x11,
0x8C, 0x14, 0x15, 0x09, 0x0F, 0x16, 0x0C, 0x0D, 0x20, 0x1A, 0x02, 0x01,
0x28, 0x2B, 0x56, 0x43, 0x34, 0x5F, 0x07, 0x04, 0x2A, 0x29, 0x1F, 0x0E,
0x10, 0x01, 0x0D, 0x0C, 0x10, 0x10, 0x07, 0x0E, 0x15, 0x1B, 0x1A, 0x04,
0x03, 0x04, 0x09, 0x1D, 0x1B, 0x08, 0x11, 0x47, 0x14, 0x0A, 0x26, 0x08,
0x04, 0x15, 0x1C, 0x5C, 0x45, 0x39, 0x2D, 0x39, 0x00, 0x01, 0x00, 0x87,
0x00, 0x35, 0x02, 0x87, 0x02, 0xAF, 0x00, 0x27, 0x00, 0x00, 0x01, 0x36,
0x17, 0x16, 0x17, 0x1E, 0x01, 0x07, 0x06, 0x07, 0x0E, 0x01, 0x14, 0x16,
0x17, 0x16, 0x17, 0x1E, 0x01, 0x0F, 0x01, 0x2B, 0x01, 0x27, 0x26, 0x36,
0x37, 0x36, 0x37, 0x36, 0x37, 0x36, 0x34, 0x26, 0x27, 0x2E, 0x01, 0x37,
0x3E, 0x01, 0x01, 0x61, 0x23, 0x25, 0x0F, 0x17, 0x31, 0x31, 0x0B, 0x09,
0x23, 0x13, 0x15, 0x18, 0x11, 0x67, 0x1E, 0x06, 0x01, 0x04, 0x04, 0xF8,
0xF8, 0x03, 0x05, 0x02, 0x05, 0x18, 0x4A, 0x25, 0x1D, 0x0A, 0x15, 0x13,
0x1C, 0x18, 0x08, 0x09, 0x44, 0x02, 0xA7, 0x08, 0x07, 0x03, 0x09, 0x15,
0x5A, 0x30, 0x28, 0x1E, 0x11, 0x0A, 0x02, 0x09, 0x0A, 0x3C, 0x83, 0x19,
0x52, 0x16, 0x12, 0x12, 0x16, 0x52, 0x19, 0x6B, 0x3C, 0x1E, 0x09, 0x04,
0x02, 0x0A, 0x11, 0x19, 0x46, 0x24, 0x26, 0x3E, 0x00, 0x0B, 0x00, 0x62,
0xFF, 0xDF, 0x03, 0x4A, 0x02, 0xC5, 0x00, 0x48, 0x00, 0x56, 0x00, 0x61,
0x00, 0x6D, 0x00, 0x7C, 0x00, 0x88, 0x00, 0xC4, 0x00, 0xD4, 0x00, 0xEF,
0x01, 0x04, 0x01, 0x1A, 0x00, 0x00, 0x01, 0x37, 0x17, 0x16, 0x15, 0x14,
0x07, 0x06, 0x17, 0x16, 0x17, 0x16, 0x17, 0x16, 0x15, 0x14, 0x17, 0x1E,
0x01, 0x33, 0x32, 0x37, 0x36, 0x17, 0x16, 0x33, 0x36, 0x17, 0x16, 0x17,
0x16, 0x1F, 0x01, 0x23, 0x22, 0x07, 0x06, 0x15, 0x14, 0x17, 0x16, 0x37,
0x36, 0x37, 0x36, 0x35, 0x34, 0x17, 0x16, 0x07, 0x06, 0x0F, 0x01, 0x17,
0x16, 0x07, 0x06, 0x07, 0x06, 0x27, 0x26, 0x27, 0x26, 0x27, 0x26, 0x37,
0x36, 0x35, 0x26, 0x27, 0x26, 0x35, 0x36, 0x05, 0x36, 0x33, 0x32, 0x17,
0x16, 0x15, 0x14, 0x07, 0x06, 0x27, 0x26, 0x2F, 0x01, 0x37, 0x36, 0x32,
0x1F, 0x01, 0x07, 0x06, 0x07, 0x22, 0x2F, 0x01, 0x3E, 0x01, 0x17, 0x16,
0x17, 0x16, 0x17, 0x15, 0x23, 0x06, 0x27, 0x26, 0x37, 0x36, 0x33, 0x32,
0x17, 0x16, 0x17, 0x14, 0x06, 0x23, 0x22, 0x27, 0x26, 0x35, 0x34, 0x27,
0x36, 0x17, 0x16, 0x07, 0x06, 0x07, 0x06, 0x27, 0x26, 0x27, 0x34, 0x25,
0x36, 0x33, 0x32, 0x1F, 0x04, 0x16, 0x15, 0x14, 0x0F, 0x01, 0x23, 0x22,
0x07, 0x06, 0x17, 0x16, 0x07, 0x06, 0x15, 0x06, 0x17, 0x16, 0x23, 0x06,
0x27, 0x26, 0x27, 0x26, 0x27, 0x26, 0x27, 0x26, 0x37, 0x32, 0x2F, 0x01,
0x37, 0x36, 0x17, 0x26, 0x27, 0x26, 0x2F, 0x01, 0x23, 0x06, 0x27, 0x26,
0x35, 0x26, 0x0F, 0x01, 0x2F, 0x01, 0x37, 0x36, 0x17, 0x34, 0x23, 0x22,
0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x17, 0x16, 0x37, 0x34, 0x37, 0x36,
0x03, 0x36, 0x16, 0x17, 0x1E, 0x01, 0x17, 0x1E, 0x01, 0x07, 0x06, 0x07,
0x06, 0x07, 0x06, 0x26, 0x27, 0x2E, 0x01, 0x27, 0x26, 0x36, 0x37, 0x3E,
0x01, 0x37, 0x36, 0x17, 0x2E, 0x01, 0x07, 0x22, 0x07, 0x06, 0x07, 0x06,
0x0F, 0x01, 0x1F, 0x01, 0x37, 0x36, 0x37, 0x36, 0x26, 0x27, 0x2E, 0x01,
0x03, 0x2E, 0x01, 0x23, 0x22, 0x07, 0x0E, 0x01, 0x17, 0x16, 0x17, 0x16,
0x17, 0x16, 0x32, 0x37, 0x36, 0x37, 0x3E, 0x01, 0x35, 0x34, 0x01, 0x38,
0x06, 0x0C, 0x0D, 0x09, 0x0A, 0x05, 0x02, 0x08, 0x06, 0x01, 0x02, 0x04,
0x05, 0x04, 0x02, 0x02, 0x05, 0x05, 0x01, 0x08, 0x01, 0x03, 0x09, 0x1B,
0x15, 0x1F, 0x17, 0x05, 0x0C, 0x0D, 0x09, 0x0A, 0x0A, 0x12, 0x0F, 0x06,
0x06, 0x06, 0x02, 0x02, 0x04, 0x07, 0x0F, 0x0A, 0x01, 0x03, 0x03, 0x02,
0x10, 0x33, 0x3F, 0x0E, 0x12, 0x12, 0x01, 0x02, 0x06, 0x04, 0x01, 0x07,
0x0B, 0x01, 0x01, 0x6A, 0x04, 0x02, 0x01, 0x05, 0x05, 0x04, 0x04, 0x03,
0x03, 0x04, 0x03, 0x12, 0x03, 0x04, 0x0D, 0x0D, 0x03, 0x03, 0x02, 0x01,
0x0E, 0x0D, 0x07, 0x03, 0x13, 0x14, 0x01, 0x01, 0x01, 0x13, 0x14, 0x03,
0x02, 0x01, 0x0A, 0x02, 0x02, 0x03, 0x03, 0x01, 0x16, 0x02, 0x02, 0x03,
0x03, 0x0D, 0x06, 0x06, 0x04, 0x03, 0x02, 0x03, 0x02, 0x05, 0x05, 0x01,
0xFE, 0xF9, 0x0D, 0x0B, 0x3C, 0x22, 0x0B, 0x39, 0x3A, 0x11, 0x12, 0x10,
0x0F, 0x2B, 0x2B, 0x01, 0x01, 0x04, 0x07, 0x06, 0x04, 0x01, 0x03, 0x03,
0x01, 0x01, 0x03, 0x08, 0x02, 0x03, 0x0A, 0x08, 0x2D, 0x18, 0x03, 0x01,
0x05, 0x06, 0x06, 0x06, 0x01, 0x07, 0x07, 0x09, 0x03, 0x03, 0x0D, 0x0A,
0x01, 0x02, 0x01, 0x06, 0x04, 0x0A, 0x0B, 0x05, 0x04, 0xAA, 0x02, 0x02,
0x04, 0x03, 0x03, 0x09, 0x01, 0x01, 0x07, 0x0C, 0x01, 0x02, 0x03, 0x77,
0x48, 0x8E, 0x38, 0x0D, 0x26, 0x08, 0x40, 0x16, 0x2E, 0x19, 0x2A, 0x2D,
0x3B, 0x5F, 0xD4, 0x53, 0x0D, 0x25, 0x09, 0x4E, 0x03, 0x50, 0x0A, 0x26,
0x0C, 0x54, 0xC2, 0x0D, 0x38, 0x09, 0x05, 0x11, 0x27, 0x25, 0x3D, 0x2A,
0x08, 0xF5, 0xF5, 0x0A, 0x1A, 0x16, 0x23, 0x01, 0x24, 0x26, 0x87, 0x8D,
0x65, 0x90, 0x01, 0x01, 0x0D, 0x46, 0x1B, 0x30, 0x34, 0x63, 0x32, 0x3A,
0x13, 0x42, 0x13, 0x52, 0x3E, 0x0E, 0x20, 0x01, 0xBD, 0x09, 0x0C, 0x0D,
0x01, 0x01, 0x03, 0x04, 0x03, 0x01, 0x01, 0x01, 0x02, 0x02, 0x05, 0x06,
0x01, 0x02, 0x14, 0x03, 0x06, 0x02, 0x07, 0x02, 0x0A, 0x16, 0x15, 0x1E,
0x1B, 0x06, 0x05, 0x05, 0x03, 0x04, 0x06, 0x0C, 0x03, 0x01, 0x04, 0x05,
0x03, 0x03, 0x02, 0x02, 0x0D, 0x18, 0x0F, 0x0A, 0x09, 0x11, 0x06, 0x05,
0x08, 0x19, 0x31, 0x0B, 0x12, 0x12, 0x04, 0x05, 0x18, 0x17, 0x0D, 0x0D,
0x1C, 0x2F, 0x19, 0x23, 0x08, 0x03, 0x08, 0x09, 0x02, 0x03, 0x02, 0x03,
0x03, 0x02, 0x08, 0x07, 0x0D, 0x05, 0x0D, 0x0C, 0x05, 0x05, 0x01, 0x0D,
0x0E, 0x1C, 0x03, 0x01, 0x01, 0x02, 0x01, 0x05, 0x06, 0x01, 0x02, 0x02,
0x28, 0x09, 0x03, 0x02, 0x04, 0x02, 0x16, 0x05, 0x04, 0x02, 0x03, 0x10,
0x09, 0x05, 0x02, 0x08, 0x08, 0x01, 0x02, 0x03, 0x02, 0x02, 0x03, 0x1D,
0x04, 0x22, 0x0A, 0x02, 0x01, 0x07, 0x08, 0x02, 0x01, 0x09, 0x09, 0x02,
0x03, 0x0B, 0x16, 0x14, 0x0D, 0x07, 0x06, 0x0E, 0x10, 0x02, 0x05, 0x09,
0x02, 0x06, 0x0A, 0x0A, 0x2A, 0x16, 0x03, 0x06, 0x06, 0x06, 0x06, 0x01,
0x06, 0x05, 0x08, 0x08, 0x08, 0x01, 0x01, 0x01, 0x03, 0x08, 0x07, 0x05,
0x0B, 0x0B, 0x02, 0x01, 0x7E, 0x02, 0x01, 0x01, 0x02, 0x05, 0x07, 0x07,
0x05, 0x0A, 0x0B, 0x06, 0x09, 0x09, 0x01, 0x46, 0x07, 0x29, 0x2E, 0x09,
0x27, 0x0B, 0x53, 0xCC, 0x5D, 0x35, 0x2A, 0x2F, 0x1C, 0x2E, 0x19, 0x42,
0x0A, 0x26, 0x0C, 0x65, 0xFC, 0x62, 0x0C, 0x26, 0x09, 0x3F, 0x0A, 0x02,
0x02, 0x01, 0x02, 0x05, 0x0E, 0x17, 0x25, 0x08, 0xF4, 0xF4, 0x0B, 0x1C,
0x2D, 0x49, 0x9D, 0x47, 0x4D, 0x62, 0xFE, 0xB8, 0x64, 0x8F, 0x0E, 0x52,
0xCE, 0x5E, 0x65, 0x33, 0x19, 0x0A, 0x03, 0x04, 0x0D, 0x2B, 0x09, 0x1B,
0x02, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x48, 0x00, 0x3F, 0x02, 0xD0,
0x02, 0xD0, 0x00, 0x07, 0x00, 0x17, 0x00, 0x27, 0x00, 0x2F, 0x00, 0x00,
0x01, 0x35, 0x3B, 0x01, 0x1D, 0x01, 0x2B, 0x01, 0x25, 0x37, 0x3B, 0x01,
0x1F, 0x01, 0x1D, 0x01, 0x0F, 0x01, 0x29, 0x01, 0x2F, 0x01, 0x19, 0x01,
0x25, 0x27, 0x2B, 0x01, 0x0F, 0x01, 0x1D, 0x01, 0x1F, 0x01, 0x3B, 0x01,
0x3F, 0x01, 0x3D, 0x01, 0x13, 0x35, 0x2B, 0x01, 0x1D, 0x01, 0x3B, 0x01,
0x01, 0xBE, 0x25, 0x25, 0x25, 0x25, 0xFE, 0x9E, 0x14, 0xF4, 0xF4, 0x3C,
0x3C, 0x12, 0x12, 0xFE, 0xE0, 0xFE, 0xE0, 0x12, 0x12, 0x01, 0xEA, 0x0C,
0xA4, 0xA4, 0x0B, 0x0A, 0x0B, 0x0A, 0xA7, 0xA7, 0x09, 0x09, 0x48, 0xF9,
0xF8, 0xF8, 0xF9, 0x02, 0x3E, 0x40, 0x40, 0x40, 0xB9, 0x19, 0x3C, 0x3C,
0xFB, 0xFB, 0x12, 0x11, 0x13, 0x14, 0x01, 0x1C, 0x01, 0x1D, 0x0A, 0x0C,
0x0B, 0x0B, 0x62, 0x63, 0x0B, 0x0A, 0x09, 0x0A, 0x63, 0x62, 0xFE, 0x56,
0x99, 0x99, 0x99, 0x00, 0x00, 0x04, 0x00, 0x68, 0x01, 0x14, 0x02, 0xB4,
0x02, 0x39, 0x00, 0x1B, 0x00, 0x40, 0x00, 0x4E, 0x00, 0x5A, 0x00, 0x00,
0x01, 0x27, 0x3B, 0x01, 0x15, 0x14, 0x17, 0x1E, 0x01, 0x37, 0x3E, 0x01,
0x3D, 0x01, 0x3B, 0x01, 0x1D, 0x01, 0x2B, 0x01, 0x3D, 0x01, 0x07, 0x06,
0x23, 0x22, 0x2F, 0x01, 0x25, 0x36, 0x17, 0x16, 0x17, 0x16, 0x14, 0x1F,
0x01, 0x2B, 0x01, 0x27, 0x2E, 0x01, 0x07, 0x06, 0x07, 0x06, 0x26, 0x27,
0x26, 0x37, 0x36, 0x37, 0x3E, 0x01, 0x35, 0x34, 0x23, 0x22, 0x07, 0x06,
0x26, 0x2F, 0x01, 0x37, 0x36, 0x17, 0x34, 0x2E, 0x01, 0x31, 0x06, 0x07,
0x0E, 0x01, 0x17, 0x1E, 0x01, 0x37, 0x36, 0x25, 0x35, 0x3B, 0x01, 0x1D,
0x01, 0x3B, 0x01, 0x1D, 0x01, 0x2B, 0x01, 0x01, 0x3D, 0x01, 0x18, 0x19,
0x02, 0x04, 0x21, 0x0F, 0x0A, 0x05, 0x1A, 0x19, 0x17, 0x17, 0x0A, 0x17,
0x1E, 0x23, 0x10, 0x08, 0x00, 0xFF, 0x0E, 0x1A, 0x3B, 0x08, 0x03, 0x05,
0x05, 0x18, 0x18, 0x03, 0x02, 0x04, 0x05, 0x05, 0x0D, 0x19, 0x34, 0x0A,
0x10, 0x17, 0x0D, 0x2E, 0x1E, 0x0D, 0x21, 0x16, 0x08, 0x04, 0x0E, 0x0F,
0x0E, 0x03, 0x0C, 0x5F, 0x01, 0x01, 0x25, 0x0F, 0x06, 0x08, 0x03, 0x05,
0x1A, 0x0F, 0x13, 0xFD, 0xEE, 0x19, 0x1A, 0x40, 0x40, 0x5A, 0x59, 0x01,
0x98, 0x55, 0x45, 0x45, 0x0A, 0x10, 0x09, 0x0B, 0x09, 0x1C, 0x39, 0x44,
0x68, 0x67, 0x0F, 0x0E, 0x0A, 0x17, 0x1C, 0x0E, 0xAA, 0x04, 0x01, 0x02,
0x2A, 0x0E, 0x7A, 0x0F, 0x10, 0x0B, 0x0A, 0x02, 0x06, 0x06, 0x07, 0x0E,
0x0F, 0x18, 0x26, 0x1C, 0x11, 0x0B, 0x08, 0x05, 0x07, 0x1B, 0x11, 0x09,
0x03, 0x02, 0x01, 0x0C, 0x24, 0x76, 0x05, 0x07, 0x04, 0x06, 0x09, 0x03,
0x0F, 0x09, 0x0D, 0x06, 0x08, 0x0A, 0x59, 0x8D, 0x75, 0x76, 0x18, 0x18,
0x00, 0x0F, 0x00, 0x1E, 0x00, 0x85, 0x03, 0xCA, 0x02, 0xC6, 0x00, 0x07,
0x00, 0x22, 0x00, 0x33, 0x00, 0x37, 0x00, 0x3B, 0x00, 0x3F, 0x00, 0x43,
0x00, 0x47, 0x00, 0x4B, 0x00, 0x4F, 0x00, 0x53, 0x00, 0x57, 0x00, 0x5B,
0x00, 0x5F, 0x00, 0x63, 0x00, 0x00, 0x01, 0x37, 0x33, 0x1D, 0x01, 0x23,
0x35, 0x33, 0x25, 0x10, 0x17, 0x16, 0x17, 0x16, 0x33, 0x21, 0x32, 0x37,
0x36, 0x37, 0x36, 0x35, 0x11, 0x34, 0x27, 0x26, 0x27, 0x26, 0x23, 0x21,
0x22, 0x07, 0x06, 0x07, 0x06, 0x13, 0x26, 0x10, 0x37, 0x32, 0x33, 0x20,
0x33, 0x16, 0x15, 0x14, 0x15, 0x14, 0x07, 0x06, 0x23, 0x20, 0x13, 0x33,
0x35, 0x23, 0x17, 0x33, 0x35, 0x23, 0x17, 0x33, 0x35, 0x23, 0x17, 0x33,
0x35, 0x23, 0x17, 0x33, 0x35, 0x23, 0x05, 0x33, 0x35, 0x23, 0x17, 0x33,
0x35, 0x23, 0x17, 0x33, 0x35, 0x23, 0x17, 0x33, 0x35, 0x23, 0x05, 0x21,
0x35, 0x21, 0x07, 0x33, 0x35, 0x23, 0x05, 0x33, 0x35, 0x23, 0x02, 0xF5,
0x01, 0x5A, 0x91, 0x36, 0xFD, 0x29, 0x01, 0x05, 0x27, 0x0C, 0x22, 0x02,
0xF6, 0x22, 0x0C, 0x27, 0x05, 0x01, 0x03, 0x07, 0x2B, 0x0A, 0x1C, 0xFD,
0x0A, 0x33, 0x0F, 0x12, 0x04, 0x03, 0x3E, 0x01, 0x01, 0x0B, 0x12, 0x03,
0x0A, 0x09, 0x01, 0x01, 0x0B, 0x12, 0xFC, 0xF6, 0x33, 0x5A, 0x5A, 0x79,
0x5B, 0x5B, 0x79, 0x5B, 0x5B, 0x79, 0x5B, 0x5B, 0x79, 0x5B, 0x5B, 0xFE,
0x1C, 0x97, 0x97, 0xB5, 0x5B, 0x5B, 0x7A, 0x5A, 0x5A, 0x79, 0x5B, 0x5B,
0xFE, 0xD1, 0x01, 0xC6, 0xFE, 0x3A, 0x79, 0x5A, 0x5A, 0x02, 0x5E, 0x5A,
0x5A, 0x01, 0xDA, 0x72, 0x98, 0x3C, 0x5B, 0x97, 0xFE, 0x5A, 0x0A, 0x2B,
0x07, 0x03, 0x03, 0x07, 0x2B, 0x0A, 0x1C, 0x01, 0x8A, 0x23, 0x0C, 0x26,
0x05, 0x01, 0x0A, 0x0B, 0x17, 0x0C, 0xFE, 0x36, 0x0C, 0x01, 0xAC, 0x0D,
0x0B, 0xAE, 0x14, 0x15, 0xD6, 0x0D, 0x01, 0x01, 0x2F, 0x5B, 0x5B, 0x5B,
0x5B, 0x5B, 0x5B, 0x5B, 0x5B, 0x5B, 0xD4, 0x5B, 0x5B, 0x5B, 0x5B, 0x5B,
0x5B, 0x5B, 0xD4, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x00, 0x00, 0x00, 0x10,
0x00, 0xC6, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x09,
0x00, 0x14, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x07,
0x00, 0x2E, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x26,
0x00, 0x84, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x09,
0x00, 0xBF, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x0F,
0x00, 0xE9, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x09,
0x01, 0x0D, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x0B,
0x01, 0x2F, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x07,
0x01, 0x4B, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, 0x00, 0x01, 0x00, 0x12,
0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, 0x00, 0x02, 0x00, 0x0E,
0x00, 0x1E, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, 0x00, 0x03, 0x00, 0x4C,
0x00, 0x36, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, 0x00, 0x04, 0x00, 0x12,
0x00, 0xAB, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, 0x00, 0x05, 0x00, 0x1E,
0x00, 0xC9, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, 0x00, 0x06, 0x00, 0x12,
0x00, 0xF9, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, 0x00, 0x10, 0x00, 0x16,
0x01, 0x17, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, 0x00, 0x11, 0x00, 0x0E,
0x01, 0x3B, 0x00, 0x67, 0x00, 0x61, 0x00, 0x6D, 0x00, 0x65, 0x00, 0x73,
0x00, 0x65, 0x00, 0x6E, 0x00, 0x73, 0x00, 0x65, 0x00, 0x00, 0x67, 0x61,
0x6D, 0x65, 0x73, 0x65, 0x6E, 0x73, 0x65, 0x00, 0x00, 0x52, 0x00, 0x65,
0x00, 0x67, 0x00, 0x75, 0x00, 0x6C, 0x00, 0x61, 0x00, 0x72, 0x00, 0x00,
0x52, 0x65, 0x67, 0x75, 0x6C, 0x61, 0x72, 0x00, 0x00, 0x46, 0x00, 0x6F,
0x00, 0x6E, 0x00, 0x74, 0x00, 0x46, 0x00, 0x6F, 0x00, 0x72, 0x00, 0x67,
0x00, 0x65, 0x00, 0x20, 0x00, 0x32, 0x00, 0x2E, 0x00, 0x30, 0x00, 0x20,
0x00, 0x3A, 0x00, 0x20, 0x00, 0x67, 0x00, 0x61, 0x00, 0x6D, 0x00, 0x65,
0x00, 0x73, 0x00, 0x65, 0x00, 0x6E, 0x00, 0x73, 0x00, 0x65, 0x00, 0x20,
0x00, 0x3A, 0x00, 0x20, 0x00, 0x32, 0x00, 0x36, 0x00, 0x2D, 0x00, 0x31,
0x00, 0x30, 0x00, 0x2D, 0x00, 0x32, 0x00, 0x30, 0x00, 0x31, 0x00, 0x39,
0x00, 0x00, 0x46, 0x6F, 0x6E, 0x74, 0x46, 0x6F, 0x72, 0x67, 0x65, 0x20,
0x32, 0x2E, 0x30, 0x20, 0x3A, 0x20, 0x67, 0x61, 0x6D, 0x65, 0x73, 0x65,
0x6E, 0x73, 0x65, 0x20, 0x3A, 0x20, 0x32, 0x36, 0x2D, 0x31, 0x30, 0x2D,
0x32, 0x30, 0x31, 0x39, 0x00, 0x00, 0x67, 0x00, 0x61, 0x00, 0x6D, 0x00,
0x65, 0x00, 0x73, 0x00, 0x65, 0x00, 0x6E, 0x00, 0x73, 0x00, 0x65, 0x00,
0x00, 0x67, 0x61, 0x6D, 0x65, 0x73, 0x65, 0x6E, 0x73, 0x65, 0x00, 0x00,
0x56, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6F, 0x00,
0x6E, 0x00, 0x20, 0x00, 0x30, 0x00, 0x30, 0x00, 0x31, 0x00, 0x2E, 0x00,
0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x00, 0x56, 0x65, 0x72, 0x73, 0x69,
0x6F, 0x6E, 0x20, 0x30, 0x30, 0x31, 0x2E, 0x30, 0x30, 0x30, 0x00, 0x00,
0x67, 0x00, 0x61, 0x00, 0x6D, 0x00, 0x65, 0x00, 0x73, 0x00, 0x65, 0x00,
0x6E, 0x00, 0x73, 0x00, 0x65, 0x00, 0x00, 0x67, 0x61, 0x6D, 0x65, 0x73,
0x65, 0x6E, 0x73, 0x65, 0x00, 0x00, 0x43, 0x00, 0x61, 0x00, 0x6C, 0x00,
0x6C, 0x00, 0x69, 0x00, 0x67, 0x00, 0x72, 0x00, 0x61, 0x00, 0x70, 0x00,
0x68, 0x00, 0x72, 0x00, 0x00, 0x43, 0x61, 0x6C, 0x6C, 0x69, 0x67, 0x72,
0x61, 0x70, 0x68, 0x72, 0x00, 0x00, 0x52, 0x00, 0x65, 0x00, 0x67, 0x00,
0x75, 0x00, 0x6C, 0x00, 0x61, 0x00, 0x72, 0x00, 0x00, 0x52, 0x65, 0x67,
0x75, 0x6C, 0x61, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xFF, 0x1F, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02,
0x01, 0x02, 0x00, 0x03, 0x00, 0x24, 0x00, 0x25, 0x00, 0x26, 0x00, 0x27,
0x00, 0x28, 0x00, 0x29, 0x00, 0x2A, 0x00, 0x2B, 0x00, 0x2C, 0x00, 0x2D,
0x01, 0x03, 0x07, 0x75, 0x6E, 0x69, 0x30, 0x30, 0x30, 0x44, 0x07, 0x75,
0x6E, 0x69, 0x30, 0x30, 0x41, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01,
0xFF, 0xFF, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
0xE5, 0x0D, 0xB7, 0x93, 0x00, 0x00, 0x00, 0x00, 0xD5, 0x6E, 0x7C, 0x67,
0x00, 0x00, 0x00, 0x00, 0xE6, 0x38, 0x53, 0x0B
};
@@ -0,0 +1,8 @@
#include "../../Globalincludes.h"
namespace FontsData
{
extern BYTE KeyBindsFont[];
extern BYTE LegitTabIcons[];
extern BYTE TabIcons[];
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,6 @@
#include "../../Globalincludes.h"
namespace TexturesData
{
extern BYTE BgTexture[];
}
+12
View File
@@ -0,0 +1,12 @@
#pragma once
template <typename T>
class singleton
{
public:
static T* get()
{
static T instance;
return &instance;
}
};
@@ -0,0 +1,129 @@
#include "Utilities.h"
#include "../Main/Main.h"
#include <iostream>
std::unique_ptr<Misc::CUtilities> Misc::Utilities = std::make_unique<Misc::CUtilities>();
using namespace Misc;
void CUtilities::Console_Create(std::string title)
{
AllocConsole();
AttachConsole(GetCurrentProcessId());
freopen_s(&m_pOutputFile, "CONOUT$", "w", stdout);
m_hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTitleA(title.c_str());
}
void CUtilities::Console_Close()
{
if (!m_pOutputFile || !m_hOutput || m_hOutput == INVALID_HANDLE_VALUE)
return;
fclose(m_pOutputFile);
SetStdHandle(STD_OUTPUT_HANDLE, m_hOldOutput);
FreeConsole();
}
void CUtilities::Console_Log(const char* text, ...)
{
if (!text)
return;
va_list va_args;
char buffer[2048] = { 0 };
va_start(va_args, text);
_vsnprintf_s(buffer, sizeof(buffer), text, va_args);
va_end(va_args);
std::cout << "[ GamesenseMenuFramework ] ";
std::cout << ": " << buffer << std::endl;
}
void CUtilities::Console_SetTitle(std::string title)
{
SetConsoleTitleA(title.c_str());
}
bool CUtilities::IsAnyMouseDown()
{
for (int n = 0; n < sizeof(this->MouseDown); n++)
if (this->MouseDown[n])
return true;
return false;
}
LRESULT CUtilities::WndProcHandler(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
int dbutton = 0;
int ubutton = 0;
switch (msg)
{
case WM_LBUTTONDOWN:
dbutton = 0; break;
case WM_RBUTTONDOWN:
dbutton = 1; break;
case WM_MBUTTONDOWN:
dbutton = 2; break;
case WM_XBUTTONDOWN:
{
if (LOWORD(wParam) == MK_XBUTTON1)
dbutton = 3;
if (LOWORD(wParam) == MK_XBUTTON2)
dbutton = 4;
if (!this->IsAnyMouseDown() && GetCapture() == NULL)
SetCapture(hwnd);
this->MouseDown[dbutton] = true;
return true;
}
case WM_LBUTTONUP:
ubutton = 0;
case WM_RBUTTONUP:
ubutton = 1;
case WM_MBUTTONUP:
ubutton = 2;
case WM_XBUTTONUP:
{
if (LOWORD(wParam) == MK_XBUTTON1)
ubutton = 3;
if (LOWORD(wParam) == MK_XBUTTON2)
ubutton = 4;
this->MouseDown[ubutton] = false;
if (!this->IsAnyMouseDown() && GetCapture() == hwnd)
ReleaseCapture();
return true;
}
case WM_MOUSEWHEEL:
return true;
case WM_MOUSEMOVE:
return false;
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
if (wParam < 256)
this->KeysDown[wParam] = 1;
return false;
case WM_KEYUP:
case WM_SYSKEYUP:
if (wParam < 256)
this->KeysDown[wParam] = 0;
return false;
case WM_CHAR:
return true;
case WM_SETCURSOR:
if (LOWORD(lParam) == HTCLIENT)
return 1;
return false;
}
return 0;
}
float CUtilities::GetDeltaTime() {
return GetStandaloneDeltaTime();
}
@@ -0,0 +1,29 @@
#pragma once
#include "../Globalincludes.h"
namespace Misc {
class CUtilities
{
public:
float deltaTime = 0.f;
void Console_Create(std::string title = "");
void Console_Close();
void Console_Log(const char* text, ...);
void Console_SetTitle(std::string title);
LRESULT WndProcHandler(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
bool IsAnyMouseDown();
float GetDeltaTime();
std::string GetCurrentDirectory();
private:
bool MouseDown[5];
bool KeysDown[512];
FILE* m_pOutputFile = nullptr;
HANDLE m_hOldOutput = NULL, m_hOutput = NULL;
};
extern std::unique_ptr<CUtilities> Utilities;
}
@@ -0,0 +1,77 @@
#include "AutoStart.h"
namespace {
const wchar_t* RUN_KEY = L"Software\\Microsoft\\Windows\\CurrentVersion\\Run";
// 获取默认 appNameexe 文件名,不含 .exe 后缀)
std::wstring GetDefaultAppName() {
wchar_t path[MAX_PATH];
GetModuleFileNameW(nullptr, path, MAX_PATH);
wchar_t* name = wcsrchr(path, L'\\');
if (!name) name = path; else ++name;
std::wstring result(name);
// 去掉 .exe 后缀
size_t dot = result.rfind(L'.');
if (dot != std::wstring::npos) result = result.substr(0, dot);
return result;
}
// 获取完整 exe 路径
std::wstring GetExePath() {
wchar_t path[MAX_PATH];
GetModuleFileNameW(nullptr, path, MAX_PATH);
return path;
}
} // anonymous namespace
namespace AutoStart {
bool IsEnabled(const wchar_t* appName) {
std::wstring name = appName ? std::wstring(appName) : GetDefaultAppName();
HKEY hKey = nullptr;
if (RegOpenKeyExW(HKEY_CURRENT_USER, RUN_KEY, 0, KEY_READ, &hKey) != ERROR_SUCCESS) {
return false;
}
DWORD type = 0;
LSTATUS result = RegQueryValueExW(hKey, name.c_str(), nullptr, &type, nullptr, nullptr);
RegCloseKey(hKey);
return (result == ERROR_SUCCESS && type == REG_SZ);
}
bool Enable(const wchar_t* appName, const wchar_t* exePath) {
std::wstring name = appName ? std::wstring(appName) : GetDefaultAppName();
std::wstring path = exePath ? std::wstring(exePath) : GetExePath();
HKEY hKey = nullptr;
if (RegOpenKeyExW(HKEY_CURRENT_USER, RUN_KEY, 0, KEY_WRITE, &hKey) != ERROR_SUCCESS) {
return false;
}
DWORD dataSize = static_cast<DWORD>((path.size() + 1) * sizeof(wchar_t));
LSTATUS result = RegSetValueExW(hKey, name.c_str(), 0, REG_SZ,
reinterpret_cast<const BYTE*>(path.c_str()), dataSize);
RegCloseKey(hKey);
return result == ERROR_SUCCESS;
}
bool Disable(const wchar_t* appName) {
std::wstring name = appName ? std::wstring(appName) : GetDefaultAppName();
HKEY hKey = nullptr;
if (RegOpenKeyExW(HKEY_CURRENT_USER, RUN_KEY, 0, KEY_WRITE, &hKey) != ERROR_SUCCESS) {
return false;
}
LSTATUS result = RegDeleteValueW(hKey, name.c_str());
RegCloseKey(hKey);
return result == ERROR_SUCCESS;
}
} // namespace AutoStart
@@ -0,0 +1,26 @@
#pragma once
#include <Windows.h>
#include <string>
// ============================================================================
// AutoStart — 独立的 Windows 开机自启模块(注册表 Run 键)
//
// 用法:
// AutoStart::Enable(); // 用 exe 名作为键名,当前路径作为值
// AutoStart::Enable(L"MyApp"); // 自定义键名
// bool on = AutoStart::IsEnabled();
// AutoStart::Disable();
// ============================================================================
namespace AutoStart {
// 查询自启是否已启用(键名默认为 exe 文件名)
bool IsEnabled(const wchar_t* appName = nullptr);
// 启用自启(写入 HKCU\...\Run
bool Enable(const wchar_t* appName = nullptr, const wchar_t* exePath = nullptr);
// 禁用自启(删除注册表值)
bool Disable(const wchar_t* appName = nullptr);
} // namespace AutoStart
@@ -0,0 +1,51 @@
#include "ClipboardUtils.h"
#include <cstdio>
#include <algorithm>
bool ClipboardUtils::CopyColor(int r, int g, int b, int a) {
char buf[32];
sprintf_s(buf, sizeof(buf), "%d,%d,%d,%d", r, g, b, a);
if (!OpenClipboard(NULL))
return false;
EmptyClipboard();
HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, strlen(buf) + 1);
if (!hMem) {
CloseClipboard();
return false;
}
char* p = (char*)GlobalLock(hMem);
strcpy_s(p, strlen(buf) + 1, buf);
GlobalUnlock(hMem);
SetClipboardData(CF_TEXT, hMem);
CloseClipboard();
return true;
}
bool ClipboardUtils::PasteColor(int col[4]) {
if (!OpenClipboard(NULL))
return false;
HANDLE hData = GetClipboardData(CF_TEXT);
if (!hData) { CloseClipboard(); return false; }
char* p = (char*)GlobalLock(hData);
if (!p) { CloseClipboard(); return false; }
int r = 255, gv = 255, b = 255, a = 255;
int parsed = sscanf_s(p, "%d,%d,%d,%d", &r, &gv, &b, &a);
GlobalUnlock(hData);
CloseClipboard();
if (parsed >= 3) {
col[0] = std::clamp(r, 0, 255);
col[1] = std::clamp(gv, 0, 255);
col[2] = std::clamp(b, 0, 255);
col[3] = (parsed >= 4) ? std::clamp(a, 0, 255) : 255;
return true;
}
return false;
}
bool ClipboardUtils::HasText() {
if (!OpenClipboard(NULL))
return false;
bool has = IsClipboardFormatAvailable(CF_TEXT) != 0;
CloseClipboard();
return has;
}
@@ -0,0 +1,15 @@
#pragma once
#include "../Globalincludes.h"
#include <string>
namespace ClipboardUtils {
// Copy RGBA color to system clipboard in "R,G,B,A" format
bool CopyColor(int r, int g, int b, int a);
// Paste RGBA color from system clipboard, returns true if successful
// On failure, col[] is unchanged
bool PasteColor(int col[4]);
// Check if clipboard has text content
bool HasText();
}
@@ -0,0 +1,213 @@
#include "SysTray.h"
UINT SysTray::WM_TASKBARCREATED = RegisterWindowMessage(TEXT("TaskbarCreated"));
SysTray::SysTray(HWND hwnd, HICON hIcon, const wchar_t* tooltip)
: m_hwnd(hwnd)
, m_trayHwnd(nullptr)
, m_hIcon(hIcon ? hIcon : LoadIcon(nullptr, IDI_APPLICATION))
, m_timerId(0)
{
// 生成唯一窗口类名
wchar_t buf[64];
swprintf_s(buf, L"SysTray_%p", this);
m_className = buf;
if (!RegisterWindowClass()) return;
m_trayHwnd = CreateWindowEx(
0, m_className.c_str(), L"",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
nullptr, nullptr, GetModuleHandle(nullptr), nullptr
);
if (!m_trayHwnd) return;
// 将 this 指针存入窗口,窗口过程通过 GWLP_USERDATA 取回
SetWindowLongPtr(m_trayHwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this));
ZeroMemory(&m_nid, sizeof(m_nid));
m_nid.cbSize = sizeof(m_nid);
m_nid.hWnd = m_trayHwnd;
m_nid.uID = 1;
m_nid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
m_nid.uCallbackMessage = WM_TRAYICON;
m_nid.hIcon = m_hIcon;
wcscpy_s(m_nid.szTip, tooltip ? tooltip : L"");
}
SysTray::~SysTray() {
StopAutoRefresh();
RemoveIcon();
if (m_trayHwnd) {
SetWindowLongPtr(m_trayHwnd, GWLP_USERDATA, 0);
DestroyWindow(m_trayHwnd);
m_trayHwnd = nullptr;
}
UnregisterWindowClass();
}
bool SysTray::RegisterWindowClass() {
WNDCLASSEX wc = {};
wc.cbSize = sizeof(WNDCLASSEX);
wc.lpfnWndProc = WindowProc;
wc.hInstance = GetModuleHandle(nullptr);
wc.lpszClassName = m_className.c_str();
wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
wc.hbrBackground = static_cast<HBRUSH>(GetStockObject(WHITE_BRUSH));
return RegisterClassEx(&wc) != 0;
}
void SysTray::UnregisterWindowClass() {
UnregisterClass(m_className.c_str(), GetModuleHandle(nullptr));
}
bool SysTray::AddIcon() {
if (!m_trayHwnd) return false;
return Shell_NotifyIcon(NIM_ADD, &m_nid) != FALSE;
}
bool SysTray::RemoveIcon() {
if (!m_trayHwnd) return false;
return Shell_NotifyIcon(NIM_DELETE, &m_nid) != FALSE;
}
bool SysTray::RefreshIcon() {
if (!m_trayHwnd) return false;
m_nid.uFlags = NIF_ICON | NIF_TIP;
return Shell_NotifyIcon(NIM_MODIFY, &m_nid) != FALSE;
}
void SysTray::ReaddIcon() {
for (int retry = 0; retry < 3; ++retry) {
RemoveIcon(); // best-effort cleanup; may fail if explorer already removed the icon
if (AddIcon()) return;
if (retry < 2) Sleep(100);
}
}
void SysTray::StartAutoRefresh(UINT intervalMinutes) {
if (m_timerId != 0) {
KillTimer(m_trayHwnd, m_timerId);
}
if (intervalMinutes == 0) {
m_timerId = 0;
return;
}
m_timerId = SetTimer(m_trayHwnd, 1, intervalMinutes * 60 * 1000, nullptr);
}
void SysTray::StopAutoRefresh() {
if (m_timerId != 0) {
KillTimer(m_trayHwnd, m_timerId);
m_timerId = 0;
}
}
void SysTray::AddMenuItem(UINT id, const wchar_t* text, MenuCallback onSelect) {
m_menuItems.push_back({id, text, std::move(onSelect)});
}
void SysTray::SetMenuItemChecked(UINT id, bool checked) {
for (auto& item : m_menuItems) {
if (item.id == id) {
item.checked = checked;
return;
}
}
}
void SysTray::ClearMenuItems() {
m_menuItems.clear();
}
void SysTray::ShowContextMenu() {
HMENU hMenu = CreatePopupMenu();
if (!hMenu) return;
for (const auto& item : m_menuItems) {
UINT flags = MF_STRING;
if (item.checked) flags |= MF_CHECKED;
AppendMenu(hMenu, flags, item.id, item.text.c_str());
}
POINT pt;
GetCursorPos(&pt);
SetForegroundWindow(m_trayHwnd);
TrackPopupMenu(hMenu, TPM_RIGHTBUTTON, pt.x, pt.y, 0, m_trayHwnd, nullptr);
PostMessage(m_trayHwnd, WM_NULL, 0, 0);
DestroyMenu(hMenu);
}
void SysTray::HandleMessage(UINT msg, WPARAM wParam, LPARAM lParam) {
if (msg != WM_TRAYICON) return;
switch (lParam) {
case WM_RBUTTONUP:
ShowContextMenu();
break;
case WM_LBUTTONUP:
if (m_onLeftClick) m_onLeftClick();
break;
case WM_LBUTTONDBLCLK:
if (m_onDoubleClick) m_onDoubleClick();
break;
}
}
LRESULT CALLBACK SysTray::WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
auto* self = reinterpret_cast<SysTray*>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
// 托盘图标消息
if (self && msg == self->WM_TRAYICON) {
self->HandleMessage(msg, wParam, lParam);
return 0;
}
// Explorer 重启后重建托盘图标
if (msg == WM_TASKBARCREATED) {
if (self) self->ReaddIcon();
return 0;
}
// 菜单命令
if (msg == WM_COMMAND && self) {
UINT id = LOWORD(wParam);
// 先查菜单项回调
for (const auto& item : self->m_menuItems) {
if (item.id == id && item.callback) {
item.callback(id);
return 0;
}
}
// 再查通用菜单回调
if (self->m_menuCallback) {
self->m_menuCallback(id);
}
return 0;
}
// 自动刷新定时器
if (msg == WM_TIMER && self) {
self->RefreshIcon();
return 0;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
// ============================================================================
// 便捷函数
// ============================================================================
SysTray* SysTrayUtil::CreateSimple(HWND hwnd, HICON hIcon, const wchar_t* tooltip) {
auto* tray = new SysTray(hwnd, hIcon, tooltip);
tray->SetOnDoubleClick([hwnd]() {
ShowWindow(hwnd, SW_RESTORE);
SetForegroundWindow(hwnd);
});
tray->AddMenuItem(999, L"退出");
tray->AddIcon();
tray->StartAutoRefresh(30);
return tray;
}
@@ -0,0 +1,91 @@
#pragma once
#include <Windows.h>
#include <shellapi.h>
#include <functional>
#include <vector>
#include <string>
// ============================================================================
// SysTray — 独立的 Windows 系统托盘模块
//
// 用法:
// SysTray tray(hwnd, hIcon, L"MyApp");
// tray.AddMenuItem(1001, L"设置", [](UINT id) { ... });
// tray.AddMenuItem(1002, L"退出", [](UINT id) { ... });
// tray.AddIcon();
// tray.StartAutoRefresh(30);
// // 在消息循环中调用 tray.HandleMessage(msg, wParam, lParam);
// ============================================================================
class SysTray {
public:
using MenuCallback = std::function<void(UINT menuId)>;
using SimpleCallback = std::function<void()>;
SysTray(HWND hwnd, HICON hIcon, const wchar_t* tooltip);
~SysTray();
// 生命周期
bool AddIcon();
bool RemoveIcon();
bool RefreshIcon();
// 自动刷新(防 Explorer 崩溃后图标丢失)
void StartAutoRefresh(UINT intervalMinutes = 30);
void StopAutoRefresh();
// 菜单项
void AddMenuItem(UINT id, const wchar_t* text, MenuCallback onSelect = nullptr);
void SetMenuItemChecked(UINT id, bool checked);
void ClearMenuItems();
// 回调设置
void SetOnLeftClick(SimpleCallback cb) { m_onLeftClick = std::move(cb); }
void SetOnDoubleClick(SimpleCallback cb) { m_onDoubleClick = std::move(cb); }
void SetMenuCallback(MenuCallback cb) { m_menuCallback = std::move(cb); }
// 消息处理 —— 在主消息循环中调用
void HandleMessage(UINT msg, WPARAM wParam, LPARAM lParam);
// 获取托盘窗口句柄
HWND GetTrayWindow() const { return m_trayHwnd; }
// 窗口过程(供子类化使用)
static LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
private:
void ShowContextMenu();
void ReaddIcon();
bool RegisterWindowClass();
void UnregisterWindowClass();
HWND m_hwnd; // 主窗口
HWND m_trayHwnd; // 托盘消息窗口
HICON m_hIcon;
NOTIFYICONDATA m_nid;
UINT_PTR m_timerId;
std::wstring m_className;
struct MenuItem {
UINT id;
std::wstring text;
MenuCallback callback;
bool checked = false;
};
std::vector<MenuItem> m_menuItems;
MenuCallback m_menuCallback;
SimpleCallback m_onLeftClick;
SimpleCallback m_onDoubleClick;
static const UINT WM_TRAYICON = WM_USER + 1;
static UINT WM_TASKBARCREATED;
};
// ============================================================================
// 便捷函数:为任意 HWND 创建简单托盘
// ============================================================================
namespace SysTrayUtil {
// 注册并显示一个最简托盘(左键恢复窗口,右键退出菜单)
SysTray* CreateSimple(HWND hwnd, HICON hIcon, const wchar_t* tooltip);
}
@@ -0,0 +1,110 @@
#include "WindowGuard.h"
#include <unordered_map>
namespace {
struct GuardData {
WNDPROC originalWndProc = nullptr;
UINT flags = 0;
bool allowClose = false;
bool intentionalHide = false;
};
std::unordered_map<HWND, GuardData> g_guards;
const wchar_t* PROP_NAME = L"WindowGuardData";
LRESULT CALLBACK GuardWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
auto it = g_guards.find(hwnd);
if (it == g_guards.end()) {
return DefWindowProc(hwnd, msg, wParam, lParam);
}
auto& gd = it->second;
// 拦截关闭 (WM_CLOSE from DefWindowProc / DestroyWindow)
if (msg == WM_CLOSE && (gd.flags & WindowGuard::BlockClose)) {
if (!gd.allowClose) {
return 0; // Swallow the message
}
}
// 拦截 SC_CLOSE (taskbar "Close window", Alt+F4, thumbnail X button).
// WM_CLOSE above catches the DefWindowProc path, but many window
// libraries (raylib/GLFW) handle SC_CLOSE directly before it ever
// becomes WM_CLOSE. Intercept it here so the taskbar can't kill us.
if (msg == WM_SYSCOMMAND && wParam == SC_CLOSE && (gd.flags & WindowGuard::BlockClose)) {
if (!gd.allowClose) {
return 0;
}
}
// 拦截最小化
if (msg == WM_SIZE && wParam == SIZE_MINIMIZED && (gd.flags & WindowGuard::BlockMinimize)) {
ShowWindow(hwnd, SW_RESTORE);
return 0;
}
// 拦截外部隐藏
if (msg == WM_WINDOWPOSCHANGING && (gd.flags & WindowGuard::BlockHide)) {
auto* wp = reinterpret_cast<WINDOWPOS*>(lParam);
if ((wp->flags & SWP_HIDEWINDOW) && !gd.intentionalHide) {
wp->flags &= ~SWP_HIDEWINDOW;
wp->flags |= SWP_SHOWWINDOW;
return 0;
}
// 允许本次隐藏后复位标志
if ((wp->flags & SWP_HIDEWINDOW) && gd.intentionalHide) {
gd.intentionalHide = false;
}
}
return CallWindowProc(gd.originalWndProc, hwnd, msg, wParam, lParam);
}
} // anonymous namespace
namespace WindowGuard {
WNDPROC Install(HWND hwnd, UINT flags) {
if (g_guards.find(hwnd) != g_guards.end()) {
return g_guards[hwnd].originalWndProc;
}
GuardData gd;
gd.flags = flags;
gd.originalWndProc = reinterpret_cast<WNDPROC>(
SetWindowLongPtr(hwnd, GWLP_WNDPROC,
reinterpret_cast<LONG_PTR>(GuardWndProc)));
g_guards[hwnd] = gd;
return gd.originalWndProc;
}
void Uninstall(HWND hwnd) {
auto it = g_guards.find(hwnd);
if (it == g_guards.end()) return;
SetWindowLongPtr(hwnd, GWLP_WNDPROC,
reinterpret_cast<LONG_PTR>(it->second.originalWndProc));
g_guards.erase(it);
}
void SetAllowClose(HWND hwnd, bool allow) {
auto it = g_guards.find(hwnd);
if (it != g_guards.end()) {
it->second.allowClose = allow;
}
}
void SetIntentionalHide(HWND hwnd, bool intentional) {
auto it = g_guards.find(hwnd);
if (it != g_guards.end()) {
it->second.intentionalHide = intentional;
}
}
bool IsInstalled(HWND hwnd) {
return g_guards.find(hwnd) != g_guards.end();
}
} // namespace WindowGuard
@@ -0,0 +1,39 @@
#pragma once
#include <Windows.h>
// ============================================================================
// WindowGuard — 独立的窗口保护模块(防关闭 / 防最小化)
//
// 用法:
// // 安装保护
// WindowGuard::Install(hwnd, WindowGuard::BlockClose | WindowGuard::BlockMinimize);
// // ...
// // 卸载保护
// WindowGuard::Uninstall(hwnd);
// // 需要正常关闭时,先调用 AllowClose() 再发送 WM_CLOSE
// ============================================================================
namespace WindowGuard {
enum Flag : UINT {
BlockClose = 1 << 0, // 拦截 WM_CLOSE,窗口保持原样
BlockMinimize = 1 << 1, // 拦截 SIZE_MINIMIZED,立即恢复
BlockHide = 1 << 2, // 拦截 SWP_HIDEWINDOW,防止被外部隐藏(Win+D 等)
};
// 安装窗口保护,返回旧的 WNDPROC(可用于链式调用)
WNDPROC Install(HWND hwnd, UINT flags);
// 卸载窗口保护,恢复原始 WNDPROC
void Uninstall(HWND hwnd);
// 临时允许关闭:设为 true 后下一次 WM_CLOSE 会被放行
void SetAllowClose(HWND hwnd, bool allow);
// 标记窗口为"主动隐藏",跳过 BlockHide 拦截(用于 clearwinicon 等场景)
void SetIntentionalHide(HWND hwnd, bool intentional);
// 查询是否安装了保护
bool IsInstalled(HWND hwnd);
} // namespace WindowGuard
+241
View File
@@ -0,0 +1,241 @@
#include "Draw.h"
#include <algorithm>
#include <chrono>
#include <sstream>
#include <iomanip>
#include "../../Backend/Config/Config.h"
#include "../../Backend/Misc/Fonts/FontManager.h"
#include "../Renderer/Renderer.h"
#include <psapi.h>
CConfig* cfg = CConfig::get();
static std::time_t GetSystemTimeRaw()
{
auto now = std::chrono::system_clock::now();
return std::chrono::system_clock::to_time_t(now);
}
static std::tm GetSystemTimeLocal()
{
std::time_t now = GetSystemTimeRaw();
std::tm localTime;
localtime_s(&localTime, &now);
return localTime;
}
static std::string GetSystemTimeString(const char* format)
{
std::tm localTime = GetSystemTimeLocal();
std::stringstream ss;
ss << std::put_time(&localTime, format);
return ss.str();
}
static void Time() {
if (!cfg->b["time"])
return;
// 时间格式: 0-3 标准(前导零), 4-7 短格式(所有两位数字去前导零)
static const char* baseFormats[] = { "%H:%M:%S", "%H:%M", "%I:%M:%S %p", "%I:%M %p" };
int fmtIdx = cfg->i.count("time_format") ? std::clamp(cfg->i["time_format"], 0, 7) : 0;
bool shortFormat = (fmtIdx >= 4);
std::string time = GetSystemTimeString(baseFormats[shortFormat ? (fmtIdx - 4) : fmtIdx]);
// 短格式:去除所有两位数字的前导零 "01:02:03" → "1:2:3"
if (shortFormat)
{
std::string out;
for (size_t i = 0; i < time.size(); i++)
{
if (time[i] == '0' && i + 1 < time.size()
&& time[i + 1] >= '0' && time[i + 1] <= '9'
&& (i == 0 || time[i - 1] < '0' || time[i - 1] > '9'))
{
continue; // skip leading zero
}
out += time[i];
}
time = out;
}
// 分离主时间部分与 AM/PM 后缀
std::string timeMain = time;
std::string timeSuffix;
const char* ampmMarkers[] = { " AM", " PM" };
for (int mi = 0; mi < 2; mi++)
{
size_t pos = time.rfind(ampmMarkers[mi]);
if (pos != std::string::npos)
{
timeMain = time.substr(0, pos);
timeSuffix = ampmMarkers[mi];
break;
}
}
auto& fm = FontManager::GetInstance();
// 注册主字体
int fontSize = cfg->i["time_text_size"];
if (fontSize <= 0) fontSize = 45;
static int lastFontSize = 0;
if (lastFontSize != fontSize) {
if (lastFontSize == 0)
fm.RegisterFont("TimeFont", "C:\\Windows\\Fonts\\Verdana.ttf", fontSize);
else
fm.SetFontBaseSize("TimeFont", fontSize);
lastFontSize = fontSize;
}
fm.EnsureText("TimeFont", timeMain.c_str());
RLFont font = fm.GetFont("TimeFont");
float charSpacing = (float)cfg->i["time_text_character_spacing"];
// 注册 AM/PM 小字体(主字体 ~55% 大小)
RLFont smallFont = { 0 };
int suffixFontSize = 0;
float suffixOffsetX = 0.f;
if (!timeSuffix.empty())
{
suffixFontSize = std::max(8, (int)(fontSize * 0.55f));
static int lastSuffixSize = 0;
if (lastSuffixSize != suffixFontSize) {
if (lastSuffixSize == 0)
fm.RegisterFont("TimeFontSmall", "C:\\Windows\\Fonts\\Verdana.ttf", suffixFontSize);
else
fm.SetFontBaseSize("TimeFontSmall", suffixFontSize);
lastSuffixSize = suffixFontSize;
}
fm.EnsureText("TimeFontSmall", timeSuffix.c_str());
smallFont = fm.GetFont("TimeFontSmall");
// 后缀 X 偏移 = 主时间文本宽度 + 字符间距
RLVector2 mainSize = fm.MeasureText("TimeFont", timeMain.c_str(), fontSize);
suffixOffsetX = mainSize.x + charSpacing;
}
const int* color = cfg->c["time_text_Color"];
RLColor textColor = {
static_cast<unsigned char>(color[0]),
static_cast<unsigned char>(color[1]),
static_cast<unsigned char>(color[2]),
static_cast<unsigned char>(color[3])
};
float xPos = cfg->f["time_x_pos"];
float yPos = cfg->f["time_y_pos"];
// AM/PM 垂直偏下偏移靠左
float suffixOffsetY = timeSuffix.empty() ? 0.f : ((float)fontSize - (float)suffixFontSize) * 0.65f;
const int* colorborder = cfg->c["text_border_Color"];
RLColor borderCol = {
static_cast<unsigned char>(colorborder[0]),
static_cast<unsigned char>(colorborder[1]),
static_cast<unsigned char>(colorborder[2]),
static_cast<unsigned char>(colorborder[3])
};
if (cfg->b["text_border"]) {
for (int dy = -1; dy <= 1; ++dy) {
for (int dx = -1; dx <= 1; ++dx) {
if (dx == 0 && dy == 0) continue;
RLDrawTextEx(font, timeMain.c_str(), RLVector2{ xPos + (float)dx, yPos + (float)dy }, (float)fontSize, charSpacing, borderCol);
}
}
}
RLDrawTextEx(font, timeMain.c_str(), RLVector2{ xPos, yPos }, (float)fontSize, charSpacing, textColor);
}
static std::string GetForegroundProcessName() {
HWND fg = GetForegroundWindow();
if (!fg) return "";
DWORD pid = 0;
GetWindowThreadProcessId(fg, &pid);
if (pid == 0) return "";
HANDLE hProc = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid);
if (!hProc) return "";
char exeName[MAX_PATH] = "";
DWORD size = MAX_PATH;
if (!QueryFullProcessImageNameA(hProc, 0, exeName, &size)) {
CloseHandle(hProc);
return "";
}
CloseHandle(hProc);
const char* base = strrchr(exeName, '\\');
return base ? (base + 1) : exeName;
}
static bool IsWindowWhitelisted() {
std::string whitelist(cfg->s["keyboard_whitelist"]);
if (whitelist.empty()) return false;
std::string fgName = GetForegroundProcessName();
if (fgName.empty()) return false;
// Case-insensitive exact match against whitelist entries
size_t pos = 0;
while (pos < whitelist.size()) {
size_t end = whitelist.find(';', pos);
if (end == std::string::npos) end = whitelist.size();
std::string entry = whitelist.substr(pos, end - pos);
if (!entry.empty() && _stricmp(entry.c_str(), fgName.c_str()) == 0)
return true;
pos = end + 1;
}
return false;
}
static void KeyboardControl() {
if (!cfg->b["keyboard_control"])
return;
// Skip control if active window is in whitelist
if (IsWindowWhitelisted())
return;
// Throttle: only attempt toggle every 250ms to prevent frame-rate flicker
// when the game also fights for lock-key state
static ULONGLONG lastAttempt = 0;
ULONGLONG now = GetTickCount64();
if (now - lastAttempt < 250)
return;
lastAttempt = now;
// Caps Lock control
{
int mode = cfg->i["Caps_control"];
if (mode != 0) {
bool capsOn = (GetKeyState(VK_CAPITAL) & 0x0001) != 0;
bool wantOn = (mode == 1); // 1=常开(Always On), 2=常关(Always Off)
if (capsOn != wantOn) {
// keybd_event is NOT subject to UIPI (unlike SendInput), so it works with elevated fullscreen games
keybd_event(VK_CAPITAL, 0x3A, 0, 0);
keybd_event(VK_CAPITAL, 0x3A, KEYEVENTF_KEYUP, 0);
}
}
}
// Num Lock control
{
int mode = cfg->i["Num_control"];
if (mode != 0) {
bool numOn = (GetKeyState(VK_NUMLOCK) & 0x0001) != 0;
bool wantOn = (mode == 1); // 1=常开(Always On), 2=常关(Always Off)
if (numOn != wantOn) {
// keybd_event is NOT subject to UIPI (unlike SendInput), so it works with elevated fullscreen games
keybd_event(VK_NUMLOCK, 0x45, KEYEVENTF_EXTENDEDKEY | 0, 0);
keybd_event(VK_NUMLOCK, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
}
}
}
}
namespace Render {
void DrawOverlay() {
KeyboardControl();
Time();
}
} // namespace Render
+5
View File
@@ -0,0 +1,5 @@
#pragma once
namespace Render {
void DrawOverlay();
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,280 @@
#pragma once
#include "../../Backend/Globalincludes.h"
#include <unordered_map>
typedef int GuiFlags;
typedef int DrawListType;
namespace GamesenseMenuFramework {
struct HSV {
float h;
float s;
float v;
float a;
HSV() {
h = 0;
s = 0;
v = 0;
a = 255;
}
HSV(float h_, float s_, float v_, float a_) {
h = h_;
s = s_;
v = v_;
a = a_;
}
};
struct Vec2 {
float x, y;
Vec2() { x = y = 0; }
Vec2(float _x, float _y) { x = _x; y = _y; }
Vec2& operator+=(const Vec2& other)
{
x += other.x;
y += other.y;
return *this;
}
Vec2& operator-=(const Vec2& other)
{
x -= other.x;
y -= other.y;
return *this;
}
Vec2 operator+(const Vec2& other)
{
return Vec2(x + other.x, y + other.y);
}
Vec2 operator-(const Vec2& other)
{
return Vec2(x - other.x, y - other.y);
}
bool operator==(const Vec2& other) const {
return x == other.x && y == other.y;
}
};
struct Rect {
Vec2 Min;
Vec2 Max;
Rect() : Min(FLT_MAX, FLT_MAX), Max(-FLT_MAX, -FLT_MAX) {}
Rect(const Vec2& min, const Vec2& max) : Min(min), Max(max) {}
Rect(float x1, float y1, float x2, float y2) : Min(x1, y1), Max(x2, y2) {}
};
class DrawList {
private:
struct RenderObject {
DrawListType Type;
Vec2 Pos;
Vec2 Size;
RLColor Color;
RLColor OtherColor;
const char* Text;
RLFont Font;
bool Bordered;
bool Vertical;
Vec2 TextClipSize;
bool Antialias;
RenderObject(DrawListType Type, Vec2 Pos, Vec2 Size, RLColor color, RLColor OtherColor, const char* text, RLFont font, bool Bordered, bool Vertical, Vec2 TextClipSize, bool Antialias) {
this->Type = Type;
this->Pos = Pos;
this->Size = Size;
this->Color = color;
this->OtherColor = OtherColor;
this->Text = text;
this->Font = font;
this->Bordered = Bordered;
this->Vertical = Vertical;
this->TextClipSize = TextClipSize;
this->Antialias = Antialias;
}
};
public:
static std::vector<RenderObject> Drawlist;
static void AddText(const char* text, int x, int y, RLColor Color, RLFont font, bool Bordered = false, Vec2 TextClipSize = Vec2(0, 0));
static void AddFilledRect(Vec2 Pos, Vec2 Size, RLColor Color);
static void AddRect(Vec2 Pos, Vec2 Size, RLColor Color, bool Antialias = false);
static void AddGradient(Vec2 Pos, Vec2 Size, RLColor Color, RLColor OtherColor, bool Vertical = false, bool Antialias = false);
};
enum DrawListType_ {
DrawType_Text = 0,
DrawType_FilledRect = 1,
DrawType_Rect = 2,
DrawType_Gradient = 3,
DrawType_Triangle = 4
};
enum GuiFlags_ {
GuiFlags_None = 0,
GuiFlags_NoMove = 1 << 1,
GuiFlags_NoResize = 1 << 2,
GuiFlags_ReturnKeyReleased = 1 << 3,
GuiFlags_NoTabButton = 1 << 4,
GuiFlags_ChildWindow = 1 << 5,
GuiFlags_PopUp = 1 << 6,
GuiFlags_TabButton = 1 << 7,
GuiFlags_CheckBox = 1 << 8,
GuiFlags_Button = 1 << 9,
GuiFlags_FloatSlider = 1 << 10,
GuiFlags_IntSlider = 1 << 11,
GuiFlags_ComboBox = 1 << 12,
GuiFlags_Selectable = 1 << 13,
GuiFlags_SingleSelect = 1 << 14,
GuiFlags_ColorPicker = 1 << 15,
GuiFlags_Label = 1 << 16,
GuiFlags_LegitTab = 1 << 17,
GuiFlags_Listbox = 1 << 18,
GuiFlags_NoKeyBindMenu = 1 << 19,
GuiFlags_MultiKey = 1 << 20
};
struct GuiWindow {
std::string Name;
GuiFlags Flags;
Vec2 Pos, Size;
Vec2 CursorPos;
Vec2 PevCursorPos;
Vec2 PrevCursorPos;
GuiWindow* ParentWindow;
std::vector<GuiWindow*> ChildWindows;
std::vector<GuiWindow*> PopUpWindows;
std::string SelectedItem;
bool Opened;
bool Dragging;
bool Resizing;
bool Block;
bool Init;
bool WidgetClicked;
std::unordered_map<const char*, bool> ItemActive;
int xSize = 3;
int ySize = 10;
int xPos = 0;
int yPos = 0;
float ScrollRatio;
};
struct NextWindowInfo {
Vec2 Pos;
Vec2 Size;
bool PosCond;
bool SizeCond;
};
struct GuiContext {
bool Initialized;
std::vector<GuiWindow*> Windows;
std::vector<std::string> WindowsByName;
GuiWindow* CurrentWindow;
NextWindowInfo NextWindowInfo;
Vec2 ItemSpacing;
int MenuAlpha;
float dpiScale = 1.0f;
bool KeyState[256];
bool PrevKeyState[256];
Vec2 MousePos;
Vec2 PrevMousePos;
float MouseWheel = 0.f;
bool AwaitingInput = false;
bool IsBindingKey = false;
int LastInput = 0;
};
namespace ui {
//-------Helpers-------//中文
bool IsInside(float x, float y, float w, float h); // 检查鼠标是否在矩形内
bool IsInsideWindow(GuiWindow* Window = 0); // 检查鼠标是否在窗口内
bool KeyPressed(const int key); // 检查按键是否被按下
bool KeyDown(const int key); // 检查按键是否被按下
bool KeyReleased(const int key); // 检查按键是否被释放
bool ButtonBehavior(GuiWindow* Window, const char* label, Rect bb, bool& hovered, bool& held, GuiFlags flags = NULL); // 按钮行为
bool ChildsAreStable(GuiWindow* Window); // 检查子窗口是否稳定
bool PopUpsAreClosed(GuiWindow* Window); // 检查弹出窗口是否关闭关闭
void HandleMoving(GuiWindow* Window, Rect Constraints = Rect{}, Vec2* v = nullptr); // 处理窗口移动
void HandleResize(GuiWindow* Window, Rect Constraints = Rect{}, Vec2* buffer = nullptr); // 处理窗口调整大小
void AddItemToWindow(GuiWindow* Window, Rect size, GuiFlags flags = NULL); // 添加窗口项
bool NoItemsActive(GuiWindow* Window); // 检查窗口项是否激活
template <typename T> // 滑块行为
bool SliderBehavior(const char* item_id, Rect bb, T value, T min_value, T max_value, GuiFlags flags); // 滑块行为
HSV ColorPickerBehavior(GuiWindow* PickerWindow, Rect& RcColor, Rect& RcAlpha, Rect& RcHue, int col[4], bool reset = false); // 颜色选择器行为
//-------Context-------//
void Shutdown(GuiContext* context); // 关闭上下文
void Init(GuiContext* context); // 初始化上下文
GuiContext* CreateContext(); // 创建上下文
void DeleteContext(GuiContext* ctx); // 删除上下文
//-------WindoW------//
GuiWindow* FindWindowByName(const char*& name); // 根据名称查找窗口
static GuiWindow* CreateNewWindow(const char*& name, Vec2 size, GuiFlags flags); // 创建新窗口
void GetInputFromWindow(const std::string& window_name); // 获取窗口输入
GuiWindow* GetCurrentWindow(); // 获取当前窗口
void SetCurrentWindow(GuiWindow* window); // 设置当前窗口
void SetWindowSize(GuiWindow* window, const Vec2& size); // 设置窗口大小
void SetWindowSize(const Vec2& size); // 设置窗口大小
void SetWindowSize(const char* name, const Vec2& size); // 设置窗口大小
Vec2 GetWindowSize(); // 获取窗口大小
Vec2 GetWindowPos(); // 获取窗口位置
void SetWindowPos(GuiWindow* window, const Vec2& pos); // 设置窗口位置
void SetWindowPos(const Vec2& pos); // 设置窗口位置
void SetNextWindowPos(const Vec2& pos); // 设置下一个窗口位置
void SetNextWindowSize(const Vec2& size); // 设置下一个窗口大小
void Begin(const char* Id, GuiFlags flags); // 开始绘制
void End(); // 结束绘制
void BeginChild(const char* id, Rect X = { Vec2(0, 0), Vec2(3,10) }, GuiFlags flags = NULL); // 开始绘制子窗口
void EndChild(); // 结束绘制子窗口
void TabButton(const char* label, int* selected, int num, int total, GuiFlags flags = NULL); // 绘制选项卡按钮
bool Checkbox(const char* label, bool* v, bool special = false, bool* rightClicked = nullptr); // 绘制复选框
bool Button(const char* label, const Vec2& size = Vec2(0, 0)); // 绘制按钮
void SliderInt(const char* label, int* v, int v_min, int v_max, const char* format = NULL, int remove = 0); // 绘制整数滑块
void SliderFloat(const char* label, float* v, float v_min, float v_max, const char* format, float scale); // 绘制浮点数滑块
bool SingleSelect(const char* label, int* current_item, std::vector<const char*> items); // 绘制单选框
bool MultiSelect(const char* label, std::unordered_map<int, bool>* data, std::vector<const char*> items); // 绘制多选框
bool ColorPicker(const char* label, int col[4], GuiFlags flags = NULL); // 绘制颜色选择器
bool KeyBind(const char* id, int* current_key, int* key_style, GuiFlags flags = GuiFlags_None); // 单键绑定
bool MultiKeyBind(const char* label, int* keystyle, GuiFlags flags = GuiFlags_None); // 多键组合绑定
void Label(const char* label, bool special = false, GuiFlags flags = NULL); // 绘制标签
void InputText(const char* id, char* buffer, GuiFlags flags = NULL); // 绘制输入文本框
template <typename T> // 绘制滑块
void Slider(const char* label, T* v, T v_min, T v_max, const char* format = NULL, GuiFlags flags = NULL, float scale = 1.f, int remove = 0.f); // 绘制滑块
bool ComboSelectable(const char* label, bool selected = false, GuiFlags flags = NULL, const Vec2& size_arg = Vec2(0, 0)); // 绘制下拉选择框
bool Selectable(const char* label, bool activated, const Vec2& size_arg = Vec2()); // 绘制可选框
bool BeginCombo(const char* label, const char* preview_value, int items, GuiFlags flags = NULL); // 开始绘制下拉选择框
void EndCombo(); // 结束绘制下拉选择框
bool BeginListbox(const char* id, const Vec2 Size = Vec2(), GuiFlags flags = NULL); // 开始绘制列表框
void EndListbox(); // 结束绘制列表框
}
namespace Globals {
extern GuiContext* Gui_Ctx;
// Multi-key bind cache: returns ref to persistent string for cfgKey
std::string& MultiKeyCache(const std::string& cfgKey);
}
}
+597
View File
@@ -0,0 +1,597 @@
#include "Menu.h"
#include "../../Backend/Utilities/Utilities.h"
#include "../../Backend/Config/Settings.h"
#include "../../Backend/Config/Config.h"
#include "../../Backend/Config/MenuParams.h"
#include "../../Backend/Console/Console.h"
#include "../../Overlay/Overlay.h"
#include "../Renderer/Renderer.h"
#include "../../Backend/Main/Main.h"
#include <algorithm>
#include <set>
#include <psapi.h>
#include <shellapi.h>
#include <ShlObj_core.h>
using namespace GamesenseMenuFramework;
// ------------------------------------------------------------------
// Initialize
// ------------------------------------------------------------------
void CMenu::Initialize()
{
if (m_bInitialized)
return;
ui::CreateContext();
GuiContext* g = Globals::Gui_Ctx;
g->ItemSpacing = Vec2(0, 6);
g->MenuAlpha = 1;
CConfig::get()->LoadDefaults();
CConfig::get()->AutoLoad();
// Apply saved console visibility
Console::Get()->SetVisible(CConfig::get()->b["show_console"]);
if (CConfig::get()->b["isAdmin"] && !IsUserAnAdmin()) {
CConfig::get()->AutoSave();
RestartAsAdmin();
}
m_bIsOpened = false;
m_bInitialized = true;
}
// ------------------------------------------------------------------
// Program control helpers
// ------------------------------------------------------------------
void CMenu::RestartAsAdmin()
{
ReleaseSingleInstanceMutex();
wchar_t exePath[MAX_PATH];
GetModuleFileNameW(NULL, exePath, MAX_PATH);
SHELLEXECUTEINFOW sei = { sizeof(sei) };
sei.fMask = SEE_MASK_NOCLOSEPROCESS;
sei.lpVerb = L"runas";
sei.lpFile = exePath;
sei.nShow = SW_SHOW;
if (ShellExecuteExW(&sei)) {
ExitProcess(0);
}
CConfig::get()->b["isAdmin"] = false;
}
// Launch exePath non-elevated via a temporary scheduled task (/rl LIMITED).
// This is the most reliable de-elevation method — no token APIs or privileges needed.
static bool SchtasksNonElevated(const wchar_t* exePath)
{
wchar_t cmd[1024];
// 1. Create a one-shot task that runs with least privilege.
// conhost.exe for classic console; --unelevated to fix CWD.
swprintf_s(cmd, L"schtasks /create /tn \"RcjyDelevate\" /tr \"conhost.exe \\\"%s\\\" --unelevated\" /sc once /st 00:00 /f /rl LIMITED", exePath);
STARTUPINFOW si = { sizeof(si) };
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE;
PROCESS_INFORMATION pi;
if (!CreateProcessW(NULL, cmd, NULL, NULL, FALSE, CREATE_NO_WINDOW,
NULL, NULL, &si, &pi))
return false;
WaitForSingleObject(pi.hProcess, 5000);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
// 2. Run the task immediately
swprintf_s(cmd, L"schtasks /run /tn \"RcjyDelevate\"");
if (!CreateProcessW(NULL, cmd, NULL, NULL, FALSE, CREATE_NO_WINDOW,
NULL, NULL, &si, &pi))
return false;
WaitForSingleObject(pi.hProcess, 5000);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
// Give the task a moment to start the target process
Sleep(1000);
// 3. Delete the task
swprintf_s(cmd, L"schtasks /delete /tn \"RcjyDelevate\" /f");
if (!CreateProcessW(NULL, cmd, NULL, NULL, FALSE, CREATE_NO_WINDOW,
NULL, NULL, &si, &pi))
return false;
WaitForSingleObject(pi.hProcess, 5000);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return true;
}
void CMenu::RestartProgram()
{
ReleaseSingleInstanceMutex();
wchar_t exePath[MAX_PATH];
GetModuleFileNameW(NULL, exePath, MAX_PATH);
if (!SchtasksNonElevated(exePath)) {
ShellExecuteW(NULL, L"open", exePath, NULL, NULL, SW_SHOW);
}
HWND hwnd = reinterpret_cast<HWND>(RLGetWindowHandle());
WindowGuard::SetAllowClose(hwnd, true);
COverlay::Get()->Shutdown();
std::exit(0);
}
void CMenu::ExitProgram()
{
HWND hwnd = reinterpret_cast<HWND>(RLGetWindowHandle());
WindowGuard::SetAllowClose(hwnd, true);
COverlay::Get()->Shutdown();
std::exit(0);
}
// ------------------------------------------------------------------
// Animation & layout
// ------------------------------------------------------------------
bool CMenu::HandleAlpha()
{
static float alpha = 0;
float fc = Misc::Utilities->GetDeltaTime() * 255 * 10;
if (!m_bIsOpened && alpha > 0.f)
alpha = std::clamp(alpha - fc / 255.f, 0.f, 1.f);
if (m_bIsOpened && alpha < 1.f)
alpha = std::clamp(alpha + fc / 255.f, 0.f, 1.f);
Globals::Gui_Ctx->MenuAlpha = static_cast<int>(floor(alpha * 255));
if (!m_bIsOpened && alpha == 0.f)
return false;
return true;
}
void CMenu::HandleLayout()
{
static bool layoutLoaded = false;
if (!layoutLoaded) {
MenuParams.Load();
ui::SetNextWindowPos(MenuParams.GetPos());
layoutLoaded = true;
}
static float lastRenderW = 0.f, lastRenderH = 0.f;
float curRenderW = Render::Draw->Screen.RenderWidth;
float curRenderH = Render::Draw->Screen.RenderHeight;
if (lastRenderW > 0.f && lastRenderH > 0.f && (curRenderW != lastRenderW || curRenderH != lastRenderH)) {
if (MenuParams.Width > curRenderW)
MenuParams.Width = curRenderW;
if (MenuParams.Height > curRenderH)
MenuParams.Height = curRenderH;
if (MenuParams.PosX + MenuParams.Width < 100.f)
MenuParams.PosX = curRenderW - MenuParams.Width;
if (MenuParams.PosX > curRenderW - 100.f)
MenuParams.PosX = curRenderW - MenuParams.Width;
if (MenuParams.PosY < -40.f)
MenuParams.PosY = 0.f;
if (MenuParams.PosY > curRenderH - 40.f)
MenuParams.PosY = curRenderH - MenuParams.Height;
ui::SetNextWindowPos(MenuParams.GetPos());
}
lastRenderW = curRenderW;
lastRenderH = curRenderH;
ui::SetNextWindowSize(MenuParams.GetSize());
}
void CMenu::SaveLayout()
{
GamesenseMenuFramework::Vec2 curPos = ui::GetWindowPos();
GamesenseMenuFramework::Vec2 curSize = ui::GetWindowSize();
MenuParams.Save(curPos, curSize);
}
// ------------------------------------------------------------------
// Tab buttons
// ------------------------------------------------------------------
void CMenu::DrawTabButtons()
{
ui::TabButton("A", &m_nCurrentTab, 0, 7);
ui::TabButton("G", &m_nCurrentTab, 1, 7);
ui::TabButton("C", &m_nCurrentTab, 2, 7);
ui::TabButton("J", &m_nCurrentTab, 3, 7);
ui::TabButton("D", &m_nCurrentTab, 4, 7);
ui::TabButton("E", &m_nCurrentTab, 5, 7);
ui::TabButton("F", &m_nCurrentTab, 6, 7);
ui::TabButton("H", &m_nCurrentTab, 7, 7);
}
void CMenu::Tab1()
{
CConfig* cfg = CConfig::get();
ui::BeginChild("Itme#0", { Vec2(0,0), Vec2(3, 10) });
{
static bool prevIsAdmin = IsUserAnAdmin();
bool isAdmin = IsUserAnAdmin();
ui::Checkbox("管理员", &isAdmin);
if (isAdmin != prevIsAdmin) {
cfg->b["isAdmin"] = isAdmin;
cfg->Save();
if (isAdmin)
RestartAsAdmin();
else
RestartProgram();
}
prevIsAdmin = isAdmin;
}
ui::EndChild();
ui::BeginChild("Setting#0", { Vec2(6, 0), Vec2(3, 10) });
ui::EndChild();
}
void CMenu::Tab2()
{
ui::BeginChild("Itme#1", { Vec2(0,0), Vec2(3, 10) });
ui::EndChild();
ui::BeginChild("Setting#1", { Vec2(6, 0), Vec2(3, 10) });
ui::EndChild();
}
void CMenu::RendererTab()
{
CConfig* cfg = CConfig::get();
ui::BeginChild("Itme#3", { Vec2(0,0), Vec2(3, 10) });
{
ui::Checkbox("显示时间", &cfg->b["time"], false, &cfg->b["time_setting"]);
}
ui::EndChild();
ui::BeginChild("Setting#3", { Vec2(6, 0), Vec2(3, 10) });
{
if (cfg->b["time_setting"]) {
ui::Label("显示时间");
ui::ColorPicker("菜单颜色", cfg->c["time_text_Color"]);
ui::Checkbox("文字边框", &cfg->b["text_border"]);
ui::ColorPicker("文字边框颜色", cfg->c["text_border_Color"]);
ui::SingleSelect("时间格式", &cfg->i["time_format"], {
"24H HH:MM:SS", "24H HH:MM", "12H HH:MM:SS", "12H HH:MM",
"24H H:M:S", "24H H:M", "12H H:M:S", "12H H:M"
});
ui::SliderInt("文字大小", &cfg->i["time_text_size"], 10, 100, "%d");
ui::SliderInt("字符间距", &cfg->i["time_text_character_spacing"], 0, 100, "%d");
float maxX = Render::Draw->Screen.RenderWidth;
float maxY = Render::Draw->Screen.RenderHeight;
int fontSize = cfg->i["time_text_size"];
float charSpacing = (float)cfg->i["time_text_character_spacing"];
RLVector2 textSize = FontManager::GetInstance().MeasureText("TimeFont", "00:00:00", fontSize);
if (textSize.x > 0 && textSize.y > 0) {
float textW = textSize.x + (charSpacing - 1.0f) * 7;
float textH = textSize.y;
if (cfg->b["text_border"]) { textW += 2; textH += 2; }
maxX = std::max(0.0f, Render::Draw->Screen.RenderWidth - textW);
maxY = std::max(0.0f, Render::Draw->Screen.RenderHeight - textH);
}
ui::SliderFloat("水平位置", &cfg->f["time_x_pos"], 0, maxX, "%0.1f", 1.0f);
ui::SliderFloat("高度位置", &cfg->f["time_y_pos"], 0, maxY, "%0.1f", 1.0f);
ui::Label("\n");
}
}
ui::EndChild();
}
void CMenu::Tab4()
{
CConfig* cfg = CConfig::get();
ui::BeginChild("Itme#2", { Vec2(0,0), Vec2(3, 10) });
{
ui::Checkbox("键盘控制", &cfg->b["keyboard_control"], false, &cfg->b["keyboard_control_setting"]);
}
ui::EndChild();
ui::BeginChild("Setting#2", { Vec2(6, 0), Vec2(3, 10) });
{
if (!cfg->b["keyboard_control_setting"]) {
ui::EndChild();
return;
}
ui::SingleSelect("大写控制", &cfg->i["Caps_control"], { "", "常开", "常关" });
ui::SingleSelect("数字控制", &cfg->i["Num_control"], { "", "常开", "常关" });
ui::Label("--- 白名单 (窗口程序) ---");
static std::vector<std::string> windowList;
static std::vector<const char*> windowListPtrs;
static int refreshCounter = 0;
if (++refreshCounter >= 60) {
refreshCounter = 0;
RefreshWindowList(windowList, windowListPtrs);
}
ui::Label("窗口程序列表 (点击添加):");
if (ui::BeginListbox("窗口程序列表")) {
for (size_t i = 0; i < windowList.size(); i++) {
if (ui::Selectable(windowList[i].c_str(), false)) {
AddToWhitelist(windowList[i]);
}
}
}
ui::EndListbox();
// Whitelist entries (click to remove)
std::string whitelist(cfg->s["keyboard_whitelist"]);
if (!whitelist.empty()) {
ui::Label("白名单列表 (点击删除):");
std::vector<std::string> entries;
size_t pos = 0;
while (pos < whitelist.size()) {
size_t end = whitelist.find(';', pos);
if (end == std::string::npos) end = whitelist.size();
std::string entry = whitelist.substr(pos, end - pos);
if (!entry.empty()) entries.push_back(entry);
pos = end + 1;
}
if (ui::BeginListbox("白名单列表")) {
for (size_t i = 0; i < entries.size(); i++) {
if (ui::Selectable(entries[i].c_str(), false)) {
RemoveFromWhitelist(entries[i]);
}
}
}
ui::EndListbox();
}
ui::Label("\n");
}
ui::EndChild();
}
void CMenu::SettingTab()
{
CConfig* cfg = CConfig::get();
ui::BeginChild("Settings", { Vec2(0,0), Vec2(3, 10) });
{
ui::Label("菜单按键");
ui::MultiKeyBind("menu_key", &cfg->i["menu_keystyle"], GuiFlags_NoKeyBindMenu);
ui::Label("菜单颜色");
ui::ColorPicker("菜单颜色", cfg->c["MenuColor"]);
ui::Checkbox("开机自启", &cfg->b["autostart"]);
ui::Checkbox("锁定菜单布局", &cfg->b["lock_menu_layout"]);
ui::Checkbox("隐藏任务栏图标", &cfg->b["hide_taskbar_icon"]);
{
static bool prevShow = cfg->b["show_console"];
ui::Checkbox("显示控制台", &cfg->b["show_console"]);
if (cfg->b["show_console"] != prevShow) {
HWND hCon = GetConsoleWindow();
if (hCon)
ShowWindow(hCon, cfg->b["show_console"] ? SW_SHOW : SW_HIDE);
prevShow = cfg->b["show_console"];
cfg->Save();
}
}
}
ui::EndChild();
ui::BeginChild("其他", { Vec2(6, 0), Vec2(3, 10) });
{
if (ui::Button("重启程序")) {
RestartProgram();
}
if (ui::Button("关闭程序")) {
ExitProgram();
}
}
ui::EndChild();
}
void CMenu::Tab6()
{
ui::BeginChild("Itme#5", { Vec2(0,0), Vec2(3, 10) });
ui::EndChild();
ui::BeginChild("Setting#5", { Vec2(6, 0), Vec2(3, 10) });
ui::EndChild();
}
void CMenu::Tab7()
{
ui::BeginChild("Itme#6", { Vec2(0,0), Vec2(3, 10) });
ui::EndChild();
ui::BeginChild("Setting#6", { Vec2(6, 0), Vec2(3, 10) });
ui::EndChild();
}
void CMenu::ConfigTab()
{
CConfig* cfg = CConfig::get();
ui::BeginChild("参数", { Vec2(0,0), Vec2(3, 10) });
if (ui::BeginListbox("参数列表")) {
for (auto config : CConfig::get()->List) {
if (ui::Selectable(config.c_str(), CConfig::get()->Current == config.c_str()))
strcpy_s(cfg->s["config_name"], config.c_str());
}
}
ui::EndListbox();
ui::InputText("参数输入框", cfg->s["config_name"]);
bool hasName = (cfg->s["config_name"][0] != 0);
if (ui::Button("加载") && hasName)
CConfig::get()->Load();
if (ui::Button("保存") && hasName)
CConfig::get()->Save();
if (ui::Button("删除") && hasName)
CConfig::get()->Delete();
if (ui::Button("重置"))
CConfig::get()->LoadDefaults();
ui::EndChild();
ui::BeginChild("Setting#0", { Vec2(6, 0), Vec2(3, 10) });
ui::EndChild();
}
// ------------------------------------------------------------------
// Whitelist helpers
// ------------------------------------------------------------------
void CMenu::RefreshWindowList(std::vector<std::string>& windowList, std::vector<const char*>& windowListPtrs)
{
windowList.clear();
windowListPtrs.clear();
std::set<std::string> seen;
HWND hwnd = GetTopWindow(NULL);
while (hwnd) {
if (IsWindowVisible(hwnd)) {
DWORD pid = 0;
GetWindowThreadProcessId(hwnd, &pid);
if (pid != 0) {
HANDLE hProc = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid);
if (hProc) {
char exeName[MAX_PATH] = "";
DWORD size = MAX_PATH;
if (QueryFullProcessImageNameA(hProc, 0, exeName, &size)) {
const char* base = strrchr(exeName, '\\');
std::string name = base ? (base + 1) : exeName;
if (seen.find(name) == seen.end()) {
seen.insert(name);
windowList.push_back(name);
}
}
CloseHandle(hProc);
}
}
}
hwnd = GetNextWindow(hwnd, GW_HWNDNEXT);
}
std::sort(windowList.begin(), windowList.end(), [](const std::string& a, const std::string& b) {
return _stricmp(a.c_str(), b.c_str()) < 0;
});
for (auto& s : windowList)
windowListPtrs.push_back(s.c_str());
}
void CMenu::AddToWhitelist(const std::string& name)
{
CConfig* cfg = CConfig::get();
std::string whitelist(cfg->s["keyboard_whitelist"]);
// Check if already exists
size_t pos = 0;
while (pos < whitelist.size()) {
size_t end = whitelist.find(';', pos);
if (end == std::string::npos) end = whitelist.size();
std::string entry = whitelist.substr(pos, end - pos);
if (_stricmp(entry.c_str(), name.c_str()) == 0)
return;
pos = end + 1;
}
std::string updated = whitelist.empty() ? name : (whitelist + ";" + name);
strncpy_s(cfg->s["keyboard_whitelist"], 255, updated.c_str(), 254);
}
void CMenu::RemoveFromWhitelist(const std::string& name)
{
CConfig* cfg = CConfig::get();
std::string whitelist(cfg->s["keyboard_whitelist"]);
// Parse entries and rebuild without the removed one
std::vector<std::string> entries;
size_t pos = 0;
while (pos < whitelist.size()) {
size_t end = whitelist.find(';', pos);
if (end == std::string::npos) end = whitelist.size();
std::string entry = whitelist.substr(pos, end - pos);
if (!entry.empty()) entries.push_back(entry);
pos = end + 1;
}
std::string newWhitelist;
for (size_t j = 0; j < entries.size(); j++) {
if (_stricmp(entries[j].c_str(), name.c_str()) != 0) {
if (!newWhitelist.empty()) newWhitelist += ";";
newWhitelist += entries[j];
}
}
strncpy_s(cfg->s["keyboard_whitelist"], 255, newWhitelist.c_str(), 254);
}
// ------------------------------------------------------------------
// Main Draw
// ------------------------------------------------------------------
void CMenu::Draw()
{
if (!HandleAlpha())
return;
HandleLayout();
ui::Begin("Rcjy", GuiFlags_None);
DrawTabButtons();
switch (m_nCurrentTab) {
case 0: Tab1(); break;
case 1: Tab2(); break;
case 2: RendererTab(); break;
case 3: Tab4(); break;
case 4: SettingTab(); break;
case 5: Tab6(); break;
case 6: Tab7(); break;
case 7: ConfigTab(); break;
}
ui::End();
SaveLayout();
}
// ------------------------------------------------------------------
// Public accessors
// ------------------------------------------------------------------
bool CMenu::IsMenuOpened()
{
return m_bIsOpened;
}
void CMenu::SetMenuOpened(bool v)
{
// When opening the menu, cancel any active QuickEdit selection so log
// output (e.g. config load/save) doesn't get stuck on the console.
if (v)
Console::Get()->CancelSelectionIfActive();
m_bIsOpened = v;
}
RLColor CMenu::GetMenuColor()
{
GuiContext* g = Globals::Gui_Ctx;
CConfig* cfg = CConfig::get();
return RLColor{
(unsigned char)(cfg->c["MenuColor"][0]),
(unsigned char)(cfg->c["MenuColor"][1]),
(unsigned char)(cfg->c["MenuColor"][2]),
(unsigned char)(std::min(cfg->c["MenuColor"][3], g->MenuAlpha))
};
}
+57
View File
@@ -0,0 +1,57 @@
#pragma once
#include "../../Backend/Globalincludes.h"
#include "../../Backend/Misc/singleton.h"
#include "../Framework/MenuFramework.h"
#include <unordered_map>
#include <vector>
#include <string>
// Launch exePath as a non-elevated process (de-elevate from admin).
// Returns true on success, false if fallback (ShellExecuteW) is needed.
bool LaunchAsNonElevated(const wchar_t* exePath);
class CMenu : public singleton<CMenu>
{
public:
void Initialize();
void Draw();
bool IsMenuOpened();
void SetMenuOpened(bool v);
RLColor GetMenuColor();
int Menu_key = VK_INSERT;
private:
// Animation & layout
bool HandleAlpha();
void HandleLayout();
void SaveLayout();
// Program control
void RestartAsAdmin();
void RestartProgram();
void ExitProgram();
// Tab rendering
void DrawTabButtons();
void Tab1();
void Tab2();
void RendererTab();
void Tab4();
void SettingTab();
void Tab6();
void Tab7();
void ConfigTab();
// Whitelist helpers
void RefreshWindowList(std::vector<std::string>& windowList, std::vector<const char*>& windowListPtrs);
void AddToWhitelist(const std::string& name);
void RemoveFromWhitelist(const std::string& name);
bool m_bInitialized = false;
bool m_bIsOpened = false;
int m_nCurrentTab = 0;
int m_nCurrentLegitTab = 0;
};
@@ -0,0 +1,224 @@
#include "Renderer.h"
#include "../../Backend/Misc/Fonts/Fonts.h"
#include "../../Backend/Misc/Fonts/FontManager.h"
#include "../../Backend/Misc/Textures/Textures.h"
std::unique_ptr<Render::CDraw> Render::Draw = std::make_unique<Render::CDraw>();
using namespace Render;
using namespace GamesenseMenuFramework;
void CDraw::CreateObjects()
{
// Register fonts through FontManager (DPI-scaled)
float s = m_CurrentDpiScale;
auto& fm = FontManager::GetInstance();
// Standard UI fonts: Verdana 12, Tahombd 12, SmallFont 8
fm.RegisterFont("Verdana", "C:\\Windows\\Fonts\\Verdana.ttf", (int)(12 * s));
fm.RegisterFont("Tahombd", "C:\\Windows\\Fonts\\Verdanab.ttf", (int)(12 * s));
fm.RegisterFont("SmallFont", "C:\\Windows\\Fonts\\verdana.ttf", (int)(8 * s));
// Chinese fallback fonts (searched in order on first CJK text)
fm.RegisterFont("CJK", "C:\\Windows\\Fonts\\simhei.ttf", (int)(12 * s));
// Tab icon fonts from memory
fm.RegisterFontFromMemory("TabIcons", FontsData::TabIcons, 5192, (int)(47 * s));
// Load background texture from memory (16x16, tile mode)
RLImage bgImage = RLLoadImageFromMemory(".png", TexturesData::BgTexture, 424852);
m_BgTexture = RLLoadTextureFromImage(bgImage);
RLUnloadImage(bgImage);
RLSetTextureWrap(m_BgTexture, RL_E_TEXTURE_WRAP_REPEAT);
}
void CDraw::SetDpiScale(float dpiScale)
{
if (dpiScale == m_CurrentDpiScale)
return;
m_CurrentDpiScale = dpiScale;
FontManager::GetInstance().SetDpiScale(dpiScale);
}
void CDraw::ReleaseObjects()
{
if (!Initialized)
return;
FontManager::GetInstance().UnloadAll();
RLUnloadTexture(m_BgTexture);
}
void CDraw::Init()
{
if (!Initialized) {
CreateObjects();
Initialized = true;
}
}
void CDraw::Reset()
{
Screen.Width = (float)RLGetScreenWidth();
Screen.Height = (float)RLGetScreenHeight();
Screen.x_center = Screen.Width / 2;
Screen.y_center = Screen.Height / 2;
// Usable render area (excludes taskbar): get work area via Win32 API
RECT workArea = { 0 };
SystemParametersInfo(SPI_GETWORKAREA, 0, &workArea, 0);
Screen.RenderWidth = (float)(workArea.right - workArea.left);
Screen.RenderHeight = (float)(workArea.bottom - workArea.top);
// Set up correct alpha blending for DWM transparent window:
// - RGB: standard alpha blending (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
// - Alpha: preserve source alpha for opaque pixels (GL_ONE, GL_ONE_MINUS_SRC_ALPHA)
// This ensures opaque menu elements write alpha=255 so DWM renders them solid
rlSetBlendMode(RL_BLEND_CUSTOM_SEPARATE);
rlSetBlendFactorsSeparate(RL_SRC_ALPHA, RL_ONE_MINUS_SRC_ALPHA,
RL_ONE, RL_ONE_MINUS_SRC_ALPHA,
RL_FUNC_ADD, RL_FUNC_ADD);
}
void CDraw::Line(Vec2 Pos, Vec2 Pos2, RLColor Color)
{
RLDrawLine((int)round(Pos.x), (int)round(Pos.y), (int)round(Pos2.x), (int)round(Pos2.y), Color);
}
void CDraw::Rect(Vec2 Pos, Vec2 Size, float LineWidth, RLColor Color, bool Antialias)
{
if (LineWidth == 0 || LineWidth == 1)
{
RLDrawRectangleLines((int)Pos.x, (int)Pos.y, (int)Size.x, (int)Size.y, Color);
}
else
{
RLDrawRectangleLinesEx(RLRectangle{ Pos.x, Pos.y, Size.x, Size.y }, LineWidth, Color);
}
}
void CDraw::FilledRect(Vec2 Pos, Vec2 Size, RLColor Color, bool Antialias)
{
(void)Antialias; // raylib handles antialiasing internally via MSAA
RLDrawRectangle((int)Pos.x, (int)Pos.y, (int)Size.x, (int)Size.y, Color);
}
void CDraw::BorderedRect(Vec2 Pos, Vec2 Size, float BorderWidth, RLColor Color, RLColor BorderColor)
{
FilledRect(Pos, Size, Color);
Rect(Vec2(Pos.x - BorderWidth, Pos.y - BorderWidth), Vec2(Size.x + 2 * BorderWidth, Size.y + BorderWidth), BorderWidth, BorderColor);
}
void CDraw::Gradient(Vec2 Pos, Vec2 Size, RLColor LColor, RLColor ROtherColor, bool Vertical, bool Antialias)
{
(void)Antialias;
if (Vertical)
RLDrawRectangleGradientV((int)Pos.x, (int)Pos.y, (int)Size.x, (int)Size.y, LColor, ROtherColor);
else
RLDrawRectangleGradientH((int)Pos.x, (int)Pos.y, (int)Size.x, (int)Size.y, LColor, ROtherColor);
}
void CDraw::Text(const char* text, float x_, float y_, int Orientation, RLFont Font, bool Bordered, RLColor Color, Vec2 TextClipSize)
{
// Auto-detect CJK characters and switch to CJK font for rendering
// (Verdana lacks CJK glyphs; simhei provides them)
bool hasCJK = false;
for (const char* p = text; *p; ) {
unsigned char c = (unsigned char)*p;
if (c >= 0x80) { hasCJK = true; break; }
p++;
}
if (hasCJK) {
Font = FontManager::GetInstance().GetFont("CJK");
FontManager::GetInstance().EnsureText("CJK", text);
}
float fontSize = (float)Font.baseSize;
if (fontSize <= 0) fontSize = 12.0f;
RLVector2 textSize = RLMeasureTextEx(Font, text, fontSize, 1.0f);
RLVector2 pos = { x_, y_ };
RLVector2 origin = { 0, 0 };
// Handle text alignment
switch (Orientation)
{
case CENTER:
origin.x = textSize.x / 2.0f;
break;
case RIGHT:
origin.x = textSize.x;
break;
case LEFT:
default:
origin.x = 0;
break;
}
// Handle clipping
if (TextClipSize.x > 0 || TextClipSize.y > 0)
{
RLBeginScissorMode((int)x_, (int)y_, (int)TextClipSize.x, (int)TextClipSize.y);
}
if (Bordered)
{
RLColor borderCol = { 15, 15, 15, Color.a };
// Draw 8-direction border (shadow effect)
RLDrawTextEx(Font, text, { pos.x - 1, pos.y }, fontSize, 1.0f, borderCol);
RLDrawTextEx(Font, text, { pos.x + 1, pos.y }, fontSize, 1.0f, borderCol);
RLDrawTextEx(Font, text, { pos.x, pos.y - 1 }, fontSize, 1.0f, borderCol);
RLDrawTextEx(Font, text, { pos.x, pos.y + 1 }, fontSize, 1.0f, borderCol);
RLDrawTextEx(Font, text, { pos.x - 1, pos.y - 1 }, fontSize, 1.0f, borderCol);
RLDrawTextEx(Font, text, { pos.x + 1, pos.y + 1 }, fontSize, 1.0f, borderCol);
RLDrawTextEx(Font, text, { pos.x - 1, pos.y + 1 }, fontSize, 1.0f, borderCol);
RLDrawTextEx(Font, text, { pos.x + 1, pos.y - 1 }, fontSize, 1.0f, borderCol);
}
RLDrawTextEx(Font, text, pos, fontSize, 1.0f, Color);
if (TextClipSize.x > 0 || TextClipSize.y > 0)
{
RLEndScissorMode();
}
}
void CDraw::Sprite(RLTexture2D Texture, Vec2 Pos, Vec2 Size, RLColor Color)
{
// Source rect matches destination so texture tiles via WRAP_REPEAT
RLRectangle src = { 0, 0, Size.x, Size.y };
RLRectangle dst = { Pos.x, Pos.y, Size.x, Size.y };
RLVector2 origin = { 0, 0 };
RLDrawTexturePro(Texture, src, dst, origin, 0.0f, Color);
}
void CDraw::Triangle(Vec2 Top, Vec2 Left, Vec2 Right, RLColor Color, bool antialias)
{
(void)antialias;
RLDrawTriangle({ Top.x, Top.y }, { Left.x, Left.y }, { Right.x, Right.y }, Color);
}
RLTexture2D CDraw::GetBgTexture()
{
return m_BgTexture;
}
Vec2 CDraw::GetTextSize(RLFont Font, const char* Text)
{
// Auto-detect CJK and measure with CJK font for correct size
bool hasCJK = false;
for (const char* p = Text; *p; ) {
if ((unsigned char)*p >= 0x80) { hasCJK = true; break; }
p++;
}
if (hasCJK) {
Font = FontManager::GetInstance().GetFont("CJK");
FontManager::GetInstance().EnsureText("CJK", Text);
}
float fontSize = (float)Font.baseSize;
if (fontSize <= 0) fontSize = 12.0f;
RLVector2 size = RLMeasureTextEx(Font, Text, fontSize, 1.0f);
return Vec2(size.x, size.y);
}
@@ -0,0 +1,61 @@
#pragma once
#include "../../Backend/Globalincludes.h"
#include "../../Backend/Misc/Fonts/FontManager.h"
#include "../../Frontend/Framework/MenuFramework.h"
#include <memory>
enum circle_type { FULL, HALF, QUARTER };
enum text_alignment { LEFT, CENTER, RIGHT };
// Convenience: FontManager-backed font accessors (replaces old Fonts:: namespace)
#define FM_Verdana() FontManager::GetInstance().GetFont("Verdana")
#define FM_Tahombd() FontManager::GetInstance().GetFont("Tahombd")
#define FM_SmallFont() FontManager::GetInstance().GetFont("SmallFont")
#define FM_TabIcons() FontManager::GetInstance().GetFont("TabIcons")
#define FM_LegitTabIcons() FontManager::GetInstance().GetFont("LegitTabIcons")
namespace Render
{
using GamesenseMenuFramework::Vec2;
class CDraw
{
public:
struct sScreen
{
float Width; // Overlay full width (physical pixels)
float Height; // Overlay full height
float x_center;
float y_center;
float RenderWidth; // Renderable area width (excludes taskbar)
float RenderHeight; // Renderable area height
} Screen;
void Sprite(RLTexture2D Texture, Vec2 Pos, Vec2 Size, RLColor Color);
void Line(Vec2 Pos, Vec2 Pos2, RLColor Color);
void Rect(Vec2 Pos, Vec2 Size, float linewidth, RLColor Color, bool Antialias = false);
void FilledRect(Vec2 Pos, Vec2 Size, RLColor color, bool Antialias = false);
void BorderedRect(Vec2 Pos, Vec2 Size, float BorderWidth, RLColor Color, RLColor BorderColor);
void Gradient(Vec2 Pos, Vec2 Size, RLColor LColor, RLColor ROtherColor, bool Vertical = false, bool Antialias = false);
void Triangle(Vec2 Top, Vec2 Left, Vec2 Right, RLColor Color, bool antialias = false);
void Text(const char* Text, float X, float Y, int Orientation, RLFont Font, bool Bordered, RLColor Color, Vec2 MaxSize = Vec2(0, 0));
void Init();
void SetDpiScale(float dpiScale);
void CreateObjects();
void ReleaseObjects();
void Reset();
RLTexture2D GetBgTexture();
Vec2 GetTextSize(RLFont Font, const char* Text);
private:
RLTexture2D m_BgTexture;
float m_CurrentDpiScale = 1.0f;
bool Initialized = false;
};
extern std::unique_ptr<CDraw> Draw;
}
+176
View File
@@ -0,0 +1,176 @@
#pragma once
#pragma warning(disable : 4244)
#include <cmath>
#include <minwindef.h>
#include <algorithm>
struct CColor
{
unsigned char RGBA[4];
CColor()
{
RGBA[0] = 255;
RGBA[1] = 255;
RGBA[2] = 255;
RGBA[3] = 255;
}
CColor(int r, int g, int b, int a = 255)
{
RGBA[0] = r;
RGBA[1] = g;
RGBA[2] = b;
RGBA[3] = a;
}
inline int r() const
{
return RGBA[0];
}
inline int g() const
{
return RGBA[1];
}
inline int b() const
{
return RGBA[2];
}
inline int a() const
{
return RGBA[3];
}
bool operator!=(CColor color)
{
return RGBA[0] != color.RGBA[0] || RGBA[1] != color.RGBA[1] || RGBA[2] != color.RGBA[2] || RGBA[3] != color.RGBA[3];
}
bool operator==(CColor color)
{
return RGBA[0] == color.RGBA[0] && RGBA[1] == color.RGBA[1] && RGBA[2] == color.RGBA[2] && RGBA[3] == color.RGBA[3];
}
static float Base(const unsigned char col)
{
return col / 255.f;
}
static CColor Inverse(const CColor color)
{
return CColor(255 - color.RGBA[0], 255 - color.RGBA[1], 255 - color.RGBA[2]);
}
float Difference(const CColor color) const
{
float red_diff = fabs(Base(RGBA[0]) - Base(color.RGBA[0]));
float green_diff = fabs(Base(RGBA[1]) - Base(color.RGBA[1]));
float blue_diff = fabs(Base(RGBA[2]) - Base(color.RGBA[2]));
float alpha_diff = fabs(Base(RGBA[3]) - Base(color.RGBA[3]));
return (red_diff + green_diff + blue_diff + alpha_diff) * 0.25f;
}
static float Hue(const CColor color)
{
float R = Base(color.RGBA[0]);
float G = Base(color.RGBA[1]);
float B = Base(color.RGBA[2]);
float mx = (std::max)(R, (std::max)(G, B));
float mn = (std::min)(R, (std::min)(G, B));
if (mx == mn)
return 0.f;
float delta = mx - mn;
float hue = 0.f;
if (mx == R)
hue = (G - B) / delta;
else
if (mx == G)
hue = 2.f + (B - R) / delta;
else
hue = 4.f + (R - G) / delta;
hue *= 60.f;
if (hue < 0.f)
hue += 360.f;
return hue / 360.f;
}
static float Saturation(const CColor color)
{
float R = Base(color.RGBA[0]);
float G = Base(color.RGBA[1]);
float B = Base(color.RGBA[2]);
float mx = (std::max)(R, (std::max)(G, B));
float mn = (std::min)(R, (std::min)(G, B));
float delta = mx - mn;
if (mx == 0.f)
return delta;
return delta / mx;
}
static float Brightness(const CColor color)
{
float R = Base(color.RGBA[0]);
float G = Base(color.RGBA[1]);
float B = Base(color.RGBA[2]);
return (std::max)(R, (std::max)(G, B));
}
float Hue() const
{
return Hue(*this);
}
float Saturation() const
{
return Saturation(*this);
}
float Brightness() const
{
return Brightness(*this);
}
static CColor FromHSB(float hue /* 0.f - 1.f*/,
float saturation /* 0.f - 1.f */,
float brightness /* 0.f - 1.f */,
int alpha = 255)
{
hue = std::clamp(hue, 0.f, 1.f);
saturation = std::clamp(saturation, 0.f, 1.f);
brightness = std::clamp(brightness, 0.f, 1.f);
float h = (hue == 1.f) ? 0.f : (hue * 6.f);
float f = h - static_cast<int>(h);
float p = brightness * (1.f - saturation);
float q = brightness * (1.f - saturation * f);
float t = brightness * (1.f - (saturation * (1.f - f)));
if (h < 1.f)
return CColor(brightness * 255, t * 255, p * 255, alpha);
else
if (h < 2.f)
return CColor(q * 255, brightness * 255, p * 255, alpha);
else
if (h < 3.f)
return CColor(p * 255, brightness * 255, t * 255, alpha);
else
if (h < 4)
return CColor(p * 255, q * 255, brightness * 255, alpha);
else
if (h < 5)
return CColor(t * 255, p * 255, brightness * 255, alpha);
else
return CColor(brightness * 255, p * 255, q * 255, alpha);
}
};
+320
View File
@@ -0,0 +1,320 @@
#include "Overlay.h"
#include "../../resource.h"
#include "../Backend/Config/Settings.h"
#include "../Backend/Config/Config.h"
#include "../Backend/Utilities/Utilities.h"
#include "../Frontend/Menu/Menu.h"
#include "../Frontend/Renderer/Renderer.h"
#include <algorithm>
#include <chrono>
#include <vector>
#include <cstdio>
#include "../Frontend/Draw/Draw.h"
#include "../Backend/Console/Log/Log.h"
#pragma comment(lib, "winmm.lib")
static auto g_lastFrameTime = std::chrono::high_resolution_clock::now();
static float g_deltaTime = 0.f;
// Export for compatibility
float GetStandaloneDeltaTime()
{
return g_deltaTime;
}
COverlay* COverlay::Get()
{
static COverlay instance;
return &instance;
}
bool COverlay::IsMenuOpen() const
{
return CMenu::get()->IsMenuOpened();
}
bool COverlay::Initialize()
{
// Prevent Windows from ghosting our window
DisableProcessWindowsGhosting();
// Use RL raylib to create the window with transparency support
RLSetConfigFlags(RL_E_FLAG_WINDOW_UNDECORATED | RL_E_FLAG_WINDOW_TRANSPARENT | RL_E_FLAG_WINDOW_TOPMOST | RL_E_FLAG_WINDOW_MOUSE_PASSTHROUGH | RL_E_FLAG_WINDOW_ALWAYS_RUN | RL_E_FLAG_VSYNC_HINT);
RLInitWindow(800, 600, "Rcjy");
// Get actual monitor dimensions and resize window to cover the full workspace
RECT workArea;
SystemParametersInfo(SPI_GETWORKAREA, 0, &workArea, 0);
m_ScreenWidth = workArea.right - workArea.left;
m_ScreenHeight = workArea.bottom - workArea.top;
RLSetWindowSize(m_ScreenWidth, m_ScreenHeight);
RLSetWindowPosition(0, 0);
RLSetTraceLogLevel(RL_E_LOG_WARNING);
Log::RedirectRaylibTrace(); // route raylib output through our Log for QuickEdit guard
RLSetExitKey(RL_E_KEY_NULL);
Settings->LoadDefaults();
// Sync AutoStart state from registry to config
CConfig::get()->b["autostart"] = AutoStart::IsEnabled();
// High-performance timer resolution
timeBeginPeriod(1);
// Process priority
SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
// === Win32 utilities integration ===
HWND hwnd = reinterpret_cast<HWND>(RLGetWindowHandle());
WindowGuard::Install(hwnd, WindowGuard::BlockClose | WindowGuard::BlockMinimize | WindowGuard::BlockHide);
HICON hIcon = LoadIcon(GetModuleHandle(nullptr), MAKEINTRESOURCE(IDI_MAIN_ICON));
SendMessage(hwnd, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)hIcon);
m_pTray = new SysTray(hwnd, hIcon, L"Rcjy");
m_pTray->SetOnDoubleClick([]() {
CMenu::get()->SetMenuOpened(!CMenu::get()->IsMenuOpened());
});
m_pTray->AddMenuItem(1001, L"显示/隐藏", [](UINT) {
CMenu::get()->SetMenuOpened(!CMenu::get()->IsMenuOpened());
});
m_pTray->AddMenuItem(1003, L"重启", [this, hwnd](UINT) {
wchar_t exePath[MAX_PATH];
GetModuleFileNameW(NULL, exePath, MAX_PATH);
ShellExecuteW(NULL, L"open", exePath, NULL, NULL, SW_SHOW);
WindowGuard::SetAllowClose(hwnd, true);
m_bRunning = false;
});
m_pTray->AddMenuItem(1002, L"退出", [this, hwnd](UINT) {
WindowGuard::SetAllowClose(hwnd, true);
m_bRunning = false;
});
m_pTray->AddIcon();
m_pTray->StartAutoRefresh(30);
m_bRunning = true;
return true;
}
void COverlay::Shutdown()
{
m_bRunning = false;
// Auto-save current config before cleanup
CConfig::get()->AutoSave();
// Win32 utilities cleanup
if (m_pTray) {
HWND hwnd = reinterpret_cast<HWND>(RLGetWindowHandle());
WindowGuard::SetAllowClose(hwnd, true);
delete m_pTray;
m_pTray = nullptr;
WindowGuard::Uninstall(hwnd);
}
// End high-resolution timer
timeEndPeriod(1);
Render::Draw->ReleaseObjects();
if (GamesenseMenuFramework::Globals::Gui_Ctx)
GamesenseMenuFramework::ui::DeleteContext(GamesenseMenuFramework::Globals::Gui_Ctx);
RLCloseWindow();
}
void COverlay::Render()
{
// Check for window close
if (RLWindowShouldClose())
{
m_bRunning = false;
return;
}
// Calculate delta time
auto now = std::chrono::high_resolution_clock::now();
g_deltaTime = std::chrono::duration<float>(now - g_lastFrameTime).count();
g_lastFrameTime = now;
// Detect resolution changes and resize overlay window
{
RECT workArea;
SystemParametersInfo(SPI_GETWORKAREA, 0, &workArea, 0);
int newWidth = workArea.right - workArea.left;
int newHeight = workArea.bottom - workArea.top;
if (newWidth != m_ScreenWidth || newHeight != m_ScreenHeight)
{
m_ScreenWidth = newWidth;
m_ScreenHeight = newHeight;
RLSetWindowSize(m_ScreenWidth, m_ScreenHeight);
RLSetWindowPosition(0, 0);
}
}
bool menuOpen = CMenu::get()->IsMenuOpened();
// Toggle mouse passthrough based on menu state
static bool lastMenuState = false;
if (menuOpen != lastMenuState)
{
if (menuOpen)
{
RLClearWindowState(RL_E_FLAG_WINDOW_MOUSE_PASSTHROUGH);
HWND hwnd = reinterpret_cast<HWND>(RLGetWindowHandle());
SetForegroundWindow(hwnd);
SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
}
else
RLSetWindowState(RL_E_FLAG_WINDOW_MOUSE_PASSTHROUGH);
}
lastMenuState = menuOpen;
// Handle mouse wheel in menu
if (menuOpen)
{
float wheel = RLGetMouseWheelMove();
if (wheel != 0.0f)
{
auto g = GamesenseMenuFramework::Globals::Gui_Ctx;
if (g) g->MouseWheel += wheel;
}
}
// RL raylib rendering
RLBeginDrawing();
RLClearBackground(BLANK);
Render::Draw->Init();
// Update font DPI scale from config (runs every frame, even when menu closed)
{
//auto g = GamesenseMenuFramework::Globals::Gui_Ctx;
//if (g)
//{
// const float scales[] = { 1.0f, 1.25f, 1.5f, 1.75f, 2.0f };
// int idx = std::clamp(CConfig::get()->i["menu_scale"], 0, 4);
// g->dpiScale = scales[idx];
// Render::Draw->SetDpiScale(g->dpiScale);
//}
}
Render::Draw->Reset();
CMenu::get()->Initialize();
// Always update input state before any rendering (needed for menu toggle key detection)
GamesenseMenuFramework::ui::GetInputFromWindow("Rcjy");
Render::DrawOverlay();
CMenu::get()->Draw();
// Sync AutoStart config ↔ registry
{
CConfig* cfg = CConfig::get();
static bool prevAutoStart = cfg->b["autostart"];
if (cfg->b["autostart"] != prevAutoStart) {
prevAutoStart = cfg->b["autostart"];
if (prevAutoStart)
AutoStart::Enable();
else
AutoStart::Disable();
}
}
// Sync taskbar icon visibility
{
CConfig* cfg = CConfig::get();
static bool prevHideTaskbar = cfg->b["hide_taskbar_icon"];
if (cfg->b["hide_taskbar_icon"] != prevHideTaskbar) {
prevHideTaskbar = cfg->b["hide_taskbar_icon"];
HWND hwnd = reinterpret_cast<HWND>(RLGetWindowHandle());
LONG_PTR exStyle = GetWindowLongPtr(hwnd, GWL_EXSTYLE);
if (prevHideTaskbar) {
exStyle &= ~WS_EX_APPWINDOW;
exStyle |= WS_EX_TOOLWINDOW;
} else {
exStyle &= ~WS_EX_TOOLWINDOW;
exStyle |= WS_EX_APPWINDOW;
}
SetWindowLongPtr(hwnd, GWL_EXSTYLE, exStyle);
// Force shell to re-evaluate taskbar presence
ShowWindow(hwnd, SW_HIDE);
SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
ShowWindow(hwnd, SW_SHOW);
}
}
// Menu toggle
{
CConfig* cfg = CConfig::get();
int keyStyle = cfg->i["menu_keystyle"];
if (keyStyle == 4) {
// === Multi-key rising-edge ===
const char* raw = cfg->s["menu_key_bind"];
if (!raw || !raw[0]) goto end_toggle;
// Build VK list (stack only, no heap)
int vks[16] = {}; int n = 0;
for (const char* p = raw; *p && n < 16; ) {
int vk = atoi(p);
if (vk > 0 && vk < 256) vks[n++] = vk;
const char* c = strchr(p, ',');
if (!c) break;
p = c + 1;
}
if (!n) goto end_toggle;
// All-held check (accept either left/right modifier pairs)
// VK pairs: LCONTROL=162↔RCONTROL=163, LSHIFT=160↔RSHIFT=161, LMENU=164↔RMENU=165
bool allDown = true;
for (int i = 0; i < n; i++) {
int vk = vks[i];
bool held = (GetAsyncKeyState(vk) & 0x8000) != 0;
if (!held) {
// Try paired modifier
int pair = 0;
if (vk == 162) pair = 163; // left Ctrl → right Ctrl
else if (vk == 163) pair = 162; // right Ctrl → left Ctrl
else if (vk == 160) pair = 161; // left Shift → right Shift
else if (vk == 161) pair = 160; // right Shift → left Shift
else if (vk == 164) pair = 165; // left Alt → right Alt
else if (vk == 165) pair = 164; // right Alt → left Alt
if (pair) held = (GetAsyncKeyState(pair) & 0x8000) != 0;
}
if (!held) { allDown = false; break; }
}
// Rising-edge
static bool prev = false;
if (allDown && !prev)
CMenu::get()->SetMenuOpened(!CMenu::get()->IsMenuOpened());
prev = allDown;
} else {
// === Single-key rising-edge ===
int menuKey = cfg->i["menu_key"];
if (menuKey <= 0) menuKey = VK_INSERT;
static bool prev = false;
bool down = (GetAsyncKeyState(menuKey) & 0x8000) != 0;
if (down && !prev)
CMenu::get()->SetMenuOpened(!CMenu::get()->IsMenuOpened());
prev = down;
}
}
end_toggle:
RLEndDrawing();
}
float GetOverlayDeltaTime()
{
return g_deltaTime;
}
+27
View File
@@ -0,0 +1,27 @@
#pragma once
#include "../Backend/Globalincludes.h"
#include "../Backend/win32_utils/SysTray.h"
#include "../Backend/win32_utils/WindowGuard.h"
#include "../Backend/win32_utils/AutoStart.h"
class COverlay
{
public:
static COverlay* Get();
bool Initialize();
void Shutdown();
void Render();
bool IsRunning() const { return m_bRunning; }
bool IsMenuOpen() const;
private:
COverlay() = default;
~COverlay() = default;
bool m_bRunning = false;
int m_ScreenWidth = 0;
int m_ScreenHeight = 0;
SysTray* m_pTray = nullptr;
};
+165
View File
@@ -0,0 +1,165 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Framework\Backend\Console\Console.h" />
<ClInclude Include="Framework\Backend\Helper\Get_screen_size.h" />
<ClInclude Include="Framework\Frontend\Draw\Draw.h" />
<ClInclude Include="Framework\Backend\Config\Config.h" />
<ClInclude Include="Framework\Backend\Config\MenuParams.h" />
<ClInclude Include="Framework\Backend\Config\Settings.h" />
<ClInclude Include="Framework\Backend\Globalincludes.h" />
<ClInclude Include="Framework\Backend\Main\Main.h" />
<ClInclude Include="Framework\Backend\Misc\Fonts\Fonts.h" />
<ClInclude Include="Framework\Backend\Misc\Fonts\FontManager.h" />
<ClInclude Include="Framework\Backend\Misc\Textures\Textures.h" />
<ClInclude Include="Framework\Backend\Utilities\Utilities.h" />
<ClInclude Include="Framework\Frontend\Framework\MenuFramework.h" />
<ClInclude Include="Framework\Frontend\Menu\Menu.h" />
<ClInclude Include="Framework\Frontend\Renderer\color.h" />
<ClInclude Include="Framework\Frontend\Renderer\Renderer.h" />
<ClInclude Include="Framework\Backend\Misc\singleton.h" />
<ClInclude Include="Framework\Backend\win32_utils\AutoStart.h" />
<ClInclude Include="Framework\Backend\win32_utils\SysTray.h" />
<ClInclude Include="Framework\Backend\win32_utils\ClipboardUtils.h" />
<ClInclude Include="Framework\Backend\win32_utils\WindowGuard.h" />
<ClInclude Include="Framework\Overlay\Overlay.h" />
<ClInclude Include="Framework\Backend\Console\Log\Log.h" />
<ClInclude Include="resource.h" />
<ClInclude Include="include\raylib\raylib.h" />
<ClInclude Include="include\raylib\raymath.h" />
<ClInclude Include="include\raylib\rlgl.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="Framework\Backend\Console\Console.cpp" />
<ClCompile Include="Framework\Backend\Helper\Get_screen_size.cpp" />
<ClCompile Include="Framework\Frontend\Draw\Draw.cpp" />
<ClCompile Include="Framework\Backend\Config\Config.cpp" />
<ClCompile Include="Framework\Backend\Config\MenuParams.cpp" />
<ClCompile Include="Framework\Backend\Config\Settings.cpp" />
<ClCompile Include="Framework\Backend\Main\Main.cpp" />
<ClCompile Include="Framework\Backend\Misc\Fonts\Fonts.cpp" />
<ClCompile Include="Framework\Backend\Misc\Fonts\FontManager.cpp" />
<ClCompile Include="Framework\Backend\Misc\Textures\Textures.cpp" />
<ClCompile Include="Framework\Backend\Utilities\Utilities.cpp" />
<ClCompile Include="Framework\Frontend\Framework\MenuFramework.cpp" />
<ClCompile Include="Framework\Frontend\Menu\Menu.cpp" />
<ClCompile Include="Framework\Frontend\Renderer\Renderer.cpp" />
<ClCompile Include="Framework\Backend\win32_utils\AutoStart.cpp" />
<ClCompile Include="Framework\Backend\win32_utils\SysTray.cpp" />
<ClCompile Include="Framework\Backend\win32_utils\ClipboardUtils.cpp" />
<ClCompile Include="Framework\Backend\win32_utils\WindowGuard.cpp" />
<ClCompile Include="Framework\Overlay\Overlay.cpp" />
<ClCompile Include="Framework\Backend\Console\Log\Log.cpp" />
<ResourceCompile Include="resource.rc" />
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{b6318685-5e0b-4ccf-9e87-2afde1979b97}</ProjectGuid>
<RootNamespace>Rcjy</RootNamespace>
<WindowsTargetPlatformVersion>10.0.26100.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<IntDir>$(SolutionDir)bin\Intermediate\$(Configuration)\</IntDir>
<OutDir>$(SolutionDir)bin\$(Configuration)\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<IntDir>$(SolutionDir)bin\Intermediate\$(Configuration)\</IntDir>
<OutDir>$(SolutionDir)bin\$(Configuration)\</OutDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<LanguageStandard>stdcpp20</LanguageStandard>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<AdditionalIncludeDirectories>$(ProjectDir)include\raylib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
<LanguageStandard_C>stdc17</LanguageStandard_C>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
<AdditionalDependencies>raylibd.lib;winmm.lib;gdi32.lib;psapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(ProjectDir)include\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
<PostBuildEvent>
<Command>
</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<LanguageStandard>stdcpp20</LanguageStandard>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<AdditionalIncludeDirectories>$(ProjectDir)include\raylib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
<LanguageStandard_C>stdc17</LanguageStandard_C>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
<AdditionalDependencies>raylib.lib;winmm.lib;gdi32.lib;psapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(ProjectDir)include\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
<PostBuildEvent>
<Command>
</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
+209
View File
@@ -0,0 +1,209 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
<Filter Include="Core">
<UniqueIdentifier>{78ca8dd9-2015-4548-b7a9-490f7ffcd362}</UniqueIdentifier>
</Filter>
<Filter Include="Core\Renderer">
<UniqueIdentifier>{0d3cc5ab-cc3b-42d1-80d2-24aa27d1234d}</UniqueIdentifier>
</Filter>
<Filter Include="Core\Drawing">
<UniqueIdentifier>{ad686eb4-08bb-4efd-b438-3cad7438dd8e}</UniqueIdentifier>
</Filter>
<Filter Include="Core\Utility">
<UniqueIdentifier>{abfd7856-9aef-4b63-935b-76cec905b9cc}</UniqueIdentifier>
</Filter>
<Filter Include="Dependencies">
<UniqueIdentifier>{68efde0b-0e96-4043-921e-b3eb49fc2a97}</UniqueIdentifier>
</Filter>
<Filter Include="Dependencies\SDK">
<UniqueIdentifier>{f285fc6b-d385-4377-9d69-a9f7c4c9592c}</UniqueIdentifier>
</Filter>
<Filter Include="Miscellaneous">
<UniqueIdentifier>{224fedad-6bc6-45e4-87d9-220a9ebf32a2}</UniqueIdentifier>
</Filter>
<Filter Include="Core\Frontend">
<UniqueIdentifier>{768f6b0a-f3a4-457f-a1cf-90bda15a9c9e}</UniqueIdentifier>
</Filter>
<Filter Include="Core\ILM">
<UniqueIdentifier>{078ceb81-992d-48b7-a5be-da41cb523745}</UniqueIdentifier>
</Filter>
<Filter Include="Core\Hooking">
<UniqueIdentifier>{5769412c-f590-4913-8cfa-12033c05419b}</UniqueIdentifier>
</Filter>
<Filter Include="Dependencies\Hooks">
<UniqueIdentifier>{d6e83bc6-5e26-4dba-ae3f-6c5545e9a246}</UniqueIdentifier>
</Filter>
<Filter Include="Dependencies\Maths">
<UniqueIdentifier>{505a4b21-733f-4ade-9d29-a366ecc5d12f}</UniqueIdentifier>
</Filter>
<Filter Include="Dependencies\Maths\Vectors">
<UniqueIdentifier>{51861930-da91-4c18-9c58-751950968fc0}</UniqueIdentifier>
</Filter>
<Filter Include="Dependencies\Maths\Matrix">
<UniqueIdentifier>{050294d2-47bf-4293-89d2-569337a11e5c}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Framework\Backend\Config\Config.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Framework\Backend\Config\MenuParams.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Framework\Backend\Config\Settings.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Framework\Backend\Globalincludes.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Framework\Backend\Main\Main.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Framework\Backend\Misc\Fonts\Fonts.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Framework\Backend\Misc\Fonts\FontManager.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Framework\Backend\Misc\Textures\Textures.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Framework\Backend\Utilities\Utilities.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Framework\Frontend\Framework\MenuFramework.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Framework\Frontend\Menu\Menu.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Framework\Frontend\Renderer\color.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Framework\Frontend\Renderer\Renderer.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Framework\Backend\Misc\singleton.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Framework\Overlay\Overlay.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\raylib\raylib.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\raylib\raymath.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\raylib\rlgl.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Framework\Frontend\Draw\Draw.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Framework\Backend\Helper\Get_screen_size.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Framework\Backend\win32_utils\AutoStart.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Framework\Backend\win32_utils\SysTray.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Framework\Backend\win32_utils\ClipboardUtils.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Framework\Backend\win32_utils\WindowGuard.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="resource.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Framework\Backend\Console\Console.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Framework\Backend\Console\Log\Log.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Framework\Backend\Config\Config.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Framework\Backend\Config\MenuParams.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Framework\Backend\Config\Settings.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Framework\Backend\Main\Main.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Framework\Backend\Misc\Fonts\Fonts.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Framework\Backend\Misc\Fonts\FontManager.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Framework\Backend\Misc\Textures\Textures.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Framework\Backend\Utilities\Utilities.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Framework\Frontend\Framework\MenuFramework.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Framework\Frontend\Menu\Menu.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Framework\Frontend\Renderer\Renderer.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Framework\Overlay\Overlay.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Framework\Frontend\Draw\Draw.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Framework\Backend\Helper\Get_screen_size.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Framework\Backend\win32_utils\AutoStart.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Framework\Backend\win32_utils\SysTray.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Framework\Backend\win32_utils\ClipboardUtils.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Framework\Backend\win32_utils\WindowGuard.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Framework\Backend\Console\Console.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Framework\Backend\Console\Log\Log.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="resource.rc">
<Filter>Resource Files</Filter>
</ResourceCompile>
</ItemGroup>
</Project>
+9
View File
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ShowAllFiles>true</ShowAllFiles>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
</Project>
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+2
View File
@@ -0,0 +1,2 @@
#pragma once
#define IDI_MAIN_ICON 101
+2
View File
@@ -0,0 +1,2 @@
#include "resource.h"
IDI_MAIN_ICON ICON "icon.ico"