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