From e3dfba2c34436a0c4fdd69778233ff0a99857381 Mon Sep 17 00:00:00 2001 From: Themaister Date: Thu, 21 Feb 2013 23:44:07 +0100 Subject: [PATCH] Add preliminary disk swapping interface. Works with Mednafen's disk swapping model. --- config.def.h | 4 +++ driver.h | 2 ++ dynamic.c | 9 ++++-- general.h | 2 ++ input/input_common.c | 2 ++ libretro.h | 37 +++++++++++++++++++++++ retroarch.c | 72 ++++++++++++++++++++++++++++++++++++++++++++ retroarch.cfg | 7 +++++ settings.c | 2 ++ 9 files changed, 134 insertions(+), 3 deletions(-) diff --git a/config.def.h b/config.def.h index 779117199b..01bf16d1ab 100644 --- a/config.def.h +++ b/config.def.h @@ -515,6 +515,8 @@ static const bool input_autodetect_enable = true; #define RETRO_LBL_VOLUME_UP "Volume Up" #define RETRO_LBL_VOLUME_DOWN "Volume Down" #define RETRO_LBL_OVERLAY_NEXT "Next Overlay" +#define RETRO_LBL_DISK_EJECT_TOGGLE "Disk Eject Toggle" +#define RETRO_LBL_DISK_NEXT "Disk Swap Next" // Player 1 static const struct retro_keybind retro_keybinds_1[] = { @@ -583,6 +585,8 @@ static const struct retro_keybind retro_keybinds_1[] = { { true, RARCH_VOLUME_UP, RETRO_LBL_VOLUME_UP, RETROK_KP_PLUS, NO_BTN, AXIS_NONE }, { true, RARCH_VOLUME_DOWN, RETRO_LBL_VOLUME_DOWN, RETROK_KP_MINUS,NO_BTN, AXIS_NONE }, { true, RARCH_OVERLAY_NEXT, RETRO_LBL_OVERLAY_NEXT, RETROK_UNKNOWN, NO_BTN, AXIS_NONE }, + { true, RARCH_DISK_EJECT_TOGGLE, RETRO_LBL_DISK_EJECT_TOGGLE, RETROK_UNKNOWN, NO_BTN, AXIS_NONE }, + { true, RARCH_DISK_NEXT, RETRO_LBL_DISK_NEXT, RETROK_UNKNOWN, NO_BTN, AXIS_NONE }, }; // Player 2-5 diff --git a/driver.h b/driver.h index 59c06b63ee..159ac06fae 100644 --- a/driver.h +++ b/driver.h @@ -105,6 +105,8 @@ enum // RetroArch specific bind IDs. RARCH_VOLUME_UP, RARCH_VOLUME_DOWN, RARCH_OVERLAY_NEXT, + RARCH_DISK_EJECT_TOGGLE, + RARCH_DISK_NEXT, #ifdef RARCH_CONSOLE RARCH_CHEAT_INPUT, diff --git a/dynamic.c b/dynamic.c index 8b7f44c45e..103aae552a 100644 --- a/dynamic.c +++ b/dynamic.c @@ -485,13 +485,17 @@ static bool environment_cb(unsigned cmd, void *data) case RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK: { + RARCH_LOG("Environ SET_KEYBOARD_CALLBACK.\n"); const struct retro_keyboard_callback *info = (const struct retro_keyboard_callback*)data; - g_extern.system.key_event = info->callback; - break; } + case RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE: + RARCH_LOG("Environ SET_DISK_CONTROL_INTERFACE.\n"); + g_extern.system.disk_control = *(const struct retro_disk_control_callback*)data; + break; + default: RARCH_LOG("Environ UNSUPPORTED (#%u).\n", cmd); return false; @@ -505,7 +509,6 @@ static void set_environment(void) pretro_set_environment(environment_cb); } -// Assume SNES as defaults. static void set_environment_defaults(void) { char *save; diff --git a/general.h b/general.h index 044ff55e54..6d22a52847 100644 --- a/general.h +++ b/general.h @@ -380,6 +380,8 @@ struct global char valid_extensions[PATH_MAX]; retro_keyboard_event_t key_event; + + struct retro_disk_control_callback disk_control; } system; struct diff --git a/input/input_common.c b/input/input_common.c index 9886591462..f9e0aa5a2a 100644 --- a/input/input_common.c +++ b/input/input_common.c @@ -549,6 +549,8 @@ static const struct str_to_bind_map str_to_bind[] = { { "volume_up", RARCH_VOLUME_UP }, { "volume_down", RARCH_VOLUME_DOWN }, { "overlay_next", RARCH_OVERLAY_NEXT }, + { "disk_eject_toggle", RARCH_DISK_EJECT_TOGGLE }, + { "disk_next", RARCH_DISK_NEXT }, }; unsigned input_str_to_bind(const char *str) diff --git a/libretro.h b/libretro.h index 21e24eeeff..f765a66047 100755 --- a/libretro.h +++ b/libretro.h @@ -415,6 +415,12 @@ enum retro_mod #define RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK 12 // const struct retro_keyboard_callback * -- // Sets a callback function used to notify core about keyboard events. + // +#define RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE 13 + // const struct retro_disk_control_callback * -- + // Sets an interface which frontend can use to eject and insert disk images. + // This is used for games which consist of multiple images and must be manually + // swapped out by the user (e.g. PSX). // Callback type passed in RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK. Called by the frontend in response to keyboard events. @@ -429,6 +435,37 @@ struct retro_keyboard_callback retro_keyboard_event_t callback; }; +// Callback for RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE. +// Should be set for implementations which can swap out multiple disk images in runtime. +// If the implementation can do this automatically, it should strive to do so. +// However, there are cases where the user must manually do so. +// +// Overview: To swap a disk image, eject the disk image with set_eject_state(true). +// Set the disk index with set_image_index(index). Insert the disk again with set_eject_state(false). + +// If ejected is true, "ejects" the virtual disk tray. When ejected, the disk image index can be set. +typedef bool (*retro_set_eject_state_t)(bool ejected); +// Gets current eject state. The initial state is not ejected. +typedef bool (*retro_get_eject_state_t)(void); +// Gets current disk index. First disk is index 0. +// If return value is >= get_num_images(), no disk is currently inserted. +typedef unsigned (*retro_get_image_index_t)(void); +// Sets image index. Can only be called when disk is ejected. +// The implementation supports setting "no disk" by using an index >= get_num_images(). +typedef bool (*retro_set_image_index_t)(unsigned index); +// Gets total number of images which are available to use. +typedef unsigned (*retro_get_num_images_t)(void); + +struct retro_disk_control_callback +{ + retro_set_eject_state_t set_eject_state; + retro_get_eject_state_t get_eject_state; + + retro_get_image_index_t get_image_index; + retro_set_image_index_t set_image_index; + retro_get_num_images_t get_num_images; +}; + enum retro_pixel_format { // 0RGB1555, native endian. 0 bit must be set to 0. diff --git a/retroarch.c b/retroarch.c index 66cf2848de..ca68744afe 100644 --- a/retroarch.c +++ b/retroarch.c @@ -2390,6 +2390,77 @@ static void check_cheats(void) old_pressed_toggle = pressed_toggle; } +static void check_disk(void) +{ + const struct retro_disk_control_callback *control = &g_extern.system.disk_control; + if (!control->get_num_images) + return; + + static bool old_pressed_eject; + static bool old_pressed_next; + + bool pressed_eject = input_key_pressed_func(RARCH_DISK_EJECT_TOGGLE); + bool pressed_next = input_key_pressed_func(RARCH_DISK_NEXT); + bool error = false; + char msg[256]; + *msg = '\0'; + + if (pressed_eject && !old_pressed_eject) + { + bool new_state = !control->get_eject_state(); + if (control->set_eject_state(new_state)) + snprintf(msg, sizeof(msg), "%s virtual disk tray.", new_state ? "Ejected" : "Closed"); + else + { + error = true; + snprintf(msg, sizeof(msg), "Failed to %s virtual disk tray.", new_state ? "eject" : "close"); + } + } + else if (pressed_next && !old_pressed_next) + { + unsigned num_disks = control->get_num_images(); + unsigned current = control->get_image_index(); + if (num_disks && num_disks != UINT_MAX) + { + // Use "no disk" state when index == num_disks. + unsigned next_index = current >= num_disks ? 0 : ((current + 1) % (num_disks + 1)); + if (control->set_image_index(next_index)) + { + if (next_index < num_disks) + snprintf(msg, sizeof(msg), "Setting disk %u of %u in tray.", next_index + 1, num_disks); + else + snprintf(msg, sizeof(msg), "Removed disk from tray."); + } + else + { + if (next_index < num_disks) + snprintf(msg, sizeof(msg), "Failed to set disk %u of %u.", next_index + 1, num_disks); + else + snprintf(msg, sizeof(msg), "Failed to remove disk from tray."); + error = true; + } + } + else + { + snprintf(msg, sizeof(msg), "Got invalid disk index from libretro."); + error = true; + } + } + + if (*msg) + { + if (error) + RARCH_ERR("%s\n", msg); + else + RARCH_LOG("%s\n", msg); + msg_queue_clear(g_extern.msg_queue); + msg_queue_push(g_extern.msg_queue, msg, 1, 180); + } + + old_pressed_eject = pressed_eject; + old_pressed_next = pressed_next; +} + #if defined(HAVE_SCREENSHOTS) && !defined(_XBOX) static void check_screenshot(void) { @@ -2562,6 +2633,7 @@ static void do_state_checks(void) check_shader_dir(); check_cheats(); + check_disk(); #ifdef HAVE_DYLIB check_dsp_config(); diff --git a/retroarch.cfg b/retroarch.cfg index 22248ce2cf..e7d853d73b 100644 --- a/retroarch.cfg +++ b/retroarch.cfg @@ -380,6 +380,13 @@ # Toggles to next overlay. Wraps around. # input_overlay_next = +# Toggles eject for disks. Used for multiple-disk games. +# input_disk_eject_toggle = + +# Cycles through disk images. Use after ejecting. +# Complete by toggling eject again. +# input_disk_next = + #### Misc # Enable rewinding. This will take a performance hit when playing, so it is disabled by default. diff --git a/settings.c b/settings.c index 83093c3e13..fd08c27ea1 100644 --- a/settings.c +++ b/settings.c @@ -825,6 +825,8 @@ static const struct bind_map bind_maps[MAX_PLAYERS][RARCH_BIND_LIST_END_NULL] = DECLARE_BIND(volume_up, RARCH_VOLUME_UP), DECLARE_BIND(volume_down, RARCH_VOLUME_DOWN), DECLARE_BIND(overlay_next, RARCH_OVERLAY_NEXT), + DECLARE_BIND(disk_eject_toggle, RARCH_DISK_EJECT_TOGGLE), + DECLARE_BIND(disk_next, RARCH_DISK_NEXT), }, { DECL_PLAYER(2) },