diff --git a/driver.h b/driver.h index d3c1396e54..4791dcb004 100644 --- a/driver.h +++ b/driver.h @@ -492,6 +492,7 @@ typedef struct driver #endif bool stdin_claimed; bool block_hotkey; + bool block_input; bool nonblock_state; // Opaque handles to currently running window. diff --git a/file_list.c b/file_list.c index b241e5ecff..0b92977911 100644 --- a/file_list.c +++ b/file_list.c @@ -26,11 +26,9 @@ struct item_file size_t directory_ptr; }; -void file_list_push(void *userdata, +void file_list_push(file_list_t *list, const char *path, unsigned type, size_t directory_ptr) { - file_list_t *list = (file_list_t*)userdata; - if (!list) return; @@ -120,3 +118,23 @@ void file_list_get_last(const file_list_t *list, if (list->size) file_list_get_at_offset(list, list->size - 1, path, file_type); } + +bool file_list_search(const file_list_t *list, const char *needle, size_t *index) +{ + size_t i; + const char *alt; + for (i = 0; i < list->size; i++) + { + file_list_get_alt_at_offset(list, i, &alt); + if (!alt) + continue; + if (strstr(alt, needle)) + { + *index = i; + return true; + } + } + + return false; +} + diff --git a/file_list.h b/file_list.h index ee0b2d52d2..8438860477 100644 --- a/file_list.h +++ b/file_list.h @@ -21,6 +21,8 @@ extern "C" { #endif +#include "boolean.h" + struct item_file; typedef struct file_list { @@ -32,7 +34,7 @@ typedef struct file_list void file_list_free(file_list_t *list); -void file_list_push(void *userdata, const char *path, +void file_list_push(file_list_t *userdata, const char *path, unsigned type, size_t current_directory_ptr); void file_list_pop(file_list_t *list, size_t *directory_ptr); void file_list_clear(file_list_t *list); @@ -50,6 +52,8 @@ void file_list_get_alt_at_offset(const file_list_t *list, size_t index, void file_list_sort_on_alt(file_list_t *list); +bool file_list_search(const file_list_t *list, const char *needle, size_t *index); + #ifdef __cplusplus } #endif diff --git a/frontend/menu/disp/rgui.c b/frontend/menu/disp/rgui.c index e607b10931..b387dc4eb8 100644 --- a/frontend/menu/disp/rgui.c +++ b/frontend/menu/disp/rgui.c @@ -510,6 +510,13 @@ static void rgui_render(void *data) rgui_render_messagebox(rgui, message_queue); #endif + + if (rgui->display_keyboard) + { + char msg[1024]; + snprintf(msg, sizeof(msg), "Search: %s", rgui->keyboard.buffer ? rgui->keyboard.buffer : ""); + rgui_render_messagebox(rgui, msg); + } } static void *rgui_init(void) diff --git a/frontend/menu/menu_common.c b/frontend/menu/menu_common.c index 383679d05b..3f2ed0d8fe 100644 --- a/frontend/menu/menu_common.c +++ b/frontend/menu/menu_common.c @@ -426,6 +426,8 @@ void menu_free(void) rom_history_free(rgui->history); core_info_list_free(rgui->core_info); + menu_keyboard_state_clear(&rgui->keyboard); + free(rgui); } @@ -1382,6 +1384,7 @@ bool menu_iterate(void) rgui->old_input_state |= 1ULL << RARCH_MENU_TOGGLE; } + rarch_check_block_hotkey(); rarch_input_poll(); #ifdef HAVE_OVERLAY rarch_check_overlay(); @@ -1423,6 +1426,9 @@ bool menu_iterate(void) 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 @@ -1718,13 +1724,69 @@ bool menu_poll_find_trigger(struct rgui_bind_state *state, struct rgui_bind_stat return false; } +bool menu_keyboard_state_event(struct rgui_keyboard_state *state, + bool down, enum retro_key key, uint32_t character) +{ + // Treat extended chars as ? as we cannot support printable characters for unicode stuff. + char c = character >= 128 ? '?' : character; + if (c == '\r' || c == '\n') + return true; + + if (c == '\b') + { + if (state->ptr) + { + memmove(state->buffer + state->ptr - 1, state->buffer + state->ptr, + state->size - state->ptr + 1); + state->ptr--; + state->size--; + } + } + // Handle left/right here when suitable + else if (isprint(c)) + { + char *newbuf = (char*)realloc(state->buffer, state->size + 2); + if (!newbuf) + return false; + + memmove(newbuf + state->ptr + 1, newbuf + state->ptr, state->size - state->ptr + 1); + newbuf[state->ptr] = c; + state->ptr++; + state->size++; + newbuf[state->size] = '\0'; + + state->buffer = newbuf; + } + + return false; +} + +void menu_keyboard_state_clear(struct rgui_keyboard_state *state) +{ + free(state->buffer); + memset(state, 0, sizeof(*state)); +} + void menu_key_event(bool down, unsigned keycode, uint32_t character, uint16_t key_modifiers) { - // TODO: Do something with this. Stub for now. - (void)down; - (void)keycode; - (void)character; (void)key_modifiers; + + if (!driver.block_input && character == '/') + { + driver.block_input = true; + rgui->display_keyboard = true; + menu_keyboard_state_clear(&rgui->keyboard); + return; + } + + if (driver.block_input && menu_keyboard_state_event(&rgui->keyboard, down, keycode, character) && rgui->keyboard.buffer) + { + file_list_search(rgui->selection_buf, rgui->keyboard.buffer, &rgui->selection_ptr); + menu_keyboard_state_clear(&rgui->keyboard); + driver.block_input = false; + rgui->display_keyboard = false; + rgui->old_input_state = -1ull; // Avoid triggering states on pressing return. + } } static inline int menu_list_get_first_char(file_list_t *buf, unsigned offset) diff --git a/frontend/menu/menu_common.h b/frontend/menu/menu_common.h index b3cbc42fe4..e2311e0fb8 100644 --- a/frontend/menu/menu_common.h +++ b/frontend/menu/menu_common.h @@ -242,6 +242,17 @@ void menu_poll_bind_get_rested_axes(struct rgui_bind_state *state); void menu_poll_bind_state(struct rgui_bind_state *state); bool menu_poll_find_trigger(struct rgui_bind_state *state, struct rgui_bind_state *new_state); +struct rgui_keyboard_state +{ + char *buffer; + size_t ptr; + size_t size; +}; + +void menu_keyboard_state_clear(struct rgui_keyboard_state *state); +bool menu_keyboard_state_event(struct rgui_keyboard_state *state, + bool down, enum retro_key key, uint32_t character); + #ifdef GEKKO enum { @@ -324,6 +335,8 @@ typedef struct rarch_time_t last_time; // Used to throttle RGUI in case VSync is broken. struct rgui_bind_state binds; + struct rgui_keyboard_state keyboard; + bool display_keyboard; } rgui_handle_t; extern rgui_handle_t *rgui; diff --git a/general.h b/general.h index a1695f223d..4182cc5048 100644 --- a/general.h +++ b/general.h @@ -678,6 +678,7 @@ void rarch_init_msg_queue(void); void rarch_deinit_msg_queue(void); void rarch_input_poll(void); void rarch_check_overlay(void); +void rarch_check_block_hotkey(void); void rarch_init_rewind(void); void rarch_deinit_rewind(void); void rarch_set_fullscreen(bool fullscreen); diff --git a/retroarch.c b/retroarch.c index c965af2c9f..4be598231b 100644 --- a/retroarch.c +++ b/retroarch.c @@ -2690,17 +2690,17 @@ static void check_netplay_flip(void) } #endif -static void check_block_hotkey(void) +void rarch_check_block_hotkey(void) { - driver.block_hotkey = false; + driver.block_hotkey = driver.block_input; // If we haven't bound anything to this, // always allow hotkeys. static const struct retro_keybind *bind = &g_settings.input.binds[0][RARCH_ENABLE_HOTKEY]; - if (bind->key == RETROK_UNKNOWN && bind->joykey == NO_BTN && bind->joyaxis == AXIS_NONE) + if (!driver.block_hotkey && bind->key == RETROK_UNKNOWN && bind->joykey == NO_BTN && bind->joyaxis == AXIS_NONE) return; - driver.block_hotkey = !input_key_pressed_func(RARCH_ENABLE_HOTKEY); + driver.block_hotkey = driver.block_input || !input_key_pressed_func(RARCH_ENABLE_HOTKEY); } #ifdef HAVE_OVERLAY @@ -2743,7 +2743,7 @@ static void check_grab_mouse_toggle(void) static void do_state_checks(void) { - check_block_hotkey(); + rarch_check_block_hotkey(); #if defined(HAVE_SCREENSHOTS) && !defined(_XBOX) check_screenshot();