Merge pull request #6106 from ToadKing/emscripten-fixes

Emscripten rewrites
This commit is contained in:
Twinaphex 2018-01-14 22:40:00 +01:00 committed by GitHub
commit 9b0b16e2c0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 898 additions and 378 deletions

View File

@ -554,6 +554,7 @@ endif
ifeq ($(HAVE_EMSCRIPTEN), 1)
OBJ += frontend/drivers/platform_emscripten.o \
input/drivers/rwebinput_input.o \
input/drivers_joypad/rwebpad_joypad.o \
audio/drivers/rwebaudio.o \
camera/drivers/rwebcam.o
endif

View File

@ -18,7 +18,7 @@ HAVE_RPNG = 1
HAVE_EMSCRIPTEN = 1
HAVE_RGUI = 1
HAVE_SDL = 0
HAVE_SDL2 = 1
HAVE_SDL2 = 0
HAVE_ZLIB = 1
WANT_ZLIB = 1
HAVE_STATIC_VIDEO_FILTERS = 1
@ -32,17 +32,12 @@ ifneq ($(NATIVE_ZLIB),)
WANT_ZLIB = 0
endif
ifeq ($(HAVE_SDL2), 1)
DEFINES += -DHAVE_SDL2
endif
#if you compile with SDL2 flag add this Emscripten flag "-s USE_SDL=2" to LDFLAGS:
LIBS := -s USE_SDL=2 -s USE_ZLIB=1
LDFLAGS := -L. --no-heap-copy -s USE_ZLIB=1 -s TOTAL_MEMORY=$(MEMORY) \
LIBS := -s USE_ZLIB=1
LDFLAGS := -L. --no-heap-copy -s USE_ZLIB=1 -s TOTAL_MEMORY=$(MEMORY) -s NO_EXIT_RUNTIME=0 \
-s EXPORTED_FUNCTIONS="['_main', '_malloc', '_cmd_savefiles', '_cmd_save_state', '_cmd_load_state', '_cmd_take_screenshot']" \
--js-library emscripten/library_rwebaudio.js \
--js-library emscripten/library_rwebinput.js \
--js-library emscripten/library_rwebcam.js
ifneq ($(PTHREAD), 0)
LDFLAGS += -s USE_PTHREADS=$(PTHREAD) -s PTHREAD_POOL_SIZE=2
@ -50,7 +45,12 @@ endif
ifeq ($(ASYNC), 1)
LDFLAGS += -s ASYNCIFY=$(ASYNC)
endif
endif
ifeq ($(HAVE_SDL2), 1)
LIBS += -s USE_SDL=2
DEFINES += -DHAVE_SDL2
endif
include Makefile.common

View File

@ -69,7 +69,7 @@ static const bool def_playlist_entry_rename = true;
static const unsigned int def_user_language = 0;
#if (defined(_WIN32) && !defined(_XBOX)) || (defined(__linux) && !defined(ANDROID) && !defined(HAVE_LAKKA)) || (defined(__MACH__) && !defined(IOS))
#if (defined(_WIN32) && !defined(_XBOX)) || (defined(__linux) && !defined(ANDROID) && !defined(HAVE_LAKKA)) || (defined(__MACH__) && !defined(IOS)) || defined(EMSCRIPTEN)
static const bool def_mouse_enable = true;
#else
static const bool def_mouse_enable = false;

View File

