rosalina: add ability to menu to take screenshot of itself (default combo: L+Up+Select)

Only for documentation purposes, via compile-time flag.

And fix some resource leak bugs, etc.
This commit is contained in:
TuxSH 2024-09-23 00:32:48 +02:00
parent 7e4a106787
commit ef1773ef4a
5 changed files with 125 additions and 17 deletions

View File

@ -23,7 +23,9 @@ Result IFile_OpenFromArchive(IFile *file, FS_Archive archive, FS_Path filePath,
Result IFile_Close(IFile *file) Result IFile_Close(IFile *file)
{ {
return FSFILE_Close(file->handle); Result res = file->handle != 0 ? FSFILE_Close(file->handle) : 0;
file->handle = 0;
return res;
} }
Result IFile_GetSize(IFile *file, u64 *size) Result IFile_GetSize(IFile *file, u64 *size)

View File

@ -44,3 +44,5 @@ void RosalinaMenu_ShowSystemInfo();
bool rosalinaMenuShouldShowDebugInfo(void); bool rosalinaMenuShouldShowDebugInfo(void);
void RosalinaMenu_ShowDebugInfo(void); void RosalinaMenu_ShowDebugInfo(void);
void menuTakeSelfScreenshot(void);

View File

@ -49,7 +49,9 @@ Result IFile_OpenFromArchive(IFile *file, FS_Archive archive, FS_Path filePath,
Result IFile_Close(IFile *file) Result IFile_Close(IFile *file)
{ {
return FSFILE_Close(file->handle); Result res = file->handle != 0 ? FSFILE_Close(file->handle) : 0;
file->handle = 0;
return res;
} }
Result IFile_GetSize(IFile *file, u64 *size) Result IFile_GetSize(IFile *file, u64 *size)

View File

@ -40,6 +40,8 @@
#include "menus/screen_filters.h" #include "menus/screen_filters.h"
#include "shell.h" #include "shell.h"
//#define ROSALINA_MENU_SELF_SCREENSHOT 1 // uncomment this to enable the feature
u32 menuCombo = 0; u32 menuCombo = 0;
bool isHidInitialized = false; bool isHidInitialized = false;
bool isQtmInitialized = false; bool isQtmInitialized = false;
@ -61,10 +63,22 @@ bool hidShouldUseIrrst(void)
static inline u32 convertHidKeys(u32 keys) static inline u32 convertHidKeys(u32 keys)
{ {
// Nothing to do yet // No actual conversion done
return keys; return keys;
} }
void scanInputHook(void)
{
hidScanInput();
#ifdef ROSALINA_MENU_SELF_SCREENSHOT
// Ugly hack but should work. For self-documentation w/o capture card purposes only.
u32 selfScreenshotCombo = KEY_L | KEY_DUP | KEY_SELECT;
if ((hidKeysHeld() & selfScreenshotCombo) == selfScreenshotCombo && (hidKeysDown() & selfScreenshotCombo) != 0)
menuTakeSelfScreenshot();
#endif
}
u32 waitInputWithTimeout(s32 msec) u32 waitInputWithTimeout(s32 msec)
{ {
s32 n = 0; s32 n = 0;
@ -82,7 +96,7 @@ u32 waitInputWithTimeout(s32 msec)
} }
n++; n++;
hidScanInput(); scanInputHook();
keys = convertHidKeys(hidKeysDown()) | (convertHidKeys(hidKeysDownRepeat()) & DIRECTIONAL_KEYS); keys = convertHidKeys(hidKeysDown()) | (convertHidKeys(hidKeysDownRepeat()) & DIRECTIONAL_KEYS);
Draw_Unlock(); Draw_Unlock();
} while (keys == 0 && !menuShouldExit && isHidInitialized && (msec < 0 || n < msec)); } while (keys == 0 && !menuShouldExit && isHidInitialized && (msec < 0 || n < msec));
@ -108,7 +122,7 @@ u32 waitInputWithTimeoutEx(u32 *outHeldKeys, s32 msec)
} }
n++; n++;
hidScanInput(); scanInputHook();
keys = convertHidKeys(hidKeysDown()) | (convertHidKeys(hidKeysDownRepeat()) & DIRECTIONAL_KEYS); keys = convertHidKeys(hidKeysDown()) | (convertHidKeys(hidKeysDownRepeat()) & DIRECTIONAL_KEYS);
*outHeldKeys = convertHidKeys(hidKeysHeld()); *outHeldKeys = convertHidKeys(hidKeysHeld());
Draw_Unlock(); Draw_Unlock();
@ -133,7 +147,7 @@ static u32 scanHeldKeys(void)
keys = 0; keys = 0;
else else
{ {
hidScanInput(); scanInputHook();
keys = convertHidKeys(hidKeysHeld()); keys = convertHidKeys(hidKeysHeld());
} }
@ -362,7 +376,9 @@ void menuThreadMain(void)
Cheat_ApplyCheats(); Cheat_ApplyCheats();
if(((scanHeldKeys() & menuCombo) == menuCombo) && !g_blockMenuOpen) u32 kHeld = scanHeldKeys();
if(((kHeld & menuCombo) == menuCombo) && !g_blockMenuOpen)
{ {
menuEnter(); menuEnter();
if(isN3DS) N3DSMenu_UpdateStatus(); if(isN3DS) N3DSMenu_UpdateStatus();
@ -459,14 +475,7 @@ static void menuDraw(Menu *menu, u32 selected)
int n = sprintf(ipBuffer, "%hhu.%hhu.%hhu.%hhu", addr[0], addr[1], addr[2], addr[3]); int n = sprintf(ipBuffer, "%hhu.%hhu.%hhu.%hhu", addr[0], addr[1], addr[2], addr[3]);
Draw_DrawString(SCREEN_BOT_WIDTH - 10 - SPACING_X * n, 10, COLOR_WHITE, ipBuffer); Draw_DrawString(SCREEN_BOT_WIDTH - 10 - SPACING_X * n, 10, COLOR_WHITE, ipBuffer);
} }
#if 0
else if (areScreenTypesInitialized)
{
char screenTypesBuffer[32];
int n = sprintf(screenTypesBuffer, "T: %s | B: %s", topScreenType, bottomScreenType);
Draw_DrawString(SCREEN_BOT_WIDTH - 10 - SPACING_X * n, 10, COLOR_WHITE, screenTypesBuffer);
}
#endif
else else
Draw_DrawFormattedString(SCREEN_BOT_WIDTH - 10 - SPACING_X * 15, 10, COLOR_WHITE, "%15s", ""); Draw_DrawFormattedString(SCREEN_BOT_WIDTH - 10 - SPACING_X * 15, 10, COLOR_WHITE, "%15s", "");

