src/joystick/SDL_joystick.c
author Sam Lantinga
Fri, 27 Jan 2017 21:23:27 -0800
changeset 10861 71d8f9afb690
parent 10856 486aa38c6a88
child 10867 a512396c9f3f
permissions -rw-r--r--
Fixed bug 3569 - GL_UpdateViewport leaves PROJECTION matrix selected

Tom Seddon

GL_ActivateRenderer may call GL_UpdateViewport, which leaves the GL_PROJECTION matrix selected. But after GL_ResetState, the GL_MODELVIEW matrix is selected, suggesting that's the intended default state.

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