diff --git a/CMakeLists.txt b/CMakeLists.txt index 8ad4037..abf3be6 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 @@ -138,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/README.md b/README.md index 984507a..3f6e7f8 100644 --- a/README.md +++ b/README.md @@ -135,4 +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. +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 7fcef72..da64988 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); @@ -47,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; @@ -55,6 +59,7 @@ int service_count = 0; bool inited = false; bool updateByCoin = false; HWND windowHandle = nullptr; +bool usePoll = false; HKL currentLayout; namespace bnusio { @@ -118,16 +123,21 @@ bnusio_GetSwIn () { return sw; } +bool waitAll = false; u16 drumWaitPeriod = 4; 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[] = { @@ -138,52 +148,40 @@ 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 bool 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) { + buttonWaitPeriod[player] = drumWaitPeriod; + buttonQueue[player].pop (); 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 ((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; - return 0; + const u16 hitValue = !valueStates[which] ? 50 : 51; + valueStates[which] = !valueStates[which]; + analogValue = (hitValue << 15) / 100 + 1; + } + return analogValue; } u16 __fastcall bnusio_GetCoin (i32 a1) { @@ -193,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); @@ -263,6 +237,65 @@ 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, "(experimental) Using Async Update!"); + std::unique_lock syncLock(syncMtx); + while (exited < 120) { + syncCV.wait (syncLock); +#endif + if (exited && ++exited >= 120) ExitProcess (0); + +#ifndef ASYNC_IO + 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); +#endif + std::vector buffer = {}; + if (IsButtonTapped (COIN_ADD)) coin_count++; + if (IsButtonTapped (SERVICE) && !testEnabled) service_count++; + if (IsButtonTapped (TEST)) testEnabled = !testEnabled; + 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); + } 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 (); @@ -274,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"); @@ -292,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")) { @@ -369,14 +405,20 @@ 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 (usePoll) InitializePoll (windowHandle); if (autoIme) { currentLayout = GetKeyboardLayout (0); auto engLayout = LoadKeyboardLayout (TEXT ("00000409"), KLF_ACTIVATE); @@ -386,31 +428,15 @@ Update () { 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 (); + UpdatePoll (windowHandle, usePoll); + 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..b0f7588 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..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; @@ -149,6 +150,11 @@ DllMain (HMODULE module, const DWORD reason, LPVOID reserved) { InitializeLogger (GetLogLevel (logLevelStr), logToFile); LogMessage (LogLevel::INFO, "Loading config..."); + #ifdef ASYNC_IO + LogMessage (LogLevel::WARN, "(experimental) Using Async IO!"); + 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); @@ -171,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); @@ -223,7 +232,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 +269,12 @@ DllMain (HMODULE module, const DWORD reason, LPVOID reserved) { patches::AmAuth::Init (); patches::LayeredFs::Init (); patches::TestMode::Init (); + + if (highResTimer) { + patches::Timer::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/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..5a4d249 --- /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::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::WARN, "(experimental) Successfully change Timer resolution to {}ms", maximumResolution / 10000.0); + } else { + LogMessage (LogLevel::ERROR, "(experimental) Failed to change Timer resolution, status={}", status); + } + atexit (Release); + } + } 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 7489607..fd4d1f4 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); } @@ -374,68 +387,85 @@ 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; } -// 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 (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 (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 (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; @@ -471,7 +501,6 @@ Init () { i32 yRes = 1080; bool vsync = false; bool unlockSongs = true; - bool fixLanguage = false; bool chsPatch = false; bool useLayeredfs = false; @@ -481,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); } } @@ -500,21 +528,19 @@ 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); + // 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 +590,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 +700,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 @@ -683,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 { @@ -696,23 +744,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 +765,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/poll.cpp b/src/poll.cpp index 64cbfb5..cc2d778 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]; @@ -325,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"); @@ -344,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; @@ -353,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; @@ -362,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; @@ -370,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; @@ -784,3 +486,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..a184ed2 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, @@ -58,17 +65,29 @@ 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 *key_bind); +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); -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 +void UpdatePoll (HWND windowHandle); +bool KeyboardIsUp (const u8 keycode); bool KeyboardIsReleased (u8 keycode); bool KeyboardWasDown (u8 keycode); bool KeyboardWasUp (u8 keycode); @@ -76,26 +95,20 @@ 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 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 new file mode 100644 index 0000000..964ac83 --- /dev/null +++ b/src/pollasync.cpp @@ -0,0 +1,482 @@ +#include "poll.h" + +#ifdef ASYNC_IO +#include "polldef.h" +extern bool jpLayout; +extern int exited; + +#ifndef MIN +#define MIN(a,b) ((a)<(b)?(a):(b)) +#endif + +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 }; +char currentMouseWheelDirection = 0; +int mouseWheelCount[2] = { 0 }; +int mouseWheelDiff[2] = { 0 }; + +int maxCount = 1; + +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, bool *usePoll) { + 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: { + *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; + break; + } + } + 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; + 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; +HHOOK mouseHook; + +// 钩子回调函数 +LRESULT CALLBACK InputProc(int nCode, WPARAM wParam, LPARAM lParam) { + if (nCode == HC_ACTION) { + 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: { + 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); +} + +void +InitializeKeyboard () { + 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 +// UpdateLoop () { +// LogMessage (LogLevel::DEBUG, "Enter Controller UpdateLoop"); + +// while (!exited) { + +// } +// } + +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, bool useController) { + 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) 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); + 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; + } + 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 +DisposePoll () { + SDL_DestroyWindow (window); + SDL_Quit (); +} + +ConfigValue +StringToConfigEnum (const char *value) { + ConfigValue rval = {}; + for (size_t i = 0; i < ConfigKeyboardButtonsCount; ++i) + if (!strcmp (value, ConfigKeyboardButtons[i].string)) { + rval.type = keycode; + rval.keycode = ConfigKeyboardButtons[i].keycode; + return rval; + } + for (const auto &[string, button_] : ConfigControllerButtons) + if (!strcmp (value, string)) { + rval.type = button; + rval.button = button_; + return rval; + } + for (const auto &[string, axis_] : ConfigControllerAXIS) + if (!strcmp (value, string)) { + rval.type = axis; + rval.axis = axis_; + return rval; + } + for (auto &[string, scroll_] : ConfigMouseScroll) + if (!strcmp (value, string)) { + rval.type = scroll; + rval.scroll = scroll_; + return rval; + } + + LogMessage (LogLevel::ERROR, std::string (value) + ": Unknown value"); + return rval; +} + +void +SetRumble (int left, int right, int length) { + for (auto &controller : controllers) { + if (!controller || !SDL_GameControllerHasRumble (controller)) continue; + SDL_GameControllerRumble (controller, left, right, length); + } +} + +bool +KeyboardIsDown (const uint8_t keycode) { + return currentKeyboardState[keycode]; +} + +int maxKeyboardCount = 1; +bool +KeyboardIsTapped (const uint8_t keycode) { + if (keyboardCount[keycode] > 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) { + if (scroll == MOUSE_SCROLL_UP) return GetMouseScrollUp (); + else return GetMouseScrollDown (); +} + +int maxWheelCount = 1; +bool +GetMouseScrollIsTapped (const Scroll scroll) { + 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 +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