static void limit_frame_time(void) { retro_time_t current = rarch_get_time_usec(); retro_time_t target = 0, to_sleep_ms = 0; double effective_fps = g_extern.system.av_info.timing.fps * g_settings.fastforward_ratio; double mft_f = 1000000.0f / effective_fps; g_extern.frame_limit.minimum_frame_time = (retro_time_t) roundf(mft_f); target = g_extern.frame_limit.last_frame_time + g_extern.frame_limit.minimum_frame_time; to_sleep_ms = (target - current) / 1000; if (to_sleep_ms > 0) { rarch_sleep((unsigned int)to_sleep_ms); /* Combat jitter a bit. */ g_extern.frame_limit.last_frame_time += g_extern.frame_limit.minimum_frame_time; } else g_extern.frame_limit.last_frame_time = rarch_get_time_usec(); }
/** * rarch_limit_frame_time: * * Limit frame time if fast forward ratio throttle is enabled. **/ static void rarch_limit_frame_time(settings_t *settings, runloop_t *runloop) { retro_time_t target = 0; retro_time_t to_sleep_ms = 0; retro_time_t current = rarch_get_time_usec(); struct retro_system_av_info *av_info = video_viewport_get_system_av_info(); double effective_fps = av_info->timing.fps * settings->fastforward_ratio; double mft_f = 1000000.0f / effective_fps; runloop->frames.limit.minimum_time = (retro_time_t) roundf(mft_f); target = runloop->frames.limit.last_time + runloop->frames.limit.minimum_time; to_sleep_ms = (target - current) / 1000; if (to_sleep_ms <= 0) { runloop->frames.limit.last_time = rarch_get_time_usec(); return; } rarch_sleep((unsigned int)to_sleep_ms); /* Combat jitter a bit. */ runloop->frames.limit.last_time += runloop->frames.limit.minimum_time; }
static void data_thread_loop(void *data) { data_runloop_t *runloop = (data_runloop_t*)data; RARCH_LOG("[Data Thread]: Initializing data thread.\n"); slock_lock(runloop->lock); while (!runloop->thread_inited) scond_wait(runloop->cond, runloop->lock); slock_unlock(runloop->lock); RARCH_LOG("[Data Thread]: Starting data thread.\n"); while (runloop->alive) { slock_lock(runloop->lock); if (!runloop->alive) break; data_runloop_iterate(true); if (!rarch_main_data_active()) rarch_sleep(10); slock_unlock(runloop->lock); } RARCH_LOG("[Data Thread]: Stopping data thread.\n"); }
static void emscripten_mainloop(void) { int ret = rarch_main_iterate(); if (ret == 1) rarch_sleep(10); rarch_main_data_iterate(); if (ret != -1) return; main_exit(NULL); exit(0); }
static void emscripten_mainloop(void) { unsigned sleep_ms = 0; int ret = rarch_main_iterate(&sleep_ms); if (ret == 1 && sleep_ms > 0) rarch_sleep(sleep_ms); rarch_main_data_iterate(); if (ret != -1) return; main_exit(NULL); exit(0); }
static const char *get_rom_path(sgui_handle_t *sgui) { uint16_t old_input_state = 0; bool can_quit = false; sgui_iterate(sgui, SGUI_ACTION_REFRESH); for (;;) { uint16_t input_state = 0; input_wii.poll(NULL); if (input_wii.key_pressed(NULL, RARCH_QUIT_KEY)) { if (can_quit) return NULL; } else can_quit = true; for (unsigned i = 0; i < RARCH_FIRST_META_KEY; i++) { input_state |= input_wii.input_state(NULL, NULL, false, RETRO_DEVICE_JOYPAD, 0, i) ? (1 << i) : 0; } uint16_t trigger_state = input_state & ~old_input_state; sgui_action_t action = SGUI_ACTION_NOOP; if (trigger_state & (1 << RETRO_DEVICE_ID_JOYPAD_B)) action = SGUI_ACTION_CANCEL; else if (trigger_state & (1 << RETRO_DEVICE_ID_JOYPAD_A)) action = SGUI_ACTION_OK; else if (trigger_state & (1 << RETRO_DEVICE_ID_JOYPAD_UP)) action = SGUI_ACTION_UP; else if (trigger_state & (1 << RETRO_DEVICE_ID_JOYPAD_DOWN)) action = SGUI_ACTION_DOWN; const char *ret = sgui_iterate(sgui, action); if (ret) return ret; video_wii.frame(NULL, menu_framebuf, SGUI_WIDTH, SGUI_HEIGHT, SGUI_WIDTH * sizeof(uint16_t), NULL); old_input_state = input_state; rarch_sleep(10); } }
static void throttle_frame(void) { if (!driver.menu) return; /* Throttle in case VSync is broken (avoid 1000+ FPS Menu). */ driver.menu->time = rarch_get_time_usec(); driver.menu->delta = (driver.menu->time - driver.menu->last_time) / 1000; driver.menu->target_msec = 750 / g_settings.video.refresh_rate; /* Try to sleep less, so we can hopefully rely on FPS logger. */ driver.menu->sleep_msec = driver.menu->target_msec - driver.menu->delta; if (driver.menu->sleep_msec > 0) rarch_sleep((unsigned int)driver.menu->sleep_msec); driver.menu->last_time = rarch_get_time_usec(); }
static bool al_get_buffer(al_t *al, ALuint *buffer) { if (!al->res_ptr) { for (;;) { if (al_unqueue_buffers(al)) break; if (al->nonblock) return false; // Must sleep as there is no proper blocking method. :( rarch_sleep(1); } } *buffer = al->res_buf[--al->res_ptr]; return true; }
void wait_for_input(void) { printf("\n\nPress Start.\n\n"); fflush(stdout); while(aptMainLoop()) { u32 kDown; hidScanInput(); kDown = hidKeysDown(); if (kDown & KEY_START) break; if (kDown & KEY_SELECT) select_pressed = true; rarch_sleep(1); } }
/////////////////////////////////////////////////////////////////////////// // // SD_SetMusicMode() - sets the device to use for background music // /////////////////////////////////////////////////////////////////////////// boolean SD_SetMusicMode(SMMode mode) { boolean result = false; SD_FadeOutMusic(); while (SD_MusicPlaying()) rarch_sleep(5); switch (mode) { case SMM_OFF: result = true; break; case SMM_ADLIB: if (AdLibPresent) result = true; break; } if (result) MusicMode = mode; return(result); }
void VL_WaitVBL(int vbls) { rarch_sleep(vbls * 8); }
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; }
int rarch_main_iterate(void) { unsigned i; retro_input_t trigger_input; int ret = 0; static retro_input_t last_input = 0; retro_input_t old_input = last_input; retro_input_t input = input_keys_pressed(); last_input = input; if (driver.flushing_input) driver.flushing_input = (input) ? input_flush(&input) : false; trigger_input = input & ~old_input; if (time_to_exit(input)) return -1; if (g_extern.system.frame_time.callback) update_frame_time(); #ifdef HAVE_MENU if (check_enter_menu_func(trigger_input) || (g_extern.libretro_dummy)) do_state_check_menu_toggle(); if (g_extern.is_menu) { if (menu_iterate(input, old_input, trigger_input) == -1) rarch_main_set_state(RARCH_ACTION_STATE_MENU_RUNNING_FINISHED); if (!input && g_settings.menu.pause_libretro) ret = 1; goto success; } #endif if (g_extern.exec) { g_extern.exec = false; return -1; } if (do_state_checks(input, old_input, trigger_input)) { /* RetroArch has been paused */ driver.retro_ctx.poll_cb(); rarch_sleep(10); return 1; } #if defined(HAVE_THREADS) lock_autosave(); #endif #ifdef HAVE_NETPLAY if (driver.netplay_data) netplay_pre_frame((netplay_t*)driver.netplay_data); #endif if (g_extern.bsv.movie) bsv_movie_set_frame_start(g_extern.bsv.movie); if (g_extern.system.camera_callback.caps) driver_camera_poll(); /* Update binds for analog dpad modes. */ for (i = 0; i < MAX_PLAYERS; i++) { if (!g_settings.input.analog_dpad_mode[i]) continue; input_push_analog_dpad(g_settings.input.binds[i], g_settings.input.analog_dpad_mode[i]); input_push_analog_dpad(g_settings.input.autoconf_binds[i], g_settings.input.analog_dpad_mode[i]); } if ((g_settings.video.frame_delay > 0) && !driver.nonblock_state) rarch_sleep(g_settings.video.frame_delay); /* Run libretro for one frame. */ pretro_run(); for (i = 0; i < MAX_PLAYERS; i++) { if (!g_settings.input.analog_dpad_mode[i]) continue; input_pop_analog_dpad(g_settings.input.binds[i]); input_pop_analog_dpad(g_settings.input.autoconf_binds[i]); } if (g_extern.bsv.movie) bsv_movie_set_frame_end(g_extern.bsv.movie); #ifdef HAVE_NETPLAY if (driver.netplay_data) netplay_post_frame((netplay_t*)driver.netplay_data); #endif #if defined(HAVE_THREADS) unlock_autosave(); #endif success: if (g_settings.fastforward_ratio_throttle_enable) limit_frame_time(); return ret; }
/** * rarch_main_iterate: * * Run Libretro core in RetroArch for one frame. * * Returns: 0 on success, 1 if we have to wait until button input in order * to wake up the loop, -1 if we forcibly quit out of the RetroArch iteration loop. **/ int rarch_main_iterate(void) { unsigned i; retro_input_t trigger_input, old_input; event_cmd_state_t cmd = {0}; int ret = 0; static retro_input_t last_input = 0; driver_t *driver = driver_get_ptr(); settings_t *settings = config_get_ptr(); global_t *global = global_get_ptr(); runloop_t *runloop = rarch_main_get_ptr(); retro_input_t input = input_keys_pressed(driver, settings, global); rarch_system_info_t *system = rarch_system_info_get_ptr(); old_input = last_input; last_input = input; if (driver->flushing_input) driver->flushing_input = (input) ? input_flush(runloop, &input) : false; trigger_input = input & ~old_input; rarch_main_cmd_get_state(&cmd, input, old_input, trigger_input); if (time_to_exit(driver, global, runloop, &cmd)) return rarch_main_iterate_quit(settings, global); if (system->frame_time.callback) rarch_update_frame_time(driver, settings, runloop); do_pre_state_checks(settings, global, runloop, &cmd); #ifdef HAVE_OVERLAY rarch_main_iterate_linefeed_overlay(driver, settings); #endif #ifdef HAVE_MENU if (menu_driver_alive()) { menu_handle_t *menu = menu_driver_get_ptr(); if (menu) if (menu_iterate(input, old_input, trigger_input) == -1) rarch_main_set_state(RARCH_ACTION_STATE_MENU_RUNNING_FINISHED); if (!input && settings->menu.pause_libretro) ret = 1; goto success; } #endif if (global->exec) { global->exec = false; return rarch_main_iterate_quit(settings, global); } if (do_state_checks(driver, settings, global, runloop, &cmd)) { /* RetroArch has been paused */ driver->retro_ctx.poll_cb(); rarch_sleep(10); return 1; } #if defined(HAVE_THREADS) lock_autosave(); #endif #ifdef HAVE_NETPLAY if (driver->netplay_data) netplay_pre_frame((netplay_t*)driver->netplay_data); #endif if (global->bsv.movie) bsv_movie_set_frame_start(global->bsv.movie); if (system->camera_callback.caps) driver_camera_poll(); /* Update binds for analog dpad modes. */ for (i = 0; i < settings->input.max_users; i++) { if (!settings->input.analog_dpad_mode[i]) continue; input_push_analog_dpad(settings->input.binds[i], settings->input.analog_dpad_mode[i]); input_push_analog_dpad(settings->input.autoconf_binds[i], settings->input.analog_dpad_mode[i]); } if ((settings->video.frame_delay > 0) && !driver->nonblock_state) rarch_sleep(settings->video.frame_delay); /* Run libretro for one frame. */ pretro_run(); for (i = 0; i < settings->input.max_users; i++) { if (!settings->input.analog_dpad_mode[i]) continue; input_pop_analog_dpad(settings->input.binds[i]); input_pop_analog_dpad(settings->input.autoconf_binds[i]); } if (global->bsv.movie) bsv_movie_set_frame_end(global->bsv.movie); #ifdef HAVE_NETPLAY if (driver->netplay_data) netplay_post_frame((netplay_t*)driver->netplay_data); #endif #if defined(HAVE_THREADS) unlock_autosave(); #endif success: if (settings->fastforward_ratio_throttle_enable) rarch_limit_frame_time(settings, runloop); return ret; }
static void get_binds(config_file_t *conf, config_file_t *auto_conf, int player, int joypad) { int i, timeout_cnt; const rarch_joypad_driver_t *driver = input_joypad_init_driver(g_driver); if (!driver) { fprintf(stderr, "Cannot find any valid input driver.\n"); exit(1); } if (!driver->query_pad(joypad)) { fprintf(stderr, "Couldn't open joystick #%d.\n", joypad); exit(1); } fprintf(stderr, "Found joypad driver: %s\n", driver->ident); const char *joypad_name = input_joypad_name(driver, joypad); fprintf(stderr, "Using joypad: %s\n", joypad_name ? joypad_name : "Unknown"); if (joypad_name && auto_conf) { config_set_string(auto_conf, "input_device", joypad_name); config_set_string(auto_conf, "input_driver", driver->ident); } int16_t initial_axes[MAX_AXES] = {0}; struct poll_data old_poll = {{0}}; struct poll_data new_poll = {{0}}; int last_axis = -1; bool block_axis = false; int timeout_ticks = g_timeout * 100; poll_joypad(driver, joypad, &old_poll); fprintf(stderr, "\nJoypads tend to have stale state after opened.\nPress some buttons and move some axes around to make sure joypad state is completely neutral before proceeding.\nWhen done, press Enter ... "); getchar(); poll_joypad(driver, joypad, &old_poll); for (i = 0; i < MAX_AXES; i++) { int16_t initial = input_joypad_axis_raw(driver, joypad, i); if (abs(initial) < 20000) initial = 0; /* Certain joypads (such as XBox360 controller on Linux) * has a default negative axis for shoulder triggers, * which makes configuration very awkward. * * If default negative, we can't trigger on the negative axis, * and similar with defaulted positive axes. */ if (initial) fprintf(stderr, "Axis %d is defaulted to %s axis value of %d.\n", i, initial > 0 ? "positive" : "negative", initial); initial_axes[i] = initial; } for (i = 0; i < MAX_BUTTONS; i++) { if (old_poll.buttons[i]) fprintf(stderr, "Button %d was initially pressed. This indicates broken initial state.\n", i); } fprintf(stderr, "Configuring binds for player #%d on joypad #%d.\n\n", player + 1, joypad); for (i = 0, timeout_cnt = 0; input_config_bind_map[i].valid; i++, timeout_cnt = 0) { int j; if (i == RARCH_TURBO_ENABLE) continue; unsigned meta_level = input_config_bind_map[i].meta; if (meta_level > g_meta_level) continue; fprintf(stderr, "%s\n", input_config_bind_map[i].desc); unsigned player_index = input_config_bind_map[i].meta ? 0 : player; for (;;) { old_poll = new_poll; /* To avoid pegging CPU. * Ideally use an event-based joypad scheme, * but it adds far more complexity, so, meh. */ rarch_sleep(10); if (timeout_ticks) { timeout_cnt++; if (timeout_cnt >= timeout_ticks) { fprintf(stderr, "\tTimed out ...\n"); break; } } poll_joypad(driver, joypad, &new_poll); for (j = 0; j < MAX_BUTTONS; j++) { if (new_poll.buttons[j] && !old_poll.buttons[j]) { fprintf(stderr, "\tJoybutton pressed: %d\n", j); char key[64]; snprintf(key, sizeof(key), "%s_%s_btn", input_config_get_prefix(player_index, input_config_bind_map[i].meta), input_config_bind_map[i].base); config_set_int(conf, key, j); if (auto_conf) { snprintf(key, sizeof(key), "input_%s_btn", input_config_bind_map[i].base); config_set_int(auto_conf, key, j); } goto out; } } for (j = 0; j < MAX_AXES; j++) { if (new_poll.axes[j] == old_poll.axes[j]) continue; int16_t value = new_poll.axes[j]; bool same_axis = last_axis == j; bool require_negative = initial_axes[j] > 0; bool require_positive = initial_axes[j] < 0; /* Block the axis config until we're sure * axes have returned to their neutral state. */ if (same_axis) { if (abs(value) < 10000 || (require_positive && value < 0) || (require_negative && value > 0)) block_axis = false; } /* If axes are in their neutral state, * we can't allow it. */ if (require_negative && value >= 0) continue; if (require_positive && value <= 0) continue; if (block_axis) continue; if (abs(value) > 20000) { last_axis = j; fprintf(stderr, "\tJoyaxis moved: Axis %d, Value %d\n", j, value); char buf[8]; snprintf(buf, sizeof(buf), value > 0 ? "+%d" : "-%d", j); char key[64]; snprintf(key, sizeof(key), "%s_%s_axis", input_config_get_prefix(player_index, input_config_bind_map[i].meta), input_config_bind_map[i].base); config_set_string(conf, key, buf); if (auto_conf) { snprintf(key, sizeof(key), "input_%s_axis", input_config_bind_map[i].base); config_set_string(auto_conf, key, buf); } block_axis = true; goto out; } } for (j = 0; j < MAX_HATS; j++) { const char *quark = NULL; uint16_t value = new_poll.hats[j]; uint16_t old_value = old_poll.hats[j]; if ((value & HAT_UP_MASK) && !(old_value & HAT_UP_MASK)) quark = "up"; else if ((value & HAT_LEFT_MASK) && !(old_value & HAT_LEFT_MASK)) quark = "left"; else if ((value & HAT_RIGHT_MASK) && !(old_value & HAT_RIGHT_MASK)) quark = "right"; else if ((value & HAT_DOWN_MASK) && !(old_value & HAT_DOWN_MASK)) quark = "down"; if (quark) { fprintf(stderr, "\tJoyhat moved: Hat %d, direction %s\n", j, quark); char buf[16]; snprintf(buf, sizeof(buf), "h%d%s", j, quark); char key[64]; snprintf(key, sizeof(key), "%s_%s_btn", input_config_get_prefix(player_index, input_config_bind_map[i].meta), input_config_bind_map[i].base); config_set_string(conf, key, buf); if (auto_conf) { snprintf(key, sizeof(key), "input_%s_btn", input_config_bind_map[i].base); config_set_string(auto_conf, key, buf); } goto out; } } } out: old_poll = new_poll; } }
/////////////////////////////////////////////////////////////////////////// // // SD_WaitSoundDone() - waits until the current sound is done playing // /////////////////////////////////////////////////////////////////////////// void SD_WaitSoundDone(void) { while (SD_SoundPlaying()) rarch_sleep(5); }
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; }
/** * main_entry: * * Main function of RetroArch. * * If HAVE_MAIN is not defined, will contain main loop and will not * be exited from until we exit the program. Otherwise, will * just do initialization. * * Returns: varies per platform. **/ int rarch_main(int argc, char *argv[], void *data) { void *args = (void*)data; int ret = 0; settings_t *settings = NULL; driver_t *driver = NULL; rarch_main_alloc(); driver = driver_get_ptr(); if (driver) driver->frontend_ctx = (frontend_ctx_driver_t*)frontend_ctx_init_first(); if (!driver || !driver->frontend_ctx) RARCH_WARN("Frontend context could not be initialized.\n"); if (driver->frontend_ctx && driver->frontend_ctx->init) driver->frontend_ctx->init(args); rarch_main_new(); if (driver->frontend_ctx) { if (!(ret = (main_load_content(argc, argv, args, driver->frontend_ctx->environment_get, driver->frontend_ctx->process_args)))) return ret; } event_command(EVENT_CMD_HISTORY_INIT); settings = config_get_ptr(); if (settings->history_list_enable) { global_t *global = global_get_ptr(); rarch_system_info_t *system = rarch_system_info_get_ptr(); if (global->inited.content || system->no_content) history_playlist_push( g_defaults.history, global->path.fullpath, settings->libretro, system ? &system->info : NULL); } if (driver) driver->ui_companion = (ui_companion_driver_t*)ui_companion_init_first(); if (driver->ui_companion && driver->ui_companion->toggle) { if (settings->ui.companion_start_on_boot) driver->ui_companion->toggle(driver->ui_companion_data); } #ifndef HAVE_MAIN do{ ret = rarch_main_iterate(); if (ret == 1) rarch_sleep(10); rarch_main_data_iterate(); }while(ret != -1); main_exit(args); #endif return 0; }
static void get_binds(config_file_t *conf, int player, int joypad) { const rarch_joypad_driver_t *driver = input_joypad_init_first(); if (!driver) { fprintf(stderr, "Cannot find any valid input driver.\n"); exit(1); } if (!driver->query_pad(joypad)) { fprintf(stderr, "Couldn't open joystick #%u.\n", joypad); exit(1); } fprintf(stderr, "Found joypad driver: %s\n", driver->ident); int16_t initial_axes[MAX_AXES] = {0}; struct poll_data old_poll = {{0}}; struct poll_data new_poll = {{0}}; int last_axis = -1; bool block_axis = false; poll_joypad(driver, joypad, &old_poll); for (int i = 0; i < MAX_AXES; i++) { int16_t initial = input_joypad_axis_raw(driver, joypad, i); if (abs(initial) < 20000) initial = 0; // Certain joypads (such as XBox360 controller on Linux) has a default negative axis for shoulder triggers, // which makes configuration very awkward. // If default negative, we can't trigger on the negative axis, and similar with defaulted positive axes. if (initial) fprintf(stderr, "Axis %d is defaulted to %s axis value of %d\n", i, initial > 0 ? "positive" : "negative", initial); initial_axes[i] = initial; } fprintf(stderr, "Configuring binds for player #%d on joypad #%d.\n\n", player + 1, joypad); for (unsigned i = 0; i < sizeof(binds) / sizeof(binds[0]) && (g_use_misc || !binds[i].is_misc) ; i++) { fprintf(stderr, "%s\n", binds[i].keystr); unsigned player_index = binds[i].is_misc ? 0 : player; for (;;) { old_poll = new_poll; // To avoid pegging CPU. // Ideally use an event-based joypad scheme, // but it adds far more complexity, so, meh. rarch_sleep(10); poll_joypad(driver, joypad, &new_poll); for (int j = 0; j < MAX_BUTTONS; j++) { if (new_poll.buttons[j] && !old_poll.buttons[j]) { fprintf(stderr, "\tJoybutton pressed: %u\n", j); config_set_int(conf, binds[i].confbtn[player_index], j); goto out; } } for (int j = 0; j < MAX_AXES; j++) { if (new_poll.axes[j] != old_poll.axes[j]) { int16_t value = new_poll.axes[j]; bool same_axis = last_axis == j; bool require_negative = initial_axes[j] > 0; bool require_positive = initial_axes[j] < 0; // Block the axis config until we're sure axes have returned to their neutral state. if (same_axis) { if (abs(value) < 10000 || (require_positive && value < 0) || (require_negative && value > 0)) block_axis = false; } // If axes are in their neutral state, we can't allow it. if (require_negative && value >= 0) continue; if (require_positive && value <= 0) continue; if (block_axis) continue; if (abs(value) > 20000) { last_axis = j; fprintf(stderr, "\tJoyaxis moved: Axis %d, Value %d\n", j, value); char buf[8]; snprintf(buf, sizeof(buf), value > 0 ? "+%d" : "-%d", j); config_set_string(conf, binds[i].confaxis[player_index], buf); block_axis = true; goto out; } } } for (int j = 0; j < MAX_HATS; j++) { const char *quark = NULL; uint16_t value = new_poll.hats[j]; uint16_t old_value = old_poll.hats[j]; if ((value & HAT_UP_MASK) && !(old_value & HAT_UP_MASK)) quark = "up"; else if ((value & HAT_LEFT_MASK) && !(old_value & HAT_LEFT_MASK)) quark = "left"; else if ((value & HAT_RIGHT_MASK) && !(old_value & HAT_RIGHT_MASK)) quark = "right"; else if ((value & HAT_DOWN_MASK) && !(old_value & HAT_DOWN_MASK)) quark = "down"; if (quark) { fprintf(stderr, "\tJoyhat moved: Hat %d, direction %s\n", j, quark); char buf[16]; snprintf(buf, sizeof(buf), "h%d%s", j, quark); config_set_string(conf, binds[i].confbtn[player_index], buf); goto out; } } } out: old_poll = new_poll; } }
/** * rarch_main_iterate: * * Run Libretro core in RetroArch for one frame. * * Returns: 0 on success, 1 if we have to wait until button input in order * to wake up the loop, -1 if we forcibly quit out of the RetroArch iteration loop. **/ int rarch_main_iterate(unsigned *sleep_ms) { unsigned i; retro_input_t trigger_input; event_cmd_state_t cmd; bool do_quit = false; static retro_input_t last_input = 0; driver_t *driver = driver_get_ptr(); settings_t *settings = config_get_ptr(); global_t *global = global_get_ptr(); retro_input_t input = input_keys_pressed(driver, settings, global); rarch_system_info_t *system = rarch_system_info_get_ptr(); retro_input_t old_input = last_input; last_input = input; if (driver->flushing_input) { driver->flushing_input = false; if (input) { input = 0; /* If core was paused before entering menu, evoke * pause toggle to wake it up. */ if (main_is_paused) BIT64_SET(input, RARCH_PAUSE_TOGGLE); driver->flushing_input = true; } } trigger_input = input & ~old_input; rarch_main_cmd_get_state(driver, settings, &cmd, input, old_input, trigger_input); if (time_to_exit(driver, global, system, &cmd)) do_quit = true; if (system->frame_time.callback) rarch_update_frame_time(driver, settings->slowmotion_ratio, system); do_pre_state_checks(settings, global, &cmd); #ifdef HAVE_OVERLAY rarch_main_iterate_linefeed_overlay(driver, settings); #endif if (global->exec) { global->exec = false; do_quit = true; } if (do_quit) { /* Quits out of RetroArch main loop. * On special case, loads dummy core * instead of exiting RetroArch completely. * Aborts core shutdown if invoked. */ if (global->core_shutdown_initiated && settings->load_dummy_on_core_shutdown) { if (!event_command(EVENT_CMD_PREPARE_DUMMY)) return -1; system->shutdown = false; global->core_shutdown_initiated = false; return 0; } return -1; } #ifdef HAVE_MENU if (menu_driver_alive()) { menu_handle_t *menu = menu_driver_get_ptr(); if (menu) if (menu_iterate(true, menu_input_frame(input, trigger_input)) == -1) rarch_main_set_state(RARCH_ACTION_STATE_MENU_RUNNING_FINISHED); if (!input && settings->menu.pause_libretro) return 1; return rarch_limit_frame_time(settings->fastforward_ratio, sleep_ms); } #endif if (do_state_checks(driver, settings, global, &cmd)) { /* RetroArch has been paused. */ driver->retro_ctx.poll_cb(); *sleep_ms = 10; return 1; } #if defined(HAVE_THREADS) lock_autosave(); #endif #ifdef HAVE_NETPLAY if (driver->netplay_data) netplay_pre_frame((netplay_t*)driver->netplay_data); #endif if (global->bsv.movie) bsv_movie_set_frame_start(global->bsv.movie); if (system->camera_callback.caps) driver_camera_poll(); /* Update binds for analog dpad modes. */ for (i = 0; i < settings->input.max_users; i++) { if (!settings->input.analog_dpad_mode[i]) continue; input_push_analog_dpad(settings->input.binds[i], settings->input.analog_dpad_mode[i]); input_push_analog_dpad(settings->input.autoconf_binds[i], settings->input.analog_dpad_mode[i]); } if ((settings->video.frame_delay > 0) && !driver->nonblock_state) rarch_sleep(settings->video.frame_delay); /* Run libretro for one frame. */ pretro_run(); for (i = 0; i < settings->input.max_users; i++) { if (!settings->input.analog_dpad_mode[i]) continue; input_pop_analog_dpad(settings->input.binds[i]); input_pop_analog_dpad(settings->input.autoconf_binds[i]); } if (global->bsv.movie) bsv_movie_set_frame_end(global->bsv.movie); #ifdef HAVE_NETPLAY if (driver->netplay_data) netplay_post_frame((netplay_t*)driver->netplay_data); #endif #if defined(HAVE_THREADS) unlock_autosave(); #endif return rarch_limit_frame_time(settings->fastforward_ratio, sleep_ms); }
/////////////////////////////////////////////////////////////////////////// // // US_LineInput() - Gets a line of user input at (x,y), the string defaults // to whatever is pointed at by def. Input is restricted to maxchars // chars or maxwidth pixels wide. If the user hits escape (and escok is // true), nothing is copied into buf, and false is returned. If the // user hits return, the current string is copied into buf, and true is // returned // /////////////////////////////////////////////////////////////////////////// boolean US_LineInput(int x,int y,char *buf,const char *def,boolean escok, int maxchars,int maxwidth) { boolean redraw, cursorvis,cursormoved, done,result, checkkey; ScanCode sc; char c; char s[MaxString],olds[MaxString]; int cursor,len; word i, w,h, temp; longword curtime, lasttime, lastdirtime, lastbuttontime, lastdirmovetime; ControlInfo ci; Direction lastdir = dir_None; if (def) strcpy(s,def); else *s = '\0'; *olds = '\0'; cursor = (int) strlen(s); cursormoved = redraw = true; cursorvis = done = false; lasttime = lastdirtime = lastdirmovetime = GetTimeCount(); lastbuttontime = lasttime + TickBase / 4; // 250 ms => first button press accepted after 500 ms LastASCII = key_None; LastScan = sc_None; while (!done) { ReadAnyControl(&ci); if (cursorvis) USL_XORICursor(x,y,s,cursor); sc = LastScan; LastScan = sc_None; c = LastASCII; LastASCII = key_None; checkkey = true; curtime = GetTimeCount(); // After each direction change accept the next change after 250 ms and then everz 125 ms if(ci.dir != lastdir || ((curtime - lastdirtime > TickBase / 4) && (curtime - lastdirmovetime > TickBase / 8))) { if(ci.dir != lastdir) { lastdir = ci.dir; lastdirtime = curtime; } lastdirmovetime = curtime; switch(ci.dir) { case dir_West: if(cursor) { // Remove trailing whitespace if cursor is at end of string if(s[cursor] == ' ' && s[cursor + 1] == 0) s[cursor] = 0; cursor--; } cursormoved = true; checkkey = false; break; case dir_East: if(cursor >= MaxString - 1) break; if(!s[cursor]) { USL_MeasureString(s,&w,&h); if(len >= maxchars || (maxwidth && w >= maxwidth)) break; s[cursor] = ' '; s[cursor + 1] = 0; } cursor++; cursormoved = true; checkkey = false; break; case dir_North: if(!s[cursor]) { USL_MeasureString(s,&w,&h); if(len >= maxchars || (maxwidth && w >= maxwidth)) break; s[cursor + 1] = 0; } s[cursor] = USL_RotateChar(s[cursor], 1); redraw = true; checkkey = false; break; case dir_South: if(!s[cursor]) { USL_MeasureString(s,&w,&h); if(len >= maxchars || (maxwidth && w >= maxwidth)) break; s[cursor + 1] = 0; } s[cursor] = USL_RotateChar(s[cursor], -1); redraw = true; checkkey = false; break; default: break; } } if((int)(curtime - lastbuttontime) > TickBase / 4) // 250 ms { if(ci.button0) // acts as return { strcpy(buf,s); done = true; result = true; checkkey = false; } if(ci.button1 && escok) // acts as escape { done = true; result = false; checkkey = false; } if(ci.button2) // acts as backspace { lastbuttontime = curtime; if(cursor) { strcpy(s + cursor - 1,s + cursor); cursor--; redraw = true; } cursormoved = true; checkkey = false; } } if(checkkey) { switch (sc) { case sc_LeftArrow: if (cursor) cursor--; c = key_None; cursormoved = true; break; case sc_RightArrow: if (s[cursor]) cursor++; c = key_None; cursormoved = true; break; case sc_Home: cursor = 0; c = key_None; cursormoved = true; break; case sc_End: cursor = (int) strlen(s); c = key_None; cursormoved = true; break; case sc_Return: strcpy(buf,s); done = true; result = true; c = key_None; break; case sc_Escape: if (escok) { done = true; result = false; } c = key_None; break; case sc_BackSpace: if (cursor) { strcpy(s + cursor - 1,s + cursor); cursor--; redraw = true; } c = key_None; cursormoved = true; break; case sc_Delete: if (s[cursor]) { strcpy(s + cursor,s + cursor + 1); redraw = true; } c = key_None; cursormoved = true; break; case SDLK_KP5: //0x4c: // Keypad 5 // TODO: hmmm... case sc_UpArrow: case sc_DownArrow: case sc_PgUp: case sc_PgDn: case sc_Insert: c = key_None; break; } if (c) { len = (int) strlen(s); USL_MeasureString(s,&w,&h); if(isprint(c) && (len < MaxString - 1) && ((!maxchars) || (len < maxchars)) && ((!maxwidth) || (w < maxwidth))) { for (i = len + 1;i > cursor;i--) s[i] = s[i - 1]; s[cursor++] = c; redraw = true; } } } if (redraw) { px = x; py = y; temp = fontcolor; fontcolor = backcolor; USL_DrawString(olds); fontcolor = (byte) temp; strcpy(olds,s); px = x; py = y; USL_DrawString(s); redraw = false; } if (cursormoved) { cursorvis = false; lasttime = curtime - TickBase; cursormoved = false; } if (curtime - lasttime > TickBase / 2) // 500 ms { lasttime = curtime; cursorvis ^= true; } else rarch_sleep(5); if (cursorvis) USL_XORICursor(x,y,s,cursor); VW_UpdateScreen(); } if (cursorvis) USL_XORICursor(x,y,s,cursor); if (!result) { px = x; py = y; USL_DrawString(olds); } VW_UpdateScreen(); IN_ClearKeysDown(); return(result); }
static bool get_rom_path(rgui_handle_t *rgui) { uint16_t old_input_state = 0; bool can_quit = false; bool first = true; for (;;) { uint16_t input_state = 0; input_wii.poll(NULL); if (input_wii.key_pressed(NULL, RARCH_QUIT_KEY)) { if (can_quit) return false; } else can_quit = true; for (unsigned i = 0; i < RARCH_FIRST_META_KEY; i++) { input_state |= input_wii.input_state(NULL, NULL, false, RETRO_DEVICE_JOYPAD, 0, i) ? (1 << i) : 0; } uint16_t trigger_state = input_state & ~old_input_state; rgui_action_t action = RGUI_ACTION_NOOP; if (trigger_state & (1 << RETRO_DEVICE_ID_JOYPAD_B)) action = RGUI_ACTION_CANCEL; else if (trigger_state & (1 << RETRO_DEVICE_ID_JOYPAD_A)) action = RGUI_ACTION_OK; else if (trigger_state & (1 << RETRO_DEVICE_ID_JOYPAD_UP)) action = RGUI_ACTION_UP; else if (trigger_state & (1 << RETRO_DEVICE_ID_JOYPAD_DOWN)) action = RGUI_ACTION_DOWN; else if (trigger_state & (1 << RETRO_DEVICE_ID_JOYPAD_LEFT)) action = RGUI_ACTION_LEFT; else if (trigger_state & (1 << RETRO_DEVICE_ID_JOYPAD_RIGHT)) action = RGUI_ACTION_RIGHT; else if (trigger_state & (1 << RETRO_DEVICE_ID_JOYPAD_START)) action = RGUI_ACTION_START; else if (trigger_state & (1 << RETRO_DEVICE_ID_JOYPAD_SELECT) && !first) // don't catch start+select+l+r when exiting action = RGUI_ACTION_SETTINGS; const char *ret = rgui_iterate(rgui, action); video_wii.frame(NULL, menu_framebuf, RGUI_WIDTH, RGUI_HEIGHT, RGUI_WIDTH * sizeof(uint16_t), NULL); if (ret) { g_console.initialize_rarch_enable = true; strlcpy(g_console.rom_path, ret, sizeof(g_console.rom_path)); if (rarch_startup(NULL)) return true; } old_input_state = input_state; first = false; rarch_sleep(10); } }