From b5f822241025b1f0d2a0889f4ee45cc4f7116f4e Mon Sep 17 00:00:00 2001 From: Maschell Date: Fri, 3 Jan 2025 09:01:24 +0100 Subject: [PATCH 1/5] Use the existing DRCAttachCallback from VPADBASE instead of registering our own --- source/DRCAttachCallback.cpp | 76 ------------------------------------ source/DRCAttachCallback.h | 19 --------- source/function_patches.cpp | 28 ++++++------- source/main.cpp | 8 ---- 4 files changed, 13 insertions(+), 118 deletions(-) delete mode 100644 source/DRCAttachCallback.cpp delete mode 100644 source/DRCAttachCallback.h diff --git a/source/DRCAttachCallback.cpp b/source/DRCAttachCallback.cpp deleted file mode 100644 index dae2fba..0000000 --- a/source/DRCAttachCallback.cpp +++ /dev/null @@ -1,76 +0,0 @@ -#include "DRCAttachCallback.h" -#include "ButtonComboManager.h" -#include "globals.h" -#include "logger.h" - -#include - -#include -#include - -#include - -std::mutex gDRCCallbackMutex; -CCRCDCCallbackData gCCRCDCCallbackDataCurrent; -std::map gDRCCallbackData; - -void DRCAttachDetachCallbackWrapper(CCRCDCCallbackData *data, void *) { - std::lock_guard lock(gDRCCallbackMutex); - // Callbacks get called when added, so we need to save the current "data" and then pass it to newly added callbacks - memcpy(&gCCRCDCCallbackDataCurrent, data, sizeof(CCRCDCCallbackData)); - - // Call all callbacks. - for (auto &cur : gDRCCallbackData) { - if (cur.first != nullptr) { - cur.first(data, cur.second); - } - } -} - -/** - * From what I can tell `CCRCDCRegisterUVCAttachCallback` is never used by any .rpl/.rpx - * Let's add support multiple for multiple callbacks anyway, better safe than sorry. - */ -DECL_FUNCTION(void, CCRCDCRegisterUVCAttachCallback, CCRCDCCallbackDataCallback callback, void *context) { - std::lock_guard lock(gDRCCallbackMutex); - if (callback == nullptr && context == nullptr) { // Delete (all) callbacks. - real_CCRCDCRegisterUVCAttachCallback(callback, context); - gDRCCallbackData.clear(); - return; - } - if (callback != nullptr) { - // Add callback - gDRCCallbackData[callback] = context; - // Call callback - callback(&gCCRCDCCallbackDataCurrent, context); - } -} - -function_replacement_data_t drc_function_replacements[] = { - REPLACE_FUNCTION(CCRCDCRegisterUVCAttachCallback, LIBRARY_NSYSCCR, CCRCDCRegisterUVCAttachCallback), -}; - -uint32_t drc_function_replacements_size = sizeof(drc_function_replacements) / sizeof(function_replacement_data_t); - - -void DRCAttachDetachCallback(CCRCDCCallbackData *data, void *) { - if (data->attached) { - if (gButtonComboManager) { - const bool block = gButtonComboManager->hasActiveComboWithTVButton(); - VPADSetTVMenuInvalid(data->chan, block); - } - } -} - -extern "C" int CCRCDCRegisterUVCAttachCallback(void (*)(CCRCDCCallbackData *, void *), void *); - -void InitDRCAttachCallbacks() { - // Clear existing callbacks - gDRCCallbackData.clear(); - - // Add wrapper function to support multiple callbacks. - real_CCRCDCRegisterUVCAttachCallback(DRCAttachDetachCallbackWrapper, nullptr); - - // Add the real callback we want to use. - CCRCDCRegisterUVCAttachCallback(DRCAttachDetachCallback, nullptr); -} \ No newline at end of file diff --git a/source/DRCAttachCallback.h b/source/DRCAttachCallback.h deleted file mode 100644 index 936e4c8..0000000 --- a/source/DRCAttachCallback.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once -#include - -#include -#include - -struct WUT_PACKED CCRCDCCallbackData { - uint32_t attached; - VPADChan chan; - WUT_UNKNOWN_BYTES(6); -}; - -extern CCRCDCCallbackData gCCRCDCCallbackDataCurrent; -typedef void (*CCRCDCCallbackDataCallback)(CCRCDCCallbackData *, void *); - -void InitDRCAttachCallbacks(); - -extern function_replacement_data_t drc_function_replacements[]; -extern uint32_t drc_function_replacements_size; \ No newline at end of file diff --git a/source/function_patches.cpp b/source/function_patches.cpp index 9536843..d890c72 100644 --- a/source/function_patches.cpp +++ b/source/function_patches.cpp @@ -1,11 +1,10 @@ #include "ButtonComboInfo.h" #include "ButtonComboManager.h" -#include "DRCAttachCallback.h" #include "globals.h" #include +#include -#include #include #include @@ -29,28 +28,27 @@ DECL_FUNCTION(void, WPADRead, WPADChan chan, WPADStatus *data) { gButtonComboManager->UpdateInputWPAD(chan, data); } } +struct WUT_PACKED CCRCDCCallbackData { + uint32_t attached; + VPADChan chan; + WUT_UNKNOWN_BYTES(6); +}; +DECL_FUNCTION(void, __VPADBASEAttachCallback, CCRCDCCallbackData *data, void *context) { + real___VPADBASEAttachCallback(data, context); -static uint32_t lastData0 = 0; -DECL_FUNCTION(uint32_t, OSReceiveMessage, OSMessageQueue *queue, OSMessage *message, uint32_t flags) { - const uint32_t res = real_OSReceiveMessage(queue, message, flags); - if (queue == OSGetSystemMessageQueue()) { - if (message != nullptr && res) { - if (lastData0 != message->args[0]) { - if (message->args[0] == 0xFACEF000) { - InitDRCAttachCallbacks(); - } - } - lastData0 = message->args[0]; + if (data && data->attached) { + if (gButtonComboManager) { + const bool block = gButtonComboManager->hasActiveComboWithTVButton(); + VPADSetTVMenuInvalid(data->chan, block); } } - return res; } function_replacement_data_t function_replacements[] = { REPLACE_FUNCTION(VPADRead, LIBRARY_VPAD, VPADRead), REPLACE_FUNCTION(WPADRead, LIBRARY_PADSCORE, WPADRead), - REPLACE_FUNCTION(OSReceiveMessage, LIBRARY_COREINIT, OSReceiveMessage), + REPLACE_FUNCTION_VIA_ADDRESS(__VPADBASEAttachCallback, 0x31000000 + 0x0200146c - 0x00EE0100, 0x0200146c - 0x00EE0100), }; uint32_t function_replacements_size = sizeof(function_replacements) / sizeof(function_replacement_data_t); diff --git a/source/main.cpp b/source/main.cpp index 3f8a6e2..6f36e4e 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -1,5 +1,4 @@ #include "ButtonComboManager.h" -#include "DRCAttachCallback.h" #include "function_patches.h" #include "globals.h" #include "logger.h" @@ -31,11 +30,6 @@ WUMS_INITIALIZE() { OSFatal("ButtonComboModule: Failed to patch ButtonComboModule function"); } } - for (uint32_t i = 0; i < drc_function_replacements_size; i++) { - if (FunctionPatcher_AddFunctionPatch(&drc_function_replacements[i], nullptr, &patchSuccess) != FUNCTION_PATCHER_RESULT_SUCCESS || !patchSuccess) { - OSFatal("ButtonComboModule: Failed to patch ButtonComboModule function"); - } - } DEBUG_FUNCTION_LINE("Patch ButtonComboModule functions finished"); @@ -51,8 +45,6 @@ WUMS_DEINITIALIZE() { WUMS_APPLICATION_STARTS() { initLogging(); OSReport("Running ButtonComboModule " MODULE_VERSION MODULE_VERSION_EXTRA "\n"); - - InitDRCAttachCallbacks(); } WUMS_APPLICATION_ENDS() { From de08760899295644080ee58424dab41252b75f74 Mon Sep 17 00:00:00 2001 From: Maschell Date: Fri, 3 Jan 2025 09:03:58 +0100 Subject: [PATCH 2/5] Allow abort in combo detection from any controller, not just the ones which are allowed for the combo --- source/ButtonComboManager.cpp | 48 ++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/source/ButtonComboManager.cpp b/source/ButtonComboManager.cpp index ab96dd0..8f06bf1 100644 --- a/source/ButtonComboManager.cpp +++ b/source/ButtonComboManager.cpp @@ -612,36 +612,50 @@ ButtonComboModule_Error ButtonComboManager::DetectButtonCombo_Blocking(const But const uint32_t abortButton = options.abortButtonCombo; while (true) { - uint32_t buttonsHold = 0; + uint32_t buttonsHold = 0; + uint32_t buttonsHoldAbort = 0; for (int i = 0; i < 2; i++) { - VPADReadError vpad_error = VPAD_READ_UNINITIALIZED; - VPADStatus vpad_data = {}; - if (i == 0 && !(options.controllerMask & BUTTON_COMBO_MODULE_CONTROLLER_VPAD_0)) { continue; } - if (i == 1 && !(options.controllerMask & BUTTON_COMBO_MODULE_CONTROLLER_VPAD_1)) { continue; } + VPADReadError vpad_error = VPAD_READ_UNINITIALIZED; + VPADStatus vpad_data = {}; + uint32_t convertedButtons = 0; if (VPADRead(static_cast(i), &vpad_data, 1, &vpad_error) > 0 && vpad_error == VPAD_READ_SUCCESS) { - buttonsHold = remapVPADButtons(vpad_data.hold); + convertedButtons = remapVPADButtons(vpad_data.hold); } + buttonsHoldAbort |= convertedButtons; + + if (i == 0 && !(options.controllerMask & BUTTON_COMBO_MODULE_CONTROLLER_VPAD_0)) { continue; } + if (i == 1 && !(options.controllerMask & BUTTON_COMBO_MODULE_CONTROLLER_VPAD_1)) { continue; } + + buttonsHold |= convertedButtons; } for (int i = 0; i < 7; i++) { - if (i == 0 && !(options.controllerMask & BUTTON_COMBO_MODULE_CONTROLLER_WPAD_0)) { continue; } - if (i == 1 && !(options.controllerMask & BUTTON_COMBO_MODULE_CONTROLLER_WPAD_1)) { continue; } - if (i == 2 && !(options.controllerMask & BUTTON_COMBO_MODULE_CONTROLLER_WPAD_2)) { continue; } - if (i == 3 && !(options.controllerMask & BUTTON_COMBO_MODULE_CONTROLLER_WPAD_3)) { continue; } - if (i == 4 && !(options.controllerMask & BUTTON_COMBO_MODULE_CONTROLLER_WPAD_4)) { continue; } - if (i == 5 && !(options.controllerMask & BUTTON_COMBO_MODULE_CONTROLLER_WPAD_5)) { continue; } - if (i == 6 && !(options.controllerMask & BUTTON_COMBO_MODULE_CONTROLLER_WPAD_6)) { continue; } - kpad_data = {}; + + uint32_t convertedButtons = 0; + kpad_data = {}; if (KPADReadEx(static_cast(i), &kpad_data, 1, &kpad_error) > 0) { + DEBUG_FUNCTION_LINE_ERR("KPAD chan %d success %d %d", i, kpad_error, kpad_data.extensionType); if (kpad_error == KPAD_ERROR_OK && kpad_data.extensionType != 0xFF) { if (kpad_data.extensionType == WPAD_EXT_CORE || kpad_data.extensionType == WPAD_EXT_NUNCHUK) { - buttonsHold |= remapWiiMoteButtons(kpad_data.hold); + convertedButtons = remapWiiMoteButtons(kpad_data.hold); } else if (kpad_data.extensionType == WPAD_EXT_PRO_CONTROLLER) { - buttonsHold |= remapProButtons(kpad_data.pro.hold); + convertedButtons = remapProButtons(kpad_data.pro.hold); } else { - buttonsHold |= remapClassicButtons(kpad_data.classic.hold); + convertedButtons = remapClassicButtons(kpad_data.classic.hold); } } } + + buttonsHoldAbort |= convertedButtons; + + if (i == 0 && !(options.controllerMask & BUTTON_COMBO_MODULE_CONTROLLER_WPAD_0)) { continue; } + if (i == 1 && !(options.controllerMask & BUTTON_COMBO_MODULE_CONTROLLER_WPAD_1)) { continue; } + if (i == 2 && !(options.controllerMask & BUTTON_COMBO_MODULE_CONTROLLER_WPAD_2)) { continue; } + if (i == 3 && !(options.controllerMask & BUTTON_COMBO_MODULE_CONTROLLER_WPAD_3)) { continue; } + if (i == 4 && !(options.controllerMask & BUTTON_COMBO_MODULE_CONTROLLER_WPAD_4)) { continue; } + if (i == 5 && !(options.controllerMask & BUTTON_COMBO_MODULE_CONTROLLER_WPAD_5)) { continue; } + if (i == 6 && !(options.controllerMask & BUTTON_COMBO_MODULE_CONTROLLER_WPAD_6)) { continue; } + + buttonsHold |= convertedButtons; } if (buttonsHold == lastHold) { From 868efff139678ca1fb2433062fd89eed3b9dd9ff Mon Sep 17 00:00:00 2001 From: Maschell Date: Fri, 3 Jan 2025 09:05:40 +0100 Subject: [PATCH 3/5] Only try to read connected kpad controller in button combo detection --- source/ButtonComboManager.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/source/ButtonComboManager.cpp b/source/ButtonComboManager.cpp index 8f06bf1..bf10aa1 100644 --- a/source/ButtonComboManager.cpp +++ b/source/ButtonComboManager.cpp @@ -629,6 +629,10 @@ ButtonComboModule_Error ButtonComboManager::DetectButtonCombo_Blocking(const But buttonsHold |= convertedButtons; } for (int i = 0; i < 7; i++) { + WPADExtensionType type; + if (WPADProbe(static_cast(i), &type) != 0) { + continue; + } uint32_t convertedButtons = 0; kpad_data = {}; From 383cfeacd33234e64701bedd85b6ed65b772aeb2 Mon Sep 17 00:00:00 2001 From: Maschell Date: Fri, 3 Jan 2025 09:11:47 +0100 Subject: [PATCH 4/5] Init KPAD and Pro Controller support if needed --- source/ButtonComboManager.cpp | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/source/ButtonComboManager.cpp b/source/ButtonComboManager.cpp index bf10aa1..b1a53d7 100644 --- a/source/ButtonComboManager.cpp +++ b/source/ButtonComboManager.cpp @@ -602,6 +602,19 @@ ButtonComboModule_Error ButtonComboManager::DetectButtonCombo_Blocking(const But return BUTTON_COMBO_MODULE_ERROR_INVALID_ARGUMENT; } + bool doShutdownKPAD = false; + bool doDisableProController = false; + KPADStatus status; + KPADError err = KPAD_ERROR_OK; + if (KPADReadEx(WPAD_CHAN_0, &status, 0, &err) == 0 && err == KPAD_ERROR_UNINITIALIZED) { + doShutdownKPAD = true; + KPADInit(); + } + if (!WPADIsEnabledURC()) { + WPADEnableURCC(true); + doDisableProController = true; + } + KPADStatus kpad_data{}; KPADError kpad_error; @@ -611,6 +624,8 @@ ButtonComboModule_Error ButtonComboManager::DetectButtonCombo_Blocking(const But const uint32_t holdAbortTarget = options.holdAbortForInMs >> 4; // roughly ms to frames. Works because we wait 16ms in the loop const uint32_t abortButton = options.abortButtonCombo; + + ButtonComboModule_Error result = BUTTON_COMBO_MODULE_ERROR_UNKNOWN_ERROR; while (true) { uint32_t buttonsHold = 0; uint32_t buttonsHoldAbort = 0; @@ -673,16 +688,27 @@ ButtonComboModule_Error ButtonComboManager::DetectButtonCombo_Blocking(const But if (holdFor >= holdAbortTarget && lastHold == abortButton) { DEBUG_FUNCTION_LINE("Aborted button combo detection"); - return BUTTON_COMBO_MODULE_ERROR_ABORTED; + result = BUTTON_COMBO_MODULE_ERROR_ABORTED; + break; } if (holdFor >= holdForTarget) { DEBUG_FUNCTION_LINE_INFO("Detected button combo %08X", lastHold); outButtonCombo = static_cast(lastHold); + result = BUTTON_COMBO_MODULE_ERROR_SUCCESS; break; } OSSleepTicks(OSMillisecondsToTicks(16)); } - return BUTTON_COMBO_MODULE_ERROR_SUCCESS; + if (doDisableProController) { + WPADEnableURCC(false); + } + + if (doShutdownKPAD) { + KPADShutdown(); + } + + + return result; } From e01f2d0b0d66c543adae1d695332458951fa8527 Mon Sep 17 00:00:00 2001 From: Maschell Date: Fri, 3 Jan 2025 09:12:04 +0100 Subject: [PATCH 5/5] Log some additional information on invalid parameters --- source/ButtonComboManager.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/ButtonComboManager.cpp b/source/ButtonComboManager.cpp index b1a53d7..9e62b76 100644 --- a/source/ButtonComboManager.cpp +++ b/source/ButtonComboManager.cpp @@ -595,10 +595,12 @@ ButtonComboModule_Error ButtonComboManager::DetectButtonCombo_Blocking(const But std::lock_guard lock(mMutex); if (options.controllerMask == BUTTON_COMBO_MODULE_CONTROLLER_NONE) { + DEBUG_FUNCTION_LINE_WARN("Failed to detect button combo: Controller Mask was empty."); return BUTTON_COMBO_MODULE_ERROR_INVALID_ARGUMENT; } if (options.holdComboForInMs == 0 || options.holdAbortForInMs == 0 || options.abortButtonCombo == 0) { + DEBUG_FUNCTION_LINE_WARN("Failed to detect button combo: Invalid params. holdComboFor: %s ms, holdAbortFor: %d ms, abortButtonCombo: %08X", options.holdComboForInMs, options.holdAbortForInMs, options.abortButtonCombo); return BUTTON_COMBO_MODULE_ERROR_INVALID_ARGUMENT; }