Compare commits

...

9 Commits

Author SHA1 Message Date
Maschell 81bbe5f810 Fix the default button combo 2024-04-27 15:43:40 +02:00
Maschell 3ffae910c1 Bump softprops/action-gh-release from 1 to 2 2024-04-27 14:05:32 +02:00
Maschell 04e739aa4c Bump version 2024-04-27 14:05:32 +02:00
Maschell 2ecce77126 Update Dockerfile 2024-04-27 14:05:32 +02:00
Maschell aa3c5db46b Fix config menu and use latest WUPS version 2024-04-27 14:05:32 +02:00
Maschell c6e247c5cb Use the time of creating the screenshot, not the time of saving the screenshot 2024-04-27 14:05:32 +02:00
Maschell f447e0333f Implement support for WUPS 0.8.0 2024-04-27 14:05:32 +02:00
dependabot[bot] b2921402cb Bump actions/checkout from 3 to 4
Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-27 14:05:32 +02:00
dependabot[bot] 47253a73fa Bump wiiu-env/devkitppc from 20230621 to 20231112
Bumps wiiu-env/devkitppc from 20230621 to 20231112.

---
updated-dependencies:
- dependency-name: wiiu-env/devkitppc
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-27 14:05:32 +02:00
18 changed files with 435 additions and 311 deletions

View File

@ -9,7 +9,7 @@ jobs:
clang-format:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: clang-format
run: |
docker run --rm -v ${PWD}:/src ghcr.io/wiiu-env/clang-format:13.0.0-2 -r ./src
@ -17,7 +17,7 @@ jobs:
runs-on: ubuntu-22.04
needs: clang-format
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: create version.h
run: |
git_hash=$(git rev-parse --short "$GITHUB_SHA")
@ -48,7 +48,7 @@ jobs:
- name: zip artifact
run: zip -r ${{ env.REPOSITORY_NAME }}_${{ env.DATETIME }}.zip *.wps
- name: Create Release
uses: "softprops/action-gh-release@v1"
uses: "softprops/action-gh-release@v2"
with:
tag_name: ${{ env.REPOSITORY_NAME }}-${{ env.DATETIME }}
draft: false

View File

@ -6,7 +6,7 @@ jobs:
clang-format:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: clang-format
run: |
docker run --rm -v ${PWD}:/src ghcr.io/wiiu-env/clang-format:13.0.0-2 -r ./src
@ -14,7 +14,7 @@ jobs:
runs-on: ubuntu-22.04
needs: clang-format
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: create version.h
run: |
git_hash=$(git rev-parse --short "${{ github.event.pull_request.head.sha }}")

View File

@ -1,7 +1,7 @@
FROM ghcr.io/wiiu-env/devkitppc:20230621
FROM ghcr.io/wiiu-env/devkitppc:20240423
COPY --from=ghcr.io/wiiu-env/wiiupluginsystem:20230719 /artifacts $DEVKITPRO
COPY --from=ghcr.io/wiiu-env/wiiupluginsystem:20240425 /artifacts $DEVKITPRO
COPY --from=ghcr.io/wiiu-env/libmappedmemory:20230621 /artifacts $DEVKITPRO
COPY --from=ghcr.io/wiiu-env/libnotifications:20230621 /artifacts $DEVKITPRO
COPY --from=ghcr.io/wiiu-env/libnotifications:20240426 /artifacts $DEVKITPRO
WORKDIR project

View File

@ -1,21 +1,27 @@
#pragma once
#include <coreinit/time.h>
#define WIIU_SCREENSHOT_PATH "fs:/vol/external01/wiiu/screenshots/"
typedef enum {
enum ImageOutputFormatEnum {
IMAGE_OUTPUT_FORMAT_JPEG = 0,
IMAGE_OUTPUT_FORMAT_PNG = 1,
IMAGE_OUTPUT_FORMAT_BMP = 2,
} ImageOutputFormatEnum;
};
typedef enum {
enum ImageSourceEnum {
IMAGE_SOURCE_TV_AND_DRC = 0,
IMAGE_SOURCE_TV = 1,
IMAGE_SOURCE_DRC = 2,
} ImageSourceEnum;
};
enum ScreenshotState {
SCREENSHOT_STATE_READY,
SCREENSHOT_STATE_REQUESTED,
SCREENSHOT_STATE_SAVING,
};
struct ScreenshotStateInfo {
ScreenshotState state;
OSCalendarTime time;
};

View File

