WIP broken

This commit is contained in:
Maschell 2024-12-23 12:57:52 +01:00
parent b567ae31b9
commit 2335f907ad
14 changed files with 226 additions and 739 deletions

View File

@ -1,75 +0,0 @@
#include "DRCAttachCallback.h"
#include "retain_vars.hpp"
#include "utils/logger.h"
#include <coreinit/cache.h>
#include <map>
#include <mutex>
#include <wups.h>
std::mutex gDRCCallbackMutex;
CCRCDCCallbackData gCCRCDCCallbackDataCurrent;
std::map<CCRCDCCallbackDataCallback, void *> gDRCCallbackData;
void DRCAttachDetachCallbackWrapper(CCRCDCCallbackData *data, void *context) {
std::lock_guard<std::mutex> 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<std::mutex> 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) {
if (gButtonCombo & VPAD_BUTTON_TV) {
DEBUG_FUNCTION_LINE("Block TV Menu");
VPADSetTVMenuInvalid(data->chan, true);
} else {
DEBUG_FUNCTION_LINE("Unblock TV Menu");
VPADSetTVMenuInvalid(data->chan, false);
}
} else {
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);
}

View File

@ -1,14 +0,0 @@
#pragma once
#include <vpad/input.h>
#include <wut.h>
struct WUT_PACKED CCRCDCCallbackData {
uint32_t attached;
VPADChan chan;
WUT_UNKNOWN_BYTES(6);
};
extern CCRCDCCallbackData gCCRCDCCallbackDataCurrent;
typedef void (*CCRCDCCallbackDataCallback)(CCRCDCCallbackData *, void *);
void InitDRCAttachCallbacks();

View File

