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