diff --git a/Makefile.emscripten b/Makefile.emscripten
index 559638ab75..c1e913419c 100644
--- a/Makefile.emscripten
+++ b/Makefile.emscripten
@@ -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
diff --git a/emscripten/RWebAudio.c b/audio/rwebaudio.c
similarity index 98%
rename from emscripten/RWebAudio.c
rename to audio/rwebaudio.c
index 1040da32d7..7139a88de4 100644
--- a/emscripten/RWebAudio.c
+++ b/audio/rwebaudio.c
@@ -16,7 +16,7 @@
#include "../driver.h"
#include "../general.h"
-#include "RWebAudio.h"
+#include "../emscripten/RWebAudio.h"
static void ra_free(void *data)
{
diff --git a/config.def.h b/config.def.h
index 32d263a623..9e6903f4e4 100644
--- a/config.def.h
+++ b/config.def.h
@@ -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__)
diff --git a/driver.c b/driver.c
index 51e8e6a577..cc5ea7f253 100644
--- a/driver.c
+++ b/driver.c
@@ -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
diff --git a/driver.h b/driver.h
index 91dd004005..8bf5cc4f6b 100644
--- a/driver.h
+++ b/driver.h
@@ -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"
diff --git a/emscripten/RWebInput.h b/emscripten/RWebInput.h
new file mode 100644
index 0000000000..103cc7a0cd
--- /dev/null
+++ b/emscripten/RWebInput.h
@@ -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 .
+ */
+
+#include
+
+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);
diff --git a/emscripten/library_rwebinput.js b/emscripten/library_rwebinput.js
new file mode 100644
index 0000000000..3ca2fd9cd1
--- /dev/null
+++ b/emscripten/library_rwebinput.js
@@ -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);
diff --git a/gfx/context/emscriptenegl_ctx.c b/gfx/context/emscriptenegl_ctx.c
index 363152c358..f9b89a42ca 100644
--- a/gfx/context/emscriptenegl_ctx.c
+++ b/gfx/context/emscriptenegl_ctx.c
@@ -31,7 +31,6 @@
#include
#include
#include
-#include
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;
}
}
diff --git a/input/input_common.c b/input/input_common.c
index e58eede808..9993a99f13 100644
--- a/input/input_common.c
+++ b/input/input_common.c
@@ -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)
diff --git a/input/input_common.h b/input/input_common.h
index 2ce912e98a..64b6447062 100644
--- a/input/input_common.h
+++ b/input/input_common.h
@@ -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);
diff --git a/input/rwebinput_input.c b/input/rwebinput_input.c
new file mode 100644
index 0000000000..1a65eec7d3
--- /dev/null
+++ b/input/rwebinput_input.c
@@ -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 .
+ */
+
+#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,
+};
+
diff --git a/settings.c b/settings.c
index 682774941a..4e4331bc63 100644
--- a/settings.c
+++ b/settings.c
@@ -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: