From 21d928ba0ea931716f5d37f3b3691554836ca9a5 Mon Sep 17 00:00:00 2001 From: Toad King Date: Sun, 14 Jan 2018 00:15:30 -0600 Subject: [PATCH] add joypad driver for emscripten --- Makefile.common | 1 + griffin/griffin.c | 1 + input/drivers/rwebinput_input.c | 113 ++++++++++----- input/drivers_joypad/rwebpad_joypad.c | 195 ++++++++++++++++++++++++++ input/input_driver.c | 5 +- input/input_driver.h | 1 + 6 files changed, 277 insertions(+), 39 deletions(-) create mode 100644 input/drivers_joypad/rwebpad_joypad.c diff --git a/Makefile.common b/Makefile.common index 8c82929a6c..f1eed13ace 100644 --- a/Makefile.common +++ b/Makefile.common @@ -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 diff --git a/griffin/griffin.c b/griffin/griffin.c index 5bba239c5b..53d450061b 100644 --- a/griffin/griffin.c +++ b/griffin/griffin.c @@ -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" diff --git a/input/drivers/rwebinput_input.c b/input/drivers/rwebinput_input.c index 1e9052e918..003c104a07 100644 --- a/input/drivers/rwebinput_input.c +++ b/input/drivers/rwebinput_input.c @@ -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 @@ -66,6 +66,7 @@ typedef struct rwebinput_input { rwebinput_keyboard_state_t keyboard; rwebinput_mouse_state_t mouse; + const input_device_driver_t *joypad; bool blocked; } rwebinput_input_t; @@ -186,8 +187,8 @@ static const rwebinput_key_to_code_map_entry_t rwebinput_key_to_code_map[] = { "Power", RETROK_POWER }, }; -static bool g_initialized; -static rwebinput_keyboard_state_t *g_keyboard; +static bool g_rwebinput_mouset_initialized; +static rwebinput_keyboard_state_t *g_rwebinput_mouset_keyboard; static rwebinput_mouse_state_t *g_mouse; /* to make the string labels for codes from JavaScript work, we convert them @@ -275,7 +276,7 @@ static EM_BOOL rwebinput_keyboard_cb(int event_type, if (translated_keycode < RETROK_LAST) { - g_keyboard->keys[translated_keycode] = keydown; + g_rwebinput_mouset_keyboard->keys[translated_keycode] = keydown; } return EM_TRUE; @@ -321,19 +322,19 @@ static void *rwebinput_input_init(const char *joypad_driver) { rwebinput_input_t *rwebinput = (rwebinput_input_t*)calloc(1, sizeof(*rwebinput)); - g_keyboard = - (rwebinput_keyboard_state_t*)calloc(1, sizeof(rwebinput_keyboard_state_t)); - g_mouse = - (rwebinput_mouse_state_t*)calloc(1, sizeof(rwebinput_mouse_state_t)); + g_rwebinput_mouset_keyboard = (rwebinput_keyboard_state_t*) + calloc(1, sizeof(rwebinput_keyboard_state_t)); + g_mouse = (rwebinput_mouse_state_t*) + calloc(1, sizeof(rwebinput_mouse_state_t)); - if (!rwebinput || !g_keyboard || !g_mouse) + if (!rwebinput || !g_rwebinput_mouset_keyboard || !g_mouse) goto error; - if (!g_initialized) + if (!g_rwebinput_mouset_initialized) { EMSCRIPTEN_RESULT r; - g_initialized = true; + g_rwebinput_mouset_initialized = true; rwebinput_generate_lut(); /* emscripten currently doesn't have an API to remove handlers, so make @@ -397,16 +398,19 @@ static void *rwebinput_input_init(const char *joypad_driver) input_keymaps_init_keyboard_lut(rarch_key_map_rwebinput); + rwebinput->joypad = input_joypad_init_driver(joypad_driver, rwebinput); + return rwebinput; error: - free(g_keyboard); + free(g_rwebinput_mouset_keyboard); free(g_mouse); free(rwebinput); return NULL; } -static bool rwebinput_key_pressed(rwebinput_keyboard_state_t *keyboard, int key) +static bool rwebinput_key_pressed(rwebinput_keyboard_state_t *keyboard, + int key) { if (key >= RETROK_LAST) return false; @@ -414,20 +418,6 @@ static bool rwebinput_key_pressed(rwebinput_keyboard_state_t *keyboard, int key) return keyboard->keys[key]; } -static bool rwebinput_is_pressed(rwebinput_keyboard_state_t *keyboard, - const struct retro_keybind *binds, unsigned id) -{ - if (id < RARCH_BIND_LIST_END) - { - const struct retro_keybind *bind = &binds[id]; - int key = binds[id].key; - return bind->valid && (key < RETROK_LAST) - && rwebinput_key_pressed(keyboard, key); - } - - return false; -} - static int16_t rwebinput_pointer_device_state(rwebinput_mouse_state_t *mouse, unsigned id, bool screen) { @@ -455,8 +445,6 @@ static int16_t rwebinput_pointer_device_state(rwebinput_mouse_state_t *mouse, res_y = res_screen_y; } - printf("%d %d %d %d\n", res_x, res_y, res_screen_x, res_screen_y); - inside = (res_x >= -0x7fff) && (res_y >= -0x7fff); if (!inside) @@ -507,8 +495,36 @@ static int16_t rwebinput_mouse_state(rwebinput_mouse_state_t *mouse, 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->keyboard, 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; @@ -516,9 +532,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->keyboard, binds, id_minus)) + if (rwebinput_is_pressed(rwebinput, joypad_info, binds, idx, id_minus)) pressed_minus = -0x7fff; - if (rwebinput_is_pressed(&rwebinput->keyboard, binds, id_plus)) + if (rwebinput_is_pressed(rwebinput, joypad_info, binds, idx, id_plus)) pressed_plus = 0x7fff; return pressed_plus + pressed_minus; @@ -529,14 +545,23 @@ 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->keyboard, 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->keyboard, id); case RETRO_DEVICE_MOUSE: @@ -556,8 +581,8 @@ static void rwebinput_input_free(void *data) { rwebinput_input_t *rwebinput = (rwebinput_input_t*)data; - free(g_keyboard); - g_keyboard = NULL; + free(g_rwebinput_mouset_keyboard); + g_rwebinput_mouset_keyboard = NULL; free(g_mouse); g_mouse = NULL; free(rwebinput); @@ -568,11 +593,15 @@ static void rwebinput_input_poll(void *data) unsigned i; rwebinput_input_t *rwebinput = (rwebinput_input_t*)data; - memcpy(&rwebinput->keyboard, g_keyboard, sizeof(*g_keyboard)); + memcpy(&rwebinput->keyboard, g_rwebinput_mouset_keyboard, + sizeof(*g_rwebinput_mouset_keyboard)); memcpy(&rwebinput->mouse, g_mouse, sizeof(*g_mouse)); g_mouse->delta_x = g_mouse->delta_y = 0; g_mouse->scroll_x = g_mouse->scroll_y = 0.0; + + if (rwebinput->joypad) + rwebinput->joypad->poll(); } static void rwebinput_grab_mouse(void *data, bool state) @@ -596,6 +625,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; @@ -637,7 +674,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, diff --git a/input/drivers_joypad/rwebpad_joypad.c b/input/drivers_joypad/rwebpad_joypad.c new file mode 100644 index 0000000000..2b47df6103 --- /dev/null +++ b/input/drivers_joypad/rwebpad_joypad.c @@ -0,0 +1,195 @@ +/* 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 . + */ + +#include +#include + +#include +#include +#include + +#include "../input_driver.h" + +#include "../../tasks/tasks_internal.h" +#include "../../verbosity.h" + +static bool g_rwebpad_initialized; + +static EM_BOOL rwebpad_gamepad_cb(int event_type, + const EmscriptenGamepadEvent *gamepad_event, void *user_data) +{ + (void)event_type; + (void)gamepad_event; + (void)user_data; + + 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 */ + 0, /* vid */ + 0)) /* 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 < ARRAY_SIZE(gamepad_state.digitalButton)) + { + 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; + + BIT256_CLEAR_ALL_PTR(state); + + r = emscripten_get_gamepad_status(port_num, &gamepad_state); + + if (r == EMSCRIPTEN_RESULT_SUCCESS) + { + int i; + + for (i = 0; i < ARRAY_SIZE(gamepad_state.digitalButton); i++) + { + if (gamepad_state.digitalButton[i]) + BIT256_SET_PTR(state, i); + } + } +} + +static int16_t rwebpad_joypad_axis(unsigned port_num, uint32_t joyaxis) +{ + EmscriptenGamepadEvent gamepad_state; + EMSCRIPTEN_RESULT r; + + if (joyaxis > ARRAY_SIZE(gamepad_state.axis)) + return 0; + + r = emscripten_get_gamepad_status(port_num, &gamepad_state); + + if (r == EMSCRIPTEN_RESULT_SUCCESS) + return gamepad_state.axis[joyaxis] * 0x7FFF; + else + return 0; +} + +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", +}; diff --git a/input/input_driver.c b/input/input_driver.c index 01fff706e3..73ea18aefe 100644 --- a/input/input_driver.c +++ b/input/input_driver.c @@ -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; diff --git a/input/input_driver.h b/input/input_driver.h index 01782d0252..b3c53ab8d2 100644 --- a/input/input_driver.h +++ b/input/input_driver.h @@ -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;