void debug(const char *fmt, ...) { char s[512]; memset(s, 0, 512); va_list args; va_start(args, fmt); vsprintf(s, fmt, args); va_end(args); while (aptMainLoop()) { hidScanInput(); if (hidKeysDown()) break; gfxClear(); gfxDrawText(GFX_TOP, GFX_LEFT, &fontDefault, s, 8, 32); gfxDrawText(GFX_TOP, GFX_LEFT, &fontDefault, "Press any key to continue...", 8, 64); gfxSwap(); } }
bool confirm(int confirmButton, const char *fmt, ...) { char s[512]; memset(s, 0, 512); va_list args; va_start(args, fmt); vsprintf(s, fmt, args); va_end(args); while (aptMainLoop()) { hidScanInput(); u32 key = hidKeysDown(); if (key & BIT(confirmButton)) { return true; } else if (key) { return false; } gfxClear(); gfxDrawText(GFX_TOP, GFX_LEFT, &fontDefault, s, 8, 32); gfxDrawText(GFX_TOP, GFX_LEFT, &fontDefault, "Press any key to cancel...", 8, 64); gfxDrawTextf(GFX_TOP, GFX_LEFT, &fontDefault, 8, 80, "Press (%s) to confirm...", get_button(confirmButton)); gfxSwap(); } }
void pick_file(file_s *picked, const char *path) { picker = malloc(sizeof(picker_s)); get_dir(path); // key repeat timer static time_t t_start = 0, t_end = 0, t_elapsed = 0; while (aptMainLoop()) { hidScanInput(); u32 kHeld = hidKeysHeld(); u32 kDown = hidKeysDown(); if (hidKeysUp()) { time(&t_start); // reset held timer } if (kDown & KEY_DOWN) { picker->file_index++; if (picker->file_index >= picker->file_count) picker->file_index = 0; time(&t_start); } else if (kHeld & KEY_DOWN) { time(&t_end); t_elapsed = t_end - t_start; if (t_elapsed > 0) { picker->file_index++; if (picker->file_index >= picker->file_count) picker->file_index = 0; svcSleep(100); } } if (kDown & KEY_UP) { picker->file_index--; if (picker->file_index < 0) picker->file_index = picker->file_count - 1; time(&t_start); } else if (kHeld & KEY_UP) { time(&t_end); t_elapsed = t_end - t_start; if (t_elapsed > 0) { picker->file_index--; if (picker->file_index < 0) picker->file_index = picker->file_count - 1; svcSleep(100); } } if (kDown & KEY_A) { int index = picker->file_index; if (!picker->files[index].isDir) { if (confirm(0, "Launch \"%s\" ?", picker->files[index].name)) { strncpy(picked->name, picker->files[index].name, 512); strncpy(picked->path, picker->files[index].path, 512); picked->isDir = picker->files[index].isDir; picked->size = picker->files[index].size; break; } } else { get_dir(picker->files[index].path); } } else if (kDown & KEY_X) { int index = picker->file_index; if (!picker->files[index].isDir) { const char *ext = get_filename_ext(picker->files[index].name); if (strcasecmp(ext, "3dsx") == 0) { if (confirm(3, "Add entry to boot menu: \"%s\" ?", picker->files[index].name)) { if (config->count > CONFIG_MAX_ENTRIES - 1) { debug("Maximum entries reached (%i)\n", CONFIG_MAX_ENTRIES); } else if (configAddEntry(picker->files[index].name, picker->files[index].path, 0) == 0) { debug("Added entry: %s\n", picker->files[index].name); } else { debug("Error adding entry: %s\n", picker->files[index].name); } } } } } else if (kDown & KEY_B) { // exit if we can't go back if (strlen(picker->now_path) <= 1) break; // remove slash if needed if (end_with(picker->now_path, '/')) picker->now_path[strlen(picker->now_path) - 1] = '\0'; // build path char *slash = strrchr(picker->now_path, '/'); if (slash == NULL) break; int len = (int) (slash - picker->now_path); picker->now_path[len] = '\0'; // enter new dir get_dir(picker->now_path); } gfxClear(); gfxDrawText(GFX_TOP, GFX_LEFT, &fontTitle, "*** Select a file ***", 130, 20); int minX = 16; int maxX = 400 - 16; int minY = 32; int maxY = 240 - 16; drawRect(GFX_TOP, GFX_LEFT, minX, minY, maxX, maxY, (u8) 0xFF, (u8) 0xFF, (u8) 0xFF); minY += 20; int i, y = 0; int page = picker->file_index / MAX_LINE; for (i = page * MAX_LINE; i < page * MAX_LINE + MAX_LINE; i++) { if (i >= picker->file_count) break; if (i == picker->file_index) { gfxDrawRectangle(GFX_TOP, GFX_LEFT, (u8[]) {0xDC, 0xDC, 0xDC}, minX + 4, minY + 16 * y, maxX - 23, 15); gfxDrawTextN(GFX_TOP, GFX_LEFT, &fontSelected, picker->files[i].name, 47, minX + 6, minY + 16 * y); if (!picker->files[i].isDir) { gfxDrawText(GFX_BOTTOM, GFX_LEFT, &fontTitle, "Informations", minX + 6, 20); gfxDrawText(GFX_BOTTOM, GFX_LEFT, &fontDefault, "Press (A) to launch\nPress (X) to add to boot menu", minX + 12, 40); } } else { gfxDrawTextN(GFX_TOP, GFX_LEFT, &fontDefault, picker->files[i].name, 47, minX + 6, minY + 16 * y); } y++; }
int menu_boot() { time_t start, end, elapsed; int boot_index = config->index; hidScanInput(); if (config->timeout < 0 || hidKeysHeld() & BIT(config->recovery)) { // disable autoboot timer = false; } else if (config->timeout == 0 && config->count > boot_index) { // autoboot return autoBootFix(boot_index); } time(&start); while (aptMainLoop()) { hidScanInput(); u32 kDown = hidKeysDown(); if (timer) { time(&end); elapsed = end - start; if (elapsed >= config->timeout && config->count > boot_index) { return autoBootFix(boot_index); } } if (kDown & KEY_DOWN) { timer = false; boot_index++; if (boot_index > config->count) boot_index = 0; } if (kDown & KEY_UP) { timer = false; boot_index--; if (boot_index < 0) boot_index = config->count; } if (kDown & KEY_A) { timer = false; if (boot_index == config->count) { if (menu_more() == 0) { break; } } else { if (load(config->entries[boot_index].path, config->entries[boot_index].offset) == 0) { break; } } } if (kDown & KEY_X) { timer = false; if (boot_index != config->count) { if (confirm(3, "Delete boot entry: \"%s\" ?\n", config->entries[boot_index].title)) { configRemoveEntry(boot_index); boot_index--; } } } gfxClear(); if (!timer) { gfxDrawText(GFX_TOP, GFX_LEFT, &fontTitle, "*** Grub for CTR beta ***", 120, 20); } else { gfxDrawTextf(GFX_TOP, GFX_LEFT, &fontTitle, 100, 20, "*** Booting %s in %i ***", config->entries[boot_index].title, config->timeout - elapsed); } int minX = 16, maxX = 400 - 16; int minY = 32, maxY = 240 - 8; drawRect(GFX_TOP, GFX_LEFT, minX, minY, maxX, maxY, 0xFF, 0xFF, 0xFF); minY += 20; int i; for (i = 0; i < config->count; i++) { if (i >= config->count) break; if (i == boot_index) { gfxDrawRectangle(GFX_TOP, GFX_LEFT, (u8[]) {0xDC, 0xDC, 0xDC}, minX + 4, minY + (16 * i), maxX - 23, 15); gfxDrawTextf(GFX_TOP, GFX_LEFT, &fontSelected, minX + 6, minY + (16 * i), "%s", config->entries[i].title); gfxDrawText(GFX_BOTTOM, GFX_LEFT, &fontTitle, "Informations", minX + 6, 20); gfxDrawTextf(GFX_BOTTOM, GFX_LEFT, &fontDefault, minX + 12, 40, "Name: %s\nPath: %s\nOffset: 0x%lx\n\n\nPress (A) to launch\nPress (X) to remove entry\n", config->entries[i].title, config->entries[i].path, config->entries[i].offset); } else gfxDrawText(GFX_TOP, GFX_LEFT, &fontDefault, config->entries[i].title, minX + 6, minY + (16 * i)); }
int menu_more() { menu_index = 0; while (aptMainLoop()) { hidScanInput(); u32 kDown = hidKeysDown(); if (kDown & KEY_DOWN) { menu_index++; if (menu_index >= menu_count) menu_index = 0; } if (kDown & KEY_UP) { menu_index--; if (menu_index < 0) menu_index = menu_count - 1; } if (kDown & KEY_A) { if (menu_index == 0 && menu_choose() == 0) { return 0; } else if (menu_index == 1 && menu_netloader() == 0) { return 0; } else if (menu_index == 2) { menu_config(); } else if (menu_index == 3) { reboot(); } else if (menu_index == 4) { poweroff(); } } if (kDown & KEY_B) { return -1; } gfxClear(); gfxDrawText(GFX_TOP, GFX_LEFT, &fontDefault, "*** Select an option ***", 140, 20); int minX = 16; int maxX = 400 - 16; int minY = 32; int maxY = 240 - 16; drawRect(GFX_TOP, GFX_LEFT, minX, minY, maxX, maxY, 0xFF, 0xFF, 0xFF); minY += 20; int i; for (i = 0; i < menu_count; i++) { if (i >= menu_count) break; if (i == menu_index) { gfxDrawRectangle(GFX_TOP, GFX_LEFT, (u8[]) { 0xDC, 0xDC, 0xDC }, minX + 4, minY + (16 * i), maxX - 23, 15); gfxDrawText(GFX_TOP, GFX_LEFT, &fontSelected, menu_item[i], minX + 6, minY + (16 * i)); } else gfxDrawText(GFX_TOP, GFX_LEFT, &fontDefault, menu_item[i], minX + 6, minY + (16 * i)); }