uint64_t menu_input(void *data) { unsigned i; uint64_t input_state; rgui_handle_t *rgui; #ifdef RARCH_CONSOLE static const struct retro_keybind *binds[] = { g_settings.input.menu_binds }; #else static const struct retro_keybind *binds[] = { g_settings.input.binds[0] }; #endif rgui = (rgui_handle_t*)data; input_state = 0; if (!rgui) return 0; input_push_analog_dpad((struct retro_keybind*)binds[0], (g_settings.input.analog_dpad_mode[0] == ANALOG_DPAD_NONE) ? ANALOG_DPAD_LSTICK : g_settings.input.analog_dpad_mode[0]); for (i = 0; i < MAX_PLAYERS; i++) input_push_analog_dpad(g_settings.input.autoconf_binds[i], g_settings.input.analog_dpad_mode[i]); for (i = 0; i < RETRO_DEVICE_ID_JOYPAD_R2; i++) { input_state |= input_input_state_func(binds, 0, RETRO_DEVICE_JOYPAD, 0, i) ? (1ULL << i) : 0; #ifdef HAVE_OVERLAY input_state |= (driver.overlay_state.buttons & (UINT64_C(1) << i)) ? (1ULL << i) : 0; #endif } input_state |= input_key_pressed_func(RARCH_MENU_TOGGLE) ? (1ULL << RARCH_MENU_TOGGLE) : 0; input_pop_analog_dpad((struct retro_keybind*)binds[0]); for (i = 0; i < MAX_PLAYERS; i++) input_pop_analog_dpad(g_settings.input.autoconf_binds[i]); rgui->trigger_state = input_state & ~rgui->old_input_state; rgui->do_held = (input_state & ( (1ULL << RETRO_DEVICE_ID_JOYPAD_UP) | (1ULL << RETRO_DEVICE_ID_JOYPAD_DOWN) | (1ULL << RETRO_DEVICE_ID_JOYPAD_LEFT) | (1ULL << RETRO_DEVICE_ID_JOYPAD_RIGHT) | (1ULL << RETRO_DEVICE_ID_JOYPAD_L) | (1ULL << RETRO_DEVICE_ID_JOYPAD_R) )) && !(input_state & (1ULL << RARCH_MENU_TOGGLE)); return input_state; }
static void *android_app_entry(void *data) { struct android_app* android_app = (struct android_app*)data; android_app->config = AConfiguration_new(); AConfiguration_fromAssetManager(android_app->config, android_app->activity->assetManager); print_cur_config(android_app); ALooper* looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS); ALooper_addFd(looper, android_app->msgread, LOOPER_ID_MAIN, ALOOPER_EVENT_INPUT, NULL, NULL); android_app->looper = looper; pthread_mutex_lock(&android_app->mutex); android_app->running = 1; pthread_cond_broadcast(&android_app->cond); pthread_mutex_unlock(&android_app->mutex); memset(&g_android, 0, sizeof(g_android)); g_android = android_app; RARCH_LOG("Native Activity started.\n"); rarch_main_clear_state(); while (!android_app->window) { if (!android_run_events(android_app)) goto exit; } rarch_init_msg_queue(); if (!android_app_start_main(android_app)) { g_settings.input.overlay[0] = 0; // threaded video doesn't work right for just displaying one frame g_settings.video.threaded = false; init_drivers(); driver.video_poke->set_aspect_ratio(driver.video_data, ASPECT_RATIO_SQUARE); rarch_render_cached_frame(); sleep(2); goto exit; } if (!g_extern.libretro_dummy) menu_rom_history_push_current(); for (;;) { if (g_extern.system.shutdown) break; else if (g_extern.lifecycle_mode_state & (1ULL << MODE_LOAD_GAME)) { load_menu_game_prepare(); // If ROM load fails, we exit RetroArch. On console it might make more sense to go back to menu though ... if (load_menu_game()) g_extern.lifecycle_mode_state |= (1ULL << MODE_GAME); else { #ifdef RARCH_CONSOLE g_extern.lifecycle_mode_state |= (1ULL << MODE_MENU); #else return NULL; #endif } g_extern.lifecycle_mode_state &= ~(1ULL << MODE_LOAD_GAME); } else if (g_extern.lifecycle_mode_state & (1ULL << MODE_GAME)) { driver.input->poll(NULL); if (driver.video_poke->set_aspect_ratio) driver.video_poke->set_aspect_ratio(driver.video_data, g_settings.video.aspect_ratio_idx); if (g_extern.lifecycle_mode_state & (1ULL << MODE_VIDEO_THROTTLE_ENABLE)) audio_start_func(); // Main loop while (rarch_main_iterate()); if (g_extern.lifecycle_mode_state & (1ULL << MODE_VIDEO_THROTTLE_ENABLE)) audio_stop_func(); g_extern.lifecycle_mode_state &= ~(1ULL << MODE_GAME); } else if(g_extern.lifecycle_mode_state & (1ULL << MODE_MENU)) { g_extern.lifecycle_mode_state |= (1ULL << MODE_MENU_PREINIT); while((input_key_pressed_func(RARCH_PAUSE_TOGGLE)) ? android_run_events(android_app) : menu_iterate()); g_extern.lifecycle_mode_state &= ~(1ULL << MODE_MENU); } else break; } exit: android_app->activityState = APP_CMD_DEAD; RARCH_LOG("Deinitializing RetroArch...\n"); menu_free(); if (g_extern.config_save_on_exit && *g_extern.config_path) config_save_file(g_extern.config_path); if (g_extern.main_is_init) rarch_main_deinit(); rarch_deinit_msg_queue(); #ifdef PERF_TEST rarch_perf_log(); #endif rarch_main_clear_state(); RARCH_LOG("android_app_destroy!"); if (android_app->inputQueue != NULL) AInputQueue_detachLooper(android_app->inputQueue); AConfiguration_delete(android_app->config); // exit() here is nasty. // pthread_exit(NULL) or return NULL; causes hanging ... // Should probably called ANativeActivity_finsih(), but it's bugged, it will hang our app. exit(0); }
bool menu_iterate(void *data) { unsigned action; static bool initial_held = true; static bool first_held = false; uint64_t input_state; int32_t input_entry_ret, ret; rgui_handle_t *rgui; input_state = 0; input_entry_ret = 0; ret = 0; rgui = (rgui_handle_t*)data; if (!rgui) return false; if (g_extern.lifecycle_state & (1ULL << MODE_MENU_PREINIT)) { rgui->need_refresh = true; g_extern.lifecycle_state &= ~(1ULL << MODE_MENU_PREINIT); rgui->old_input_state |= 1ULL << RARCH_MENU_TOGGLE; } rarch_input_poll(); rarch_check_block_hotkey(); #ifdef HAVE_OVERLAY rarch_check_overlay(); #endif rarch_check_fullscreen(); if (input_key_pressed_func(RARCH_QUIT_KEY) || !video_alive_func()) { g_extern.lifecycle_state |= (1ULL << MODE_GAME); return false; } input_state = menu_input(rgui); if (rgui->do_held) { if (!first_held) { first_held = true; rgui->delay_timer = initial_held ? 12 : 6; rgui->delay_count = 0; } if (rgui->delay_count >= rgui->delay_timer) { first_held = false; rgui->trigger_state = input_state; rgui->scroll_accel = min(rgui->scroll_accel + 1, 64); } initial_held = false; } else { first_held = false; initial_held = true; rgui->scroll_accel = 0; } rgui->delay_count++; rgui->old_input_state = input_state; if (driver.block_input) rgui->trigger_state = 0; action = RGUI_ACTION_NOOP; // don't run anything first frame, only capture held inputs for old_input_state if (rgui->trigger_state & (1ULL << RETRO_DEVICE_ID_JOYPAD_UP)) action = RGUI_ACTION_UP; else if (rgui->trigger_state & (1ULL << RETRO_DEVICE_ID_JOYPAD_DOWN)) action = RGUI_ACTION_DOWN; else if (rgui->trigger_state & (1ULL << RETRO_DEVICE_ID_JOYPAD_LEFT)) action = RGUI_ACTION_LEFT; else if (rgui->trigger_state & (1ULL << RETRO_DEVICE_ID_JOYPAD_RIGHT)) action = RGUI_ACTION_RIGHT; else if (rgui->trigger_state & (1ULL << RETRO_DEVICE_ID_JOYPAD_L)) action = RGUI_ACTION_SCROLL_UP; else if (rgui->trigger_state & (1ULL << RETRO_DEVICE_ID_JOYPAD_R)) action = RGUI_ACTION_SCROLL_DOWN; else if (rgui->trigger_state & (1ULL << RETRO_DEVICE_ID_JOYPAD_B)) action = RGUI_ACTION_CANCEL; else if (rgui->trigger_state & (1ULL << RETRO_DEVICE_ID_JOYPAD_A)) action = RGUI_ACTION_OK; else if (rgui->trigger_state & (1ULL << RETRO_DEVICE_ID_JOYPAD_START)) action = RGUI_ACTION_START; if (driver.menu_ctx && driver.menu_ctx->backend && driver.menu_ctx->backend->iterate) input_entry_ret = driver.menu_ctx->backend->iterate(rgui, action); if (driver.video_data && driver.video_poke && driver.video_poke->set_texture_enable) driver.video_poke->set_texture_enable(driver.video_data, rgui->frame_buf_show, MENU_TEXTURE_FULLSCREEN); rarch_render_cached_frame(); // Throttle in case VSync is broken (avoid 1000+ FPS RGUI). rgui->time = rarch_get_time_usec(); rgui->delta = (rgui->time - rgui->last_time) / 1000; rgui->target_msec = 750 / g_settings.video.refresh_rate; // Try to sleep less, so we can hopefully rely on FPS logger. rgui->sleep_msec = rgui->target_msec - rgui->delta; if (rgui->sleep_msec > 0) rarch_sleep((unsigned int)rgui->sleep_msec); rgui->last_time = rarch_get_time_usec(); if (driver.video_data && driver.video_poke && driver.video_poke->set_texture_enable) driver.video_poke->set_texture_enable(driver.video_data, false, MENU_TEXTURE_FULLSCREEN); if (driver.menu_ctx && driver.menu_ctx->input_postprocess) ret = driver.menu_ctx->input_postprocess(rgui, rgui->old_input_state); if (ret < 0) { unsigned type = 0; file_list_get_last(rgui->menu_stack, NULL, &type); while (type != RGUI_SETTINGS) { file_list_pop(rgui->menu_stack, &rgui->selection_ptr); file_list_get_last(rgui->menu_stack, NULL, &type); } } if (ret || input_entry_ret) return false; return true; }
bool menu_iterate(void) { rarch_time_t time, delta, target_msec, sleep_msec; static bool initial_held = true; static bool first_held = false; uint64_t input_state = 0; int input_entry_ret; if (g_extern.lifecycle_mode_state & (1ULL << MODE_MENU_PREINIT)) { rgui->need_refresh = true; g_extern.lifecycle_mode_state &= ~(1ULL << MODE_MENU_PREINIT); rgui->old_input_state |= 1ULL << DEVICE_NAV_MENU; } rarch_input_poll(); #ifdef HAVE_OVERLAY rarch_check_overlay(); #endif if (input_key_pressed_func(RARCH_QUIT_KEY) || !video_alive_func()) { g_extern.lifecycle_mode_state |= (1ULL << MODE_GAME); goto deinit; } input_state = rgui_input(); if (rgui->do_held) { if (!first_held) { first_held = true; rgui->delay_timer = initial_held ? 12 : 6; rgui->delay_count = 0; } if (rgui->delay_count >= rgui->delay_timer) { first_held = false; rgui->trigger_state = input_state; } initial_held = false; } else { first_held = false; initial_held = true; } rgui->delay_count++; rgui->old_input_state = input_state; input_entry_ret = rgui_iterate(rgui); if (driver.video_poke && driver.video_poke->set_texture_enable) driver.video_poke->set_texture_enable(driver.video_data, rgui->frame_buf_show, MENU_TEXTURE_FULLSCREEN); rarch_render_cached_frame(); // Throttle in case VSync is broken (avoid 1000+ FPS RGUI). time = rarch_get_time_usec(); delta = (time - rgui->last_time) / 1000; target_msec = 750 / g_settings.video.refresh_rate; // Try to sleep less, so we can hopefully rely on FPS logger. sleep_msec = target_msec - delta; if (sleep_msec > 0) rarch_sleep(sleep_msec); rgui->last_time = rarch_get_time_usec(); if (driver.video_poke && driver.video_poke->set_texture_enable) driver.video_poke->set_texture_enable(driver.video_data, false, MENU_TEXTURE_FULLSCREEN); if (rgui_input_postprocess(rgui, rgui->old_input_state) || input_entry_ret) goto deinit; return true; deinit: return false; }
static uint64_t rgui_input(void) { uint64_t input_state = 0; // FIXME: Very ugly. Should do something more uniform. #if defined(RARCH_CONSOLE) || defined(ANDROID) for (unsigned i = 0; i < DEVICE_NAV_LAST; i++) input_state |= driver.input->input_state(driver.input_data, menu_nav_binds, 0, RETRO_DEVICE_JOYPAD, 0, i) ? (1ULL << i) : 0; input_state |= driver.input->key_pressed(driver.input_data, RARCH_MENU_TOGGLE) ? (1ULL << DEVICE_NAV_MENU) : 0; #ifdef HAVE_OVERLAY for (unsigned i = 0; i < DEVICE_NAV_LAST; i++) input_state |= driver.overlay_state & menu_nav_binds[0][i].joykey ? (1ULL << i) : 0; #endif #else static const int maps[] = { RETRO_DEVICE_ID_JOYPAD_UP, DEVICE_NAV_UP, RETRO_DEVICE_ID_JOYPAD_DOWN, DEVICE_NAV_DOWN, RETRO_DEVICE_ID_JOYPAD_LEFT, DEVICE_NAV_LEFT, RETRO_DEVICE_ID_JOYPAD_RIGHT, DEVICE_NAV_RIGHT, RETRO_DEVICE_ID_JOYPAD_A, DEVICE_NAV_A, RETRO_DEVICE_ID_JOYPAD_B, DEVICE_NAV_B, RETRO_DEVICE_ID_JOYPAD_START, DEVICE_NAV_START, RETRO_DEVICE_ID_JOYPAD_SELECT, DEVICE_NAV_SELECT, }; static const struct retro_keybind *binds[] = { g_settings.input.binds[0] }; for (unsigned i = 0; i < ARRAY_SIZE(maps); i += 2) { input_state |= input_input_state_func(binds, 0, RETRO_DEVICE_JOYPAD, 0, maps[i + 0]) ? (1ULL << maps[i + 1]) : 0; #ifdef HAVE_OVERLAY input_state |= (driver.overlay_state & (UINT64_C(1) << maps[i + 0])) ? (1ULL << maps[i + 1]) : 0; #endif } input_state |= input_key_pressed_func(RARCH_MENU_TOGGLE) ? (1ULL << DEVICE_NAV_MENU) : 0; #endif rgui->trigger_state = input_state & ~rgui->old_input_state; #if defined(HAVE_RGUI) rgui->do_held = (input_state & ( (1ULL << DEVICE_NAV_UP) | (1ULL << DEVICE_NAV_DOWN) | (1ULL << DEVICE_NAV_LEFT) | (1ULL << DEVICE_NAV_RIGHT))) && !(input_state & (1ULL << DEVICE_NAV_MENU)); #elif defined(HAVE_RMENU) rgui->do_held = (input_state & ( (1ULL << DEVICE_NAV_LEFT) | (1ULL << DEVICE_NAV_RIGHT) | (1ULL << DEVICE_NAV_UP) | (1ULL << DEVICE_NAV_DOWN) | (1ULL << RARCH_ANALOG_LEFT_Y_DPAD_UP) | (1ULL << RARCH_ANALOG_LEFT_Y_DPAD_DOWN) | (1ULL << RARCH_ANALOG_LEFT_X_DPAD_LEFT) | (1ULL << RARCH_ANALOG_LEFT_X_DPAD_RIGHT) | (1ULL << RARCH_ANALOG_RIGHT_Y_DPAD_UP) | (1ULL << RARCH_ANALOG_RIGHT_Y_DPAD_DOWN) | (1ULL << RARCH_ANALOG_RIGHT_X_DPAD_LEFT) | (1ULL << RARCH_ANALOG_RIGHT_X_DPAD_RIGHT) | (1ULL << DEVICE_NAV_L2) | (1ULL << DEVICE_NAV_R2) )) && !(input_state & (1ULL << DEVICE_NAV_MENU)); #endif return input_state; }