2013-12-10 18:39:09 +00:00
|
|
|
/* RetroArch - A frontend for libretro.
|
2014-01-01 00:50:59 +00:00
|
|
|
* Copyright (C) 2010-2014 - Hans-Kristian Arntzen
|
2014-04-13 10:12:12 +00:00
|
|
|
*
|
2013-12-10 18:39:09 +00:00
|
|
|
* 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 <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "keyboard_line.h"
|
|
|
|
#include "../general.h"
|
|
|
|
#include "../driver.h"
|
|
|
|
#include <stddef.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stddef.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2014-05-12 20:32:14 +00:00
|
|
|
bool input_keyboard_line_event(input_keyboard_line_t *state, uint32_t character, bool down)
|
2013-12-10 18:39:09 +00:00
|
|
|
{
|
2014-05-12 20:32:14 +00:00
|
|
|
if (!down)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2013-12-10 18:39:09 +00:00
|
|
|
// 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;
|
|
|
|
|
2014-04-13 10:12:12 +00:00
|
|
|
static input_keyboard_press_t g_keyboard_press_cb;
|
|
|
|
static void *g_keyboard_press_data;
|
|
|
|
|
2013-12-10 18:39:09 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2014-04-13 10:12:12 +00:00
|
|
|
void input_keyboard_wait_keys(void *userdata, input_keyboard_press_t cb)
|
|
|
|
{
|
|
|
|
g_keyboard_press_cb = cb;
|
|
|
|
g_keyboard_press_data = userdata;
|
|
|
|
// While waiting for input, we have to block all hotkeys.
|
|
|
|
driver.block_input = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void input_keyboard_wait_keys_cancel(void)
|
|
|
|
{
|
|
|
|
g_keyboard_press_cb = NULL;
|
|
|
|
g_keyboard_press_data = NULL;
|
|
|
|
driver.block_input = false;
|
|
|
|
}
|
|
|
|
|
2013-12-10 18:39:09 +00:00
|
|
|
void input_keyboard_event(bool down, unsigned code, uint32_t character, uint16_t mod)
|
|
|
|
{
|
2014-04-13 17:47:32 +00:00
|
|
|
static bool deferred_wait_keys;
|
|
|
|
|
|
|
|
if (deferred_wait_keys)
|
|
|
|
{
|
2014-04-13 17:51:10 +00:00
|
|
|
if (!down)
|
|
|
|
{
|
|
|
|
input_keyboard_wait_keys_cancel();
|
|
|
|
deferred_wait_keys = false;
|
|
|
|
}
|
2014-04-13 17:47:32 +00:00
|
|
|
}
|
|
|
|
else if (g_keyboard_press_cb)
|
2014-04-13 10:12:12 +00:00
|
|
|
{
|
|
|
|
if (down && code != RETROK_UNKNOWN && !g_keyboard_press_cb(g_keyboard_press_data, code))
|
2014-04-13 17:47:32 +00:00
|
|
|
deferred_wait_keys = true;
|
2014-04-13 10:12:12 +00:00
|
|
|
}
|
|
|
|
else if (g_keyboard_line)
|
2013-12-10 18:39:09 +00:00
|
|
|
{
|
2014-05-12 20:32:14 +00:00
|
|
|
if (input_keyboard_line_event(g_keyboard_line, character, down))
|
2013-12-10 18:39:09 +00:00
|
|
|
{
|
|
|
|
// 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);
|
|
|
|
}
|
|
|
|
|