From 6c79d66e1b49b6dd5b8575a0254dbd42c1142e69 Mon Sep 17 00:00:00 2001 From: Toad King Date: Fri, 25 May 2012 15:44:39 -0400 Subject: [PATCH] linuxraw input: gets input straight from stdin WARNING: this mode uses a raw keyboard mode. if the emulator does not exit cleanly, you could be left at a terminal with no form of input. do not use this mode for testing. --- Makefile | 2 + config.def.h | 1 + driver.c | 3 + driver.h | 1 + gfx/rpi.c | 13 +- input/linuxraw_input.c | 271 +++++++++++++++++++++++++++++++++++++++++ input/linuxraw_input.h | 13 ++ settings.c | 2 + 8 files changed, 305 insertions(+), 1 deletion(-) create mode 100644 input/linuxraw_input.c create mode 100644 input/linuxraw_input.h diff --git a/Makefile b/Makefile index 19f845bd56..7052dbd32d 100644 --- a/Makefile +++ b/Makefile @@ -30,6 +30,8 @@ endif ifneq ($(findstring Linux,$(OS)),) LIBS += -lrt + DEFINES += -DIS_LINUX + OBJ += input/linuxraw_input.o endif ifeq ($(HAVE_THREADS), 1) diff --git a/config.def.h b/config.def.h index 749ca8f178..895092f94c 100644 --- a/config.def.h +++ b/config.def.h @@ -63,6 +63,7 @@ #define INPUT_XENON360 21 #define INPUT_WII 23 #define INPUT_XDK360 26 +#define INPUT_LINUXRAW 30 //////////////////////// #if defined(HAVE_RPI) diff --git a/driver.c b/driver.c index 5d957c982b..1c8dc38290 100644 --- a/driver.c +++ b/driver.c @@ -123,6 +123,9 @@ static const input_driver_t *input_drivers[] = { #ifdef GEKKO &input_wii, #endif +#ifdef IS_LINUX + &input_linuxraw, +#endif }; static void find_audio_driver(void) diff --git a/driver.h b/driver.h index 5dd541f988..22cb157bc1 100644 --- a/driver.h +++ b/driver.h @@ -211,6 +211,7 @@ extern const input_driver_t input_ps3; extern const input_driver_t input_xenon360; extern const input_driver_t input_wii; extern const input_driver_t input_xdk360; +extern const input_driver_t input_linuxraw; //////////////////////////////////////////////// // Convenience macros. diff --git a/gfx/rpi.c b/gfx/rpi.c index 4b9c724f2f..33cc016ceb 100644 --- a/gfx/rpi.c +++ b/gfx/rpi.c @@ -7,6 +7,8 @@ #include #include "../libretro.h" #include "../general.h" +#include "../input/linuxraw_input.h" +#include "../driver.h" typedef struct { EGLDisplay mDisplay; @@ -28,7 +30,7 @@ typedef struct { static void rpi_set_nonblock_state(void *data, bool state) { rpi_t *rpi = (rpi_t*)data; - eglSwapInterval(rpi->mDisplay, state ? 1 : 0); + eglSwapInterval(rpi->mDisplay, state ? 0 : 1); } static void *rpi_init(const video_info_t *video, const input_driver_t **input, void **input_data) @@ -170,6 +172,15 @@ static void *rpi_init(const video_info_t *video, const input_driver_t **input, v // one image at the end of the day. rpi->mImage = vgCreateImage(VG_sXBGR_8888, rpi->mTextureWidth, rpi->mTextureHeight, VG_IMAGE_QUALITY_NONANTIALIASED); rpi_set_nonblock_state(rpi, video->vsync); + + linuxraw_input_t *linuxraw_input = (linuxraw_input_t*)input_linuxraw.init(); + if (linuxraw_input) + { + *input = &input_linuxraw; + *input_data = linuxraw_input; + } + else + *input = NULL; return rpi; } diff --git a/input/linuxraw_input.c b/input/linuxraw_input.c new file mode 100644 index 0000000000..a1c5af9e53 --- /dev/null +++ b/input/linuxraw_input.c @@ -0,0 +1,271 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2010-2012 - 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 "../driver.h" + +#include +#include +#include +#include +#include "../general.h" +#include "linuxraw_input.h" +#include "rarch_sdl_input.h" + +static long oldKbmd = 0xFFFF; +static struct termios oldTerm, newTerm; + +struct key_bind +{ + uint8_t x; + enum rarch_key sk; +}; + +static unsigned keysym_lut[SK_LAST]; +static const struct key_bind lut_binds[] = { + { 1, SK_ESCAPE }, + { 2, SK_1 }, + { 3, SK_2 }, + { 4, SK_3}, + { 5, SK_4 }, + { 6, SK_5 }, + { 7, SK_6 }, + { 8, SK_7 }, + { 9, SK_8 }, + { 10, SK_9 }, + { 11, SK_0 }, + { 12, SK_MINUS }, + { 13, SK_EQUALS }, + { 14, SK_BACKSPACE }, + { 15, SK_TAB }, + { 16, SK_q }, + { 17, SK_w }, + { 18, SK_e }, + { 19, SK_r }, + { 20, SK_t }, + { 21, SK_y }, + { 22, SK_u }, + { 23, SK_i }, + { 24, SK_o }, + { 25, SK_p }, + { 26, SK_LEFTBRACKET }, + { 27, SK_RIGHTBRACKET }, + { 28, SK_RETURN }, + { 29, SK_LCTRL }, + { 30, SK_a }, + { 31, SK_s }, + { 32, SK_d }, + { 33, SK_f }, + { 34, SK_g }, + { 35, SK_h }, + { 36, SK_j }, + { 37, SK_k }, + { 38, SK_l }, + { 39, SK_SEMICOLON }, + { 40, SK_COMMA }, + { 41, SK_BACKQUOTE }, + { 42, SK_LSHIFT }, + { 43, SK_BACKSLASH }, + { 44, SK_z }, + { 45, SK_x }, + { 46, SK_c }, + { 47, SK_v }, + { 48, SK_b }, + { 49, SK_n }, + { 50, SK_m }, + { 51, SK_COMMA }, + { 52, SK_PERIOD }, + { 53, SK_SLASH }, + { 54, SK_RSHIFT }, + { 55, SK_KP_MULTIPLY }, + { 56, SK_LALT }, + { 57, SK_SPACE }, + { 58, SK_CAPSLOCK }, + { 59, SK_F1 }, + { 60, SK_F2 }, + { 61, SK_F3 }, + { 62, SK_F4 }, + { 63, SK_F5 }, + { 64, SK_F6 }, + { 65, SK_F7 }, + { 66, SK_F8 }, + { 67, SK_F9 }, + { 68, SK_F10 }, + { 69, SK_NUMLOCK }, + { 70, SK_SCROLLOCK }, + { 71, SK_KP7 }, + { 72, SK_KP8 }, + { 73, SK_KP9 }, + { 74, SK_KP_MINUS }, + { 75, SK_KP4 }, + { 76, SK_KP5 }, + { 77, SK_KP6 }, + { 78, SK_KP_PLUS }, + { 79, SK_KP1 }, + { 80, SK_KP2 }, + { 81, SK_KP3 }, + { 82, SK_KP0 }, + { 83, SK_KP_PERIOD }, + + { 87, SK_F11 }, + { 88, SK_F12 }, + + { 96, SK_KP_ENTER }, + { 97, SK_RCTRL }, + { 98, SK_KP_DIVIDE }, + { 99, SK_PRINT }, + { 100, SK_RALT }, + + { 102, SK_HOME }, + { 103, SK_UP }, + { 104, SK_PAGEUP }, + { 105, SK_LEFT }, + { 106, SK_RIGHT }, + { 107, SK_END }, + { 108, SK_DOWN }, + { 109, SK_PAGEDOWN }, + { 110, SK_INSERT }, + { 111, SK_DELETE }, + + { 119, SK_PAUSE }, +}; + +static void init_lut(void) +{ + memset(keysym_lut, 0, sizeof(keysym_lut)); + for (unsigned i = 0; i < sizeof(lut_binds) / sizeof(lut_binds[0]); i++) + keysym_lut[lut_binds[i].sk] = lut_binds[i].x; +} + +static void linuxraw_resetKbmd() +{ + if (oldKbmd != 0xFFFF) + { + ioctl(0, KDSKBMODE, oldKbmd); + tcsetattr(0, TCSAFLUSH, &oldTerm); + oldKbmd = 0xFFFF; + } +} + +static void *linuxraw_input_init(void) +{ + linuxraw_input_t *linuxraw = (linuxraw_input_t*)calloc(1, sizeof(*linuxraw)); + if (!linuxraw) + return NULL; + + if (oldKbmd == 0xFFFF) + { + tcgetattr(0, &oldTerm); + newTerm = oldTerm; + newTerm.c_lflag &= ~(ECHO | ICANON | ISIG); + newTerm.c_iflag &= ~(ISTRIP | IGNCR | ICRNL | INLCR | IXOFF | IXON); + newTerm.c_cc[VMIN] = 0; + newTerm.c_cc[VTIME] = 0; + + if (ioctl(0, KDGKBMODE, &oldKbmd) != 0) + return NULL; + } + + tcsetattr(0, TCSAFLUSH, &newTerm); + + if (ioctl(0, KDSKBMODE, K_MEDIUMRAW) != 0) + { + linuxraw_resetKbmd(); + return NULL; + } + + atexit(linuxraw_resetKbmd); + + linuxraw->sdl = (sdl_input_t*)input_sdl.init(); + if (!linuxraw->sdl) + { + free(linuxraw); + return NULL; + } + + init_lut(); + + linuxraw->sdl->use_keyboard = false; + return linuxraw; +} + +static bool linuxraw_key_pressed(linuxraw_input_t *linuxraw, int key) +{ + return linuxraw->state[keysym_lut[key]]; +} + +static bool linuxraw_is_pressed(linuxraw_input_t *linuxraw, const struct snes_keybind *binds, unsigned id) +{ + if (id < RARCH_BIND_LIST_END) + { + const struct snes_keybind *bind = &binds[id]; + return bind->valid && linuxraw_key_pressed(linuxraw, binds[id].key); + } + else + return false; +} + +static bool linuxraw_bind_button_pressed(void *data, int key) +{ + linuxraw_input_t *linuxraw = (linuxraw_input_t*)data; + return linuxraw_is_pressed(linuxraw, g_settings.input.binds[0], key) || + input_sdl.key_pressed(linuxraw->sdl, key); +} + +static int16_t linuxraw_input_state(void *data, const struct snes_keybind **binds, unsigned port, unsigned device, unsigned index, unsigned id) +{ + linuxraw_input_t *linuxraw = (linuxraw_input_t*)data; + + switch (device) + { + case RETRO_DEVICE_JOYPAD: + return linuxraw_is_pressed(linuxraw, binds[port], id) || + input_sdl.input_state(linuxraw->sdl, binds, port, device, index, id); + + default: + return 0; + } +} + +static void linuxraw_input_free(void *data) +{ + linuxraw_input_t *linuxraw = (linuxraw_input_t*)data; + input_sdl.free(linuxraw->sdl); + linuxraw_resetKbmd(); + free(data); +} + +static void linuxraw_input_poll(void *data) +{ + linuxraw_input_t *linuxraw = (linuxraw_input_t*)data; + uint8_t c; + + while (read(0, &c, 1)) + { + bool pressed = !(c & 0x80); + c &= ~0x80; + linuxraw->state[c] = pressed; + } + + input_sdl.poll(linuxraw->sdl); +} + +const input_driver_t input_linuxraw = { + linuxraw_input_init, + linuxraw_input_poll, + linuxraw_input_state, + linuxraw_bind_button_pressed, + linuxraw_input_free, + "linuxraw" +}; diff --git a/input/linuxraw_input.h b/input/linuxraw_input.h new file mode 100644 index 0000000000..a75caf03bb --- /dev/null +++ b/input/linuxraw_input.h @@ -0,0 +1,13 @@ +#include "../general.h" +#include "rarch_sdl_input.h" + +#ifndef _LINUXRAW_INPUT_H +#define _LINUXRAW_INPUT_H + +typedef struct linuxraw_input +{ + sdl_input_t *sdl; + bool state[0x80]; +} linuxraw_input_t; + +#endif diff --git a/settings.c b/settings.c index 6576fc4811..3895ffd5cb 100644 --- a/settings.c +++ b/settings.c @@ -114,6 +114,8 @@ const char *config_get_default_input(void) return "xdk360"; case INPUT_WII: return "wii"; + case INPUT_LINUXRAW: + return "linuxraw"; default: return NULL; }