diff --git a/sysmodules/loader/source/ifile.c b/sysmodules/loader/source/ifile.c index 462d632b..fd736055 100644 --- a/sysmodules/loader/source/ifile.c +++ b/sysmodules/loader/source/ifile.c @@ -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) diff --git a/sysmodules/rosalina/include/menus.h b/sysmodules/rosalina/include/menus.h index ea9135b7..59ee509f 100644 --- a/sysmodules/rosalina/include/menus.h +++ b/sysmodules/rosalina/include/menus.h @@ -44,3 +44,5 @@ void RosalinaMenu_ShowSystemInfo(); bool rosalinaMenuShouldShowDebugInfo(void); void RosalinaMenu_ShowDebugInfo(void); + +void menuTakeSelfScreenshot(void); diff --git a/sysmodules/rosalina/source/ifile.c b/sysmodules/rosalina/source/ifile.c index 65164d3b..94951d1e 100644 --- a/sysmodules/rosalina/source/ifile.c +++ b/sysmodules/rosalina/source/ifile.c @@ -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) diff --git a/sysmodules/rosalina/source/menu.c b/sysmodules/rosalina/source/menu.c index ef6c1bde..f172a94c 100644 --- a/sysmodules/rosalina/source/menu.c +++ b/sysmodules/rosalina/source/menu.c @@ -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", ""); diff --git a/sysmodules/rosalina/source/menus.c b/sysmodules/rosalina/source/menus.c index a6ce9fe0..6ac4523d 100644 --- a/sysmodules/rosalina/source/menus.c +++ b/sysmodules/rosalina/source/menus.c @@ -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 -}