[EMSCRIPTEN] add custom input driver, removes SDL dependency + adds mouse support

This commit is contained in:
ToadKing 2013-09-10 20:21:48 -04:00
parent 336e1eeb51
commit a09dda3a9d
12 changed files with 403 additions and 24 deletions

View File

@ -15,6 +15,7 @@ OBJ = frontend/frontend_emscripten.o \
movie.o \
gfx/gfx_common.o \
input/input_common.o \
input/rwebinput_input.o \
core_options.o \
patch.o \
compat/compat.o \
@ -22,7 +23,7 @@ OBJ = frontend/frontend_emscripten.o \
screenshot.o \
cheats.o \
audio/utils.o \
emscripten/RWebAudio.o \
audio/rwebaudio.o \
input/overlay.o \
fifo_buffer.o \
gfx/scaler/scaler.o \
@ -41,9 +42,7 @@ OBJ = frontend/frontend_emscripten.o \
HAVE_OPENGL = 1
HAVE_RGUI = 1
HAVE_SDL = 1
HAVE_SDL_IMAGE = 1
HAVE_FREETYPE = 1
HAVE_SDL = 0
HAVE_ZLIB = 1
HAVE_FBO = 1
WANT_MINIZ = 1
@ -59,11 +58,7 @@ libretro = libretro_emscripten.bc
LIBS = -lm
DEFINES = -DHAVE_SCREENSHOTS -DHAVE_NULLAUDIO -DHAVE_BSV_MOVIE -DPACKAGE_VERSION=\"0.9.9.3\"
LDFLAGS = -L. -s TOTAL_MEMORY=$(MEMORY) --js-library emscripten/library_rwebaudio.js
ifeq ($(SCALER_NO_SIMD), 1)
DEFINES += -DSCALER_NO_SIMD
endif
LDFLAGS = -L. -s TOTAL_MEMORY=$(MEMORY) --js-library emscripten/library_rwebaudio.js --js-library emscripten/library_rwebinput.js
ifeq ($(PERF_TEST), 1)
DEFINES += -DPERF_TEST
@ -80,11 +75,6 @@ ifeq ($(HAVE_SDL), 1)
DEFINES += -ISDL -DHAVE_SDL
endif
ifeq ($(HAVE_THREADS), 1)
OBJ += autosave.o thread.o gfx/thread_wrapper.o
DEFINES += -DHAVE_THREADS
endif
ifeq ($(HAVE_OPENGL), 1)
OBJ += gfx/gl.o gfx/math/matrix.o gfx/fonts/gl_font.o gfx/fonts/gl_raster_font.o gfx/gfx_context.o gfx/context/emscriptenegl_ctx.o gfx/shader_glsl.o gfx/glsym/rglgen.o gfx/glsym/glsym_es2.o
DEFINES += -DHAVE_OPENGL -DHAVE_OPENGLES -DHAVE_OPENGLES2 -DHAVE_EGL -DHAVE_OVERLAY -DHAVE_GLSL

View File

@ -16,7 +16,7 @@
#include "../driver.h"
#include "../general.h"
#include "RWebAudio.h"
#include "../emscripten/RWebAudio.h"
static void ra_free(void *data)
{

View File

@ -78,6 +78,7 @@ enum
INPUT_LINUXRAW,
INPUT_APPLE,
INPUT_QNX,
INPUT_RWEBINPUT,
INPUT_NULL
};
@ -155,6 +156,8 @@ enum
#define INPUT_DEFAULT_DRIVER INPUT_ANDROID
#elif defined(_WIN32)
#define INPUT_DEFAULT_DRIVER INPUT_DINPUT
#elif defined(EMSCRIPTEN)
#define INPUT_DEFAULT_DRIVER INPUT_RWEBINPUT
#elif defined(HAVE_SDL)
#define INPUT_DEFAULT_DRIVER INPUT_SDL
#elif defined(__CELLOS_LV2__)

View File