@ -6,6 +6,7 @@
#include "utils/utils.h"
#include <vpad/input.h>
#include <wups.h>
#include <wups/config/WUPSConfigCategory.h>
#include <wups/config/WUPSConfigItemBoolean.h>
#include <wups/config/WUPSConfigItemIntegerRange.h>
#include <wups/config/WUPSConfigItemMultipleValues.h>
@ -13,76 +14,50 @@
WUPS_USE_STORAGE("screenshot_plugin");
WUPSConfigAPICallbackStatus ConfigMenuOpenedCallback(WUPSConfigCategoryHandle rootHandle);
void ConfigMenuClosedCallback() {
WUPSStorageError storageRes;
if ((storageRes = WUPSStorageAPI::SaveStorage()) != WUPS_STORAGE_ERROR_SUCCESS) {
DEBUG_FUNCTION_LINE_ERR("Failed to close storage %s (%d)", WUPSStorageAPI::GetStatusStr(storageRes).data(), storageRes);
}
}
void InitConfig() {
gButtonCombo = VPAD_BUTTON_TV;
// Open storage to read values
WUPSStorageError storageRes = WUPS_OpenStorage();
if (storageRes != WUPS_STORAGE_ERROR_SUCCESS) {
DEBUG_FUNCTION_LINE_ERR("Failed to open storage %s (%d)", WUPS_GetStorageStatusStr(storageRes), storageRes);
} else {
// Try to get value from storage
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");
}
} else if (storageRes != WUPS_STORAGE_ERROR_SUCCESS) {
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, FORMAT_CONFIG_STRING, reinterpret_cast<int32_t *>(&gOutputFormat))) == WUPS_STORAGE_ERROR_NOT_FOUND) {
// Add the value to the storage if it's missing.
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) {
DEBUG_FUNCTION_LINE_ERR("Failed to get value %s (%d)", WUPS_GetStorageStatusStr(storageRes), storageRes);
}
WUPSConfigAPIOptionsV1 configOptions = {.name = "Screenshot Plugin"};
if (WUPSConfigAPI_Init(configOptions, ConfigMenuOpenedCallback, ConfigMenuClosedCallback) != WUPSCONFIG_API_RESULT_SUCCESS) {
DEBUG_FUNCTION_LINE_ERR("Failed to init config api");
}
// Try to get value from storage
if ((storageRes = WUPS_GetInt(nullptr, QUALITY_CONFIG_STRING, reinterpret_cast<int32_t *>(&gQuality))) == WUPS_STORAGE_ERROR_NOT_FOUND) {
// Add the value to the storage if it's missing.
if (WUPS_StoreInt(nullptr, QUALITY_CONFIG_STRING, (int32_t) gQuality) != 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);
}
gButtonCombo = BUTTON_COMBO_CONFIG_DEFAULT;
// Try to get value from storage
if ((storageRes = WUPS_GetInt(nullptr, SCREEN_CONFIG_STRING, reinterpret_cast<int32_t *>(&gImageSource))) == WUPS_STORAGE_ERROR_NOT_FOUND) {
// Add the value to the storage if it's missing.
if (WUPS_StoreInt(nullptr, SCREEN_CONFIG_STRING, (int32_t) gImageSource) != 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);
}
WUPSStorageError storageRes;
if ((storageRes = WUPSStorageAPI::GetOrStoreDefault(ENABLED_CONFIG_STRING, gEnabled, ENABLED_CONFIG_DEFAULT)) != WUPS_STORAGE_ERROR_SUCCESS) {
DEBUG_FUNCTION_LINE_ERR("Failed to GetOrStoreDefault value %s (%d)", WUPSStorageAPI::GetStatusStr(storageRes).data(), storageRes);
}
// Try to get value from storage
if ((storageRes = WUPS_GetInt(nullptr, BUTTON_COMBO_CONFIG_STRING, reinterpret_cast<int32_t *>(&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);
}
if ((storageRes = WUPSStorageAPI::GetOrStoreDefault(FORMAT_CONFIG_STRING, gOutputFormat, FORMAT_CONFIG_DEFAULT)) != WUPS_STORAGE_ERROR_SUCCESS) {
DEBUG_FUNCTION_LINE_ERR("Failed to GetOrStoreDefault value %s (%d)", WUPSStorageAPI::GetStatusStr(storageRes).data(), storageRes);
}
// Try to get value from storage
if ((storageRes = WUPS_GetBool(nullptr, RESERVED_BIT_USAGE_CONFIG_STRING, &gReservedBitUsage)) == WUPS_STORAGE_ERROR_NOT_FOUND) {
// Add the value to the storage if it's missing.
if (WUPS_StoreBool(nullptr, RESERVED_BIT_USAGE_CONFIG_STRING, gReservedBitUsage) != 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);
}
if ((storageRes = WUPSStorageAPI::GetOrStoreDefault(QUALITY_CONFIG_STRING, gQuality, QUALITY_CONFIG_DEFAULT)) != WUPS_STORAGE_ERROR_SUCCESS) {
DEBUG_FUNCTION_LINE_ERR("Failed to GetOrStoreDefault value %s (%d)", WUPSStorageAPI::GetStatusStr(storageRes).data(), storageRes);
}
// Close storage
if (WUPS_CloseStorage() != WUPS_STORAGE_ERROR_SUCCESS) {
DEBUG_FUNCTION_LINE_ERR("Failed to close storage");
}
if ((storageRes = WUPSStorageAPI::GetOrStoreDefault(SCREEN_CONFIG_STRING, gImageSource, SCREEN_CONFIG_DEFAULT)) != WUPS_STORAGE_ERROR_SUCCESS) {
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) {
DEBUG_FUNCTION_LINE_ERR("Failed to GetOrStoreDefault value %s (%d)", WUPSStorageAPI::GetStatusStr(storageRes).data(), storageRes);
}
if ((storageRes = WUPSStorageAPI::GetOrStoreDefault(RESERVED_BIT_USAGE_CONFIG_STRING, gReservedBitUsage, RESERVED_BIT_USAGE_CONFIG_DEFAULT)) != WUPS_STORAGE_ERROR_SUCCESS) {
DEBUG_FUNCTION_LINE_ERR("Failed to GetOrStoreDefault value %s (%d)", WUPSStorageAPI::GetStatusStr(storageRes).data(), storageRes);
}
if ((storageRes = WUPSStorageAPI::SaveStorage()) != WUPS_STORAGE_ERROR_SUCCESS) {
DEBUG_FUNCTION_LINE_ERR("Failed to save storage %s (%d)", WUPSStorageAPI::GetStatusStr(storageRes).data(), storageRes);
}
if (gButtonCombo & VPAD_BUTTON_TV) {
@ -104,32 +79,38 @@ void InitConfig() {
}
void multipleValueItemCallback(ConfigItemMultipleValues *item, uint32_t newValue) {
if (item && item->configId) {
if (item && item->identifier) {
DEBUG_FUNCTION_LINE("New value in %s changed: %d", item->configId, newValue);
if (std::string_view(item->configId) == FORMAT_CONFIG_STRING) {
if (std::string_view(item->identifier) == FORMAT_CONFIG_STRING) {
gOutputFormat = (ImageOutputFormatEnum) newValue;
if (gOutputFormat >= 3) {
gOutputFormat = IMAGE_OUTPUT_FORMAT_JPEG;
}
WUPS_StoreInt(nullptr, item->configId, (int32_t) newValue);
} else if (std::string_view(item->configId) == SCREEN_CONFIG_STRING) {
WUPSStorageError err;
if ((err = WUPSStorageAPI::Store(item->identifier, gOutputFormat)) != WUPS_STORAGE_ERROR_SUCCESS) {
DEBUG_FUNCTION_LINE_ERR("Failed to store item %s (newValue: %d): %s", item->identifier, gOutputFormat, WUPSStorageAPI::GetStatusStr(err).data());
}
} else if (std::string_view(item->identifier) == SCREEN_CONFIG_STRING) {
gImageSource = (ImageSourceEnum) newValue;
if (gImageSource >= 3) {
gImageSource = IMAGE_SOURCE_TV_AND_DRC;
}
WUPS_StoreInt(nullptr, item->configId, (int32_t) newValue);
WUPSStorageError err;
if ((err = WUPSStorageAPI::Store(item->identifier, gImageSource)) != WUPS_STORAGE_ERROR_SUCCESS) {
DEBUG_FUNCTION_LINE_ERR("Failed to store item %s (newValue: %d): %s", item->identifier, gImageSource, WUPSStorageAPI::GetStatusStr(err).data());
}
}
}
}
void integerRangeItemCallback(ConfigItemIntegerRange *item, int32_t newValue) {
if (item && item->configId) {
if (item && item->identifier) {
DEBUG_FUNCTION_LINE("New value in %s changed: %d", item->configId, newValue);
if (std::string_view(item->configId) == QUALITY_CONFIG_STRING) {
if (std::string_view(item->identifier) == QUALITY_CONFIG_STRING) {
gQuality = (ImageOutputFormatEnum) newValue;
if (gQuality < 10) {
@ -138,31 +119,40 @@ void integerRangeItemCallback(ConfigItemIntegerRange *item, int32_t newValue) {
gQuality = 100;
}
WUPS_StoreInt(nullptr, item->configId, (int32_t) gQuality);
WUPSStorageError err;
if ((err = WUPSStorageAPI::Store(item->identifier, gQuality)) != WUPS_STORAGE_ERROR_SUCCESS) {
DEBUG_FUNCTION_LINE_ERR("Failed to store item %s (newValue: %d): %s", item->identifier, gQuality, WUPSStorageAPI::GetStatusStr(err).data());
}
}
}
}
void boolItemCallback(ConfigItemBoolean *item, bool newValue) {
if (item && item->configId) {
if (item && item->identifier) {
DEBUG_FUNCTION_LINE("New value in %s changed: %d", item->configId, newValue);
if (std::string_view(item->configId) == ENABLED_CONFIG_STRING) {
if (std::string_view(item->identifier) == ENABLED_CONFIG_STRING) {
gEnabled = newValue;
if (gEnabled) {
InitNotificationModule();
}
WUPS_StoreBool(nullptr, item->configId, gEnabled);
} else if (std::string_view(item->configId) == RESERVED_BIT_USAGE_CONFIG_STRING) {
WUPSStorageError err;
if ((err = WUPSStorageAPI::Store(item->identifier, gEnabled)) != WUPS_STORAGE_ERROR_SUCCESS) {
DEBUG_FUNCTION_LINE_ERR("Failed to store item %s (newValue: %d): %s", item->identifier, gEnabled, WUPSStorageAPI::GetStatusStr(err).data());
}
} else if (std::string_view(item->identifier) == RESERVED_BIT_USAGE_CONFIG_STRING) {
gReservedBitUsage = newValue;
WUPS_StoreBool(nullptr, item->configId, gReservedBitUsage);
WUPSStorageError err;
if ((err = WUPSStorageAPI::Store(item->identifier, gReservedBitUsage)) != WUPS_STORAGE_ERROR_SUCCESS) {
DEBUG_FUNCTION_LINE_ERR("Failed to store item %s (newValue: %d): %s", item->identifier, gReservedBitUsage, WUPSStorageAPI::GetStatusStr(err).data());
}
}
}
}
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) {
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");
@ -171,85 +161,65 @@ void buttonComboItemChanged(ConfigItemButtonCombo *item, uint32_t newValue) {
DEBUG_FUNCTION_LINE("Unblock TV Menu");
VPADSetTVMenuInvalid(VPAD_CHAN_0, false);
}
WUPS_StoreInt(nullptr, item->configId, (int32_t) gButtonCombo);
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());
}
}
}
}
WUPS_GET_CONFIG() {
// We open the storage, so we can persist the configuration the user did.
if (WUPS_OpenStorage() != WUPS_STORAGE_ERROR_SUCCESS) {
DEBUG_FUNCTION_LINE_ERR("Failed to open storage");
return 0;
WUPSConfigAPICallbackStatus ConfigMenuOpenedCallback(WUPSConfigCategoryHandle rootHandle) {
try {
WUPSConfigCategory root = WUPSConfigCategory(rootHandle);
root.add(WUPSConfigItemBoolean::Create(ENABLED_CONFIG_STRING,
"Enabled",
ENABLED_CONFIG_DEFAULT, gEnabled,
&boolItemCallback));
root.add(WUPSConfigItemButtonCombo::Create(BUTTON_COMBO_CONFIG_STRING,
"Button combo",
BUTTON_COMBO_CONFIG_DEFAULT, gButtonCombo,
&buttonComboItemChanged));
constexpr WUPSConfigItemMultipleValues::ValuePair possibleScreenValues[] = {
{IMAGE_SOURCE_TV_AND_DRC, "TV & GamePad"},
{IMAGE_SOURCE_TV, "TV only"},
{IMAGE_SOURCE_DRC, "GamePad only"},
};
root.add(WUPSConfigItemMultipleValues::CreateFromValue(SCREEN_CONFIG_STRING,
"Screen",
SCREEN_CONFIG_DEFAULT, gImageSource,
possibleScreenValues,
&multipleValueItemCallback));
constexpr WUPSConfigItemMultipleValues::ValuePair possibleFormatValues[] = {
{IMAGE_OUTPUT_FORMAT_JPEG, "JPEG"},
{IMAGE_OUTPUT_FORMAT_PNG, "PNG"},
{IMAGE_OUTPUT_FORMAT_BMP, "BMP"}};
root.add(WUPSConfigItemMultipleValues::CreateFromValue(FORMAT_CONFIG_STRING,
"Output format",
FORMAT_CONFIG_DEFAULT, gOutputFormat,
possibleFormatValues,
&multipleValueItemCallback));
root.add(WUPSConfigItemIntegerRange::Create(QUALITY_CONFIG_STRING,
"JPEG quality",
QUALITY_CONFIG_DEFAULT, gQuality,
10, 100,
&integerRangeItemCallback));
root.add(WUPSConfigItemBoolean::Create(RESERVED_BIT_USAGE_CONFIG_STRING,
"Check ReservedBit for taking screenshots",
RESERVED_BIT_USAGE_CONFIG_DEFAULT, gReservedBitUsage,
&boolItemCallback));
} catch (std::exception &e) {
OSReport("Exception: %s\n", e.what());
return WUPSCONFIG_API_CALLBACK_RESULT_ERROR;
}
WUPSConfigHandle config;
WUPSConfig_CreateHandled(&config, "Screenshot plugin");
WUPSConfigCategoryHandle setting;
WUPSConfig_AddCategoryByNameHandled(config, "Settings", &setting);
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";
source[1].value = IMAGE_SOURCE_TV;
source[1].valueName = (char *) "TV only";
source[2].value = IMAGE_SOURCE_DRC;
source[2].valueName = (char *) "GamePad only";
uint32_t defaultIndex = 0;
uint32_t curIndex = 0;
for (auto &cur : source) {
if (cur.value == gImageSource) {
defaultIndex = curIndex;
break;
}
curIndex++;
}
WUPSConfigItemMultipleValues_AddToCategoryHandled(config, setting, SCREEN_CONFIG_STRING, "Screen", defaultIndex, source,
sizeof(source) / sizeof(source[0]), &multipleValueItemCallback);
ConfigItemMultipleValuesPair fileFormat[3];
fileFormat[0].value = IMAGE_OUTPUT_FORMAT_JPEG;
fileFormat[0].valueName = (char *) "JPEG";
fileFormat[1].value = IMAGE_OUTPUT_FORMAT_PNG;
fileFormat[1].valueName = (char *) "PNG";
fileFormat[2].value = IMAGE_OUTPUT_FORMAT_BMP;
fileFormat[2].valueName = (char *) "BMP";
defaultIndex = 0;
curIndex = 0;
for (auto &cur : fileFormat) {
if (cur.value == gOutputFormat) {
defaultIndex = curIndex;
break;
}
curIndex++;
}
WUPSConfigItemMultipleValues_AddToCategoryHandled(config, setting, FORMAT_CONFIG_STRING, "Output format", defaultIndex, fileFormat,
sizeof(fileFormat) / sizeof(fileFormat[0]), &multipleValueItemCallback);
WUPSConfigItemIntegerRange_AddToCategoryHandled(config, setting, QUALITY_CONFIG_STRING, "JPEG quality", gQuality, 10, 100, &integerRangeItemCallback);
WUPSConfigItemBoolean_AddToCategoryHandled(config, setting, RESERVED_BIT_USAGE_CONFIG_STRING, "Check ReservedBit for taking screenshots", gReservedBitUsage, &boolItemCallback);
return config;
return WUPSCONFIG_API_CALLBACK_RESULT_SUCCESS;
}
WUPS_CONFIG_CLOSED() {
// Save all changes
if (WUPS_CloseStorage() != WUPS_STORAGE_ERROR_SUCCESS) {
DEBUG_FUNCTION_LINE_ERR("Failed to close storage");
}
}

View File

@ -1,10 +1,18 @@
#pragma once
#include <vpad/input.h>
#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_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_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"
void InitConfig();

View File

@ -43,11 +43,14 @@ void RequestScreenshot() {
gNotAvailableNotificationDisplayed = true;
}
} else {
OSCalendarTime time;
OSTicksToCalendarTime(OSGetTime(), &time);
if (gImageSource == IMAGE_SOURCE_TV_AND_DRC || gImageSource == IMAGE_SOURCE_TV) {
if (gTakeScreenshotTV == SCREENSHOT_STATE_READY) {
if (gTakeScreenshotTV.state == SCREENSHOT_STATE_READY) {
DEBUG_FUNCTION_LINE("Requested screenshot for TV!");
gTakeScreenshotTV = SCREENSHOT_STATE_REQUESTED;
gReadySinceFramesTV = 0;
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,
@ -64,9 +67,11 @@ void RequestScreenshot() {
DEBUG_FUNCTION_LINE("Screenshots are blocked for DRC because it's not connected");
return;
}
if (gTakeScreenshotDRC == SCREENSHOT_STATE_READY) {
if (gTakeScreenshotDRC.state == SCREENSHOT_STATE_READY) {
DEBUG_FUNCTION_LINE("Requested screenshot for DRC!");
gTakeScreenshotDRC = SCREENSHOT_STATE_REQUESTED;
gTakeScreenshotDRC.state = SCREENSHOT_STATE_REQUESTED;
gTakeScreenshotDRC.time = time;
gReadySinceFramesDRC = 0;
} else if (!gInProgressNotificationDisplayedDRC) {
if ((err = NotificationModule_AddErrorNotificationWithCallback("Screenshot of the GamePad already in progress.",
@ -88,7 +93,7 @@ DECL_FUNCTION(int32_t, VPADRead, VPADChan chan, VPADStatus *buffer, uint32_t buf
VPADReadError real_error;
int32_t result = real_VPADRead(chan, buffer, buffer_size, &real_error);
if (gEnabled) {
if (gEnabled && gButtonCombo != 0) {
if (result > 0 && real_error == VPAD_READ_SUCCESS) {
uint32_t end = 1;
// Fix games like TP HD
@ -125,7 +130,7 @@ static uint32_t sWasHoldForXFrame[4];
DECL_FUNCTION(void, WPADRead, WPADChan chan, WPADStatusProController *data) {
real_WPADRead(chan, data);
if (gEnabled && chan >= 0 && chan < 4) {
if (gEnabled && gButtonCombo > 0 && chan >= 0 && chan < 4) {
if (data[0].err == 0) {
if (data[0].extensionType != 0xFF) {
uint32_t curButtonHold = 0;
@ -169,29 +174,29 @@ DECL_FUNCTION(void, WPADRead, WPADChan chan, WPADStatusProController *data) {
DECL_FUNCTION(void, GX2CopyColorBufferToScanBuffer, const GX2ColorBuffer *colorBuffer, GX2ScanTarget scan_target) {
if (gEnabled) {
if (gCheckIfScreenRendered) {
if (gTakeScreenshotTV == SCREENSHOT_STATE_REQUESTED && ++gReadySinceFramesTV > 5) {
gTakeScreenshotTV = SCREENSHOT_STATE_READY;
gReadySinceFramesTV = 0;
} else if (gTakeScreenshotDRC == SCREENSHOT_STATE_REQUESTED && ++gReadySinceFramesDRC > 5) {
gTakeScreenshotDRC = SCREENSHOT_STATE_READY;
gReadySinceFramesDRC = 0;
if (gTakeScreenshotTV.state == SCREENSHOT_STATE_REQUESTED && ++gReadySinceFramesTV > 5) {
gTakeScreenshotTV.state = SCREENSHOT_STATE_READY;
gReadySinceFramesTV = 0;
} else if (gTakeScreenshotDRC.state == SCREENSHOT_STATE_REQUESTED && ++gReadySinceFramesDRC > 5) {
gTakeScreenshotDRC.state = SCREENSHOT_STATE_READY;
gReadySinceFramesDRC = 0;
}
}
if (scan_target == GX2_SCAN_TARGET_TV && colorBuffer != nullptr && gTakeScreenshotTV == SCREENSHOT_STATE_REQUESTED) {
if (scan_target == GX2_SCAN_TARGET_TV && colorBuffer != nullptr && gTakeScreenshotTV.state == SCREENSHOT_STATE_REQUESTED) {
gReadySinceFramesTV = 0;
DEBUG_FUNCTION_LINE("Lets take a screenshot from TV.");
if (!takeScreenshot((GX2ColorBuffer *) colorBuffer, scan_target, gTVSurfaceFormat, gOutputFormat, gQuality)) {
gTakeScreenshotTV = SCREENSHOT_STATE_READY;
if (!takeScreenshot((GX2ColorBuffer *) colorBuffer, scan_target, gTVSurfaceFormat, gOutputFormat, gQuality, gTakeScreenshotTV.time)) {
gTakeScreenshotTV.state = SCREENSHOT_STATE_READY;
} else {
gTakeScreenshotTV = SCREENSHOT_STATE_SAVING;
gTakeScreenshotTV.state = SCREENSHOT_STATE_SAVING;
}
} else if (scan_target == GX2_SCAN_TARGET_DRC0 && colorBuffer != nullptr && gTakeScreenshotDRC == SCREENSHOT_STATE_REQUESTED) {
} else if (scan_target == GX2_SCAN_TARGET_DRC0 && colorBuffer != nullptr && gTakeScreenshotDRC.state == SCREENSHOT_STATE_REQUESTED) {
gReadySinceFramesDRC = 0;
DEBUG_FUNCTION_LINE("Lets take a screenshot from DRC.");
if (!takeScreenshot((GX2ColorBuffer *) colorBuffer, scan_target, gDRCSurfaceFormat, gOutputFormat, gQuality)) {
gTakeScreenshotDRC = SCREENSHOT_STATE_READY;
if (!takeScreenshot((GX2ColorBuffer *) colorBuffer, scan_target, gDRCSurfaceFormat, gOutputFormat, gQuality, gTakeScreenshotDRC.time)) {
gTakeScreenshotDRC.state = SCREENSHOT_STATE_READY;
} else {
gTakeScreenshotDRC = SCREENSHOT_STATE_SAVING;
gTakeScreenshotDRC.state = SCREENSHOT_STATE_SAVING;
}
}
}
@ -226,19 +231,19 @@ DECL_FUNCTION(void, GX2GetCurrentScanBuffer, GX2ScanTarget scanTarget, GX2ColorB
DECL_FUNCTION(void, GX2MarkScanBufferCopied, GX2ScanTarget scan_target) {
if (gEnabled) {
if (scan_target == GX2_SCAN_TARGET_TV && gTakeScreenshotTV == SCREENSHOT_STATE_REQUESTED) {
if (scan_target == GX2_SCAN_TARGET_TV && gTakeScreenshotTV.state == SCREENSHOT_STATE_REQUESTED) {
DEBUG_FUNCTION_LINE("Lets take a screenshot from TV.");
if (!takeScreenshot((GX2ColorBuffer *) &lastTVColorBuffer, scan_target, gTVSurfaceFormat, gOutputFormat, gQuality)) {
gTakeScreenshotTV = SCREENSHOT_STATE_READY;
if (!takeScreenshot((GX2ColorBuffer *) &lastTVColorBuffer, scan_target, gTVSurfaceFormat, gOutputFormat, gQuality, gTakeScreenshotTV.time)) {
gTakeScreenshotTV.state = SCREENSHOT_STATE_READY;
} else {
gTakeScreenshotTV = SCREENSHOT_STATE_SAVING;
gTakeScreenshotTV.state = SCREENSHOT_STATE_SAVING;
}
} else if (scan_target == GX2_SCAN_TARGET_DRC0 && gTakeScreenshotDRC == SCREENSHOT_STATE_REQUESTED) {
} else if (scan_target == GX2_SCAN_TARGET_DRC0 && gTakeScreenshotDRC.state == SCREENSHOT_STATE_REQUESTED) {
DEBUG_FUNCTION_LINE("Lets take a screenshot from DRC.");
if (!takeScreenshot((GX2ColorBuffer *) &lastDRCColorBuffer, scan_target, gDRCSurfaceFormat, gOutputFormat, gQuality)) {
gTakeScreenshotDRC = SCREENSHOT_STATE_READY;
if (!takeScreenshot((GX2ColorBuffer *) &lastDRCColorBuffer, scan_target, gDRCSurfaceFormat, gOutputFormat, gQuality, gTakeScreenshotDRC.time)) {
gTakeScreenshotDRC.state = SCREENSHOT_STATE_READY;
} else {
gTakeScreenshotDRC = SCREENSHOT_STATE_SAVING;
gTakeScreenshotDRC.state = SCREENSHOT_STATE_SAVING;
}
}
}

View File

@ -1,5 +1,5 @@
#pragma once
#include "version.h"
#define VERSION "v0.1.2"
#define VERSION "v0.1.3"
#define VERSION_FULL VERSION VERSION_EXTRA

View File

@ -1,19 +1,21 @@
#include "retain_vars.hpp"
#include "config.h"
#include <string>
GX2SurfaceFormat gTVSurfaceFormat = GX2_SURFACE_FORMAT_UNORM_R8_G8_B8_A8;
GX2SurfaceFormat gDRCSurfaceFormat = GX2_SURFACE_FORMAT_UNORM_R8_G8_B8_A8;
ImageSourceEnum gImageSource = IMAGE_SOURCE_TV_AND_DRC;
bool gEnabled = true;
uint32_t gButtonCombo = 0;
int32_t gQuality = 90;
ImageOutputFormatEnum gOutputFormat = IMAGE_OUTPUT_FORMAT_JPEG;
GX2SurfaceFormat gTVSurfaceFormat = GX2_SURFACE_FORMAT_UNORM_R8_G8_B8_A8;
GX2SurfaceFormat gDRCSurfaceFormat = GX2_SURFACE_FORMAT_UNORM_R8_G8_B8_A8;
ImageSourceEnum gImageSource = SCREEN_CONFIG_DEFAULT;
bool gEnabled = ENABLED_CONFIG_DEFAULT;
uint32_t gButtonCombo = BUTTON_COMBO_CONFIG_DEFAULT;
int32_t gQuality = QUALITY_CONFIG_DEFAULT;
ImageOutputFormatEnum gOutputFormat = FORMAT_CONFIG_DEFAULT;
bool gReservedBitUsage = RESERVED_BIT_USAGE_CONFIG_DEFAULT;
std::string gShortNameEn;
ScreenshotState gTakeScreenshotTV = SCREENSHOT_STATE_READY;
ScreenshotState gTakeScreenshotDRC = SCREENSHOT_STATE_READY;
bool gReservedBitUsage = true;
ScreenshotStateInfo gTakeScreenshotTV = {SCREENSHOT_STATE_READY};
ScreenshotStateInfo gTakeScreenshotDRC = {SCREENSHOT_STATE_READY};
bool gInProgressNotificationDisplayedDRC = false;
bool gInProgressNotificationDisplayedTV = false;

View File

@ -4,19 +4,21 @@
#include <notifications/notifications.h>
#include <string>
extern bool gEnabled;
extern ImageSourceEnum gImageSource;
extern GX2SurfaceFormat gTVSurfaceFormat;
extern GX2SurfaceFormat gDRCSurfaceFormat;
extern ImageSourceEnum gImageSource;
extern bool gEnabled;
extern uint32_t gButtonCombo;
extern int32_t gQuality;
extern ImageOutputFormatEnum gOutputFormat;
extern bool gReservedBitUsage;
extern std::string gShortNameEn;
extern ScreenshotState gTakeScreenshotTV;
extern ScreenshotState gTakeScreenshotDRC;
extern ScreenshotStateInfo gTakeScreenshotTV;
extern ScreenshotStateInfo gTakeScreenshotDRC;
extern bool gReservedBitUsage;
extern bool gInProgressNotificationDisplayedDRC;
extern bool gInProgressNotificationDisplayedTV;

View File

@ -180,14 +180,14 @@ static bool copyBuffer(GX2ColorBuffer *sourceBuffer, GX2ColorBuffer *targetBuffe
void ScreenshotSavedCallback(NotificationModuleHandle handle, void *context) {
auto scanTarget = (GX2ScanTarget) (uint32_t) context;
if (scanTarget == GX2_SCAN_TARGET_TV) {
gTakeScreenshotTV = SCREENSHOT_STATE_READY;
gTakeScreenshotTV.state = SCREENSHOT_STATE_READY;
} else {
gTakeScreenshotDRC = SCREENSHOT_STATE_READY;
gTakeScreenshotDRC.state = SCREENSHOT_STATE_READY;
}
OSMemoryBarrier();
}
bool takeScreenshot(GX2ColorBuffer *srcBuffer, GX2ScanTarget scanTarget, GX2SurfaceFormat outputBufferSurfaceFormat, ImageOutputFormatEnum outputFormat, int quality) {
bool takeScreenshot(GX2ColorBuffer *srcBuffer, GX2ScanTarget scanTarget, GX2SurfaceFormat outputBufferSurfaceFormat, ImageOutputFormatEnum outputFormat, int quality, const OSCalendarTime &time) {
if (srcBuffer == nullptr) {
DEBUG_FUNCTION_LINE_ERR("Source buffer was NULL");
return false;
@ -262,6 +262,7 @@ bool takeScreenshot(GX2ColorBuffer *srcBuffer, GX2ScanTarget scanTarget, GX2Surf
param->quality = quality;
param->format = colorBuffer.surface.format;
param->scanTarget = scanTarget;
param->time = time;
res = sendMessageToThread(param);
if (!res) {

View File

@ -9,5 +9,4 @@
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);
bool takeScreenshot(GX2ColorBuffer *srcBuffer, GX2ScanTarget scanTarget, GX2SurfaceFormat outputBufferSurfaceFormat, ImageOutputFormatEnum outputFormat, int quality, const OSCalendarTime &time);

View File

@ -4,7 +4,6 @@
#include "screenshot_utils.h"
#include "utils/StringTools.h"
#include "utils/logger.h"
#include "utils/utils.h"
#include <coreinit/cache.h>
#include <coreinit/title.h>
#include <dirent.h>
@ -14,9 +13,7 @@
FSIOThreadData gThreadData;
bool gThreadsRunning;
bool getPath(GX2ScanTarget scanTarget, ImageOutputFormatEnum outputFormat, std::string &path) {
OSCalendarTime output;
OSTicksToCalendarTime(OSGetTime(), &output);
static bool getPath(GX2ScanTarget scanTarget, ImageOutputFormatEnum outputFormat, std::string &path, OSCalendarTime &output) {
std::string buffer = string_format("%s%016llX", WIIU_SCREENSHOT_PATH, OSGetTitleID());
if (!gShortNameEn.empty()) {
buffer += string_format(" (%s)", gShortNameEn.c_str());
@ -66,7 +63,7 @@ bool getPath(GX2ScanTarget scanTarget, ImageOutputFormatEnum outputFormat, std::
return true;
}
static int32_t fsIOthreadCallback([[maybe_unused]] int argc, const char **argv) {
static int32_t fsIOThreadCallback([[maybe_unused]] int argc, const char **argv) {
auto *magic = ((FSIOThreadData *) argv);
constexpr int32_t messageSize = sizeof(magic->messages) / sizeof(magic->messages[0]);
@ -81,7 +78,7 @@ static int32_t fsIOthreadCallback([[maybe_unused]] int argc, const char **argv)
std::string path;
bool success = false;
if (getPath(message->scanTarget, message->outputFormat, path)) {
if (getPath(message->scanTarget, message->outputFormat, path, message->time)) {
DEBUG_FUNCTION_LINE("Saving to %s", path.c_str());
auto res = saveTextureAsPicture(path, message->sourceBuffer, message->width, message->height, message->pitch, message->format, message->outputFormat, message->convertRGBtoSRGB, message->quality);
if (res) {
@ -155,7 +152,7 @@ void startFSIOThreads() {
OSMemoryBarrier();
if (!OSCreateThread(threadData->thread, &fsIOthreadCallback, 1, (char *) threadData, reinterpret_cast<void *>((uint32_t) threadData->stack + stackSize), stackSize, 31, OS_THREAD_ATTRIB_AFFINITY_ANY)) {
if (!OSCreateThread(threadData->thread, &fsIOThreadCallback, 1, (char *) threadData, reinterpret_cast<void *>((uint32_t) threadData->stack + stackSize), stackSize, 31, OS_THREAD_ATTRIB_AFFINITY_ANY)) {
free(threadData->thread);
free(threadData->stack);
threadData->setup = false;

View File

@ -27,6 +27,7 @@ struct SaveScreenshotMessage {
bool convertRGBtoSRGB;
int quality;
GX2ScanTarget scanTarget;
OSCalendarTime time;
};
extern FSIOThreadData gThreadData;

View File

@ -1,5 +1,4 @@
#include "WUPSConfigItemButtonCombo.h"
#include "StringTools.h"
#include "utils/input.h"
#include <coreinit/debug.h>
#include <coreinit/thread.h>
@ -11,7 +10,7 @@
#include <vpad/input.h>
#include <wups.h>
const char *getButtonChar(VPADButtons value) {
static const char *getButtonChar(VPADButtons value) {
std::string combo;
if (value & VPAD_BUTTON_A) {
return "\ue000";
@ -70,7 +69,7 @@ const char *getButtonChar(VPADButtons value) {
return "";
}
std::string getComboAsString(uint32_t value) {
static std::string getComboAsString(uint32_t value) {
char comboString[60];
memset(comboString, 0, sizeof(comboString));
@ -91,22 +90,20 @@ std::string getComboAsString(uint32_t value) {
return res;
}
int32_t WUPSConfigItemButtonCombo_getCurrentValueDisplay(void *context, char *out_buf, int32_t out_size) {
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;
}
bool WUPSConfigItemButtonCombo_callCallback(void *context) {
static void WUPSConfigItemButtonCombo_onCloseCallback(void *context) {
auto *item = (ConfigItemButtonCombo *) context;
if (item->callback != nullptr) {
((ButtonComboValueChangedCallback) (item->callback))(item, item->value);
return true;
if (item->valueAtCreation != item->value && item->valueChangedCallback != nullptr) {
((ButtonComboValueChangedCallback) (item->valueChangedCallback))(item, item->value);
}
return false;
}
void checkForHold(ConfigItemButtonCombo *item) {
static void checkForHold(ConfigItemButtonCombo *item) {
uint32_t lastHold = 0;
uint32_t holdFor = 0;
uint32_t holdForTarget = item->holdDurationInMs >> 4;
@ -122,9 +119,8 @@ void checkForHold(ConfigItemButtonCombo *item) {
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) {
VPADStatus vpad_data = {};
if (VPADRead(VPAD_CHAN_0, &vpad_data, 1, &vpad_error) > 0 && vpad_error == VPAD_READ_SUCCESS) {
buttonsHold = vpad_data.hold;
}
@ -166,20 +162,16 @@ void checkForHold(ConfigItemButtonCombo *item) {
}
}
void WUPSConfigItemButtonCombo_onButtonPressed(void *context, WUPSConfigButtons buttons) {
static void WUPSConfigItemButtonCombo_onInput(void *context, WUPSConfigSimplePadData input) {
auto *item = (ConfigItemButtonCombo *) context;
if (item->state == BUTTON_COMBO_STATE_NONE) {
if ((buttons & WUPS_CONFIG_BUTTON_A) == WUPS_CONFIG_BUTTON_A) {
if ((input.buttons_d & 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) {
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) {
@ -195,72 +187,112 @@ int32_t WUPSConfigItemButtonCombo_getCurrentValueSelectedDisplay(void *context,
return 0;
}
void WUPSConfigItemButtonCombo_restoreDefault(void *context) {
static 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);
static void WUPSConfigItemButtonCombo_Cleanup(ConfigItemButtonCombo *item) {
if (!item) {
return;
}
free((void *) item->identifier);
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;
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 false;
return WUPSCONFIG_API_RESULT_INVALID_ARGUMENT;
}
if (configID != nullptr) {
item->configId = strdup(configID);
if (identifier != nullptr) {
item->identifier = strdup(identifier);
} else {
item->configId = nullptr;
item->identifier = nullptr;
}
item->abortButton = abortButton;
item->abortButtonHoldDurationInMs = abortButtonHoldDurationInMs;
item->holdDurationInMs = holdDurationInMs;
item->defaultValue = defaultComboInVPADButtons;
item->value = defaultComboInVPADButtons;
item->callback = (void *) callback;
item->value = currentComboInVPADButtons;
item->valueAtCreation = currentComboInVPADButtons;
item->valueChangedCallback = (void *) callback;
item->state = BUTTON_COMBO_STATE_NONE;
WUPSConfigCallbacks_t callbacks = {
WUPSConfigAPIItemCallbacksV2 callbacks = {
.getCurrentValueDisplay = &WUPSConfigItemButtonCombo_getCurrentValueDisplay,
.getCurrentValueSelectedDisplay = &WUPSConfigItemButtonCombo_getCurrentValueSelectedDisplay,
.onSelected = &WUPSConfigItemButtonCombo_onSelected,
.onSelected = nullptr,
.restoreDefault = &WUPSConfigItemButtonCombo_restoreDefault,
.isMovementAllowed = &WUPSConfigItemButtonCombo_isMovementAllowed,
.callCallback = &WUPSConfigItemButtonCombo_callCallback,
.onButtonPressed = &WUPSConfigItemButtonCombo_onButtonPressed,
.onDelete = &WUPSConfigItemButtonCombo_onDelete};
.isMovementAllowed = nullptr,
.onCloseCallback = &WUPSConfigItemButtonCombo_onCloseCallback,
.onInput = &WUPSConfigItemButtonCombo_onInput,
.onInputEx = nullptr,
.onDelete = &WUPSConfigItemButtonCombo_onDelete,
};
if (WUPSConfigItem_Create(&item->handle, configID, displayName, callbacks, item) < 0) {
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");
free(item);
return false;
WUPSConfigItemButtonCombo_Cleanup(item);
return err;
}
if (WUPSConfigCategory_AddItem(cat, item->handle) < 0) {
OSReport("WUPSConfigItemButtonComboAddToCategoryEx: Failed to add item to category.\n");
WUPSConfigItem_Destroy(item->handle);
return false;
*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;
}
return true;
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 *configID, const char *displayName, uint32_t defaultComboInVPADButtons, ButtonComboValueChangedCallback callback) {
return WUPSConfigItemButtonComboAddToCategoryEx(cat, configID, displayName, defaultComboInVPADButtons, 2000, VPAD_BUTTON_B, 250, callback);
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

@ -13,31 +13,82 @@ typedef enum ButtonComboState {
} ButtonComboState;
typedef struct ConfigItemButtonCombo {
char *configId;
const char *identifier;
WUPSConfigItemHandle handle;
uint32_t defaultValue;
uint32_t value;
uint32_t valueAtCreation;
uint32_t holdDurationInMs;
VPADButtons abortButton;
uint32_t abortButtonHoldDurationInMs;
void *callback;
ButtonComboState state;
void *valueChangedCallback;
} ConfigItemButtonCombo;
typedef void (*ButtonComboValueChangedCallback)(ConfigItemButtonCombo *item, uint32_t buttonComboInVPADButtons);
bool WUPSConfigItemButtonComboAddToCategory(WUPSConfigCategoryHandle cat, const char *configId, const char *displayName, uint32_t defaultComboInVPADButtons, ButtonComboValueChangedCallback callback);
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 WUPSConfigItemButtonComboAddToCategoryEx(WUPSConfigCategoryHandle cat, const char *configId, const char *displayName, uint32_t defaultComboInVPADButtons, uint32_t holdDurationInMs, VPADButtons abortButton, uint32_t abortButtonHoldDurationInMs, ButtonComboValueChangedCallback callback);
bool WUPSConfigItemButtonComboAddToCategory(WUPSConfigCategoryHandle cat,
const char *displayName,
uint32_t defaultComboInVPADButtons, uint32_t currentComboInVPADButtons,
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)
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

@ -0,0 +1,52 @@
#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

@ -86,22 +86,20 @@ void InitNotificationModule() {
}
NotificationModuleStatus res;
if ((res = NotificationModule_InitLibrary()) != NOTIFICATION_MODULE_RESULT_SUCCESS) {
gInitNotificationModule = true;
std::string error = string_format("Failed to init Screenshot Plugin: \n"
"NotificationModule_InitLibrary returned:\n%s\n\n"
"Please update to latest Aroma before using the plugin.\n\n"
"The plugin has been disabled. You need to enable again in the\n"
"config menu after updating\n\n"
"Hold the POWER button of your CONSOLE for 5 seconds to shut down.",
NotificationModule_GetStatusStr(res));
gEnabled = false;
WUPSStorageError storageRes = WUPS_OpenStorage();
if (storageRes == WUPS_STORAGE_ERROR_SUCCESS) {
if (WUPS_StoreBool(nullptr, ENABLED_CONFIG_STRING, gEnabled) != WUPS_STORAGE_ERROR_SUCCESS) {
DEBUG_FUNCTION_LINE_ERR("Failed to store value");
}
WUPS_CloseStorage();
gInitNotificationModule = true;
std::string error = string_format("Failed to init Screenshot Plugin: \n"
"NotificationModule_InitLibrary returned:\n%s\n\n"
"Please update to latest Aroma before using the plugin.\n\n"
"The plugin has been disabled. You need to enable again in the\n"
"config menu after updating\n\n"
"Hold the POWER button of your CONSOLE for 5 seconds to shut down.",
NotificationModule_GetStatusStr(res));
gEnabled = false;
if (WUPSStorageAPI::Store(ENABLED_CONFIG_STRING, gEnabled) != WUPS_STORAGE_ERROR_SUCCESS) {
DEBUG_FUNCTION_LINE_ERR("Failed to store value");
}
WUPSStorageAPI::SaveStorage();
OSFatal(error.c_str());
}