From 134aba2b37ca7fec28b6fcd1cd6fca0dd1abc9ab Mon Sep 17 00:00:00 2001 From: jdgleaver Date: Tue, 10 Nov 2020 12:03:10 +0000 Subject: Add dedicated RetroPad fast-forward button --- input.c | 34 ++++++++++++++++++++++++-- input.h | 5 ++++ libretro.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++--------- libretro.h | 55 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 162 insertions(+), 13 deletions(-) diff --git a/input.c b/input.c index f4ab6e8..44455d2 100644 --- a/input.c +++ b/input.c @@ -19,11 +19,18 @@ #include "common.h" +bool libretro_supports_bitmasks = false; +bool libretro_supports_ff_override = false; +bool libretro_ff_enabled = false; +bool libretro_ff_enabled_prev = false; + static u32 old_key = 0; static retro_input_state_t input_state_cb; void retro_set_input_state(retro_input_state_t cb) { input_state_cb = cb; } +extern void set_fastforward_override(bool fastforward); + static void trigger_key(u32 key) { u32 p1_cnt = io_registers[REG_P1CNT]; @@ -53,8 +60,24 @@ u32 update_input(void) if (!input_state_cb) return 0; - for (i = 0; i < sizeof(btn_map) / sizeof(map); i++) - new_key |= input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, btn_map[i].retropad) ? btn_map[i].gba : 0; + if (libretro_supports_bitmasks) + { + int16_t ret = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_MASK); + + for (i = 0; i < sizeof(btn_map) / sizeof(map); i++) + new_key |= (ret & (1 << btn_map[i].retropad)) ? btn_map[i].gba : 0; + + libretro_ff_enabled = libretro_supports_ff_override && + (ret & (1 << RETRO_DEVICE_ID_JOYPAD_R2)); + } + else + { + for (i = 0; i < sizeof(btn_map) / sizeof(map); i++) + new_key |= input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, btn_map[i].retropad) ? btn_map[i].gba : 0; + + libretro_ff_enabled = libretro_supports_ff_override && + input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R2); + } if ((new_key | old_key) != old_key) trigger_key(new_key); @@ -62,6 +85,13 @@ u32 update_input(void) old_key = new_key; io_registers[REG_P1] = (~old_key) & 0x3FF; + /* Handle fast forward button */ + if (libretro_ff_enabled != libretro_ff_enabled_prev) + { + set_fastforward_override(libretro_ff_enabled); + libretro_ff_enabled_prev = libretro_ff_enabled; + } + return 0; } diff --git a/input.h b/input.h index bec7997..90fc930 100644 --- a/input.h +++ b/input.h @@ -56,6 +56,11 @@ static const map btn_map[] = { { RETRO_DEVICE_ID_JOYPAD_A, BUTTON_A } }; +extern bool libretro_supports_bitmasks; +extern bool libretro_supports_ff_override; +extern bool libretro_ff_enabled; +extern bool libretro_ff_enabled_prev; + void init_input(void); u32 update_input(void); void input_write_savestate(void); diff --git a/libretro.c b/libretro.c index 4126eca..28db9dd 100644 --- a/libretro.c +++ b/libretro.c @@ -339,6 +339,31 @@ static void init_post_processing(void) /* Video post processing END */ +/* Fast forward override */ +void set_fastforward_override(bool fastforward) +{ + struct retro_fastforwarding_override ff_override; + + if (!libretro_supports_ff_override) + return; + + ff_override.ratio = -1.0f; + ff_override.notification = true; + + if (fastforward) + { + ff_override.fastforward = true; + ff_override.inhibit_toggle = true; + } + else + { + ff_override.fastforward = false; + ff_override.inhibit_toggle = false; + } + + environ_cb(RETRO_ENVIRONMENT_SET_FASTFORWARDING_OVERRIDE, &ff_override); +} + static void video_run(void) { u16 *gba_screen_pixels_buf = gba_screen_pixels; @@ -496,6 +521,14 @@ void retro_init(void) gba_screen_pixels = (uint16_t*)malloc(GBA_SCREEN_PITCH * GBA_SCREEN_HEIGHT * sizeof(uint16_t)); #endif + libretro_supports_bitmasks = false; + if (environ_cb(RETRO_ENVIRONMENT_GET_INPUT_BITMASKS, NULL)) + libretro_supports_bitmasks = true; + + libretro_supports_ff_override = false; + if (environ_cb(RETRO_ENVIRONMENT_SET_FASTFORWARDING_OVERRIDE, NULL)) + libretro_supports_ff_override = true; + current_frameskip_type = no_frameskip; frameskip_threshold = 0; frameskip_interval = 0; @@ -813,20 +846,38 @@ static void check_variables(int started_from_load) static void set_input_descriptors() { struct retro_input_descriptor descriptors[] = { - { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left" }, - { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "D-Pad Up" }, - { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "D-Pad Down" }, - { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" }, - { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "B" }, - { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "A" }, - { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" }, - { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Start" }, - { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "L" }, - { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R, "R" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "D-Pad Up" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "D-Pad Down" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "B" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "A" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Start" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "L" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R, "R" }, + { 0 }, + }; + + struct retro_input_descriptor descriptors_ff[] = { + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "D-Pad Up" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "D-Pad Down" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "B" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "A" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Start" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "L" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R, "R" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R2, "Fast Forward" }, { 0 }, }; - environ_cb(RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS, descriptors); + if (libretro_supports_ff_override) + environ_cb(RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS, descriptors_ff); + else + environ_cb(RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS, descriptors); } static void set_memory_descriptors(void) @@ -921,6 +972,14 @@ bool retro_load_game_special(unsigned game_type, void retro_unload_game(void) { update_backup(); + + if (libretro_ff_enabled) + set_fastforward_override(false); + + libretro_supports_bitmasks = false; + libretro_supports_ff_override = false; + libretro_ff_enabled = false; + libretro_ff_enabled_prev = false; } unsigned retro_get_region(void) diff --git a/libretro.h b/libretro.h index d843114..bda0b77 100644 --- a/libretro.h +++ b/libretro.h @@ -282,6 +282,7 @@ enum retro_language RETRO_LANGUAGE_PERSIAN = 20, RETRO_LANGUAGE_HEBREW = 21, RETRO_LANGUAGE_ASTURIAN = 22, + RETRO_LANGUAGE_FINNISH = 23, RETRO_LANGUAGE_LAST, /* Ensure sizeof(enum) == sizeof(int) */ @@ -712,6 +713,9 @@ enum retro_mod * state of rumble motors in controllers. * A strong and weak motor is supported, and they can be * controlled indepedently. + * Should be called from either retro_init() or retro_load_game(). + * Should not be called from retro_set_environment(). + * Returns false if rumble functionality is unavailable. */ #define RETRO_ENVIRONMENT_GET_INPUT_DEVICE_CAPABILITIES 24 /* uint64_t * -- @@ -1374,6 +1378,16 @@ enum retro_mod * call will target the newly initialized driver. */ +#define RETRO_ENVIRONMENT_SET_FASTFORWARDING_OVERRIDE 64 + /* const struct retro_fastforwarding_override * -- + * Used by a libretro core to override the current + * fastforwarding mode of the frontend. + * If NULL is passed to this function, the frontend + * will return true if fastforwarding override + * functionality is supported (no change in + * fastforwarding state will occur in this case). + */ + /* VFS functionality */ /* File paths: @@ -2934,6 +2948,47 @@ struct retro_framebuffer Set by frontend in GET_CURRENT_SOFTWARE_FRAMEBUFFER. */ }; +/* Used by a libretro core to override the current + * fastforwarding mode of the frontend */ +struct retro_fastforwarding_override +{ + /* Specifies the runtime speed multiplier that + * will be applied when 'fastforward' is true. + * For example, a value of 5.0 when running 60 FPS + * content will cap the fast-forward rate at 300 FPS. + * Note that the target multiplier may not be achieved + * if the host hardware has insufficient processing + * power. + * Setting a value of 0.0 (or greater than 0.0 but + * less than 1.0) will result in an uncapped + * fast-forward rate (limited only by hardware + * capacity). + * If the value is negative, it will be ignored + * (i.e. the frontend will use a runtime speed + * multiplier of its own choosing) */ + float ratio; + + /* If true, fastforwarding mode will be enabled. + * If false, fastforwarding mode will be disabled. */ + bool fastforward; + + /* If true, and if supported by the frontend, an + * on-screen notification will be displayed while + * 'fastforward' is true. + * If false, and if supported by the frontend, any + * on-screen fast-forward notifications will be + * suppressed */ + bool notification; + + /* If true, the core will have sole control over + * when fastforwarding mode is enabled/disabled; + * the frontend will not be able to change the + * state set by 'fastforward' until either + * 'inhibit_toggle' is set to false, or the core + * is unloaded */ + bool inhibit_toggle; +}; + /* Callbacks */ /* Environment callback. Gives implementations a way of performing -- cgit v1.2.3