From f4c2196ce16ff9dfd7683b083a68c09e6fedfe5c Mon Sep 17 00:00:00 2001 From: Maschell Date: Sat, 24 Sep 2022 17:57:29 +0200 Subject: [PATCH] Add option to change the button combo --- README.md | 4 +- src/main.cpp | 37 +++- src/utils/WUPSConfigItemButtonCombo.cpp | 268 ++++++++++++++++++++++++ src/utils/WUPSConfigItemButtonCombo.h | 43 ++++ 4 files changed, 344 insertions(+), 8 deletions(-) create mode 100644 src/utils/WUPSConfigItemButtonCombo.cpp create mode 100644 src/utils/WUPSConfigItemButtonCombo.h diff --git a/README.md b/README.md index 80f2456..6ae1e71 100644 --- a/README.md +++ b/README.md @@ -11,12 +11,14 @@ The screenshots will be saved on the SD card in the folder `sd:/wiiu/screenshots 3. Requires the [MemoryMappingModule](https://github.com/wiiu-env/MemoryMappingModule) in `sd:/wiiu/environments/[ENVIRONMENT]/modules`. ## Usage -Press ZL + L + ZR + R on the GamePad to take a screenshot. +Press a button combo (default is L + R + ZL + ZR) on the GamePad to take a screenshot. Via the plugin config menu (press L, DPAD Down and Minus on the GamePad, Pro Controller or Classic Controller) you can configure the plugin. The available options are the following: - **Settings**: - Enabled: (Default is true) - Enables or disables the screenshot plugin. + - Button combo: (Default is L + R + ZL + ZR) + - Changes the button combo for taking screenshots. - Screen: (Default is TV and GamePad) - Determines from which screen a screenshot should be taken. Possible options: TV & GamePad, TV only, GamePad only. - Output format: (Default is JPEG) diff --git a/src/main.cpp b/src/main.cpp index 078c84c..759df91 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,5 +1,6 @@ #include "main.h" #include "retain_vars.hpp" +#include "utils/WUPSConfigItemButtonCombo.h" #include "utils/logger.h" #include #include @@ -24,10 +25,11 @@ WUPS_USE_WUT_DEVOPTAB(); WUPS_USE_STORAGE("screenshot_plugin"); -#define ENABLED_CONFIG_STRING "enabled" -#define FORMAT_CONFIG_STRING "format" -#define QUALITY_CONFIG_STRING "quality" -#define SCREEN_CONFIG_STRING "screen" +#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" // Gets called once the loader exists. INITIALIZE_PLUGIN() { @@ -41,7 +43,7 @@ INITIALIZE_PLUGIN() { DEBUG_FUNCTION_LINE_ERR("Failed to open storage %s (%d)", WUPS_GetStorageStatusStr(storageRes), storageRes); } else { // Try to get value from storage - if ((storageRes = WUPS_GetInt(nullptr, ENABLED_CONFIG_STRING, reinterpret_cast(&gEnabled))) == WUPS_STORAGE_ERROR_NOT_FOUND) { + if ((storageRes = WUPS_GetBool(nullptr, ENABLED_CONFIG_STRING, &gEnabled)) == WUPS_STORAGE_ERROR_NOT_FOUND) { // Add the value to the storage if it's missing. if (WUPS_StoreBool(nullptr, ENABLED_CONFIG_STRING, gEnabled) != WUPS_STORAGE_ERROR_SUCCESS) { DEBUG_FUNCTION_LINE_ERR("Failed to store value"); @@ -52,7 +54,7 @@ INITIALIZE_PLUGIN() { // Try to get value from storage if ((storageRes = WUPS_GetInt(nullptr, FORMAT_CONFIG_STRING, reinterpret_cast(&gOutputFormat))) == WUPS_STORAGE_ERROR_NOT_FOUND) { // Add the value to the storage if it's missing. - if (WUPS_StoreBool(nullptr, FORMAT_CONFIG_STRING, gOutputFormat) != WUPS_STORAGE_ERROR_SUCCESS) { + if (WUPS_StoreInt(nullptr, FORMAT_CONFIG_STRING, gOutputFormat) != WUPS_STORAGE_ERROR_SUCCESS) { DEBUG_FUNCTION_LINE_ERR("Failed to store value"); } } else if (storageRes != WUPS_STORAGE_ERROR_SUCCESS) { @@ -79,6 +81,16 @@ INITIALIZE_PLUGIN() { DEBUG_FUNCTION_LINE_ERR("Failed to get value %s (%d)", WUPS_GetStorageStatusStr(storageRes), storageRes); } + // Try to get value from storage + if ((storageRes = WUPS_GetInt(nullptr, BUTTON_COMBO_CONFIG_STRING, reinterpret_cast(&gButtonCombo))) == WUPS_STORAGE_ERROR_NOT_FOUND) { + // Add the value to the storage if it's missing. + if (WUPS_StoreInt(nullptr, BUTTON_COMBO_CONFIG_STRING, (int32_t) gButtonCombo) != WUPS_STORAGE_ERROR_SUCCESS) { + DEBUG_FUNCTION_LINE_ERR("Failed to store value"); + } + } else if (storageRes != WUPS_STORAGE_ERROR_SUCCESS) { + DEBUG_FUNCTION_LINE_ERR("Failed to get value %s (%d)", WUPS_GetStorageStatusStr(storageRes), storageRes); + } + // Close storage if (WUPS_CloseStorage() != WUPS_STORAGE_ERROR_SUCCESS) { DEBUG_FUNCTION_LINE_ERR("Failed to close storage"); @@ -139,12 +151,21 @@ void boolItemCallback(ConfigItemBoolean *item, bool newValue) { DEBUG_FUNCTION_LINE("New value in %s changed: %d", item->configId, newValue); if (std::string_view(item->configId) == ENABLED_CONFIG_STRING) { gEnabled = (ImageOutputFormatEnum) newValue; - WUPS_StoreBool(nullptr, item->configId, gEnabled); } } } +void buttonComboItemChanged(ConfigItemButtonCombo *item, uint32_t newValue) { + if (item && item->configId) { + DEBUG_FUNCTION_LINE("New value in %s changed: %d", item->configId, newValue); + if (std::string_view(item->configId) == BUTTON_COMBO_CONFIG_STRING) { + gButtonCombo = newValue; + WUPS_StoreInt(nullptr, item->configId, (int32_t) gButtonCombo); + } + } +} + WUPS_GET_CONFIG() { // We open the storage, so we can persist the configuration the user did. if (WUPS_OpenStorage() != WUPS_STORAGE_ERROR_SUCCESS) { @@ -160,6 +181,8 @@ WUPS_GET_CONFIG() { WUPSConfigItemBoolean_AddToCategoryHandled(config, setting, ENABLED_CONFIG_STRING, "Enabled", gEnabled, &boolItemCallback); + WUPSConfigItemButtonCombo_AddToCategoryHandled(config, setting, BUTTON_COMBO_CONFIG_STRING, "Button combo", gButtonCombo, &buttonComboItemChanged); + ConfigItemMultipleValuesPair source[3]; source[0].value = IMAGE_SOURCE_TV_AND_DRC; source[0].valueName = (char *) "TV & GamePad"; diff --git a/src/utils/WUPSConfigItemButtonCombo.cpp b/src/utils/WUPSConfigItemButtonCombo.cpp new file mode 100644 index 0000000..fc062be --- /dev/null +++ b/src/utils/WUPSConfigItemButtonCombo.cpp @@ -0,0 +1,268 @@ +#include "WUPSConfigItemButtonCombo.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +std::string 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"; + } + return "?"; +} + +std::string getComboAsString(uint32_t value) { + std::string combo; + if (value & VPAD_BUTTON_A) { + combo += getButtonChar(VPAD_BUTTON_A).append("+"); + } + if (value & VPAD_BUTTON_B) { + combo += getButtonChar(VPAD_BUTTON_B).append("+"); + } + if (value & VPAD_BUTTON_X) { + combo += getButtonChar(VPAD_BUTTON_X).append("+"); + } + if (value & VPAD_BUTTON_Y) { + combo += getButtonChar(VPAD_BUTTON_Y).append("+"); + } + if (value & VPAD_BUTTON_L) { + combo += getButtonChar(VPAD_BUTTON_L).append("+"); + } + if (value & VPAD_BUTTON_R) { + combo += getButtonChar(VPAD_BUTTON_R).append("+"); + } + if (value & VPAD_BUTTON_ZL) { + combo += getButtonChar(VPAD_BUTTON_ZL).append("+"); + } + if (value & VPAD_BUTTON_ZR) { + combo += getButtonChar(VPAD_BUTTON_ZR).append("+"); + } + if (value & VPAD_BUTTON_UP) { + combo += getButtonChar(VPAD_BUTTON_UP).append("+"); + } + if (value & VPAD_BUTTON_DOWN) { + combo += getButtonChar(VPAD_BUTTON_DOWN).append("+"); + } + if (value & VPAD_BUTTON_LEFT) { + combo += getButtonChar(VPAD_BUTTON_LEFT).append("+"); + } + if (value & VPAD_BUTTON_RIGHT) { + combo += getButtonChar(VPAD_BUTTON_RIGHT).append("+"); + } + if (value & VPAD_BUTTON_STICK_L) { + combo += getButtonChar(VPAD_BUTTON_STICK_L).append("+"); + } + if (value & VPAD_BUTTON_STICK_R) { + combo += getButtonChar(VPAD_BUTTON_STICK_R).append("+"); + } + if (value & VPAD_BUTTON_PLUS) { + combo += getButtonChar(VPAD_BUTTON_PLUS).append("+"); + } + if (value & VPAD_BUTTON_MINUS) { + combo += getButtonChar(VPAD_BUTTON_MINUS).append("+"); + } + if (combo.ends_with("+")) { + combo.pop_back(); + } + return combo; +} + +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; +} + +bool WUPSConfigItemButtonCombo_callCallback(void *context) { + auto *item = (ConfigItemButtonCombo *) context; + if (item->callback != nullptr) { + ((ButtonComboValueChangedCallback) (item->callback))(item, item->value); + return true; + } + return false; +} + +void checkForHold(ConfigItemButtonCombo *item) { + uint32_t lastHold = 0; + uint32_t holdFor = 0; + uint32_t holdForTarget = item->holdDurationInMs >> 3; + uint32_t holdAbortTarget = item->abortButtonHoldDurationInMs >> 3; + while (true) { + uint32_t buttonsHold = 0; + VPADReadError vpad_error = VPAD_READ_UNINITIALIZED; + VPADStatus vpad_data; + VPADRead(VPAD_CHAN_0, &vpad_data, 1, &vpad_error); + if (vpad_error == VPAD_READ_SUCCESS) { + buttonsHold = vpad_data.hold; + } + + 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(8)); + } +} + +void WUPSConfigItemButtonCombo_onButtonPressed(void *context, WUPSConfigButtons buttons) { + auto *item = (ConfigItemButtonCombo *) context; + if (item->state == BUTTON_COMBO_STATE_NONE) { + if ((buttons & WUPS_CONFIG_BUTTON_A) == WUPS_CONFIG_BUTTON_A) { + item->state = BUTTON_COMBO_STATE_PREPARE_FOR_HOLD; + } + } +} + +bool WUPSConfigItemButtonCombo_isMovementAllowed(void *context) { + return true; +} + +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, "", item->holdDurationInMs, getButtonChar(item->abortButton).c_str()); + 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; +} + +void WUPSConfigItemButtonCombo_restoreDefault(void *context) { + auto *item = (ConfigItemButtonCombo *) context; + item->value = item->defaultValue; +} + +void WUPSConfigItemButtonCombo_onSelected(void *context, bool isSelected) { +} + +void WUPSConfigItemButtonCombo_onDelete(void *context) { + auto *item = (ConfigItemButtonCombo *) context; + if (item->configId) { + free(item->configId); + } + free(item); +} + +extern "C" bool +WUPSConfigItemButtonComboAddToCategoryEx(WUPSConfigCategoryHandle cat, const char *configID, const char *displayName, uint32_t defaultComboInVPADButtons, uint32_t holdDurationInMs, VPADButtons abortButton, uint32_t abortButtonHoldDurationInMs, ButtonComboValueChangedCallback callback) { + if (cat == 0) { + return false; + } + auto *item = (ConfigItemButtonCombo *) malloc(sizeof(ConfigItemButtonCombo)); + if (item == nullptr) { + OSReport("WUPSConfigItemButtonComboAddToCategoryEx: Failed to allocate memory for item data.\n"); + return false; + } + + if (configID != nullptr) { + item->configId = strdup(configID); + } else { + item->configId = nullptr; + } + + item->abortButton = abortButton; + item->abortButtonHoldDurationInMs = abortButtonHoldDurationInMs; + item->holdDurationInMs = holdDurationInMs; + item->defaultValue = defaultComboInVPADButtons; + item->value = defaultComboInVPADButtons; + item->callback = (void *) callback; + item->state = BUTTON_COMBO_STATE_NONE; + + WUPSConfigCallbacks_t callbacks = { + .getCurrentValueDisplay = &WUPSConfigItemButtonCombo_getCurrentValueDisplay, + .getCurrentValueSelectedDisplay = &WUPSConfigItemButtonCombo_getCurrentValueSelectedDisplay, + .onSelected = &WUPSConfigItemButtonCombo_onSelected, + .restoreDefault = &WUPSConfigItemButtonCombo_restoreDefault, + .isMovementAllowed = &WUPSConfigItemButtonCombo_isMovementAllowed, + .callCallback = &WUPSConfigItemButtonCombo_callCallback, + .onButtonPressed = &WUPSConfigItemButtonCombo_onButtonPressed, + .onDelete = &WUPSConfigItemButtonCombo_onDelete}; + + if (WUPSConfigItem_Create(&item->handle, configID, displayName, callbacks, item) < 0) { + OSReport("WUPSConfigItemButtonComboAddToCategoryEx: Failed to create config item.\n"); + free(item); + return false; + } + + if (WUPSConfigCategory_AddItem(cat, item->handle) < 0) { + OSReport("WUPSConfigItemButtonComboAddToCategoryEx: Failed to add item to category.\n"); + WUPSConfigItem_Destroy(item->handle); + return false; + } + return true; +} + +extern "C" bool +WUPSConfigItemButtonComboAddToCategory(WUPSConfigCategoryHandle cat, const char *configID, const char *displayName, uint32_t defaultComboInVPADButtons, ButtonComboValueChangedCallback callback) { + return WUPSConfigItemButtonComboAddToCategoryEx(cat, configID, displayName, defaultComboInVPADButtons, 2000, VPAD_BUTTON_B, 250, callback); +} \ No newline at end of file diff --git a/src/utils/WUPSConfigItemButtonCombo.h b/src/utils/WUPSConfigItemButtonCombo.h new file mode 100644 index 0000000..80c90fb --- /dev/null +++ b/src/utils/WUPSConfigItemButtonCombo.h @@ -0,0 +1,43 @@ +#include +#include +#include + +#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 { + char *configId; + WUPSConfigItemHandle handle; + uint32_t defaultValue; + uint32_t value; + uint32_t holdDurationInMs; + VPADButtons abortButton; + uint32_t abortButtonHoldDurationInMs; + void *callback; + ButtonComboState state; +} ConfigItemButtonCombo; + +typedef void (*ButtonComboValueChangedCallback)(ConfigItemButtonCombo *item, uint32_t buttonComboInVPADButtons); + +bool WUPSConfigItemButtonComboAddToCategory(WUPSConfigCategoryHandle cat, const char *configId, const char *displayName, uint32_t defaultComboInVPADButtons, ButtonComboValueChangedCallback callback); + +bool WUPSConfigItemButtonComboAddToCategoryEx(WUPSConfigCategoryHandle cat, const char *configId, const char *displayName, uint32_t defaultComboInVPADButtons, uint32_t holdDurationInMs, VPADButtons abortButton, uint32_t abortButtonHoldDurationInMs, ButtonComboValueChangedCallback callback); + +#define WUPSConfigItemButtonCombo_AddToCategoryHandled(__config__, __cat__, __configID__, __displayName__, __defaultComboInVPADButtons__, __callback__) \ + do { \ + if (!WUPSConfigItemButtonComboAddToCategory(__cat__, __configID__, __displayName__, __defaultComboInVPADButtons__, __callback__)) { \ + WUPSConfig_Destroy(__config__); \ + return 0; \ + } \ + } while (0) + +#ifdef __cplusplus +} +#endif \ No newline at end of file