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;