@ -1,19 +1,87 @@
#include "config.h"
#include "common.h"
#include "retain_vars.hpp"
#include "utils/WUPSConfigItemButtonCombo.h"
#include "utils/logger.h"
#include "utils/utils.h"
#include <vpad/input.h>
#include <screenshot_utils.h>
#include <utils/StringTools.h>
#include <wups.h>
#include <wups/config/WUPSConfigCategory.h>
#include <wups/config/WUPSConfigItemBoolean.h>
#include <wups/config/WUPSConfigItemButtonCombo.h>
#include <wups/config/WUPSConfigItemIntegerRange.h>
#include <wups/config/WUPSConfigItemMultipleValues.h>
#include <wups/storage.h>
WUPS_USE_STORAGE("screenshot_plugin");
namespace {
uint32_t migrateButtonCombo(const uint32_t buttons) {
uint32_t conv_buttons = 0;
if (buttons & VPAD_BUTTON_A) {
conv_buttons |= WUPS_BUTTON_COMBO_BUTTON_A;
}
if (buttons & VPAD_BUTTON_B) {
conv_buttons |= WUPS_BUTTON_COMBO_BUTTON_B;
}
if (buttons & VPAD_BUTTON_X) {
conv_buttons |= WUPS_BUTTON_COMBO_BUTTON_X;
}
if (buttons & VPAD_BUTTON_Y) {
conv_buttons |= WUPS_BUTTON_COMBO_BUTTON_Y;
}
if (buttons & VPAD_BUTTON_LEFT) {
conv_buttons |= WUPS_BUTTON_COMBO_BUTTON_LEFT;
}
if (buttons & VPAD_BUTTON_RIGHT) {
conv_buttons |= WUPS_BUTTON_COMBO_BUTTON_RIGHT;
}
if (buttons & VPAD_BUTTON_UP) {
conv_buttons |= WUPS_BUTTON_COMBO_BUTTON_UP;
}
if (buttons & VPAD_BUTTON_DOWN) {
conv_buttons |= WUPS_BUTTON_COMBO_BUTTON_DOWN;
}
if (buttons & VPAD_BUTTON_ZL) {
conv_buttons |= WUPS_BUTTON_COMBO_BUTTON_ZL;
}
if (buttons & VPAD_BUTTON_ZR) {
conv_buttons |= WUPS_BUTTON_COMBO_BUTTON_ZR;
}
if (buttons & VPAD_BUTTON_L) {
conv_buttons |= WUPS_BUTTON_COMBO_BUTTON_L;
}
if (buttons & VPAD_BUTTON_R) {
conv_buttons |= WUPS_BUTTON_COMBO_BUTTON_R;
}
if (buttons & VPAD_BUTTON_PLUS) {
conv_buttons |= WUPS_BUTTON_COMBO_BUTTON_PLUS;
}
if (buttons & VPAD_BUTTON_MINUS) {
conv_buttons |= WUPS_BUTTON_COMBO_BUTTON_MINUS;
}
if (buttons & VPAD_BUTTON_STICK_R) {
conv_buttons |= WUPS_BUTTON_COMBO_BUTTON_STICK_R;
}
if (buttons & VPAD_BUTTON_STICK_L) {
conv_buttons |= WUPS_BUTTON_COMBO_BUTTON_STICK_L;
}
if (buttons & VPAD_BUTTON_TV) {
conv_buttons |= WUPS_BUTTON_COMBO_BUTTON_TV;
}
return conv_buttons;
}
} // namespace
WUPSConfigAPICallbackStatus ConfigMenuOpenedCallback(WUPSConfigCategoryHandle rootHandle);
void ConfigMenuClosedCallback() {
@ -23,13 +91,19 @@ void ConfigMenuClosedCallback() {
}
}
WUPSButtonCombo_ComboHandle gButtonComboHandle = 0;
WUPSButtonCombo_ComboStatus gButtonComboStatus = WUPS_BUTTON_COMBO_COMBO_STATUS_INVALID_STATUS;
void InitConfig() {
WUPSConfigAPIOptionsV1 configOptions = {.name = "Screenshot Plugin"};
if (WUPSConfigAPI_Init(configOptions, ConfigMenuOpenedCallback, ConfigMenuClosedCallback) != WUPSCONFIG_API_RESULT_SUCCESS) {
DEBUG_FUNCTION_LINE_ERR("Failed to init config api");
}
gButtonCombo = BUTTON_COMBO_CONFIG_DEFAULT;
NotificationModule_SetDefaultValue(NOTIFICATION_MODULE_NOTIFICATION_TYPE_INFO, NOTIFICATION_MODULE_DEFAULT_OPTION_KEEP_UNTIL_SHOWN, true);
NotificationModule_SetDefaultValue(NOTIFICATION_MODULE_NOTIFICATION_TYPE_INFO, NOTIFICATION_MODULE_DEFAULT_OPTION_DURATION_BEFORE_FADE_OUT, 20.0f);
NotificationModule_SetDefaultValue(NOTIFICATION_MODULE_NOTIFICATION_TYPE_ERROR, NOTIFICATION_MODULE_DEFAULT_OPTION_KEEP_UNTIL_SHOWN, true);
NotificationModule_SetDefaultValue(NOTIFICATION_MODULE_NOTIFICATION_TYPE_ERROR, NOTIFICATION_MODULE_DEFAULT_OPTION_DURATION_BEFORE_FADE_OUT, 20.0f);
WUPSStorageError storageRes;
if ((storageRes = WUPSStorageAPI::GetOrStoreDefault(ENABLED_CONFIG_STRING, gEnabled, ENABLED_CONFIG_DEFAULT)) != WUPS_STORAGE_ERROR_SUCCESS) {
@ -48,7 +122,20 @@ void InitConfig() {
DEBUG_FUNCTION_LINE_ERR("Failed to GetOrStoreDefault value %s (%d)", WUPSStorageAPI::GetStatusStr(storageRes).data(), storageRes);
}
if ((storageRes = WUPSStorageAPI::GetOrStoreDefault<uint32_t>(BUTTON_COMBO_CONFIG_STRING, gButtonCombo, BUTTON_COMBO_CONFIG_DEFAULT)) != WUPS_STORAGE_ERROR_SUCCESS) {
bool showButtonComboInfo = false;
auto defaultButtonCombo = BUTTON_COMBO_CONFIG_DEFAULT;
storageRes = WUPSStorageAPI::Get<uint32_t>(BUTTON_COMBO_LEGACY_CONFIG_STRING, gButtonCombo);
if (storageRes == WUPS_STORAGE_ERROR_SUCCESS) {
DEBUG_FUNCTION_LINE_INFO("Migrated button combo for screenshot plugin.");
gButtonCombo = migrateButtonCombo(gButtonCombo);
defaultButtonCombo = static_cast<WUPSButtonCombo_Buttons>(gButtonCombo);
WUPSStorageAPI::DeleteItem(BUTTON_COMBO_LEGACY_CONFIG_STRING);
} else if (storageRes == WUPS_STORAGE_ERROR_NOT_FOUND && WUPSStorageAPI::Get<uint32_t>(BUTTON_COMBO_CONFIG_STRING, gButtonCombo) == WUPS_STORAGE_ERROR_NOT_FOUND) {
showButtonComboInfo = true;
}
gButtonCombo = defaultButtonCombo;
if ((storageRes = WUPSStorageAPI::GetOrStoreDefault<uint32_t>(BUTTON_COMBO_CONFIG_STRING, gButtonCombo, defaultButtonCombo)) != WUPS_STORAGE_ERROR_SUCCESS) {
DEBUG_FUNCTION_LINE_ERR("Failed to GetOrStoreDefault value %s (%d)", WUPSStorageAPI::GetStatusStr(storageRes).data(), storageRes);
}
@ -60,12 +147,30 @@ void InitConfig() {
DEBUG_FUNCTION_LINE_ERR("Failed to save storage %s (%d)", WUPSStorageAPI::GetStatusStr(storageRes).data(), storageRes);
}
if (gButtonCombo & VPAD_BUTTON_TV) {
DEBUG_FUNCTION_LINE("Block TV Menu");
VPADSetTVMenuInvalid(VPAD_CHAN_0, true);
if (const WUPSButtonCombo_Error res = WUPSButtonComboAPI_AddButtonComboPressDown("Screenshot ButtonCombo",
static_cast<WUPSButtonCombo_Buttons>(gButtonCombo),
{.callback = [](WUPSButtonCombo_ComboHandle handle, void *context) {
RequestScreenshot();
},
.context = nullptr},
&gButtonComboHandle, &gButtonComboStatus);
res != WUPS_BUTTON_COMBO_ERROR_SUCCESS) {
const auto errorMsg = string_format("Failed to register button combo for screenshots. %s", WUPSButtonComboAPI_GetStatusStr(res));
DEBUG_FUNCTION_LINE_ERR("%s", errorMsg.c_str());
NotificationModule_AddErrorNotification(errorMsg.c_str());
} else {
DEBUG_FUNCTION_LINE("Unblock TV Menu");
VPADSetTVMenuInvalid(VPAD_CHAN_0, false);
if (gButtonComboStatus == WUPS_BUTTON_COMBO_COMBO_STATUS_CONFLICT) {
const auto conflictMsg = "ScreenshotPlugin: Button combo was disabled due to a conflict with another combo. Open the config menu and assign a different combo";
DEBUG_FUNCTION_LINE_INFO("%s", conflictMsg);
NotificationModule_AddInfoNotification(conflictMsg);
} else if (gButtonComboStatus != WUPS_BUTTON_COMBO_COMBO_STATUS_VALID) {
const auto conflictMsg = string_format("Unknown error happened while registering button combo for the Screenshots. Error: %d", gButtonComboStatus);
DEBUG_FUNCTION_LINE_INFO("%s", conflictMsg.c_str());
NotificationModule_AddInfoNotification(conflictMsg.c_str());
} else if (showButtonComboInfo) {
NotificationModule_AddInfoNotification("Press \ue089+\ue07B to take screenshots! You can change this button combination at any time in the config menu");
}
}
if (gOutputFormat >= 3) {
@ -76,6 +181,11 @@ void InitConfig() {
} else if (gQuality > 100) {
gQuality = 100;
}
NotificationModule_SetDefaultValue(NOTIFICATION_MODULE_NOTIFICATION_TYPE_INFO, NOTIFICATION_MODULE_DEFAULT_OPTION_KEEP_UNTIL_SHOWN, false);
NotificationModule_SetDefaultValue(NOTIFICATION_MODULE_NOTIFICATION_TYPE_INFO, NOTIFICATION_MODULE_DEFAULT_OPTION_DURATION_BEFORE_FADE_OUT, 2.0f);
NotificationModule_SetDefaultValue(NOTIFICATION_MODULE_NOTIFICATION_TYPE_ERROR, NOTIFICATION_MODULE_DEFAULT_OPTION_KEEP_UNTIL_SHOWN, false);
NotificationModule_SetDefaultValue(NOTIFICATION_MODULE_NOTIFICATION_TYPE_ERROR, NOTIFICATION_MODULE_DEFAULT_OPTION_DURATION_BEFORE_FADE_OUT, 2.0f);
}
void multipleValueItemCallback(ConfigItemMultipleValues *item, uint32_t newValue) {
@ -149,18 +259,12 @@ void boolItemCallback(ConfigItemBoolean *item, bool newValue) {
}
}
void buttonComboItemChanged(ConfigItemButtonCombo *item, uint32_t newValue) {
if (item && item->identifier) {
DEBUG_FUNCTION_LINE("New value in %s changed: %08X", item->configId, newValue);
if (std::string_view(item->identifier) == BUTTON_COMBO_CONFIG_STRING) {
gButtonCombo = newValue;
if (gButtonCombo & VPAD_BUTTON_TV) {
DEBUG_FUNCTION_LINE("Block TV Menu");
VPADSetTVMenuInvalid(VPAD_CHAN_0, true);
} else {
DEBUG_FUNCTION_LINE("Unblock TV Menu");
VPADSetTVMenuInvalid(VPAD_CHAN_0, false);
}
WUPSStorageError err;
if ((err = WUPSStorageAPI::Store(item->identifier, gButtonCombo)) != WUPS_STORAGE_ERROR_SUCCESS) {
DEBUG_FUNCTION_LINE_ERR("Failed to store item %s (newValue: %08X): %s", item->identifier, gButtonCombo, WUPSStorageAPI::GetStatusStr(err).data());
@ -180,7 +284,7 @@ WUPSConfigAPICallbackStatus ConfigMenuOpenedCallback(WUPSConfigCategoryHandle ro
root.add(WUPSConfigItemButtonCombo::Create(BUTTON_COMBO_CONFIG_STRING,
"Button combo",
BUTTON_COMBO_CONFIG_DEFAULT, gButtonCombo,
BUTTON_COMBO_CONFIG_DEFAULT, gButtonComboHandle,
&buttonComboItemChanged));
constexpr WUPSConfigItemMultipleValues::ValuePair possibleScreenValues[] = {

View File

@ -1,18 +1,23 @@
#pragma once
#include <vpad/input.h>
#include <wups/button_combo.h>
#define ENABLED_CONFIG_DEFAULT true
#define FORMAT_CONFIG_DEFAULT IMAGE_OUTPUT_FORMAT_JPEG
#define QUALITY_CONFIG_DEFAULT 90
#define SCREEN_CONFIG_DEFAULT IMAGE_SOURCE_TV_AND_DRC
#define BUTTON_COMBO_CONFIG_DEFAULT VPAD_BUTTON_TV
#define RESERVED_BIT_USAGE_CONFIG_DEFAULT true
#define ENABLED_CONFIG_DEFAULT true
#define FORMAT_CONFIG_DEFAULT IMAGE_OUTPUT_FORMAT_JPEG
#define QUALITY_CONFIG_DEFAULT 90
#define SCREEN_CONFIG_DEFAULT IMAGE_SOURCE_TV_AND_DRC
#define BUTTON_COMBO_CONFIG_DEFAULT ((WUPSButtonCombo_Buttons) (WUPS_BUTTON_COMBO_BUTTON_TV | WUPS_BUTTON_COMBO_BUTTON_LEFT))
#define RESERVED_BIT_USAGE_CONFIG_DEFAULT true
#define ENABLED_CONFIG_STRING "enabled"
#define BUTTON_COMBO_CONFIG_STRING "buttonCombo"
#define FORMAT_CONFIG_STRING "format"
#define QUALITY_CONFIG_STRING "quality"
#define SCREEN_CONFIG_STRING "screen"
#define RESERVED_BIT_USAGE_CONFIG_STRING "reservedBitUsage"
#define ENABLED_CONFIG_STRING "enabled"
#define BUTTON_COMBO_LEGACY_CONFIG_STRING "buttonCombo"
#define BUTTON_COMBO_CONFIG_STRING "buttonComboNew"
#define FORMAT_CONFIG_STRING "format"
#define QUALITY_CONFIG_STRING "quality"
#define SCREEN_CONFIG_STRING "screen"
#define RESERVED_BIT_USAGE_CONFIG_STRING "reservedBitUsage"
#define BUTTON_COMBO_INFO_SHOWN_CONFIG_STRING "buttonComboInfoShown"
void InitConfig();
extern WUPSButtonCombo_ComboHandle gButtonComboHandle;
extern WUPSButtonCombo_ComboStatus gButtonComboStatus;

View File

@ -1,176 +1,11 @@
#include "common.h"
#include "fs/FSUtils.h"
#include "retain_vars.hpp"
#include "screenshot_utils.h"
#include "thread.h"
#include "utils/input.h"
#include "utils/logger.h"
#include <coreinit/cache.h>
#include <gx2/surface.h>
#include <padscore/wpad.h>
#include <vpad/input.h>
#include <wups.h>
extern "C" uint32_t VPADGetButtonProcMode(uint32_t);
void AlreadyInProgressCallback(NotificationModuleHandle handle, void *context) {
auto scanTarget = (GX2ScanTarget) (uint32_t) context;
if (scanTarget == GX2_SCAN_TARGET_TV) {
gInProgressNotificationDisplayedTV = false;
} else if (scanTarget == GX2_SCAN_TARGET_DRC) {
gInProgressNotificationDisplayedDRC = false;
}
OSMemoryBarrier();
}
void NotAvailableCallback(NotificationModuleHandle handle, void *context) {
gNotAvailableNotificationDisplayed = false;
OSMemoryBarrier();
}
void RequestScreenshot() {
NotificationModuleStatus err;
if (gBlockScreenshots) {
if (!gNotAvailableNotificationDisplayed) {
if ((err = NotificationModule_AddErrorNotificationWithCallback("Screenshots not available at the moment.",
NotAvailableCallback,
nullptr)) != NOTIFICATION_MODULE_RESULT_SUCCESS) {
DEBUG_FUNCTION_LINE_ERR("Failed to display \"Screenshots not available at the moment.\" notification");
DEBUG_FUNCTION_LINE_ERR("Error: %s,", NotificationModule_GetStatusStr(err));
return;
}
gNotAvailableNotificationDisplayed = true;
}
} else {
OSCalendarTime time;
OSTicksToCalendarTime(OSGetTime(), &time);
if (gImageSource == IMAGE_SOURCE_TV_AND_DRC || gImageSource == IMAGE_SOURCE_TV) {
if (gTakeScreenshotTV.state == SCREENSHOT_STATE_READY) {
DEBUG_FUNCTION_LINE("Requested screenshot for TV!");
gTakeScreenshotTV.state = SCREENSHOT_STATE_REQUESTED;
gTakeScreenshotTV.time = time;
gReadySinceFramesTV = 0;
} else if (!gInProgressNotificationDisplayedTV) {
if ((err = NotificationModule_AddErrorNotificationWithCallback("Screenshot of the TV already in progress.",
AlreadyInProgressCallback,
(void *) GX2_SCAN_TARGET_TV)) != NOTIFICATION_MODULE_RESULT_SUCCESS) {
DEBUG_FUNCTION_LINE_ERR("Failed to display \"Screenshot of the TV already in progress.\" notification");
DEBUG_FUNCTION_LINE_ERR("Error: %s,", NotificationModule_GetStatusStr(err));
return;
}
gInProgressNotificationDisplayedTV = true;
}
}
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.state == SCREENSHOT_STATE_READY) {
DEBUG_FUNCTION_LINE("Requested screenshot for DRC!");
gTakeScreenshotDRC.state = SCREENSHOT_STATE_REQUESTED;
gTakeScreenshotDRC.time = time;
gReadySinceFramesDRC = 0;
} else if (!gInProgressNotificationDisplayedDRC) {
if ((err = NotificationModule_AddErrorNotificationWithCallback("Screenshot of the GamePad already in progress.",
AlreadyInProgressCallback,
(void *) GX2_SCAN_TARGET_DRC)) != NOTIFICATION_MODULE_RESULT_SUCCESS) {
DEBUG_FUNCTION_LINE_ERR("Failed to display \"Screenshot of the GamePad already in progress.\" notification");
DEBUG_FUNCTION_LINE_ERR("Error: %s,", NotificationModule_GetStatusStr(err));
return;
}
gInProgressNotificationDisplayedDRC = true;
}
}
OSMemoryBarrier();
}
}
static uint32_t sWasHoldForXFrameGamePad;
DECL_FUNCTION(int32_t, VPADRead, VPADChan chan, VPADStatus *buffer, uint32_t buffer_size, VPADReadError *error) {
VPADReadError real_error;
int32_t result = real_VPADRead(chan, buffer, buffer_size, &real_error);
if (gEnabled && gButtonCombo != 0) {
if (result > 0 && real_error == VPAD_READ_SUCCESS) {
uint32_t end = 1;
// Fix games like TP HD
if (VPADGetButtonProcMode(chan) == 1) {
end = result;
}
bool found = false;
for (uint32_t i = 0; i < end; i++) {
if ((((buffer[i].hold & 0x000FFFFF) & gButtonCombo) == gButtonCombo)) {
found = true;
break;
}
}
if (found) {
if (sWasHoldForXFrameGamePad == 0) {
RequestScreenshot();
}
sWasHoldForXFrameGamePad++;
} else {
sWasHoldForXFrameGamePad = 0;
}
}
}
if (error) {
*error = real_error;
}
return result;
}
static uint32_t sWPADLastButtonHold[4];
static uint32_t sWasHoldForXFrame[4];
DECL_FUNCTION(void, WPADRead, WPADChan chan, WPADStatusProController *data) {
real_WPADRead(chan, data);
if (gEnabled && gButtonCombo > 0 && chan >= 0 && chan < 4) {
if (data[0].err == 0) {
if (data[0].extensionType != 0xFF) {
uint32_t curButtonHold = 0;
if (data[0].extensionType == WPAD_EXT_CORE || data[0].extensionType == WPAD_EXT_NUNCHUK) {
// button data is in the first 2 bytes for wiimotes
curButtonHold = remapWiiMoteButtons(((uint16_t *) data)[0]);
} else if (data[0].extensionType == WPAD_EXT_CLASSIC) {
curButtonHold = remapClassicButtons(((uint32_t *) data)[10] & 0xFFFF);
} else if (data[0].extensionType == WPAD_EXT_PRO_CONTROLLER) {
curButtonHold = remapProButtons(data[0].buttons);
}
uint32_t curButtonTrigger = (curButtonHold & (~(sWPADLastButtonHold[chan])));
bool takeScreenshot = false;
if (gReservedBitUsage && curButtonTrigger & VPAD_BUTTON_RESERVED_BIT) {
takeScreenshot = true;
}
if (!takeScreenshot) {
if ((gButtonCombo != 0 && (curButtonHold & gButtonCombo) == gButtonCombo)) {
if (sWasHoldForXFrame[chan] == 0) {
takeScreenshot = true;
}
sWasHoldForXFrame[chan]++;
} else {
sWasHoldForXFrame[chan] = 0;
}
}
if (takeScreenshot) {
RequestScreenshot();
}
sWPADLastButtonHold[chan] = curButtonHold;
}
}
}
}
DECL_FUNCTION(void, GX2CopyColorBufferToScanBuffer, const GX2ColorBuffer *colorBuffer, GX2ScanTarget scan_target) {
if (gEnabled) {
if (gCheckIfScreenRendered) {
@ -251,10 +86,8 @@ DECL_FUNCTION(void, GX2MarkScanBufferCopied, GX2ScanTarget scan_target) {
real_GX2MarkScanBufferCopied(scan_target);
}
WUPS_MUST_REPLACE(VPADRead, WUPS_LOADER_LIBRARY_VPAD, VPADRead);
WUPS_MUST_REPLACE(GX2MarkScanBufferCopied, WUPS_LOADER_LIBRARY_GX2, GX2MarkScanBufferCopied);
WUPS_MUST_REPLACE(GX2GetCurrentScanBuffer, WUPS_LOADER_LIBRARY_GX2, GX2GetCurrentScanBuffer);
WUPS_MUST_REPLACE(GX2CopyColorBufferToScanBuffer, WUPS_LOADER_LIBRARY_GX2, GX2CopyColorBufferToScanBuffer);
WUPS_MUST_REPLACE(GX2SetTVBuffer, WUPS_LOADER_LIBRARY_GX2, GX2SetTVBuffer);
WUPS_MUST_REPLACE(GX2SetDRCBuffer, WUPS_LOADER_LIBRARY_GX2, GX2SetDRCBuffer);
WUPS_MUST_REPLACE(WPADRead, WUPS_LOADER_LIBRARY_PADSCORE, WPADRead);

View File

@ -1,9 +1,7 @@
#include "main.h"
#include "DRCAttachCallback.h"
#include "config.h"
#include "retain_vars.hpp"
#include "thread.h"
#include "utils/WUPSConfigItemButtonCombo.h"
#include "utils/logger.h"
#include "utils/utils.h"
#include <notifications/notifications.h>
@ -23,6 +21,7 @@ WUPS_USE_WUT_DEVOPTAB();
// Gets called once the loader exists.
INITIALIZE_PLUGIN() {
initLogging();
NotificationModule_InitLibrary();
InitConfig();
if (gEnabled) {
InitNotificationModule();
@ -31,11 +30,11 @@ INITIALIZE_PLUGIN() {
DEINITIALIZE_PLUGIN() {
NotificationModule_DeInitLibrary();
if (const WUPSButtonCombo_Error res = WUPSButtonComboAPI_RemoveButtonCombo(gButtonComboHandle); res != WUPS_BUTTON_COMBO_ERROR_SUCCESS) {
DEBUG_FUNCTION_LINE_ERR("Failed to remove button combo. %s", WUPSButtonComboAPI_GetStatusStr(res));
}
}
ON_ACQUIRED_FOREGROUND() {
InitDRCAttachCallbacks();
}
// Called whenever an application was started.
ON_APPLICATION_START() {
@ -45,8 +44,6 @@ ON_APPLICATION_START() {
startFSIOThreads();
ApplyGameSpecificPatches();
InitDRCAttachCallbacks();
}
ON_APPLICATION_REQUESTS_EXIT() {

View File

@ -12,6 +12,83 @@
#include <notifications/notifications.h>
#include <valarray>
namespace {
void AlreadyInProgressCallback(NotificationModuleHandle handle, void *context) {
auto scanTarget = (GX2ScanTarget) (uint32_t) context;
if (scanTarget == GX2_SCAN_TARGET_TV) {
gInProgressNotificationDisplayedTV = false;
} else if (scanTarget == GX2_SCAN_TARGET_DRC) {
gInProgressNotificationDisplayedDRC = false;
}
OSMemoryBarrier();
}
void NotAvailableCallback(NotificationModuleHandle handle, void *context) {
gNotAvailableNotificationDisplayed = false;
OSMemoryBarrier();
}
} // namespace
void RequestScreenshot() {
NotificationModuleStatus err;
if (gBlockScreenshots) {
if (!gNotAvailableNotificationDisplayed) {
if ((err = NotificationModule_AddErrorNotificationWithCallback("Screenshots not available at the moment.",
NotAvailableCallback,
nullptr)) != NOTIFICATION_MODULE_RESULT_SUCCESS) {
DEBUG_FUNCTION_LINE_ERR("Failed to display \"Screenshots not available at the moment.\" notification");
DEBUG_FUNCTION_LINE_ERR("Error: %s,", NotificationModule_GetStatusStr(err));
return;
}
gNotAvailableNotificationDisplayed = true;
}
} else {
OSCalendarTime time;
OSTicksToCalendarTime(OSGetTime(), &time);
if (gImageSource == IMAGE_SOURCE_TV_AND_DRC || gImageSource == IMAGE_SOURCE_TV) {
if (gTakeScreenshotTV.state == SCREENSHOT_STATE_READY) {
DEBUG_FUNCTION_LINE("Requested screenshot for TV!");
gTakeScreenshotTV.state = SCREENSHOT_STATE_REQUESTED;
gTakeScreenshotTV.time = time;
gReadySinceFramesTV = 0;
} else if (!gInProgressNotificationDisplayedTV) {
if ((err = NotificationModule_AddErrorNotificationWithCallback("Screenshot of the TV already in progress.",
AlreadyInProgressCallback,
(void *) GX2_SCAN_TARGET_TV)) != NOTIFICATION_MODULE_RESULT_SUCCESS) {
DEBUG_FUNCTION_LINE_ERR("Failed to display \"Screenshot of the TV already in progress.\" notification");
DEBUG_FUNCTION_LINE_ERR("Error: %s,", NotificationModule_GetStatusStr(err));
return;
}
gInProgressNotificationDisplayedTV = true;
}
}
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.state == SCREENSHOT_STATE_READY) {
DEBUG_FUNCTION_LINE("Requested screenshot for DRC!");
gTakeScreenshotDRC.state = SCREENSHOT_STATE_REQUESTED;
gTakeScreenshotDRC.time = time;
gReadySinceFramesDRC = 0;
} else if (!gInProgressNotificationDisplayedDRC) {
if ((err = NotificationModule_AddErrorNotificationWithCallback("Screenshot of the GamePad already in progress.",
AlreadyInProgressCallback,
(void *) GX2_SCAN_TARGET_DRC)) != NOTIFICATION_MODULE_RESULT_SUCCESS) {
DEBUG_FUNCTION_LINE_ERR("Failed to display \"Screenshot of the GamePad already in progress.\" notification");
DEBUG_FUNCTION_LINE_ERR("Error: %s,", NotificationModule_GetStatusStr(err));
return;
}
gInProgressNotificationDisplayedDRC = true;
}
}
OSMemoryBarrier();
}
}
bool saveTextureAsPicture(const std::string &path, uint8_t *sourceBuffer, uint32_t width, uint32_t height, uint32_t pitch, GX2SurfaceFormat format, ImageOutputFormatEnum outputFormat, bool convertRGBtoSRGB, int quality) {
if (sourceBuffer == nullptr) {
DEBUG_FUNCTION_LINE_ERR("sourceBuffer is nullptr");

View File

@ -10,3 +10,5 @@
bool saveTextureAsPicture(const std::string &path, uint8_t *sourceBuffer, uint32_t width, uint32_t height, uint32_t pitch, GX2SurfaceFormat format, ImageOutputFormatEnum outputFormat, bool convertRGBtoSRGB, int quality);
bool takeScreenshot(GX2ColorBuffer *srcBuffer, GX2ScanTarget scanTarget, GX2SurfaceFormat outputBufferSurfaceFormat, ImageOutputFormatEnum outputFormat, int quality, const OSCalendarTime &time);
void RequestScreenshot();

View File

@ -11,4 +11,4 @@ std::string string_format(const std::string &format, Args... args) {
auto buf = std::make_unique<char[]>(size);
std::snprintf(buf.get(), size, format.c_str(), args...);
return std::string(buf.get(), buf.get() + size - 1); // We don't want the '\0' inside
}
}

View File

@ -1,298 +0,0 @@
#include "WUPSConfigItemButtonCombo.h"
#include "utils/input.h"
#include <coreinit/debug.h>
#include <coreinit/thread.h>
#include <coreinit/time.h>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <vpad/input.h>
#include <wups.h>
static const char *getButtonChar(VPADButtons value) {
std::string combo;
if (value & VPAD_BUTTON_A) {
return "\ue000";
}
if (value & VPAD_BUTTON_B) {
return "\ue001";
}
if (value & VPAD_BUTTON_X) {
return "\ue002";
}
if (value & VPAD_BUTTON_Y) {
return "\ue003";
}
if (value & VPAD_BUTTON_L) {
return "\ue083";
}
if (value & VPAD_BUTTON_R) {
return "\ue084";
}
if (value & VPAD_BUTTON_ZL) {
return "\ue085";
}
if (value & VPAD_BUTTON_ZR) {
return "\ue086";
}
if (value & VPAD_BUTTON_UP) {
return "\ue079";
}
if (value & VPAD_BUTTON_DOWN) {
return "\ue07A";
}
if (value & VPAD_BUTTON_LEFT) {
return "\ue07B";
}
if (value & VPAD_BUTTON_RIGHT) {
return "\ue07C";
}
if (value & VPAD_BUTTON_STICK_L) {
return "\ue081";
}
if (value & VPAD_BUTTON_STICK_R) {
return "\ue082";
}
if (value & VPAD_BUTTON_PLUS) {
return "\ue045";
}
if (value & VPAD_BUTTON_MINUS) {
return "\ue046";
}
if (value & VPAD_BUTTON_TV) {
return "\ue089";
}
if (value & VPAD_BUTTON_RESERVED_BIT) {
return "\ue01E";
}
return "";
}
static std::string getComboAsString(uint32_t value) {
char comboString[60];
memset(comboString, 0, sizeof(comboString));
for (uint32_t i = 0; i < 32; i++) {
uint32_t bitMask = 1 << i;
if (value & bitMask) {
auto val = getButtonChar(static_cast<VPADButtons>(bitMask));
if (val[0] != '\0') {
strcat(comboString, val);
strcat(comboString, "+");
}
}
}
std::string res(comboString);
if (res.ends_with("+")) {
res.pop_back();
}
return res;
}
static int32_t WUPSConfigItemButtonCombo_getCurrentValueDisplay(void *context, char *out_buf, int32_t out_size) {
auto *item = (ConfigItemButtonCombo *) context;
snprintf(out_buf, out_size, "%s", getComboAsString(item->value).c_str());
return 0;
}
static void WUPSConfigItemButtonCombo_onCloseCallback(void *context) {
auto *item = (ConfigItemButtonCombo *) context;
if (item->valueAtCreation != item->value && item->valueChangedCallback != nullptr) {
((ButtonComboValueChangedCallback) (item->valueChangedCallback))(item, item->value);
}
}
static void checkForHold(ConfigItemButtonCombo *item) {
uint32_t lastHold = 0;
uint32_t holdFor = 0;
uint32_t holdForTarget = item->holdDurationInMs >> 4;
uint32_t holdAbortTarget = item->abortButtonHoldDurationInMs >> 4;
auto mask = VPAD_BUTTON_A | VPAD_BUTTON_B | VPAD_BUTTON_X | VPAD_BUTTON_Y | VPAD_BUTTON_L | VPAD_BUTTON_R |
VPAD_BUTTON_ZL | VPAD_BUTTON_ZR | VPAD_BUTTON_UP | VPAD_BUTTON_DOWN | VPAD_BUTTON_LEFT | VPAD_BUTTON_RIGHT |
VPAD_BUTTON_STICK_L | VPAD_BUTTON_STICK_R | VPAD_BUTTON_PLUS | VPAD_BUTTON_MINUS | VPAD_BUTTON_TV | VPAD_BUTTON_RESERVED_BIT;
KPADStatus kpad_data{};
KPADError kpad_error;
while (true) {
uint32_t buttonsHold = 0;
VPADReadError vpad_error = VPAD_READ_UNINITIALIZED;
VPADStatus vpad_data = {};
if (VPADRead(VPAD_CHAN_0, &vpad_data, 1, &vpad_error) > 0 && vpad_error == VPAD_READ_SUCCESS) {
buttonsHold = vpad_data.hold;
}
for (int i = 0; i < 4; i++) {
memset(&kpad_data, 0, sizeof(kpad_data));
if (KPADReadEx((KPADChan) i, &kpad_data, 1, &kpad_error) > 0) {
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);
} else if (kpad_data.extensionType == WPAD_EXT_PRO_CONTROLLER) {
buttonsHold |= remapProButtons(kpad_data.pro.hold);
} else {
buttonsHold |= remapClassicButtons(kpad_data.classic.hold);
}
}
}
}
buttonsHold &= mask;
if (buttonsHold == lastHold) {
if (buttonsHold != 0) {
holdFor++;
}
} else {
holdFor = 0;
}
lastHold = buttonsHold;
if (holdFor >= holdAbortTarget && lastHold == item->abortButton) {
break;
}
if (holdFor >= holdForTarget) {
item->value = lastHold;
break;
}
OSSleepTicks(OSMillisecondsToTicks(16));
}
}
static void WUPSConfigItemButtonCombo_onInput(void *context, WUPSConfigSimplePadData input) {
auto *item = (ConfigItemButtonCombo *) context;
if (item->state == BUTTON_COMBO_STATE_NONE) {
if ((input.buttons_d & WUPS_CONFIG_BUTTON_A) == WUPS_CONFIG_BUTTON_A) {
item->state = BUTTON_COMBO_STATE_PREPARE_FOR_HOLD;
}
}
}
static int32_t WUPSConfigItemButtonCombo_getCurrentValueSelectedDisplay(void *context, char *out_buf, int32_t out_size) {
auto *item = (ConfigItemButtonCombo *) context;
if (item->state == BUTTON_COMBO_STATE_PREPARE_FOR_HOLD || item->state == BUTTON_COMBO_STATE_WAIT_FOR_HOLD) {
if (item->state == BUTTON_COMBO_STATE_PREPARE_FOR_HOLD) {
item->state = BUTTON_COMBO_STATE_WAIT_FOR_HOLD;
snprintf(out_buf, out_size, "<Hold new combo for %dms; hold %s to abort>", item->holdDurationInMs, getButtonChar(item->abortButton));
return 0;
} else {
checkForHold(item);
item->state = BUTTON_COMBO_STATE_NONE;
}
}
snprintf(out_buf, out_size, "(Press \ue000 to change) %s", getComboAsString(item->value).c_str());
return 0;
}
static void WUPSConfigItemButtonCombo_restoreDefault(void *context) {
auto *item = (ConfigItemButtonCombo *) context;
item->value = item->defaultValue;
}
static void WUPSConfigItemButtonCombo_Cleanup(ConfigItemButtonCombo *item) {
if (!item) {
return;
}
free((void *) item->identifier);
free(item);
}
static void WUPSConfigItemButtonCombo_onDelete(void *context) {
WUPSConfigItemButtonCombo_Cleanup((ConfigItemButtonCombo *) context);
}
extern "C" WUPSConfigAPIStatus
WUPSConfigItemButtonCombo_CreateEx(const char *identifier,
const char *displayName,
uint32_t defaultComboInVPADButtons, uint32_t currentComboInVPADButtons,
uint32_t holdDurationInMs,
VPADButtons abortButton,
uint32_t abortButtonHoldDurationInMs,
ButtonComboValueChangedCallback callback,
WUPSConfigItemHandle *outHandle) {
if (outHandle == nullptr) {
return WUPSCONFIG_API_RESULT_INVALID_ARGUMENT;
}
auto *item = (ConfigItemButtonCombo *) malloc(sizeof(ConfigItemButtonCombo));
if (item == nullptr) {
OSReport("WUPSConfigItemButtonComboAddToCategoryEx: Failed to allocate memory for item data.\n");
return WUPSCONFIG_API_RESULT_INVALID_ARGUMENT;
}
if (identifier != nullptr) {
item->identifier = strdup(identifier);
} else {
item->identifier = nullptr;
}
item->abortButton = abortButton;
item->abortButtonHoldDurationInMs = abortButtonHoldDurationInMs;
item->holdDurationInMs = holdDurationInMs;
item->defaultValue = defaultComboInVPADButtons;
item->value = currentComboInVPADButtons;
item->valueAtCreation = currentComboInVPADButtons;
item->valueChangedCallback = (void *) callback;
item->state = BUTTON_COMBO_STATE_NONE;
WUPSConfigAPIItemCallbacksV2 callbacks = {
.getCurrentValueDisplay = &WUPSConfigItemButtonCombo_getCurrentValueDisplay,
.getCurrentValueSelectedDisplay = &WUPSConfigItemButtonCombo_getCurrentValueSelectedDisplay,
.onSelected = nullptr,
.restoreDefault = &WUPSConfigItemButtonCombo_restoreDefault,
.isMovementAllowed = nullptr,
.onCloseCallback = &WUPSConfigItemButtonCombo_onCloseCallback,
.onInput = &WUPSConfigItemButtonCombo_onInput,
.onInputEx = nullptr,
.onDelete = &WUPSConfigItemButtonCombo_onDelete,
};
WUPSConfigAPIItemOptionsV2 options = {
.displayName = displayName,
.context = item,
.callbacks = callbacks,
};
WUPSConfigAPIStatus err;
if ((err = WUPSConfigAPI_Item_Create(options, &item->handle)) != WUPSCONFIG_API_RESULT_SUCCESS) {
OSReport("WUPSConfigItemButtonComboAddToCategoryEx: Failed to create config item.\n");
WUPSConfigItemButtonCombo_Cleanup(item);
return err;
}
*outHandle = item->handle;
return WUPSCONFIG_API_RESULT_SUCCESS;
}
extern "C" WUPSConfigAPIStatus
WUPSConfigItemButtonCombo_AddToCategoryEx(WUPSConfigCategoryHandle cat,
const char *identifier,
const char *displayName,
uint32_t defaultComboInVPADButtons, uint32_t currentComboInVPADButtons,
uint32_t holdDurationInMs, VPADButtons abortButton, uint32_t abortButtonHoldDurationInMs,
ButtonComboValueChangedCallback callback) {
WUPSConfigItemHandle itemHandle;
WUPSConfigAPIStatus res;
if ((res = WUPSConfigItemButtonCombo_CreateEx(identifier,
displayName,
defaultComboInVPADButtons, currentComboInVPADButtons,
holdDurationInMs, abortButton, abortButtonHoldDurationInMs,
callback, &itemHandle)) != WUPSCONFIG_API_RESULT_SUCCESS) {
return res;
}
if ((res = WUPSConfigAPI_Category_AddItem(cat, itemHandle)) != WUPSCONFIG_API_RESULT_SUCCESS) {
WUPSConfigAPI_Item_Destroy(itemHandle);
return res;
}
return WUPSCONFIG_API_RESULT_SUCCESS;
}
extern "C" bool
WUPSConfigItemButtonComboAddToCategory(WUPSConfigCategoryHandle cat, const char *displayName, uint32_t defaultComboInVPADButtons, uint32_t currentComboInVPADButtons, ButtonComboValueChangedCallback callback) {
return WUPSConfigItemButtonComboAddToCategoryEx(cat, displayName, defaultComboInVPADButtons, currentComboInVPADButtons, 2000, VPAD_BUTTON_B, 250, callback);
}

View File

@ -1,94 +0,0 @@
#include <stdint.h>
#include <vpad/input.h>
#include <wups.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef enum ButtonComboState {
BUTTON_COMBO_STATE_NONE,
BUTTON_COMBO_STATE_PREPARE_FOR_HOLD,
BUTTON_COMBO_STATE_WAIT_FOR_HOLD,
} ButtonComboState;
typedef struct ConfigItemButtonCombo {
const char *identifier;
WUPSConfigItemHandle handle;
uint32_t defaultValue;
uint32_t value;
uint32_t valueAtCreation;
uint32_t holdDurationInMs;
VPADButtons abortButton;
uint32_t abortButtonHoldDurationInMs;
ButtonComboState state;
void *valueChangedCallback;
} ConfigItemButtonCombo;
typedef void (*ButtonComboValueChangedCallback)(ConfigItemButtonCombo *item, uint32_t buttonComboInVPADButtons);
extern "C" WUPSConfigAPIStatus
WUPSConfigItemButtonCombo_CreateEx(const char *identifier,
const char *displayName,
uint32_t defaultComboInVPADButtons, uint32_t currentComboInVPADButtons,
uint32_t holdDurationInMs, VPADButtons abortButton, uint32_t abortButtonHoldDurationInMs,
ButtonComboValueChangedCallback callback,
WUPSConfigItemHandle *outHandle);
bool WUPSConfigItemButtonComboAddToCategory(WUPSConfigCategoryHandle cat,
const char *displayName,
uint32_t defaultComboInVPADButtons, uint32_t currentComboInVPADButtons,
ButtonComboValueChangedCallback callback);
bool WUPSConfigItemButtonComboAddToCategoryEx(WUPSConfigCategoryHandle cat,
const char *displayName,
uint32_t defaultComboInVPADButtons, uint32_t currentComboInVPADButtons,
uint32_t holdDurationInMs,
VPADButtons abortButton,
uint32_t abortButtonHoldDurationInMs,
ButtonComboValueChangedCallback callback);
#ifdef __cplusplus
}
#endif
#ifdef __cplusplus
#include <optional>
#include <stdexcept>
#include <string>
#include <wups/config/WUPSConfigItem.h>
#include <wups/config_api.h>
class WUPSConfigItemButtonCombo : public WUPSConfigItem {
public:
static std::optional<WUPSConfigItemButtonCombo> CreateEx(std::optional<std::string> identifier,
std::string_view displayName,
uint32_t defaultComboInVPADButtons, uint32_t currentComboInVPADButtons,
uint32_t holdDurationInMs, VPADButtons abortButton, uint32_t abortButtonHoldDurationInMs,
ButtonComboValueChangedCallback callback,
WUPSConfigAPIStatus &err) noexcept;
static WUPSConfigItemButtonCombo CreateEx(std::optional<std::string> identifier,
std::string_view displayName,
uint32_t defaultComboInVPADButtons, uint32_t currentComboInVPADButtons,
uint32_t holdDurationInMs, VPADButtons abortButton, uint32_t abortButtonHoldDurationInMs,
ButtonComboValueChangedCallback callback);
static std::optional<WUPSConfigItemButtonCombo> Create(std::optional<std::string> identifier,
std::string_view displayName,
uint32_t defaultComboInVPADButtons, uint32_t currentComboInVPADButtons,
ButtonComboValueChangedCallback callback,
WUPSConfigAPIStatus &err) noexcept;
static WUPSConfigItemButtonCombo Create(std::optional<std::string> identifier,
std::string_view displayName,
uint32_t defaultComboInVPADButtons, uint32_t currentComboInVPADButtons,
ButtonComboValueChangedCallback callback);
private:
explicit WUPSConfigItemButtonCombo(WUPSConfigItemHandle itemHandle) : WUPSConfigItem(itemHandle) {
}
};
#endif

View File

@ -1,52 +0,0 @@
#include "WUPSConfigItemButtonCombo.h"
std::optional<WUPSConfigItemButtonCombo> WUPSConfigItemButtonCombo::CreateEx(std::optional<std::string> identifier,
std::string_view displayName,
uint32_t defaultComboInVPADButtons, uint32_t currentComboInVPADButtons,
uint32_t holdDurationInMs, VPADButtons abortButton, uint32_t abortButtonHoldDurationInMs,
ButtonComboValueChangedCallback callback,
WUPSConfigAPIStatus &err) noexcept {
WUPSConfigItemHandle itemHandle;
if ((err = WUPSConfigItemButtonCombo_CreateEx(identifier ? identifier->data() : nullptr,
displayName.data(),
defaultComboInVPADButtons, currentComboInVPADButtons,
holdDurationInMs, abortButton, abortButtonHoldDurationInMs,
callback,
&itemHandle)) != WUPSCONFIG_API_RESULT_SUCCESS) {
return std::nullopt;
}
return WUPSConfigItemButtonCombo(itemHandle);
}
WUPSConfigItemButtonCombo WUPSConfigItemButtonCombo::CreateEx(std::optional<std::string> identifier,
std::string_view displayName,
uint32_t defaultComboInVPADButtons, uint32_t currentComboInVPADButtons,
uint32_t holdDurationInMs, VPADButtons abortButton, uint32_t abortButtonHoldDurationInMs,
ButtonComboValueChangedCallback callback) {
WUPSConfigAPIStatus err;
auto result = CreateEx(std::move(identifier), displayName, defaultComboInVPADButtons, currentComboInVPADButtons, holdDurationInMs, abortButton, abortButtonHoldDurationInMs, callback, err);
if (!result) {
throw std::runtime_error(std::string("Failed to create WUPSConfigItemButtonCombo: ").append(WUPSConfigAPI_GetStatusStr(err)));
}
return std::move(*result);
}
std::optional<WUPSConfigItemButtonCombo> WUPSConfigItemButtonCombo::Create(std::optional<std::string> identifier,
std::string_view displayName,
uint32_t defaultComboInVPADButtons, uint32_t currentComboInVPADButtons,
ButtonComboValueChangedCallback callback,
WUPSConfigAPIStatus &err) noexcept {
return CreateEx(std::move(identifier), displayName, defaultComboInVPADButtons, currentComboInVPADButtons, 2000, VPAD_BUTTON_B, 250, callback, err);
}
WUPSConfigItemButtonCombo WUPSConfigItemButtonCombo::Create(std::optional<std::string> identifier,
std::string_view displayName,
uint32_t defaultComboInVPADButtons, uint32_t currentComboInVPADButtons,
ButtonComboValueChangedCallback callback) {
WUPSConfigAPIStatus err = WUPSCONFIG_API_RESULT_UNKNOWN_ERROR;
auto res = Create(std::move(identifier), displayName, defaultComboInVPADButtons, currentComboInVPADButtons, callback, err);
if (!res) {
throw std::runtime_error(std::string("Failed to create WUPSConfigItemButtonCombo: ").append(WUPSConfigAPI_GetStatusStr(err)));
}
return std::move(*res);
}

View File

@ -58,6 +58,7 @@ extern "C" {
#define DEBUG_FUNCTION_LINE_ERR(FMT, ARGS...) LOG_EX_DEFAULT(OSReport, "##ERROR## ", "\n", FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE_WARN(FMT, ARGS...) LOG_EX_DEFAULT(OSReport, "##WARN ## ", "\n", FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE_INFO(FMT, ARGS...) LOG_EX_DEFAULT(OSReport, "##INFO ## ", "\n", FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE_ERR_LAMBDA(FILENAME, FUNCTION, LINE, FMT, ARGS...) LOG_EX(FILENAME, FUNCTION, LINE, OSReport, "##ERROR## ", "\n", FMT, ##ARGS);

View File

@ -76,6 +76,7 @@ std::string GetSanitizedNameOfCurrentApplication() {
} else {
result.clear();
}
ACPFinalize();
return result;
}