gkms-localify-dmm/src/windowsPlatform.cpp

457 lines
16 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "windowsPlatform.hpp"
#include "GakumasLocalify/Plugin.h"
#include "GakumasLocalify/Log.h"
#include "GakumasLocalify/Local.h"
#include "GakumasLocalify/MasterLocal.h"
#include "GakumasLocalify/camera/camera.hpp"
#include "GakumasLocalify/config/Config.hpp"
#include "GakumasLocalify/Il2cppUtils.hpp"
#include "gkmsGUI/gkmsGUIMain.hpp"
#include "gkmsGUI/GUII18n.hpp"
#include "resourceUpdate/resourceUpdate.hpp"
#include <stdinclude.hpp>
#include "deps/UnityResolve/UnityResolve.hpp"
#include <cpprest/details/basic_types.h>
#include <cpprest/details/http_helpers.h>
#include <windowsx.h>
bool mh_inited;
extern std::filesystem::path gakumasLocalPath;
extern std::filesystem::path ConfigJson;
extern std::filesystem::path ProgramConfigJson;
int hotk = 'u';
void reload_all_data();
std::function<void()> g_on_close;
std::function<void()> on_hotKey_0;
std::function<void()> g_reload_all_data = reload_all_data;
void patchGameAssenbly();
void readProgramConfig();
namespace
{
class AndroidHookInstaller : public GakumasLocal::HookInstaller
{
public:
explicit AndroidHookInstaller(const std::string& il2cppLibraryPath, const std::string& localizationFilesDir)
{
this->m_Il2CppLibrary = GetModuleHandle("GameAssembly.dll");
this->m_il2cppLibraryPath = il2cppLibraryPath;
this->localizationFilesDir = localizationFilesDir;
}
~AndroidHookInstaller() override {
if (!mh_inited) return;
MH_DisableHook(MH_ALL_HOOKS);
MH_Uninitialize();
}
void* InstallHook(void* addr, void* hook, void** orig) override
{
auto createStat = MH_CreateHook(addr, hook, orig);
MH_EnableHook(addr);
return reinterpret_cast<void*>(createStat);
}
GakumasLocal::OpaqueFunctionPointer LookupSymbol(const char* name) override
{
return reinterpret_cast<GakumasLocal::OpaqueFunctionPointer>(GetProcAddress(reinterpret_cast<HMODULE>(m_Il2CppLibrary), name));
}
private:
void* m_Il2CppLibrary;
};
}
void* load_library_w_orig;
HMODULE __stdcall load_library_w_hook(const wchar_t* path)
{
// GakumasLocal::Log::DebugFmt("LoadLibrary %s", utility::conversions::to_utf8string(path).c_str());
using namespace std;
if (path == L"VuplexWebViewWindows.dll"sv) {
// if (path == L"cri_ware_unity.dll"sv) {
// if (path == L"NVUnityPlugin"sv) {
patchGameAssenbly();
}
return reinterpret_cast<decltype(LoadLibraryW)*>(load_library_w_orig)(path);
}
void patchGameAssenbly() {
static bool patched = false;
if (patched) return;
patched = true;
auto& plugin = GakumasLocal::Plugin::GetInstance();
plugin.InstallHook(std::make_unique<AndroidHookInstaller>("GameAssembly.dll", gakumasLocalPath.string()));
}
void unInitHook() {
if (!mh_inited) return;
MH_DisableHook(MH_ALL_HOOKS);
MH_Uninitialize();
}
void initHook() {
mh_inited = true;
if (MH_Initialize() != MH_OK)
return;
auto stat1 = MH_CreateHook(LoadLibraryW, load_library_w_hook, &load_library_w_orig);
auto stat2 = MH_EnableHook(LoadLibraryW);
g_on_close = []() {
unInitHook();
TerminateProcess(GetCurrentProcess(), 0);
};
static bool guiStarting = false;
on_hotKey_0 = []() {
if (guiStarting) return;
guiStarting = true;
std::thread([]() {
printf("GUI START\n");
guimain();
guiStarting = false;
printf("GUI END\n");
}).detach();
};
GakumasLocal::Log::InfoFmt("initHook stat: %s - %s\n", MH_StatusToString(stat1), MH_StatusToString(stat2));
}
void checkAndInitConfig(const std::filesystem::path& LocalConfigFile) {
if (!std::filesystem::exists(ProgramConfigJson)) {
g_useAPIAssetsURL = GkmsGUII18n::ts("default_assets_check_api");
GkmsResourceUpdate::saveProgramConfig();
}
if (!std::filesystem::exists(LocalConfigFile)) {
GakumasLocal::Config::SaveConfig(LocalConfigFile.string());
}
}
void loadConfig(const std::string& configJson) {
GakumasLocal::Config::LoadConfig(configJson);
}
void loadConfig(const std::filesystem::path& filePath) {
checkAndInitConfig(filePath);
std::ifstream file(filePath);
if (!file.is_open()) {
GakumasLocal::Log::ErrorFmt("Load config %s failed.\n", filePath.string().c_str());
loadConfig(std::string("{}"));
return;
}
std::string fileContent((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
file.close();
loadConfig(fileContent);
}
void reload_all_data() {
readProgramConfig();
loadConfig(ConfigJson);
GkmsResourceUpdate::GetCurrentResourceVersion(false);
GkmsResourceUpdate::GetCurrentTextureVersion(false);
GakumasLocal::Local::LoadData();
GakumasLocal::MasterLocal::LoadData();
}
bool getCurrentLodingProgress(int* stepTotal, int* stepCurrent, int* currTotal, int* currCurrent) {
*stepTotal = UnityResolveProgress::assembliesProgress.total;
*stepCurrent = UnityResolveProgress::assembliesProgress.current;
*currTotal = UnityResolveProgress::classProgress.total;
*currCurrent = UnityResolveProgress::classProgress.current;
return UnityResolveProgress::startInit;
}
void checkDBGKey(int action, int key_code) {
if (action != WM_KEYDOWN) return;
static const std::vector<int> targetDbgKeyList = { 38, 38, 40, 40, 37, 39, 37, 39, 66, 65};
static int currentIndex = 0;
if (targetDbgKeyList[currentIndex] == key_code) {
if (currentIndex == targetDbgKeyList.size() - 1) {
currentIndex = 0;
GakumasLocal::Config::dbgMode = !GakumasLocal::Config::dbgMode;
GakumasLocal::Config::SaveConfig(ConfigJson.string());
GakumasLocal::Log::InfoFmt("Debug Mode: %d", GakumasLocal::Config::dbgMode);
}
else {
currentIndex++;
}
}
else {
currentIndex = 0;
}
}
void keyboardEvents(int action, int key_code) {
// GakumasLocal::Log::DebugFmt("keyboardEvents: %d - %d", action, key_code);
checkDBGKey(action, key_code);
GKCamera::on_cam_rawinput_keyboard(action, key_code);
const auto msg = GakumasLocal::Local::OnKeyDown(action, key_code);
if (!msg.empty()) {
GakumasLocal::Log::Info(msg.c_str());
}
}
namespace GakumasLocal::WinHooks {
using Il2cppString = UnityResolve::UnityType::String;
void* LoadAssetBundle(const std::string& path) {
Il2cppString* bundlePath = Il2cppString::New(path);
static auto LoadFromFileAsync = Il2cppUtils::GetMethod("UnityEngine.AssetBundleModule.dll", "UnityEngine", "AssetBundle", "LoadFromFileAsync");
static auto get_assetBundle = Il2cppUtils::GetMethod("UnityEngine.AssetBundleModule.dll", "UnityEngine", "AssetBundleCreateRequest", "get_assetBundle");
auto bundleTask = LoadFromFileAsync->Invoke<void*>(bundlePath);
if (!bundleTask) {
return nullptr;
}
return get_assetBundle->Invoke<void*>(bundleTask);
}
void SwitchFullScreen(HWND hWnd) {
static auto Screen_SetResolution = reinterpret_cast<void (*)(UINT, UINT, UINT, void*)>(
Il2cppUtils::il2cpp_resolve_icall("UnityEngine.Screen::SetResolution_Injected(System.Int32,System.Int32,UnityEngine.FullScreenMode,UnityEngine.RefreshRate&)"));
static auto get_Height = reinterpret_cast<int (*)()>(Il2cppUtils::il2cpp_resolve_icall("UnityEngine.Screen::get_height()"));
static auto get_Width = reinterpret_cast<int (*)()>(Il2cppUtils::il2cpp_resolve_icall("UnityEngine.Screen::get_width()"));
LONG style = GetWindowLong(hWnd, GWL_STYLE);
bool currFullScreen = style & WS_POPUP;
static int savedWidth = -1;
static int savedHeight = -1;
int64_t v8[3];
v8[0] = 0x100000000LL;
if (currFullScreen) {
// 取消全屏
if (savedWidth == -1) {
savedWidth = 542;
savedHeight = 990;
}
Screen_SetResolution(savedWidth, savedHeight, 2 * !false + 1, v8);
}
else {
savedWidth = get_Width();
savedHeight = get_Height();
Screen_SetResolution(GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), 2 * !true + 1, v8);
}
}
namespace Keyboard {
std::function<void(int, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD)> mKeyBoardCallBack = nullptr;
WNDPROC g_pfnOldWndProc = NULL;
LRESULT CALLBACK WndProcCallback(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
DWORD SHIFT_key = 0;
DWORD CTRL_key = 0;
DWORD ALT_key = 0;
DWORD SPACE_key = 0;
DWORD UP_key = 0;
DWORD DOWN_key = 0;
DWORD LEFT_key = 0;
DWORD RIGHT_key = 0;
// printf("WndProcCallback: 0x%x (%d)\n", uMsg, uMsg);
switch (uMsg) {
case WM_INPUT: {
RAWINPUT rawInput;
UINT size = sizeof(RAWINPUT);
if (GetRawInputData((HRAWINPUT)lParam, RID_INPUT, &rawInput, &size, sizeof(RAWINPUTHEADER)) == size) {
/* 鼠标事件,后面加上
if (rawInput.header.dwType == RIM_TYPEMOUSE)
{
switch (rawInput.data.mouse.ulButtons) {
case 0: { // move
SCCamera::mouseMove(rawInput.data.mouse.lLastX, rawInput.data.mouse.lLastY, 3);
}; break;
case 4: { // press
SCCamera::mouseMove(0, 0, 1);
}; break;
case 8: { // release
SCCamera::mouseMove(0, 0, 2);
}; break;
default: break;
}
if (rawInput.data.mouse.usButtonFlags == RI_MOUSE_WHEEL) {
if (rawInput.data.mouse.usButtonData == 120) {
SCCamera::mouseMove(0, 1, 4);
}
else {
SCCamera::mouseMove(0, -1, 4);
}
}
}*/
}
}; break;
case WM_SYSKEYUP:
case WM_KEYUP: {
int key = wParam;
keyboardEvents(uMsg, key);
}; break;
case WM_SYSKEYDOWN:
case WM_KEYDOWN: {
int key = wParam;
keyboardEvents(uMsg, key);
SHIFT_key = GetAsyncKeyState(VK_SHIFT);
CTRL_key = GetAsyncKeyState(VK_CONTROL);
ALT_key = GetAsyncKeyState(VK_MENU);
SPACE_key = GetAsyncKeyState(VK_SPACE);
UP_key = GetAsyncKeyState(VK_UP);
DOWN_key = GetAsyncKeyState(VK_DOWN);
LEFT_key = GetAsyncKeyState(VK_LEFT);
RIGHT_key = GetAsyncKeyState(VK_RIGHT);
if (mKeyBoardCallBack != nullptr) {
mKeyBoardCallBack(key, SHIFT_key, CTRL_key, ALT_key, SPACE_key, UP_key, DOWN_key, LEFT_key, RIGHT_key);
}
if (key == 122) {
// F11
if (GakumasLocal::Config::dmmUnlockSize) {
SwitchFullScreen(hWnd);
}
}
if (key >= 'A' && key <= 'Z')
{
if (GetAsyncKeyState(VK_SHIFT) >= 0) key += 32;
if (CTRL_key != 0 && key == hotk)
{
// fopenExternalPlugin(tlgport);
printf("hotKey pressed.\n");
if (on_hotKey_0) on_hotKey_0();
}
SHIFT_key = 0;
CTRL_key = 0;
ALT_key = 0;
SPACE_key = 0;
DWORD UP_key = 0;
DWORD DOWN_key = 0;
DWORD LEFT_key = 0;
DWORD RIGHT_key = 0;
}
}; break;
case WM_NCACTIVATE: {
if (!wParam) {
// SCCamera::onKillFocus();
return FALSE;
}
}; break;
case WM_KILLFOCUS: {
// SCCamera::onKillFocus();
return FALSE;
}; break;
case WM_CLOSE: {
if (g_on_close) g_on_close();
}; break;
case WM_NCHITTEST:
{
if (GakumasLocal::Config::dmmUnlockSize) {
POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
ScreenToClient(hWnd, &pt);
RECT rcClient;
GetClientRect(hWnd, &rcClient);
const int borderWidth = 8; // 根据需要调整边缘宽度
bool left = pt.x < borderWidth;
bool right = pt.x >= rcClient.right - borderWidth;
bool top = pt.y < borderWidth;
bool bottom = pt.y >= rcClient.bottom - borderWidth;
if (top && left) return HTTOPLEFT;
if (top && right) return HTTOPRIGHT;
if (bottom && left) return HTBOTTOMLEFT;
if (bottom && right) return HTBOTTOMRIGHT;
if (left) return HTLEFT;
if (right) return HTRIGHT;
if (top) return HTTOP;
if (bottom) return HTBOTTOM;
return HTCLIENT;
}
} break;
case WM_GETMINMAXINFO:
{
if (GakumasLocal::Config::dmmUnlockSize) {
LPMINMAXINFO lpMMI = (LPMINMAXINFO)lParam;
// 设置最大尺寸为屏幕分辨率,这样就不限制窗口的最大尺寸
lpMMI->ptMaxTrackSize.x = GetSystemMetrics(SM_CXSCREEN) * 3;
lpMMI->ptMaxTrackSize.y = GetSystemMetrics(SM_CYSCREEN) * 3;
// 可选设置窗口最小尺寸例如200x200
lpMMI->ptMinTrackSize.x = 200;
lpMMI->ptMinTrackSize.y = 200;
return 1;
}
} break;
case WM_SYSCOMMAND: {
if (GakumasLocal::Config::dmmUnlockSize) {
if ((wParam & 0xFFF0) == SC_MAXIMIZE) {
SwitchFullScreen(hWnd);
return 1;
}
}
} break;
case WM_NCPAINT: {
if (GakumasLocal::Config::dmmUnlockSize) {
LONG style = GetWindowLong(hWnd, GWL_STYLE);
// printf("WM_NCPAINT: 0x%x\n", style);
if (!(style & WS_POPUP)) {
// 添加可调整大小的边框和最大化按钮
style |= WS_THICKFRAME | WS_MAXIMIZEBOX;
SetWindowLong(hWnd, GWL_STYLE, style);
}
}
} break;
default: break;
}
return CallWindowProc(g_pfnOldWndProc, hWnd, uMsg, wParam, lParam);
}
void InstallWndProcHook() {
auto hWnd = FindWindowW(L"UnityWndClass", L"gakumas");
g_pfnOldWndProc = (WNDPROC)GetWindowLongPtr(hWnd, GWLP_WNDPROC);
SetWindowLongPtr(FindWindowW(L"UnityWndClass", L"gakumas"), GWLP_WNDPROC, (LONG_PTR)WndProcCallback);
// 添加可调整大小的边框和最大化按钮
LONG style = GetWindowLong(hWnd, GWL_STYLE);
style |= WS_THICKFRAME | WS_MAXIMIZEBOX;
SetWindowLong(hWnd, GWL_STYLE, style);
}
void UninstallWndProcHook(HWND hWnd)
{
SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)g_pfnOldWndProc);
}
}
}