SDL_sysjoystick.c
Go to the documentation of this file.
/*
Simple DirectMedia Layer
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "../../SDL_internal.h"
#ifdef SDL_JOYSTICK_EMSCRIPTEN
#include <stdio.h> /* For the definition of NULL */
#include "SDL_error.h"
#include "SDL_events.h"
#if !SDL_EVENTS_DISABLED
#include "../../events/SDL_events_c.h"
#endif
#include "SDL_joystick.h"
#include "SDL_hints.h"
#include "SDL_assert.h"
#include "SDL_timer.h"
#include "SDL_log.h"
#include "SDL_sysjoystick_c.h"
#include "../SDL_joystick_c.h"
static SDL_joylist_item * JoystickByIndex(int index);
static SDL_joylist_item *SDL_joylist = NULL;
static SDL_joylist_item *SDL_joylist_tail = NULL;
static int numjoysticks = 0;
static int instance_counter = 0;
EM_BOOL
Emscripten_JoyStickConnected(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData)
{
int i;
SDL_joylist_item *item;
if (JoystickByIndex(gamepadEvent->index) != NULL) {
return 1;
}
#if !SDL_EVENTS_DISABLED
SDL_Event event;
#endif
item = (SDL_joylist_item *) SDL_malloc(sizeof (SDL_joylist_item));
if (item == NULL) {
return 1;
}
SDL_zerop(item);
item->index = gamepadEvent->index;
item->name = SDL_strdup(gamepadEvent->id);
if ( item->name == NULL ) {
SDL_free(item);
return 1;
}
item->mapping = SDL_strdup(gamepadEvent->mapping);
if ( item->mapping == NULL ) {
SDL_free(item->name);
SDL_free(item);
return 1;
}
item->naxes = gamepadEvent->numAxes;
item->nbuttons = gamepadEvent->numButtons;
item->device_instance = instance_counter++;
item->timestamp = gamepadEvent->timestamp;
for( i = 0; i < item->naxes; i++) {
item->axis[i] = gamepadEvent->axis[i];
}
for( i = 0; i < item->nbuttons; i++) {
item->analogButton[i] = gamepadEvent->analogButton[i];
item->digitalButton[i] = gamepadEvent->digitalButton[i];
}
if (SDL_joylist_tail == NULL) {
SDL_joylist = SDL_joylist_tail = item;
} else {
SDL_joylist_tail->next = item;
SDL_joylist_tail = item;
}
++numjoysticks;
#ifdef DEBUG_JOYSTICK
SDL_Log("Number of joysticks is %d", numjoysticks);
#endif
#if !SDL_EVENTS_DISABLED
event.type = SDL_JOYDEVICEADDED;
if (SDL_GetEventState(event.type) == SDL_ENABLE) {
event.jdevice.which = numjoysticks - 1;
if ( (SDL_EventOK == NULL) ||
(*SDL_EventOK) (SDL_EventOKParam, &event) ) {
SDL_PushEvent(&event);
}
}
#endif /* !SDL_EVENTS_DISABLED */
#ifdef DEBUG_JOYSTICK
SDL_Log("Added joystick with index %d", item->index);
#endif
return 1;
}
EM_BOOL
Emscripten_JoyStickDisconnected(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData)
{
SDL_joylist_item *item = SDL_joylist;
SDL_joylist_item *prev = NULL;
#if !SDL_EVENTS_DISABLED
SDL_Event event;
#endif
while (item != NULL) {
if (item->index == gamepadEvent->index) {
break;
}
prev = item;
item = item->next;
}
if (item == NULL) {
return 1;
}
if (item->joystick) {
item->joystick->hwdata = NULL;
}
if (prev != NULL) {
prev->next = item->next;
} else {
SDL_assert(SDL_joylist == item);
SDL_joylist = item->next;
}
if (item == SDL_joylist_tail) {
SDL_joylist_tail = prev;
}
/* Need to decrement the joystick count before we post the event */
--numjoysticks;
#if !SDL_EVENTS_DISABLED
event.type = SDL_JOYDEVICEREMOVED;
if (SDL_GetEventState(event.type) == SDL_ENABLE) {
event.jdevice.which = item->device_instance;
if ( (SDL_EventOK == NULL) ||
(*SDL_EventOK) (SDL_EventOKParam, &event) ) {
SDL_PushEvent(&event);
}
}
#endif /* !SDL_EVENTS_DISABLED */
#ifdef DEBUG_JOYSTICK
SDL_Log("Removed joystick with id %d", item->device_instance);
#endif
SDL_free(item->name);
SDL_free(item->mapping);
SDL_free(item);
return 1;
}
/* Function to scan the system for joysticks.
* It should return 0, or -1 on an unrecoverable fatal error.
*/
int
SDL_SYS_JoystickInit(void)
{
int retval, i, numjs;
EmscriptenGamepadEvent gamepadState;
numjoysticks = 0;
numjs = emscripten_get_num_gamepads();
/* Check if gamepad is supported by browser */
if (numjs == EMSCRIPTEN_RESULT_NOT_SUPPORTED) {
return SDL_SetError("Gamepads not supported");
}
/* handle already connected gamepads */
if (numjs > 0) {
for(i = 0; i < numjs; i++) {
retval = emscripten_get_gamepad_status(i, &gamepadState);
if (retval == EMSCRIPTEN_RESULT_SUCCESS) {
Emscripten_JoyStickConnected(EMSCRIPTEN_EVENT_GAMEPADCONNECTED,
&gamepadState,
NULL);
}
}
}
retval = emscripten_set_gamepadconnected_callback(NULL,
0,
Emscripten_JoyStickConnected);
if(retval != EMSCRIPTEN_RESULT_SUCCESS) {
SDL_SYS_JoystickQuit();
return SDL_SetError("Could not set gamepad connect callback");
}
retval = emscripten_set_gamepaddisconnected_callback(NULL,
0,
Emscripten_JoyStickDisconnected);
if(retval != EMSCRIPTEN_RESULT_SUCCESS) {
SDL_SYS_JoystickQuit();
return SDL_SetError("Could not set gamepad disconnect callback");
}
return 0;
}
/* Returns item matching given SDL device index. */
static SDL_joylist_item *
JoystickByDeviceIndex(int device_index)
{
SDL_joylist_item *item = SDL_joylist;
while (0 < device_index) {
--device_index;
item = item->next;
}
return item;
}
/* Returns item matching given HTML gamepad index. */
static SDL_joylist_item *
JoystickByIndex(int index)
{
SDL_joylist_item *item = SDL_joylist;
if (index < 0) {
return NULL;
}
while (item != NULL) {
if (item->index == index) {
break;
}
item = item->next;
}
return item;
}
int SDL_SYS_NumJoysticks()
{
return numjoysticks;
}
void SDL_SYS_JoystickDetect()
{
}
/* Function to get the device-dependent name of a joystick */
const char *
SDL_SYS_JoystickNameForDeviceIndex(int device_index)
{
return JoystickByDeviceIndex(device_index)->name;
}
/* Function to perform the mapping from device index to the instance id for this index */
SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index)
{
return JoystickByDeviceIndex(device_index)->device_instance;
}
/* Function to open a joystick for use.
The joystick to open is specified by the device index.
This should fill the nbuttons and naxes fields of the joystick structure.
It returns 0, or -1 if there is an error.
*/
int
SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index)
{
SDL_joylist_item *item = JoystickByDeviceIndex(device_index);
if (item == NULL ) {
return SDL_SetError("No such device");
}
if (item->joystick != NULL) {
return SDL_SetError("Joystick already opened");
}
joystick->instance_id = item->device_instance;
joystick->hwdata = (struct joystick_hwdata *) item;
item->joystick = joystick;
/* HTML5 Gamepad API doesn't say anything about these */
joystick->nhats = 0;
joystick->nballs = 0;
joystick->nbuttons = item->nbuttons;
joystick->naxes = item->naxes;
return (0);
}
/* Function to determine if this joystick is attached to the system right now */
SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick)
{
return joystick->hwdata != NULL;
}
/* Function to update the state of a joystick - called as a device poll.
* This function shouldn't update the joystick structure directly,
* but instead should call SDL_PrivateJoystick*() to deliver events
* and update joystick device state.
*/
void
SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
{
EmscriptenGamepadEvent gamepadState;
SDL_joylist_item *item = (SDL_joylist_item *) joystick->hwdata;
int i, result, buttonState;
if (item) {
result = emscripten_get_gamepad_status(item->index, &gamepadState);
if( result == EMSCRIPTEN_RESULT_SUCCESS) {
if(gamepadState.timestamp == 0 || gamepadState.timestamp != item->timestamp) {
for(i = 0; i < item->nbuttons; i++) {
if(item->digitalButton[i] != gamepadState.digitalButton[i]) {
buttonState = gamepadState.digitalButton[i]? SDL_PRESSED: SDL_RELEASED;
SDL_PrivateJoystickButton(item->joystick, i, buttonState);
}
/* store values to compare them in the next update */
item->analogButton[i] = gamepadState.analogButton[i];
item->digitalButton[i] = gamepadState.digitalButton[i];
}
for(i = 0; i < item->naxes; i++) {
if(item->axis[i] != gamepadState.axis[i]) {
// do we need to do conversion?
SDL_PrivateJoystickAxis(item->joystick, i,
(Sint16) (32767.*gamepadState.axis[i]));
}
/* store to compare in next update */
item->axis[i] = gamepadState.axis[i];
}
item->timestamp = gamepadState.timestamp;
}
}
}
}
/* Function to close a joystick after use */
void
SDL_SYS_JoystickClose(SDL_Joystick * joystick)
{
}
/* Function to perform any system-specific joystick related cleanup */
void
SDL_SYS_JoystickQuit(void)
{
SDL_joylist_item *item = NULL;
SDL_joylist_item *next = NULL;
for (item = SDL_joylist; item; item = next) {
next = item->next;
SDL_free(item->mapping);
SDL_free(item->name);
SDL_free(item);
}
SDL_joylist = SDL_joylist_tail = NULL;
numjoysticks = 0;
instance_counter = 0;
emscripten_set_gamepadconnected_callback(NULL, 0, NULL);
emscripten_set_gamepaddisconnected_callback(NULL, 0, NULL);
}
SDL_JoystickGUID
SDL_SYS_JoystickGetDeviceGUID(int device_index)
{
SDL_JoystickGUID guid;
/* the GUID is just the first 16 chars of the name for now */
const char *name = SDL_SYS_JoystickNameForDeviceIndex(device_index);
SDL_zero(guid);
SDL_memcpy(&guid, name, SDL_min(sizeof(guid), SDL_strlen(name)));
return guid;
}
SDL_JoystickGUID
SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick)
{
SDL_JoystickGUID guid;
/* the GUID is just the first 16 chars of the name for now */
const char *name = joystick->name;
SDL_zero(guid);
SDL_memcpy(&guid, name, SDL_min(sizeof(guid), SDL_strlen(name)));
return guid;
}
#endif /* SDL_JOYSTICK_EMSCRIPTEN */
SDL_min
#define SDL_min(x, y)
Definition: SDL_stdinc.h:345
SDL_joystick.h
result
GLuint64EXT * result
Definition: SDL_opengl_glext.h:9432
joystick_hwdata::guid
SDL_JoystickGUID guid
Definition: SDL_sysjoystick_c.h:65
SDL_log.h
SDL_SYS_NumJoysticks
int SDL_SYS_NumJoysticks()
Definition: SDL_sysjoystick.m:309
SDL_JOYDEVICEADDED
Definition: SDL_events.h:113
joystick_hwdata::joystick
SDL_Joystick * joystick
Definition: SDL_sysjoystick_c.h:39
SDL_events.h
SDL_PrivateJoystickButton
int SDL_PrivateJoystickButton(SDL_Joystick *joystick, Uint8 button, Uint8 state)
Definition: SDL_joystick.c:618
SDL_ENABLE
#define SDL_ENABLE
Definition: SDL_events.h:718
joystick_hwdata::next
struct joystick_hwdata * next
Definition: SDL_sysjoystick_c.h:47
name
GLuint const GLchar * name
Definition: SDL_opengl_glext.h:660
SDL_SYS_JoystickQuit
void SDL_SYS_JoystickQuit(void)
Definition: SDL_sysjoystick.m:611
SDL_zerop
#define SDL_zerop(x)
Definition: SDL_stdinc.h:356
SDL_PrivateJoystickAxis
int SDL_PrivateJoystickAxis(SDL_Joystick *joystick, Uint8 axis, Sint16 value)
Definition: SDL_joystick.c:501
joystick_hwdata
Definition: SDL_sysjoystick_c.h:44
SDL_JOYDEVICEREMOVED
Definition: SDL_events.h:114
SDL_bool
SDL_bool
Definition: SDL_stdinc.h:126
retval
SDL_bool retval
Definition: testgamecontroller.c:65
SDL_Log
#define SDL_Log
Definition: SDL_dynapi_overrides.h:37
SDL_memcpy
#define SDL_memcpy
Definition: SDL_dynapi_overrides.h:393
SDL_GetEventState
#define SDL_GetEventState(type)
Definition: SDL_events.h:731
SDL_JoystickID
Sint32 SDL_JoystickID
Definition: SDL_joystick.h:72
event
struct _cl_event * event
Definition: SDL_opengl_glext.h:2649
SDL_free
void SDL_free(void *mem)
SDL_SYS_JoystickAttached
SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick)
Definition: SDL_sysjoystick.m:382
SDL_EventOK
SDL_EventFilter SDL_EventOK
Definition: SDL_events.c:40
SDL_PushEvent
#define SDL_PushEvent
Definition: SDL_dynapi_overrides.h:131
SDL_hints.h
SDL_SYS_JoystickDetect
void SDL_SYS_JoystickDetect()
Definition: SDL_sysjoystick.m:314
SDL_zero
#define SDL_zero(x)
Definition: SDL_stdinc.h:355
SDL_SYS_JoystickNameForDeviceIndex
const char * SDL_SYS_JoystickNameForDeviceIndex(int device_index)
Definition: SDL_sysjoystick.m:320
SDL_SYS_JoystickUpdate
void SDL_SYS_JoystickUpdate(SDL_Joystick *joystick)
Definition: SDL_sysjoystick.m:569
index
GLuint index
Definition: SDL_opengl_glext.h:660
SDL_SYS_JoystickGetGUID
SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick *joystick)
Definition: SDL_sysjoystick.m:652
i
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:42
SDL_assert
#define SDL_assert(condition)
Definition: SDL_assert.h:167
SDL_SYS_JoystickInit
int SDL_SYS_JoystickInit(void)
Definition: SDL_sysjoystick.m:260
SDL_EventOKParam
void * SDL_EventOKParam
Definition: SDL_events.c:41
NULL
#define NULL
Definition: begin_code.h:143
SDL_SetError
#define SDL_SetError
Definition: SDL_dynapi_overrides.h:36
SDL_strlen
#define SDL_strlen
Definition: SDL_dynapi_overrides.h:399
SDL_strdup
#define SDL_strdup
Definition: SDL_dynapi_overrides.h:403
joystick_hwdata::item
struct SDL_joylist_item * item
Definition: SDL_sysjoystick_c.h:30
SDL_JoystickGUID
Definition: SDL_joystick.h:68
SDL_SYS_GetInstanceIdOfDeviceIndex
SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index)
Definition: SDL_sysjoystick.m:327
numjoysticks
static int numjoysticks
Definition: SDL_sysjoystick.m:53
SDL_SYS_JoystickOpen
int SDL_SYS_JoystickOpen(SDL_Joystick *joystick, int device_index)
Definition: SDL_sysjoystick.m:339
SDL_Event
General event structure.
Definition: SDL_events.h:521
SDL_malloc
#define SDL_malloc
Definition: SDL_dynapi_overrides.h:380
SDL_PRESSED
#define SDL_PRESSED
Definition: SDL_events.h:50
SDL_timer.h
SDL_SYS_JoystickClose
void SDL_SYS_JoystickClose(SDL_Joystick *joystick)
Definition: SDL_sysjoystick.m:586
SDL_RELEASED
#define SDL_RELEASED
Definition: SDL_events.h:49
SDL_error.h
SDL_SYS_JoystickGetDeviceGUID
SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID(int device_index)
Definition: SDL_sysjoystick.m:639
Sint16
int16_t Sint16
A signed 16-bit integer type.
Definition: SDL_stdinc.h:143
SDL_Event::type
Uint32 type
Definition: SDL_events.h:523
SDL_assert.h