#include <stdio.h>#include <stdlib.h>#include <string.h> #include <gccore.h>#include <wiiuse/wpad.h>#include <ogc/wiilaunch.h> #define VISIBLE_ROWS 8#define VISIBLE_COLS 12 #define INPUT_ANY() (wpad_down | pad_down)#define INPUT_HOME() ((wpad_down & WPAD_BUTTON_HOME) | (pad_down & PAD_BUTTON_MENU))#define INPUT_ACCEPT() ((wpad_down & WPAD_BUTTON_A) | (pad_down & PAD_BUTTON_A))#define INPUT_BACK() ((wpad_down & WPAD_BUTTON_B) | (pad_down & PAD_BUTTON_B))#define INPUT_UP() ((wpad_down & WPAD_BUTTON_UP) | (pad_down & PAD_BUTTON_UP))#define INPUT_DOWN() ((wpad_down & WPAD_BUTTON_DOWN) | (pad_down & PAD_BUTTON_DOWN))#define INPUT_LEFT() ((wpad_down & WPAD_BUTTON_LEFT) | (pad_down & PAD_BUTTON_LEFT))#define INPUT_RIGHT() ((wpad_down & WPAD_BUTTON_RIGHT) | (pad_down & PAD_BUTTON_RIGHT)) static u32 wpad_down = 0;static u32 wpad_held = 0;static u32 pad_down = 0;static u32 pad_held = 0; static u32 *xfb = NULL;static GXRModeObj *rmode = NULL; void video_init() { VIDEO_Init(); rmode = VIDEO_GetPreferredMode(NULL); xfb = MEM_K0_TO_K1(SYS_AllocateFramebuffer(rmode)); console_init(xfb, 20, 20, rmode->fbWidth, rmode->xfbHeight, rmode->fbWidth * VI_DISPLAY_PIX_SZ); VIDEO_Configure(rmode); VIDEO_SetNextFramebuffer(xfb); VIDEO_SetBlack(FALSE); VIDEO_Flush(); VIDEO_WaitVSync(); if (rmode->viTVMode & VI_NON_INTERLACE) VIDEO_WaitVSync();} void poll_input(void) { WPAD_ScanPads(); PAD_ScanPads(); wpad_down = WPAD_ButtonsDown(0); wpad_held = WPAD_ButtonsHeld(0); pad_down = PAD_ButtonsDown(0); pad_held = PAD_ButtonsHeld(0);} void render_titles(int hl_idx, u64 *title_ids, int n_titles) { for (int i = 0; i < n_titles && i < VISIBLE_ROWS * VISIBLE_COLS; i++) { int row = 4 + (i / VISIBLE_COLS) * 2; int col = 1 + (i % VISIBLE_COLS) * 6; char *t = (char*)&title_ids[i] + 4; printf("\x1b[%d;%dH%c%c%c%c", row, col, t[0], t[1], t[2], t[3]); if (i == hl_idx) { int x = ((col * 8) - 2) / 2; int y = (row * 16) - 2; for (int j = 0; j < 20; j++) { int off = (y+j) * 320 + x; for (int k = 0; k < 18; k++) { u32 *color = &xfb[off+k]; if (*color == COLOR_BLACK) *color = COLOR_BLUE; } } } }} int main() { video_init(); VIDEO_ClearFrameBuffer(rmode, xfb, COLOR_BLACK); printf("\x1b[1;1HChannel Launcher"); WII_Initialize(); int n_titles = 0; ES_GetNumTitles((u32*)&n_titles); if (n_titles <= 0) { printf("\x1b[3;1HFailed to list titles. Exiting..."); return 1; } int size = (2 * n_titles * sizeof(u64)) + 0x20; void *mem = calloc(size, 1); u64 *all_title_ids = (u64*)(((u32)mem + 0x1f) & ~0x1f); u64 *title_ids = &all_title_ids[n_titles]; ES_GetTitles(all_title_ids, n_titles); int n_visible_ids = 0; for (int i = 0; i < n_titles; i++) { char *t = (char*)&all_title_ids[i] + 4; if (t[0] < ' ' || t[1] < ' ' || t[2] < ' ' || t[3] < ' ' || t[0] > '~' || t[1] > '~' || t[2] > '~' || t[3] > '~') { continue; } title_ids[n_visible_ids++] = all_title_ids[i]; } int hl = 0; render_titles(hl, title_ids, n_visible_ids); WPAD_Init(); PAD_Init(); while (1) { VIDEO_WaitVSync(); poll_input(); if (INPUT_HOME()) break; if (INPUT_ACCEPT()) { if (hl >= 0 && hl < n_visible_ids) { char *t = (char*)&title_ids[hl] + 4; printf("\x1b[2;1HLaunching %c%c%c%c...", t[0], t[1], t[2], t[3]); WII_LaunchTitle(title_ids[hl]); } } int delta = 0; if (INPUT_UP()) delta = -VISIBLE_COLS; else if (INPUT_DOWN()) delta = VISIBLE_COLS; else if (INPUT_LEFT()) delta = -1; else if (INPUT_RIGHT()) delta = 1; int next_hl = hl + delta; if (next_hl >= 0 && next_hl < n_visible_ids) hl = next_hl; if (INPUT_ANY()) { VIDEO_ClearFrameBuffer(rmode, xfb, COLOR_BLACK); printf("\x1b[1;1HChannel Launcher"); render_titles(hl, title_ids, n_visible_ids); } } printf("\x1b[2;1HExiting..."); return 0;}