emscripten: recreate input event listeners properly

There's a new (undocumented -_-) API for removing event listeners in emscripten
now, so use that when recreating input listeners. Fixes mouse events breaking
when loading cores.
This commit is contained in:
Toad King 2020-01-18 12:51:21 -06:00
parent 142503d3b5
commit 14c67fde7f
4 changed files with 116 additions and 127 deletions

View File

@ -63,9 +63,13 @@ typedef struct rwebinput_mouse_states
{
signed x;
signed y;
signed pending_delta_x;
signed pending_delta_y;
signed delta_x;
signed delta_y;
uint8_t buttons;
double pending_scroll_x;
double pending_scroll_y;
double scroll_x;
double scroll_y;
} rwebinput_mouse_state_t;
@ -74,6 +78,7 @@ typedef struct rwebinput_input
{
bool keys[RETROK_LAST];
rwebinput_mouse_state_t mouse;
rwebinput_keyboard_event_queue_t keyboard;
const input_device_driver_t *joypad;
} rwebinput_input_t;
@ -194,10 +199,6 @@ static const rwebinput_key_to_code_map_entry_t rwebinput_key_to_code_map[] =
{ "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)
@ -237,22 +238,24 @@ static void rwebinput_generate_lut(void)
static EM_BOOL rwebinput_keyboard_cb(int event_type,
const EmscriptenKeyboardEvent *key_event, void *user_data)
{
rwebinput_input_t *rwebinput = (rwebinput_input_t*)user_data;
if (event_type == EMSCRIPTEN_EVENT_KEYPRESS)
return EM_TRUE;
if (g_rwebinput_keyboard->count >= g_rwebinput_keyboard->max_size)
if (rwebinput->keyboard.count >= 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;
size_t new_max = MAX(1, rwebinput->keyboard.max_size << 1);
rwebinput->keyboard.events = realloc(rwebinput->keyboard.events,
new_max * sizeof(rwebinput->keyboard.events[0]));
retro_assert(rwebinput->keyboard.events != NULL);
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,
rwebinput->keyboard.events[rwebinput->keyboard.count].type = event_type;
memcpy(&rwebinput->keyboard.events[rwebinput->keyboard.count].event,
key_event, sizeof(*key_event));
g_rwebinput_keyboard->count++;
rwebinput->keyboard.count++;
return EM_TRUE;
}
@ -260,22 +263,22 @@ static EM_BOOL rwebinput_keyboard_cb(int event_type,
static EM_BOOL rwebinput_mouse_cb(int event_type,
const EmscriptenMouseEvent *mouse_event, void *user_data)
{
(void)user_data;
rwebinput_input_t *rwebinput = (rwebinput_input_t*)user_data;
uint8_t mask = 1 << mouse_event->button;
g_rwebinput_mouse->x = mouse_event->targetX;
g_rwebinput_mouse->y = mouse_event->targetY;
g_rwebinput_mouse->delta_x += mouse_event->movementX;
g_rwebinput_mouse->delta_y += mouse_event->movementY;
rwebinput->mouse.x = mouse_event->targetX;
rwebinput->mouse.y = mouse_event->targetY;
rwebinput->mouse.pending_delta_x += mouse_event->movementX;
rwebinput->mouse.pending_delta_y += mouse_event->movementY;
if (event_type == EMSCRIPTEN_EVENT_MOUSEDOWN)
{
g_rwebinput_mouse->buttons |= mask;
rwebinput->mouse.buttons |= mask;
}
else if (event_type == EMSCRIPTEN_EVENT_MOUSEUP)
{
g_rwebinput_mouse->buttons &= ~mask;
rwebinput->mouse.buttons &= ~mask;
}
return EM_TRUE;
@ -284,91 +287,80 @@ static EM_BOOL rwebinput_mouse_cb(int event_type,
static EM_BOOL rwebinput_wheel_cb(int event_type,
const EmscriptenWheelEvent *wheel_event, void *user_data)
{
rwebinput_input_t *rwebinput = (rwebinput_input_t*)user_data;
(void)event_type;
(void)user_data;
g_rwebinput_mouse->scroll_x += wheel_event->deltaX;
g_rwebinput_mouse->scroll_y += wheel_event->deltaY;
rwebinput->mouse.pending_scroll_x += wheel_event->deltaX;
rwebinput->mouse.pending_scroll_y += wheel_event->deltaY;
return EM_TRUE;
}
static void *rwebinput_input_init(const char *joypad_driver)
{
EMSCRIPTEN_RESULT r;
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)
if (!rwebinput)
goto error;
if (!g_rwebinput_initialized)
rwebinput_generate_lut();
r = emscripten_set_keydown_callback(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, rwebinput, false,
rwebinput_keyboard_cb);
if (r != EMSCRIPTEN_RESULT_SUCCESS)
{
EMSCRIPTEN_RESULT r;
RARCH_ERR(
"[EMSCRIPTEN/INPUT] failed to create keydown callback: %d\n", r);
}
g_rwebinput_initialized = true;
rwebinput_generate_lut();
r = emscripten_set_keyup_callback(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, rwebinput, false,
rwebinput_keyboard_cb);
if (r != EMSCRIPTEN_RESULT_SUCCESS)
{
RARCH_ERR(
"[EMSCRIPTEN/INPUT] failed to create keydown callback: %d\n", r);
}
/* emscripten currently doesn't have an API to remove handlers, so make
* once and reuse it */
r = emscripten_set_keydown_callback(EMSCRIPTEN_EVENT_TARGET_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(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, rwebinput, false,
rwebinput_keyboard_cb);
if (r != EMSCRIPTEN_RESULT_SUCCESS)
{
RARCH_ERR(
"[EMSCRIPTEN/INPUT] failed to create keypress callback: %d\n", r);
}
r = emscripten_set_keyup_callback(EMSCRIPTEN_EVENT_TARGET_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_mousedown_callback("#canvas", rwebinput, false,
rwebinput_mouse_cb);
if (r != EMSCRIPTEN_RESULT_SUCCESS)
{
RARCH_ERR(
"[EMSCRIPTEN/INPUT] failed to create mousedown callback: %d\n", r);
}
r = emscripten_set_keypress_callback(EMSCRIPTEN_EVENT_TARGET_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_mouseup_callback("#canvas", rwebinput, false,
rwebinput_mouse_cb);
if (r != EMSCRIPTEN_RESULT_SUCCESS)
{
RARCH_ERR(
"[EMSCRIPTEN/INPUT] failed to create mouseup 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_mousemove_callback("#canvas", rwebinput, false,
rwebinput_mouse_cb);
if (r != EMSCRIPTEN_RESULT_SUCCESS)
{
RARCH_ERR(
"[EMSCRIPTEN/INPUT] failed to create mousemove 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(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, NULL, false,
rwebinput_wheel_cb);
if (r != EMSCRIPTEN_RESULT_SUCCESS)
{
RARCH_ERR(
"[EMSCRIPTEN/INPUT] failed to create wheel callback: %d\n", r);
}
r = emscripten_set_wheel_callback(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, rwebinput, 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);
@ -378,8 +370,6 @@ static void *rwebinput_input_init(const char *joypad_driver)
return rwebinput;
error:
free(g_rwebinput_keyboard);
free(g_rwebinput_mouse);
free(rwebinput);
return NULL;
}
@ -526,7 +516,7 @@ static int16_t rwebinput_input_state(void *data,
const struct retro_keybind **binds,
unsigned port, unsigned device, unsigned idx, unsigned id)
{
rwebinput_input_t *rwebinput = (rwebinput_input_t*)data;
rwebinput_input_t *rwebinput = (rwebinput_input_t*)data;
switch (device)
{
@ -584,14 +574,15 @@ static void rwebinput_input_free(void *data)
{
rwebinput_input_t *rwebinput = (rwebinput_input_t*)data;
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;
emscripten_html5_remove_all_event_listeners();
if (rwebinput->joypad)
rwebinput->joypad->destroy();
free(rwebinput->keyboard.events);
free(rwebinput);
}
static void rwebinput_process_keyboard_events(rwebinput_input_t *rwebinput,
rwebinput_keyboard_event_t *event)
{
@ -644,14 +635,20 @@ static void rwebinput_input_poll(void *data)
size_t i;
rwebinput_input_t *rwebinput = (rwebinput_input_t*)data;
for (i = 0; i < g_rwebinput_keyboard->count; i++)
for (i = 0; i < rwebinput->keyboard.count; i++)
rwebinput_process_keyboard_events(rwebinput,
&g_rwebinput_keyboard->events[i]);
g_rwebinput_keyboard->count = 0;
&rwebinput->keyboard.events[i]);
rwebinput->keyboard.count = 0;
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;
rwebinput->mouse.delta_x = rwebinput->mouse.pending_delta_x;
rwebinput->mouse.delta_y = rwebinput->mouse.pending_delta_y;
rwebinput->mouse.pending_delta_x = 0;
rwebinput->mouse.pending_delta_y = 0;
rwebinput->mouse.scroll_x = rwebinput->mouse.pending_scroll_x;
rwebinput->mouse.scroll_y = rwebinput->mouse.pending_scroll_y;
rwebinput->mouse.pending_scroll_x = 0;
rwebinput->mouse.pending_scroll_y = 0;
if (rwebinput->joypad)
rwebinput->joypad->poll();

View File

@ -27,8 +27,6 @@
#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)
{
@ -64,34 +62,28 @@ static EM_BOOL rwebpad_gamepad_cb(int event_type,
static bool rwebpad_joypad_init(void *data)
{
EMSCRIPTEN_RESULT supported;
EMSCRIPTEN_RESULT r;
(void)data;
supported = emscripten_sample_gamepad_data();
if (supported == EMSCRIPTEN_RESULT_NOT_SUPPORTED)
r = emscripten_sample_gamepad_data();
if (r == EMSCRIPTEN_RESULT_NOT_SUPPORTED)
return false;
if (!g_rwebpad_initialized)
/* callbacks needs to be registered for gamepads to connect */
r = emscripten_set_gamepadconnected_callback(NULL, false,
rwebpad_gamepad_cb);
if (r != EMSCRIPTEN_RESULT_SUCCESS)
{
EMSCRIPTEN_RESULT r;
g_rwebpad_initialized = true;
RARCH_ERR(
"[EMSCRIPTEN/PAD] failed to create connect callback: %d\n", r);
}
/* 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);
}
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;

View File

@ -50,11 +50,11 @@
</button>
<input class="btn btn-primary disabled" style="display: none" type="file" id="btnRom" name="upload" onclick="document.getElementById('btnAdd').click();" onchange="selectFiles(event.target.files)" multiple />
<button class="btn btn-primary disabled tooltip-enable" id="btnMenu" onclick="keyPress(112);" title="Menu toggle" disabled>
<button class="btn btn-primary disabled tooltip-enable" id="btnMenu" onclick="keyPress('F1');" title="Menu toggle" disabled>
<span class="fa fa-bars" id="btnMenu"></span> <span class="sr-only">Menu</span>
</button>
<button class="btn btn-primary disabled tooltip-enable" id="btnFullscreen" onclick="Module.requestFullscreen()" title="Fullscreen" disabled>
<button class="btn btn-primary disabled tooltip-enable" id="btnFullscreen" onclick="Module.requestFullscreen(false)" title="Fullscreen" disabled>
<span class="fa fa-desktop" id="icnAdd"></span> <span class="sr-only">Fullscreen</span>
</button>

View File

@ -93,7 +93,7 @@
<button class="btn btn-primary disabled tooltip-enable" id="btnMenu" onclick="keyPress('F1');" title="Menu toggle" disabled>
<span class="fa fa-bars" id="btnMenu"></span> <span class="sr-only">Menu</span>
</button>
<button class="btn btn-primary disabled tooltip-enable" id="btnFullscreen" onclick="Module.requestFullscreen()" title="Fullscreen" disabled>
<button class="btn btn-primary disabled tooltip-enable" id="btnFullscreen" onclick="Module.requestFullscreen(false)" title="Fullscreen" disabled>
<span class="fa fa-desktop" id="icnAdd"></span> <span class="sr-only">Fullscreen</span>
</button>
</button>