mirror of
https://github.com/wiiu-env/ScreenshotWUPS.git
synced 2024-11-05 07:55:09 +01:00
Show progress of screenshots on screen
This commit is contained in:
parent
da7565dbdd
commit
0831da5703
2
Makefile
2
Makefile
@ -49,7 +49,7 @@ CXXFLAGS += -DDEBUG -DVERBOSE_DEBUG -g
|
||||
CFLAGS += -DDEBUG -DVERBOSE_DEBUG -g
|
||||
endif
|
||||
|
||||
LIBS := -lwups -lwut -lgd -lpng -ljpeg -lz -lmappedmemory
|
||||
LIBS := -lwups -lwut -lgd -lpng -ljpeg -lz -lnotifications -lmappedmemory
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# list of directories containing libraries, this must be the top level
|
||||
|
@ -13,12 +13,75 @@
|
||||
|
||||
extern "C" uint32_t VPADGetButtonProcMode(uint32_t);
|
||||
|
||||
DECL_FUNCTION(int32_t, VPADRead, VPADChan chan, VPADStatus *buffer, uint32_t buffer_size, VPADReadError *error) {
|
||||
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 (!OSIsHomeButtonMenuEnabled()) {
|
||||
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 {
|
||||
if (gImageSource == IMAGE_SOURCE_TV_AND_DRC || gImageSource == IMAGE_SOURCE_TV) {
|
||||
if (gTakeScreenshotTV == SCREENSHOT_STATE_READY) {
|
||||
DEBUG_FUNCTION_LINE("Requested screenshot for TV!");
|
||||
gTakeScreenshotTV = SCREENSHOT_STATE_REQUESTED;
|
||||
} 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 (gTakeScreenshotDRC == SCREENSHOT_STATE_READY) {
|
||||
DEBUG_FUNCTION_LINE("Requested screenshot for DRC!");
|
||||
gTakeScreenshotDRC = SCREENSHOT_STATE_REQUESTED;
|
||||
} 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();
|
||||
}
|
||||
}
|
||||
|
||||
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 && (gTakeScreenshotTV == SCREENSHOT_STATE_READY || gTakeScreenshotDRC == SCREENSHOT_STATE_READY)) {
|
||||
if (gEnabled) {
|
||||
if (result > 0 && real_error == VPAD_READ_SUCCESS) {
|
||||
uint32_t end = 1;
|
||||
// Fix games like TP HD
|
||||
@ -27,23 +90,7 @@ DECL_FUNCTION(int32_t, VPADRead, VPADChan chan, VPADStatus *buffer, uint32_t buf
|
||||
}
|
||||
for (uint32_t i = 0; i < end; i++) {
|
||||
if (((buffer[i].trigger & 0x000FFFFF) == gButtonCombo)) {
|
||||
if (!OSIsHomeButtonMenuEnabled()) {
|
||||
DEBUG_FUNCTION_LINE("Screenshots are disabled");
|
||||
} else {
|
||||
if (gImageSource == IMAGE_SOURCE_TV_AND_DRC || gImageSource == IMAGE_SOURCE_TV) {
|
||||
if (gTakeScreenshotTV == SCREENSHOT_STATE_READY) {
|
||||
DEBUG_FUNCTION_LINE("Requested screenshot for TV!");
|
||||
gTakeScreenshotTV = SCREENSHOT_STATE_REQUESTED;
|
||||
}
|
||||
}
|
||||
if (gImageSource == IMAGE_SOURCE_TV_AND_DRC || gImageSource == IMAGE_SOURCE_DRC) {
|
||||
if (gTakeScreenshotDRC == SCREENSHOT_STATE_READY) {
|
||||
DEBUG_FUNCTION_LINE("Requested screenshot for DRC!");
|
||||
gTakeScreenshotDRC = SCREENSHOT_STATE_REQUESTED;
|
||||
}
|
||||
}
|
||||
OSMemoryBarrier();
|
||||
}
|
||||
RequestScreenshot();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -60,7 +107,7 @@ static uint32_t sWPADLastButtonHold[4];
|
||||
DECL_FUNCTION(void, WPADRead, WPADChan chan, WPADStatusProController *data) {
|
||||
real_WPADRead(chan, data);
|
||||
|
||||
if (gEnabled && chan >= 0 && chan < 4 && OSIsHomeButtonMenuEnabled() && (gTakeScreenshotTV == SCREENSHOT_STATE_READY || gTakeScreenshotDRC == SCREENSHOT_STATE_READY)) {
|
||||
if (gEnabled && chan >= 0 && chan < 4) {
|
||||
if (data[0].err == 0) {
|
||||
if (data[0].extensionType != 0xFF) {
|
||||
uint32_t curButtonHold = 0;
|
||||
@ -87,19 +134,7 @@ DECL_FUNCTION(void, WPADRead, WPADChan chan, WPADStatusProController *data) {
|
||||
}
|
||||
|
||||
if (forceScreenshot || (buttonComboConverted != 0 && curButtonTrigger == buttonComboConverted)) {
|
||||
if (gImageSource == IMAGE_SOURCE_TV_AND_DRC || gImageSource == IMAGE_SOURCE_TV) {
|
||||
if (gTakeScreenshotTV == SCREENSHOT_STATE_READY) {
|
||||
DEBUG_FUNCTION_LINE("Requested screenshot for TV!");
|
||||
gTakeScreenshotTV = SCREENSHOT_STATE_REQUESTED;
|
||||
}
|
||||
}
|
||||
if (gImageSource == IMAGE_SOURCE_TV_AND_DRC || gImageSource == IMAGE_SOURCE_DRC) {
|
||||
if (gTakeScreenshotDRC == SCREENSHOT_STATE_READY) {
|
||||
DEBUG_FUNCTION_LINE("Requested screenshot for DRC!");
|
||||
gTakeScreenshotDRC = SCREENSHOT_STATE_REQUESTED;
|
||||
}
|
||||
}
|
||||
OSMemoryBarrier();
|
||||
RequestScreenshot();
|
||||
}
|
||||
|
||||
sWPADLastButtonHold[chan] = curButtonHold;
|
||||
|
10
src/main.cpp
10
src/main.cpp
@ -7,6 +7,7 @@
|
||||
#include <coreinit/title.h>
|
||||
#include <malloc.h>
|
||||
#include <nn/acp.h>
|
||||
#include <notifications/notifications.h>
|
||||
#include <string>
|
||||
#include <wups.h>
|
||||
#include <wups/config/WUPSConfigItemBoolean.h>
|
||||
@ -38,6 +39,11 @@ INITIALIZE_PLUGIN() {
|
||||
gButtonCombo = VPAD_BUTTON_TV;
|
||||
OSMemoryBarrier();
|
||||
|
||||
NotificationModuleStatus res;
|
||||
if ((res = NotificationModule_InitLibrary()) != NOTIFICATION_MODULE_RESULT_SUCCESS) {
|
||||
DEBUG_FUNCTION_LINE_ERR("NotificationModule_InitLibrary failed: %s", NotificationModule_GetStatusStr(res));
|
||||
}
|
||||
|
||||
// Open storage to read values
|
||||
WUPSStorageError storageRes = WUPS_OpenStorage();
|
||||
if (storageRes != WUPS_STORAGE_ERROR_SUCCESS) {
|
||||
@ -117,6 +123,10 @@ INITIALIZE_PLUGIN() {
|
||||
}
|
||||
}
|
||||
|
||||
DEINITIALIZE_PLUGIN() {
|
||||
NotificationModule_DeInitLibrary();
|
||||
}
|
||||
|
||||
void multipleValueItemCallback(ConfigItemMultipleValues *item, uint32_t newValue) {
|
||||
if (item && item->configId) {
|
||||
DEBUG_FUNCTION_LINE("New value in %s changed: %d", item->configId, newValue);
|
||||
|
@ -13,4 +13,10 @@ std::string gShortNameEn;
|
||||
ScreenshotState gTakeScreenshotTV = SCREENSHOT_STATE_READY;
|
||||
ScreenshotState gTakeScreenshotDRC = SCREENSHOT_STATE_READY;
|
||||
|
||||
bool gReservedBitUsage = true;
|
||||
bool gReservedBitUsage = true;
|
||||
|
||||
bool gInProgressNotificationDisplayedDRC = false;
|
||||
bool gInProgressNotificationDisplayedTV = false;
|
||||
bool gNotAvailableNotificationDisplayed = false;
|
||||
|
||||
NMColor COLOR_RED = {237, 28, 36, 255};
|
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
#include "common.h"
|
||||
#include <gx2/surface.h>
|
||||
#include <notifications/notifications.h>
|
||||
#include <string>
|
||||
|
||||
extern bool gEnabled;
|
||||
@ -15,4 +16,10 @@ extern std::string gShortNameEn;
|
||||
extern ScreenshotState gTakeScreenshotTV;
|
||||
extern ScreenshotState gTakeScreenshotDRC;
|
||||
|
||||
extern bool gReservedBitUsage;
|
||||
extern bool gReservedBitUsage;
|
||||
|
||||
extern bool gInProgressNotificationDisplayedDRC;
|
||||
extern bool gInProgressNotificationDisplayedTV;
|
||||
extern bool gNotAvailableNotificationDisplayed;
|
||||
|
||||
extern NMColor COLOR_RED;
|
@ -9,6 +9,7 @@
|
||||
#include <gx2/event.h>
|
||||
#include <gx2/mem.h>
|
||||
#include <memory/mappedmemory.h>
|
||||
#include <notifications/notifications.h>
|
||||
#include <valarray>
|
||||
|
||||
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) {
|
||||
@ -176,11 +177,31 @@ 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;
|
||||
} else {
|
||||
gTakeScreenshotDRC = SCREENSHOT_STATE_READY;
|
||||
}
|
||||
OSMemoryBarrier();
|
||||
}
|
||||
|
||||
bool takeScreenshot(GX2ColorBuffer *srcBuffer, GX2ScanTarget scanTarget, GX2SurfaceFormat outputBufferSurfaceFormat, ImageOutputFormatEnum outputFormat, int quality) {
|
||||
if (srcBuffer == nullptr) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Source buffer was NULL");
|
||||
return false;
|
||||
}
|
||||
auto text = string_format("\ue01e Saving screenshot of the %s...", scanTarget == GX2_SCAN_TARGET_TV ? "TV" : "GamePad");
|
||||
NotificationModuleHandle screenshot;
|
||||
NotificationModuleStatus err;
|
||||
if ((err = NotificationModule_AddDynamicNotificationWithCallback(text.c_str(),
|
||||
&screenshot,
|
||||
ScreenshotSavedCallback,
|
||||
(void *) scanTarget)) != NOTIFICATION_MODULE_RESULT_SUCCESS) {
|
||||
DEBUG_FUNCTION_LINE_ERR("NotificationModule_AddDynamicNotificationWithCallback failed: %s", NotificationModule_GetStatusStr(err));
|
||||
return false;
|
||||
}
|
||||
|
||||
GX2ColorBuffer colorBuffer;
|
||||
|
||||
@ -231,6 +252,7 @@ bool takeScreenshot(GX2ColorBuffer *srcBuffer, GX2ScanTarget scanTarget, GX2Surf
|
||||
goto error;
|
||||
}
|
||||
|
||||
param->notificationHandle = screenshot;
|
||||
param->sourceBuffer = (uint8_t *) colorBuffer.surface.image;
|
||||
param->width = width;
|
||||
param->height = height;
|
||||
@ -257,5 +279,13 @@ error:
|
||||
colorBuffer.surface.image = nullptr;
|
||||
}
|
||||
|
||||
auto errorText = string_format("\ue01e Saving screenshot of the %s failed", scanTarget == GX2_SCAN_TARGET_TV ? "TV" : "GamePad");
|
||||
if ((err = NotificationModule_UpdateDynamicNotificationText(screenshot, errorText.c_str())) != NOTIFICATION_MODULE_RESULT_SUCCESS ||
|
||||
(err = NotificationModule_UpdateDynamicNotificationBackgroundColor(screenshot, COLOR_RED)) != NOTIFICATION_MODULE_RESULT_SUCCESS ||
|
||||
(err = NotificationModule_FinishDynamicNotificationWithShake(screenshot, 2.0f, 0.5f)) != NOTIFICATION_MODULE_RESULT_SUCCESS) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to update notification: %s", NotificationModule_GetStatusStr(err));
|
||||
}
|
||||
|
||||
OSMemoryBarrier();
|
||||
return false;
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
#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>
|
||||
@ -84,20 +85,25 @@ static int32_t fsIOthreadCallback([[maybe_unused]] int argc, const char **argv)
|
||||
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) {
|
||||
DEBUG_FUNCTION_LINE("Saving screenshot was successful");
|
||||
NotificationModuleStatus err;
|
||||
auto text = string_format("\ue01e Saving screenshot of the %s done!", message->scanTarget == GX2_SCAN_TARGET_TV ? "TV" : "GamePad");
|
||||
if ((err = NotificationModule_UpdateDynamicNotificationText(message->notificationHandle, text.c_str())) != NOTIFICATION_MODULE_RESULT_SUCCESS ||
|
||||
(err = NotificationModule_FinishDynamicNotification(message->notificationHandle, 2.0)) != NOTIFICATION_MODULE_RESULT_SUCCESS) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to update notification: %s", NotificationModule_GetStatusStr(err));
|
||||
}
|
||||
success = true;
|
||||
}
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to get and create path");
|
||||
}
|
||||
if (!success) {
|
||||
DEBUG_FUNCTION_LINE("Saving screenshot failed");
|
||||
}
|
||||
|
||||
if (message->scanTarget == GX2_SCAN_TARGET_TV) {
|
||||
gTakeScreenshotTV = SCREENSHOT_STATE_READY;
|
||||
} else if (message->scanTarget == GX2_SCAN_TARGET_DRC) {
|
||||
gTakeScreenshotDRC = SCREENSHOT_STATE_READY;
|
||||
NotificationModuleStatus err;
|
||||
auto errorText = string_format("\ue01e Saving screenshot of the %s failed", message->scanTarget == GX2_SCAN_TARGET_TV ? "TV" : "GamePad");
|
||||
if ((err = NotificationModule_UpdateDynamicNotificationText(message->notificationHandle, errorText.c_str())) != NOTIFICATION_MODULE_RESULT_SUCCESS ||
|
||||
(err = NotificationModule_UpdateDynamicNotificationBackgroundColor(message->notificationHandle, COLOR_RED)) != NOTIFICATION_MODULE_RESULT_SUCCESS ||
|
||||
(err = NotificationModule_FinishDynamicNotificationWithShake(message->notificationHandle, 2.0f, 0.5f)) != NOTIFICATION_MODULE_RESULT_SUCCESS) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to update notification: %s", NotificationModule_GetStatusStr(err));
|
||||
}
|
||||
}
|
||||
|
||||
// Free the colorbuffer copy.
|
||||
|
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
#include "common.h"
|
||||
#include "notifications/notifications.h"
|
||||
#include <coreinit/messagequeue.h>
|
||||
#include <coreinit/semaphore.h>
|
||||
#include <coreinit/thread.h>
|
||||
@ -16,6 +17,7 @@ struct FSIOThreadData {
|
||||
};
|
||||
|
||||
struct SaveScreenshotMessage {
|
||||
NotificationModuleHandle notificationHandle;
|
||||
uint8_t *sourceBuffer;
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
|
Loading…
Reference in New Issue
Block a user