View File

@ -302,7 +302,7 @@ static Result RosalinaMenu_WriteScreenshot(IFile *file, u32 width, bool top, boo
void RosalinaMenu_TakeScreenshot(void) void RosalinaMenu_TakeScreenshot(void)
{ {
IFile file; IFile file = {0};
Result res = 0; Result res = 0;
char filename[64]; char filename[64];
@ -340,6 +340,11 @@ void RosalinaMenu_TakeScreenshot(void)
res = 0; res = 0;
FSUSER_CloseArchive(archive); FSUSER_CloseArchive(archive);
} }
else
{
archive = 0;
goto end;
}
dateTimeToString(dateTimeStr, osGetTime(), true); dateTimeToString(dateTimeStr, osGetTime(), true);
@ -364,6 +369,9 @@ void RosalinaMenu_TakeScreenshot(void)
end: end:
IFile_Close(&file); IFile_Close(&file);
if (archive != 0)
FSUSER_CloseArchive(archive);
if (R_FAILED(Draw_AllocateFramebufferCache(FB_BOTTOM_SIZE))) if (R_FAILED(Draw_AllocateFramebufferCache(FB_BOTTOM_SIZE)))
__builtin_trap(); // We're f***ed if this happens __builtin_trap(); // We're f***ed if this happens
@ -391,6 +399,91 @@ end:
Draw_Unlock(); Draw_Unlock();
} }
while(!(waitInput() & KEY_B) && !menuShouldExit); while(!(waitInput() & KEY_B) && !menuShouldExit);
}
static Result menuWriteSelfScreenshot(IFile *file)
{
u64 total;
Result res = 0;
u32 width = 320;
u32 lineSize = 3 * width;
u32 scaleFactorY = 1;
u32 numLinesScaled = 240 * scaleFactorY;
u32 addr = 0x0D800000; // keep this in check
u32 tmp;
u32 size = ((54 + lineSize * numLinesScaled * scaleFactorY) + 0xFFF) >> 12 << 12; // round-up
u8 *buffer = NULL;
TRY(svcControlMemoryEx(&tmp, addr, 0, size, MEMOP_ALLOC | MEMOP_REGION_SYSTEM, MEMPERM_READWRITE, true));
buffer = (u8 *)addr;
Draw_CreateBitmapHeader(buffer, width, numLinesScaled);
Draw_ConvertFrameBufferLines(buffer + 54, width, 0, numLinesScaled, scaleFactorY, false, false);
TRY(IFile_Write(file, &total, buffer, 54 + lineSize * numLinesScaled * scaleFactorY, 0)); // don't forget to write the header
end:
if (buffer)
svcControlMemoryEx(&tmp, addr, 0, size, MEMOP_FREE, MEMPERM_DONTCARE, false);
return res;
}
void menuTakeSelfScreenshot(void)
{
// Optimized for N3DS. May fail due to OOM.
IFile file = {0};
Result res = 0;
char filename[100];
char dateTimeStr[64];
FS_Archive archive;
FS_ArchiveID archiveId;
s64 out;
bool isSdMode;
timeSpentConvertingScreenshot = 0;
timeSpentWritingScreenshot = 0;
if(R_FAILED(svcGetSystemInfo(&out, 0x10000, 0x203))) svcBreak(USERBREAK_ASSERT);
isSdMode = (bool)out;
archiveId = isSdMode ? ARCHIVE_SDMC : ARCHIVE_NAND_RW;
Draw_Lock();
svcFlushEntireDataCache();
res = FSUSER_OpenArchive(&archive, archiveId, fsMakePath(PATH_EMPTY, ""));
if(R_SUCCEEDED(res))
{
res = FSUSER_CreateDirectory(archive, fsMakePath(PATH_ASCII, "/luma/screenshots"), 0);
if((u32)res == 0xC82044BE) // directory already exists
res = 0;
FSUSER_CloseArchive(archive);
}
else
{
archive = 0;
goto end;
}
dateTimeToString(dateTimeStr, osGetTime(), true);
sprintf(filename, "/luma/screenshots/rosalina_menu_%s.bmp", dateTimeStr);
TRY(IFile_Open(&file, archiveId, fsMakePath(PATH_EMPTY, ""), fsMakePath(PATH_ASCII, filename), FS_OPEN_CREATE | FS_OPEN_WRITE));
TRY(menuWriteSelfScreenshot(&file));
end:
IFile_Close(&file);
if (archive != 0)
FSUSER_CloseArchive(archive);
}
#undef TRY #undef TRY
}