add joypad driver for emscripten

This commit is contained in:
Toad King 2018-01-14 00:15:30 -06:00
parent 38ec1acf8e
commit 21d928ba0e
6 changed files with 277 additions and 39 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

@ -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
@ -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,

View File

@ -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 <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"
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",
};

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;