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