/* RetroArch - A frontend for libretro. * Copyright (C) 2010-2014 - 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' || c == '\x7f') /* 0x7f is ASCII for del */ { 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; static input_keyboard_press_t g_keyboard_press_cb; static void *g_keyboard_press_data; 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_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; } void input_keyboard_event(bool down, unsigned code, uint32_t character, uint16_t mod) { static bool deferred_wait_keys; if (deferred_wait_keys) { if (!down) { input_keyboard_wait_keys_cancel(); deferred_wait_keys = false; } } else if (g_keyboard_press_cb) { if (down && code != RETROK_UNKNOWN && !g_keyboard_press_cb(g_keyboard_press_data, code)) deferred_wait_keys = true; } else if (g_keyboard_line) { if (down && 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); }