@ -1,143 +0,0 @@
//"use strict";
var LibraryRWebInput = {
$RI__deps: ['$Browser'],
$RI: {
temp: null,
contexts: [],
stateX: 0,
stateY: 0,
currentX: 0,
currentY: 0,
canvasEventHandler: function(event) {
switch (event.type) {
case 'mouseup':
case 'mousedown':
var value;
var offset;
if (event.button === 0) offset = 40;
else if (event.button === 2) offset = 41;
else break;
if (event.type === 'mouseup') value = 0;
else value = 1;
for (var i = 0; i < RI.contexts.length; i++) {
{{{ makeSetValue('RI.contexts[i].state', 'offset', 'value', 'i8') }}};
}
break;
}
},
eventHandler: function(event) {
var i;
switch (event.type) {
case 'mousemove':
var x = 0;
var y = 0;
var newX = event['clientX'] - Module.canvas.offsetLeft;
var newY = event['clientY'] - Module.canvas.offsetTop;
if (newX < 0) {
newX = 0;
x = -Module.canvas.offsetWidth;
} else if (newX > Module.canvas.offsetWidth) {
newX = Module.canvas.offsetWidth;
x = Module.canvas.offsetWidth;
} else {
x = newX - RI.currentX;
}
if (newY < 0) {
newY = 0;
y = -Module.canvas.offsetHeight;
} else if (newY > Module.canvas.offsetHeight) {
newY = Module.canvas.offsetHeight;
y = Module.canvas.offsetHeight;
} else {
y = newY - RI.currentY;
}
RI.currentX = newX;
RI.currentY = newY;
for (i = 0; i < RI.contexts.length; i++) {
{{{ makeSetValue('RI.contexts[i].state', '32', 'x', 'i32') }}};
{{{ makeSetValue('RI.contexts[i].state', '36', 'y', 'i32') }}};
}
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() {
if (RI.contexts.length === 0) {
document.addEventListener('keyup', RI.eventHandler, false);
document.addEventListener('keydown', RI.eventHandler, false);
document.addEventListener('mousemove', RI.eventHandler, false);
Module.canvas.addEventListener('mouseup', RI.canvasEventHandler, false);
Module.canvas.addEventListener('mousedown', RI.canvasEventHandler, 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);
Module.canvas.removeEventListener('mouseup', RI.canvasEventHandler, false);
Module.canvas.removeEventListener('mousedown', RI.canvasEventHandler, false);
document.removeEventListener('blur', RI.eventHandler, false);
document.removeEventListener('onvisbilitychange', RI.eventHandler, false);
}
}
}
};
autoAddDeps(LibraryRWebInput, '$RI');
mergeInto(LibraryManager.library, LibraryRWebInput);

View File

@ -16,6 +16,7 @@
*/
#include <emscripten/emscripten.h>
#include <emscripten/html5.h>
#include <string.h>
#include <file/config_file.h>
@ -56,7 +57,7 @@ static void emscripten_mainloop(void)
return;
main_exit(NULL);
exit(0);
emscripten_force_exit(0);
}
void cmd_savefiles(void)
@ -169,7 +170,8 @@ int main(int argc, char *argv[])
{
settings_t *settings = config_get_ptr();
emscripten_set_canvas_size(800, 600);
emscripten_set_canvas_element_size("#canvas", 800, 600);
emscripten_set_element_css_size("#canvas", 800.0, 600.0);
rarch_main(argc, argv, NULL);
emscripten_set_main_loop(emscripten_mainloop,
settings->bools.video_vsync ? 0 : INT_MAX, 1);

View File

@ -20,6 +20,7 @@
#include <unistd.h>
#include <emscripten/emscripten.h>
#include <emscripten/html5.h>
#ifdef HAVE_CONFIG_H
#include "../../config.h"
@ -44,6 +45,9 @@ typedef struct
unsigned fb_height;
} emscripten_ctx_data_t;
static int emscripten_initial_width;
static int emscripten_initial_height;
static void gfx_ctx_emscripten_swap_interval(void *data, unsigned interval)
{
(void)data;
@ -51,23 +55,82 @@ static void gfx_ctx_emscripten_swap_interval(void *data, unsigned interval)
(void)interval;
}
static void gfx_ctx_emscripten_get_canvas_size(int *width, int *height)
{
EMSCRIPTEN_RESULT r;
EmscriptenFullscreenChangeEvent fullscreen_status;
bool is_fullscreen = false;
r = emscripten_get_fullscreen_status(&fullscreen_status);
if (r == EMSCRIPTEN_RESULT_SUCCESS)
{
if (fullscreen_status.isFullscreen)
{
is_fullscreen = true;
*width = fullscreen_status.screenWidth;
*height = fullscreen_status.screenHeight;
}
}
if (!is_fullscreen)
{
r = emscripten_get_canvas_element_size("#canvas", width, height);
if (r != EMSCRIPTEN_RESULT_SUCCESS)
{
RARCH_ERR("[EMSCRIPTEN/EGL]: Could not get screen dimensions: %d\n",
r);
*width = 800;
*height = 600;
}
}
}
static void gfx_ctx_emscripten_check_window(void *data, bool *quit,
bool *resize, unsigned *width, unsigned *height, bool is_shutdown)
{
EMSCRIPTEN_RESULT r;
int input_width;
int input_height;
int is_fullscreen;
emscripten_ctx_data_t *emscripten = (emscripten_ctx_data_t*)data;
(void)data;
gfx_ctx_emscripten_get_canvas_size(&input_width, &input_height);
if (input_width == 0 || input_height == 0)
{
input_width = emscripten_initial_width;
input_height = emscripten_initial_height;
emscripten->fb_width = emscripten->fb_height = 0;
}
emscripten_get_canvas_size(&input_width, &input_height, &is_fullscreen);
*width = (unsigned)input_width;
*height = (unsigned)input_height;
*resize = false;
if (*width != emscripten->fb_width || *height != emscripten->fb_height)
if (input_width != emscripten->fb_width ||
input_height != emscripten->fb_height)
{
r = emscripten_set_canvas_element_size("#canvas",
input_width, input_height);
if (r != EMSCRIPTEN_RESULT_SUCCESS)
{
RARCH_ERR("[EMSCRIPTEN/EGL]: error resizing canvas: %d\n", r);
}
/* fix Module.requestFullscreen messing with the canvas size */
r = emscripten_set_element_css_size("#canvas",
(double)input_width, (double)input_height);
if (r != EMSCRIPTEN_RESULT_SUCCESS)
{
RARCH_ERR("[EMSCRIPTEN/EGL]: error resizing canvas css: %d\n", r);
}
*resize = true;
emscripten_reinit_video = true;
}
emscripten->fb_width = (unsigned)input_width;
emscripten->fb_height = (unsigned)input_height;
@ -98,7 +161,8 @@ static void gfx_ctx_emscripten_destroy(void *data)
free(data);
}
static void *gfx_ctx_emscripten_init(video_frame_info_t *video_info, void *video_driver)
static void *gfx_ctx_emscripten_init(video_frame_info_t *video_info,
void *video_driver)
{
#ifdef HAVE_EGL
unsigned width, height;
@ -128,6 +192,10 @@ static void *gfx_ctx_emscripten_init(video_frame_info_t *video_info, void *video
(void)video_driver;
if (emscripten_initial_width == 0 || emscripten_initial_height == 0)
emscripten_get_canvas_element_size("#canvas",
&emscripten_initial_width, &emscripten_initial_height);
#ifdef HAVE_EGL
if (g_egl_inited)
{
@ -135,8 +203,8 @@ static void *gfx_ctx_emscripten_init(video_frame_info_t *video_info, void *video
return (void*)"emscripten";
}
if (!egl_init_context(&emscripten->egl, EGL_NONE, EGL_DEFAULT_DISPLAY,
&major, &minor, &n, attribute_list))
if (!egl_init_context(&emscripten->egl, EGL_NONE,
(void *)EGL_DEFAULT_DISPLAY, &major, &minor, &n, attribute_list))
{
egl_report_error();
goto error;
@ -202,20 +270,10 @@ static void gfx_ctx_emscripten_input_driver(void *data,
const char *name,
const input_driver_t **input, void **input_data)
{
void *rwebinput = NULL;
void *rwebinput = input_rwebinput.init(name);
*input = NULL;
*input_data = NULL;
#ifndef HAVE_SDL2
rwebinput = input_rwebinput.init();
if (!rwebinput)
return;
*input = &input_rwebinput;
*input = rwebinput ? &input_rwebinput : NULL;
*input_data = rwebinput;
#endif
}
static bool gfx_ctx_emscripten_has_focus(void *data)

View File

@ -548,6 +548,7 @@ INPUT
#include "../input/drivers_joypad/qnx_joypad.c"
#elif defined(EMSCRIPTEN)
#include "../input/drivers/rwebinput_input.c"
#include "../input/drivers_joypad/rwebpad_joypad.c"
#elif defined(DJGPP)
#include "../input/drivers/dos_input.c"
#include "../input/drivers_joypad/dos_joypad.c"

View File

@ -1,5 +1,5 @@
/* RetroArch - A frontend for libretro.
* Copyright (C) 2010-2015 - Michael Lelli
* Copyright (C) 2010-2018 - Michael Lelli
* Copyright (C) 2011-2017 - Daniel De Matteis
*
* RetroArch is free software: you can redistribute it and/or modify it under the terms
@ -19,107 +19,487 @@
#include <string.h>
#include <boolean.h>
#include <retro_assert.h>
#include <retro_miscellaneous.h>
#include <encodings/crc32.h>
#include <encodings/utf.h>
#include <emscripten/html5.h>
#include "../input_driver.h"
#include "../input_keymaps.h"
#include "../../tasks/tasks_internal.h"
#include "../../configuration.h"
#include "../../verbosity.h"
typedef struct rwebinput_state
/* https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/button */
#define RWEBINPUT_MOUSE_BTNL 0
#define RWEBINPUT_MOUSE_BTNM 1
#define RWEBINPUT_MOUSE_BTNR 2
#define RWEBINPUT_MOUSE_BTN4 3
#define RWEBINPUT_MOUSE_BTN5 4
typedef struct rwebinput_key_to_code_map_entry
{
uint8_t keys[32];
int mouse_x;
int mouse_y;
char mouse_l;
char mouse_r;
bool blocked;
} rwebinput_state_t;
const char *key;
enum retro_key rk;
} rwebinput_key_to_code_map_entry_t;
int RWebInputInit(void);
rwebinput_state_t *RWebInputPoll(int context);
void RWebInputDestroy(int context);
typedef struct rwebinput_keyboard_event
{
int type;
EmscriptenKeyboardEvent event;
} rwebinput_keyboard_event_t;
typedef struct rwebinput_keyboard_event_queue
{
size_t count;
size_t max_size;
rwebinput_keyboard_event_t *events;
} rwebinput_keyboard_event_queue_t;
typedef struct rwebinput_mouse_states
{
signed x;
signed y;
signed delta_x;
signed delta_y;
uint8_t buttons;
double scroll_x;
double scroll_y;
} rwebinput_mouse_state_t;
typedef struct rwebinput_input
{
rwebinput_state_t state;
int context;
bool keys[RETROK_LAST];
rwebinput_mouse_state_t mouse;
const input_device_driver_t *joypad;
bool blocked;
} rwebinput_input_t;
/* KeyboardEvent.keyCode has been deprecated for a while and doesn't have
* separate left/right modifer codes, so we have to map string labels from
* KeyboardEvent.code to retro keys */
static const rwebinput_key_to_code_map_entry_t rwebinput_key_to_code_map[] =
{
{ "KeyA", RETROK_a },
{ "KeyB", RETROK_b },
{ "KeyC", RETROK_c },
{ "KeyD", RETROK_d },
{ "KeyE", RETROK_e },
{ "KeyF", RETROK_f },
{ "KeyG", RETROK_g },
{ "KeyH", RETROK_h },
{ "KeyI", RETROK_i },
{ "KeyJ", RETROK_j },
{ "KeyK", RETROK_k },
{ "KeyL", RETROK_l },
{ "KeyM", RETROK_m },
{ "KeyN", RETROK_n },
{ "KeyO", RETROK_o },
{ "KeyP", RETROK_p },
{ "KeyQ", RETROK_q },
{ "KeyR", RETROK_r },
{ "KeyS", RETROK_s },
{ "KeyT", RETROK_t },
{ "KeyU", RETROK_u },
{ "KeyV", RETROK_v },
{ "KeyW", RETROK_w },
{ "KeyX", RETROK_x },
{ "KeyY", RETROK_y },
{ "KeyZ", RETROK_z },
{ "ArrowLeft", RETROK_LEFT },
{ "ArrowRight", RETROK_RIGHT },
{ "ArrowUp", RETROK_UP },
{ "ArrowDown", RETROK_DOWN },
{ "Enter", RETROK_RETURN },
{ "NumpadEnter", RETROK_KP_ENTER },
{ "Tab", RETROK_TAB },
{ "Insert", RETROK_INSERT },
{ "Delete", RETROK_DELETE },
{ "End", RETROK_END },
{ "Home", RETROK_HOME },
{ "ShiftRight", RETROK_RSHIFT },
{ "ShiftLeft", RETROK_LSHIFT },
{ "ControlLeft", RETROK_LCTRL },
{ "AltLeft", RETROK_LALT },
{ "Space", RETROK_SPACE },
{ "Escape", RETROK_ESCAPE },
{ "NumpadAdd", RETROK_KP_PLUS },
{ "NumpadSubtract", RETROK_KP_MINUS },
{ "F1", RETROK_F1 },
{ "F2", RETROK_F2 },
{ "F3", RETROK_F3 },
{ "F4", RETROK_F4 },
{ "F5", RETROK_F5 },
{ "F6", RETROK_F6 },
{ "F7", RETROK_F7 },
{ "F8", RETROK_F8 },
{ "F9", RETROK_F9 },
{ "F10", RETROK_F10 },
{ "F11", RETROK_F11 },
{ "F12", RETROK_F12 },
{ "Digit0", RETROK_0 },
{ "Digit1", RETROK_1 },
{ "Digit2", RETROK_2 },
{ "Digit3", RETROK_3 },
{ "Digit4", RETROK_4 },
{ "Digit5", RETROK_5 },
{ "Digit6", RETROK_6 },
{ "Digit7", RETROK_7 },
{ "Digit8", RETROK_8 },
{ "Digit9", RETROK_9 },
{ "PageUp", RETROK_PAGEUP },
{ "PageDown", RETROK_PAGEDOWN },
{ "Numpad0", RETROK_KP0 },
{ "Numpad1", RETROK_KP1 },
{ "Numpad2", RETROK_KP2 },
{ "Numpad3", RETROK_KP3 },
{ "Numpad4", RETROK_KP4 },
{ "Numpad5", RETROK_KP5 },
{ "Numpad6", RETROK_KP6 },
{ "Numpad7", RETROK_KP7 },
{ "Numpad8", RETROK_KP8 },
{ "Numpad9", RETROK_KP9 },
{ "Period", RETROK_PERIOD },
{ "CapsLock", RETROK_CAPSLOCK },
{ "NumLock", RETROK_NUMLOCK },
{ "Backspace", RETROK_BACKSPACE },
{ "NumpadMultiply", RETROK_KP_MULTIPLY },
{ "NumpadDivide", RETROK_KP_DIVIDE },
{ "PrintScreen", RETROK_PRINT },
{ "ScrollLock", RETROK_SCROLLOCK },
{ "Backquote", RETROK_BACKQUOTE },
{ "Pause", RETROK_PAUSE },
{ "Quote", RETROK_QUOTE },
{ "Comma", RETROK_COMMA },
{ "Minus", RETROK_MINUS },
{ "Slash", RETROK_SLASH },
{ "Semicolon", RETROK_SEMICOLON },
{ "Equal", RETROK_EQUALS },
{ "BracketLeft", RETROK_LEFTBRACKET },
{ "Backslash", RETROK_BACKSLASH },
{ "BracketRight", RETROK_RIGHTBRACKET },
{ "NumpadDecimal", RETROK_KP_PERIOD },
{ "NumpadEqual", RETROK_KP_EQUALS },
{ "ControlRight", RETROK_RCTRL },
{ "AltRight", RETROK_RALT },
{ "F13", RETROK_F13 },
{ "F14", RETROK_F14 },
{ "F15", RETROK_F15 },
{ "MetaRight", RETROK_RMETA },
{ "MetaLeft", RETROK_LMETA },
{ "Help", RETROK_HELP },
{ "ContextMenu", RETROK_MENU },
{ "Power", RETROK_POWER },
};
static bool g_rwebinput_initialized;
static rwebinput_keyboard_event_queue_t *g_rwebinput_keyboard;
static rwebinput_mouse_state_t *g_rwebinput_mouse;
/* to make the string labels for codes from JavaScript work, we convert them
* to CRC32 hashes for the LUT */
static void rwebinput_generate_lut(void)
{
int i;
struct rarch_key_map *key_map;
retro_assert(ARRAY_SIZE(rarch_key_map_rwebinput) ==
ARRAY_SIZE(rwebinput_key_to_code_map) + 1);
for (i = 0; i < ARRAY_SIZE(rwebinput_key_to_code_map); i++)
{
int j;
uint32_t crc;
const rwebinput_key_to_code_map_entry_t *key_to_code =
&rwebinput_key_to_code_map[i];
key_map = &rarch_key_map_rwebinput[i];
crc = encoding_crc32(0, (const uint8_t *)key_to_code->key,
strlen(key_to_code->key));
/* sanity check: make sure there's no collisions */
for (j = 0; j < i; j++)
{
retro_assert(rarch_key_map_rwebinput[j].sym != crc);
}
key_map->rk = key_to_code->rk;
key_map->sym = crc;
}
/* set terminating entry */
key_map = &rarch_key_map_rwebinput[ARRAY_SIZE(rarch_key_map_rwebinput) - 1];
key_map->rk = RETROK_UNKNOWN;
key_map->sym = 0;
}
static EM_BOOL rwebinput_keyboard_cb(int event_type,
const EmscriptenKeyboardEvent *key_event, void *user_data)
{
if (event_type == EMSCRIPTEN_EVENT_KEYPRESS)
return EM_TRUE;
if (g_rwebinput_keyboard->count >= g_rwebinput_keyboard->max_size)
{
size_t new_max = MAX(1, g_rwebinput_keyboard->max_size << 1);
g_rwebinput_keyboard->events = realloc(g_rwebinput_keyboard->events,
new_max * sizeof(g_rwebinput_keyboard->events[0]));
retro_assert(g_rwebinput_keyboard->events != NULL);
g_rwebinput_keyboard->max_size = new_max;
}
g_rwebinput_keyboard->events[g_rwebinput_keyboard->count].type = event_type;
memcpy(&g_rwebinput_keyboard->events[g_rwebinput_keyboard->count].event,
key_event, sizeof(*key_event));
g_rwebinput_keyboard->count++;
return EM_TRUE;
}
static EM_BOOL rwebinput_mouse_cb(int event_type,
const EmscriptenMouseEvent *mouse_event, void *user_data)
{
(void)user_data;
uint8_t mask = 1 << mouse_event->button;
g_rwebinput_mouse->x = mouse_event->canvasX;
g_rwebinput_mouse->y = mouse_event->canvasY;
g_rwebinput_mouse->delta_x += mouse_event->movementX;
g_rwebinput_mouse->delta_y += mouse_event->movementY;
if (event_type == EMSCRIPTEN_EVENT_MOUSEDOWN)
{
g_rwebinput_mouse->buttons |= mask;
}
else if (event_type == EMSCRIPTEN_EVENT_MOUSEUP)
{
g_rwebinput_mouse->buttons &= ~mask;
}
return EM_TRUE;
}
static EM_BOOL rwebinput_wheel_cb(int event_type,
const EmscriptenWheelEvent *wheel_event, void *user_data)
{
(void)event_type;
(void)user_data;
g_rwebinput_mouse->scroll_x += wheel_event->deltaX;
g_rwebinput_mouse->scroll_y += wheel_event->deltaY;
return EM_TRUE;
}
static void *rwebinput_input_init(const char *joypad_driver)
{
rwebinput_input_t *rwebinput = (rwebinput_input_t*)calloc(1, sizeof(*rwebinput));
if (!rwebinput)
rwebinput_input_t *rwebinput =
(rwebinput_input_t*)calloc(1, sizeof(*rwebinput));
g_rwebinput_keyboard = (rwebinput_keyboard_event_queue_t*)
calloc(1, sizeof(rwebinput_keyboard_event_queue_t));
g_rwebinput_mouse = (rwebinput_mouse_state_t*)
calloc(1, sizeof(rwebinput_mouse_state_t));
if (!rwebinput || !g_rwebinput_keyboard || !g_rwebinput_mouse)
goto error;
rwebinput->context = RWebInputInit();
if (!rwebinput->context)
goto error;
if (!g_rwebinput_initialized)
{
EMSCRIPTEN_RESULT r;
g_rwebinput_initialized = true;
rwebinput_generate_lut();
/* emscripten currently doesn't have an API to remove handlers, so make
* once and reuse it */
r = emscripten_set_keydown_callback("#document", NULL, false,
rwebinput_keyboard_cb);
if (r != EMSCRIPTEN_RESULT_SUCCESS)
{
RARCH_ERR(
"[EMSCRIPTEN/INPUT] failed to create keydown callback: %d\n", r);
}
r = emscripten_set_keyup_callback("#document", NULL, false,
rwebinput_keyboard_cb);
if (r != EMSCRIPTEN_RESULT_SUCCESS)
{
RARCH_ERR(
"[EMSCRIPTEN/INPUT] failed to create keydown callback: %d\n", r);
}
r = emscripten_set_keypress_callback("#document", NULL, false,
rwebinput_keyboard_cb);
if (r != EMSCRIPTEN_RESULT_SUCCESS)
{
RARCH_ERR(
"[EMSCRIPTEN/INPUT] failed to create keypress callback: %d\n", r);
}
r = emscripten_set_mousedown_callback("#canvas", NULL, false,
rwebinput_mouse_cb);
if (r != EMSCRIPTEN_RESULT_SUCCESS)
{
RARCH_ERR(
"[EMSCRIPTEN/INPUT] failed to create mousedown callback: %d\n", r);
}
r = emscripten_set_mouseup_callback("#canvas", NULL, false,
rwebinput_mouse_cb);
if (r != EMSCRIPTEN_RESULT_SUCCESS)
{
RARCH_ERR(
"[EMSCRIPTEN/INPUT] failed to create mouseup callback: %d\n", r);
}
r = emscripten_set_mousemove_callback("#canvas", NULL, false,
rwebinput_mouse_cb);
if (r != EMSCRIPTEN_RESULT_SUCCESS)
{
RARCH_ERR(
"[EMSCRIPTEN/INPUT] failed to create mousemove callback: %d\n", r);
}
r = emscripten_set_wheel_callback("#document", NULL, false,
rwebinput_wheel_cb);
if (r != EMSCRIPTEN_RESULT_SUCCESS)
{
RARCH_ERR(
"[EMSCRIPTEN/INPUT] failed to create wheel callback: %d\n", r);
}
}
input_keymaps_init_keyboard_lut(rarch_key_map_rwebinput);
rwebinput->joypad = input_joypad_init_driver(joypad_driver, rwebinput);
return rwebinput;
error:
if (rwebinput)
free(rwebinput);
free(g_rwebinput_keyboard);
free(g_rwebinput_mouse);
free(rwebinput);
return NULL;
}
static bool rwebinput_key_pressed_internal(void *data, int key)
static bool rwebinput_key_pressed(rwebinput_input_t *rwebinput, int key)
{
unsigned sym;
bool ret;
rwebinput_input_t *rwebinput = (rwebinput_input_t*)data;
if (key >= RETROK_LAST)
return false;
sym = rarch_keysym_lut[(enum retro_key)key];
ret = rwebinput->state.keys[sym >> 3] & (1 << (sym & 7));
return ret;
return rwebinput->keys[key];
}
static bool rwebinput_is_pressed(rwebinput_input_t *rwebinput,
const struct retro_keybind *binds, unsigned id)
static int16_t rwebinput_pointer_device_state(rwebinput_mouse_state_t *mouse,
unsigned id, bool screen)
{
if (id < RARCH_BIND_LIST_END)
struct video_viewport vp;
bool inside = false;
int16_t res_x = 0;
int16_t res_y = 0;
int16_t res_screen_x = 0;
int16_t res_screen_y = 0;
vp.x = 0;
vp.y = 0;
vp.width = 0;
vp.height = 0;
vp.full_width = 0;
vp.full_height = 0;
if (!(video_driver_translate_coord_viewport_wrap(&vp, mouse->x, mouse->x,
&res_x, &res_y, &res_screen_x, &res_screen_y)))
return 0;
if (screen)
{
const struct retro_keybind *bind = &binds[id];
int key = binds[id].key;
return bind->valid && (key < RETROK_LAST)
&& rwebinput_key_pressed_internal(rwebinput, key);
res_x = res_screen_x;
res_y = res_screen_y;
}
return false;
}
inside = (res_x >= -0x7fff) && (res_y >= -0x7fff);
static bool rwebinput_key_pressed(void *data, int key)
{
rwebinput_input_t *rwebinput = (rwebinput_input_t*)data;
return rwebinput_is_pressed(rwebinput, input_config_binds[0], key);
}
if (!inside)
return 0;
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;
case RETRO_DEVICE_ID_POINTER_X:
return res_x;
case RETRO_DEVICE_ID_POINTER_Y:
return res_y;
case RETRO_DEVICE_ID_POINTER_PRESSED:
return !!(mouse->buttons & (1 << RWEBINPUT_MOUSE_BTNL));
}
return 0;
}
static int16_t rwebinput_mouse_state(rwebinput_mouse_state_t *mouse,
unsigned id, bool screen)
{
switch (id)
{
case RETRO_DEVICE_ID_MOUSE_X:
return (int16_t)(screen ? mouse->x : mouse->delta_x);
case RETRO_DEVICE_ID_MOUSE_Y:
return (int16_t)(screen ? mouse->y : mouse->delta_y);
case RETRO_DEVICE_ID_MOUSE_LEFT:
return !!(mouse->buttons & (1 << RWEBINPUT_MOUSE_BTNL));
case RETRO_DEVICE_ID_MOUSE_RIGHT:
return !!(mouse->buttons & (1 << RWEBINPUT_MOUSE_BTNR));
case RETRO_DEVICE_ID_MOUSE_MIDDLE:
return !!(mouse->buttons & (1 << RWEBINPUT_MOUSE_BTNM));
case RETRO_DEVICE_ID_MOUSE_BUTTON_4:
return !!(mouse->buttons & (1 << RWEBINPUT_MOUSE_BTN4));
case RETRO_DEVICE_ID_MOUSE_BUTTON_5:
return !!(mouse->buttons & (1 << RWEBINPUT_MOUSE_BTN5));
case RETRO_DEVICE_ID_MOUSE_WHEELUP:
return mouse->scroll_y < 0.0;
case RETRO_DEVICE_ID_MOUSE_WHEELDOWN:
return mouse->scroll_y > 0.0;
case RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELUP:
return mouse->scroll_x < 0.0;
case RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELDOWN:
return mouse->scroll_x > 0.0;
}
return 0;
}
static bool rwebinput_is_pressed(rwebinput_input_t *rwebinput,
rarch_joypad_info_t joypad_info, const struct retro_keybind *binds,
unsigned port, unsigned id)
{
if (id < RARCH_BIND_LIST_END)
{
const struct retro_keybind *bind = &binds[id];
int key = bind->key;
if (!rwebinput->blocked && (bind->key < RETROK_LAST) &&
rwebinput_key_pressed(rwebinput, key))
return true;
if (bind->valid)
{
if (port == 0 && !!rwebinput_mouse_state(&rwebinput->mouse,
bind->mbutton, false))
return true;
if (input_joypad_pressed(rwebinput->joypad, joypad_info, port, binds,
id))
return true;
}
}
return false;
}
static int16_t rwebinput_analog_pressed(rwebinput_input_t *rwebinput,
const struct retro_keybind *binds, unsigned idx, unsigned id)
rarch_joypad_info_t joypad_info, const struct retro_keybind *binds,
unsigned idx, unsigned id)
{
int16_t pressed_minus = 0, pressed_plus = 0;
unsigned id_minus = 0;
@ -127,9 +507,9 @@ static int16_t rwebinput_analog_pressed(rwebinput_input_t *rwebinput,
input_conv_analog_id_to_bind_id(idx, id, &id_minus, &id_plus);
if (rwebinput_is_pressed(rwebinput, binds, id_minus))
if (rwebinput_is_pressed(rwebinput, joypad_info, binds, idx, id_minus))
pressed_minus = -0x7fff;
if (rwebinput_is_pressed(rwebinput, binds, id_plus))
if (rwebinput_is_pressed(rwebinput, joypad_info, binds, idx, id_plus))
pressed_plus = 0x7fff;
return pressed_plus + pressed_minus;
@ -140,18 +520,33 @@ static int16_t rwebinput_input_state(void *data,
const struct retro_keybind **binds,
unsigned port, unsigned device, unsigned idx, unsigned id)
{
int16_t ret;
rwebinput_input_t *rwebinput = (rwebinput_input_t*)data;
switch (device)
{
case RETRO_DEVICE_JOYPAD:
return rwebinput_is_pressed(rwebinput, binds[port], id);
if (id < RARCH_BIND_LIST_END)
return rwebinput_is_pressed(rwebinput, joypad_info, binds[port],
port, id);
break;
case RETRO_DEVICE_ANALOG:
return rwebinput_analog_pressed(rwebinput, binds[port], idx, id);
ret = rwebinput_analog_pressed(rwebinput, joypad_info, binds[port],
idx, id);
if (!ret && binds[port])
ret = input_joypad_analog(rwebinput->joypad, joypad_info, port,
idx, id, binds[port]);
return ret;
case RETRO_DEVICE_KEYBOARD:
return rwebinput_key_pressed(rwebinput, id);
case RETRO_DEVICE_MOUSE:
return rwebinput_mouse_state(rwebinput, id);
return rwebinput_mouse_state(&rwebinput->mouse, id, false);
case RARCH_DEVICE_MOUSE_SCREEN:
return rwebinput_mouse_state(&rwebinput->mouse, id, true);
case RETRO_DEVICE_POINTER:
return rwebinput_pointer_device_state(&rwebinput->mouse, id, false);
case RARCH_DEVICE_POINTER_SCREEN:
return rwebinput_pointer_device_state(&rwebinput->mouse, id, true);
}
return 0;
@ -161,47 +556,88 @@ static void rwebinput_input_free(void *data)
{
rwebinput_input_t *rwebinput = (rwebinput_input_t*)data;
if (!rwebinput)
return;
RWebInputDestroy(rwebinput->context);
if (g_rwebinput_keyboard)
free(g_rwebinput_keyboard->events);
free(g_rwebinput_keyboard);
g_rwebinput_keyboard = NULL;
free(g_rwebinput_mouse);
g_rwebinput_mouse = NULL;
free(rwebinput);
}
static void rwebinput_process_keyboard_events(rwebinput_input_t *rwebinput,
rwebinput_keyboard_event_t *event)
{
uint32_t crc;
uint32_t keycode;
unsigned translated_keycode;
uint32_t character = 0;
uint16_t mod = 0;
const EmscriptenKeyboardEvent *key_event = &event->event;
bool keydown = event->type == EMSCRIPTEN_EVENT_KEYDOWN;
/* a printable key: populate character field */
if (utf8len(key_event->key) == 1)
{
const char *key_ptr = &key_event->key[0];
character = utf8_walk(&key_ptr);
}
if (key_event->ctrlKey)
mod |= RETROKMOD_CTRL;
if (key_event->altKey)
mod |= RETROKMOD_ALT;
if (key_event->shiftKey)
mod |= RETROKMOD_SHIFT;
if (key_event->metaKey)
mod |= RETROKMOD_META;
keycode = encoding_crc32(0, (const uint8_t *)key_event->code,
strnlen(key_event->code, sizeof(key_event->code)));
translated_keycode = input_keymaps_translate_keysym_to_rk(keycode);
if (translated_keycode == RETROK_BACKSPACE)
character = '\b';
else if (translated_keycode == RETROK_RETURN ||
translated_keycode == RETROK_KP_ENTER)
character = '\n';
else if (translated_keycode == RETROK_TAB)
character = '\t';
input_keyboard_event(keydown, translated_keycode, character, mod,
RETRO_DEVICE_KEYBOARD);
if (translated_keycode < RETROK_LAST)
{
rwebinput->keys[translated_keycode] = keydown;
}
}
static void rwebinput_input_poll(void *data)
{
unsigned i;
size_t i;
rwebinput_input_t *rwebinput = (rwebinput_input_t*)data;
rwebinput_state_t *state = RWebInputPoll(rwebinput->context);
/* Get new keys. */
for (i = 0; i < 32; i++)
{
unsigned k;
uint8_t diff;
for (i = 0; i < g_rwebinput_keyboard->count; i++)
rwebinput_process_keyboard_events(rwebinput,
&g_rwebinput_keyboard->events[i]);
g_rwebinput_keyboard->count = 0;
if (state->keys[i] == rwebinput->state.keys[i])
continue;
memcpy(&rwebinput->mouse, g_rwebinput_mouse, sizeof(*g_rwebinput_mouse));
g_rwebinput_mouse->delta_x = g_rwebinput_mouse->delta_y = 0;
g_rwebinput_mouse->scroll_x = g_rwebinput_mouse->scroll_y = 0.0;
diff = state->keys[i] ^ rwebinput->state.keys[i];
for (k = 0; diff; diff >>= 1, k++)
{
if (diff & 1)
input_keyboard_event((state->keys[i] & (1 << k)) != 0,
input_keymaps_translate_keysym_to_rk(i * 8 + k), 0, 0,
RETRO_DEVICE_KEYBOARD);
}
}
memcpy(&rwebinput->state, state, sizeof(rwebinput->state));
if (rwebinput->joypad)
rwebinput->joypad->poll();
}
static void rwebinput_grab_mouse(void *data, bool state)
{
(void)data;
(void)state;
if (state)
emscripten_request_pointerlock("#canvas", EM_TRUE);
else
emscripten_exit_pointerlock();
}
static bool rwebinput_set_rumble(void *data, unsigned port,
@ -215,6 +651,14 @@ static bool rwebinput_set_rumble(void *data, unsigned port,
return false;
}
static const input_device_driver_t *rwebinput_get_joypad_driver(void *data)
{
rwebinput_input_t *rwebinput = (rwebinput_input_t*)data;
if (!rwebinput)
return NULL;
return rwebinput->joypad;
}
static uint64_t rwebinput_get_capabilities(void *data)
{
uint64_t caps = 0;
@ -223,6 +667,7 @@ static uint64_t rwebinput_get_capabilities(void *data)
caps |= (1 << RETRO_DEVICE_ANALOG);
caps |= (1 << RETRO_DEVICE_KEYBOARD);
caps |= (1 << RETRO_DEVICE_MOUSE);
caps |= (1 << RETRO_DEVICE_POINTER);
return caps;
}
@ -232,7 +677,7 @@ static bool rwebinput_keyboard_mapping_is_blocked(void *data)
rwebinput_input_t *rwebinput = (rwebinput_input_t*)data;
if (!rwebinput)
return false;
return rwebinput->state.blocked;
return rwebinput->blocked;
}
static void rwebinput_keyboard_mapping_set_block(void *data, bool value)
@ -240,7 +685,7 @@ static void rwebinput_keyboard_mapping_set_block(void *data, bool value)
rwebinput_input_t *rwebinput = (rwebinput_input_t*)data;
if (!rwebinput)
return;
rwebinput->state.blocked = value;
rwebinput->blocked = value;
}
input_driver_t input_rwebinput = {
@ -255,7 +700,7 @@ input_driver_t input_rwebinput = {
rwebinput_grab_mouse,
NULL,
rwebinput_set_rumble,
NULL,
rwebinput_get_joypad_driver,
NULL,
rwebinput_keyboard_mapping_is_blocked,
rwebinput_keyboard_mapping_set_block,

View File

@ -0,0 +1,219 @@
/* RetroArch - A frontend for libretro.
* Copyright (C) 2018 - 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 <stdint.h>
#include <stddef.h>
#include <boolean.h>
#include <retro_miscellaneous.h>
#include <emscripten/html5.h>
#include "../input_driver.h"
#include "../../tasks/tasks_internal.h"
#include "../../verbosity.h"
#define CLAMPDOUBLE(x) MIN(1.0, MAX(-1.0, (x)))
static bool g_rwebpad_initialized;
static EM_BOOL rwebpad_gamepad_cb(int event_type,
const EmscriptenGamepadEvent *gamepad_event, void *user_data)
{
unsigned vid = 0;
unsigned pid = 0;
(void)event_type;
(void)gamepad_event;
(void)user_data;
if (strncmp(gamepad_event->mapping, "standard",
sizeof(gamepad_event->mapping)) == 0)
{
/* give a dummy vid/pid for automapping */
vid = 1;
pid = 1;
}
if (event_type == EMSCRIPTEN_EVENT_GAMEPADCONNECTED)
{
if(!input_autoconfigure_connect(
gamepad_event->id, /* name */
NULL, /* display name */
rwebpad_joypad.ident, /* driver */
gamepad_event->index, /* idx */
vid, /* vid */
pid)) /* pid */
input_config_set_device_name(gamepad_event->index,
gamepad_event->id);
}
else if (event_type == EMSCRIPTEN_EVENT_GAMEPADDISCONNECTED)
{
input_autoconfigure_disconnect(gamepad_event->index,
rwebpad_joypad.ident);
}
return EM_TRUE;
}
static bool rwebpad_joypad_init(void *data)
{
int supported = emscripten_get_num_gamepads();
(void)data;
if (supported == EMSCRIPTEN_RESULT_NOT_SUPPORTED)
return false;
if (!g_rwebpad_initialized)
{
EMSCRIPTEN_RESULT r;
g_rwebpad_initialized = true;
/* callbacks needs to be registered for gamepads to connect */
r = emscripten_set_gamepadconnected_callback(NULL, false,
rwebpad_gamepad_cb);
if (r != EMSCRIPTEN_RESULT_SUCCESS)
{
RARCH_ERR(
"[EMSCRIPTEN/PAD] failed to create connect callback: %d\n", r);
}
r = emscripten_set_gamepaddisconnected_callback(NULL, false,
rwebpad_gamepad_cb);
if (r != EMSCRIPTEN_RESULT_SUCCESS)
{
RARCH_ERR(
"[EMSCRIPTEN/PAD] failed to create disconnect callback: %d\n", r);
}
}
return true;
}
static const char *rwebpad_joypad_name(unsigned pad)
{
static EmscriptenGamepadEvent gamepad_state;
EMSCRIPTEN_RESULT r;
r = emscripten_get_gamepad_status(pad, &gamepad_state);
if (r == EMSCRIPTEN_RESULT_SUCCESS)
return gamepad_state.id;
else
return "";
}
static bool rwebpad_joypad_button(unsigned port_num, uint16_t joykey)
{
EmscriptenGamepadEvent gamepad_state;
EMSCRIPTEN_RESULT r;
r = emscripten_get_gamepad_status(port_num, &gamepad_state);
if (r == EMSCRIPTEN_RESULT_SUCCESS)
if (joykey < gamepad_state.numButtons)
return gamepad_state.digitalButton[joykey];
return false;
}
static void rwebpad_joypad_get_buttons(unsigned port_num, retro_bits_t *state)
{
EmscriptenGamepadEvent gamepad_state;
EMSCRIPTEN_RESULT r;
r = emscripten_get_gamepad_status(port_num, &gamepad_state);
if (r == EMSCRIPTEN_RESULT_SUCCESS)
{
int i;
for (i = 0; i < gamepad_state.numButtons; i++)
{
if (gamepad_state.digitalButton[i])
BIT256_SET_PTR(state, i);
}
}
else
BIT256_CLEAR_ALL_PTR(state);
}
static int16_t rwebpad_joypad_axis(unsigned port_num, uint32_t joyaxis)
{
EmscriptenGamepadEvent gamepad_state;
EMSCRIPTEN_RESULT r;
int16_t val = 0;
if (joyaxis == 0xFFFFFFFF)
return 0;
r = emscripten_get_gamepad_status(port_num, &gamepad_state);
if (r == EMSCRIPTEN_RESULT_SUCCESS)
{
if (AXIS_NEG_GET(joyaxis) < gamepad_state.numAxes)
{
val = CLAMPDOUBLE(gamepad_state.axis[AXIS_NEG_GET(joyaxis)]) * 0x7FFF;
if (val > 0)
val = 0;
}
else if (AXIS_POS_GET(joyaxis) < gamepad_state.numAxes)
{
val = CLAMPDOUBLE(gamepad_state.axis[AXIS_POS_GET(joyaxis)]) * 0x7FFF;
if (val < 0)
val = 0;
}
}
return val;
}
static void rwebpad_joypad_poll(void)
{
/* this call makes emscripten poll gamepad state */
(void)emscripten_get_num_gamepads();
}
static bool rwebpad_joypad_query_pad(unsigned pad)
{
EmscriptenGamepadEvent gamepad_state;
EMSCRIPTEN_RESULT r;
r = emscripten_get_gamepad_status(pad, &gamepad_state);
if (r == EMSCRIPTEN_RESULT_SUCCESS)
return gamepad_state.connected == EM_TRUE;
return false;
}
static void rwebpad_joypad_destroy(void)
{
}
input_device_driver_t rwebpad_joypad = {
rwebpad_joypad_init,
rwebpad_joypad_query_pad,
rwebpad_joypad_destroy,
rwebpad_joypad_button,
rwebpad_joypad_get_buttons,
rwebpad_joypad_axis,
rwebpad_joypad_poll,
NULL,
rwebpad_joypad_name,
"rwebpad",
};

View File

@ -37,7 +37,8 @@
#define DECL_AXIS(axis, bind) "input_" #axis "_axis = " #bind "\n"
#define DECL_AXIS_EX(axis, bind, name) "input_" #axis "_axis = " #bind "\ninput_" #axis "_axis_label = \"" name "\"\n"
#define DECL_MENU(btn) "input_menu_toggle_btn = " #btn "\n"
#define DECL_AUTOCONF_DEVICE(device, driver, binds) "input_device = \"" device "\" \ninput_driver = \"" driver "\" \n" binds
#define DECL_AUTOCONF_DEVICE(device, driver, binds) "input_device = \"" device "\"\ninput_driver = \"" driver "\"\n" binds
#define DECL_AUTOCONF_PID(pid, vid, driver, binds) "input_product_id = " #pid "\ninput_vendor_id = " #vid "\ninput_driver = \"" driver "\"\n" binds
/* TODO/FIXME - Missing L2/R2 */
@ -528,6 +529,32 @@ DECL_AXIS(r_x_minus, -2) \
DECL_AXIS(r_y_plus, +3) \
DECL_AXIS(r_y_minus, -3)
#define EMSCRIPTEN_DEFAULT_BINDS \
DECL_BTN(a, 1) \
DECL_BTN(b, 0) \
DECL_BTN(x, 3) \
DECL_BTN(y, 2) \
DECL_BTN(start, 9) \
DECL_BTN(select, 8) \
DECL_BTN(up, 12) \
DECL_BTN(down, 13) \
DECL_BTN(left, 14) \
DECL_BTN(right, 15) \
DECL_BTN(l, 4) \
DECL_BTN(r, 5) \
DECL_BTN(l2, 6) \
DECL_BTN(r2, 7) \
DECL_BTN(l3, 10) \
DECL_BTN(r3, 11) \
DECL_AXIS(l_x_plus, +0) \
DECL_AXIS(l_x_minus, -0) \
DECL_AXIS(l_y_plus, +1) \
DECL_AXIS(l_y_minus, -1) \
DECL_AXIS(r_x_plus, +2) \
DECL_AXIS(r_x_minus, -2) \
DECL_AXIS(r_y_plus, +3) \
DECL_AXIS(r_y_minus, -3)
const char* const input_builtin_autoconfs[] =
{
#if defined(_WIN32) && defined(_XBOX)
@ -588,6 +615,9 @@ const char* const input_builtin_autoconfs[] =
#endif
#ifdef __SWITCH__
DECL_AUTOCONF_DEVICE("Switch Controller", "switch", SWITCH_DEFAULT_BINDS),
#endif
#ifdef EMSCRIPTEN
DECL_AUTOCONF_PID(1, 1, "rwebpad", EMSCRIPTEN_DEFAULT_BINDS),
#endif
NULL
};

View File

@ -181,6 +181,9 @@ static input_device_driver_t *joypad_drivers[] = {
* to be selectable in the UI. */
#if defined(HAVE_HID) && !defined(WIIU)
&hid_joypad,
#endif
#ifdef EMSCRIPTEN
&rwebpad_joypad,
#endif
&null_joypad,
NULL,
@ -804,7 +807,7 @@ void state_tracker_update_input(uint16_t *input1, uint16_t *input2)
static INLINE bool input_keys_pressed_iterate(unsigned i,
retro_bits_t* p_new_state)
{
if ((i >= RARCH_FIRST_META_KEY) &&
if ((i >= RARCH_FIRST_META_KEY) &&
BIT64_GET(lifecycle_state, i)
)
return true;

View File

@ -814,6 +814,7 @@ extern input_device_driver_t qnx_joypad;
extern input_device_driver_t null_joypad;
extern input_device_driver_t mfi_joypad;
extern input_device_driver_t dos_joypad;
extern input_device_driver_t rwebpad_joypad;
extern input_driver_t input_android;
extern input_driver_t input_sdl;

View File

@ -579,109 +579,8 @@ 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 },
{ 222, RETROK_QUOTE },
{ 188, RETROK_COMMA },
{ 173, RETROK_MINUS },
{ 191, RETROK_SLASH },
{ 59, RETROK_SEMICOLON },
{ 61, RETROK_EQUALS },
{ 219, RETROK_LEFTBRACKET },
{ 220, RETROK_BACKSLASH },
{ 221, RETROK_RIGHTBRACKET },
{ 188, RETROK_KP_PERIOD },
{ 17, RETROK_RCTRL },
{ 18, RETROK_RALT },
{ 190, RETROK_PERIOD },
{ 145, RETROK_SCROLLOCK },
{ 20, RETROK_CAPSLOCK },
{ 144, RETROK_NUMLOCK },
{ 0, RETROK_UNKNOWN },
};
/* this is generated at runtime, so it isn't constant */
struct rarch_key_map rarch_key_map_rwebinput[RARCH_KEY_MAP_RWEBINPUT_SIZE];
#endif
#ifdef WIIU

View File

@ -46,13 +46,18 @@ struct apple_key_name_map_entry
extern const struct apple_key_name_map_entry apple_key_name_map[];
#endif
#define RARCH_KEY_MAP_RWEBINPUT_SIZE 111
extern const struct input_key_map input_config_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_sdl2[];
extern const struct rarch_key_map rarch_key_map_dinput[];
extern const struct rarch_key_map rarch_key_map_rwebinput[];
/* is generated at runtime so can't be const */
extern struct rarch_key_map rarch_key_map_rwebinput[RARCH_KEY_MAP_RWEBINPUT_SIZE];
extern const struct rarch_key_map rarch_key_map_linux[];
extern const struct rarch_key_map rarch_key_map_apple_hid[];
extern const struct rarch_key_map rarch_key_map_android[];
@ -96,4 +101,3 @@ extern enum retro_key rarch_keysym_lut[RETROK_LAST];
RETRO_END_DECLS
#endif

View File

@ -10,11 +10,11 @@
<!-- Font Awesome -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.0/css/font-awesome.min.css">
<!-- Material Design Bootstrap -->
<link href="//cdnjs.cloudflare.com/ajax/libs/mdbootstrap/4.1.1/css/mdb.min.css" rel="stylesheet">
<link href="//cdnjs.cloudflare.com/ajax/libs/mdbootstrap/4.1.1/css/mdb.min.css" rel="stylesheet">
<link href="embed.css" rel="stylesheet" type="text/css">
<link rel="shortcut icon" href="media/retroarch.ico" />
</head>
<body>
<body>
<!--Navbar-->
<nav class="navbar navbar-dark bg-warning">
<div class="container">
@ -101,7 +101,7 @@
<div class="bg-inverse webplayer-container">
<div class="container">
<div class="webplayer_border text-xs-center" id="canvas_div">
<canvas class="webplayer col-xs-12" id="canvas" tabindex="1" oncontextmenu="event.preventDefault()" style="display: none"></canvas>
<canvas class="webplayer" id="canvas" tabindex="1" oncontextmenu="event.preventDefault()" style="display: none"></canvas>
<img class="webplayer-preview img-fluid" src="media/canvas.png" width="960px" height="720px" alt="RetroArch Logo">
</div>
</div>

View File

@ -11,11 +11,11 @@
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.0/css/font-awesome.min.css">
<!-- Material Design Bootstrap -->
<link href="//cdnjs.cloudflare.com/ajax/libs/mdbootstrap/4.1.1/css/mdb.min.css" rel="stylesheet">
<link href="itch.css" rel="stylesheet" type="text/css">
<link rel="shortcut icon" href="https://buildbot.libretro.com/web/media/retroarch.ico" />
</head>
<body>
<body>
<!--Navbar-->
<nav class="navbar navbar-dark bg-danger">
<div class="container">
@ -105,7 +105,7 @@
<div class="bg-inverse webplayer-container">
<div class="container">
<div class="webplayer_border text-xs-center" id="canvas_div">
<canvas class="webplayer col-xs-12" id="canvas" tabindex="1" oncontextmenu="event.preventDefault()" style="display: none"></canvas>
<canvas class="webplayer" id="canvas" tabindex="1" oncontextmenu="event.preventDefault()" style="display: none"></canvas>
<img class="webplayer-preview img-fluid" src="https://buildbot.libretro.com/web/media/canvas.png" width="960px" height="720px" alt="RetroArch Logo">
</div>
</div>

View File

@ -102,7 +102,7 @@
<div class="bg-inverse webplayer-container">
<div class="container">
<div class="webplayer_border text-xs-center" id="canvas_div">
<canvas class="webplayer col-xs-12" id="canvas" tabindex="1" oncontextmenu="event.preventDefault()" style="display: none"></canvas>
<canvas class="webplayer" id="canvas" tabindex="1" oncontextmenu="event.preventDefault()" style="display: none"></canvas>
<img class="webplayer-preview img-fluid" src="media/canvas.png" width="960px" height="720px" alt="RetroArch Logo">
</div>
</div>