From 977cec137888296b0228ef665b6aa1ff95f13515 Mon Sep 17 00:00:00 2001 From: Themaister Date: Tue, 10 Dec 2013 19:39:09 +0100 Subject: [PATCH] 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;