@ -63,7 +63,7 @@ static const audio_driver_t *audio_drivers[] = {
#ifdef HAVE_JACK
&audio_jack,
#endif
#if defined(HAVE_SDL) && !defined(EMSCRIPTEN)
#ifdef HAVE_SDL
&audio_sdl,
#endif
#ifdef HAVE_XAUDIO
@ -168,6 +168,9 @@ static const input_driver_t *input_drivers[] = {
#ifdef __BLACKBERRY_QNX__
&input_qnx,
#endif
#ifdef EMSCRIPTEN
&input_rwebinput,
#endif
#ifdef HAVE_NULLINPUT
&input_null,
#endif

View File

@ -537,6 +537,7 @@ extern const input_driver_t input_xinput;
extern const input_driver_t input_linuxraw;
extern const input_driver_t input_apple;
extern const input_driver_t input_qnx;
extern const input_driver_t input_rwebinput;
extern const input_driver_t input_null;
#include "driver_funcs.h"

29
emscripten/RWebInput.h Normal file
View File

@ -0,0 +1,29 @@
/* RetroArch - A frontend for libretro.
* Copyright (C) 2010-2013 - Michael Lelli
*
* 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 <stdlib.h>
typedef struct rwebinput_state
{
char keys[32];
int mouse_x;
int mouse_y;
char mouse_l;
char mouse_r;
} rwebinput_state_t;
int RWebInputInit(void);
rwebinput_state_t *RWebInputPoll(int context);
void RWebInputDestroy(int context);

View File

@ -0,0 +1,115 @@
//"use strict";
var LibraryRWebInput = {
$RI__deps: ['$Browser'],
$RI: {
temp: null,
contexts: [],
eventHandler: function(event) {
var i;
switch (event.type) {
case 'mousemove':
var x = event['movementX'] || event['mozMovementX'] || event['webkitMovementX'];
var y = event['movementY'] || event['mozMovementY'] || event['webkitMovementY'];
for (i = 0; i < RI.contexts.length; i++) {
var oldX = {{{ makeGetValue('RI.contexts[i].state', '32', 'i32') }}};
var oldY = {{{ makeGetValue('RI.contexts[i].state', '36', 'i32') }}};
x += oldX;
y += oldY;
{{{ makeSetValue('RI.contexts[i].state', '32', 'x', 'i32') }}};
{{{ makeSetValue('RI.contexts[i].state', '36', 'y', 'i32') }}};
}
break;
case 'mouseup':
case 'mousedown':
var l, r;
if (event.buttons & 1) l = 1;
else l = 0;
if (event.buttons & 2) r = 1;
else r = 0;
for (i = 0; i < RI.contexts.length; i++) {
{{{ makeSetValue('RI.contexts[i].state', '40', 'l', 'i8') }}};
{{{ makeSetValue('RI.contexts[i].state', '41', 'r', 'i8') }}};
}
break;
case 'click':
e.preventDefault();
break;
case 'keyup':
case 'keydown':
var key = event.keyCode;
var offset = key >> 3;
var bit = 1 << (key & 7);
if (offset >= 32) throw 'key code error! bad code: ' + key;
for (i = 0; i < RI.contexts.length; i++) {
var value = {{{ makeGetValue('RI.contexts[i].state', 'offset', 'i8') }}};
if (event.type === 'keyup') value &= ~bit;
else value |= bit;
{{{ makeSetValue('RI.contexts[i].state', 'offset', 'value', 'i8') }}};
}
event.preventDefault();
break;
case 'blur':
case 'visibilitychange':
for (i = 0; i < RI.contexts.length; i++) {
_memset(RI.contexts[i].state, 0, 42);
}
break;
}
}
},
RWebInputInit: function(latency) {
if (RI.contexts.length === 0) {
document.addEventListener('keyup', RI.eventHandler, false);
document.addEventListener('keydown', RI.eventHandler, false);
document.addEventListener('mousemove', RI.eventHandler, false);
document.addEventListener('mouseup', RI.eventHandler, false);
document.addEventListener('mousedown', RI.eventHandler, false);
document.addEventListener('click', RI.eventHandler, false);
document.addEventListener('blur', RI.eventHandler, false);
document.addEventListener('onvisbilitychange', RI.eventHandler, false);
}
if (RI.temp === null) RI.temp = _malloc(42);
var s = _malloc(42);
_memset(s, 0, 42);
RI.contexts.push({
state: s
});
return RI.contexts.length;
},
RWebInputPoll: function(context) {
context -= 1;
var state = RI.contexts[context].state;
_memcpy(RI.temp, state, 42);
// reset mouse movements
{{{ makeSetValue('RI.contexts[context].state', '32', '0', 'i32') }}};
{{{ makeSetValue('RI.contexts[context].state', '36', '0', 'i32') }}};
return RI.temp;
},
RWebInputDestroy: function (context) {
if (context === RI.contexts.length) {
RI.contexts.pop();
if (RI.contexts.length === 0) {
document.removeEventListener('keyup', RI.eventHandler, false);
document.removeEventListener('keydown', RI.eventHandler, false);
document.removeEventListener('mousemove', RI.eventHandler, false);
document.removeEventListener('mouseup', RI.eventHandler, false);
document.removeEventListener('mousedown', RI.eventHandler, false);
document.removeEventListener('click', RI.eventHandler, false);
document.removeEventListener('blur', RI.eventHandler, false);
document.removeEventListener('onvisbilitychange', RI.eventHandler, false);
}
}
}
};
autoAddDeps(LibraryRWebInput, '$RI');
mergeInto(LibraryManager.library, LibraryRWebInput);

View File

@ -31,7 +31,6 @@
#include <emscripten/emscripten.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <SDL/SDL.h>
static EGLContext g_egl_ctx;
static EGLSurface g_egl_surf;
@ -220,15 +219,12 @@ static void gfx_ctx_input_driver(const input_driver_t **input, void **input_data
{
*input = NULL;
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE) != 0)
return;
void *rwebinput = input_rwebinput.init();
void *sdlinput = input_sdl.init();
if (sdlinput)
if (rwebinput)
{
*input = &input_sdl;
*input_data = sdlinput;
*input = &input_rwebinput;
*input_data = rwebinput;
}
}

View File

@ -513,6 +513,96 @@ const struct rarch_key_map rarch_key_map_dinput[] = {
};
#endif
#ifdef EMSCRIPTEN
const struct rarch_key_map rarch_key_map_rwebinput[] = {
{ 37, RETROK_LEFT },
{ 39, RETROK_RIGHT },
{ 38, RETROK_UP },
{ 40, RETROK_DOWN },
{ 13, RETROK_RETURN },
{ 9, RETROK_TAB },
{ 45, RETROK_INSERT },
{ 46, RETROK_DELETE },
{ 16, RETROK_RSHIFT },
{ 16, RETROK_LSHIFT },
{ 17, RETROK_LCTRL },
{ 35, RETROK_END },
{ 36, RETROK_HOME },
{ 34, RETROK_PAGEDOWN },
{ 33, RETROK_PAGEUP },
{ 18, RETROK_LALT },
{ 32, RETROK_SPACE },
{ 27, RETROK_ESCAPE },
{ 8, RETROK_BACKSPACE },
{ 13, RETROK_KP_ENTER },
{ 107, RETROK_KP_PLUS },
{ 109, RETROK_KP_MINUS },
{ 106, RETROK_KP_MULTIPLY },
{ 111, RETROK_KP_DIVIDE },
{ 192, RETROK_BACKQUOTE },
{ 19, RETROK_PAUSE },
{ 96, RETROK_KP0 },
{ 97, RETROK_KP1 },
{ 98, RETROK_KP2 },
{ 99, RETROK_KP3 },
{ 100, RETROK_KP4 },
{ 101, RETROK_KP5 },
{ 102, RETROK_KP6 },
{ 103, RETROK_KP7 },
{ 104, RETROK_KP8 },
{ 105, RETROK_KP9 },
{ 48, RETROK_0 },
{ 49, RETROK_1 },
{ 50, RETROK_2 },
{ 51, RETROK_3 },
{ 52, RETROK_4 },
{ 53, RETROK_5 },
{ 54, RETROK_6 },
{ 55, RETROK_7 },
{ 56, RETROK_8 },
{ 57, RETROK_9 },
{ 112, RETROK_F1 },
{ 113, RETROK_F2 },
{ 114, RETROK_F3 },
{ 115, RETROK_F4 },
{ 116, RETROK_F5 },
{ 117, RETROK_F6 },
{ 118, RETROK_F7 },
{ 119, RETROK_F8 },
{ 120, RETROK_F9 },
{ 121, RETROK_F10 },
{ 122, RETROK_F11 },
{ 123, RETROK_F12 },
{ 65, RETROK_a },
{ 66, RETROK_b },
{ 67, RETROK_c },
{ 68, RETROK_d },
{ 69, RETROK_e },
{ 70, RETROK_f },
{ 71, RETROK_g },
{ 72, RETROK_h },
{ 73, RETROK_i },
{ 74, RETROK_j },
{ 75, RETROK_k },
{ 76, RETROK_l },
{ 77, RETROK_m },
{ 78, RETROK_n },
{ 79, RETROK_o },
{ 80, RETROK_p },
{ 81, RETROK_q },
{ 82, RETROK_r },
{ 83, RETROK_s },
{ 84, RETROK_t },
{ 85, RETROK_u },
{ 86, RETROK_v },
{ 87, RETROK_w },
{ 88, RETROK_x },
{ 89, RETROK_y },
{ 90, RETROK_z },
{ 0, RETROK_UNKNOWN },
};
#endif
static enum retro_key rarch_keysym_lut[RETROK_LAST];
void input_init_keyboard_lut(const struct rarch_key_map *map)

View File

@ -105,6 +105,7 @@ struct rarch_key_map
extern const struct rarch_key_map rarch_key_map_x11[];
extern const struct rarch_key_map rarch_key_map_sdl[];
extern const struct rarch_key_map rarch_key_map_dinput[];
extern const struct rarch_key_map rarch_key_map_rwebinput[];
void input_init_keyboard_lut(const struct rarch_key_map *map);
enum retro_key input_translate_keysym_to_rk(unsigned sym);

149
input/rwebinput_input.c Normal file
View File

@ -0,0 +1,149 @@
/* RetroArch - A frontend for libretro.
* Copyright (C) 2010-2013 - Michael Lelli
*
* 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 "input_common.h"
#include "../driver.h"
#include "../boolean.h"
#include "../general.h"
#include "../emscripten/RWebInput.h"
static bool uninited = false;
typedef struct rwebinput_input
{
rwebinput_state_t state;
int context;
} rwebinput_input_t;
static void *rwebinput_input_init(void)
{
rwebinput_input_t *rwebinput = (rwebinput_input_t*)calloc(1, sizeof(*rwebinput));
if (!rwebinput)
return NULL;
rwebinput->context = RWebInputInit();
if (!rwebinput->context)
{
free(rwebinput);
return NULL;
}
input_init_keyboard_lut(rarch_key_map_rwebinput);
return rwebinput;
}
static bool rwebinput_key_pressed(rwebinput_input_t *rwebinput, int key)
{
if (key >= RETROK_LAST)
return false;
unsigned sym = input_translate_rk_to_keysym((enum retro_key)key);
bool ret = rwebinput->state.keys[sym >> 3] & (1 << (sym & 7));
return ret;
}
static bool rwebinput_is_pressed(rwebinput_input_t *rwebinput, const struct retro_keybind *binds, unsigned id)
{
if (id < RARCH_BIND_LIST_END)
{
const struct retro_keybind *bind = &binds[id];
return bind->valid && rwebinput_key_pressed(rwebinput, binds[id].key);
}
else
return false;
}
static bool rwebinput_bind_button_pressed(void *data, int key)
{
rwebinput_input_t *rwebinput = (rwebinput_input_t*)data;
return rwebinput_is_pressed(rwebinput, g_settings.input.binds[0], key);
}
static int16_t rwebinput_mouse_state(rwebinput_input_t *rwebinput, unsigned id)
{
switch (id)
{
case RETRO_DEVICE_ID_MOUSE_X:
return (int16_t) rwebinput->state.mouse_x;
case RETRO_DEVICE_ID_MOUSE_Y:
return (int16_t) rwebinput->state.mouse_y;
case RETRO_DEVICE_ID_MOUSE_LEFT:
return rwebinput->state.mouse_l;
case RETRO_DEVICE_ID_MOUSE_RIGHT:
return rwebinput->state.mouse_r;
default:
return 0;
}
}
static int16_t rwebinput_input_state(void *data, const struct retro_keybind **binds, unsigned port, unsigned device, unsigned index, unsigned id)
{
rwebinput_input_t *rwebinput = (rwebinput_input_t*)data;
switch (device)
{
case RETRO_DEVICE_JOYPAD:
return rwebinput_is_pressed(rwebinput, binds[port], id);
case RETRO_DEVICE_KEYBOARD:
return rwebinput_key_pressed(rwebinput, id);
case RETRO_DEVICE_MOUSE:
return rwebinput_mouse_state(rwebinput, id);
default:
return 0;
}
}
static void rwebinput_input_free(void *data)
{
rwebinput_input_t *rwebinput = (rwebinput_input_t*)data;
uninited = true;
RWebInputDestroy(rwebinput->context);
free(data);
}
static void rwebinput_input_poll(void *data)
{
rwebinput_input_t *rwebinput = (rwebinput_input_t*)data;
rwebinput_state_t *state = RWebInputPoll(rwebinput->context);
memcpy(&rwebinput->state, state, sizeof(rwebinput->state));
}
static void rwebinput_grab_mouse(void *data, bool state)
{
(void)data;
(void)state;
}
const input_driver_t input_rwebinput = {
rwebinput_input_init,
rwebinput_input_poll,
rwebinput_input_state,
rwebinput_bind_button_pressed,
rwebinput_input_free,
NULL,
"rwebinput",
rwebinput_grab_mouse,
};

View File

@ -139,6 +139,8 @@ const char *config_get_default_input(void)
return "apple_input";
case INPUT_QNX:
return "qnx_input";
case INPUT_RWEBINPUT:
return "rwebinput";
case INPUT_NULL:
return "null";
default: