diff --git a/Dockerfile b/Dockerfile index 523d7cd..15e7022 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,7 @@ -FROM ghcr.io/wiiu-env/devkitppc:20241128 +FROM ghcr.io/wiiu-env/devkitppc:20250608 COPY --from=ghcr.io/wiiu-env/libbuttoncombo:20250125-cb22627 /artifacts $DEVKITPRO COPY --from=ghcr.io/wiiu-env/libfunctionpatcher:20241012 /artifacts $DEVKITPRO COPY --from=ghcr.io/wiiu-env/wiiumodulesystem:20240424 /artifacts $DEVKITPRO -WORKDIR project +WORKDIR /project diff --git a/README.md b/README.md index 6a3cd9c..2dc00a6 100644 --- a/README.md +++ b/README.md @@ -1,29 +1,61 @@ +# ButtonComboModule + [![CI-Release](https://github.com/wiiu-env/ButtonComboModule/actions/workflows/ci.yml/badge.svg)](https://github.com/wiiu-env/ButtonComboModule/actions/workflows/ci.yml) +**ButtonComboModule** is a Wii U Module System (WUMS) module that provides system-wide button combination detection. It +allows other homebrew applications and modules to easily register callbacks for specific button presses or holds across +various controllers (GamePad, Pro Controller, Wii Remote, etc.). + ## Usage -(`[ENVIRONMENT]` is a placeholder for the actual environment name.) -1. Copy the file `ButtonComboModule.wms` into `sd:/wiiu/environments/[ENVIRONMENT]/modules`. -2. Requires the [WUMSLoader](https://github.com/wiiu-env/WUMSLoader) in `sd:/wiiu/environments/[ENVIRONMENT]/modules/setup`. -3. Requires the [FunctionPatcherModule](https://github.com/wiiu-env/FunctionPatcherModule) in `sd:/wiiu/environments/[ENVIRONMENT]/modules`. +(`[ENVIRONMENT]` is a placeholder for the actual environment name, e.g., `tiramisu` or `aroma`.) + +1. Copy the file `ButtonComboModule.wms` into `sd:/wiiu/environments/[ENVIRONMENT]/modules`. +2. Requires the [WUMSLoader](https://github.com/wiiu-env/WUMSLoader) in + `sd:/wiiu/environments/[ENVIRONMENT]/modules/setup`. +3. Requires the [FunctionPatcherModule](https://github.com/wiiu-env/FunctionPatcherModule) in + `sd:/wiiu/environments/[ENVIRONMENT]/modules`. + +## Development + +### Homebrew Applications (.rpx / .wuhb) + +If you are developing a standard homebrew application and want to use system-wide button combos, you should use the +**libbuttoncombo** client library. + +* **Repository**: [wiiu-env/libbuttoncombo](https://github.com/wiiu-env/libbuttoncombo) + +### WUPS Plugins (.wps) + +If you are developing a plugin for the Wii U Plugin System (WUPS), you **should not** use `libbuttoncombo`. -## Buildflags +The [WiiUPluginSystem](https://github.com/wiiu-env/WiiUPluginSystem) (WUPS) library already provides built-in wrappers +for the ButtonComboModule. You can use the WUPS API directly to register combos without linking an external library. -### Logging -Building via `make` only logs errors (via OSReport). To enable logging via the [LoggingModule](https://github.com/wiiu-env/LoggingModule) set `DEBUG` to `1` or `VERBOSE`. +## Building -`make` Logs errors only (via OSReport). -`make DEBUG=1` Enables information and error logging via [LoggingModule](https://github.com/wiiu-env/LoggingModule). -`make DEBUG=VERBOSE` Enables verbose information and error logging via [LoggingModule](https://github.com/wiiu-env/LoggingModule). +To build this module, you need **devkitPro** installed with `wut` and `wums`. You also need the `libfunctionpatcher` +libraries installed. -If the [LoggingModule](https://github.com/wiiu-env/LoggingModule) is not present, it'll fallback to UDP (Port 4405) and [CafeOS](https://github.com/wiiu-env/USBSerialLoggingModule) logging. +### Build Flags (Logging) -## Building using the Dockerfile +Building via `make` only logs critical errors via OSReport by default. To enable verbose logging via +the [LoggingModule](https://github.com/wiiu-env/LoggingModule), set `DEBUG` to `1` or `VERBOSE`. -It's possible to use a docker image for building. This way you don't need anything installed on your host system. +* `make`: Logs errors only (via OSReport). +* `make DEBUG=1`: Enables information and error logging via [LoggingModule](https://github.com/wiiu-env/LoggingModule). +* `make DEBUG=VERBOSE`: Enables verbose information and error logging + via [LoggingModule](https://github.com/wiiu-env/LoggingModule). + +If the [LoggingModule](https://github.com/wiiu-env/LoggingModule) is not present, it will fallback to UDP (Port 4405) +and [USBSerialLoggingModule](https://github.com/wiiu-env/USBSerialLoggingModule) logging. + +### Building using Docker + +It is possible to use a Docker image for building. This way, you don't need anything installed on your host system. ``` -# Build docker image (only needed once) +# Build Docker image (only needed once) docker build . -t buttoncombomodule-builder # make @@ -33,6 +65,14 @@ docker run -it --rm -v ${PWD}:/project buttoncombomodule-builder make docker run -it --rm -v ${PWD}:/project buttoncombomodule-builder make clean ``` -## Format the code via docker +## Formatting + +You can format the code via Docker: + +``` +docker run --rm -v ${PWD}:/src ghcr.io/wiiu-env/clang-format:13.0.0-2 -r ./source -i +``` + +## License -`docker run --rm -v ${PWD}:/src ghcr.io/wiiu-env/clang-format:13.0.0-2 -r ./source -i` \ No newline at end of file +This module is licensed under the **GPL-3.0**. \ No newline at end of file diff --git a/source/ButtonComboInfoDown.cpp b/source/ButtonComboInfoDown.cpp index 275b6e2..024fc64 100644 --- a/source/ButtonComboInfoDown.cpp +++ b/source/ButtonComboInfoDown.cpp @@ -42,7 +42,7 @@ void ButtonComboInfoDown::UpdateInput( DEBUG_FUNCTION_LINE("Calling callback [%08X](controller: %08X, context: %08X) for \"%s\" [handle: %08X], pressed down %08X", mCallback, controller, mContext, mLabel.c_str(), getHandle().handle, mCombo); mCallback(controller, getHandle(), mContext); } else { - DEBUG_FUNCTION_LINE_WARN("Callback was null for combo %08X", getHandle()); + DEBUG_FUNCTION_LINE_WARN("Callback was null for combo %p", getHandle().handle); } } prevButtonCombo = pressedButton; diff --git a/source/ButtonComboInfoHold.cpp b/source/ButtonComboInfoHold.cpp index 959fdb0..9c9d088 100644 --- a/source/ButtonComboInfoHold.cpp +++ b/source/ButtonComboInfoHold.cpp @@ -55,7 +55,7 @@ void ButtonComboInfoHold::UpdateInput(const ButtonComboModule_ControllerTypes co mCallback(controller, getHandle(), mContext); } else { - DEBUG_FUNCTION_LINE_WARN("Callback was null for combo %08X", getHandle()); + DEBUG_FUNCTION_LINE_WARN("Callback was null for combo %p", getHandle().handle); } holdInformation.callbackTriggered = true; } diff --git a/source/ButtonComboManager.cpp b/source/ButtonComboManager.cpp index e451e71..3952437 100644 --- a/source/ButtonComboManager.cpp +++ b/source/ButtonComboManager.cpp @@ -9,6 +9,7 @@ #include #include +#include #include namespace { @@ -367,20 +368,21 @@ void ButtonComboManager::AddCombo(std::shared_ptr newComboInf outHandle = newComboInfo->getHandle(); mCombos.emplace_front(std::move(newComboInfo)); - const auto block = hasActiveComboWithTVButton(); - VPADSetTVMenuInvalid(VPAD_CHAN_0, block); - VPADSetTVMenuInvalid(VPAD_CHAN_1, block); + UpdateTVMenuBlocking(); } ButtonComboModule_Error ButtonComboManager::RemoveCombo(ButtonComboModule_ComboHandle handle) { std::lock_guard lock(mMutex); + + if (mIsIterating) { + mCombosToRemove.push_back(handle); + return BUTTON_COMBO_MODULE_ERROR_SUCCESS; + } + if (!remove_first_if(mCombos, [handle](const auto &combo) { return combo->getHandle() == handle; })) { - DEBUG_FUNCTION_LINE_WARN("Failed to remove combo by handle %08X", handle); + DEBUG_FUNCTION_LINE_WARN("Failed to remove combo by handle %p", handle.handle); } else { - const auto block = hasActiveComboWithTVButton(); - - VPADSetTVMenuInvalid(VPAD_CHAN_0, block); - VPADSetTVMenuInvalid(VPAD_CHAN_1, block); + UpdateTVMenuBlocking(); } return BUTTON_COMBO_MODULE_ERROR_SUCCESS; @@ -431,12 +433,36 @@ void ButtonComboManager::UpdateInputVPAD(const VPADChan chan, const VPADStatus * mVPADButtonBuffer[usedBufferSize - i - 1] = remapVPADButtons(buffer[i].hold); } - for (const auto &combo : mCombos) { - if (combo->getStatus() != BUTTON_COMBO_MODULE_COMBO_STATUS_VALID) { - continue; - } - combo->UpdateInput(controller, std::span(mVPADButtonBuffer.data(), usedBufferSize)); + UpdateInputsLocked(controller, std::span(mVPADButtonBuffer.data(), usedBufferSize)); + } +} + +void ButtonComboManager::UpdateTVMenuBlocking() { + const auto block = hasActiveComboWithTVButton(); + VPADSetTVMenuInvalid(VPAD_CHAN_0, block); + VPADSetTVMenuInvalid(VPAD_CHAN_1, block); +} + +void ButtonComboManager::UpdateInputsLocked(const ButtonComboModule_ControllerTypes controller, const std::span pressedButtons) { + std::lock_guard lock(mMutex); + mIsIterating++; + for (const auto &combo : mCombos) { + if (combo->getStatus() != BUTTON_COMBO_MODULE_COMBO_STATUS_VALID) { + continue; } + combo->UpdateInput(controller, pressedButtons); + } + mIsIterating--; + + // Remove pending removals if existing + if (mIsIterating == 0 && !mCombosToRemove.empty()) { + for (auto handle : mCombosToRemove) { + remove_first_if(mCombos, [handle](const auto &combo) { return combo->getHandle() == handle; }); + } + mCombosToRemove.clear(); + + // Update TV Menu blocking status once after all removals + UpdateTVMenuBlocking(); } } @@ -479,18 +505,12 @@ void ButtonComboManager::UpdateInputWPAD(const WPADChan chan, WPADStatus *data) default: return; } - { - std::lock_guard lock(mMutex); - for (const auto &combo : mCombos) { - if (combo->getStatus() != BUTTON_COMBO_MODULE_COMBO_STATUS_VALID) { - continue; - } - combo->UpdateInput(controller, std::span(&pressedButtons, 1)); - } - } + + UpdateInputsLocked(controller, std::span(&pressedButtons, 1)); } ButtonComboInfoIF *ButtonComboManager::GetComboInfoForHandle(const ButtonComboModule_ComboHandle handle) const { + std::lock_guard lock(mMutex); for (const auto &combo : mCombos) { if (combo->getHandle() == handle) { return combo.get(); @@ -554,9 +574,7 @@ ButtonComboModule_Error ButtonComboManager::UpdateButtonCombo(const ButtonComboM comboInfo->setStatus(CheckComboStatus(*comboInfo)); outComboStatus = comboInfo->getStatus(); - const auto block = hasActiveComboWithTVButton(); - VPADSetTVMenuInvalid(VPAD_CHAN_0, block); - VPADSetTVMenuInvalid(VPAD_CHAN_1, block); + UpdateTVMenuBlocking(); return BUTTON_COMBO_MODULE_ERROR_SUCCESS; } @@ -603,7 +621,7 @@ ButtonComboModule_Error ButtonComboManager::GetButtonComboInfoEx(const ButtonCom std::lock_guard lock(mMutex); const auto *comboInfo = GetComboInfoForHandle(handle); if (!comboInfo) { - DEBUG_FUNCTION_LINE_ERR("ButtonComboModule_GetButtonComboInfo failed to get manager for handle %08X", handle); + DEBUG_FUNCTION_LINE_ERR("ButtonComboModule_GetButtonComboInfo failed to get manager for handle %p", handle.handle); return BUTTON_COMBO_MODULE_ERROR_INVALID_ARGUMENT; } outOptions = comboInfo->getComboInfoEx(); @@ -630,7 +648,7 @@ ButtonComboModule_Error ButtonComboManager::DetectButtonCombo_Blocking(const But } 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); + DEBUG_FUNCTION_LINE_WARN("Failed to detect button combo: Invalid params. holdComboFor: %d ms, holdAbortFor: %d ms, abortButtonCombo: %08X", options.holdComboForInMs, options.holdAbortForInMs, options.abortButtonCombo); return BUTTON_COMBO_MODULE_ERROR_INVALID_ARGUMENT; } diff --git a/source/ButtonComboManager.h b/source/ButtonComboManager.h index afead3b..65b3454 100644 --- a/source/ButtonComboManager.h +++ b/source/ButtonComboManager.h @@ -19,16 +19,13 @@ class ButtonComboManager { static std::optional> CreateComboInfo(const ButtonComboModule_ComboOptions &options, ButtonComboModule_Error &err); - [[nodiscard]] ButtonComboInfoIF *GetComboInfoForHandle(ButtonComboModule_ComboHandle handle) const; - void UpdateInputVPAD(VPADChan chan, const VPADStatus *buffer, uint32_t bufferSize, const VPADReadError *error); + void UpdateTVMenuBlocking(); void UpdateInputWPAD(WPADChan chan, WPADStatus *data); bool hasActiveComboWithTVButton(); - ButtonComboModule_ComboStatus CheckComboStatus(const ButtonComboInfoIF &other); - void AddCombo(std::shared_ptr newComboInfo, ButtonComboModule_ComboHandle &outHandle, ButtonComboModule_ComboStatus &outStatus); ButtonComboModule_Error RemoveCombo(ButtonComboModule_ComboHandle handle); @@ -56,9 +53,17 @@ class ButtonComboManager { ButtonComboModule_Error DetectButtonCombo_Blocking(const ButtonComboModule_DetectButtonComboOptions &options, ButtonComboModule_Buttons &outButtonCombo); private: + [[nodiscard]] ButtonComboInfoIF *GetComboInfoForHandle(ButtonComboModule_ComboHandle handle) const; + + void UpdateInputsLocked(ButtonComboModule_ControllerTypes controller, std::span pressedButtons); + + ButtonComboModule_ComboStatus CheckComboStatus(const ButtonComboInfoIF &other); + std::forward_list> mCombos; + std::vector mCombosToRemove; + int mIsIterating = 0; std::vector mVPADButtonBuffer; - std::mutex mMutex; - std::mutex mDetectButtonsMutex; + mutable std::recursive_mutex mMutex; + std::recursive_mutex mDetectButtonsMutex; bool mInButtonComboDetection = false; }; \ No newline at end of file diff --git a/source/export.cpp b/source/export.cpp index 24c1e20..9529859 100644 --- a/source/export.cpp +++ b/source/export.cpp @@ -13,7 +13,8 @@ ButtonComboModule_Error ButtonComboModule_AddButtonCombo(const ButtonComboModule return BUTTON_COMBO_MODULE_ERROR_INVALID_ARGUMENT; } - if (!gButtonComboManager) { + const auto comboManager = gButtonComboManager; + if (!comboManager) { return BUTTON_COMBO_MODULE_ERROR_UNKNOWN_ERROR; } @@ -26,7 +27,7 @@ ButtonComboModule_Error ButtonComboModule_AddButtonCombo(const ButtonComboModule ButtonComboModule_ComboHandle handle; ButtonComboModule_ComboStatus tmpStatus = BUTTON_COMBO_MODULE_COMBO_STATUS_INVALID_STATUS; - gButtonComboManager->AddCombo(*comboInfoMaybe, handle, tmpStatus); + comboManager->AddCombo(*comboInfoMaybe, handle, tmpStatus); if (outStatus) { *outStatus = tmpStatus; } *outHandle = handle; @@ -38,12 +39,13 @@ ButtonComboModule_Error ButtonComboModule_RemoveButtonCombo(const ButtonComboMod return BUTTON_COMBO_MODULE_ERROR_INVALID_ARGUMENT; } - if (!gButtonComboManager) { + const auto comboManager = gButtonComboManager; + if (!comboManager) { DEBUG_FUNCTION_LINE_ERR("gButtonComboManager was nullptr"); return BUTTON_COMBO_MODULE_ERROR_UNKNOWN_ERROR; } - return gButtonComboManager->RemoveCombo(handle); + return comboManager->RemoveCombo(handle); } ButtonComboModule_Error ButtonComboModule_GetButtonComboStatus(const ButtonComboModule_ComboHandle handle, @@ -52,12 +54,13 @@ ButtonComboModule_Error ButtonComboModule_GetButtonComboStatus(const ButtonCombo return BUTTON_COMBO_MODULE_ERROR_INVALID_ARGUMENT; } - if (!gButtonComboManager) { + const auto comboManager = gButtonComboManager; + if (!comboManager) { DEBUG_FUNCTION_LINE_ERR("gButtonComboManager was nullptr"); return BUTTON_COMBO_MODULE_ERROR_UNKNOWN_ERROR; } - return gButtonComboManager->GetButtonComboStatus(handle, *outComboStatus); + return comboManager->GetButtonComboStatus(handle, *outComboStatus); } ButtonComboModule_Error ButtonComboModule_UpdateButtonComboMeta(const ButtonComboModule_ComboHandle handle, @@ -65,12 +68,14 @@ ButtonComboModule_Error ButtonComboModule_UpdateButtonComboMeta(const ButtonComb if (handle == nullptr || options == nullptr) { return BUTTON_COMBO_MODULE_ERROR_INVALID_ARGUMENT; } - if (!gButtonComboManager) { + + const auto comboManager = gButtonComboManager; + if (!comboManager) { DEBUG_FUNCTION_LINE_ERR("gButtonComboManager was nullptr"); return BUTTON_COMBO_MODULE_ERROR_UNKNOWN_ERROR; } - return gButtonComboManager->UpdateButtonComboMeta(handle, *options); + return comboManager->UpdateButtonComboMeta(handle, *options); } ButtonComboModule_Error ButtonComboModule_UpdateButtonComboCallback(const ButtonComboModule_ComboHandle handle, @@ -78,12 +83,14 @@ ButtonComboModule_Error ButtonComboModule_UpdateButtonComboCallback(const Button if (handle == nullptr || options == nullptr) { return BUTTON_COMBO_MODULE_ERROR_INVALID_ARGUMENT; } - if (!gButtonComboManager) { + + const auto comboManager = gButtonComboManager; + if (!comboManager) { DEBUG_FUNCTION_LINE_ERR("gButtonComboManager was nullptr"); return BUTTON_COMBO_MODULE_ERROR_UNKNOWN_ERROR; } - return gButtonComboManager->UpdateButtonComboCallback(handle, *options); + return comboManager->UpdateButtonComboCallback(handle, *options); } ButtonComboModule_Error ButtonComboModule_UpdateControllerMask(const ButtonComboModule_ComboHandle handle, @@ -93,13 +100,14 @@ ButtonComboModule_Error ButtonComboModule_UpdateControllerMask(const ButtonCombo return BUTTON_COMBO_MODULE_ERROR_INVALID_ARGUMENT; } - if (!gButtonComboManager) { + const auto comboManager = gButtonComboManager; + if (!comboManager) { DEBUG_FUNCTION_LINE_ERR("gButtonComboManager was nullptr"); return BUTTON_COMBO_MODULE_ERROR_UNKNOWN_ERROR; } ButtonComboModule_ComboStatus tmpStatus = BUTTON_COMBO_MODULE_COMBO_STATUS_INVALID_STATUS; - auto res = gButtonComboManager->UpdateControllerMask(handle, controllerMask, tmpStatus); + auto res = comboManager->UpdateControllerMask(handle, controllerMask, tmpStatus); if (outComboStatus) { *outComboStatus = tmpStatus; } return res; } @@ -111,13 +119,14 @@ ButtonComboModule_Error ButtonComboModule_UpdateButtonCombo(const ButtonComboMod return BUTTON_COMBO_MODULE_ERROR_INVALID_ARGUMENT; } - if (!gButtonComboManager) { + const auto comboManager = gButtonComboManager; + if (!comboManager) { DEBUG_FUNCTION_LINE_ERR("gButtonComboManager was nullptr"); return BUTTON_COMBO_MODULE_ERROR_UNKNOWN_ERROR; } ButtonComboModule_ComboStatus tmpStatus = BUTTON_COMBO_MODULE_COMBO_STATUS_INVALID_STATUS; - auto res = gButtonComboManager->UpdateButtonCombo(handle, combo, tmpStatus); + auto res = comboManager->UpdateButtonCombo(handle, combo, tmpStatus); if (outComboStatus) { *outComboStatus = tmpStatus; } return res; } @@ -128,12 +137,13 @@ ButtonComboModule_Error ButtonComboModule_UpdateHoldDuration(const ButtonComboMo return BUTTON_COMBO_MODULE_ERROR_INVALID_ARGUMENT; } - if (!gButtonComboManager) { + const auto comboManager = gButtonComboManager; + if (!comboManager) { DEBUG_FUNCTION_LINE_ERR("gButtonComboManager was nullptr"); return BUTTON_COMBO_MODULE_ERROR_UNKNOWN_ERROR; } - return gButtonComboManager->UpdateHoldDuration(handle, holdDurationInFrames); + return comboManager->UpdateHoldDuration(handle, holdDurationInFrames); } ButtonComboModule_Error ButtonComboModule_GetButtonComboMeta(const ButtonComboModule_ComboHandle handle, @@ -142,12 +152,13 @@ ButtonComboModule_Error ButtonComboModule_GetButtonComboMeta(const ButtonComboMo return BUTTON_COMBO_MODULE_ERROR_INVALID_ARGUMENT; } - if (!gButtonComboManager) { + const auto comboManager = gButtonComboManager; + if (!comboManager) { DEBUG_FUNCTION_LINE_ERR("gButtonComboManager was nullptr"); return BUTTON_COMBO_MODULE_ERROR_UNKNOWN_ERROR; } - return gButtonComboManager->GetButtonComboMeta(handle, *outOptions); + return comboManager->GetButtonComboMeta(handle, *outOptions); } ButtonComboModule_Error ButtonComboModule_GetButtonComboCallback(const ButtonComboModule_ComboHandle handle, @@ -156,12 +167,13 @@ ButtonComboModule_Error ButtonComboModule_GetButtonComboCallback(const ButtonCom return BUTTON_COMBO_MODULE_ERROR_INVALID_ARGUMENT; } - if (!gButtonComboManager) { + const auto comboManager = gButtonComboManager; + if (!comboManager) { DEBUG_FUNCTION_LINE_ERR("gButtonComboManager was nullptr"); return BUTTON_COMBO_MODULE_ERROR_UNKNOWN_ERROR; } - return gButtonComboManager->GetButtonComboCallback(handle, *outOptions); + return comboManager->GetButtonComboCallback(handle, *outOptions); } ButtonComboModule_Error ButtonComboModule_GetButtonComboInfoEx(const ButtonComboModule_ComboHandle handle, @@ -170,12 +182,13 @@ ButtonComboModule_Error ButtonComboModule_GetButtonComboInfoEx(const ButtonCombo return BUTTON_COMBO_MODULE_ERROR_INVALID_ARGUMENT; } - if (!gButtonComboManager) { + const auto comboManager = gButtonComboManager; + if (!comboManager) { DEBUG_FUNCTION_LINE_ERR("gButtonComboManager was nullptr"); return BUTTON_COMBO_MODULE_ERROR_UNKNOWN_ERROR; } - return gButtonComboManager->GetButtonComboInfoEx(handle, *outOptions); + return comboManager->GetButtonComboInfoEx(handle, *outOptions); } ButtonComboModule_Error ButtonComboModule_CheckComboAvailable(const ButtonComboModule_ButtonComboOptions *options, @@ -183,12 +196,13 @@ ButtonComboModule_Error ButtonComboModule_CheckComboAvailable(const ButtonComboM if (options == nullptr || outStatus == nullptr) { return BUTTON_COMBO_MODULE_ERROR_INVALID_ARGUMENT; } - if (!gButtonComboManager) { + const auto comboManager = gButtonComboManager; + if (!comboManager) { DEBUG_FUNCTION_LINE_ERR("gButtonComboManager was nullptr"); return BUTTON_COMBO_MODULE_ERROR_UNKNOWN_ERROR; } - *outStatus = gButtonComboManager->CheckComboAvailable(*options); + *outStatus = comboManager->CheckComboAvailable(*options); return BUTTON_COMBO_MODULE_ERROR_SUCCESS; } @@ -198,12 +212,13 @@ ButtonComboModule_Error ButtonComboModule_DetectButtonCombo_Blocking(const Butto return BUTTON_COMBO_MODULE_ERROR_INVALID_ARGUMENT; } - if (!gButtonComboManager) { + const auto comboManager = gButtonComboManager; + if (!comboManager) { DEBUG_FUNCTION_LINE_ERR("gButtonComboManager was nullptr"); return BUTTON_COMBO_MODULE_ERROR_UNKNOWN_ERROR; } - return gButtonComboManager->DetectButtonCombo_Blocking(*options, *outButtonCombo); + return comboManager->DetectButtonCombo_Blocking(*options, *outButtonCombo); } ButtonComboModule_Error ButtonComboModule_GetVersion(ButtonComboModule_APIVersion *outVersion) { diff --git a/source/function_patches.cpp b/source/function_patches.cpp index d890c72..89ed590 100644 --- a/source/function_patches.cpp +++ b/source/function_patches.cpp @@ -11,10 +11,12 @@ DECL_FUNCTION(int32_t, VPADRead, VPADChan chan, VPADStatus *buffer, uint32_t buffer_size, VPADReadError *error) { VPADReadError real_error; const int32_t result = real_VPADRead(chan, buffer, buffer_size, &real_error); - if (result > 0 && real_error == VPAD_READ_SUCCESS && gButtonComboManager) { - gButtonComboManager->UpdateInputVPAD(chan, buffer, result > static_cast(buffer_size) ? buffer_size : result, error); - } + if (result > 0 && real_error == VPAD_READ_SUCCESS) { + if (const auto comboManager = gButtonComboManager; comboManager) { + comboManager->UpdateInputVPAD(chan, buffer, result > static_cast(buffer_size) ? buffer_size : result, error); + } + } if (error) { *error = real_error; } @@ -24,8 +26,8 @@ DECL_FUNCTION(int32_t, VPADRead, VPADChan chan, VPADStatus *buffer, uint32_t buf DECL_FUNCTION(void, WPADRead, WPADChan chan, WPADStatus *data) { real_WPADRead(chan, data); - if (gButtonComboManager) { - gButtonComboManager->UpdateInputWPAD(chan, data); + if (const auto comboManager = gButtonComboManager; comboManager) { + comboManager->UpdateInputWPAD(chan, data); } } struct WUT_PACKED CCRCDCCallbackData { @@ -38,8 +40,8 @@ DECL_FUNCTION(void, __VPADBASEAttachCallback, CCRCDCCallbackData *data, void *co real___VPADBASEAttachCallback(data, context); if (data && data->attached) { - if (gButtonComboManager) { - const bool block = gButtonComboManager->hasActiveComboWithTVButton(); + if (const auto comboManager = gButtonComboManager; comboManager) { + const bool block = comboManager->hasActiveComboWithTVButton(); VPADSetTVMenuInvalid(data->chan, block); } } diff --git a/source/globals.cpp b/source/globals.cpp index 0faee48..c88a785 100644 --- a/source/globals.cpp +++ b/source/globals.cpp @@ -1,4 +1,4 @@ #include "globals.h" #include "ButtonComboManager.h" -std::unique_ptr gButtonComboManager = {}; \ No newline at end of file +std::shared_ptr gButtonComboManager = {}; \ No newline at end of file diff --git a/source/globals.h b/source/globals.h index d94388d..0fb4b30 100644 --- a/source/globals.h +++ b/source/globals.h @@ -2,4 +2,4 @@ class ButtonComboManager; -extern std::unique_ptr gButtonComboManager; \ No newline at end of file +extern std::shared_ptr gButtonComboManager; \ No newline at end of file