From aa9b535b4f3a96fca64d9e0afb8a2423343d0ad7 Mon Sep 17 00:00:00 2001 From: ptmaster Date: Wed, 4 Dec 2024 01:03:47 +0800 Subject: [PATCH 1/6] Add AsyncUpdate/AsyncIO (experimental) Fix something to enhance stablility --- CMakeLists.txt | 4 +- src/bnusio.cpp | 100 +++++--- src/bnusio.h | 1 + src/dllmain.cpp | 9 +- src/patches/layeredfs.cpp | 20 +- src/patches/versions/JPN39.cpp | 84 +++---- src/poll.cpp | 307 +---------------------- src/poll.h | 60 +++-- src/pollasync.cpp | 429 +++++++++++++++++++++++++++++++++ src/polldef.h | 305 +++++++++++++++++++++++ 10 files changed, 910 insertions(+), 409 deletions(-) create mode 100644 src/pollasync.cpp create mode 100644 src/polldef.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 8ad4037..253385b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,7 +17,8 @@ else() add_compile_options(-Wall -Wextra -Wpedantic) endif() -# Add project definitions +# Add project definitions (Add ASYNC_UPDATE/ASYNC_IO to enable new async feature [experimental]) +# add_definitions(-DNOMINMAX -DLTC_NO_PROTOTYPES -D_CRT_SECURE_NO_WARNINGS -DASYNC_UPDATE) add_definitions(-DNOMINMAX -DLTC_NO_PROTOTYPES -D_CRT_SECURE_NO_WARNINGS) # Include FetchContent module @@ -128,6 +129,7 @@ set(SOURCES src/helpers.cpp src/logger.cpp src/poll.cpp + src/pollasync.cpp src/bnusio.cpp src/patches/amauth.cpp src/patches/dxgi.cpp diff --git a/src/bnusio.cpp b/src/bnusio.cpp index 7fcef72..faee21d 100644 --- a/src/bnusio.cpp +++ b/src/bnusio.cpp @@ -17,6 +17,7 @@ extern bool autoIme; extern bool emulateUsio; extern bool emulateCardReader; extern bool acceptInvalidCards; +extern HWND hGameWnd; typedef i32 (*callbackAttach) (i32, i32, i32 *); typedef void (*callbackTouch) (i32, i32, u8[168], u64); @@ -263,6 +264,61 @@ FUNCTION_PTR (i64, bnusio_DecCoin_Original, PROC_ADDRESS ("bnusio_original.dll", FUNCTION_PTR (u64, bnusio_DecService_Original, PROC_ADDRESS ("bnusio_original.dll", "bnusio_DecService"), i32, u16); FUNCTION_PTR (i64, bnusio_ResetCoin_Original, PROC_ADDRESS ("bnusio_original.dll", "bnusio_ResetCoin")); +#ifndef ASYNC_UPDATE +void +Update () { +#else +std::thread pollThread; +std::thread updateThread; +std::mutex syncMtx; +std::condition_variable syncCV; + +void +UpdateLoop () { + LogMessage (LogLevel::WARN, "Using Async Update (experimental)!"); + std::unique_lock syncLock(syncMtx); + while (exited < 50) { + syncCV.wait (syncLock); +#endif + if (exited && ++exited >= 50) ExitProcess (0); + if (!inited) { + windowHandle = FindWindowA ("nuFoundation.Window", nullptr); + InitializePoll (windowHandle); + if (autoIme) { + currentLayout = GetKeyboardLayout (0); + auto engLayout = LoadKeyboardLayout (TEXT ("00000409"), KLF_ACTIVATE); + ActivateKeyboardLayout (engLayout, KLF_SETFORPROCESS); + } + + patches::Plugins::Init (); + inited = true; + } + +#ifndef ASYNC_UPDATE + UpdatePoll (windowHandle); +#endif + std::vector buffer = {}; + if (IsButtonTapped (COIN_ADD)) coin_count++; + if (IsButtonTapped (SERVICE) && !testEnabled) service_count++; + if (IsButtonTapped (TEST)) testEnabled = !testEnabled; + if (IsButtonTapped (EXIT)) { exited += 1; testEnabled = 1; patches::Plugins::Exit (); } + if (GameVersion::CHN00 == gameVersion) { + if (IsButtonTapped (CARD_INSERT_1)) patches::Scanner::Qr::CommitLogin (accessCode1); + if (IsButtonTapped (CARD_INSERT_2)) patches::Scanner::Qr::CommitLogin (accessCode2); + } else { + if (IsButtonTapped (CARD_INSERT_1)) patches::Scanner::Card::Commit (accessCode1, chipId1); + if (IsButtonTapped (CARD_INSERT_2)) patches::Scanner::Card::Commit (accessCode2, chipId2); + } + if (IsButtonTapped (QR_DATA_READ)) patches::Scanner::Qr::Commit (patches::Scanner::Qr::ReadQRData (buffer)); + if (IsButtonTapped (QR_IMAGE_READ)) patches::Scanner::Qr::Commit (patches::Scanner::Qr::ReadQRImage (buffer)); + + patches::Plugins::Update (); + patches::Scanner::Update (); +#ifdef ASYNC_UPDATE + } +#endif +} + void Init () { SetKeyboardButtons (); @@ -369,48 +425,26 @@ Init () { INSTALL_HOOK_DIRECT (bnusio_ResetCoin, bnusio_ResetCoin_Original); LogMessage (LogLevel::WARN, "USIO emulation disabled"); } +#ifdef ASYNC_UPDATE + else { + updateThread = std::thread (bnusio::UpdateLoop); + updateThread.detach (); + } +#endif } +#ifdef ASYNC_UPDATE void Update () { - if (exited && ++exited >= 50) ExitProcess (0); - if (!inited) { - windowHandle = FindWindowA ("nuFoundation.Window", nullptr); - InitializePoll (windowHandle); - if (autoIme) { - currentLayout = GetKeyboardLayout (0); - auto engLayout = LoadKeyboardLayout (TEXT ("00000409"), KLF_ACTIVATE); - ActivateKeyboardLayout (engLayout, KLF_SETFORPROCESS); - } - - patches::Plugins::Init (); - inited = true; - } - - UpdatePoll (windowHandle); - std::vector buffer = {}; - if (IsButtonTapped (COIN_ADD) && !testEnabled) coin_count++; - if (IsButtonTapped (SERVICE) && !testEnabled) service_count++; - if (IsButtonTapped (TEST)) testEnabled = !testEnabled; - if (IsButtonTapped (EXIT)) { exited += 1; testEnabled = 1; } - if (GameVersion::CHN00 == gameVersion) { - if (IsButtonTapped (CARD_INSERT_1)) patches::Scanner::Qr::CommitLogin (accessCode1); - if (IsButtonTapped (CARD_INSERT_2)) patches::Scanner::Qr::CommitLogin (accessCode2); - } else { - if (IsButtonTapped (CARD_INSERT_1)) patches::Scanner::Card::Commit (accessCode1, chipId1); - if (IsButtonTapped (CARD_INSERT_2)) patches::Scanner::Card::Commit (accessCode2, chipId2); - } - if (IsButtonTapped (QR_DATA_READ)) patches::Scanner::Qr::Commit (patches::Scanner::Qr::ReadQRData (buffer)); - if (IsButtonTapped (QR_IMAGE_READ)) patches::Scanner::Qr::Commit (patches::Scanner::Qr::ReadQRImage (buffer)); - - patches::Plugins::Update (); - patches::Scanner::Update (); + if (inited) UpdatePoll (windowHandle); + syncCV.notify_all (); } +#endif void Close () { if (autoIme) ActivateKeyboardLayout (currentLayout, KLF_SETFORPROCESS); - patches::Plugins::Exit (); + // patches::Plugins::Exit (); CleanupLogger (); } } // namespace bnusio diff --git a/src/bnusio.h b/src/bnusio.h index 2a9aa53..c964101 100644 --- a/src/bnusio.h +++ b/src/bnusio.h @@ -1,4 +1,5 @@ #pragma once +// #define ASYNC_UPDATE namespace bnusio { void Init (); void Update (); diff --git a/src/dllmain.cpp b/src/dllmain.cpp index 40fa66f..1642b67 100644 --- a/src/dllmain.cpp +++ b/src/dllmain.cpp @@ -149,6 +149,11 @@ DllMain (HMODULE module, const DWORD reason, LPVOID reserved) { InitializeLogger (GetLogLevel (logLevelStr), logToFile); LogMessage (LogLevel::INFO, "Loading config..."); + #ifdef ASYNC_IO + LogMessage (LogLevel::WARN, "Using Async IO (experimental)!"); + InitializeKeyboard (); + #endif + std::string version = "auto"; const std::filesystem::path configPath = std::filesystem::current_path () / "config.toml"; const std::unique_ptr config_ptr (openConfig (configPath), toml_free); @@ -223,7 +228,7 @@ DllMain (HMODULE module, const DWORD reason, LPVOID reserved) { GetPrivateProfileStringA ("card", "accessCode2", accessCode2, accessCode2, 21, ".\\card.ini"); GetPrivateProfileStringA ("card", "chipId2", chipId2, chipId2, 33, ".\\card.ini"); - LogMessage (LogLevel::WARN, "Loading patches, please wait..."); + LogMessage (LogLevel::INFO, "==== Loading patches, please wait..."); if (cursor) INSTALL_HOOK (ShowMouse); INSTALL_HOOK (ExitWindows); @@ -260,6 +265,8 @@ DllMain (HMODULE module, const DWORD reason, LPVOID reserved) { patches::AmAuth::Init (); patches::LayeredFs::Init (); patches::TestMode::Init (); + + LogMessage (LogLevel::INFO, "==== Finished Loading patches!"); } return true; } diff --git a/src/patches/layeredfs.cpp b/src/patches/layeredfs.cpp index 0dbd3ab..434dbbe 100644 --- a/src/patches/layeredfs.cpp +++ b/src/patches/layeredfs.cpp @@ -253,6 +253,7 @@ LayeredFsHandler (const std::string &originalFileName, const std::string ¤ HOOK (HANDLE, CreateFileAHook, PROC_ADDRESS ("kernel32.dll", "CreateFileA"), LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) { + bool changed = false; const auto originalFileName = std::string (lpFileName); std::string currentFileName = originalFileName; LogMessage (LogLevel::HOOKS, ("CreateFileA: " + originalFileName).c_str ()); @@ -260,23 +261,34 @@ HOOK (HANDLE, CreateFileAHook, PROC_ADDRESS ("kernel32.dll", "CreateFileA"), LPC if (!beforeHandlers.empty ()) { for (const auto handler : beforeHandlers) { std::string result = handler->handlerMethod (originalFileName, currentFileName); - if (result != "") currentFileName = result; + if (result != "") { + currentFileName = result; + changed = true; + } } } if (useLayeredFs) { const std::string result = LayeredFsHandler (originalFileName, currentFileName); - if (result != "") currentFileName = result; + if (result != "") { + currentFileName = result; + changed = true; + } } if (!afterHandlers.empty ()) { for (const auto handler : afterHandlers) { std::string result = handler->handlerMethod (originalFileName, currentFileName); - if (result != "") currentFileName = result; + if (result != "") { + currentFileName = result; + changed = true; + } } } - return originalCreateFileAHook (currentFileName.c_str (), dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, + LPCSTR pFinalFileName = changed ? currentFileName.c_str () : lpFileName; + if (changed) LogMessage (LogLevel::DEBUG, "Final Redirect: {}", currentFileName); + return originalCreateFileAHook (pFinalFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); } diff --git a/src/patches/versions/JPN39.cpp b/src/patches/versions/JPN39.cpp index 7489607..468beb3 100644 --- a/src/patches/versions/JPN39.cpp +++ b/src/patches/versions/JPN39.cpp @@ -394,48 +394,48 @@ MID_HOOK (AttractDemo, ASLR (0x14045A720), SafetyHookContext &ctx) { if (TestMode::ReadTestModeValue (L"AttractDemoItem") == 1) ctx.r14 = 0; } -// HOOK (u64, EnsoGameManagerInitialize, ASLR (0x1400E2520), u64 a1, u64 a2, u64 a3) { -// LogMessage (LogLevel::DEBUG, "Begin EnsoGameManagerInitialize"); -// u64 result = originalEnsoGameManagerInitialize (a1, a2, a3); -// LogMessage (LogLevel::DEBUG, "End EnsoGameManagerInitialize result={}", result); -// return result; -// } +HOOK (u64, EnsoGameManagerInitialize, ASLR (0x1400E2520), u64 a1, u64 a2, u64 a3) { + LogMessage (LogLevel::DEBUG, "Begin EnsoGameManagerInitialize"); + u64 result = originalEnsoGameManagerInitialize (a1, a2, a3); + LogMessage (LogLevel::DEBUG, "End EnsoGameManagerInitialize result={}", result); + return result; +} -// HOOK (u64, EnsoGameManagerLoading, ASLR (0x1400E2750), u64 a1, u64 a2, u64 a3) { -// LogMessage (LogLevel::DEBUG, "Begin EnsoGameManagerLoading"); -// u64 result = originalEnsoGameManagerLoading (a1, a2, a3); -// LogMessage (LogLevel::DEBUG, "End EnsoGameManagerLoading result={}", result); -// return result; -// } +HOOK (u64, EnsoGameManagerLoading, ASLR (0x1400E2750), u64 a1, u64 a2, u64 a3) { + LogMessage (LogLevel::DEBUG, "Begin EnsoGameManagerLoading"); + u64 result = originalEnsoGameManagerLoading (a1, a2, a3); + LogMessage (LogLevel::DEBUG, "End EnsoGameManagerLoading result={}", result); + return result; +} -// HOOK (bool, EnsoGameManagerPreparing, ASLR (0x1400E2990), u64 a1) { -// LogMessage (LogLevel::DEBUG, "Begin EnsoGameManagerPreparing"); -// bool result = originalEnsoGameManagerPreparing (a1); // crashes here -// LogMessage (LogLevel::DEBUG, "End EnsoGameManagerPreparing result={}", result); -// return result; -// } +HOOK (bool, EnsoGameManagerPreparing, ASLR (0x1400E2990), u64 a1, u64 a2, u64 a3) { + LogMessage (LogLevel::DEBUG, "Begin EnsoGameManagerPreparing"); + bool result = originalEnsoGameManagerPreparing (a1, a2, a3); // crashes here + LogMessage (LogLevel::DEBUG, "End EnsoGameManagerPreparing result={}", result); + return result; +} -// HOOK (u64, EnsoGraphicManagerPreparing, ASLR (0x1400F0AB0), u64 a1, u64 a2, u64 a3) { -// LogMessage (LogLevel::DEBUG, "Begin EnsoGraphicManagerPreparing"); -// u64 result = originalEnsoGraphicManagerPreparing (a1, a2, a3); -// LogMessage (LogLevel::DEBUG, "End EnsoGraphicManagerPreparing result={}", result); -// return result; -// } +HOOK (u64, EnsoGraphicManagerPreparing, ASLR (0x1400F0AB0), u64 a1, u64 a2, u64 a3) { + LogMessage (LogLevel::DEBUG, "Begin EnsoGraphicManagerPreparing"); + u64 result = originalEnsoGraphicManagerPreparing (a1, a2, a3); + LogMessage (LogLevel::DEBUG, "End EnsoGraphicManagerPreparing result={}", result); + return result; +} -// HOOK (u64, EnsoGameManagerStart, ASLR (0x1400E2A10), u64 a1, u64 a2, u64 a3) { -// LogMessage (LogLevel::DEBUG, "Begin EnsoGameManagerStart"); -// u64 result = originalEnsoGameManagerStart (a1, a2, a3); -// LogMessage (LogLevel::DEBUG, "End EnsoGameManagerStart result={}", result); -// return result; -// } +HOOK (u64, EnsoGameManagerStart, ASLR (0x1400E2A10), u64 a1, u64 a2, u64 a3) { + LogMessage (LogLevel::DEBUG, "Begin EnsoGameManagerStart"); + u64 result = originalEnsoGameManagerStart (a1, a2, a3); + LogMessage (LogLevel::DEBUG, "End EnsoGameManagerStart result={}", result); + return result; +} -// HOOK (u64, EnsoGameManagerChechEnsoEnd, ASLR (0x1400E2A10), u64 a1, u64 a2, u64 a3) { -// LogMessage (LogLevel::DEBUG, "Begin EnsoGameManagerChechEnsoEnd"); -// u64 result = originalEnsoGameManagerChechEnsoEnd (a1, a2, a3); -// LogMessage (LogLevel::DEBUG, "End EnsoGameManagerChechEnsoEnd result={}", result); -// return result; -// } +HOOK (u64, EnsoGameManagerChechEnsoEnd, ASLR (0x1400E2A10), u64 a1, u64 a2, u64 a3) { + LogMessage (LogLevel::DEBUG, "Begin EnsoGameManagerChechEnsoEnd"); + u64 result = originalEnsoGameManagerChechEnsoEnd (a1, a2, a3); + LogMessage (LogLevel::DEBUG, "End EnsoGameManagerChechEnsoEnd result={}", result); + return result; +} constexpr i32 datatableBufferSize = 1024 * 1024 * 12; safetyhook::Allocation datatableBuffer1; @@ -500,12 +500,12 @@ Init () { // Hook to get AppAccessor and ComponentAccessor INSTALL_HOOK (DeviceCheck); INSTALL_HOOK (luaL_newstate); - // INSTALL_HOOK (EnsoGameManagerInitialize); - // INSTALL_HOOK (EnsoGameManagerLoading); - // INSTALL_HOOK (EnsoGameManagerPreparing); - // INSTALL_HOOK (EnsoGraphicManagerPreparing); - // INSTALL_HOOK (EnsoGameManagerStart); - // INSTALL_HOOK (EnsoGameManagerChechEnsoEnd); + INSTALL_HOOK (EnsoGameManagerInitialize); + INSTALL_HOOK (EnsoGameManagerLoading); + INSTALL_HOOK (EnsoGameManagerPreparing); + INSTALL_HOOK (EnsoGraphicManagerPreparing); + INSTALL_HOOK (EnsoGameManagerStart); + INSTALL_HOOK (EnsoGameManagerChechEnsoEnd); // Apply common config patch WRITE_MEMORY (ASLR (0x140494533), i32, xRes); diff --git a/src/poll.cpp b/src/poll.cpp index 64cbfb5..ae6887e 100644 --- a/src/poll.cpp +++ b/src/poll.cpp @@ -1,311 +1,9 @@ #include "poll.h" +#ifndef ASYNC_IO +#include "polldef.h" extern bool jpLayout; -struct KeyCodePair { - const char *string; - u8 keycode; -}; -size_t ConfigKeyboardButtonsCount = 0; -KeyCodePair *ConfigKeyboardButtons = nullptr; -KeyCodePair ConfigKeyboardButtons_US[] = { - // Reference:https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes - // Wayback Machine:https://web.archive.org/web/20231223135232/https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes - // Row 1 - {"ESCAPE", VK_ESCAPE}, - {"F1", VK_F1}, - {"F2", VK_F2}, - {"F3", VK_F3}, - {"F4", VK_F4}, - {"F5", VK_F5}, - {"F6", VK_F6}, - {"F7", VK_F7}, - {"F8", VK_F8}, - {"F9", VK_F9}, - {"F10", VK_F10}, - {"F11", VK_F11}, - {"F12", VK_F12}, - - // Row 2 - {"`", VK_OEM_3}, - {"1", '1'}, - {"2", '2'}, - {"3", '3'}, - {"4", '4'}, - {"5", '5'}, - {"6", '6'}, - {"7", '7'}, - {"8", '8'}, - {"9", '9'}, - {"0", '0'}, - {"-", VK_OEM_MINUS}, - {"=", VK_OEM_PLUS}, - {"BACKSPACE", VK_BACK}, - - // Row 3 - {"TAB", VK_TAB}, - {"Q", 'Q'}, - {"W", 'W'}, - {"E", 'E'}, - {"R", 'R'}, - {"T", 'T'}, - {"Y", 'Y'}, - {"U", 'U'}, - {"I", 'I'}, - {"O", 'O'}, - {"P", 'P'}, - {"[", VK_OEM_4}, - {"]", VK_OEM_6}, - {"BACKSLASH", VK_OEM_5}, - - // Row 4 - {"CAPS_LOCK", VK_CAPITAL}, - {"A", 'A'}, - {"S", 'S'}, - {"D", 'D'}, - {"F", 'F'}, - {"G", 'G'}, - {"H", 'H'}, - {"J", 'J'}, - {"K", 'K'}, - {"L", 'L'}, - {";", VK_OEM_1}, - {"'", VK_OEM_7}, - {"ENTER", VK_RETURN}, - - // Row 5 - {"SHIFT", VK_SHIFT}, - {"Z", 'Z'}, - {"X", 'X'}, - {"C", 'C'}, - {"V", 'V'}, - {"B", 'B'}, - {"N", 'N'}, - {"M", 'M'}, - {",", VK_OEM_COMMA}, - {".", VK_OEM_PERIOD}, - {"SLASH", VK_OEM_2}, - - // Row 6 - {"CONTROL", VK_CONTROL}, - {"L_WIN", VK_LWIN}, - {"ALT", VK_MENU}, - {"SPACE", VK_SPACE}, - {"R_WIN", VK_RWIN}, - {"MENU", VK_APPS}, - - // Other Keys - // PrtSc is more important when making snapshots, therefore comment it as reserved - //{"PRINT_SCREEN", VK_SNAPSHOT}, - {"SCROLL_LOCK", VK_SCROLL}, - {"PAUSE", VK_PAUSE}, - {"INSERT", VK_INSERT}, - {"DELETE", VK_DELETE}, - {"HOME", VK_HOME}, - {"END", VK_END}, - {"PAGE_UP", VK_PRIOR}, - {"PAGE_DOWN", VK_NEXT}, - - // Arrow Keys - {"UPARROW", VK_UP}, - {"LEFTARROW", VK_LEFT}, - {"DOWNARROW", VK_DOWN}, - {"RIGHTARROW", VK_RIGHT}, - - // NUMPAD Keys - {"NUM_LOCK", VK_NUMLOCK}, - {"DIVIDE", VK_DIVIDE}, - {"MULTIPLY", VK_MULTIPLY}, - {"SUBTRACT", VK_SUBTRACT}, - {"NUM7", VK_NUMPAD7}, - {"NUM8", VK_NUMPAD8}, - {"NUM9", VK_NUMPAD9}, - {"ADD", VK_ADD}, - {"NUM4", VK_NUMPAD4}, - {"NUM5", VK_NUMPAD5}, - {"NUM6", VK_NUMPAD6}, - {"NUM1", VK_NUMPAD1}, - {"NUM2", VK_NUMPAD2}, - {"NUM3", VK_NUMPAD3}, - {"NUM0", VK_NUMPAD0}, - {"DECIMAL", VK_DECIMAL}, -}; -KeyCodePair ConfigKeyboardButtons_JP[] = { - // Reference:https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes - // Wayback Machine:https://web.archive.org/web/20231223135232/https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes - // Row 1 - {"ESCAPE", VK_ESCAPE}, - {"F1", VK_F1}, - {"F2", VK_F2}, - {"F3", VK_F3}, - {"F4", VK_F4}, - {"F5", VK_F5}, - {"F6", VK_F6}, - {"F7", VK_F7}, - {"F8", VK_F8}, - {"F9", VK_F9}, - {"F10", VK_F10}, - {"F11", VK_F11}, - {"F12", VK_F12}, - - // Row 2 - {"1", '1'}, - {"2", '2'}, - {"3", '3'}, - {"4", '4'}, - {"5", '5'}, - {"6", '6'}, - {"7", '7'}, - {"8", '8'}, - {"9", '9'}, - {"0", '0'}, - {"-", VK_OEM_MINUS}, - {"^", VK_OEM_7}, - {"YEN", VK_OEM_5}, - {"BACKSPACE", VK_BACK}, - - // Row 3 - {"TAB", VK_TAB}, - {"Q", 'Q'}, - {"W", 'W'}, - {"E", 'E'}, - {"R", 'R'}, - {"T", 'T'}, - {"Y", 'Y'}, - {"U", 'U'}, - {"I", 'I'}, - {"O", 'O'}, - {"P", 'P'}, - {"@", VK_OEM_3}, - {"[", VK_OEM_4}, - - // Row 4 - {"CAPS_LOCK", VK_CAPITAL}, - {"A", 'A'}, - {"S", 'S'}, - {"D", 'D'}, - {"F", 'F'}, - {"G", 'G'}, - {"H", 'H'}, - {"J", 'J'}, - {"K", 'K'}, - {"L", 'L'}, - {";", VK_OEM_PLUS}, - {":", VK_OEM_1}, - {"]", VK_OEM_6}, - {"ENTER", VK_RETURN}, - - // Row 5 - {"SHIFT", VK_SHIFT}, - {"Z", 'Z'}, - {"X", 'X'}, - {"C", 'C'}, - {"V", 'V'}, - {"B", 'B'}, - {"N", 'N'}, - {"M", 'M'}, - {",", VK_OEM_COMMA}, - {".", VK_OEM_PERIOD}, - {"SLASH", VK_OEM_2}, - {"BACKSLASH", VK_OEM_102}, - - // Row 6 - {"CONTROL", VK_CONTROL}, - {"L_WIN", VK_LWIN}, - {"ALT", VK_MENU}, - {"SPACE", VK_SPACE}, - {"R_WIN", VK_RWIN}, - {"MENU", VK_APPS}, - - // Other Keys - // PrtSc is more important when making snapshots, therefore comment it as reserved - //{"PRINT_SCREEN", VK_SNAPSHOT}, - {"SCROLL_LOCK", VK_SCROLL}, - {"PAUSE", VK_PAUSE}, - {"INSERT", VK_INSERT}, - {"DELETE", VK_DELETE}, - {"HOME", VK_HOME}, - {"END", VK_END}, - {"PAGE_UP", VK_PRIOR}, - {"PAGE_DOWN", VK_NEXT}, - - // Arrow Keys - {"UPARROW", VK_UP}, - {"LEFTARROW", VK_LEFT}, - {"DOWNARROW", VK_DOWN}, - {"RIGHTARROW", VK_RIGHT}, - - // NUMPAD Keys - {"NUM_LOCK", VK_NUMLOCK}, - {"DIVIDE", VK_DIVIDE}, - {"MULTIPLY", VK_MULTIPLY}, - {"SUBTRACT", VK_SUBTRACT}, - {"NUM7", VK_NUMPAD7}, - {"NUM8", VK_NUMPAD8}, - {"NUM9", VK_NUMPAD9}, - {"ADD", VK_ADD}, - {"NUM4", VK_NUMPAD4}, - {"NUM5", VK_NUMPAD5}, - {"NUM6", VK_NUMPAD6}, - {"NUM1", VK_NUMPAD1}, - {"NUM2", VK_NUMPAD2}, - {"NUM3", VK_NUMPAD3}, - {"NUM0", VK_NUMPAD0}, - {"DECIMAL", VK_DECIMAL}, -}; - -struct { - const char *string; - SDL_GameControllerButton button; -} ConfigControllerButtons[] = { - {"SDL_A", SDL_CONTROLLER_BUTTON_A}, - {"SDL_B", SDL_CONTROLLER_BUTTON_B}, - {"SDL_X", SDL_CONTROLLER_BUTTON_X}, - {"SDL_Y", SDL_CONTROLLER_BUTTON_Y}, - {"SDL_BACK", SDL_CONTROLLER_BUTTON_BACK}, - {"SDL_GUIDE", SDL_CONTROLLER_BUTTON_GUIDE}, - {"SDL_START", SDL_CONTROLLER_BUTTON_START}, - {"SDL_LSTICK_PRESS", SDL_CONTROLLER_BUTTON_LEFTSTICK}, - {"SDL_RSTICK_PRESS", SDL_CONTROLLER_BUTTON_RIGHTSTICK}, - {"SDL_LSHOULDER", SDL_CONTROLLER_BUTTON_LEFTSHOULDER}, - {"SDL_RSHOULDER", SDL_CONTROLLER_BUTTON_RIGHTSHOULDER}, - {"SDL_DPAD_UP", SDL_CONTROLLER_BUTTON_DPAD_UP}, - {"SDL_DPAD_DOWN", SDL_CONTROLLER_BUTTON_DPAD_DOWN}, - {"SDL_DPAD_LEFT", SDL_CONTROLLER_BUTTON_DPAD_LEFT}, - {"SDL_DPAD_RIGHT", SDL_CONTROLLER_BUTTON_DPAD_RIGHT}, - {"SDL_MISC", SDL_CONTROLLER_BUTTON_MISC1}, - {"SDL_PADDLE1", SDL_CONTROLLER_BUTTON_PADDLE1}, - {"SDL_PADDLE2", SDL_CONTROLLER_BUTTON_PADDLE2}, - {"SDL_PADDLE3", SDL_CONTROLLER_BUTTON_PADDLE3}, - {"SDL_PADDLE4", SDL_CONTROLLER_BUTTON_PADDLE4}, - {"SDL_TOUCHPAD", SDL_CONTROLLER_BUTTON_TOUCHPAD}, -}; - -struct { - const char *string; - SDLAxis axis; -} ConfigControllerAXIS[] = { - {"SDL_LSTICK_LEFT", SDL_AXIS_LEFT_LEFT}, {"SDL_LSTICK_UP", SDL_AXIS_LEFT_UP}, {"SDL_LSTICK_DOWN", SDL_AXIS_LEFT_DOWN}, - {"SDL_LSTICK_RIGHT", SDL_AXIS_LEFT_RIGHT}, {"SDL_RSTICK_LEFT", SDL_AXIS_RIGHT_LEFT}, {"SDL_RSTICK_UP", SDL_AXIS_RIGHT_UP}, - {"SDL_RSTICK_DOWN", SDL_AXIS_RIGHT_DOWN}, {"SDL_RSTICK_RIGHT", SDL_AXIS_RIGHT_RIGHT}, {"SDL_LTRIGGER", SDL_AXIS_LTRIGGER_DOWN}, - {"SDL_RTRIGGER", SDL_AXIS_RTRIGGER_DOWN}, -}; - -struct { - const char *string; - Scroll scroll; -} ConfigMouseScroll[] = { - {"SCROLL_UP", MOUSE_SCROLL_UP}, - {"SCROLL_DOWN", MOUSE_SCROLL_DOWN}, -}; - -struct MouseState { - POINT Position; - POINT RelativePosition; - bool ScrolledUp; - bool ScrolledDown; -} currentMouseState, lastMouseState; - bool currentKeyboardState[0xFF]; bool lastKeyboardState[0xFF]; @@ -784,3 +482,4 @@ float IsButtonDown (const Keybindings &bindings) { return GetInternalButtonState (bindings).Down; } +#endif \ No newline at end of file diff --git a/src/poll.h b/src/poll.h index 8487aaf..e16d1f3 100644 --- a/src/poll.h +++ b/src/poll.h @@ -1,6 +1,13 @@ #pragma once #include #include "helpers.h" +#include "bnusio.h" + +#ifdef ASYNC_UPDATE +#define ASYNC_IO +#endif + +// #define ASYNC_IO enum SDLAxis { SDL_AXIS_NULL, @@ -62,13 +69,25 @@ void UpdatePoll (HWND windowHandle); void DisposePoll (); void SetKeyboardButtons (); ConfigValue StringToConfigEnum (const char *value); -void SetConfigValue (const toml_table_t *table, const char *key, Keybindings *key_bind); +void SetConfigValue (const toml_table_t *table, const char *key, Keybindings *keybind); InternalButtonState GetInternalButtonState (const Keybindings &bindings); void SetRumble (int left, int right, int length); -bool KeyboardIsDown (u8 keycode); -bool KeyboardIsUp (u8 keycode); -bool KeyboardIsTapped (u8 keycode); +bool KeyboardIsDown (const uint8_t keycode); +bool KeyboardIsTapped (const uint8_t keycode); +bool GetMouseScrollUp (); +bool GetMouseScrollDown (); +bool GetMouseScrollIsDown (const Scroll scroll); +bool GetMouseScrollIsTapped (const Scroll scroll); +bool ControllerButtonIsDown (const SDL_GameControllerButton button); +bool ControllerButtonIsTapped (const SDL_GameControllerButton button); +float ControllerAxisIsDown (const SDLAxis axis); +bool ControllerAxisIsTapped (const SDLAxis axis); +bool IsButtonTapped (const Keybindings &bindings); +float IsButtonDown (const Keybindings &bindings); + +#ifndef ASYNC_IO +bool KeyboardIsUp (const u8 keycode); bool KeyboardIsReleased (u8 keycode); bool KeyboardWasDown (u8 keycode); bool KeyboardWasUp (u8 keycode); @@ -76,26 +95,19 @@ POINT GetMousePosition (); POINT GetLastMousePosition (); POINT GetMouseRelativePosition (); POINT GetLastMouseRelativePosition (); -void SetMousePosition (POINT newPosition); -bool GetMouseScrollUp (); -bool GetMouseScrollDown (); +void SetMousePosition (const POINT newPosition); bool GetWasMouseScrollUp (); bool GetWasMouseScrollDown (); -bool GetMouseScrollIsReleased (Scroll scroll); -bool GetMouseScrollIsDown (Scroll scroll); -bool GetMouseScrollIsTapped (Scroll scroll); -bool ControllerButtonIsDown (SDL_GameControllerButton button); -bool ControllerButtonIsUp (SDL_GameControllerButton button); -bool ControllerButtonWasDown (SDL_GameControllerButton button); -bool ControllerButtonWasUp (SDL_GameControllerButton button); -bool ControllerButtonIsTapped (SDL_GameControllerButton button); -bool ControllerButtonIsReleased (SDL_GameControllerButton button); -float ControllerAxisIsDown (SDLAxis axis); -bool ControllerAxisIsUp (SDLAxis axis); -float ControllerAxisWasDown (SDLAxis axis); -bool ControllerAxisWasUp (SDLAxis axis); -bool ControllerAxisIsTapped (SDLAxis axis); -bool ControllerAxisIsReleased (SDLAxis axis); -bool IsButtonTapped (const Keybindings &bindings); +bool GetMouseScrollIsReleased (const Scroll scroll); +bool ControllerButtonWasDown (const SDL_GameControllerButton button); +bool ControllerButtonWasUp (const SDL_GameControllerButton button); +bool ControllerButtonIsReleased (const SDL_GameControllerButton button); +bool ControllerAxisIsUp (const SDLAxis axis); +float ControllerAxisWasDown (const SDLAxis axis); +bool ControllerAxisWasUp (const SDLAxis axis); +bool ControllerAxisIsReleased (const SDLAxis axis); bool IsButtonReleased (const Keybindings &bindings); -float IsButtonDown (const Keybindings &bindings); +#else +void InitializeKeyboard (); +void DisposeKeyboard (); +#endif \ No newline at end of file diff --git a/src/pollasync.cpp b/src/pollasync.cpp new file mode 100644 index 0000000..51608b8 --- /dev/null +++ b/src/pollasync.cpp @@ -0,0 +1,429 @@ +#include "poll.h" + +#ifdef ASYNC_IO +#include "polldef.h" +extern bool jpLayout; +extern int exited; + +bool wndForeground = false; + +bool currentKeyboardState[0xFF] = { false }; +int keyboardCount[0xFF] = { 0 }; +int keyboardDiff[0xFF] = { 0 }; +bool currentControllerButtonsState[SDL_CONTROLLER_BUTTON_MAX] = { false }; +int controllerCount[SDL_CONTROLLER_BUTTON_MAX] = { 0 }; +int controllerDiff[SDL_CONTROLLER_BUTTON_MAX] = { 0 }; +SDLAxisState currentControllerAxisState; + +SDL_Window *window; +SDL_GameController *controllers[255]; + +std::thread updatePollThread; + +void +SetKeyboardButtons () { + ConfigKeyboardButtonsCount = jpLayout ? std::size (ConfigKeyboardButtons_JP) : std::size (ConfigKeyboardButtons_US); + ConfigKeyboardButtons = static_cast (malloc (ConfigKeyboardButtonsCount * sizeof (KeyCodePair))); + memcpy (ConfigKeyboardButtons, jpLayout ? ConfigKeyboardButtons_JP : ConfigKeyboardButtons_US, ConfigKeyboardButtonsCount * sizeof (KeyCodePair)); +} + +void +SetConfigValue (const toml_table_t *table, const char *key, Keybindings *key_bind) { + const toml_array_t *array = toml_array_in (table, key); + if (!array) { + LogMessage (LogLevel::WARN, std::string (key) + ": Cannot find array"); + return; + } + + memset (key_bind, 0, sizeof (*key_bind)); + for (size_t i = 0; i < std::size (key_bind->buttons); i++) + key_bind->buttons[i] = SDL_CONTROLLER_BUTTON_INVALID; + + for (int idx = 0;; idx++) { + const auto [ok, u] = toml_string_at (array, idx); + if (!ok) break; + const ConfigValue value = StringToConfigEnum (u.s); + free (u.s); + + switch (value.type) { + case keycode: { + for (int i = 0; i < std::size (key_bind->keycodes); i++) { + if (key_bind->keycodes[i] == 0) { + key_bind->keycodes[i] = value.keycode; + break; + } + } + break; + } + case button: { + for (int i = 0; i < std::size (key_bind->buttons); i++) { + if (key_bind->buttons[i] == SDL_CONTROLLER_BUTTON_INVALID) { + key_bind->buttons[i] = value.button; + break; + } + } + break; + } + case axis: { + for (int i = 0; i < std::size (key_bind->axis); i++) { + if (key_bind->axis[i] == 0) { + key_bind->axis[i] = value.axis; + break; + } + } + } + case scroll: { + for (int i = 0; i < std::size (key_bind->scroll); i++) { + if (key_bind->scroll[i] == 0) { + key_bind->scroll[i] = value.scroll; + break; + } + } + break; + } + default: break; + } + } +} + +// 钩子句柄 +HHOOK keyboardHook; + +// 钩子回调函数 +LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) { + if (nCode == HC_ACTION) { + KBDLLHOOKSTRUCT* pKeyboard = reinterpret_cast(lParam); + DWORD keyCode = pKeyboard->vkCode; + switch (wParam) { + case WM_KEYDOWN: if (wndForeground) { + if (!currentKeyboardState[keyCode]) keyboardCount[keyCode] ++; + currentKeyboardState[keyCode] = true; + } break; + // keyup will accepted even if you're not focus in this window + case WM_KEYUP: currentKeyboardState[keyCode] = false; break; + } + } + return CallNextHookEx(keyboardHook, nCode, wParam, lParam); +} + +void +InitializeKeyboard () { + keyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardProc, nullptr, 0); + if (keyboardHook == nullptr) LogMessage (LogLevel::ERROR, "Failed to install keyboard hook!\n"); + atexit (DisposeKeyboard); +} + +void +DisposeKeyboard () { + if (keyboardHook) UnhookWindowsHookEx(keyboardHook); +} + +void +UpdateLoop () { + LogMessage (LogLevel::DEBUG, "Enter Controller UpdateLoop"); + SDL_Event event; + SDL_GameController *controller; + while (!exited) { + while (SDL_WaitEvent (&event) != 0) { + switch (event.type) { + case SDL_CONTROLLERDEVICEADDED: + if (!SDL_IsGameController (event.cdevice.which)) break; + + controller = SDL_GameControllerOpen (event.cdevice.which); + if (!controller) { + LogMessage (LogLevel::ERROR, std::string ("Could not open gamecontroller ") + SDL_GameControllerNameForIndex (event.cdevice.which) + + ": " + SDL_GetError ()); + continue; + } + LogMessage (LogLevel::DEBUG, "Controller connected!"); + controllers[event.cdevice.which] = controller; + break; + case SDL_CONTROLLERDEVICEREMOVED: + LogMessage (LogLevel::DEBUG, "Controller removed!"); + if (!SDL_IsGameController (event.cdevice.which)) break; + SDL_GameControllerClose (controllers[event.cdevice.which]); + break; + case SDL_MOUSEWHEEL: + if (wndForeground) { + if (event.wheel.y > 0) currentMouseState.ScrolledUp = true; + else if (event.wheel.y < 0) currentMouseState.ScrolledDown = true; + } + break; + case SDL_CONTROLLERBUTTONUP: + // keyup will accepted even if you're not focus in this window + currentControllerButtonsState[event.cbutton.button] = false; break; + case SDL_CONTROLLERBUTTONDOWN: + if (wndForeground) { + if (!currentControllerButtonsState[event.cbutton.button]) controllerCount[event.cbutton.button]++; + currentControllerButtonsState[event.cbutton.button] = true; + } else LogMessage (LogLevel::WARN, "Controller button pressed but window not focused!"); + break; + case SDL_CONTROLLERAXISMOTION: + float sensorValue = event.caxis.value == 0 ? 0 : event.caxis.value / (event.caxis.value > 0 ? 32767.0f : -32768.0f); + if (wndForeground || sensorValue == 0) { + switch (event.caxis.axis) { + case SDL_CONTROLLER_AXIS_LEFTX: currentControllerAxisState.LeftRight = sensorValue; break; + case SDL_CONTROLLER_AXIS_LEFTY: currentControllerAxisState.LeftDown = sensorValue; break; + case SDL_CONTROLLER_AXIS_RIGHTX: currentControllerAxisState.RightRight = sensorValue; break; + case SDL_CONTROLLER_AXIS_RIGHTY: currentControllerAxisState.RightDown = sensorValue; break; + case SDL_CONTROLLER_AXIS_TRIGGERLEFT: currentControllerAxisState.LTriggerDown = sensorValue; break; + case SDL_CONTROLLER_AXIS_TRIGGERRIGHT: currentControllerAxisState.RTriggerDown = sensorValue; break; + } + } + break; + } + } + } +} + +bool +InitializePoll (HWND windowHandle) { + LogMessage (LogLevel::DEBUG, "InitializePoll"); + bool hasRumble = true; + wndForeground = windowHandle == GetForegroundWindow (); + SDL_SetMainReady (); + + SDL_SetHint (SDL_HINT_JOYSTICK_HIDAPI_PS4, "1"); + SDL_SetHint (SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, "1"); + SDL_SetHint (SDL_HINT_JOYSTICK_HIDAPI_PS5, "1"); + SDL_SetHint (SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, "1"); + + if (SDL_Init (SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_GAMECONTROLLER | SDL_INIT_EVENTS | SDL_INIT_VIDEO) != 0) { + if (SDL_Init (SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER | SDL_INIT_EVENTS | SDL_INIT_VIDEO) == 0) { + hasRumble = false; + } else { + LogMessage (LogLevel::ERROR, + std::string ("SDL_Init (SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_GAMECONTROLLER | SDL_INIT_EVENTS | SDL_INIT_VIDEO): ") + + SDL_GetError ()); + return false; + } + } + + auto configPath = std::filesystem::current_path () / "gamecontrollerdb.txt"; + if (SDL_GameControllerAddMappingsFromFile (configPath.string ().c_str ()) == -1) + LogMessage (LogLevel::ERROR, "Cannot read gamecontrollerdb.txt"); + SDL_GameControllerEventState (SDL_ENABLE); + SDL_JoystickEventState (SDL_ENABLE); + + for (int i = 0; i < SDL_NumJoysticks (); i++) { + if (!SDL_IsGameController (i)) continue; + + SDL_GameController *controller = SDL_GameControllerOpen (i); + if (!controller) { + LogMessage (LogLevel::WARN, std::string ("Could not open gamecontroller ") + SDL_GameControllerNameForIndex (i) + ": " + SDL_GetError ()); + continue; + } + + LogMessage (LogLevel::DEBUG, "Init Controller connected!"); + controllers[i] = controller; + } + + window = SDL_CreateWindowFrom (windowHandle); + if (window == NULL) LogMessage (LogLevel::ERROR, std::string ("SDL_CreateWindowFrom (windowHandle): ") + SDL_GetError ()); + + atexit (DisposePoll); + + updatePollThread = std::thread (UpdateLoop); + updatePollThread.detach (); + + return hasRumble; +} + +bool +CheckForegroundWindow (HWND processWindow) { + if (processWindow == nullptr) return false; + if (wndForeground ^ (processWindow == GetForegroundWindow ())) { + wndForeground = !wndForeground; + LogMessage (LogLevel::DEBUG, "window focus={}", wndForeground); + } + return wndForeground; +} + +void +UpdatePoll (HWND windowHandle) { + if (!CheckForegroundWindow (windowHandle)) return; + + // currentMouseState.ScrolledUp = false; + // currentMouseState.ScrolledDown = false; + for (int i=0; i<255; i++) keyboardCount[i] -= (bool)keyboardDiff[i]; + for (int i=0; i 0) { + if (maxKeyboardCount < keyboardCount[keycode]) { + maxKeyboardCount = keyboardCount[keycode]; + LogMessage (LogLevel::DEBUG, "MAX KEYBOARD COLLECTED {} {}", keycode, maxKeyboardCount); + } + keyboardDiff[keycode] = 1; + return true; + } return false; +} + +bool +GetMouseScrollUp () { + return currentMouseState.ScrolledUp; +} + +bool +GetMouseScrollDown () { + return currentMouseState.ScrolledDown; +} + +bool +GetMouseScrollIsDown (const Scroll scroll) { + return false; + // if (scroll == MOUSE_SCROLL_UP) return GetMouseScrollUp (); + // else return GetMouseScrollDown (); +} + +bool +GetMouseScrollIsTapped (const Scroll scroll) { + return false; + // if (scroll == MOUSE_SCROLL_UP) return GetMouseScrollUp () && !GetWasMouseScrollUp (); + // else return GetMouseScrollDown () && !GetWasMouseScrollDown (); +} + +bool +ControllerButtonIsDown (const SDL_GameControllerButton button) { + return currentControllerButtonsState[button]; +} + +int maxButtonCount = 1; +bool +ControllerButtonIsTapped (const SDL_GameControllerButton button) { + if (controllerCount[button] > 0) { + if (maxButtonCount < controllerCount[button]) { + maxButtonCount = controllerCount[button]; + LogMessage (LogLevel::DEBUG, "MAX BUTTON COLLECTED {} {}", (int)button, maxButtonCount); + } + controllerDiff[button] = 1; + return true; + } return false; +} + +float +ControllerAxisIsDown (const SDLAxis axis) { + switch (axis) { + case SDL_AXIS_LEFT_LEFT: return currentControllerAxisState.LeftLeft; + case SDL_AXIS_LEFT_RIGHT: return currentControllerAxisState.LeftRight; + case SDL_AXIS_LEFT_UP: return currentControllerAxisState.LeftUp; + case SDL_AXIS_LEFT_DOWN: return currentControllerAxisState.LeftDown; + case SDL_AXIS_RIGHT_LEFT: return currentControllerAxisState.RightLeft; + case SDL_AXIS_RIGHT_RIGHT: return currentControllerAxisState.RightRight; + case SDL_AXIS_RIGHT_UP: return currentControllerAxisState.RightUp; + case SDL_AXIS_RIGHT_DOWN: return currentControllerAxisState.RightDown; + case SDL_AXIS_LTRIGGER_DOWN: return currentControllerAxisState.LTriggerDown; + case SDL_AXIS_RTRIGGER_DOWN: return currentControllerAxisState.RTriggerDown; + default: return false; + } +} + +bool +ControllerAxisIsTapped (const SDLAxis axis) { + return ControllerAxisIsDown (axis); +} + +bool +IsButtonTapped (const Keybindings &bindings) { + + for (size_t i = 0; i < ConfigKeyboardButtonsCount; i++) { + if (bindings.keycodes[i] == 0) continue; + if (KeyboardIsTapped (bindings.keycodes[i])) return true; + } + for (size_t i = 0; i < std::size (ConfigControllerButtons); i++) { + if (bindings.buttons[i] == SDL_CONTROLLER_BUTTON_INVALID) continue; + if (ControllerButtonIsTapped (bindings.buttons[i])) return true; + } + for (size_t i = 0; i < std::size (ConfigControllerAXIS); i++) { + if (bindings.axis[i] == 0) continue; + if (float val = ControllerAxisIsTapped (bindings.axis[i]); val > 0) return true; + } + for (size_t i = 0; i < std::size (ConfigMouseScroll); i++) { + if (bindings.scroll[i] == 0) continue; + if (GetMouseScrollIsTapped (bindings.scroll[i])) return true; + } + return false; + // return GetInternalButtonState (bindings).Tapped; +} + +float +IsButtonDown (const Keybindings &bindings) { + for (size_t i = 0; i < ConfigKeyboardButtonsCount; i++) { + if (bindings.keycodes[i] == 0) continue; + if (KeyboardIsDown (bindings.keycodes[i])) return 1.0f; + } + for (size_t i = 0; i < std::size (ConfigControllerButtons); i++) { + if (bindings.buttons[i] == SDL_CONTROLLER_BUTTON_INVALID) continue; + if (ControllerButtonIsDown (bindings.buttons[i])) return 1.0f; + } + for (size_t i = 0; i < std::size (ConfigControllerAXIS); i++) { + if (bindings.axis[i] == 0) continue; + if (float val = ControllerAxisIsDown (bindings.axis[i]); val > 0) return val; + } + for (size_t i = 0; i < std::size (ConfigMouseScroll); i++) { + if (bindings.scroll[i] == 0) continue; + if (GetMouseScrollIsDown (bindings.scroll[i])) return 1.0f; + } + return 0.0f; + // return GetInternalButtonState (bindings).Down; +} +#endif \ No newline at end of file diff --git a/src/polldef.h b/src/polldef.h new file mode 100644 index 0000000..f1bbe4a --- /dev/null +++ b/src/polldef.h @@ -0,0 +1,305 @@ +#include "poll.h" + +struct KeyCodePair { + const char *string; + u8 keycode; +}; +size_t ConfigKeyboardButtonsCount = 0; +KeyCodePair *ConfigKeyboardButtons = nullptr; +KeyCodePair ConfigKeyboardButtons_US[] = { + // Reference:https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes + // Wayback Machine:https://web.archive.org/web/20231223135232/https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes + // Row 1 + {"ESCAPE", VK_ESCAPE}, + {"F1", VK_F1}, + {"F2", VK_F2}, + {"F3", VK_F3}, + {"F4", VK_F4}, + {"F5", VK_F5}, + {"F6", VK_F6}, + {"F7", VK_F7}, + {"F8", VK_F8}, + {"F9", VK_F9}, + {"F10", VK_F10}, + {"F11", VK_F11}, + {"F12", VK_F12}, + + // Row 2 + {"`", VK_OEM_3}, + {"1", '1'}, + {"2", '2'}, + {"3", '3'}, + {"4", '4'}, + {"5", '5'}, + {"6", '6'}, + {"7", '7'}, + {"8", '8'}, + {"9", '9'}, + {"0", '0'}, + {"-", VK_OEM_MINUS}, + {"=", VK_OEM_PLUS}, + {"BACKSPACE", VK_BACK}, + + // Row 3 + {"TAB", VK_TAB}, + {"Q", 'Q'}, + {"W", 'W'}, + {"E", 'E'}, + {"R", 'R'}, + {"T", 'T'}, + {"Y", 'Y'}, + {"U", 'U'}, + {"I", 'I'}, + {"O", 'O'}, + {"P", 'P'}, + {"[", VK_OEM_4}, + {"]", VK_OEM_6}, + {"BACKSLASH", VK_OEM_5}, + + // Row 4 + {"CAPS_LOCK", VK_CAPITAL}, + {"A", 'A'}, + {"S", 'S'}, + {"D", 'D'}, + {"F", 'F'}, + {"G", 'G'}, + {"H", 'H'}, + {"J", 'J'}, + {"K", 'K'}, + {"L", 'L'}, + {";", VK_OEM_1}, + {"'", VK_OEM_7}, + {"ENTER", VK_RETURN}, + + // Row 5 + {"SHIFT", VK_SHIFT}, + {"Z", 'Z'}, + {"X", 'X'}, + {"C", 'C'}, + {"V", 'V'}, + {"B", 'B'}, + {"N", 'N'}, + {"M", 'M'}, + {",", VK_OEM_COMMA}, + {".", VK_OEM_PERIOD}, + {"SLASH", VK_OEM_2}, + + // Row 6 + {"CONTROL", VK_CONTROL}, + {"L_WIN", VK_LWIN}, + {"ALT", VK_MENU}, + {"SPACE", VK_SPACE}, + {"R_WIN", VK_RWIN}, + {"MENU", VK_APPS}, + + // Other Keys + // PrtSc is more important when making snapshots, therefore comment it as reserved + //{"PRINT_SCREEN", VK_SNAPSHOT}, + {"SCROLL_LOCK", VK_SCROLL}, + {"PAUSE", VK_PAUSE}, + {"INSERT", VK_INSERT}, + {"DELETE", VK_DELETE}, + {"HOME", VK_HOME}, + {"END", VK_END}, + {"PAGE_UP", VK_PRIOR}, + {"PAGE_DOWN", VK_NEXT}, + + // Arrow Keys + {"UPARROW", VK_UP}, + {"LEFTARROW", VK_LEFT}, + {"DOWNARROW", VK_DOWN}, + {"RIGHTARROW", VK_RIGHT}, + + // NUMPAD Keys + {"NUM_LOCK", VK_NUMLOCK}, + {"DIVIDE", VK_DIVIDE}, + {"MULTIPLY", VK_MULTIPLY}, + {"SUBTRACT", VK_SUBTRACT}, + {"NUM7", VK_NUMPAD7}, + {"NUM8", VK_NUMPAD8}, + {"NUM9", VK_NUMPAD9}, + {"ADD", VK_ADD}, + {"NUM4", VK_NUMPAD4}, + {"NUM5", VK_NUMPAD5}, + {"NUM6", VK_NUMPAD6}, + {"NUM1", VK_NUMPAD1}, + {"NUM2", VK_NUMPAD2}, + {"NUM3", VK_NUMPAD3}, + {"NUM0", VK_NUMPAD0}, + {"DECIMAL", VK_DECIMAL}, +}; +KeyCodePair ConfigKeyboardButtons_JP[] = { + // Reference:https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes + // Wayback Machine:https://web.archive.org/web/20231223135232/https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes + // Row 1 + {"ESCAPE", VK_ESCAPE}, + {"F1", VK_F1}, + {"F2", VK_F2}, + {"F3", VK_F3}, + {"F4", VK_F4}, + {"F5", VK_F5}, + {"F6", VK_F6}, + {"F7", VK_F7}, + {"F8", VK_F8}, + {"F9", VK_F9}, + {"F10", VK_F10}, + {"F11", VK_F11}, + {"F12", VK_F12}, + + // Row 2 + {"1", '1'}, + {"2", '2'}, + {"3", '3'}, + {"4", '4'}, + {"5", '5'}, + {"6", '6'}, + {"7", '7'}, + {"8", '8'}, + {"9", '9'}, + {"0", '0'}, + {"-", VK_OEM_MINUS}, + {"^", VK_OEM_7}, + {"YEN", VK_OEM_5}, + {"BACKSPACE", VK_BACK}, + + // Row 3 + {"TAB", VK_TAB}, + {"Q", 'Q'}, + {"W", 'W'}, + {"E", 'E'}, + {"R", 'R'}, + {"T", 'T'}, + {"Y", 'Y'}, + {"U", 'U'}, + {"I", 'I'}, + {"O", 'O'}, + {"P", 'P'}, + {"@", VK_OEM_3}, + {"[", VK_OEM_4}, + + // Row 4 + {"CAPS_LOCK", VK_CAPITAL}, + {"A", 'A'}, + {"S", 'S'}, + {"D", 'D'}, + {"F", 'F'}, + {"G", 'G'}, + {"H", 'H'}, + {"J", 'J'}, + {"K", 'K'}, + {"L", 'L'}, + {";", VK_OEM_PLUS}, + {":", VK_OEM_1}, + {"]", VK_OEM_6}, + {"ENTER", VK_RETURN}, + + // Row 5 + {"SHIFT", VK_SHIFT}, + {"Z", 'Z'}, + {"X", 'X'}, + {"C", 'C'}, + {"V", 'V'}, + {"B", 'B'}, + {"N", 'N'}, + {"M", 'M'}, + {",", VK_OEM_COMMA}, + {".", VK_OEM_PERIOD}, + {"SLASH", VK_OEM_2}, + {"BACKSLASH", VK_OEM_102}, + + // Row 6 + {"CONTROL", VK_CONTROL}, + {"L_WIN", VK_LWIN}, + {"ALT", VK_MENU}, + {"SPACE", VK_SPACE}, + {"R_WIN", VK_RWIN}, + {"MENU", VK_APPS}, + + // Other Keys + // PrtSc is more important when making snapshots, therefore comment it as reserved + //{"PRINT_SCREEN", VK_SNAPSHOT}, + {"SCROLL_LOCK", VK_SCROLL}, + {"PAUSE", VK_PAUSE}, + {"INSERT", VK_INSERT}, + {"DELETE", VK_DELETE}, + {"HOME", VK_HOME}, + {"END", VK_END}, + {"PAGE_UP", VK_PRIOR}, + {"PAGE_DOWN", VK_NEXT}, + + // Arrow Keys + {"UPARROW", VK_UP}, + {"LEFTARROW", VK_LEFT}, + {"DOWNARROW", VK_DOWN}, + {"RIGHTARROW", VK_RIGHT}, + + // NUMPAD Keys + {"NUM_LOCK", VK_NUMLOCK}, + {"DIVIDE", VK_DIVIDE}, + {"MULTIPLY", VK_MULTIPLY}, + {"SUBTRACT", VK_SUBTRACT}, + {"NUM7", VK_NUMPAD7}, + {"NUM8", VK_NUMPAD8}, + {"NUM9", VK_NUMPAD9}, + {"ADD", VK_ADD}, + {"NUM4", VK_NUMPAD4}, + {"NUM5", VK_NUMPAD5}, + {"NUM6", VK_NUMPAD6}, + {"NUM1", VK_NUMPAD1}, + {"NUM2", VK_NUMPAD2}, + {"NUM3", VK_NUMPAD3}, + {"NUM0", VK_NUMPAD0}, + {"DECIMAL", VK_DECIMAL}, +}; + +struct { + const char *string; + SDL_GameControllerButton button; +} ConfigControllerButtons[] = { + {"SDL_A", SDL_CONTROLLER_BUTTON_A}, + {"SDL_B", SDL_CONTROLLER_BUTTON_B}, + {"SDL_X", SDL_CONTROLLER_BUTTON_X}, + {"SDL_Y", SDL_CONTROLLER_BUTTON_Y}, + {"SDL_BACK", SDL_CONTROLLER_BUTTON_BACK}, + {"SDL_GUIDE", SDL_CONTROLLER_BUTTON_GUIDE}, + {"SDL_START", SDL_CONTROLLER_BUTTON_START}, + {"SDL_LSTICK_PRESS", SDL_CONTROLLER_BUTTON_LEFTSTICK}, + {"SDL_RSTICK_PRESS", SDL_CONTROLLER_BUTTON_RIGHTSTICK}, + {"SDL_LSHOULDER", SDL_CONTROLLER_BUTTON_LEFTSHOULDER}, + {"SDL_RSHOULDER", SDL_CONTROLLER_BUTTON_RIGHTSHOULDER}, + {"SDL_DPAD_UP", SDL_CONTROLLER_BUTTON_DPAD_UP}, + {"SDL_DPAD_DOWN", SDL_CONTROLLER_BUTTON_DPAD_DOWN}, + {"SDL_DPAD_LEFT", SDL_CONTROLLER_BUTTON_DPAD_LEFT}, + {"SDL_DPAD_RIGHT", SDL_CONTROLLER_BUTTON_DPAD_RIGHT}, + {"SDL_MISC", SDL_CONTROLLER_BUTTON_MISC1}, + {"SDL_PADDLE1", SDL_CONTROLLER_BUTTON_PADDLE1}, + {"SDL_PADDLE2", SDL_CONTROLLER_BUTTON_PADDLE2}, + {"SDL_PADDLE3", SDL_CONTROLLER_BUTTON_PADDLE3}, + {"SDL_PADDLE4", SDL_CONTROLLER_BUTTON_PADDLE4}, + {"SDL_TOUCHPAD", SDL_CONTROLLER_BUTTON_TOUCHPAD}, +}; + +struct { + const char *string; + SDLAxis axis; +} ConfigControllerAXIS[] = { + {"SDL_LSTICK_LEFT", SDL_AXIS_LEFT_LEFT}, {"SDL_LSTICK_UP", SDL_AXIS_LEFT_UP}, {"SDL_LSTICK_DOWN", SDL_AXIS_LEFT_DOWN}, + {"SDL_LSTICK_RIGHT", SDL_AXIS_LEFT_RIGHT}, {"SDL_RSTICK_LEFT", SDL_AXIS_RIGHT_LEFT}, {"SDL_RSTICK_UP", SDL_AXIS_RIGHT_UP}, + {"SDL_RSTICK_DOWN", SDL_AXIS_RIGHT_DOWN}, {"SDL_RSTICK_RIGHT", SDL_AXIS_RIGHT_RIGHT}, {"SDL_LTRIGGER", SDL_AXIS_LTRIGGER_DOWN}, + {"SDL_RTRIGGER", SDL_AXIS_RTRIGGER_DOWN}, +}; + +struct { + const char *string; + Scroll scroll; +} ConfigMouseScroll[] = { + {"SCROLL_UP", MOUSE_SCROLL_UP}, + {"SCROLL_DOWN", MOUSE_SCROLL_DOWN}, +}; + +struct MouseState { + POINT Position; + POINT RelativePosition; + bool ScrolledUp; + bool ScrolledDown; +} currentMouseState, lastMouseState; \ No newline at end of file From f71b929f86a7824c8222bde02c051d841c725245 Mon Sep 17 00:00:00 2001 From: ptmaster Date: Wed, 4 Dec 2024 01:08:34 +0800 Subject: [PATCH 2/6] =?UTF-8?q?=E6=B7=BB=E5=8A=A0Readme=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 984507a..1bbc25b 100644 --- a/README.md +++ b/README.md @@ -136,3 +136,5 @@ cmake --build build --config Release --target bnusio ``` The compiled dll of TaikoArcadeLoader will be written in the `dist` folder. + +(experimental) To enable `async update` / `async io`, you can add `-DASYNC_UPDATE` or `-DASYNC_IO` into add_definitions in CMakeLists.txt From bb3f18a2806c705ce777af827f93720d8a57cc02 Mon Sep 17 00:00:00 2001 From: ptmaster Date: Wed, 4 Dec 2024 09:54:05 +0800 Subject: [PATCH 3/6] Handle some control info --- src/bnusio.cpp | 2 +- src/bnusio.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bnusio.cpp b/src/bnusio.cpp index faee21d..5359f3f 100644 --- a/src/bnusio.cpp +++ b/src/bnusio.cpp @@ -294,7 +294,7 @@ UpdateLoop () { inited = true; } -#ifndef ASYNC_UPDATE +#ifndef ASYNC_IO UpdatePoll (windowHandle); #endif std::vector buffer = {}; diff --git a/src/bnusio.h b/src/bnusio.h index c964101..b0f7588 100644 --- a/src/bnusio.h +++ b/src/bnusio.h @@ -1,5 +1,5 @@ #pragma once -// #define ASYNC_UPDATE +#define ASYNC_UPDATE namespace bnusio { void Init (); void Update (); From 0d4ca8b79e2ed69f3b858d6c6f590c876c8a13f8 Mon Sep 17 00:00:00 2001 From: ptmaster Date: Sat, 7 Dec 2024 06:22:53 +0800 Subject: [PATCH 4/6] optimize bnusio_GetAnalogIn add High Resolution Timer move chs_voice to testmode remove garmc dirty logs fix pollasync keyboard & mouse wheel --- CMakeLists.txt | 1 + src/bnusio.cpp | 84 ++++++++--------- src/bnusio.h | 2 +- src/dllmain.cpp | 2 + src/patches/patches.h | 4 + src/patches/scanner.cpp | 2 +- src/patches/testmode.cpp | 41 +++++++- src/patches/timer.cpp | 45 +++++++++ src/patches/versions/JPN39.cpp | 118 ++++++++++++++--------- src/pollasync.cpp | 166 +++++++++++++++++++-------------- 10 files changed, 305 insertions(+), 160 deletions(-) create mode 100644 src/patches/timer.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 253385b..abf3be6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -140,6 +140,7 @@ set(SOURCES # src/patches/qr.cpp src/patches/layeredfs.cpp src/patches/testmode.cpp + src/patches/timer.cpp src/patches/versions/JPN00.cpp src/patches/versions/JPN08.cpp src/patches/versions/JPN39.cpp diff --git a/src/bnusio.cpp b/src/bnusio.cpp index 5359f3f..230447d 100644 --- a/src/bnusio.cpp +++ b/src/bnusio.cpp @@ -125,10 +125,14 @@ bool valueStates[] = {false, false, false, false, false, false, false, false}; Keybindings *analogButtons[] = {&P1_LEFT_BLUE, &P1_LEFT_RED, &P1_RIGHT_RED, &P1_RIGHT_BLUE, &P2_LEFT_BLUE, &P2_LEFT_RED, &P2_RIGHT_RED, &P2_RIGHT_BLUE}; -u16 buttonWaitPeriodP1 = 0; -u16 buttonWaitPeriodP2 = 0; -std::queue buttonQueueP1; -std::queue buttonQueueP2; +u16 cooldown[8] = { 0 }; +u16 buttonWaitPeriod[] = { 0, 0 }; +std::queue buttonQueue[] = { {}, {} }; + +// u16 buttonWaitPeriodP1 = 0; +// u16 buttonWaitPeriodP2 = 0; +// std::queue buttonQueueP1; +// std::queue buttonQueueP2; bool analogInput; SDLAxis analogBindings[] = { @@ -139,52 +143,39 @@ SDLAxis analogBindings[] = { u16 bnusio_GetAnalogIn (const u8 which) { if (analogInput) { - if (const u16 analogValue = static_cast (32768 * ControllerAxisIsDown (analogBindings[which])); analogValue > 100) return analogValue; - return 0; + const u16 analogValue = static_cast (32768 * ControllerAxisIsDown (analogBindings[which])); + if (analogValue > 100) return analogValue; + else return 0; } const auto button = analogButtons[which]; - if (which == 0) { - if (buttonWaitPeriodP1 > 0) buttonWaitPeriodP1--; - if (buttonWaitPeriodP2 > 0) buttonWaitPeriodP2--; - } - if (const bool isP1 = which / 4 == 0; (isP1 && !buttonQueueP1.empty ()) || (!isP1 && !buttonQueueP2.empty ())) { - if ((isP1 && buttonQueueP1.front () == which && buttonWaitPeriodP1 == 0) - || (!isP1 && buttonQueueP2.front () == which && buttonWaitPeriodP2 == 0)) { - if (isP1) { - buttonQueueP1.pop (); - buttonWaitPeriodP1 = drumWaitPeriod; - } else { - buttonQueueP2.pop (); - buttonWaitPeriodP2 = drumWaitPeriod; - } + const int blue = !(which % 4 % 3); + const int player = which / 4; - const u16 hitValue = !valueStates[which] ? 50 : 51; - valueStates[which] = !valueStates[which]; - return (hitValue << 15) / 100 + 1; - } - if (IsButtonTapped (*button)) { - if (isP1) buttonQueueP1.push (which); - else buttonQueueP2.push (which); - } - return 0; - } else if (IsButtonTapped (*button)) { - if (isP1 && buttonWaitPeriodP1 > 0) { - buttonQueueP1.push (which); - return 0; - } - if (!isP1 && buttonWaitPeriodP2 > 0) { - buttonQueueP2.push (which); - return 0; - } - if (isP1) buttonWaitPeriodP1 = drumWaitPeriod; - else buttonWaitPeriodP2 = drumWaitPeriod; + u16 analogValue = 0; + if (which == 0) { + for (int i=0; i<2; i++) if (buttonWaitPeriod[i] > 0) buttonWaitPeriod[i]--; + for (int i=0; i<8; i++) if (cooldown[i] > 0) cooldown[i]--; + } + if (buttonWaitPeriod[player] == 0 && !buttonQueue[player].empty () && buttonQueue[player].front () == which) { + buttonQueue[player].pop (); + buttonWaitPeriod[player] = drumWaitPeriod; const u16 hitValue = !valueStates[which] ? 50 : 51; valueStates[which] = !valueStates[which]; - return (hitValue << 15) / 100 + 1; + analogValue = (hitValue << 15) / 100 + 1; } + if (IsButtonTapped (*button)) { + if (drumWaitPeriod > 0) { + if (blue && buttonWaitPeriod[player] > 0) buttonQueue[player].push (which); + buttonWaitPeriod[player] = drumWaitPeriod; + } else if (blue && cooldown[which] > 0) return 0; - return 0; + if (blue) cooldown[which] = 4; + const u16 hitValue = !valueStates[which] ? 50 : 51; + valueStates[which] = !valueStates[which]; + analogValue = (hitValue << 15) / 100 + 1; + } + return analogValue; } u16 __fastcall bnusio_GetCoin (i32 a1) { @@ -277,10 +268,10 @@ void UpdateLoop () { LogMessage (LogLevel::WARN, "Using Async Update (experimental)!"); std::unique_lock syncLock(syncMtx); - while (exited < 50) { + while (exited < 120) { syncCV.wait (syncLock); #endif - if (exited && ++exited >= 50) ExitProcess (0); + if (exited && ++exited >= 120) ExitProcess (0); if (!inited) { windowHandle = FindWindowA ("nuFoundation.Window", nullptr); InitializePoll (windowHandle); @@ -301,7 +292,10 @@ UpdateLoop () { if (IsButtonTapped (COIN_ADD)) coin_count++; if (IsButtonTapped (SERVICE) && !testEnabled) service_count++; if (IsButtonTapped (TEST)) testEnabled = !testEnabled; - if (IsButtonTapped (EXIT)) { exited += 1; testEnabled = 1; patches::Plugins::Exit (); } + if (IsButtonTapped (EXIT)) { + LogMessage (LogLevel::INFO, "Exit By Press Exit Button!"); + exited += 1; testEnabled = 1; patches::Plugins::Exit (); + } if (GameVersion::CHN00 == gameVersion) { if (IsButtonTapped (CARD_INSERT_1)) patches::Scanner::Qr::CommitLogin (accessCode1); if (IsButtonTapped (CARD_INSERT_2)) patches::Scanner::Qr::CommitLogin (accessCode2); diff --git a/src/bnusio.h b/src/bnusio.h index b0f7588..c964101 100644 --- a/src/bnusio.h +++ b/src/bnusio.h @@ -1,5 +1,5 @@ #pragma once -#define ASYNC_UPDATE +// #define ASYNC_UPDATE namespace bnusio { void Init (); void Update (); diff --git a/src/dllmain.cpp b/src/dllmain.cpp index 1642b67..b0fbcd5 100644 --- a/src/dllmain.cpp +++ b/src/dllmain.cpp @@ -266,6 +266,8 @@ DllMain (HMODULE module, const DWORD reason, LPVOID reserved) { patches::LayeredFs::Init (); patches::TestMode::Init (); + patches::Timer::Init (); + LogMessage (LogLevel::INFO, "==== Finished Loading patches!"); } return true; diff --git a/src/patches/patches.h b/src/patches/patches.h index 00769cb..03cc8d6 100644 --- a/src/patches/patches.h +++ b/src/patches/patches.h @@ -55,6 +55,7 @@ void Init (); void Append (const pugi::xml_node &node, const wchar_t *attr, const std::wstring &append); void SetupAccessor (u64 appAccessor, RefTestModeMain refTestMode); int ReadTestModeValue (const wchar_t *itemId); +void SetTestModeValue (const wchar_t *itemId, int value); Menu *CreateMenu (const std::wstring &menuName, const std::wstring &menuId); void RegisterItem (const std::wstring &item, const std::function &initMethod, Menu *menu); void RegisterItem (const std::wstring &item, const std::function &initMethod); @@ -114,4 +115,7 @@ std::vector &ReadQRData (std::vector &buffer); std::vector &ReadQRImage (std::vector &buffer); } // namespace Qr } // namespace Scanner +namespace Timer { +void Init (); +} // namespace timer } // namespace patches diff --git a/src/patches/scanner.cpp b/src/patches/scanner.cpp index 83ec999..1b4a469 100644 --- a/src/patches/scanner.cpp +++ b/src/patches/scanner.cpp @@ -297,7 +297,7 @@ namespace Qr { } std::vector buffer = {}; std::string accessQRDataBase = "BNTTCNID"; - if (!accessCode._Starts_with (accessQRDataBase)) + if (!accessCode.starts_with (accessQRDataBase)) for (char word : accessQRDataBase) buffer.push_back (word); for (char word : accessCode) buffer.push_back (word); return patches::Scanner::Qr::Commit (buffer); diff --git a/src/patches/testmode.cpp b/src/patches/testmode.cpp index baca783..46353ac 100644 --- a/src/patches/testmode.cpp +++ b/src/patches/testmode.cpp @@ -82,7 +82,10 @@ public: if (size == 0) return node; size_t maxPage = size <= 14 ? 1 : (size / 13 + (size % 13 > 0)); LogMessage (LogLevel::DEBUG, "Render testmode menu with items(size={}, page={})", size, maxPage); - std::wstring parentId = node->parent ().parent ().attribute (L"id").value (); + std::wstring menuName = L"menu"; + pugi::xml_node parentNode = node->parent (); + while (parentNode.name() != menuName) parentNode = parentNode.parent (); + std::wstring parentId = parentNode.attribute (L"id").value (); pugi::xml_document menuItem; menuItem.load_string (std::format (L"", this->menuName, this->menuId).c_str ()); @@ -289,6 +292,16 @@ HOOK_DYNAMIC (void, TestModeSetMenuHook, u64 testModeLibrary, const wchar_t *lFi originalTestModeSetMenuHook (testModeLibrary, fileName.c_str ()); } +// HOOK_DYNAMIC (void, TestModeGetValueHook, u64 *reader, const wchar_t *lItemName, int *value) { +// originalTestModeGetValueHook (reader, lItemName, value); +// LogMessage (LogLevel::DEBUG, L"TestMode get Item: {} Value: {}", lItemName, *value); +// } + +// HOOK_DYNAMIC (void, TestModeSetValueHook, u64 *reader, const wchar_t *lItemName, int value) { +// LogMessage (LogLevel::DEBUG, L"TestMode set Item: {} Value: {}", lItemName, value); +// originalTestModeSetValueHook (reader, lItemName, value); +// } + void CommonModify () { // Default off Close time @@ -424,7 +437,14 @@ Init () { const auto configPath = std::filesystem::current_path () / "config.toml"; const std::unique_ptr config_ptr (openConfig (configPath), toml_free); - const u64 testModeSetMenuAddress = PROC_ADDRESS_OFFSET ("TestModeLibrary.dll", 0x99D0); + const u64 testModeLibrary = (u64)GetModuleHandle ("TestModeLibrary.dll"); + const u64 testModeSetMenu = testModeLibrary + 0x99D0; + // const u64 testModeGetValue = testModeLibrary + 0x6FB18; + // const u64 testModeSetValue = testModeLibrary + 0x6FAC8; + + LogMessage (LogLevel::DEBUG, "TestModeLibrary: {}", testModeLibrary); + // LogMessage (LogLevel::DEBUG, "TestModeLibrary set: {}", testModeSetValue); + // LogMessage (LogLevel::DEBUG, "TestModeLibrary get: {}", testModeGetValue); switch (gameVersion) { case GameVersion::UNKNOWN: break; case GameVersion::JPN00: break; @@ -442,7 +462,9 @@ Init () { CommonModify (); - INSTALL_HOOK_DYNAMIC (TestModeSetMenuHook, testModeSetMenuAddress); + INSTALL_HOOK_DYNAMIC (TestModeSetMenuHook, testModeSetMenu); + // INSTALL_HOOK_DYNAMIC (TestModeGetValueHook, testModeGetValue); + // INSTALL_HOOK_DYNAMIC (TestModeSetValueHook, testModeSetValue); } void @@ -457,7 +479,9 @@ ReadTestModeValue (const wchar_t *itemId) { if (const u64 testModeMain = refTestMode (appAccessor)) { int value = 0; u64 *reader = *reinterpret_cast (testModeMain + 16); + // LogMessage (LogLevel::DEBUG, "TestMode get:{} set:{}", *reader + 256, *reader + 176); (*reinterpret_cast (*reader + 256)) (reader, itemId, &value); + // originalTestModeGetValueHook (reader, itemId, &value); return value; } } @@ -465,6 +489,17 @@ ReadTestModeValue (const wchar_t *itemId) { return -1; } +void +SetTestModeValue (const wchar_t *itemId, int value) { + if (appAccessor) { + if (const u64 testModeMain = refTestMode (appAccessor)) { + u64 *reader = *reinterpret_cast (testModeMain + 16); + (*reinterpret_cast (*reader + 176)) (reader, itemId, value); + // ((TestModeSetValueHook)whereTestModeSetMenuHook) (reader, itemId, value); + } + } +} + Menu * CreateMenu (const std::wstring &menuName, const std::wstring &menuId) { LogMessage (LogLevel::DEBUG, L"Create MenuName: {} MenuId: {}", menuName, menuId); diff --git a/src/patches/timer.cpp b/src/patches/timer.cpp new file mode 100644 index 0000000..85f738c --- /dev/null +++ b/src/patches/timer.cpp @@ -0,0 +1,45 @@ +#include "constants.h" +#include "helpers.h" +#include "patches.h" + +extern "C" NTSTATUS NTAPI NtSetTimerResolution( + IN ULONG DesiredResolution, + IN BOOLEAN SetResolution, + OUT PULONG CurrentResolution +); + +extern "C" NTSTATUS NTAPI NtQueryTimerResolution( + OUT PULONG CurrentResolution, + OUT PULONG MinimumResolution, + OUT PULONG MaximumResolution +); + +namespace patches::Timer { + ULONG currentResolution = 0; + ULONG minimumResolution = 0; + ULONG maximumResolution = 0; + + void + Release () { + NtSetTimerResolution(currentResolution, FALSE, ¤tResolution); + } + + void + Init () { + NTSTATUS queryStatus = NtQueryTimerResolution(¤tResolution, &minimumResolution, &maximumResolution); + if (queryStatus == 0) { + bool setHighResolutionTimer = currentResolution > maximumResolution; + LogMessage (LogLevel::INFO, "Timer Resolution current: {}ms maximum: {}ms", currentResolution / 10000.0, maximumResolution / 10000.0); + + if (setHighResolutionTimer) { + NTSTATUS status = NtSetTimerResolution(maximumResolution, TRUE, ¤tResolution); + if (status == 0) { + LogMessage (LogLevel::INFO, "Successfully change Timer resolution to {}ms", maximumResolution / 10000.0); + } else { + LogMessage (LogLevel::ERROR, "Failed to change Timer resolution, status={}", status); + } + atexit (Release); + } + } else LogMessage (LogLevel::ERROR, "Failed to query Timer resolution, status={}", queryStatus); + } +} \ No newline at end of file diff --git a/src/patches/versions/JPN39.cpp b/src/patches/versions/JPN39.cpp index 468beb3..fb71d0b 100644 --- a/src/patches/versions/JPN39.cpp +++ b/src/patches/versions/JPN39.cpp @@ -16,6 +16,10 @@ HOOK_DYNAMIC (i64, curl_easy_setopt, i64 a1, i64 a2, i64 a3, i64 a4, i64 a5) { originalcurl_easy_setopt (a1, 81, 0, 0, 0); return originalcurl_easy_setopt (a1, a2, a3, a4, a5); } +HOOK_DYNAMIC (void, garmc_logger_log, i64 a1, int a2, void *a3, char a4) { + // remove garmc log + return; +} FUNCTION_PTR (i64, GetPlayDataManagerRef, ASLR (0x140024AC0), i64); @@ -50,6 +54,7 @@ HOOK (i64, DeviceCheck, ASLR (0x140464FC0), i64 a1, i64 a2, i64 a3) { LogMessage (LogLevel::HOOKS, "DeviceCheck was called"); TestMode::SetupAccessor (a3, RefTestModeMain); componentAccessor = a2; + appAccessor = a3; return originalDeviceCheck (a1, a2, a3); } @@ -75,7 +80,8 @@ MID_HOOK (DifficultyPanelCrown, ASLR (0x1403F2A25), SafetyHookContext &ctx) { } HOOK (i64, AvailableMode_Collabo024, ASLR (0x1402DE710), i64 a1) { LogMessage (LogLevel::HOOKS, "AvailableMode_Collabo024 was called"); - if (const int tournamentMode = TestMode::ReadTestModeValue (L"TournamentMode"); tournamentMode == 1) return originalAvailableMode_Collabo024 (a1); + const int tournamentMode = TestMode::ReadTestModeValue (L"TournamentMode"); + if (tournamentMode == 1) return originalAvailableMode_Collabo024 (a1); const int status = TestMode::ReadTestModeValue (L"ModModeCollabo024"); if (status == 1 && GetUserStatus () == 1) return lua_pushbool (a1, true); return originalAvailableMode_Collabo024 (a1); @@ -240,7 +246,7 @@ get_bank_id (const std::string &bankName) { void check_voice_tail (const std::string &bankName, u8 *pBinfBlock, std::map &voiceExist, const std::string &tail) { // check if any voice_xxx.nus3bank has xxx_cn audio inside while loading - if (enableSwitchVoice && bankName.starts_with ("voice_")) { + if (bankName.starts_with ("voice_")) { const int binfLength = *reinterpret_cast (pBinfBlock + 4); u8 *pGrpBlock = pBinfBlock + 8 + binfLength; const int grpLength = *reinterpret_cast (pGrpBlock + 4); @@ -261,7 +267,10 @@ check_voice_tail (const std::string &bankName, u8 *pBinfBlock, std::map 0) { std::string title (reinterpret_cast (currToneBase + titleOffset)); if (title.ends_with (tail)) { - if (!voiceExist.contains (bankName) || !voiceExist[bankName]) voiceExist[bankName] = true; + if (!voiceExist.contains (bankName) || !voiceExist[bankName]) { + voiceExist[bankName] = true; + enableSwitchVoice = true; + } return; } } @@ -288,32 +297,34 @@ MID_HOOK (GenNus3bankId, ASLR (0x1407B97BD), SafetyHookContext &ctx) { } std::string -FixToneName (const std::string &bankName, std::string toneName) { - if (language == 2 || language == 4) { +FixToneName (const std::string &bankName, std::string toneName, int voiceLang) { + if (voiceLang == 1) { if (voiceCnExist.contains (bankName) && voiceCnExist[bankName]) return toneName + "_cn"; } return toneName; } size_t commonSize = 0; -HOOK (i64, PlaySound, ASLR (0x1404C6DC0), i64 a1) { - LogMessage (LogLevel::HOOKS, "PlaySound was called"); - if (enableSwitchVoice && language != 0) { +HOOK (i64, PlaySoundMain, ASLR (0x1404C6DC0), i64 a1) { + LogMessage (LogLevel::HOOKS, "PlaySoundMain was called"); + int lang = TestMode::ReadTestModeValue (L"VoiceLanguageItem"); + if (enableSwitchVoice && lang != 0) { const std::string bankName (lua_tolstring (a1, -3, &commonSize)); if (bankName[0] == 'v') { - lua_pushstring (a1, FixToneName (bankName, lua_tolstring (a1, -2, &commonSize)).c_str ()); + lua_pushstring (a1, FixToneName (bankName, lua_tolstring (a1, -2, &commonSize), lang).c_str ()); lua_replace (a1, -3); } } - return originalPlaySound (a1); + return originalPlaySoundMain (a1); } HOOK (i64, PlaySoundMulti, ASLR (0x1404C6D60), i64 a1) { LogMessage (LogLevel::HOOKS, "PlaySoundMulti was called"); - if (enableSwitchVoice && language != 0) { + int lang = TestMode::ReadTestModeValue (L"VoiceLanguageItem"); + if (enableSwitchVoice && lang != 0) { const std::string bankName (const_cast (lua_tolstring (a1, -3, &commonSize))); if (bankName[0] == 'v') { - lua_pushstring (a1, FixToneName (bankName, lua_tolstring (a1, -2, &commonSize)).c_str ()); + lua_pushstring (a1, FixToneName (bankName, lua_tolstring (a1, -2, &commonSize), lang).c_str ()); lua_replace (a1, -3); } } @@ -323,8 +334,8 @@ HOOK (i64, PlaySoundMulti, ASLR (0x1404C6D60), i64 a1) { FUNCTION_PTR (u64 *, append_chars_to_basic_string, ASLR (0x140028DA0), u64 *, const char *, size_t); u64 * -FixToneNameEnso (u64 *Src, const std::string &bankName) { - if (language == 2 || language == 4) { +FixToneNameEnso (u64 *Src, const std::string &bankName, int voiceLang) { + if (voiceLang == 1) { if (voiceCnExist.contains (bankName) && voiceCnExist[bankName]) Src = append_chars_to_basic_string (Src, "_cn", 3); } return Src; @@ -332,18 +343,20 @@ FixToneNameEnso (u64 *Src, const std::string &bankName) { HOOK (bool, PlaySoundEnso, ASLR (0x1404ED590), u64 *a1, u64 *a2, i64 a3) { LogMessage (LogLevel::HOOKS, "PlaySoundEnso was called"); - if (enableSwitchVoice && language != 0) { + int lang = TestMode::ReadTestModeValue (L"VoiceLanguageItem"); + if (enableSwitchVoice && lang != 0) { const std::string bankName = a1[3] > 0x10 ? std::string (*reinterpret_cast (a1)) : std::string (reinterpret_cast (a1)); - if (bankName[0] == 'v') a2 = FixToneNameEnso (a2, bankName); + if (bankName[0] == 'v') a2 = FixToneNameEnso (a2, bankName, lang); } return originalPlaySoundEnso (a1, a2, a3); } HOOK (bool, PlaySoundSpecial, ASLR (0x1404ED230), u64 *a1, u64 *a2) { LogMessage (LogLevel::HOOKS, "PlaySoundSpecial was called"); - if (enableSwitchVoice && language != 0) { + int lang = TestMode::ReadTestModeValue (L"VoiceLanguageItem"); + if (enableSwitchVoice && lang != 0) { const std::string bankName = a1[3] > 0x10 ? std::string (*reinterpret_cast (a1)) : std::string (reinterpret_cast (a1)); - if (bankName[0] == 'v') a2 = FixToneNameEnso (a2, bankName); + if (bankName[0] == 'v') a2 = FixToneNameEnso (a2, bankName, lang); } return originalPlaySoundSpecial (a1, a2); } @@ -437,6 +450,23 @@ HOOK (u64, EnsoGameManagerChechEnsoEnd, ASLR (0x1400E2A10), u64 a1, u64 a2, u64 return result; } +HOOK (DWORD*, AcquireMostCompatibleDisplayMode, ASLR (0x14064C870), i64 a1, DWORD *a2, DWORD *a3) { + LogMessage (LogLevel::DEBUG, "AcquireMostCompatibleDisplayMode {:d} {:d} {:f} {:f}", a3[0], a3[1], (float)(int)a3[2], (float)(int)a3[3]); + a3[2] = (DWORD)(int)120.0f; + LogMessage (LogLevel::DEBUG, "AcquireMostCompatibleDisplayMode {:d} {:d} {:f} {:f}", a3[0], a3[1], (float)(int)a3[2], (float)(int)a3[3]); + return originalAcquireMostCompatibleDisplayMode (a1, a2, a3); +} + +HOOK (char, SceneTestModeLoading, ASLR (0x1404793D0), u64 a1, u64 a2, u64 a3) { + LogMessage (LogLevel::DEBUG, "Begin SceneTestModeLoading"); + char result = originalSceneTestModeLoading (a1, a2, a3); + LogMessage (LogLevel::DEBUG, "End originalSceneTestModeLoading"); + TestMode::SetTestModeValue (L"EnableSwitchVoice", (int)enableSwitchVoice); + if (!enableSwitchVoice) TestMode::SetTestModeValue (L"VoiceLanguageItem", 0); + LogMessage (LogLevel::DEBUG, "End SceneTestModeLoading"); + return result; +} + constexpr i32 datatableBufferSize = 1024 * 1024 * 12; safetyhook::Allocation datatableBuffer1; safetyhook::Allocation datatableBuffer2; @@ -506,15 +536,13 @@ Init () { INSTALL_HOOK (EnsoGraphicManagerPreparing); INSTALL_HOOK (EnsoGameManagerStart); INSTALL_HOOK (EnsoGameManagerChechEnsoEnd); + INSTALL_HOOK (AcquireMostCompatibleDisplayMode); + INSTALL_HOOK (SceneTestModeLoading); // Apply common config patch WRITE_MEMORY (ASLR (0x140494533), i32, xRes); WRITE_MEMORY (ASLR (0x14049453A), i32, yRes); if (!vsync) WRITE_MEMORY (ASLR (0x14064C7E9), u8, 0xBA, 0x00, 0x00, 0x00, 0x00, 0x90); - if (unlockSongs) { - WRITE_MEMORY (ASLR (0x1403F45CF), u8, 0xB0, 0x01); - INSTALL_MID_HOOK (CountLockedCrown); - } // Bypass errors WRITE_MEMORY (ASLR (0x140041A00), u8, 0xC3); @@ -564,18 +592,39 @@ Init () { ReplaceLeaBufferAddress (datatableBuffer3Addresses, datatableBuffer3.data ()); } - // Fix Language - TestMode::RegisterItem( + // Language + TestMode::Menu *langPatchesMenu = TestMode::CreateMenu (L"LANGUAGE PATCHES", L"LanguagePatchesMenu"); + TestMode::Menu *langResourceIndicator = TestMode::CreateMenu (L"RESOURCE INDICATOR", L"LanguageResourceIndicatorMenu"); + TestMode::RegisterItem ( L"", [&]() { INSTALL_HOOK (GetLanguage); INSTALL_HOOK (GetRegionLanguage); INSTALL_HOOK (GetCabinetLanguage); + }, langPatchesMenu + ); + TestMode::RegisterItem( + L"", + langResourceIndicator + ); + TestMode::RegisterItemAfter( + L"/root/menu[@id='OthersMenu']/layout[@type='Center']/select-item[@id='LanguageItem']", + L"", + [&](){ + INSTALL_HOOK (PlaySoundMain); + INSTALL_HOOK (PlaySoundMulti); + INSTALL_HOOK (PlaySoundEnso); + INSTALL_HOOK (PlaySoundSpecial); } ); + TestMode::RegisterItem(langResourceIndicator, langPatchesMenu); + TestMode::RegisterItem(langPatchesMenu); + // Unlock Songs - TestMode::RegisterItem( + TestMode::RegisterItem ( L"", [&]() { @@ -653,6 +702,7 @@ Init () { L"replace-text=\"0:ON, 1:OFF\" group=\"Setting\" id=\"AttractDemoItem\" max=\"1\" min=\"0\" default=\"0\"/>", [&](){ INSTALL_MID_HOOK (AttractDemo); } ); + // for (size_t i=0; i < 40; i++) TestMode::RegisterItem(std::format (L"", i + 1)); // Instant Result @@ -696,23 +746,6 @@ Init () { }); } - // Fix language - if (fixLanguage) { - INSTALL_HOOK (GetLanguage); // Language will use in other place - INSTALL_HOOK (GetRegionLanguage); - INSTALL_HOOK (GetCabinetLanguage); - } - - // if both chsPatch & fixLanguage enabled, try use cn voice from nus3bank - // don't worry, we will check if cn voice existed - if (chsPatch && fixLanguage) { - enableSwitchVoice = true; - INSTALL_HOOK (PlaySound); - INSTALL_HOOK (PlaySoundMulti); - INSTALL_HOOK (PlaySoundEnso); - INSTALL_HOOK (PlaySoundSpecial); - } - // Fix normal song play after passing through silent song INSTALL_MID_HOOK (GenNus3bankId); INSTALL_HOOK (LoadedBankAll); @@ -734,5 +767,6 @@ Init () { // Redirect garmc requests auto garmcHandle = reinterpret_cast (GetModuleHandle ("garmc.dll")); INSTALL_HOOK_DYNAMIC (curl_easy_setopt, reinterpret_cast (garmcHandle + 0x1FBBB0)); + INSTALL_HOOK_DYNAMIC (garmc_logger_log, reinterpret_cast (garmcHandle + 0x13AB70)); } } // namespace patches::JPN39 diff --git a/src/pollasync.cpp b/src/pollasync.cpp index 51608b8..a4b3992 100644 --- a/src/pollasync.cpp +++ b/src/pollasync.cpp @@ -5,6 +5,10 @@ extern bool jpLayout; extern int exited; +#ifndef MIN +#define MIN(a,b) ((a)<(b)?(a):(b)) +#endif + bool wndForeground = false; bool currentKeyboardState[0xFF] = { false }; @@ -13,6 +17,12 @@ int keyboardDiff[0xFF] = { 0 }; bool currentControllerButtonsState[SDL_CONTROLLER_BUTTON_MAX] = { false }; int controllerCount[SDL_CONTROLLER_BUTTON_MAX] = { 0 }; int controllerDiff[SDL_CONTROLLER_BUTTON_MAX] = { 0 }; +char currentMouseWheelDirection = 0; +int mouseWheelCount[2] = { 0 }; +int mouseWheelDiff[2] = { 0 }; + +int maxCount = 1; + SDLAxisState currentControllerAxisState; SDL_Window *window; @@ -96,7 +106,7 @@ LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) { DWORD keyCode = pKeyboard->vkCode; switch (wParam) { case WM_KEYDOWN: if (wndForeground) { - if (!currentKeyboardState[keyCode]) keyboardCount[keyCode] ++; + if (!currentKeyboardState[keyCode]) keyboardCount[keyCode] = MIN (keyboardCount[keyCode] + 1, maxCount); currentKeyboardState[keyCode] = true; } break; // keyup will accepted even if you're not focus in this window @@ -118,63 +128,14 @@ DisposeKeyboard () { if (keyboardHook) UnhookWindowsHookEx(keyboardHook); } -void -UpdateLoop () { - LogMessage (LogLevel::DEBUG, "Enter Controller UpdateLoop"); - SDL_Event event; - SDL_GameController *controller; - while (!exited) { - while (SDL_WaitEvent (&event) != 0) { - switch (event.type) { - case SDL_CONTROLLERDEVICEADDED: - if (!SDL_IsGameController (event.cdevice.which)) break; - - controller = SDL_GameControllerOpen (event.cdevice.which); - if (!controller) { - LogMessage (LogLevel::ERROR, std::string ("Could not open gamecontroller ") + SDL_GameControllerNameForIndex (event.cdevice.which) - + ": " + SDL_GetError ()); - continue; - } - LogMessage (LogLevel::DEBUG, "Controller connected!"); - controllers[event.cdevice.which] = controller; - break; - case SDL_CONTROLLERDEVICEREMOVED: - LogMessage (LogLevel::DEBUG, "Controller removed!"); - if (!SDL_IsGameController (event.cdevice.which)) break; - SDL_GameControllerClose (controllers[event.cdevice.which]); - break; - case SDL_MOUSEWHEEL: - if (wndForeground) { - if (event.wheel.y > 0) currentMouseState.ScrolledUp = true; - else if (event.wheel.y < 0) currentMouseState.ScrolledDown = true; - } - break; - case SDL_CONTROLLERBUTTONUP: - // keyup will accepted even if you're not focus in this window - currentControllerButtonsState[event.cbutton.button] = false; break; - case SDL_CONTROLLERBUTTONDOWN: - if (wndForeground) { - if (!currentControllerButtonsState[event.cbutton.button]) controllerCount[event.cbutton.button]++; - currentControllerButtonsState[event.cbutton.button] = true; - } else LogMessage (LogLevel::WARN, "Controller button pressed but window not focused!"); - break; - case SDL_CONTROLLERAXISMOTION: - float sensorValue = event.caxis.value == 0 ? 0 : event.caxis.value / (event.caxis.value > 0 ? 32767.0f : -32768.0f); - if (wndForeground || sensorValue == 0) { - switch (event.caxis.axis) { - case SDL_CONTROLLER_AXIS_LEFTX: currentControllerAxisState.LeftRight = sensorValue; break; - case SDL_CONTROLLER_AXIS_LEFTY: currentControllerAxisState.LeftDown = sensorValue; break; - case SDL_CONTROLLER_AXIS_RIGHTX: currentControllerAxisState.RightRight = sensorValue; break; - case SDL_CONTROLLER_AXIS_RIGHTY: currentControllerAxisState.RightDown = sensorValue; break; - case SDL_CONTROLLER_AXIS_TRIGGERLEFT: currentControllerAxisState.LTriggerDown = sensorValue; break; - case SDL_CONTROLLER_AXIS_TRIGGERRIGHT: currentControllerAxisState.RTriggerDown = sensorValue; break; - } - } - break; - } - } - } -} +// void +// UpdateLoop () { +// LogMessage (LogLevel::DEBUG, "Enter Controller UpdateLoop"); + +// while (!exited) { + +// } +// } bool InitializePoll (HWND windowHandle) { @@ -223,8 +184,8 @@ InitializePoll (HWND windowHandle) { atexit (DisposePoll); - updatePollThread = std::thread (UpdateLoop); - updatePollThread.detach (); + // updatePollThread = std::thread (UpdateLoop); + // updatePollThread.detach (); return hasRumble; } @@ -243,15 +204,78 @@ void UpdatePoll (HWND windowHandle) { if (!CheckForegroundWindow (windowHandle)) return; - // currentMouseState.ScrolledUp = false; - // currentMouseState.ScrolledDown = false; + currentMouseState.ScrolledUp = false; + currentMouseState.ScrolledDown = false; for (int i=0; i<255; i++) keyboardCount[i] -= (bool)keyboardDiff[i]; for (int i=0; i 0) mouseWheelCount[i] -= (bool)mouseWheelDiff[i]; std::fill_n (keyboardDiff, 0xFF, 0); std::fill_n (controllerDiff, SDL_CONTROLLER_BUTTON_MAX, 0); + std::fill_n (mouseWheelDiff, 2, 0); // GetCursorPos (¤tMouseState.Position); // ScreenToClient (windowHandle, ¤tMouseState.Position); + SDL_Event event; + SDL_GameController *controller; + while (SDL_PollEvent (&event) != 0) { + // LogMessage (LogLevel::DEBUG, "Receive SDL Event! type={}", (u64)event.type); + switch (event.type) { + case SDL_CONTROLLERDEVICEADDED: + if (!SDL_IsGameController (event.cdevice.which)) break; + controller = SDL_GameControllerOpen (event.cdevice.which); + if (!controller) { + LogMessage (LogLevel::ERROR, std::string ("Could not open gamecontroller ") + SDL_GameControllerNameForIndex (event.cdevice.which) + + ": " + SDL_GetError ()); + continue; + } + LogMessage (LogLevel::DEBUG, "Controller connected!"); + controllers[event.cdevice.which] = controller; + break; + case SDL_CONTROLLERDEVICEREMOVED: + LogMessage (LogLevel::DEBUG, "Controller removed!"); + if (!SDL_IsGameController (event.cdevice.which)) break; + SDL_GameControllerClose (controllers[event.cdevice.which]); + break; + case SDL_MOUSEWHEEL: + if (wndForeground) { + // LogMessage (LogLevel::DEBUG, "Mouse Wheel moves {}", event.wheel.y); + if (event.wheel.y > 0) { + mouseWheelCount[0] = MIN (mouseWheelCount[0] + event.wheel.y, maxCount); + mouseWheelCount[1] = 0; + currentMouseState.ScrolledUp = true; + } else if (event.wheel.y < 0) { + mouseWheelCount[1] = MIN (mouseWheelCount[1] - event.wheel.y, maxCount); + mouseWheelCount[0] = 0; + currentMouseState.ScrolledDown = true; + } + } + break; + case SDL_CONTROLLERBUTTONUP: + // keyup will accepted even if you're not focus in this window + currentControllerButtonsState[event.cbutton.button] = false; break; + case SDL_CONTROLLERBUTTONDOWN: + if (wndForeground) { + if (!currentControllerButtonsState[event.cbutton.button]) { + controllerCount[event.cbutton.button] = MIN (controllerCount[event.cbutton.button] + 1, maxCount); + } + currentControllerButtonsState[event.cbutton.button] = true; + } else LogMessage (LogLevel::WARN, "Controller button pressed but window not focused!"); + break; + case SDL_CONTROLLERAXISMOTION: + float sensorValue = event.caxis.value == 0 ? 0 : event.caxis.value / (event.caxis.value > 0 ? 32767.0f : -32768.0f); + if (wndForeground || sensorValue == 0) { + switch (event.caxis.axis) { + case SDL_CONTROLLER_AXIS_LEFTX: currentControllerAxisState.LeftRight = sensorValue; break; + case SDL_CONTROLLER_AXIS_LEFTY: currentControllerAxisState.LeftDown = sensorValue; break; + case SDL_CONTROLLER_AXIS_RIGHTX: currentControllerAxisState.RightRight = sensorValue; break; + case SDL_CONTROLLER_AXIS_RIGHTY: currentControllerAxisState.RightDown = sensorValue; break; + case SDL_CONTROLLER_AXIS_TRIGGERLEFT: currentControllerAxisState.LTriggerDown = sensorValue; break; + case SDL_CONTROLLER_AXIS_TRIGGERRIGHT: currentControllerAxisState.RTriggerDown = sensorValue; break; + } + } + break; + } + } } void @@ -330,16 +354,22 @@ GetMouseScrollDown () { bool GetMouseScrollIsDown (const Scroll scroll) { - return false; - // if (scroll == MOUSE_SCROLL_UP) return GetMouseScrollUp (); - // else return GetMouseScrollDown (); + if (scroll == MOUSE_SCROLL_UP) return GetMouseScrollUp (); + else return GetMouseScrollDown (); } +int maxWheelCount = 1; bool GetMouseScrollIsTapped (const Scroll scroll) { - return false; - // if (scroll == MOUSE_SCROLL_UP) return GetMouseScrollUp () && !GetWasMouseScrollUp (); - // else return GetMouseScrollDown () && !GetWasMouseScrollDown (); + if (scroll == MOUSE_SCROLL_INVALID) return false; + if (mouseWheelCount[scroll - 1] > 0) { + if (maxWheelCount < mouseWheelCount[scroll - 1]) { + maxWheelCount = mouseWheelCount[scroll - 1]; + LogMessage (LogLevel::DEBUG, "MAX WHEEL COLLECTED {} {}", (int)scroll, maxWheelCount); + } + mouseWheelDiff[scroll - 1] = 1; + return true; + } return false; } bool From cb0d4692ff797b53dc4c903d8184d95bd2c506e8 Mon Sep 17 00:00:00 2001 From: ptmaster Date: Sun, 8 Dec 2024 19:41:25 +0800 Subject: [PATCH 5/6] detail fix & optimize & clean up --- src/bnusio.cpp | 106 ++++++++++++----------- src/bnusio.h | 2 +- src/patches/versions/JPN39.cpp | 34 ++++---- src/poll.cpp | 6 +- src/poll.h | 5 +- src/pollasync.cpp | 149 +++++++++++++++++++-------------- 6 files changed, 163 insertions(+), 139 deletions(-) diff --git a/src/bnusio.cpp b/src/bnusio.cpp index 230447d..7d91a41 100644 --- a/src/bnusio.cpp +++ b/src/bnusio.cpp @@ -48,6 +48,9 @@ Keybindings P2_LEFT_BLUE = {.keycodes = {'Z'}}; Keybindings P2_LEFT_RED = {.keycodes = {'X'}}; Keybindings P2_RIGHT_RED = {.keycodes = {'C'}}; Keybindings P2_RIGHT_BLUE = {.keycodes = {'V'}}; +// Keybindings ALL[] = { EXIT, TEST, SERVICE, DEBUG_UP, DEBUG_DOWN, DEBUG_ENTER, COIN_ADD, +// CARD_INSERT_1, CARD_INSERT_2, QR_DATA_READ, QR_IMAGE_READ, P1_LEFT_BLUE, P1_LEFT_RED, +// P1_RIGHT_RED, P1_RIGHT_BLUE, P2_LEFT_BLUE, P2_LEFT_RED, P2_RIGHT_RED, P2_RIGHT_BLUE }; int exited = 0; bool testEnabled = false; @@ -56,6 +59,7 @@ int service_count = 0; bool inited = false; bool updateByCoin = false; HWND windowHandle = nullptr; +bool usePoll = false; HKL currentLayout; namespace bnusio { @@ -119,6 +123,7 @@ bnusio_GetSwIn () { return sw; } +bool waitAll = false; u16 drumWaitPeriod = 4; bool valueStates[] = {false, false, false, false, false, false, false, false}; @@ -148,7 +153,7 @@ bnusio_GetAnalogIn (const u8 which) { else return 0; } const auto button = analogButtons[which]; - const int blue = !(which % 4 % 3); + const bool blue = !(which % 4 % 3); const int player = which / 4; u16 analogValue = 0; @@ -157,20 +162,21 @@ bnusio_GetAnalogIn (const u8 which) { for (int i=0; i<8; i++) if (cooldown[i] > 0) cooldown[i]--; } if (buttonWaitPeriod[player] == 0 && !buttonQueue[player].empty () && buttonQueue[player].front () == which) { - buttonQueue[player].pop (); buttonWaitPeriod[player] = drumWaitPeriod; + buttonQueue[player].pop (); const u16 hitValue = !valueStates[which] ? 50 : 51; valueStates[which] = !valueStates[which]; analogValue = (hitValue << 15) / 100 + 1; } if (IsButtonTapped (*button)) { - if (drumWaitPeriod > 0) { - if (blue && buttonWaitPeriod[player] > 0) buttonQueue[player].push (which); - buttonWaitPeriod[player] = drumWaitPeriod; - } else if (blue && cooldown[which] > 0) return 0; + if ((waitAll || blue) && buttonWaitPeriod[player] > 0) { + buttonQueue[player].push (which); + return analogValue; + } else if ((waitAll || blue) && cooldown[which] > 0) return 0; + buttonWaitPeriod[player] = drumWaitPeriod; + if (waitAll || blue) cooldown[which] = 4; - if (blue) cooldown[which] = 4; const u16 hitValue = !valueStates[which] ? 50 : 51; valueStates[which] = !valueStates[which]; analogValue = (hitValue << 15) / 100 + 1; @@ -185,30 +191,6 @@ u16 __fastcall bnusio_GetCoin (i32 a1) { u16 __fastcall bnusio_GetService (i32 a1) { return service_count; } } -void -InspectWaitTouch (const i32 a1, const i32 a2, u8 _cardData[168], const u64 _touchData) { - if (AreAllBytesZero (_cardData, 0x00, 168)) // This happens when you enter test mode. - return touchCallback (a1, a2, _cardData, _touchData); - - const bool valid = !AreAllBytesZero (_cardData, 0x50, 21); - if (valid) { - LogMessage (LogLevel::DEBUG, "Card is valid"); - } else { - memcpy (_cardData + 0x50, _cardData + 0x2C, 16); // 16 to match felica lite serial number length - LogMessage (LogLevel::DEBUG, "Card is usually not supported"); - } - - std::ostringstream oss; - for (size_t i = 0; i < 168; ++i) { - oss << std::setw (2) << std::setfill ('0') << std::hex << static_cast (_cardData[i]) << " "; - if ((i + 1) % 21 == 0) oss << "\n"; - } - - LogMessage (LogLevel::DEBUG, "A1: %d, A2: %d, Card data: \n%s", a1, a2, oss.str ().c_str ()); - - if (touchCallback) return valid ? touchCallback (a1, a2, _cardData, _touchData) : touchCallback (0, 0, _cardData, _touchData); -} - FUNCTION_PTR (i64, bnusio_Open_Original, PROC_ADDRESS ("bnusio_original.dll", "bnusio_Open")); FUNCTION_PTR (i64, bnusio_Close_Original, PROC_ADDRESS ("bnusio_original.dll", "bnusio_Close")); FUNCTION_PTR (u64, bnusio_Communication_Original, PROC_ADDRESS ("bnusio_original.dll", "bnusio_Communication"), i32); @@ -272,6 +254,8 @@ UpdateLoop () { syncCV.wait (syncLock); #endif if (exited && ++exited >= 120) ExitProcess (0); + +#ifndef ASYNC_IO if (!inited) { windowHandle = FindWindowA ("nuFoundation.Window", nullptr); InitializePoll (windowHandle); @@ -285,7 +269,6 @@ UpdateLoop () { inited = true; } -#ifndef ASYNC_IO UpdatePoll (windowHandle); #endif std::vector buffer = {}; @@ -324,8 +307,8 @@ Init () { if (config_ptr) { const toml_table_t *config = config_ptr.get (); if (const auto controller = openConfigSection (config, "controller")) { - drumWaitPeriod = static_cast (readConfigInt (controller, "wait_period", drumWaitPeriod)); - analogInput = readConfigBool (controller, "analog_input", analogInput); + drumWaitPeriod = static_cast (readConfigInt (controller, "wait_period", drumWaitPeriod)); + analogInput = readConfigBool (controller, "analog_input", analogInput); if (analogInput) LogMessage (LogLevel::WARN, "Using analog input mode. All the keyboard drum inputs have been disabled."); } auto graphics = openConfigSection (config, "graphics"); @@ -342,28 +325,31 @@ Init () { const std::unique_ptr keyConfig_ptr (openConfig (keyConfigPath), toml_free); if (keyConfig_ptr) { const toml_table_t *keyConfig = keyConfig_ptr.get (); - SetConfigValue (keyConfig, "EXIT", &EXIT); + SetConfigValue (keyConfig, "EXIT", &EXIT, &usePoll); - SetConfigValue (keyConfig, "TEST", &TEST); - SetConfigValue (keyConfig, "SERVICE", &SERVICE); - SetConfigValue (keyConfig, "DEBUG_UP", &DEBUG_UP); - SetConfigValue (keyConfig, "DEBUG_DOWN", &DEBUG_DOWN); - SetConfigValue (keyConfig, "DEBUG_ENTER", &DEBUG_ENTER); + SetConfigValue (keyConfig, "TEST", &TEST, &usePoll); + SetConfigValue (keyConfig, "SERVICE", &SERVICE, &usePoll); + SetConfigValue (keyConfig, "DEBUG_UP", &DEBUG_UP, &usePoll); + SetConfigValue (keyConfig, "DEBUG_DOWN", &DEBUG_DOWN, &usePoll); + SetConfigValue (keyConfig, "DEBUG_ENTER", &DEBUG_ENTER, &usePoll); - SetConfigValue (keyConfig, "COIN_ADD", &COIN_ADD); - SetConfigValue (keyConfig, "CARD_INSERT_1", &CARD_INSERT_1); - SetConfigValue (keyConfig, "CARD_INSERT_2", &CARD_INSERT_2); - SetConfigValue (keyConfig, "QR_DATA_READ", &QR_DATA_READ); - SetConfigValue (keyConfig, "QR_IMAGE_READ", &QR_IMAGE_READ); + SetConfigValue (keyConfig, "COIN_ADD", &COIN_ADD, &usePoll); + SetConfigValue (keyConfig, "CARD_INSERT_1", &CARD_INSERT_1, &usePoll); + SetConfigValue (keyConfig, "CARD_INSERT_2", &CARD_INSERT_2, &usePoll); + SetConfigValue (keyConfig, "QR_DATA_READ", &QR_DATA_READ, &usePoll); + SetConfigValue (keyConfig, "QR_IMAGE_READ", &QR_IMAGE_READ, &usePoll); - SetConfigValue (keyConfig, "P1_LEFT_BLUE", &P1_LEFT_BLUE); - SetConfigValue (keyConfig, "P1_LEFT_RED", &P1_LEFT_RED); - SetConfigValue (keyConfig, "P1_RIGHT_RED", &P1_RIGHT_RED); - SetConfigValue (keyConfig, "P1_RIGHT_BLUE", &P1_RIGHT_BLUE); - SetConfigValue (keyConfig, "P2_LEFT_BLUE", &P2_LEFT_BLUE); - SetConfigValue (keyConfig, "P2_LEFT_RED", &P2_LEFT_RED); - SetConfigValue (keyConfig, "P2_RIGHT_RED", &P2_RIGHT_RED); - SetConfigValue (keyConfig, "P2_RIGHT_BLUE", &P2_RIGHT_BLUE); + SetConfigValue (keyConfig, "P1_LEFT_BLUE", &P1_LEFT_BLUE, &usePoll); + SetConfigValue (keyConfig, "P1_LEFT_RED", &P1_LEFT_RED, &usePoll); + SetConfigValue (keyConfig, "P1_RIGHT_RED", &P1_RIGHT_RED, &usePoll); + SetConfigValue (keyConfig, "P1_RIGHT_BLUE", &P1_RIGHT_BLUE, &usePoll); + SetConfigValue (keyConfig, "P2_LEFT_BLUE", &P2_LEFT_BLUE, &usePoll); + SetConfigValue (keyConfig, "P2_LEFT_RED", &P2_LEFT_RED, &usePoll); + SetConfigValue (keyConfig, "P2_RIGHT_RED", &P2_RIGHT_RED, &usePoll); + SetConfigValue (keyConfig, "P2_RIGHT_BLUE", &P2_RIGHT_BLUE, &usePoll); + if (!usePoll) { + LogMessage (LogLevel::WARN, "Only Keyboard config detected, disable poll!"); + } } if (!emulateUsio && !exists (std::filesystem::current_path () / "bnusio_original.dll")) { @@ -430,7 +416,19 @@ Init () { #ifdef ASYNC_UPDATE void Update () { - if (inited) UpdatePoll (windowHandle); + if (!inited) { + windowHandle = FindWindowA ("nuFoundation.Window", nullptr); + if (usePoll) InitializePoll (windowHandle); + if (autoIme) { + currentLayout = GetKeyboardLayout (0); + auto engLayout = LoadKeyboardLayout (TEXT ("00000409"), KLF_ACTIVATE); + ActivateKeyboardLayout (engLayout, KLF_SETFORPROCESS); + } + + patches::Plugins::Init (); + inited = true; + } + UpdatePoll (windowHandle, usePoll); syncCV.notify_all (); } #endif diff --git a/src/bnusio.h b/src/bnusio.h index c964101..b0f7588 100644 --- a/src/bnusio.h +++ b/src/bnusio.h @@ -1,5 +1,5 @@ #pragma once -// #define ASYNC_UPDATE +#define ASYNC_UPDATE namespace bnusio { void Init (); void Update (); diff --git a/src/patches/versions/JPN39.cpp b/src/patches/versions/JPN39.cpp index fb71d0b..bf3c357 100644 --- a/src/patches/versions/JPN39.cpp +++ b/src/patches/versions/JPN39.cpp @@ -387,21 +387,21 @@ HOOK (i32, SetMasterVolumeSpeaker, ASLR (0x140160330), i32 a1) { return originalSetMasterVolumeSpeaker (a1 > 100 ? 100 : a1); } -std::string *fontName = nullptr; -HOOK (u8, SetupFontInfo, ASLR (0x14049D820), u64 a1, u64 a2, size_t a3, u64 a4) { - LogMessage (LogLevel::HOOKS, "SetupFontInfo was called"); - if (fontName != nullptr) delete fontName; - fontName = new std::string (reinterpret_cast (a1) + 120); - return originalSetupFontInfo (a1, a2, a3, a4); -} +// std::string *fontName = nullptr; +// HOOK (u8, SetupFontInfo, ASLR (0x14049D820), u64 a1, u64 a2, size_t a3, u64 a4) { +// LogMessage (LogLevel::HOOKS, "SetupFontInfo was called"); +// if (fontName != nullptr) delete fontName; +// fontName = new std::string (reinterpret_cast (a1) + 120); +// return originalSetupFontInfo (a1, a2, a3, a4); +// } -HOOK (u32, ReadFontInfoInt, ASLR (0x14049EAC0), u64 a1, u64 a2) { - LogMessage (LogLevel::HOOKS, "ReadFontInfoInt was called"); - const std::string attribute (reinterpret_cast (a2)); - u32 result = originalReadFontInfoInt (a1, a2); - if (fontName->starts_with ("cn_") && attribute == "offsetV") result += 1; - return result; -} +// HOOK (u32, ReadFontInfoInt, ASLR (0x14049EAC0), u64 a1, u64 a2) { +// LogMessage (LogLevel::HOOKS, "ReadFontInfoInt was called"); +// const std::string attribute (reinterpret_cast (a2)); +// u32 result = originalReadFontInfoInt (a1, a2); +// if (fontName->starts_with ("cn_") && attribute == "offsetV") result += 1; +// return result; +// } MID_HOOK (AttractDemo, ASLR (0x14045A720), SafetyHookContext &ctx) { if (TestMode::ReadTestModeValue (L"AttractDemoItem") == 1) ctx.r14 = 0; @@ -501,7 +501,6 @@ Init () { i32 yRes = 1080; bool vsync = false; bool unlockSongs = true; - bool fixLanguage = false; bool chsPatch = false; bool useLayeredfs = false; @@ -511,7 +510,6 @@ Init () { if (auto patches = openConfigSection (config_ptr.get (), "patches")) { unlockSongs = readConfigBool (patches, "unlock_songs", unlockSongs); if (auto jpn39 = openConfigSection (patches, "jpn39")) { - fixLanguage = readConfigBool (jpn39, "fix_language", fixLanguage); chsPatch = readConfigBool (jpn39, "chs_patch", chsPatch); } } @@ -733,8 +731,8 @@ Init () { WRITE_MEMORY (ASLR (0x140CD1E68), wchar_t, L"加載中..\0"); WRITE_MEMORY (ASLR (0x140CD1E50), wchar_t, L"加載中...\0"); INSTALL_MID_HOOK (ChangeLanguageType); - INSTALL_HOOK (SetupFontInfo); - INSTALL_HOOK (ReadFontInfoInt); + // INSTALL_HOOK (SetupFontInfo); + // INSTALL_HOOK (ReadFontInfoInt); } LayeredFs::RegisterBefore ([=] (const std::string &originalFileName, const std::string ¤tFileName) -> std::string { diff --git a/src/poll.cpp b/src/poll.cpp index ae6887e..cc2d778 100644 --- a/src/poll.cpp +++ b/src/poll.cpp @@ -23,7 +23,7 @@ SetKeyboardButtons () { } void -SetConfigValue (const toml_table_t *table, const char *key, Keybindings *key_bind) { +SetConfigValue (const toml_table_t *table, const char *key, Keybindings *key_bind, bool *usePoll) { const toml_array_t *array = toml_array_in (table, key); if (!array) { LogMessage (LogLevel::WARN, std::string (key) + ": Cannot find array"); @@ -42,6 +42,7 @@ SetConfigValue (const toml_table_t *table, const char *key, Keybindings *key_bin switch (value.type) { case keycode: { + *usePoll = true; for (int i = 0; i < std::size (key_bind->keycodes); i++) { if (key_bind->keycodes[i] == 0) { key_bind->keycodes[i] = value.keycode; @@ -51,6 +52,7 @@ SetConfigValue (const toml_table_t *table, const char *key, Keybindings *key_bin break; } case button: { + *usePoll = true; for (int i = 0; i < std::size (key_bind->buttons); i++) { if (key_bind->buttons[i] == SDL_CONTROLLER_BUTTON_INVALID) { key_bind->buttons[i] = value.button; @@ -60,6 +62,7 @@ SetConfigValue (const toml_table_t *table, const char *key, Keybindings *key_bin break; } case axis: { + *usePoll = true; for (int i = 0; i < std::size (key_bind->axis); i++) { if (key_bind->axis[i] == 0) { key_bind->axis[i] = value.axis; @@ -68,6 +71,7 @@ SetConfigValue (const toml_table_t *table, const char *key, Keybindings *key_bin } } case scroll: { + *usePoll = true; for (int i = 0; i < std::size (key_bind->scroll); i++) { if (key_bind->scroll[i] == 0) { key_bind->scroll[i] = value.scroll; diff --git a/src/poll.h b/src/poll.h index e16d1f3..a184ed2 100644 --- a/src/poll.h +++ b/src/poll.h @@ -65,11 +65,10 @@ struct InternalButtonState { }; bool InitializePoll (HWND windowHandle); -void UpdatePoll (HWND windowHandle); void DisposePoll (); void SetKeyboardButtons (); ConfigValue StringToConfigEnum (const char *value); -void SetConfigValue (const toml_table_t *table, const char *key, Keybindings *keybind); +void SetConfigValue (const toml_table_t *table, const char *key, Keybindings *keybind, bool *usePoll); InternalButtonState GetInternalButtonState (const Keybindings &bindings); void SetRumble (int left, int right, int length); @@ -87,6 +86,7 @@ bool IsButtonTapped (const Keybindings &bindings); float IsButtonDown (const Keybindings &bindings); #ifndef ASYNC_IO +void UpdatePoll (HWND windowHandle); bool KeyboardIsUp (const u8 keycode); bool KeyboardIsReleased (u8 keycode); bool KeyboardWasDown (u8 keycode); @@ -108,6 +108,7 @@ bool ControllerAxisWasUp (const SDLAxis axis); bool ControllerAxisIsReleased (const SDLAxis axis); bool IsButtonReleased (const Keybindings &bindings); #else +void UpdatePoll (HWND windowHandle, bool useController); void InitializeKeyboard (); void DisposeKeyboard (); #endif \ No newline at end of file diff --git a/src/pollasync.cpp b/src/pollasync.cpp index a4b3992..964ac83 100644 --- a/src/pollasync.cpp +++ b/src/pollasync.cpp @@ -38,7 +38,7 @@ SetKeyboardButtons () { } void -SetConfigValue (const toml_table_t *table, const char *key, Keybindings *key_bind) { +SetConfigValue (const toml_table_t *table, const char *key, Keybindings *key_bind, bool *usePoll) { const toml_array_t *array = toml_array_in (table, key); if (!array) { LogMessage (LogLevel::WARN, std::string (key) + ": Cannot find array"); @@ -66,6 +66,7 @@ SetConfigValue (const toml_table_t *table, const char *key, Keybindings *key_bin break; } case button: { + *usePoll = true; for (int i = 0; i < std::size (key_bind->buttons); i++) { if (key_bind->buttons[i] == SDL_CONTROLLER_BUTTON_INVALID) { key_bind->buttons[i] = value.button; @@ -75,6 +76,7 @@ SetConfigValue (const toml_table_t *table, const char *key, Keybindings *key_bin break; } case axis: { + *usePoll = true; for (int i = 0; i < std::size (key_bind->axis); i++) { if (key_bind->axis[i] == 0) { key_bind->axis[i] = value.axis; @@ -98,19 +100,35 @@ SetConfigValue (const toml_table_t *table, const char *key, Keybindings *key_bin // 钩子句柄 HHOOK keyboardHook; +HHOOK mouseHook; // 钩子回调函数 -LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) { +LRESULT CALLBACK InputProc(int nCode, WPARAM wParam, LPARAM lParam) { if (nCode == HC_ACTION) { - KBDLLHOOKSTRUCT* pKeyboard = reinterpret_cast(lParam); - DWORD keyCode = pKeyboard->vkCode; switch (wParam) { case WM_KEYDOWN: if (wndForeground) { + KBDLLHOOKSTRUCT* pKeyboard = reinterpret_cast(lParam); + DWORD keyCode = pKeyboard->vkCode; if (!currentKeyboardState[keyCode]) keyboardCount[keyCode] = MIN (keyboardCount[keyCode] + 1, maxCount); currentKeyboardState[keyCode] = true; } break; // keyup will accepted even if you're not focus in this window - case WM_KEYUP: currentKeyboardState[keyCode] = false; break; + case WM_KEYUP: { + KBDLLHOOKSTRUCT* pKeyboard = reinterpret_cast(lParam); + DWORD keyCode = pKeyboard->vkCode; + currentKeyboardState[keyCode] = false; + } break; + case WM_MOUSEWHEEL: if (wndForeground) { + MSLLHOOKSTRUCT *pMouseStruct = (MSLLHOOKSTRUCT*)lParam; + int wheelDelta = GET_WHEEL_DELTA_WPARAM(pMouseStruct->mouseData); + if (wheelDelta > 0) { + mouseWheelCount[0] = MIN (mouseWheelCount[0] + wheelDelta, maxCount); + currentMouseState.ScrolledUp = true; + } else if (wheelDelta < 0) { + mouseWheelCount[1] = MIN (mouseWheelCount[1] - wheelDelta, maxCount); + currentMouseState.ScrolledDown = true; + } + } break; } } return CallNextHookEx(keyboardHook, nCode, wParam, lParam); @@ -118,14 +136,17 @@ LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) { void InitializeKeyboard () { - keyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardProc, nullptr, 0); + keyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, InputProc, nullptr, 0); if (keyboardHook == nullptr) LogMessage (LogLevel::ERROR, "Failed to install keyboard hook!\n"); + mouseHook = SetWindowsHookEx(WH_MOUSE_LL, InputProc, nullptr, 0); + if (maxCount > 1) LogMessage (LogLevel::ERROR, "CHEATING MODE! max count is set to {}", maxCount); atexit (DisposeKeyboard); } void DisposeKeyboard () { if (keyboardHook) UnhookWindowsHookEx(keyboardHook); + if (mouseHook) UnhookWindowsHookEx(mouseHook); } // void @@ -201,7 +222,7 @@ CheckForegroundWindow (HWND processWindow) { } void -UpdatePoll (HWND windowHandle) { +UpdatePoll (HWND windowHandle, bool useController) { if (!CheckForegroundWindow (windowHandle)) return; currentMouseState.ScrolledUp = false; @@ -215,65 +236,67 @@ UpdatePoll (HWND windowHandle) { // GetCursorPos (¤tMouseState.Position); // ScreenToClient (windowHandle, ¤tMouseState.Position); - SDL_Event event; - SDL_GameController *controller; - while (SDL_PollEvent (&event) != 0) { - // LogMessage (LogLevel::DEBUG, "Receive SDL Event! type={}", (u64)event.type); - switch (event.type) { - case SDL_CONTROLLERDEVICEADDED: - if (!SDL_IsGameController (event.cdevice.which)) break; - controller = SDL_GameControllerOpen (event.cdevice.which); - if (!controller) { - LogMessage (LogLevel::ERROR, std::string ("Could not open gamecontroller ") + SDL_GameControllerNameForIndex (event.cdevice.which) - + ": " + SDL_GetError ()); - continue; - } - LogMessage (LogLevel::DEBUG, "Controller connected!"); - controllers[event.cdevice.which] = controller; - break; - case SDL_CONTROLLERDEVICEREMOVED: - LogMessage (LogLevel::DEBUG, "Controller removed!"); - if (!SDL_IsGameController (event.cdevice.which)) break; - SDL_GameControllerClose (controllers[event.cdevice.which]); - break; - case SDL_MOUSEWHEEL: - if (wndForeground) { - // LogMessage (LogLevel::DEBUG, "Mouse Wheel moves {}", event.wheel.y); - if (event.wheel.y > 0) { - mouseWheelCount[0] = MIN (mouseWheelCount[0] + event.wheel.y, maxCount); - mouseWheelCount[1] = 0; - currentMouseState.ScrolledUp = true; - } else if (event.wheel.y < 0) { - mouseWheelCount[1] = MIN (mouseWheelCount[1] - event.wheel.y, maxCount); - mouseWheelCount[0] = 0; - currentMouseState.ScrolledDown = true; + if (useController) { + SDL_Event event; + SDL_GameController *controller; + while (SDL_PollEvent (&event) != 0) { + // LogMessage (LogLevel::DEBUG, "Receive SDL Event! type={}", (u64)event.type); + switch (event.type) { + case SDL_CONTROLLERDEVICEADDED: + if (!SDL_IsGameController (event.cdevice.which)) break; + controller = SDL_GameControllerOpen (event.cdevice.which); + if (!controller) { + LogMessage (LogLevel::ERROR, std::string ("Could not open gamecontroller ") + SDL_GameControllerNameForIndex (event.cdevice.which) + + ": " + SDL_GetError ()); + continue; } - } - break; - case SDL_CONTROLLERBUTTONUP: - // keyup will accepted even if you're not focus in this window - currentControllerButtonsState[event.cbutton.button] = false; break; - case SDL_CONTROLLERBUTTONDOWN: - if (wndForeground) { - if (!currentControllerButtonsState[event.cbutton.button]) { - controllerCount[event.cbutton.button] = MIN (controllerCount[event.cbutton.button] + 1, maxCount); - } - currentControllerButtonsState[event.cbutton.button] = true; - } else LogMessage (LogLevel::WARN, "Controller button pressed but window not focused!"); - break; - case SDL_CONTROLLERAXISMOTION: - float sensorValue = event.caxis.value == 0 ? 0 : event.caxis.value / (event.caxis.value > 0 ? 32767.0f : -32768.0f); - if (wndForeground || sensorValue == 0) { - switch (event.caxis.axis) { - case SDL_CONTROLLER_AXIS_LEFTX: currentControllerAxisState.LeftRight = sensorValue; break; - case SDL_CONTROLLER_AXIS_LEFTY: currentControllerAxisState.LeftDown = sensorValue; break; - case SDL_CONTROLLER_AXIS_RIGHTX: currentControllerAxisState.RightRight = sensorValue; break; - case SDL_CONTROLLER_AXIS_RIGHTY: currentControllerAxisState.RightDown = sensorValue; break; - case SDL_CONTROLLER_AXIS_TRIGGERLEFT: currentControllerAxisState.LTriggerDown = sensorValue; break; - case SDL_CONTROLLER_AXIS_TRIGGERRIGHT: currentControllerAxisState.RTriggerDown = sensorValue; break; + LogMessage (LogLevel::DEBUG, "Controller connected!"); + controllers[event.cdevice.which] = controller; + break; + case SDL_CONTROLLERDEVICEREMOVED: + LogMessage (LogLevel::DEBUG, "Controller removed!"); + if (!SDL_IsGameController (event.cdevice.which)) break; + SDL_GameControllerClose (controllers[event.cdevice.which]); + break; + // case SDL_MOUSEWHEEL: + // if (wndForeground) { + // // LogMessage (LogLevel::DEBUG, "Mouse Wheel moves {}", event.wheel.y); + // if (event.wheel.y > 0) { + // mouseWheelCount[0] = MIN (mouseWheelCount[0] + event.wheel.y, maxCount); + // // mouseWheelCount[1] = 0; + // currentMouseState.ScrolledUp = true; + // } else if (event.wheel.y < 0) { + // mouseWheelCount[1] = MIN (mouseWheelCount[1] - event.wheel.y, maxCount); + // // mouseWheelCount[0] = 0; + // currentMouseState.ScrolledDown = true; + // } + // } + // break; + case SDL_CONTROLLERBUTTONUP: + // keyup will accepted even if you're not focus in this window + currentControllerButtonsState[event.cbutton.button] = false; break; + case SDL_CONTROLLERBUTTONDOWN: + if (wndForeground) { + if (!currentControllerButtonsState[event.cbutton.button]) { + controllerCount[event.cbutton.button] = MIN (controllerCount[event.cbutton.button] + 1, maxCount); + } + currentControllerButtonsState[event.cbutton.button] = true; + } else LogMessage (LogLevel::WARN, "Controller button pressed but window not focused!"); + break; + case SDL_CONTROLLERAXISMOTION: + float sensorValue = event.caxis.value == 0 ? 0 : event.caxis.value / (event.caxis.value > 0 ? 32767.0f : -32768.0f); + if (wndForeground || sensorValue == 0) { + switch (event.caxis.axis) { + case SDL_CONTROLLER_AXIS_LEFTX: currentControllerAxisState.LeftRight = sensorValue; break; + case SDL_CONTROLLER_AXIS_LEFTY: currentControllerAxisState.LeftDown = sensorValue; break; + case SDL_CONTROLLER_AXIS_RIGHTX: currentControllerAxisState.RightRight = sensorValue; break; + case SDL_CONTROLLER_AXIS_RIGHTY: currentControllerAxisState.RightDown = sensorValue; break; + case SDL_CONTROLLER_AXIS_TRIGGERLEFT: currentControllerAxisState.LTriggerDown = sensorValue; break; + case SDL_CONTROLLER_AXIS_TRIGGERRIGHT: currentControllerAxisState.RTriggerDown = sensorValue; break; + } } + break; } - break; } } } From 703982937d313ecee87677e1cc5cae2c7af92f7b Mon Sep 17 00:00:00 2001 From: ptmaster Date: Sun, 8 Dec 2024 22:32:02 +0800 Subject: [PATCH 6/6] add High Resolution Timer switch add WARN for experimental function --- README.md | 4 +--- dist/config.toml | 2 +- src/bnusio.cpp | 2 +- src/dllmain.cpp | 12 +++++++++--- src/patches/timer.cpp | 8 ++++---- src/patches/versions/JPN39.cpp | 14 +++++++------- 6 files changed, 23 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 1bbc25b..3f6e7f8 100644 --- a/README.md +++ b/README.md @@ -135,6 +135,4 @@ cmake -B build -S . -G "Visual Studio 17 2022" -A x64 -DCMAKE_BUILD_TYPE=Release cmake --build build --config Release --target bnusio ``` -The compiled dll of TaikoArcadeLoader will be written in the `dist` folder. - -(experimental) To enable `async update` / `async io`, you can add `-DASYNC_UPDATE` or `-DASYNC_IO` into add_definitions in CMakeLists.txt +The compiled dll of TaikoArcadeLoader will be written in the `dist` folder. \ No newline at end of file diff --git a/dist/config.toml b/dist/config.toml index a584cee..fba0b8a 100644 --- a/dist/config.toml +++ b/dist/config.toml @@ -15,7 +15,7 @@ version = "auto" # Patch version # | - JPN39: For use with Taiko JPN 39.06 # | - CHN00: For use with Taiko CHN 00.32 unlock_songs = true - +high_res_timer = true # (experimental) Enable High Resolution Timer, which might improve judgement timing [patches.chn00] # These patches are only available for version CHN00 fix_language = false # Sync test mode language to attract etc diff --git a/src/bnusio.cpp b/src/bnusio.cpp index 7d91a41..da64988 100644 --- a/src/bnusio.cpp +++ b/src/bnusio.cpp @@ -248,7 +248,7 @@ std::condition_variable syncCV; void UpdateLoop () { - LogMessage (LogLevel::WARN, "Using Async Update (experimental)!"); + LogMessage (LogLevel::WARN, "(experimental) Using Async Update!"); std::unique_lock syncLock(syncMtx); while (exited < 120) { syncCV.wait (syncLock); diff --git a/src/dllmain.cpp b/src/dllmain.cpp index b0fbcd5..9d6c166 100644 --- a/src/dllmain.cpp +++ b/src/dllmain.cpp @@ -22,6 +22,7 @@ char accessCode1[21] = "00000000000000000001"; char accessCode2[21] = "00000000000000000002"; char chipId1[33] = "00000000000000000000000000000001"; char chipId2[33] = "00000000000000000000000000000002"; +bool highResTimer = true; bool windowed = false; bool autoIme = false; bool jpLayout = false; @@ -150,7 +151,7 @@ DllMain (HMODULE module, const DWORD reason, LPVOID reserved) { LogMessage (LogLevel::INFO, "Loading config..."); #ifdef ASYNC_IO - LogMessage (LogLevel::WARN, "Using Async IO (experimental)!"); + LogMessage (LogLevel::WARN, "(experimental) Using Async IO!"); InitializeKeyboard (); #endif @@ -176,7 +177,10 @@ DllMain (HMODULE module, const DWORD reason, LPVOID reserved) { std::strcat (placeId, countryCode.c_str ()); std::strcat (placeId, "0FF0"); } - if (const auto patches = openConfigSection (config, "patches")) version = readConfigString (patches, "version", version); + if (const auto patches = openConfigSection (config, "patches")) { + version = readConfigString (patches, "version", version); + highResTimer = readConfigBool (patches, "high_res_timer", highResTimer); + } if (const auto emulation = openConfigSection (config, "emulation")) { emulateUsio = readConfigBool (emulation, "usio", emulateUsio); emulateCardReader = readConfigBool (emulation, "card_reader", emulateCardReader); @@ -266,7 +270,9 @@ DllMain (HMODULE module, const DWORD reason, LPVOID reserved) { patches::LayeredFs::Init (); patches::TestMode::Init (); - patches::Timer::Init (); + if (highResTimer) { + patches::Timer::Init (); + } LogMessage (LogLevel::INFO, "==== Finished Loading patches!"); } diff --git a/src/patches/timer.cpp b/src/patches/timer.cpp index 85f738c..5a4d249 100644 --- a/src/patches/timer.cpp +++ b/src/patches/timer.cpp @@ -29,17 +29,17 @@ namespace patches::Timer { NTSTATUS queryStatus = NtQueryTimerResolution(¤tResolution, &minimumResolution, &maximumResolution); if (queryStatus == 0) { bool setHighResolutionTimer = currentResolution > maximumResolution; - LogMessage (LogLevel::INFO, "Timer Resolution current: {}ms maximum: {}ms", currentResolution / 10000.0, maximumResolution / 10000.0); + LogMessage (LogLevel::WARN, "(experimental) Timer Resolution current: {}ms maximum: {}ms", currentResolution / 10000.0, maximumResolution / 10000.0); if (setHighResolutionTimer) { NTSTATUS status = NtSetTimerResolution(maximumResolution, TRUE, ¤tResolution); if (status == 0) { - LogMessage (LogLevel::INFO, "Successfully change Timer resolution to {}ms", maximumResolution / 10000.0); + LogMessage (LogLevel::WARN, "(experimental) Successfully change Timer resolution to {}ms", maximumResolution / 10000.0); } else { - LogMessage (LogLevel::ERROR, "Failed to change Timer resolution, status={}", status); + LogMessage (LogLevel::ERROR, "(experimental) Failed to change Timer resolution, status={}", status); } atexit (Release); } - } else LogMessage (LogLevel::ERROR, "Failed to query Timer resolution, status={}", queryStatus); + } else LogMessage (LogLevel::ERROR, "(experimental) Failed to query Timer resolution, status={}", queryStatus); } } \ No newline at end of file diff --git a/src/patches/versions/JPN39.cpp b/src/patches/versions/JPN39.cpp index bf3c357..fd4d1f4 100644 --- a/src/patches/versions/JPN39.cpp +++ b/src/patches/versions/JPN39.cpp @@ -450,12 +450,12 @@ HOOK (u64, EnsoGameManagerChechEnsoEnd, ASLR (0x1400E2A10), u64 a1, u64 a2, u64 return result; } -HOOK (DWORD*, AcquireMostCompatibleDisplayMode, ASLR (0x14064C870), i64 a1, DWORD *a2, DWORD *a3) { - LogMessage (LogLevel::DEBUG, "AcquireMostCompatibleDisplayMode {:d} {:d} {:f} {:f}", a3[0], a3[1], (float)(int)a3[2], (float)(int)a3[3]); - a3[2] = (DWORD)(int)120.0f; - LogMessage (LogLevel::DEBUG, "AcquireMostCompatibleDisplayMode {:d} {:d} {:f} {:f}", a3[0], a3[1], (float)(int)a3[2], (float)(int)a3[3]); - return originalAcquireMostCompatibleDisplayMode (a1, a2, a3); -} +// HOOK (DWORD*, AcquireMostCompatibleDisplayMode, ASLR (0x14064C870), i64 a1, DWORD *a2, DWORD *a3) { +// LogMessage (LogLevel::DEBUG, "AcquireMostCompatibleDisplayMode {:d} {:d} {:f} {:f}", a3[0], a3[1], (float)(int)a3[2], (float)(int)a3[3]); +// a3[2] = (DWORD)(int)120.0f; +// LogMessage (LogLevel::DEBUG, "AcquireMostCompatibleDisplayMode {:d} {:d} {:f} {:f}", a3[0], a3[1], (float)(int)a3[2], (float)(int)a3[3]); +// return originalAcquireMostCompatibleDisplayMode (a1, a2, a3); +// } HOOK (char, SceneTestModeLoading, ASLR (0x1404793D0), u64 a1, u64 a2, u64 a3) { LogMessage (LogLevel::DEBUG, "Begin SceneTestModeLoading"); @@ -534,7 +534,7 @@ Init () { INSTALL_HOOK (EnsoGraphicManagerPreparing); INSTALL_HOOK (EnsoGameManagerStart); INSTALL_HOOK (EnsoGameManagerChechEnsoEnd); - INSTALL_HOOK (AcquireMostCompatibleDisplayMode); + // INSTALL_HOOK (AcquireMostCompatibleDisplayMode); INSTALL_HOOK (SceneTestModeLoading); // Apply common config patch