sdl

FORK: Simple Directmedia Layer
git clone https://git.neptards.moe/neptards/sdl.git
Log | Files | Refs

SDL_sysjoystick.c (12530B)


      1 /*
      2   Simple DirectMedia Layer
      3   Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
      4 
      5   This software is provided 'as-is', without any express or implied
      6   warranty.  In no event will the authors be held liable for any damages
      7   arising from the use of this software.
      8 
      9   Permission is granted to anyone to use this software for any purpose,
     10   including commercial applications, and to alter it and redistribute it
     11   freely, subject to the following restrictions:
     12 
     13   1. The origin of this software must not be misrepresented; you must not
     14      claim that you wrote the original software. If you use this software
     15      in a product, an acknowledgment in the product documentation would be
     16      appreciated but is not required.
     17   2. Altered source versions must be plainly marked as such, and must not be
     18      misrepresented as being the original software.
     19   3. This notice may not be removed or altered from any source distribution.
     20 */
     21 
     22 #include "../../SDL_internal.h"
     23 
     24 #ifdef SDL_JOYSTICK_EMSCRIPTEN
     25 
     26 #include <stdio.h>              /* For the definition of NULL */
     27 #include "SDL_error.h"
     28 #include "SDL_events.h"
     29 
     30 #include "SDL_joystick.h"
     31 #include "SDL_timer.h"
     32 #include "SDL_sysjoystick_c.h"
     33 #include "../SDL_joystick_c.h"
     34 
     35 static SDL_joylist_item * JoystickByIndex(int index);
     36 
     37 static SDL_joylist_item *SDL_joylist = NULL;
     38 static SDL_joylist_item *SDL_joylist_tail = NULL;
     39 static int numjoysticks = 0;
     40 static int instance_counter = 0;
     41 
     42 static EM_BOOL
     43 Emscripten_JoyStickConnected(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData)
     44 {
     45     int i;
     46 
     47     SDL_joylist_item *item;
     48 
     49     if (JoystickByIndex(gamepadEvent->index) != NULL) {
     50       return 1;
     51     }
     52 
     53     item = (SDL_joylist_item *) SDL_malloc(sizeof (SDL_joylist_item));
     54     if (item == NULL) {
     55         return 1;
     56     }
     57 
     58     SDL_zerop(item);
     59     item->index = gamepadEvent->index;
     60 
     61     item->name = SDL_CreateJoystickName(0, 0, NULL, gamepadEvent->id);
     62     if ( item->name == NULL ) {
     63         SDL_free(item);
     64         return 1;
     65     }
     66 
     67     item->mapping = SDL_strdup(gamepadEvent->mapping);
     68     if ( item->mapping == NULL ) {
     69         SDL_free(item->name);
     70         SDL_free(item);
     71         return 1;
     72     }
     73 
     74     item->naxes = gamepadEvent->numAxes;
     75     item->nbuttons = gamepadEvent->numButtons;
     76     item->device_instance = instance_counter++;
     77 
     78     item->timestamp = gamepadEvent->timestamp;
     79 
     80     for( i = 0; i < item->naxes; i++) {
     81         item->axis[i] = gamepadEvent->axis[i];
     82     }
     83 
     84     for( i = 0; i < item->nbuttons; i++) {
     85         item->analogButton[i] = gamepadEvent->analogButton[i];
     86         item->digitalButton[i] = gamepadEvent->digitalButton[i];
     87     }
     88 
     89     if (SDL_joylist_tail == NULL) {
     90         SDL_joylist = SDL_joylist_tail = item;
     91     } else {
     92         SDL_joylist_tail->next = item;
     93         SDL_joylist_tail = item;
     94     }
     95 
     96     ++numjoysticks;
     97 
     98     SDL_PrivateJoystickAdded(item->device_instance);
     99 
    100 #ifdef DEBUG_JOYSTICK
    101     SDL_Log("Number of joysticks is %d", numjoysticks);
    102 #endif
    103 
    104 #ifdef DEBUG_JOYSTICK
    105     SDL_Log("Added joystick with index %d", item->index);
    106 #endif
    107 
    108     return 1;
    109 }
    110 
    111 static EM_BOOL
    112 Emscripten_JoyStickDisconnected(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData)
    113 {
    114     SDL_joylist_item *item = SDL_joylist;
    115     SDL_joylist_item *prev = NULL;
    116 
    117     while (item != NULL) {
    118         if (item->index == gamepadEvent->index) {
    119             break;
    120         }
    121         prev = item;
    122         item = item->next;
    123     }
    124 
    125     if (item == NULL) {
    126         return 1;
    127     }
    128 
    129     if (item->joystick) {
    130         item->joystick->hwdata = NULL;
    131     }
    132 
    133     if (prev != NULL) {
    134         prev->next = item->next;
    135     } else {
    136         SDL_assert(SDL_joylist == item);
    137         SDL_joylist = item->next;
    138     }
    139     if (item == SDL_joylist_tail) {
    140         SDL_joylist_tail = prev;
    141     }
    142 
    143     /* Need to decrement the joystick count before we post the event */
    144     --numjoysticks;
    145 
    146     SDL_PrivateJoystickRemoved(item->device_instance);
    147 
    148 #ifdef DEBUG_JOYSTICK
    149     SDL_Log("Removed joystick with id %d", item->device_instance);
    150 #endif
    151     SDL_free(item->name);
    152     SDL_free(item->mapping);
    153     SDL_free(item);
    154     return 1;
    155 }
    156 
    157 /* Function to perform any system-specific joystick related cleanup */
    158 static void
    159 EMSCRIPTEN_JoystickQuit(void)
    160 {
    161     SDL_joylist_item *item = NULL;
    162     SDL_joylist_item *next = NULL;
    163 
    164     for (item = SDL_joylist; item; item = next) {
    165         next = item->next;
    166         SDL_free(item->mapping);
    167         SDL_free(item->name);
    168         SDL_free(item);
    169     }
    170 
    171     SDL_joylist = SDL_joylist_tail = NULL;
    172 
    173     numjoysticks = 0;
    174     instance_counter = 0;
    175 
    176     emscripten_set_gamepadconnected_callback(NULL, 0, NULL);
    177     emscripten_set_gamepaddisconnected_callback(NULL, 0, NULL);
    178 }
    179 
    180 /* Function to scan the system for joysticks.
    181  * It should return 0, or -1 on an unrecoverable fatal error.
    182  */
    183 static int
    184 EMSCRIPTEN_JoystickInit(void)
    185 {
    186     int retval, i, numjs;
    187     EmscriptenGamepadEvent gamepadState;
    188 
    189     numjoysticks = 0;
    190 
    191     retval = emscripten_sample_gamepad_data();
    192 
    193     /* Check if gamepad is supported by browser */
    194     if (retval == EMSCRIPTEN_RESULT_NOT_SUPPORTED) {
    195         return SDL_SetError("Gamepads not supported");
    196     }
    197 
    198     numjs = emscripten_get_num_gamepads();
    199 
    200     /* handle already connected gamepads */
    201     if (numjs > 0) {
    202         for(i = 0; i < numjs; i++) {
    203             retval = emscripten_get_gamepad_status(i, &gamepadState);
    204             if (retval == EMSCRIPTEN_RESULT_SUCCESS) {
    205                 Emscripten_JoyStickConnected(EMSCRIPTEN_EVENT_GAMEPADCONNECTED,
    206                                              &gamepadState,
    207                                              NULL);
    208             }
    209         }
    210     }
    211 
    212     retval = emscripten_set_gamepadconnected_callback(NULL,
    213                                                       0,
    214                                                       Emscripten_JoyStickConnected);
    215 
    216     if(retval != EMSCRIPTEN_RESULT_SUCCESS) {
    217         EMSCRIPTEN_JoystickQuit();
    218         return SDL_SetError("Could not set gamepad connect callback");
    219     }
    220 
    221     retval = emscripten_set_gamepaddisconnected_callback(NULL,
    222                                                          0,
    223                                                          Emscripten_JoyStickDisconnected);
    224     if(retval != EMSCRIPTEN_RESULT_SUCCESS) {
    225         EMSCRIPTEN_JoystickQuit();
    226         return SDL_SetError("Could not set gamepad disconnect callback");
    227     }
    228 
    229     return 0;
    230 }
    231 
    232 /* Returns item matching given SDL device index. */
    233 static SDL_joylist_item *
    234 JoystickByDeviceIndex(int device_index)
    235 {
    236     SDL_joylist_item *item = SDL_joylist;
    237 
    238     while (0 < device_index) {
    239         --device_index;
    240         item = item->next;
    241     }
    242 
    243     return item;
    244 }
    245 
    246 /* Returns item matching given HTML gamepad index. */
    247 static SDL_joylist_item *
    248 JoystickByIndex(int index)
    249 {
    250     SDL_joylist_item *item = SDL_joylist;
    251 
    252     if (index < 0) {
    253         return NULL;
    254     }
    255 
    256     while (item != NULL) {
    257         if (item->index == index) {
    258             break;
    259         }
    260         item = item->next;
    261     }
    262 
    263     return item;
    264 }
    265 
    266 static int
    267 EMSCRIPTEN_JoystickGetCount(void)
    268 {
    269     return numjoysticks;
    270 }
    271 
    272 static void
    273 EMSCRIPTEN_JoystickDetect(void)
    274 {
    275 }
    276 
    277 static const char *
    278 EMSCRIPTEN_JoystickGetDeviceName(int device_index)
    279 {
    280     return JoystickByDeviceIndex(device_index)->name;
    281 }
    282 
    283 static int
    284 EMSCRIPTEN_JoystickGetDevicePlayerIndex(int device_index)
    285 {
    286     return -1;
    287 }
    288 
    289 static void
    290 EMSCRIPTEN_JoystickSetDevicePlayerIndex(int device_index, int player_index)
    291 {
    292 }
    293 
    294 static SDL_JoystickID
    295 EMSCRIPTEN_JoystickGetDeviceInstanceID(int device_index)
    296 {
    297     return JoystickByDeviceIndex(device_index)->device_instance;
    298 }
    299 
    300 /* Function to open a joystick for use.
    301    The joystick to open is specified by the device index.
    302    This should fill the nbuttons and naxes fields of the joystick structure.
    303    It returns 0, or -1 if there is an error.
    304  */
    305 static int
    306 EMSCRIPTEN_JoystickOpen(SDL_Joystick *joystick, int device_index)
    307 {
    308     SDL_joylist_item *item = JoystickByDeviceIndex(device_index);
    309 
    310     if (item == NULL ) {
    311         return SDL_SetError("No such device");
    312     }
    313 
    314     if (item->joystick != NULL) {
    315         return SDL_SetError("Joystick already opened");
    316     }
    317 
    318     joystick->instance_id = item->device_instance;
    319     joystick->hwdata = (struct joystick_hwdata *) item;
    320     item->joystick = joystick;
    321 
    322     /* HTML5 Gamepad API doesn't say anything about these */
    323     joystick->nhats = 0;
    324     joystick->nballs = 0;
    325 
    326     joystick->nbuttons = item->nbuttons;
    327     joystick->naxes = item->naxes;
    328 
    329     return (0);
    330 }
    331 
    332 /* Function to update the state of a joystick - called as a device poll.
    333  * This function shouldn't update the joystick structure directly,
    334  * but instead should call SDL_PrivateJoystick*() to deliver events
    335  * and update joystick device state.
    336  */
    337 static void
    338 EMSCRIPTEN_JoystickUpdate(SDL_Joystick *joystick)
    339 {
    340     EmscriptenGamepadEvent gamepadState;
    341     SDL_joylist_item *item = (SDL_joylist_item *) joystick->hwdata;
    342     int i, result, buttonState;
    343 
    344     emscripten_sample_gamepad_data();
    345 
    346     if (item) {
    347         result = emscripten_get_gamepad_status(item->index, &gamepadState);
    348         if( result == EMSCRIPTEN_RESULT_SUCCESS) {
    349             if(gamepadState.timestamp == 0 || gamepadState.timestamp != item->timestamp) {
    350                 for(i = 0; i < item->nbuttons; i++) {
    351                     if(item->digitalButton[i] != gamepadState.digitalButton[i]) {
    352                         buttonState = gamepadState.digitalButton[i]? SDL_PRESSED: SDL_RELEASED;
    353                         SDL_PrivateJoystickButton(item->joystick, i, buttonState);
    354                     }
    355 
    356                     /* store values to compare them in the next update */
    357                     item->analogButton[i] = gamepadState.analogButton[i];
    358                     item->digitalButton[i] = gamepadState.digitalButton[i];
    359                 }
    360 
    361                 for(i = 0; i < item->naxes; i++) {
    362                     if(item->axis[i] != gamepadState.axis[i]) {
    363                         /* do we need to do conversion? */
    364                         SDL_PrivateJoystickAxis(item->joystick, i,
    365                                                   (Sint16) (32767.*gamepadState.axis[i]));
    366                     }
    367 
    368                     /* store to compare in next update */
    369                     item->axis[i] = gamepadState.axis[i];
    370                 }
    371 
    372                 item->timestamp = gamepadState.timestamp;
    373             }
    374         }
    375     }
    376 }
    377 
    378 /* Function to close a joystick after use */
    379 static void
    380 EMSCRIPTEN_JoystickClose(SDL_Joystick *joystick)
    381 {
    382     SDL_joylist_item *item = (SDL_joylist_item *) joystick->hwdata;
    383     if (item) {
    384         item->joystick = NULL;
    385     }
    386 }
    387 
    388 static SDL_JoystickGUID
    389 EMSCRIPTEN_JoystickGetDeviceGUID(int device_index)
    390 {
    391     SDL_JoystickGUID guid;
    392     /* the GUID is just the first 16 chars of the name for now */
    393     const char *name = EMSCRIPTEN_JoystickGetDeviceName(device_index);
    394     SDL_zero(guid);
    395     SDL_memcpy(&guid, name, SDL_min(sizeof(guid), SDL_strlen(name)));
    396     return guid;
    397 }
    398 
    399 static int
    400 EMSCRIPTEN_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
    401 {
    402     return SDL_Unsupported();
    403 }
    404 
    405 static int
    406 EMSCRIPTEN_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)
    407 {
    408     return SDL_Unsupported();
    409 }
    410 
    411 static SDL_bool
    412 EMSCRIPTEN_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out)
    413 {
    414     return SDL_FALSE;
    415 }
    416 
    417 static SDL_bool
    418 EMSCRIPTEN_JoystickHasLED(SDL_Joystick *joystick)
    419 {
    420     return SDL_FALSE;
    421 }
    422 
    423 static int
    424 EMSCRIPTEN_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
    425 {
    426     return SDL_Unsupported();
    427 }
    428 
    429 static int
    430 EMSCRIPTEN_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool enabled)
    431 {
    432     return SDL_Unsupported();
    433 }
    434 
    435 SDL_JoystickDriver SDL_EMSCRIPTEN_JoystickDriver =
    436 {
    437     EMSCRIPTEN_JoystickInit,
    438     EMSCRIPTEN_JoystickGetCount,
    439     EMSCRIPTEN_JoystickDetect,
    440     EMSCRIPTEN_JoystickGetDeviceName,
    441     EMSCRIPTEN_JoystickGetDevicePlayerIndex,
    442     EMSCRIPTEN_JoystickSetDevicePlayerIndex,
    443     EMSCRIPTEN_JoystickGetDeviceGUID,
    444     EMSCRIPTEN_JoystickGetDeviceInstanceID,
    445     EMSCRIPTEN_JoystickOpen,
    446     EMSCRIPTEN_JoystickRumble,
    447     EMSCRIPTEN_JoystickRumbleTriggers,
    448     EMSCRIPTEN_JoystickHasLED,
    449     EMSCRIPTEN_JoystickSetLED,
    450     EMSCRIPTEN_JoystickSetSensorsEnabled,
    451     EMSCRIPTEN_JoystickUpdate,
    452     EMSCRIPTEN_JoystickClose,
    453     EMSCRIPTEN_JoystickQuit,
    454     EMSCRIPTEN_JoystickGetGamepadMapping
    455 };
    456 
    457 #endif /* SDL_JOYSTICK_EMSCRIPTEN */
    458 
    459 /* vi: set ts=4 sw=4 expandtab: */