From 84c93ef94a960e17f48610d6b869f7a1e3f54194 Mon Sep 17 00:00:00 2001 From: Themaister Date: Mon, 9 Dec 2013 16:18:58 +0100 Subject: [PATCH 1/8] Add experimental RGUI keyboard search feature. Type '/' to start search, then type search string (case sensitive for now due to strcasestr being GNU ext). When done, type return. --- driver.h | 1 + file_list.c | 24 +++++++++++-- file_list.h | 6 +++- frontend/menu/disp/rgui.c | 7 ++++ frontend/menu/menu_common.c | 70 ++++++++++++++++++++++++++++++++++--- frontend/menu/menu_common.h | 13 +++++++ general.h | 1 + retroarch.c | 10 +++--- 8 files changed, 119 insertions(+), 13 deletions(-) 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(); From 977cec137888296b0228ef665b6aa1ff95f13515 Mon Sep 17 00:00:00 2001 From: Themaister Date: Tue, 10 Dec 2013 19:39:09 +0100 Subject: [PATCH 2/8] Refactor keyboard event callbacks. Go through input/keyboard_line.c to better hide internal logic regarding keyboard line input. --- Makefile | 1 + Makefile.win | 1 + frontend/menu/disp/rgui.c | 7 +- frontend/menu/menu_common.c | 73 +++++--------------- frontend/menu/menu_common.h | 22 +++--- gfx/context/win32_common.c | 17 ++--- gfx/context/x11_common.c | 8 +-- input/input_common.c | 1 + input/keyboard_line.c | 130 ++++++++++++++++++++++++++++++++++++ input/keyboard_line.h | 54 +++++++++++++++ input/udev_input.c | 7 +- 11 files changed, 229 insertions(+), 92 deletions(-) create mode 100644 input/keyboard_line.c create mode 100644 input/keyboard_line.h diff --git a/Makefile b/Makefile index c37ecb1876..0df3f12180 100644 --- a/Makefile +++ b/Makefile @@ -16,6 +16,7 @@ OBJ = frontend/frontend.o \ rewind.o \ gfx/gfx_common.o \ input/input_common.o \ + input/keyboard_line.o \ input/overlay.o \ patch.o \ fifo_buffer.o \ diff --git a/Makefile.win b/Makefile.win index c661001431..6b5d3168e9 100644 --- a/Makefile.win +++ b/Makefile.win @@ -17,6 +17,7 @@ OBJ = frontend/frontend.o \ movie.o \ gfx/gfx_common.o \ input/input_common.o \ + input/keyboard_line.o \ input/autoconf/builtin_win.o \ core_options.o \ patch.o \ diff --git a/frontend/menu/disp/rgui.c b/frontend/menu/disp/rgui.c index b387dc4eb8..ef8612026c 100644 --- a/frontend/menu/disp/rgui.c +++ b/frontend/menu/disp/rgui.c @@ -511,10 +511,13 @@ static void rgui_render(void *data) rgui_render_messagebox(rgui, message_queue); #endif - if (rgui->display_keyboard) + if (rgui->keyboard.display) { char msg[1024]; - snprintf(msg, sizeof(msg), "Search: %s", rgui->keyboard.buffer ? rgui->keyboard.buffer : ""); + const char *str = *rgui->keyboard.buffer; + if (!str) + str = ""; + snprintf(msg, sizeof(msg), "%s\n%s", rgui->keyboard.label, str); rgui_render_messagebox(rgui, msg); } } diff --git a/frontend/menu/menu_common.c b/frontend/menu/menu_common.c index 3f2ed0d8fe..6ecddf64e7 100644 --- a/frontend/menu/menu_common.c +++ b/frontend/menu/menu_common.c @@ -28,6 +28,7 @@ #include "../../file.h" #include "../../file_ext.h" #include "../../input/input_common.h" +#include "../../input/keyboard_line.h" #include "../../compat/posix_string.h" @@ -426,8 +427,6 @@ void menu_free(void) rom_history_free(rgui->history); core_info_list_free(rgui->core_info); - menu_keyboard_state_clear(&rgui->keyboard); - free(rgui); } @@ -1724,68 +1723,28 @@ 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) +static void menu_search_callback(void *userdata, const char *str) { - // 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; + rgui_handle_t *rgui = (rgui_handle_t*)userdata; - 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; + if (str) + file_list_search(rgui->selection_buf, str, &rgui->selection_ptr); + rgui->keyboard.display = false; + rgui->keyboard.label = NULL; + rgui->old_input_state = -1ULL; // Avoid triggering states on pressing return. } -void menu_keyboard_state_clear(struct rgui_keyboard_state *state) +void menu_key_event(bool down, unsigned keycode, uint32_t character, uint16_t mod) { - free(state->buffer); - memset(state, 0, sizeof(*state)); -} + (void)down; + (void)keycode; + (void)mod; -void menu_key_event(bool down, unsigned keycode, uint32_t character, uint16_t key_modifiers) -{ - (void)key_modifiers; - - if (!driver.block_input && character == '/') + if (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. + rgui->keyboard.display = true; + rgui->keyboard.label = "Search:"; + rgui->keyboard.buffer = input_keyboard_start_line(rgui, menu_search_callback); } } diff --git a/frontend/menu/menu_common.h b/frontend/menu/menu_common.h index e2311e0fb8..8a4447f3c7 100644 --- a/frontend/menu/menu_common.h +++ b/frontend/menu/menu_common.h @@ -242,17 +242,6 @@ 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 { @@ -335,8 +324,12 @@ 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; + struct + { + const char **buffer; + const char *label; + bool display; + } keyboard; } rgui_handle_t; extern rgui_handle_t *rgui; @@ -381,10 +374,11 @@ int menu_settings_toggle_setting(void *data, unsigned setting, unsigned action, int menu_set_settings(void *data, unsigned setting, unsigned action); void menu_set_settings_label(char *type_str, size_t type_str_size, unsigned *w, unsigned type); -void menu_key_event(bool down, unsigned keycode, uint32_t character, uint16_t key_modifiers); void menu_populate_entries(void *data, unsigned menu_type); unsigned menu_type_is(unsigned type); +void menu_key_event(bool down, unsigned keycode, uint32_t character, uint16_t key_modifiers); + extern const menu_ctx_driver_t *menu_ctx; #ifdef __cplusplus diff --git a/gfx/context/win32_common.c b/gfx/context/win32_common.c index de1c33833b..734815f658 100644 --- a/gfx/context/win32_common.c +++ b/gfx/context/win32_common.c @@ -14,7 +14,7 @@ */ #include "../../general.h" -#include "../../input/input_common.h" +#include "../../input/keyboard_line.h" #include "win32_common.h" LRESULT win32_handle_keyboard_event(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) @@ -32,8 +32,7 @@ LRESULT win32_handle_keyboard_event(HWND hwnd, UINT message, WPARAM wparam, LPAR // Seems to be hard to synchronize WM_CHAR and WM_KEYDOWN properly. case WM_CHAR: { - if (g_extern.system.key_event) - g_extern.system.key_event(true, RETROK_UNKNOWN, wparam, mod); + input_keyboard_event(true, RETROK_UNKNOWN, wparam, mod); return TRUE; } @@ -42,8 +41,7 @@ LRESULT win32_handle_keyboard_event(HWND hwnd, UINT message, WPARAM wparam, LPAR // DirectInput uses scancodes directly. unsigned scancode = (lparam >> 16) & 0xff; unsigned keycode = input_translate_keysym_to_rk(scancode); - if (g_extern.system.key_event) - g_extern.system.key_event(true, keycode, 0, mod); + input_keyboard_event(true, keycode, 0, mod); return 0; } @@ -52,8 +50,7 @@ LRESULT win32_handle_keyboard_event(HWND hwnd, UINT message, WPARAM wparam, LPAR // DirectInput uses scancodes directly. unsigned scancode = (lparam >> 16) & 0xff; unsigned keycode = input_translate_keysym_to_rk(scancode); - if (g_extern.system.key_event) - g_extern.system.key_event(false, keycode, 0, mod); + input_keyboard_event(false, keycode, 0, mod); return 0; } @@ -61,8 +58,7 @@ LRESULT win32_handle_keyboard_event(HWND hwnd, UINT message, WPARAM wparam, LPAR { unsigned scancode = (lparam >> 16) & 0xff; unsigned keycode = input_translate_keysym_to_rk(scancode); - if (g_extern.system.key_event) - g_extern.system.key_event(false, keycode, 0, mod); + input_keyboard_event(false, keycode, 0, mod); return 0; } @@ -70,8 +66,7 @@ LRESULT win32_handle_keyboard_event(HWND hwnd, UINT message, WPARAM wparam, LPAR { unsigned scancode = (lparam >> 16) & 0xff; unsigned keycode = input_translate_keysym_to_rk(scancode); - if (g_extern.system.key_event) - g_extern.system.key_event(true, keycode, 0, mod); + input_keyboard_event(true, keycode, 0, mod); switch (wparam) { diff --git a/gfx/context/x11_common.c b/gfx/context/x11_common.c index 10dcf086fb..516849b783 100644 --- a/gfx/context/x11_common.c +++ b/gfx/context/x11_common.c @@ -21,6 +21,7 @@ #include "../image.h" #include "../../general.h" #include "../../input/input_common.h" +#include "../../input/keyboard_line.h" static void x11_hide_mouse(Display *dpy, Window win) { @@ -343,9 +344,6 @@ static size_t conv_utf8_utf32(uint32_t *out, size_t out_chars, const char *in, s void x11_handle_key_event(XEvent *event, XIC ic, bool filter) { - if (!g_extern.system.key_event) - return; - int i; char keybuf[32] = {0}; uint32_t chars[32] = {0}; @@ -383,8 +381,8 @@ void x11_handle_key_event(XEvent *event, XIC ic, bool filter) mod |= (state & Mod1Mask) ? RETROKMOD_ALT : 0; mod |= (state & Mod4Mask) ? RETROKMOD_META : 0; - g_extern.system.key_event(down, key, chars[0], mod); + input_keyboard_event(down, key, chars[0], mod); for (i = 1; i < num; i++) - g_extern.system.key_event(down, RETROK_UNKNOWN, chars[i], mod); + input_keyboard_event(down, RETROK_UNKNOWN, chars[i], mod); } diff --git a/input/input_common.c b/input/input_common.c index a66ae67fbc..f72494fd57 100644 --- a/input/input_common.c +++ b/input/input_common.c @@ -1209,3 +1209,4 @@ void input_config_autoconfigure_joypad(unsigned index, const char *name, const c } #endif + diff --git a/input/keyboard_line.c b/input/keyboard_line.c new file mode 100644 index 0000000000..a23b974927 --- /dev/null +++ b/input/keyboard_line.c @@ -0,0 +1,130 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2010-2013 - Hans-Kristian Arntzen + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#include "keyboard_line.h" +#include "../general.h" +#include "../driver.h" +#include +#include +#include +#include + +struct input_keyboard_line +{ + char *buffer; + size_t ptr; + size_t size; + + input_keyboard_line_complete_t cb; + void *userdata; +}; + +void input_keyboard_line_free(input_keyboard_line_t *state) +{ + if (!state) + return; + + free(state->buffer); + free(state); +} + +input_keyboard_line_t *input_keyboard_line_new(void *userdata, + input_keyboard_line_complete_t cb) +{ + input_keyboard_line_t *state = (input_keyboard_line_t*)calloc(1, sizeof(*state)); + if (!state) + return NULL; + + state->cb = cb; + state->userdata = userdata; + return state; +} + +bool input_keyboard_line_event(input_keyboard_line_t *state, 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') + { + state->cb(state->userdata, state->buffer); + 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; +} + +const char **input_keyboard_line_get_buffer(const input_keyboard_line_t *state) +{ + return (const char**)&state->buffer; +} + +static input_keyboard_line_t *g_keyboard_line; + +const char **input_keyboard_start_line(void *userdata, input_keyboard_line_complete_t cb) +{ + if (g_keyboard_line) + input_keyboard_line_free(g_keyboard_line); + + g_keyboard_line = input_keyboard_line_new(userdata, cb); + // While reading keyboard line input, we have to block all hotkeys. + driver.block_input = true; + + return input_keyboard_line_get_buffer(g_keyboard_line); +} + +void input_keyboard_event(bool down, unsigned code, uint32_t character, uint16_t mod) +{ + if (g_keyboard_line) + { + if (input_keyboard_line_event(g_keyboard_line, character)) + { + // Line is complete, can free it now. + input_keyboard_line_free(g_keyboard_line); + g_keyboard_line = NULL; + + // Unblock all hotkeys. + driver.block_input = false; + } + } + else if (g_extern.system.key_event) + g_extern.system.key_event(down, code, character, mod); +} + diff --git a/input/keyboard_line.h b/input/keyboard_line.h new file mode 100644 index 0000000000..2afce3b91b --- /dev/null +++ b/input/keyboard_line.h @@ -0,0 +1,54 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2010-2013 - Hans-Kristian Arntzen + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#ifndef KEYBOARD_LINE_H__ +#define KEYBOARD_LINE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "../boolean.h" +#include "../libretro.h" +#include + +// Keyboard line reader. Handles textual input in a direct fashion. +typedef struct input_keyboard_line input_keyboard_line_t; + +// Calls back after return is pressed with the completed line. +// line can be NULL. +typedef void (*input_keyboard_line_complete_t)(void *userdata, const char *line); + +input_keyboard_line_t *input_keyboard_line_new(void *userdata, + input_keyboard_line_complete_t cb); + +// Called on every keyboard character event. +bool input_keyboard_line_event(input_keyboard_line_t *state, uint32_t character); + +// Returns pointer to string. The underlying buffer can be reallocated at any time (or be NULL), but the pointer to it remains constant throughout the objects lifetime. +const char **input_keyboard_line_get_buffer(const input_keyboard_line_t *state); +void input_keyboard_line_free(input_keyboard_line_t *state); + +// Keyboard event utils. Called by drivers when keyboard events are fired. +// This interfaces with the global driver struct and libretro callbacks. +void input_keyboard_event(bool down, unsigned code, uint32_t character, uint16_t mod); +const char **input_keyboard_start_line(void *userdata, input_keyboard_line_complete_t cb); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/input/udev_input.c b/input/udev_input.c index 84496a92ff..46bb75ccda 100644 --- a/input/udev_input.c +++ b/input/udev_input.c @@ -14,6 +14,7 @@ */ #include "input_common.h" +#include "keyboard_line.h" #include "../general.h" #include "../conf/config_file.h" #include "../file_path.h" @@ -138,9 +139,9 @@ static void handle_xkb(udev_input_t *udev, int code, int value) if (udev->mod_map[i].index != XKB_MOD_INVALID) mod |= xkb_state_mod_index_is_active(udev->xkb_state, udev->mod_map[i].index, XKB_STATE_MODS_EFFECTIVE) > 0 ? udev->mod_map[i].bit : 0; - g_extern.system.key_event(value, input_translate_keysym_to_rk(code), num_syms ? xkb_keysym_to_utf32(syms[0]) : 0, mod); + input_keyboard_event(value, input_translate_keysym_to_rk(code), num_syms ? xkb_keysym_to_utf32(syms[0]) : 0, mod); for (i = 1; i < num_syms; i++) - g_extern.system.key_event(value, RETROK_UNKNOWN, xkb_keysym_to_utf32(syms[i]), mod); + input_keyboard_event(value, RETROK_UNKNOWN, xkb_keysym_to_utf32(syms[i]), mod); } #endif @@ -155,7 +156,7 @@ static void udev_handle_keyboard(udev_input_t *udev, const struct input_event *e clear_bit(udev->key_state, event->code); #ifdef HAVE_XKBCOMMON - if (udev->xkb_state && g_extern.system.key_event) + if (udev->xkb_state) handle_xkb(udev, event->code, event->value); #endif break; From f4cf33f7171ebb74f90d470685638017240ab762 Mon Sep 17 00:00:00 2001 From: Themaister Date: Tue, 10 Dec 2013 19:42:42 +0100 Subject: [PATCH 3/8] Update griffin. --- griffin/griffin.c | 1 + 1 file changed, 1 insertion(+) diff --git a/griffin/griffin.c b/griffin/griffin.c index 459655624f..9dfbaf74a8 100644 --- a/griffin/griffin.c +++ b/griffin/griffin.c @@ -280,6 +280,7 @@ FONTS INPUT ============================================================ */ #include "../input/input_common.c" +#include "../input/keyboard_line.c" #ifdef HAVE_OVERLAY #include "../input/overlay.c" From f7a58531544b42dd1aee98d8980266807290dc15 Mon Sep 17 00:00:00 2001 From: Themaister Date: Tue, 10 Dec 2013 19:42:50 +0100 Subject: [PATCH 4/8] Fix CXX_BUILD. --- input/udev_input.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/input/udev_input.c b/input/udev_input.c index 46bb75ccda..15a9821c44 100644 --- a/input/udev_input.c +++ b/input/udev_input.c @@ -370,12 +370,12 @@ static void handle_hotplug(udev_input_t *udev) bool is_mouse = val_mouse && !strcmp(val_mouse, "1") && devnode; bool is_touchpad = val_touchpad && !strcmp(val_touchpad, "1") && devnode; - if (!is_keyboard && !is_mouse && !is_touchpad) - goto end; - device_handle_cb cb = NULL; const char *devtype = NULL; + if (!is_keyboard && !is_mouse && !is_touchpad) + goto end; + if (is_keyboard) { cb = udev_handle_keyboard; @@ -523,7 +523,7 @@ static int16_t udev_input_state(void *data, const struct retro_keybind **binds, return ret; case RETRO_DEVICE_KEYBOARD: - return id < RETROK_LAST && get_bit(udev->key_state, input_translate_rk_to_keysym(id)); + return id < RETROK_LAST && get_bit(udev->key_state, input_translate_rk_to_keysym((enum retro_key)id)); case RETRO_DEVICE_MOUSE: return udev_mouse_state(udev, id); From fde4532a33b0b5e64d6d807c9444fb33e2e4d1d3 Mon Sep 17 00:00:00 2001 From: Themaister Date: Tue, 10 Dec 2013 19:46:50 +0100 Subject: [PATCH 5/8] Fix menu_search_callback. str can be empty and non-NULL. --- frontend/menu/menu_common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/menu/menu_common.c b/frontend/menu/menu_common.c index 6ecddf64e7..d29214ca7f 100644 --- a/frontend/menu/menu_common.c +++ b/frontend/menu/menu_common.c @@ -1727,7 +1727,7 @@ static void menu_search_callback(void *userdata, const char *str) { rgui_handle_t *rgui = (rgui_handle_t*)userdata; - if (str) + if (str && *str) file_list_search(rgui->selection_buf, str, &rgui->selection_ptr); rgui->keyboard.display = false; rgui->keyboard.label = NULL; From 6fa3cb2f85123e74f50c314869726e956980c82b Mon Sep 17 00:00:00 2001 From: Themaister Date: Tue, 10 Dec 2013 20:10:19 +0100 Subject: [PATCH 6/8] Use strcasestr. Since it's a GNU extension, move to strcasestr.h. --- compat/compat.c | 33 +++++++++++++++++++++++++++++++++ compat/strcasestr.h | 41 +++++++++++++++++++++++++++++++++++++++++ file_list.c | 3 ++- 3 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 compat/strcasestr.h diff --git a/compat/compat.c b/compat/compat.c index b1ed3dd547..469ec6e228 100644 --- a/compat/compat.c +++ b/compat/compat.c @@ -202,6 +202,39 @@ int getopt_long(int argc, char *argv[], #endif +#ifndef HAVE_STRCASESTR +// Pretty much strncasecmp. +static int casencmp(const char *a, const char *b, size_t n) +{ + size_t i; + for (i = 0; i < n; i++) + { + int a_lower = tolower(a[i]); + int b_lower = tolower(b[i]); + if (a_lower != b_lower) + return a_lower - b_lower; + } + + return 0; +} + +char *strcasestr_rarch__(const char *haystack, const char *needle) +{ + size_t i; + size_t hay_len = strlen(haystack); + size_t needle_len = strlen(needle); + if (needle_len > hay_len) + return NULL; + + size_t search_off = hay_len - needle_len; + for (i = 0; i <= search_off; i++) + if (!casencmp(haystack + i, needle, needle_len)) + return (char*)haystack + i; + + return NULL; +} +#endif + #ifndef HAVE_STRL // Implementation of strlcpy()/strlcat() based on OpenBSD. diff --git a/compat/strcasestr.h b/compat/strcasestr.h new file mode 100644 index 0000000000..1b9eb847e3 --- /dev/null +++ b/compat/strcasestr.h @@ -0,0 +1,41 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2010-2013 - Hans-Kristian Arntzen + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#ifndef RARCH_STRCASESTR_H +#define RARCH_STRCASESTR_H + +#include + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifndef HAVE_STRCASESTR + +#ifdef __cplusplus +extern "C" { +#endif +// Avoid possible naming collisions during link since we prefer to use the actual name. +#define strcasestr(haystack, needle) strcasestr_rarch__(haystack, needle) + +char *strcasestr(const char *haystack, const char *needle); +#ifdef __cplusplus +} +#endif +#endif + + +#endif + diff --git a/file_list.c b/file_list.c index 0b92977911..740266d7e4 100644 --- a/file_list.c +++ b/file_list.c @@ -17,6 +17,7 @@ #include #include #include "file_list.h" +#include "compat/strcasestr.h" struct item_file { @@ -128,7 +129,7 @@ bool file_list_search(const file_list_t *list, const char *needle, size_t *index file_list_get_alt_at_offset(list, i, &alt); if (!alt) continue; - if (strstr(alt, needle)) + if (strcasestr(alt, needle)) // GNU, but compat version in posix_string.h. { *index = i; return true; From f139e070fcbbc90a298b1015afb9e80d57ae6e7b Mon Sep 17 00:00:00 2001 From: Themaister Date: Tue, 10 Dec 2013 20:12:15 +0100 Subject: [PATCH 7/8] Add strcasestr check to quickbuild. --- compat/strcasestr.h | 1 - qb/config.libs.sh | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compat/strcasestr.h b/compat/strcasestr.h index 1b9eb847e3..7bd9113326 100644 --- a/compat/strcasestr.h +++ b/compat/strcasestr.h @@ -36,6 +36,5 @@ char *strcasestr(const char *haystack, const char *needle); #endif #endif - #endif diff --git a/qb/config.libs.sh b/qb/config.libs.sh index fb8e3455d7..031fd76c16 100644 --- a/qb/config.libs.sh +++ b/qb/config.libs.sh @@ -251,6 +251,7 @@ fi check_pkgconf UDEV libudev check_lib STRL -lc strlcpy +check_lib STRCASESTR -lc strcasestr check_lib MMAP -lc mmap check_pkgconf PYTHON python3 @@ -261,6 +262,6 @@ add_define_make OS "$OS" # Creates config.mk and config.h. add_define_make GLOBAL_CONFIG_DIR "$GLOBAL_CONFIG_DIR" -VARS="RGUI ALSA OSS OSS_BSD OSS_LIB AL RSOUND ROAR JACK COREAUDIO PULSE SDL OPENGL OMAP GLES VG EGL KMS GBM DRM DYLIB GETOPT_LONG THREADS CG LIBXML2 SDL_IMAGE ZLIB DYNAMIC FFMPEG AVCODEC AVFORMAT AVUTIL SWSCALE FREETYPE XKBCOMMON XVIDEO X11 XEXT XF86VM XINERAMA NETPLAY NETWORK_CMD STDIN_CMD COMMAND SOCKET_LEGACY FBO STRL MMAP PYTHON FFMPEG_ALLOC_CONTEXT3 FFMPEG_AVCODEC_OPEN2 FFMPEG_AVIO_OPEN FFMPEG_AVFORMAT_WRITE_HEADER FFMPEG_AVFORMAT_NEW_STREAM FFMPEG_AVCODEC_ENCODE_AUDIO2 FFMPEG_AVCODEC_ENCODE_VIDEO2 BSV_MOVIE VIDEOCORE NEON FLOATHARD FLOATSOFTFP UDEV V4L2" +VARS="RGUI ALSA OSS OSS_BSD OSS_LIB AL RSOUND ROAR JACK COREAUDIO PULSE SDL OPENGL OMAP GLES VG EGL KMS GBM DRM DYLIB GETOPT_LONG THREADS CG LIBXML2 SDL_IMAGE ZLIB DYNAMIC FFMPEG AVCODEC AVFORMAT AVUTIL SWSCALE FREETYPE XKBCOMMON XVIDEO X11 XEXT XF86VM XINERAMA NETPLAY NETWORK_CMD STDIN_CMD COMMAND SOCKET_LEGACY FBO STRL STRCASESTR MMAP PYTHON FFMPEG_ALLOC_CONTEXT3 FFMPEG_AVCODEC_OPEN2 FFMPEG_AVIO_OPEN FFMPEG_AVFORMAT_WRITE_HEADER FFMPEG_AVFORMAT_NEW_STREAM FFMPEG_AVCODEC_ENCODE_AUDIO2 FFMPEG_AVCODEC_ENCODE_VIDEO2 BSV_MOVIE VIDEOCORE NEON FLOATHARD FLOATSOFTFP UDEV V4L2" create_config_make config.mk $VARS create_config_header config.h $VARS From f014f3dafd441c659a02106af636dee16b44e8eb Mon Sep 17 00:00:00 2001 From: Themaister Date: Tue, 10 Dec 2013 20:17:53 +0100 Subject: [PATCH 8/8] Prioritize matches with first chars. --- file_list.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/file_list.c b/file_list.c index 740266d7e4..9a62c881f0 100644 --- a/file_list.c +++ b/file_list.c @@ -124,18 +124,27 @@ bool file_list_search(const file_list_t *list, const char *needle, size_t *index { size_t i; const char *alt; + bool ret = false; for (i = 0; i < list->size; i++) { file_list_get_alt_at_offset(list, i, &alt); if (!alt) continue; - if (strcasestr(alt, needle)) // GNU, but compat version in posix_string.h. + + const char *str = strcasestr(alt, needle); + if (str == alt) // Found match with first chars, best possible match. { *index = i; - return true; + ret = true; + break; + } + else if (str) // Found mid-string match, but try to find a match with first chars before we settle. + { + *index = i; + ret = true; } } - return false; + return ret; }