diff --git a/src/DRCAttachCallback.cpp b/src/DRCAttachCallback.cpp new file mode 100644 index 0000000..2414499 --- /dev/null +++ b/src/DRCAttachCallback.cpp @@ -0,0 +1,67 @@ +#include "DRCAttachCallback.h" +#include "retain_vars.hpp" +#include "utils/logger.h" +#include +#include +#include +#include + +std::mutex gDRCCallbackMutex; +CCRCDCCallbackData gCCRCDCCallbackDataCurrent; +std::map gDRCCallbackData; + +void DRCAttachDetachCallbackWrapper(CCRCDCCallbackData *data, void *context) { + 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 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); + } +} + +WUPS_MUST_REPLACE(CCRCDCRegisterUVCAttachCallback, WUPS_LOADER_LIBRARY_NSYSCCR, CCRCDCRegisterUVCAttachCallback); + +void DRCAttachDetachCallback(CCRCDCCallbackData *data, void *context) { + gBlockDRCScreenshots = !data->attached; + + if (!data->attached) { + DEBUG_FUNCTION_LINE("Block DRC screenshots"); + } + OSMemoryBarrier(); +} + +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/src/DRCAttachCallback.h b/src/DRCAttachCallback.h new file mode 100644 index 0000000..e02c08d --- /dev/null +++ b/src/DRCAttachCallback.h @@ -0,0 +1,14 @@ +#pragma once +#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(); \ No newline at end of file diff --git a/src/config.cpp b/src/config.cpp index e332a70..f2ffbb8 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -93,7 +93,6 @@ void InitConfig() { } } - void multipleValueItemCallback(ConfigItemMultipleValues *item, uint32_t newValue) { if (item && item->configId) { DEBUG_FUNCTION_LINE("New value in %s changed: %d", item->configId, newValue); diff --git a/src/function_patcher.cpp b/src/function_patcher.cpp index bd8e6d5..1e11a9b 100644 --- a/src/function_patcher.cpp +++ b/src/function_patcher.cpp @@ -59,6 +59,10 @@ void RequestScreenshot() { } } if (gImageSource == IMAGE_SOURCE_TV_AND_DRC || gImageSource == IMAGE_SOURCE_DRC) { + if (gBlockDRCScreenshots) { + DEBUG_FUNCTION_LINE("Screenshots are blocked for DRC because it's not connected"); + return; + } if (gTakeScreenshotDRC == SCREENSHOT_STATE_READY) { DEBUG_FUNCTION_LINE("Requested screenshot for DRC!"); gTakeScreenshotDRC = SCREENSHOT_STATE_REQUESTED; diff --git a/src/main.cpp b/src/main.cpp index 3b59953..96f5939 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,4 +1,5 @@ #include "main.h" +#include "DRCAttachCallback.h" #include "config.h" #include "retain_vars.hpp" #include "thread.h" @@ -35,6 +36,10 @@ DEINITIALIZE_PLUGIN() { NotificationModule_DeInitLibrary(); } +ON_ACQUIRED_FOREGROUND() { + InitDRCAttachCallbacks(); +} + // Called whenever an application was started. ON_APPLICATION_START() { initLogging(); @@ -45,6 +50,8 @@ ON_APPLICATION_START() { ApplyGameSpecificPatches(); VPADSetTVMenuInvalid(VPAD_CHAN_0, true); + + InitDRCAttachCallbacks(); } ON_APPLICATION_REQUESTS_EXIT() { diff --git a/src/retain_vars.cpp b/src/retain_vars.cpp index bbc3386..3cb0750 100644 --- a/src/retain_vars.cpp +++ b/src/retain_vars.cpp @@ -21,4 +21,6 @@ bool gNotAvailableNotificationDisplayed = false; NMColor COLOR_RED = {237, 28, 36, 255}; -int32_t gThreadPriorityIncrease = 1; \ No newline at end of file +int32_t gThreadPriorityIncrease = 1; + +bool gBlockDRCScreenshots = false; \ No newline at end of file diff --git a/src/retain_vars.hpp b/src/retain_vars.hpp index fd13244..b4a2eb5 100644 --- a/src/retain_vars.hpp +++ b/src/retain_vars.hpp @@ -24,4 +24,6 @@ extern bool gNotAvailableNotificationDisplayed; extern NMColor COLOR_RED; -extern int32_t gThreadPriorityIncrease; \ No newline at end of file +extern int32_t gThreadPriorityIncrease; + +extern bool gBlockDRCScreenshots; \ No newline at end of file