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
|
2016-01-10 03:33:01 +00:00
|
|
|
* Copyright (C) 2011-2016 - Daniel De Matteis
|
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/>.
|
|
|
|
*/
|
|
|
|
|
2015-06-25 11:40:53 +00:00
|
|
|
#include <stddef.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
|
2015-11-28 15:13:16 +00:00
|
|
|
#include "input_keyboard.h"
|
2013-12-10 18:39:09 +00:00
|
|
|
|
2015-12-06 18:31:47 +00:00
|
|
|
#include "../general.h"
|
|
|
|
|
2013-12-10 18:39:09 +00:00
|
|
|
struct input_keyboard_line
|
|
|
|
{
|
|
|
|
char *buffer;
|
|
|
|
size_t ptr;
|
|
|
|
size_t size;
|
|
|
|
|
2015-01-12 02:13:03 +00:00
|
|
|
/** Line complete callback.
|
2016-02-05 13:11:38 +00:00
|
|
|
* Calls back after return is
|
|
|
|
* pressed with the completed line.
|
2015-01-12 02:13:03 +00:00
|
|
|
* Line can be NULL.
|
|
|
|
**/
|
2013-12-10 18:39:09 +00:00
|
|
|
input_keyboard_line_complete_t cb;
|
|
|
|
void *userdata;
|
|
|
|
};
|
|
|
|
|
2015-11-30 02:14:26 +00:00
|
|
|
static input_keyboard_line_t *g_keyboard_line;
|
|
|
|
|
|
|
|
static input_keyboard_press_t g_keyboard_press_cb;
|
|
|
|
|
|
|
|
static void *g_keyboard_press_data;
|
|
|
|
|
2015-01-29 22:12:42 +00:00
|
|
|
static void input_keyboard_line_toggle_osk(bool enable)
|
|
|
|
{
|
2015-03-20 21:22:06 +00:00
|
|
|
settings_t *settings = config_get_ptr();
|
|
|
|
|
|
|
|
if (!settings->osk.enable)
|
2015-01-29 22:35:06 +00:00
|
|
|
return;
|
|
|
|
|
2015-11-30 02:23:35 +00:00
|
|
|
if (enable)
|
2016-03-23 05:19:33 +00:00
|
|
|
input_keyboard_ctl(RARCH_INPUT_KEYBOARD_CTL_SET_LINEFEED_ENABLED, NULL);
|
2015-11-30 02:23:35 +00:00
|
|
|
else
|
2016-03-23 05:19:33 +00:00
|
|
|
input_keyboard_ctl(RARCH_INPUT_KEYBOARD_CTL_UNSET_LINEFEED_ENABLED, NULL);
|
2015-01-29 22:12:42 +00:00
|
|
|
}
|
|
|
|
|
2015-01-12 02:13:03 +00:00
|
|
|
/**
|
|
|
|
* input_keyboard_line_free:
|
|
|
|
* @state : Input keyboard line handle.
|
|
|
|
*
|
|
|
|
* Frees input keyboard line handle.
|
|
|
|
**/
|
2016-03-23 05:53:19 +00:00
|
|
|
static void input_keyboard_line_free(input_keyboard_line_t *state)
|
2013-12-10 18:39:09 +00:00
|
|
|
{
|
|
|
|
if (!state)
|
|
|
|
return;
|
|
|
|
|
|
|
|
free(state->buffer);
|
|
|
|
free(state);
|
2015-01-29 19:33:27 +00:00
|
|
|
|
2015-01-29 22:12:42 +00:00
|
|
|
input_keyboard_line_toggle_osk(false);
|
2013-12-10 18:39:09 +00:00
|
|
|
}
|
|
|
|
|
2015-01-12 02:13:03 +00:00
|
|
|
/**
|
|
|
|
* input_keyboard_line_new:
|
|
|
|
* @userdata : Userdata.
|
|
|
|
* @cb : Callback function.
|
|
|
|
*
|
|
|
|
* Creates and initializes input keyboard line handle.
|
|
|
|
* Also sets callback function for keyboard line handle
|
|
|
|
* to provided callback @cb.
|
|
|
|
*
|
|
|
|
* Returns: keyboard handle on success, otherwise NULL.
|
|
|
|
**/
|
2016-03-23 05:53:19 +00:00
|
|
|
static input_keyboard_line_t *input_keyboard_line_new(void *userdata,
|
2013-12-10 18:39:09 +00:00
|
|
|
input_keyboard_line_complete_t cb)
|
|
|
|
{
|
2014-09-02 14:50:28 +00:00
|
|
|
input_keyboard_line_t *state = (input_keyboard_line_t*)
|
|
|
|
calloc(1, sizeof(*state));
|
2013-12-10 18:39:09 +00:00
|
|
|
if (!state)
|
|
|
|
return NULL;
|
|
|
|
|
2016-02-15 06:16:09 +00:00
|
|
|
state->cb = cb;
|
2013-12-10 18:39:09 +00:00
|
|
|
state->userdata = userdata;
|
2015-01-29 19:33:27 +00:00
|
|
|
|
2015-01-29 22:12:42 +00:00
|
|
|
input_keyboard_line_toggle_osk(true);
|
2015-01-29 19:33:27 +00:00
|
|
|
|
2013-12-10 18:39:09 +00:00
|
|
|
return state;
|
|
|
|
}
|
|
|
|
|
2015-01-12 02:13:03 +00:00
|
|
|
/**
|
|
|
|
* input_keyboard_line_event:
|
|
|
|
* @state : Input keyboard line handle.
|
|
|
|
* @character : Inputted character.
|
|
|
|
*
|
|
|
|
* Called on every keyboard character event.
|
|
|
|
*
|
|
|
|
* Returns: true (1) on success, otherwise false (0).
|
|
|
|
**/
|
2016-03-24 02:45:16 +00:00
|
|
|
static bool input_keyboard_line_event(
|
2014-09-02 14:50:28 +00:00
|
|
|
input_keyboard_line_t *state, uint32_t character)
|
2013-12-10 18:39:09 +00:00
|
|
|
{
|
2015-01-12 02:13:03 +00:00
|
|
|
char c = character >= 128 ? '?' : character;
|
2014-09-02 14:50:28 +00:00
|
|
|
/* Treat extended chars as ? as we cannot support
|
|
|
|
* printable characters for unicode stuff. */
|
2015-01-12 02:13:03 +00:00
|
|
|
|
2013-12-10 18:39:09 +00:00
|
|
|
if (c == '\r' || c == '\n')
|
|
|
|
{
|
|
|
|
state->cb(state->userdata, state->buffer);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-05-12 21:23:34 +00:00
|
|
|
if (c == '\b' || c == '\x7f') /* 0x7f is ASCII for del */
|
2013-12-10 18:39:09 +00:00
|
|
|
{
|
|
|
|
if (state->ptr)
|
|
|
|
{
|
2016-02-05 13:11:38 +00:00
|
|
|
memmove(state->buffer + state->ptr - 1,
|
|
|
|
state->buffer + state->ptr,
|
2013-12-10 18:39:09 +00:00
|
|
|
state->size - state->ptr + 1);
|
|
|
|
state->ptr--;
|
|
|
|
state->size--;
|
|
|
|
}
|
|
|
|
}
|
2015-09-05 12:34:33 +00:00
|
|
|
else if (isprint((int)c))
|
2013-12-10 18:39:09 +00:00
|
|
|
{
|
2015-01-12 02:13:03 +00:00
|
|
|
/* Handle left/right here when suitable */
|
|
|
|
|
2016-02-15 06:16:09 +00:00
|
|
|
char *newbuf = (char*)
|
|
|
|
realloc(state->buffer, state->size + 2);
|
2013-12-10 18:39:09 +00:00
|
|
|
if (!newbuf)
|
|
|
|
return false;
|
|
|
|
|
2014-09-02 14:50:28 +00:00
|
|
|
memmove(newbuf + state->ptr + 1,
|
2016-02-05 13:11:38 +00:00
|
|
|
newbuf + state->ptr,
|
|
|
|
state->size - state->ptr + 1);
|
2013-12-10 18:39:09 +00:00
|
|
|
newbuf[state->ptr] = c;
|
|
|
|
state->ptr++;
|
|
|
|
state->size++;
|
|
|
|
newbuf[state->size] = '\0';
|
|
|
|
|
|
|
|
state->buffer = newbuf;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-01-12 02:13:03 +00:00
|
|
|
/**
|
|
|
|
* input_keyboard_start_line:
|
|
|
|
* @userdata : Userdata.
|
|
|
|
* @cb : Line complete callback function.
|
|
|
|
*
|
|
|
|
* Sets function pointer for keyboard line handle.
|
|
|
|
*
|
2016-03-24 02:45:16 +00:00
|
|
|
* The underlying buffer can be reallocated at any time
|
|
|
|
* (or be NULL), but the pointer to it remains constant
|
|
|
|
* throughout the objects lifetime.
|
|
|
|
*
|
|
|
|
* Returns: underlying buffer of the keyboard line.
|
2015-01-12 02:13:03 +00:00
|
|
|
**/
|
2014-09-02 14:50:28 +00:00
|
|
|
const char **input_keyboard_start_line(void *userdata,
|
|
|
|
input_keyboard_line_complete_t cb)
|
2013-12-10 18:39:09 +00:00
|
|
|
{
|
2016-03-24 02:36:38 +00:00
|
|
|
input_keyboard_ctl(RARCH_INPUT_KEYBOARD_CTL_LINE_FREE, NULL);
|
2013-12-10 18:39:09 +00:00
|
|
|
|
|
|
|
g_keyboard_line = input_keyboard_line_new(userdata, cb);
|
2014-09-02 14:50:28 +00:00
|
|
|
|
|
|
|
/* While reading keyboard line input, we have to block all hotkeys. */
|
2015-06-19 01:45:23 +00:00
|
|
|
input_driver_keyboard_mapping_set_block(true);
|
2013-12-10 18:39:09 +00:00
|
|
|
|
2016-03-24 02:45:16 +00:00
|
|
|
return (const char**)&g_keyboard_line->buffer;
|
2013-12-10 18:39:09 +00:00
|
|
|
}
|
|
|
|
|
2015-01-12 02:13:03 +00:00
|
|
|
/**
|
|
|
|
* input_keyboard_event:
|
|
|
|
* @down : Keycode was pressed down?
|
|
|
|
* @code : Keycode.
|
|
|
|
* @character : Character inputted.
|
|
|
|
* @mod : TODO/FIXME: ???
|
|
|
|
*
|
|
|
|
* Keyboard event utils. Called by drivers when keyboard events are fired.
|
2015-06-25 11:40:53 +00:00
|
|
|
* This interfaces with the global system driver struct and libretro callbacks.
|
2015-01-12 02:13:03 +00:00
|
|
|
**/
|
2014-09-02 14:50:28 +00:00
|
|
|
void input_keyboard_event(bool down, unsigned code,
|
2015-01-29 22:59:46 +00:00
|
|
|
uint32_t character, uint16_t mod, unsigned device)
|
2013-12-10 18:39:09 +00:00
|
|
|
{
|
2014-04-13 17:47:32 +00:00
|
|
|
static bool deferred_wait_keys;
|
|
|
|
|
|
|
|
if (deferred_wait_keys)
|
|
|
|
{
|
2015-01-18 18:39:58 +00:00
|
|
|
if (down)
|
|
|
|
return;
|
|
|
|
|
2016-03-23 05:44:00 +00:00
|
|
|
input_keyboard_ctl(RARCH_INPUT_KEYBOARD_CTL_CANCEL_WAIT_KEYS, NULL);
|
2015-01-18 18:39:58 +00:00
|
|
|
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
|
|
|
{
|
2016-03-23 05:44:00 +00:00
|
|
|
if (!down || code == RETROK_UNKNOWN)
|
2015-01-18 18:39:58 +00:00
|
|
|
return;
|
|
|
|
if (g_keyboard_press_cb(g_keyboard_press_data, code))
|
|
|
|
return;
|
|
|
|
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
|
|
|
{
|
2015-01-18 18:39:58 +00:00
|
|
|
if (!down)
|
|
|
|
return;
|
2015-01-29 06:03:20 +00:00
|
|
|
|
2015-02-15 05:57:02 +00:00
|
|
|
switch (device)
|
2015-01-29 06:03:20 +00:00
|
|
|
{
|
2015-02-15 05:57:02 +00:00
|
|
|
case RETRO_DEVICE_POINTER:
|
2016-02-05 13:11:38 +00:00
|
|
|
if (!input_keyboard_line_event(g_keyboard_line,
|
|
|
|
(code != 0x12d) ? (char)code : character))
|
2015-02-15 05:57:02 +00:00
|
|
|
return;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
if (!input_keyboard_line_event(g_keyboard_line, character))
|
|
|
|
return;
|
|
|
|
break;
|
2015-01-29 06:03:20 +00:00
|
|
|
}
|
2013-12-10 18:39:09 +00:00
|
|
|
|
2015-01-18 18:39:58 +00:00
|
|
|
/* Line is complete, can free it now. */
|
2016-03-24 02:36:38 +00:00
|
|
|
input_keyboard_ctl(RARCH_INPUT_KEYBOARD_CTL_LINE_FREE, NULL);
|
2015-01-18 18:39:58 +00:00
|
|
|
|
|
|
|
/* Unblock all hotkeys. */
|
2015-06-19 01:45:23 +00:00
|
|
|
input_driver_keyboard_mapping_set_block(false);
|
2013-12-10 18:39:09 +00:00
|
|
|
}
|
2015-12-13 12:58:19 +00:00
|
|
|
else
|
|
|
|
{
|
2015-12-13 13:31:06 +00:00
|
|
|
retro_keyboard_event_t *key_event = NULL;
|
|
|
|
runloop_ctl(RUNLOOP_CTL_KEY_EVENT_GET, &key_event);
|
2015-12-13 12:58:19 +00:00
|
|
|
|
2015-12-13 13:31:06 +00:00
|
|
|
if (key_event && *key_event)
|
|
|
|
(*key_event)(down, code, character, mod);
|
2015-12-13 12:58:19 +00:00
|
|
|
}
|
2013-12-10 18:39:09 +00:00
|
|
|
}
|
2016-03-23 05:11:39 +00:00
|
|
|
|
|
|
|
bool input_keyboard_ctl(enum rarch_input_keyboard_ctl_state state, void *data)
|
|
|
|
{
|
2016-03-23 05:18:09 +00:00
|
|
|
static bool input_driver_keyboard_linefeed_enable = false;
|
|
|
|
|
2016-03-23 05:11:39 +00:00
|
|
|
switch (state)
|
|
|
|
{
|
2016-03-24 02:36:38 +00:00
|
|
|
case RARCH_INPUT_KEYBOARD_CTL_LINE_FREE:
|
|
|
|
if (g_keyboard_line)
|
|
|
|
input_keyboard_line_free(g_keyboard_line);
|
|
|
|
g_keyboard_line = NULL;
|
|
|
|
break;
|
2016-03-23 05:44:00 +00:00
|
|
|
case RARCH_INPUT_KEYBOARD_CTL_START_WAIT_KEYS:
|
|
|
|
{
|
|
|
|
input_keyboard_ctx_wait_t *keys = (input_keyboard_ctx_wait_t*)data;
|
|
|
|
|
|
|
|
if (!keys)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
g_keyboard_press_cb = keys->cb;
|
|
|
|
g_keyboard_press_data = keys->userdata;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* While waiting for input, we have to block all hotkeys. */
|
|
|
|
input_driver_keyboard_mapping_set_block(true);
|
|
|
|
break;
|
|
|
|
case RARCH_INPUT_KEYBOARD_CTL_CANCEL_WAIT_KEYS:
|
|
|
|
g_keyboard_press_cb = NULL;
|
|
|
|
g_keyboard_press_data = NULL;
|
|
|
|
input_driver_keyboard_mapping_set_block(false);
|
|
|
|
break;
|
2016-03-23 05:18:09 +00:00
|
|
|
case RARCH_INPUT_KEYBOARD_CTL_DESTROY:
|
|
|
|
input_driver_keyboard_linefeed_enable = false;
|
|
|
|
break;
|
|
|
|
case RARCH_INPUT_KEYBOARD_CTL_SET_LINEFEED_ENABLED:
|
|
|
|
input_driver_keyboard_linefeed_enable = true;
|
|
|
|
break;
|
|
|
|
case RARCH_INPUT_KEYBOARD_CTL_UNSET_LINEFEED_ENABLED:
|
|
|
|
input_driver_keyboard_linefeed_enable = false;
|
|
|
|
break;
|
|
|
|
case RARCH_INPUT_KEYBOARD_CTL_IS_LINEFEED_ENABLED:
|
|
|
|
return input_driver_keyboard_linefeed_enable;
|
2016-03-23 05:11:39 +00:00
|
|
|
case RARCH_INPUT_KEYBOARD_CTL_NONE:
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|