diff --git a/Makefile.emscripten b/Makefile.emscripten index 2942e49c52..6a8a39e036 100644 --- a/Makefile.emscripten +++ b/Makefile.emscripten @@ -42,7 +42,6 @@ LIBS := -s USE_SDL=2 -s USE_ZLIB=1 LDFLAGS := -L. --no-heap-copy -s USE_ZLIB=1 -s TOTAL_MEMORY=$(MEMORY) \ -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 diff --git a/emscripten/library_rwebinput.js b/emscripten/library_rwebinput.js deleted file mode 100644 index 5d818f7805..0000000000 --- a/emscripten/library_rwebinput.js +++ /dev/null @@ -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); diff --git a/input/drivers/rwebinput_input.c b/input/drivers/rwebinput_input.c index dcea18a2ab..65cd0d711a 100644 --- a/input/drivers/rwebinput_input.c +++ b/input/drivers/rwebinput_input.c @@ -19,50 +19,295 @@ #include #include +#include +#include +#include +#include + +#include #include "../input_driver.h" #include "../input_keymaps.h" #include "../../tasks/tasks_internal.h" #include "../../configuration.h" +#include "../../verbosity.h" -typedef struct rwebinput_state +typedef struct rwebinput_key_to_code_map_entry { - uint8_t keys[32]; + const char *key; + enum retro_key rk; +} rwebinput_key_to_code_map_entry_t; + +typedef struct +{ + bool keys[RETROK_LAST]; +} rwebinput_key_states_t; + +typedef struct rwebinput_input +{ + rwebinput_key_states_t keyboard; int mouse_x; int mouse_y; char mouse_l; char mouse_r; bool blocked; -} rwebinput_state_t; - -int RWebInputInit(void); -rwebinput_state_t *RWebInputPoll(int context); -void RWebInputDestroy(int context); - -typedef struct rwebinput_input -{ - rwebinput_state_t state; - int context; } 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_initialized; +static rwebinput_key_states_t *g_keyboard; + +/* 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_input_cb(int event_type, + const EmscriptenKeyboardEvent *key_event, void *user_data) +{ + uint32_t crc; + uint32_t keycode; + unsigned translated_keycode; + uint32_t character = 0; + uint16_t mod = 0; + bool keydown = event_type == EMSCRIPTEN_EVENT_KEYDOWN; + + (void)user_data; + + /* capture keypress events and silence them */ + if (event_type == EMSCRIPTEN_EVENT_KEYPRESS) + return EM_TRUE; + + /* 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); + + input_keyboard_event(keydown, translated_keycode, character, mod, + RETRO_DEVICE_KEYBOARD); + + if (translated_keycode < RETROK_LAST) + { + g_keyboard->keys[translated_keycode] = keydown; + } + + 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_keyboard = + (rwebinput_key_states_t*)calloc(1, sizeof(rwebinput_key_states_t)); + + if (!rwebinput || !g_keyboard) goto error; - rwebinput->context = RWebInputInit(); - if (!rwebinput->context) - goto error; + if (!g_initialized) + { + EMSCRIPTEN_RESULT r; + + g_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_input_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_input_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_input_cb); + if (r != EMSCRIPTEN_RESULT_SUCCESS) + { + RARCH_ERR( + "[EMSCRIPTEN/INPUT] failed to create keypress callback: %d\n", r); + } + } input_keymaps_init_keyboard_lut(rarch_key_map_rwebinput); return rwebinput; error: - if (rwebinput) - free(rwebinput); + free(g_keyboard); + free(rwebinput); return NULL; } @@ -75,10 +320,7 @@ static bool rwebinput_key_pressed(void *data, int key) 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->keyboard.keys[key]; } static bool rwebinput_is_pressed(rwebinput_input_t *rwebinput, @@ -100,13 +342,13 @@ 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; + return (int16_t) rwebinput->mouse_x; case RETRO_DEVICE_ID_MOUSE_Y: - return (int16_t) rwebinput->state.mouse_y; + return (int16_t) rwebinput->mouse_y; case RETRO_DEVICE_ID_MOUSE_LEFT: - return rwebinput->state.mouse_l; + return rwebinput->mouse_l; case RETRO_DEVICE_ID_MOUSE_RIGHT: - return rwebinput->state.mouse_r; + return rwebinput->mouse_r; } return 0; @@ -155,11 +397,12 @@ static void rwebinput_input_free(void *data) { rwebinput_input_t *rwebinput = (rwebinput_input_t*)data; + free(g_keyboard); + g_keyboard = NULL; + if (!rwebinput) return; - RWebInputDestroy(rwebinput->context); - free(rwebinput); } @@ -167,29 +410,8 @@ static void rwebinput_input_poll(void *data) { unsigned 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; - - if (state->keys[i] == rwebinput->state.keys[i]) - continue; - - 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)); + memcpy(&rwebinput->keyboard, g_keyboard, sizeof(*g_keyboard)); } static void rwebinput_grab_mouse(void *data, bool state) @@ -226,7 +448,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) @@ -234,7 +456,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 = { diff --git a/input/input_keymaps.c b/input/input_keymaps.c index ef4345e8c3..8060d92b80 100644 --- a/input/input_keymaps.c +++ b/input/input_keymaps.c @@ -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 diff --git a/input/input_keymaps.h b/input/input_keymaps.h index 11757f2f68..d682af4e0e 100644 --- a/input/input_keymaps.h +++ b/input/input_keymaps.h @@ -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 -