src/joystick/SDL_joystick.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 28 Aug 2017 01:42:18 -0700
changeset 11386 d5c2d689bf6d
parent 11284 3db78361e751
child 11512 a1d8a2ce9d01
permissions -rw-r--r--
Fixed build when Wayland is dynamically loaded
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2017 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 #include "../SDL_internal.h"
    22 
    23 /* This is the joystick API for Simple DirectMedia Layer */
    24 
    25 #include "SDL.h"
    26 #include "SDL_events.h"
    27 #include "SDL_sysjoystick.h"
    28 #include "SDL_assert.h"
    29 #include "SDL_hints.h"
    30 
    31 #if !SDL_EVENTS_DISABLED
    32 #include "../events/SDL_events_c.h"
    33 #endif
    34 #include "../video/SDL_sysvideo.h"
    35 
    36 
    37 static SDL_bool SDL_joystick_allows_background_events = SDL_FALSE;
    38 static SDL_Joystick *SDL_joysticks = NULL;
    39 static SDL_bool SDL_updating_joystick = SDL_FALSE;
    40 static SDL_mutex *SDL_joystick_lock = NULL; /* This needs to support recursive locks */
    41 
    42 void
    43 SDL_LockJoystickList(void)
    44 {
    45     if (SDL_joystick_lock) {
    46         SDL_LockMutex(SDL_joystick_lock);
    47     }
    48 }
    49 
    50 void
    51 SDL_UnlockJoystickList(void)
    52 {
    53     if (SDL_joystick_lock) {
    54         SDL_UnlockMutex(SDL_joystick_lock);
    55     }
    56 }
    57 
    58 
    59 static void SDLCALL
    60 SDL_JoystickAllowBackgroundEventsChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
    61 {
    62     if (hint && *hint == '1') {
    63         SDL_joystick_allows_background_events = SDL_TRUE;
    64     } else {
    65         SDL_joystick_allows_background_events = SDL_FALSE;
    66     }
    67 }
    68 
    69 int
    70 SDL_JoystickInit(void)
    71 {
    72     int status;
    73 
    74     SDL_GameControllerInitMappings();
    75 
    76     /* Create the joystick list lock */
    77     if (!SDL_joystick_lock) {
    78         SDL_joystick_lock = SDL_CreateMutex();
    79     }
    80 
    81     /* See if we should allow joystick events while in the background */
    82     SDL_AddHintCallback(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS,
    83                         SDL_JoystickAllowBackgroundEventsChanged, NULL);
    84 
    85 #if !SDL_EVENTS_DISABLED
    86     if (SDL_InitSubSystem(SDL_INIT_EVENTS) < 0) {
    87         return -1;
    88     }
    89 #endif /* !SDL_EVENTS_DISABLED */
    90 
    91     status = SDL_SYS_JoystickInit();
    92     if (status >= 0) {
    93         status = 0;
    94     }
    95     return (status);
    96 }
    97 
    98 /*
    99  * Count the number of joysticks attached to the system
   100  */
   101 int
   102 SDL_NumJoysticks(void)
   103 {
   104     return SDL_SYS_NumJoysticks();
   105 }
   106 
   107 /*
   108  * Get the implementation dependent name of a joystick
   109  */
   110 const char *
   111 SDL_JoystickNameForIndex(int device_index)
   112 {
   113     if (device_index < 0 || device_index >= SDL_NumJoysticks()) {
   114         SDL_SetError("There are %d joysticks available", SDL_NumJoysticks());
   115         return (NULL);
   116     }
   117     return (SDL_SYS_JoystickNameForDeviceIndex(device_index));
   118 }
   119 
   120 /*
   121  * Return true if this joystick is known to have all axes centered at zero
   122  * This isn't generally needed unless the joystick never generates an initial axis value near zero,
   123  * e.g. it's emulating axes with digital buttons
   124  */
   125 static SDL_bool
   126 SDL_JoystickAxesCenteredAtZero(SDL_Joystick *joystick)
   127 {
   128     static Uint32 zero_centered_joysticks[] = {
   129         MAKE_VIDPID(0x0e8f, 0x3013),    /* HuiJia SNES USB adapter */
   130         MAKE_VIDPID(0x05a0, 0x3232),    /* 8Bitdo Zero Gamepad */
   131     };
   132 
   133     int i;
   134     Uint32 id = MAKE_VIDPID(SDL_JoystickGetVendor(joystick),
   135                             SDL_JoystickGetProduct(joystick));
   136 
   137 /*printf("JOYSTICK '%s' VID/PID 0x%.4x/0x%.4x AXES: %d\n", joystick->name, vendor, product, joystick->naxes);*/
   138 
   139     if (joystick->naxes == 2) {
   140         /* Assume D-pad or thumbstick style axes are centered at 0 */
   141         return SDL_TRUE;
   142     }
   143 
   144     for (i = 0; i < SDL_arraysize(zero_centered_joysticks); ++i) {
   145         if (id == zero_centered_joysticks[i]) {
   146             return SDL_TRUE;
   147         }
   148     }
   149     return SDL_FALSE;
   150 }
   151 
   152 /*
   153  * Open a joystick for use - the index passed as an argument refers to
   154  * the N'th joystick on the system.  This index is the value which will
   155  * identify this joystick in future joystick events.
   156  *
   157  * This function returns a joystick identifier, or NULL if an error occurred.
   158  */
   159 SDL_Joystick *
   160 SDL_JoystickOpen(int device_index)
   161 {
   162     SDL_Joystick *joystick;
   163     SDL_Joystick *joysticklist;
   164     const char *joystickname = NULL;
   165 
   166     if ((device_index < 0) || (device_index >= SDL_NumJoysticks())) {
   167         SDL_SetError("There are %d joysticks available", SDL_NumJoysticks());
   168         return (NULL);
   169     }
   170 
   171     SDL_LockJoystickList();
   172 
   173     joysticklist = SDL_joysticks;
   174     /* If the joystick is already open, return it
   175      * it is important that we have a single joystick * for each instance id
   176      */
   177     while (joysticklist) {
   178         if (SDL_JoystickGetDeviceInstanceID(device_index) == joysticklist->instance_id) {
   179                 joystick = joysticklist;
   180                 ++joystick->ref_count;
   181                 SDL_UnlockJoystickList();
   182                 return (joystick);
   183         }
   184         joysticklist = joysticklist->next;
   185     }
   186 
   187     /* Create and initialize the joystick */
   188     joystick = (SDL_Joystick *) SDL_calloc(sizeof(*joystick), 1);
   189     if (joystick == NULL) {
   190         SDL_OutOfMemory();
   191         SDL_UnlockJoystickList();
   192         return NULL;
   193     }
   194 
   195     if (SDL_SYS_JoystickOpen(joystick, device_index) < 0) {
   196         SDL_free(joystick);
   197         SDL_UnlockJoystickList();
   198         return NULL;
   199     }
   200 
   201     joystickname = SDL_SYS_JoystickNameForDeviceIndex(device_index);
   202     if (joystickname)
   203         joystick->name = SDL_strdup(joystickname);
   204     else
   205         joystick->name = NULL;
   206 
   207     if (joystick->naxes > 0) {
   208         joystick->axes = (SDL_JoystickAxisInfo *) SDL_calloc(joystick->naxes, sizeof(SDL_JoystickAxisInfo));
   209     }
   210     if (joystick->nhats > 0) {
   211         joystick->hats = (Uint8 *) SDL_calloc(joystick->nhats, sizeof(Uint8));
   212     }
   213     if (joystick->nballs > 0) {
   214         joystick->balls = (struct balldelta *) SDL_calloc(joystick->nballs, sizeof(*joystick->balls));
   215     }
   216     if (joystick->nbuttons > 0) {
   217         joystick->buttons = (Uint8 *) SDL_calloc(joystick->nbuttons, sizeof(Uint8));
   218     }
   219     if (((joystick->naxes > 0) && !joystick->axes)
   220         || ((joystick->nhats > 0) && !joystick->hats)
   221         || ((joystick->nballs > 0) && !joystick->balls)
   222         || ((joystick->nbuttons > 0) && !joystick->buttons)) {
   223         SDL_OutOfMemory();
   224         SDL_JoystickClose(joystick);
   225         SDL_UnlockJoystickList();
   226         return NULL;
   227     }
   228     joystick->epowerlevel = SDL_JOYSTICK_POWER_UNKNOWN;
   229 
   230     /* If this joystick is known to have all zero centered axes, skip the auto-centering code */
   231     if (SDL_JoystickAxesCenteredAtZero(joystick)) {
   232         int i;
   233 
   234         for (i = 0; i < joystick->naxes; ++i) {
   235             joystick->axes[i].has_initial_value = SDL_TRUE;
   236         }
   237     }
   238 
   239     joystick->is_game_controller = SDL_IsGameController(device_index);
   240 
   241     /* Add joystick to list */
   242     ++joystick->ref_count;
   243     /* Link the joystick in the list */
   244     joystick->next = SDL_joysticks;
   245     SDL_joysticks = joystick;
   246 
   247     SDL_UnlockJoystickList();
   248 
   249     SDL_SYS_JoystickUpdate(joystick);
   250 
   251     return (joystick);
   252 }
   253 
   254 
   255 /*
   256  * Checks to make sure the joystick is valid.
   257  */
   258 int
   259 SDL_PrivateJoystickValid(SDL_Joystick * joystick)
   260 {
   261     int valid;
   262 
   263     if (joystick == NULL) {
   264         SDL_SetError("Joystick hasn't been opened yet");
   265         valid = 0;
   266     } else {
   267         valid = 1;
   268     }
   269 
   270     return valid;
   271 }
   272 
   273 /*
   274  * Get the number of multi-dimensional axis controls on a joystick
   275  */
   276 int
   277 SDL_JoystickNumAxes(SDL_Joystick * joystick)
   278 {
   279     if (!SDL_PrivateJoystickValid(joystick)) {
   280         return (-1);
   281     }
   282     return (joystick->naxes);
   283 }
   284 
   285 /*
   286  * Get the number of hats on a joystick
   287  */
   288 int
   289 SDL_JoystickNumHats(SDL_Joystick * joystick)
   290 {
   291     if (!SDL_PrivateJoystickValid(joystick)) {
   292         return (-1);
   293     }
   294     return (joystick->nhats);
   295 }
   296 
   297 /*
   298  * Get the number of trackballs on a joystick
   299  */
   300 int
   301 SDL_JoystickNumBalls(SDL_Joystick * joystick)
   302 {
   303     if (!SDL_PrivateJoystickValid(joystick)) {
   304         return (-1);
   305     }
   306     return (joystick->nballs);
   307 }
   308 
   309 /*
   310  * Get the number of buttons on a joystick
   311  */
   312 int
   313 SDL_JoystickNumButtons(SDL_Joystick * joystick)
   314 {
   315     if (!SDL_PrivateJoystickValid(joystick)) {
   316         return (-1);
   317     }
   318     return (joystick->nbuttons);
   319 }
   320 
   321 /*
   322  * Get the current state of an axis control on a joystick
   323  */
   324 Sint16
   325 SDL_JoystickGetAxis(SDL_Joystick * joystick, int axis)
   326 {
   327     Sint16 state;
   328 
   329     if (!SDL_PrivateJoystickValid(joystick)) {
   330         return (0);
   331     }
   332     if (axis < joystick->naxes) {
   333         state = joystick->axes[axis].value;
   334     } else {
   335         SDL_SetError("Joystick only has %d axes", joystick->naxes);
   336         state = 0;
   337     }
   338     return (state);
   339 }
   340 
   341 /*
   342  * Get the initial state of an axis control on a joystick
   343  */
   344 SDL_bool
   345 SDL_JoystickGetAxisInitialState(SDL_Joystick * joystick, int axis, Sint16 *state)
   346 {
   347     if (!SDL_PrivateJoystickValid(joystick)) {
   348         return SDL_FALSE;
   349     }
   350     if (axis >= joystick->naxes) {
   351         SDL_SetError("Joystick only has %d axes", joystick->naxes);
   352         return SDL_FALSE;
   353     }
   354     if (state) {
   355         *state = joystick->axes[axis].initial_value;
   356     }
   357     return joystick->axes[axis].has_initial_value;
   358 }
   359 
   360 /*
   361  * Get the current state of a hat on a joystick
   362  */
   363 Uint8
   364 SDL_JoystickGetHat(SDL_Joystick * joystick, int hat)
   365 {
   366     Uint8 state;
   367 
   368     if (!SDL_PrivateJoystickValid(joystick)) {
   369         return (0);
   370     }
   371     if (hat < joystick->nhats) {
   372         state = joystick->hats[hat];
   373     } else {
   374         SDL_SetError("Joystick only has %d hats", joystick->nhats);
   375         state = 0;
   376     }
   377     return (state);
   378 }
   379 
   380 /*
   381  * Get the ball axis change since the last poll
   382  */
   383 int
   384 SDL_JoystickGetBall(SDL_Joystick * joystick, int ball, int *dx, int *dy)
   385 {
   386     int retval;
   387 
   388     if (!SDL_PrivateJoystickValid(joystick)) {
   389         return (-1);
   390     }
   391 
   392     retval = 0;
   393     if (ball < joystick->nballs) {
   394         if (dx) {
   395             *dx = joystick->balls[ball].dx;
   396         }
   397         if (dy) {
   398             *dy = joystick->balls[ball].dy;
   399         }
   400         joystick->balls[ball].dx = 0;
   401         joystick->balls[ball].dy = 0;
   402     } else {
   403         return SDL_SetError("Joystick only has %d balls", joystick->nballs);
   404     }
   405     return (retval);
   406 }
   407 
   408 /*
   409  * Get the current state of a button on a joystick
   410  */
   411 Uint8
   412 SDL_JoystickGetButton(SDL_Joystick * joystick, int button)
   413 {
   414     Uint8 state;
   415 
   416     if (!SDL_PrivateJoystickValid(joystick)) {
   417         return (0);
   418     }
   419     if (button < joystick->nbuttons) {
   420         state = joystick->buttons[button];
   421     } else {
   422         SDL_SetError("Joystick only has %d buttons", joystick->nbuttons);
   423         state = 0;
   424     }
   425     return (state);
   426 }
   427 
   428 /*
   429  * Return if the joystick in question is currently attached to the system,
   430  *  \return SDL_FALSE if not plugged in, SDL_TRUE if still present.
   431  */
   432 SDL_bool
   433 SDL_JoystickGetAttached(SDL_Joystick * joystick)
   434 {
   435     if (!SDL_PrivateJoystickValid(joystick)) {
   436         return SDL_FALSE;
   437     }
   438 
   439     return SDL_SYS_JoystickAttached(joystick);
   440 }
   441 
   442 /*
   443  * Get the instance id for this opened joystick
   444  */
   445 SDL_JoystickID
   446 SDL_JoystickInstanceID(SDL_Joystick * joystick)
   447 {
   448     if (!SDL_PrivateJoystickValid(joystick)) {
   449         return (-1);
   450     }
   451 
   452     return (joystick->instance_id);
   453 }
   454 
   455 /*
   456  * Find the SDL_Joystick that owns this instance id
   457  */
   458 SDL_Joystick *
   459 SDL_JoystickFromInstanceID(SDL_JoystickID joyid)
   460 {
   461     SDL_Joystick *joystick;
   462 
   463     SDL_LockJoystickList();
   464     for (joystick = SDL_joysticks; joystick; joystick = joystick->next) {
   465         if (joystick->instance_id == joyid) {
   466             SDL_UnlockJoystickList();
   467             return joystick;
   468         }
   469     }
   470     SDL_UnlockJoystickList();
   471     return NULL;
   472 }
   473 
   474 /*
   475  * Get the friendly name of this joystick
   476  */
   477 const char *
   478 SDL_JoystickName(SDL_Joystick * joystick)
   479 {
   480     if (!SDL_PrivateJoystickValid(joystick)) {
   481         return (NULL);
   482     }
   483 
   484     return (joystick->name);
   485 }
   486 
   487 /*
   488  * Close a joystick previously opened with SDL_JoystickOpen()
   489  */
   490 void
   491 SDL_JoystickClose(SDL_Joystick * joystick)
   492 {
   493     SDL_Joystick *joysticklist;
   494     SDL_Joystick *joysticklistprev;
   495 
   496     if (!joystick) {
   497         return;
   498     }
   499 
   500     SDL_LockJoystickList();
   501 
   502     /* First decrement ref count */
   503     if (--joystick->ref_count > 0) {
   504         SDL_UnlockJoystickList();
   505         return;
   506     }
   507 
   508     if (SDL_updating_joystick) {
   509         SDL_UnlockJoystickList();
   510         return;
   511     }
   512 
   513     SDL_SYS_JoystickClose(joystick);
   514     joystick->hwdata = NULL;
   515 
   516     joysticklist = SDL_joysticks;
   517     joysticklistprev = NULL;
   518     while (joysticklist) {
   519         if (joystick == joysticklist) {
   520             if (joysticklistprev) {
   521                 /* unlink this entry */
   522                 joysticklistprev->next = joysticklist->next;
   523             } else {
   524                 SDL_joysticks = joystick->next;
   525             }
   526             break;
   527         }
   528         joysticklistprev = joysticklist;
   529         joysticklist = joysticklist->next;
   530     }
   531 
   532     SDL_free(joystick->name);
   533 
   534     /* Free the data associated with this joystick */
   535     SDL_free(joystick->axes);
   536     SDL_free(joystick->hats);
   537     SDL_free(joystick->balls);
   538     SDL_free(joystick->buttons);
   539     SDL_free(joystick);
   540 
   541     SDL_UnlockJoystickList();
   542 }
   543 
   544 void
   545 SDL_JoystickQuit(void)
   546 {
   547     /* Make sure we're not getting called in the middle of updating joysticks */
   548     SDL_assert(!SDL_updating_joystick);
   549 
   550     SDL_LockJoystickList();
   551 
   552     /* Stop the event polling */
   553     while (SDL_joysticks) {
   554         SDL_joysticks->ref_count = 1;
   555         SDL_JoystickClose(SDL_joysticks);
   556     }
   557 
   558     /* Quit the joystick setup */
   559     SDL_SYS_JoystickQuit();
   560 
   561     SDL_UnlockJoystickList();
   562 
   563 #if !SDL_EVENTS_DISABLED
   564     SDL_QuitSubSystem(SDL_INIT_EVENTS);
   565 #endif
   566 
   567     SDL_DelHintCallback(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS,
   568                         SDL_JoystickAllowBackgroundEventsChanged, NULL);
   569 
   570     if (SDL_joystick_lock) {
   571         SDL_DestroyMutex(SDL_joystick_lock);
   572         SDL_joystick_lock = NULL;
   573     }
   574 
   575     SDL_GameControllerQuitMappings();
   576 }
   577 
   578 
   579 static SDL_bool
   580 SDL_PrivateJoystickShouldIgnoreEvent()
   581 {
   582     if (SDL_joystick_allows_background_events) {
   583         return SDL_FALSE;
   584     }
   585 
   586     if (SDL_HasWindows() && SDL_GetKeyboardFocus() == NULL) {
   587         /* We have windows but we don't have focus, ignore the event. */
   588         return SDL_TRUE;
   589     }
   590     return SDL_FALSE;
   591 }
   592 
   593 /* These are global for SDL_sysjoystick.c and SDL_events.c */
   594 
   595 void SDL_PrivateJoystickAdded(int device_index)
   596 {
   597 #if !SDL_EVENTS_DISABLED
   598     SDL_Event event;
   599 
   600     event.type = SDL_JOYDEVICEADDED;
   601 
   602     if (SDL_GetEventState(event.type) == SDL_ENABLE) {
   603         event.jdevice.which = device_index;
   604         if ((SDL_EventOK == NULL) ||
   605              (*SDL_EventOK) (SDL_EventOKParam, &event)) {
   606             SDL_PushEvent(&event);
   607         }
   608     }
   609 #endif /* !SDL_EVENTS_DISABLED */
   610 }
   611 
   612 /*
   613  * If there is an existing add event in the queue, it needs to be modified
   614  * to have the right value for which, because the number of controllers in
   615  * the system is now one less.
   616  */
   617 static void UpdateEventsForDeviceRemoval()
   618 {
   619     int i, num_events;
   620     SDL_Event *events;
   621 
   622     num_events = SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, SDL_JOYDEVICEADDED, SDL_JOYDEVICEADDED);
   623     if (num_events <= 0) {
   624         return;
   625     }
   626 
   627     events = SDL_stack_alloc(SDL_Event, num_events);
   628     if (!events) {
   629         return;
   630     }
   631 
   632     num_events = SDL_PeepEvents(events, num_events, SDL_GETEVENT, SDL_JOYDEVICEADDED, SDL_JOYDEVICEADDED);
   633     for (i = 0; i < num_events; ++i) {
   634         --events[i].jdevice.which;
   635     }
   636     SDL_PeepEvents(events, num_events, SDL_ADDEVENT, 0, 0);
   637 
   638     SDL_stack_free(events);
   639 }
   640 
   641 void SDL_PrivateJoystickRemoved(SDL_JoystickID device_instance)
   642 {
   643 #if !SDL_EVENTS_DISABLED
   644     SDL_Event event;
   645 
   646     event.type = SDL_JOYDEVICEREMOVED;
   647 
   648     if (SDL_GetEventState(event.type) == SDL_ENABLE) {
   649         event.jdevice.which = device_instance;
   650         if ((SDL_EventOK == NULL) ||
   651              (*SDL_EventOK) (SDL_EventOKParam, &event)) {
   652             SDL_PushEvent(&event);
   653         }
   654     }
   655 
   656     UpdateEventsForDeviceRemoval();
   657 #endif /* !SDL_EVENTS_DISABLED */
   658 }
   659 
   660 int
   661 SDL_PrivateJoystickAxis(SDL_Joystick * joystick, Uint8 axis, Sint16 value)
   662 {
   663     int posted;
   664     const int MAX_ALLOWED_JITTER = SDL_JOYSTICK_AXIS_MAX / 80;  /* ShanWan PS3 controller needed 96 */
   665 
   666     /* Make sure we're not getting garbage or duplicate events */
   667     if (axis >= joystick->naxes) {
   668         return 0;
   669     }
   670     if (!joystick->axes[axis].has_initial_value) {
   671         joystick->axes[axis].initial_value = value;
   672         joystick->axes[axis].value = value;
   673         joystick->axes[axis].zero = value;
   674         joystick->axes[axis].has_initial_value = SDL_TRUE;
   675     }
   676     if (SDL_abs(value - joystick->axes[axis].value) <= MAX_ALLOWED_JITTER) {
   677         return 0;
   678     }
   679     if (!joystick->axes[axis].sent_initial_value) {
   680         joystick->axes[axis].sent_initial_value = SDL_TRUE;
   681         joystick->axes[axis].value = value; /* Just so we pass the check above */
   682         SDL_PrivateJoystickAxis(joystick, axis, joystick->axes[axis].initial_value);
   683     }
   684 
   685     /* We ignore events if we don't have keyboard focus, except for centering
   686      * events.
   687      */
   688     if (SDL_PrivateJoystickShouldIgnoreEvent()) {
   689         if ((value > joystick->axes[axis].zero && value >= joystick->axes[axis].value) ||
   690             (value < joystick->axes[axis].zero && value <= joystick->axes[axis].value)) {
   691             return 0;
   692         }
   693     }
   694 
   695     /* Update internal joystick state */
   696     joystick->axes[axis].value = value;
   697 
   698     /* Post the event, if desired */
   699     posted = 0;
   700 #if !SDL_EVENTS_DISABLED
   701     if (SDL_GetEventState(SDL_JOYAXISMOTION) == SDL_ENABLE) {
   702         SDL_Event event;
   703         event.type = SDL_JOYAXISMOTION;
   704         event.jaxis.which = joystick->instance_id;
   705         event.jaxis.axis = axis;
   706         event.jaxis.value = value;
   707         posted = SDL_PushEvent(&event) == 1;
   708     }
   709 #endif /* !SDL_EVENTS_DISABLED */
   710     return (posted);
   711 }
   712 
   713 int
   714 SDL_PrivateJoystickHat(SDL_Joystick * joystick, Uint8 hat, Uint8 value)
   715 {
   716     int posted;
   717 
   718     /* Make sure we're not getting garbage or duplicate events */
   719     if (hat >= joystick->nhats) {
   720         return 0;
   721     }
   722     if (value == joystick->hats[hat]) {
   723         return 0;
   724     }
   725 
   726     /* We ignore events if we don't have keyboard focus, except for centering
   727      * events.
   728      */
   729     if (SDL_PrivateJoystickShouldIgnoreEvent()) {
   730         if (value != SDL_HAT_CENTERED) {
   731             return 0;
   732         }
   733     }
   734 
   735     /* Update internal joystick state */
   736     joystick->hats[hat] = value;
   737 
   738     /* Post the event, if desired */
   739     posted = 0;
   740 #if !SDL_EVENTS_DISABLED
   741     if (SDL_GetEventState(SDL_JOYHATMOTION) == SDL_ENABLE) {
   742         SDL_Event event;
   743         event.jhat.type = SDL_JOYHATMOTION;
   744         event.jhat.which = joystick->instance_id;
   745         event.jhat.hat = hat;
   746         event.jhat.value = value;
   747         posted = SDL_PushEvent(&event) == 1;
   748     }
   749 #endif /* !SDL_EVENTS_DISABLED */
   750     return (posted);
   751 }
   752 
   753 int
   754 SDL_PrivateJoystickBall(SDL_Joystick * joystick, Uint8 ball,
   755                         Sint16 xrel, Sint16 yrel)
   756 {
   757     int posted;
   758 
   759     /* Make sure we're not getting garbage events */
   760     if (ball >= joystick->nballs) {
   761         return 0;
   762     }
   763 
   764     /* We ignore events if we don't have keyboard focus. */
   765     if (SDL_PrivateJoystickShouldIgnoreEvent()) {
   766         return 0;
   767     }
   768 
   769     /* Update internal mouse state */
   770     joystick->balls[ball].dx += xrel;
   771     joystick->balls[ball].dy += yrel;
   772 
   773     /* Post the event, if desired */
   774     posted = 0;
   775 #if !SDL_EVENTS_DISABLED
   776     if (SDL_GetEventState(SDL_JOYBALLMOTION) == SDL_ENABLE) {
   777         SDL_Event event;
   778         event.jball.type = SDL_JOYBALLMOTION;
   779         event.jball.which = joystick->instance_id;
   780         event.jball.ball = ball;
   781         event.jball.xrel = xrel;
   782         event.jball.yrel = yrel;
   783         posted = SDL_PushEvent(&event) == 1;
   784     }
   785 #endif /* !SDL_EVENTS_DISABLED */
   786     return (posted);
   787 }
   788 
   789 int
   790 SDL_PrivateJoystickButton(SDL_Joystick * joystick, Uint8 button, Uint8 state)
   791 {
   792     int posted;
   793 #if !SDL_EVENTS_DISABLED
   794     SDL_Event event;
   795 
   796     switch (state) {
   797     case SDL_PRESSED:
   798         event.type = SDL_JOYBUTTONDOWN;
   799         break;
   800     case SDL_RELEASED:
   801         event.type = SDL_JOYBUTTONUP;
   802         break;
   803     default:
   804         /* Invalid state -- bail */
   805         return (0);
   806     }
   807 #endif /* !SDL_EVENTS_DISABLED */
   808 
   809     /* Make sure we're not getting garbage or duplicate events */
   810     if (button >= joystick->nbuttons) {
   811         return 0;
   812     }
   813     if (state == joystick->buttons[button]) {
   814         return 0;
   815     }
   816 
   817     /* We ignore events if we don't have keyboard focus, except for button
   818      * release. */
   819     if (SDL_PrivateJoystickShouldIgnoreEvent()) {
   820         if (state == SDL_PRESSED) {
   821             return 0;
   822         }
   823     }
   824 
   825     /* Update internal joystick state */
   826     joystick->buttons[button] = state;
   827 
   828     /* Post the event, if desired */
   829     posted = 0;
   830 #if !SDL_EVENTS_DISABLED
   831     if (SDL_GetEventState(event.type) == SDL_ENABLE) {
   832         event.jbutton.which = joystick->instance_id;
   833         event.jbutton.button = button;
   834         event.jbutton.state = state;
   835         posted = SDL_PushEvent(&event) == 1;
   836     }
   837 #endif /* !SDL_EVENTS_DISABLED */
   838     return (posted);
   839 }
   840 
   841 void
   842 SDL_JoystickUpdate(void)
   843 {
   844     SDL_Joystick *joystick;
   845 
   846     SDL_LockJoystickList();
   847 
   848     if (SDL_updating_joystick) {
   849         /* The joysticks are already being updated */
   850         SDL_UnlockJoystickList();
   851         return;
   852     }
   853 
   854     SDL_updating_joystick = SDL_TRUE;
   855 
   856     /* Make sure the list is unlocked while dispatching events to prevent application deadlocks */
   857     SDL_UnlockJoystickList();
   858 
   859     for (joystick = SDL_joysticks; joystick; joystick = joystick->next) {
   860         SDL_SYS_JoystickUpdate(joystick);
   861 
   862         if (joystick->force_recentering) {
   863             int i;
   864 
   865             /* Tell the app that everything is centered/unpressed... */
   866             for (i = 0; i < joystick->naxes; i++) {
   867                 if (joystick->axes[i].has_initial_value) {
   868                     SDL_PrivateJoystickAxis(joystick, i, joystick->axes[i].zero);
   869                 }
   870             }
   871 
   872             for (i = 0; i < joystick->nbuttons; i++) {
   873                 SDL_PrivateJoystickButton(joystick, i, 0);
   874             }
   875 
   876             for (i = 0; i < joystick->nhats; i++) {
   877                 SDL_PrivateJoystickHat(joystick, i, SDL_HAT_CENTERED);
   878             }
   879 
   880             joystick->force_recentering = SDL_FALSE;
   881         }
   882     }
   883 
   884     SDL_LockJoystickList();
   885 
   886     SDL_updating_joystick = SDL_FALSE;
   887 
   888     /* If any joysticks were closed while updating, free them here */
   889     for (joystick = SDL_joysticks; joystick; joystick = joystick->next) {
   890         if (joystick->ref_count <= 0) {
   891             SDL_JoystickClose(joystick);
   892         }
   893     }
   894 
   895     /* this needs to happen AFTER walking the joystick list above, so that any
   896        dangling hardware data from removed devices can be free'd
   897      */
   898     SDL_SYS_JoystickDetect();
   899 
   900     SDL_UnlockJoystickList();
   901 }
   902 
   903 int
   904 SDL_JoystickEventState(int state)
   905 {
   906 #if SDL_EVENTS_DISABLED
   907     return SDL_DISABLE;
   908 #else
   909     const Uint32 event_list[] = {
   910         SDL_JOYAXISMOTION, SDL_JOYBALLMOTION, SDL_JOYHATMOTION,
   911         SDL_JOYBUTTONDOWN, SDL_JOYBUTTONUP, SDL_JOYDEVICEADDED, SDL_JOYDEVICEREMOVED
   912     };
   913     unsigned int i;
   914 
   915     switch (state) {
   916     case SDL_QUERY:
   917         state = SDL_DISABLE;
   918         for (i = 0; i < SDL_arraysize(event_list); ++i) {
   919             state = SDL_EventState(event_list[i], SDL_QUERY);
   920             if (state == SDL_ENABLE) {
   921                 break;
   922             }
   923         }
   924         break;
   925     default:
   926         for (i = 0; i < SDL_arraysize(event_list); ++i) {
   927             SDL_EventState(event_list[i], state);
   928         }
   929         break;
   930     }
   931     return (state);
   932 #endif /* SDL_EVENTS_DISABLED */
   933 }
   934 
   935 void SDL_GetJoystickGUIDInfo(SDL_JoystickGUID guid, Uint16 *vendor, Uint16 *product, Uint16 *version)
   936 {
   937     Uint16 *guid16 = (Uint16 *)guid.data;
   938 
   939     /* If the GUID fits the form of BUS 0000 VENDOR 0000 PRODUCT 0000, return the data */
   940     if (/* guid16[0] is device bus type */
   941         guid16[1] == 0x0000 &&
   942         /* guid16[2] is vendor ID */
   943         guid16[3] == 0x0000 &&
   944         /* guid16[4] is product ID */
   945         guid16[5] == 0x0000
   946         /* guid16[6] is product version */
   947     ) {
   948         if (vendor) {
   949             *vendor = guid16[2];
   950         }
   951         if (product) {
   952             *product = guid16[4];
   953         }
   954         if (version) {
   955             *version = guid16[6];
   956         }
   957     } else {
   958         if (vendor) {
   959             *vendor = 0;
   960         }
   961         if (product) {
   962             *product = 0;
   963         }
   964         if (version) {
   965             *version = 0;
   966         }
   967     }
   968 }
   969 
   970 static SDL_bool SDL_IsJoystickProductWheel(Uint32 vidpid)
   971 {
   972     static Uint32 wheel_joysticks[] = {
   973         MAKE_VIDPID(0x046d, 0xc294),    /* Logitech generic wheel */
   974         MAKE_VIDPID(0x046d, 0xc295),    /* Logitech Momo Force */
   975         MAKE_VIDPID(0x046d, 0xc298),    /* Logitech Driving Force Pro */
   976         MAKE_VIDPID(0x046d, 0xc299),    /* Logitech G25 */
   977         MAKE_VIDPID(0x046d, 0xc29a),    /* Logitech Driving Force GT */
   978         MAKE_VIDPID(0x046d, 0xc29b),    /* Logitech G27 */
   979         MAKE_VIDPID(0x046d, 0xc261),    /* Logitech G920 (initial mode) */
   980         MAKE_VIDPID(0x046d, 0xc262),    /* Logitech G920 (active mode) */
   981         MAKE_VIDPID(0x044f, 0xb65d),    /* Thrustmaster Wheel FFB */
   982         MAKE_VIDPID(0x044f, 0xb66d),    /* Thrustmaster Wheel FFB */
   983         MAKE_VIDPID(0x044f, 0xb677),    /* Thrustmaster T150 */
   984         MAKE_VIDPID(0x044f, 0xb664),    /* Thrustmaster TX (initial mode) */
   985         MAKE_VIDPID(0x044f, 0xb669),    /* Thrustmaster TX (active mode) */
   986     };
   987     int i;
   988 
   989     for (i = 0; i < SDL_arraysize(wheel_joysticks); ++i) {
   990         if (vidpid == wheel_joysticks[i]) {
   991             return SDL_TRUE;
   992         }
   993     }
   994     return SDL_FALSE;
   995 }
   996 
   997 static SDL_bool SDL_IsJoystickProductFlightStick(Uint32 vidpid)
   998 {
   999     static Uint32 flightstick_joysticks[] = {
  1000         MAKE_VIDPID(0x044f, 0x0402),    /* HOTAS Warthog Joystick */
  1001         MAKE_VIDPID(0x0738, 0x2221),    /* Saitek Pro Flight X-56 Rhino Stick */
  1002     };
  1003     int i;
  1004 
  1005     for (i = 0; i < SDL_arraysize(flightstick_joysticks); ++i) {
  1006         if (vidpid == flightstick_joysticks[i]) {
  1007             return SDL_TRUE;
  1008         }
  1009     }
  1010     return SDL_FALSE;
  1011 }
  1012 
  1013 static SDL_bool SDL_IsJoystickProductThrottle(Uint32 vidpid)
  1014 {
  1015     static Uint32 throttle_joysticks[] = {
  1016         MAKE_VIDPID(0x044f, 0x0404),    /* HOTAS Warthog Throttle */
  1017         MAKE_VIDPID(0x0738, 0xa221),    /* Saitek Pro Flight X-56 Rhino Throttle */
  1018     };
  1019     int i;
  1020 
  1021     for (i = 0; i < SDL_arraysize(throttle_joysticks); ++i) {
  1022         if (vidpid == throttle_joysticks[i]) {
  1023             return SDL_TRUE;
  1024         }
  1025     }
  1026     return SDL_FALSE;
  1027 }
  1028 
  1029 static SDL_JoystickType SDL_GetJoystickGUIDType(SDL_JoystickGUID guid)
  1030 {
  1031     Uint16 vendor;
  1032     Uint16 product;
  1033     Uint32 vidpid;
  1034 
  1035     if (guid.data[14] == 'x') {
  1036         /* XInput GUID, get the type based on the XInput device subtype */
  1037         switch (guid.data[15]) {
  1038         case 0x01:  /* XINPUT_DEVSUBTYPE_GAMEPAD */
  1039             return SDL_JOYSTICK_TYPE_GAMECONTROLLER;
  1040         case 0x02:  /* XINPUT_DEVSUBTYPE_WHEEL */
  1041             return SDL_JOYSTICK_TYPE_WHEEL;
  1042         case 0x03:  /* XINPUT_DEVSUBTYPE_ARCADE_STICK */
  1043             return SDL_JOYSTICK_TYPE_ARCADE_STICK;
  1044         case 0x04:  /* XINPUT_DEVSUBTYPE_FLIGHT_STICK */
  1045             return SDL_JOYSTICK_TYPE_FLIGHT_STICK;
  1046         case 0x05:  /* XINPUT_DEVSUBTYPE_DANCE_PAD */
  1047             return SDL_JOYSTICK_TYPE_DANCE_PAD;
  1048         case 0x06:  /* XINPUT_DEVSUBTYPE_GUITAR */
  1049         case 0x07:  /* XINPUT_DEVSUBTYPE_GUITAR_ALTERNATE */
  1050         case 0x0B:  /* XINPUT_DEVSUBTYPE_GUITAR_BASS */
  1051             return SDL_JOYSTICK_TYPE_GUITAR;
  1052         case 0x08:  /* XINPUT_DEVSUBTYPE_DRUM_KIT */
  1053             return SDL_JOYSTICK_TYPE_DRUM_KIT;
  1054         case 0x13:  /* XINPUT_DEVSUBTYPE_ARCADE_PAD */
  1055             return SDL_JOYSTICK_TYPE_ARCADE_PAD;
  1056         default:
  1057             return SDL_JOYSTICK_TYPE_UNKNOWN;
  1058         }
  1059     }
  1060 
  1061     SDL_GetJoystickGUIDInfo(guid, &vendor, &product, NULL);
  1062     vidpid = MAKE_VIDPID(vendor, product);
  1063 
  1064     if (SDL_IsJoystickProductWheel(vidpid)) {
  1065         return SDL_JOYSTICK_TYPE_WHEEL;
  1066     }
  1067 
  1068     if (SDL_IsJoystickProductFlightStick(vidpid)) {
  1069         return SDL_JOYSTICK_TYPE_FLIGHT_STICK;
  1070     }
  1071 
  1072     if (SDL_IsJoystickProductThrottle(vidpid)) {
  1073         return SDL_JOYSTICK_TYPE_THROTTLE;
  1074     }
  1075 
  1076     return SDL_JOYSTICK_TYPE_UNKNOWN;
  1077 }
  1078 
  1079 /* return the guid for this index */
  1080 SDL_JoystickGUID SDL_JoystickGetDeviceGUID(int device_index)
  1081 {
  1082     if (device_index < 0 || device_index >= SDL_NumJoysticks()) {
  1083         SDL_JoystickGUID emptyGUID;
  1084         SDL_SetError("There are %d joysticks available", SDL_NumJoysticks());
  1085         SDL_zero(emptyGUID);
  1086         return emptyGUID;
  1087     }
  1088     return SDL_SYS_JoystickGetDeviceGUID(device_index);
  1089 }
  1090 
  1091 Uint16 SDL_JoystickGetDeviceVendor(int device_index)
  1092 {
  1093     Uint16 vendor;
  1094     SDL_JoystickGUID guid = SDL_JoystickGetDeviceGUID(device_index);
  1095 
  1096     SDL_GetJoystickGUIDInfo(guid, &vendor, NULL, NULL);
  1097     return vendor;
  1098 }
  1099 
  1100 Uint16 SDL_JoystickGetDeviceProduct(int device_index)
  1101 {
  1102     Uint16 product;
  1103     SDL_JoystickGUID guid = SDL_JoystickGetDeviceGUID(device_index);
  1104 
  1105     SDL_GetJoystickGUIDInfo(guid, NULL, &product, NULL);
  1106     return product;
  1107 }
  1108 
  1109 Uint16 SDL_JoystickGetDeviceProductVersion(int device_index)
  1110 {
  1111     Uint16 version;
  1112     SDL_JoystickGUID guid = SDL_JoystickGetDeviceGUID(device_index);
  1113 
  1114     SDL_GetJoystickGUIDInfo(guid, NULL, NULL, &version);
  1115     return version;
  1116 }
  1117 
  1118 SDL_JoystickType SDL_JoystickGetDeviceType(int device_index)
  1119 {
  1120     SDL_JoystickType type;
  1121     SDL_JoystickGUID guid = SDL_JoystickGetDeviceGUID(device_index);
  1122 
  1123     type = SDL_GetJoystickGUIDType(guid);
  1124     if (type == SDL_JOYSTICK_TYPE_UNKNOWN) {
  1125         if (SDL_IsGameController(device_index)) {
  1126             type = SDL_JOYSTICK_TYPE_GAMECONTROLLER;
  1127         }
  1128     }
  1129     return type;
  1130 }
  1131 
  1132 SDL_JoystickID SDL_JoystickGetDeviceInstanceID(int device_index)
  1133 {
  1134     if (device_index < 0 || device_index >= SDL_NumJoysticks()) {
  1135         SDL_SetError("There are %d joysticks available", SDL_NumJoysticks());
  1136         return -1;
  1137     }
  1138     return SDL_SYS_GetInstanceIdOfDeviceIndex(device_index);
  1139 }
  1140 
  1141 SDL_JoystickGUID SDL_JoystickGetGUID(SDL_Joystick * joystick)
  1142 {
  1143     if (!SDL_PrivateJoystickValid(joystick)) {
  1144         SDL_JoystickGUID emptyGUID;
  1145         SDL_zero(emptyGUID);
  1146         return emptyGUID;
  1147     }
  1148     return SDL_SYS_JoystickGetGUID(joystick);
  1149 }
  1150 
  1151 Uint16 SDL_JoystickGetVendor(SDL_Joystick * joystick)
  1152 {
  1153     Uint16 vendor;
  1154     SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
  1155 
  1156     SDL_GetJoystickGUIDInfo(guid, &vendor, NULL, NULL);
  1157     return vendor;
  1158 }
  1159 
  1160 Uint16 SDL_JoystickGetProduct(SDL_Joystick * joystick)
  1161 {
  1162     Uint16 product;
  1163     SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
  1164 
  1165     SDL_GetJoystickGUIDInfo(guid, NULL, &product, NULL);
  1166     return product;
  1167 }
  1168 
  1169 Uint16 SDL_JoystickGetProductVersion(SDL_Joystick * joystick)
  1170 {
  1171     Uint16 version;
  1172     SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
  1173 
  1174     SDL_GetJoystickGUIDInfo(guid, NULL, NULL, &version);
  1175     return version;
  1176 }
  1177 
  1178 SDL_JoystickType SDL_JoystickGetType(SDL_Joystick * joystick)
  1179 {
  1180     SDL_JoystickType type;
  1181     SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
  1182 
  1183     type = SDL_GetJoystickGUIDType(guid);
  1184     if (type == SDL_JOYSTICK_TYPE_UNKNOWN) {
  1185         if (joystick && joystick->is_game_controller) {
  1186             type = SDL_JOYSTICK_TYPE_GAMECONTROLLER;
  1187         }
  1188     }
  1189     return type;
  1190 }
  1191 
  1192 /* convert the guid to a printable string */
  1193 void SDL_JoystickGetGUIDString(SDL_JoystickGUID guid, char *pszGUID, int cbGUID)
  1194 {
  1195     static const char k_rgchHexToASCII[] = "0123456789abcdef";
  1196     int i;
  1197 
  1198     if ((pszGUID == NULL) || (cbGUID <= 0)) {
  1199         return;
  1200     }
  1201 
  1202     for (i = 0; i < sizeof(guid.data) && i < (cbGUID-1)/2; i++) {
  1203         /* each input byte writes 2 ascii chars, and might write a null byte. */
  1204         /* If we don't have room for next input byte, stop */
  1205         unsigned char c = guid.data[i];
  1206 
  1207         *pszGUID++ = k_rgchHexToASCII[c >> 4];
  1208         *pszGUID++ = k_rgchHexToASCII[c & 0x0F];
  1209     }
  1210     *pszGUID = '\0';
  1211 }
  1212 
  1213 
  1214 /*-----------------------------------------------------------------------------
  1215  * Purpose: Returns the 4 bit nibble for a hex character
  1216  * Input  : c -
  1217  * Output : unsigned char
  1218  *-----------------------------------------------------------------------------*/
  1219 static unsigned char nibble(char c)
  1220 {
  1221     if ((c >= '0') && (c <= '9')) {
  1222         return (unsigned char)(c - '0');
  1223     }
  1224 
  1225     if ((c >= 'A') && (c <= 'F')) {
  1226         return (unsigned char)(c - 'A' + 0x0a);
  1227     }
  1228 
  1229     if ((c >= 'a') && (c <= 'f')) {
  1230         return (unsigned char)(c - 'a' + 0x0a);
  1231     }
  1232 
  1233     /* received an invalid character, and no real way to return an error */
  1234     /* AssertMsg1(false, "Q_nibble invalid hex character '%c' ", c); */
  1235     return 0;
  1236 }
  1237 
  1238 
  1239 /* convert the string version of a joystick guid to the struct */
  1240 SDL_JoystickGUID SDL_JoystickGetGUIDFromString(const char *pchGUID)
  1241 {
  1242     SDL_JoystickGUID guid;
  1243     int maxoutputbytes= sizeof(guid);
  1244     size_t len = SDL_strlen(pchGUID);
  1245     Uint8 *p;
  1246     size_t i;
  1247 
  1248     /* Make sure it's even */
  1249     len = (len) & ~0x1;
  1250 
  1251     SDL_memset(&guid, 0x00, sizeof(guid));
  1252 
  1253     p = (Uint8 *)&guid;
  1254     for (i = 0; (i < len) && ((p - (Uint8 *)&guid) < maxoutputbytes); i+=2, p++) {
  1255         *p = (nibble(pchGUID[i]) << 4) | nibble(pchGUID[i+1]);
  1256     }
  1257 
  1258     return guid;
  1259 }
  1260 
  1261 
  1262 /* update the power level for this joystick */
  1263 void SDL_PrivateJoystickBatteryLevel(SDL_Joystick * joystick, SDL_JoystickPowerLevel ePowerLevel)
  1264 {
  1265     joystick->epowerlevel = ePowerLevel;
  1266 }
  1267 
  1268 
  1269 /* return its power level */
  1270 SDL_JoystickPowerLevel SDL_JoystickCurrentPowerLevel(SDL_Joystick * joystick)
  1271 {
  1272     if (!SDL_PrivateJoystickValid(joystick)) {
  1273         return (SDL_JOYSTICK_POWER_UNKNOWN);
  1274     }
  1275     return joystick->epowerlevel;
  1276 }
  1277 
  1278 /* vi: set ts=4 sw=4 expandtab: */