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)
{
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)

View File

@ -44,3 +44,5 @@ void RosalinaMenu_ShowSystemInfo();
bool rosalinaMenuShouldShowDebugInfo(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)
{
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)

View File

@ -40,6 +40,8 @@
#include "menus/screen_filters.h"
#include "shell.h"
//#define ROSALINA_MENU_SELF_SCREENSHOT 1 // uncomment this to enable the feature
u32 menuCombo = 0;
bool isHidInitialized = false;
bool isQtmInitialized = false;
@ -61,10 +63,22 @@ bool hidShouldUseIrrst(void)
static inline u32 convertHidKeys(u32 keys)
{
// Nothing to do yet
// No actual conversion done
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)
{
s32 n = 0;
@ -82,7 +96,7 @@ u32 waitInputWithTimeout(s32 msec)
}
n++;
hidScanInput();
scanInputHook();
keys = convertHidKeys(hidKeysDown()) | (convertHidKeys(hidKeysDownRepeat()) & DIRECTIONAL_KEYS);
Draw_Unlock();
} while (keys == 0 && !menuShouldExit && isHidInitialized && (msec < 0 || n < msec));
@ -108,7 +122,7 @@ u32 waitInputWithTimeoutEx(u32 *outHeldKeys, s32 msec)
}
n++;
hidScanInput();
scanInputHook();
keys = convertHidKeys(hidKeysDown()) | (convertHidKeys(hidKeysDownRepeat()) & DIRECTIONAL_KEYS);
*outHeldKeys = convertHidKeys(hidKeysHeld());
Draw_Unlock();
@ -133,7 +147,7 @@ static u32 scanHeldKeys(void)
keys = 0;
else
{
hidScanInput();
scanInputHook();
keys = convertHidKeys(hidKeysHeld());
}
@ -362,7 +376,9 @@ void menuThreadMain(void)
Cheat_ApplyCheats();
if(((scanHeldKeys() & menuCombo) == menuCombo) && !g_blockMenuOpen)
u32 kHeld = scanHeldKeys();
if(((kHeld & menuCombo) == menuCombo) && !g_blockMenuOpen)
{
menuEnter();
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]);
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
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)
{
IFile file;
IFile file = {0};
Result res = 0;
char filename[64];
@ -340,6 +340,11 @@ void RosalinaMenu_TakeScreenshot(void)
res = 0;
FSUSER_CloseArchive(archive);
}
else
{
archive = 0;
goto end;
}
dateTimeToString(dateTimeStr, osGetTime(), true);
@ -364,6 +369,9 @@ void RosalinaMenu_TakeScreenshot(void)
end:
IFile_Close(&file);
if (archive != 0)
FSUSER_CloseArchive(archive);
if (R_FAILED(Draw_AllocateFramebufferCache(FB_BOTTOM_SIZE)))
__builtin_trap(); // We're f***ed if this happens
@ -391,6 +399,91 @@ end:
Draw_Unlock();
}
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
}