src/joystick/SDL_joystick.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 28 Aug 2017 01:42:18 -0700
changeset 11386 d5c2d689bf6d
parent 11284 3db78361e751
child 11512 a1d8a2ce9d01
permissions -rw-r--r--
Fixed build when Wayland is dynamically loaded
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@11255
    34
#include "../video/SDL_sysvideo.h"
slouken@0
    35
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@11284
    59
static void SDLCALL
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@11201
    74
    SDL_GameControllerInitMappings();
slouken@11201
    75
slouken@10659
    76
    /* Create the joystick list lock */
slouken@10659
    77
    if (!SDL_joystick_lock) {
slouken@10659
    78
        SDL_joystick_lock = SDL_CreateMutex();
slouken@10659
    79
    }
slouken@10659
    80
slouken@7432
    81
    /* See if we should allow joystick events while in the background */
slouken@7432
    82
    SDL_AddHintCallback(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS,
slouken@7432
    83
                        SDL_JoystickAllowBackgroundEventsChanged, NULL);
slouken@0
    84
slouken@7360
    85
#if !SDL_EVENTS_DISABLED
slouken@7360
    86
    if (SDL_InitSubSystem(SDL_INIT_EVENTS) < 0) {
slouken@7360
    87
        return -1;
slouken@7360
    88
    }
slouken@7360
    89
#endif /* !SDL_EVENTS_DISABLED */
slouken@7360
    90
slouken@1895
    91
    status = SDL_SYS_JoystickInit();
slouken@1895
    92
    if (status >= 0) {
slouken@7337
    93
        status = 0;
slouken@1895
    94
    }
slouken@1895
    95
    return (status);
slouken@0
    96
}
slouken@0
    97
slouken@0
    98
/*
slouken@0
    99
 * Count the number of joysticks attached to the system
slouken@0
   100
 */
slouken@1895
   101
int
slouken@1895
   102
SDL_NumJoysticks(void)
slouken@0
   103
{
slouken@6690
   104
    return SDL_SYS_NumJoysticks();
slouken@0
   105
}
slouken@0
   106
slouken@0
   107
/*
slouken@0
   108
 * Get the implementation dependent name of a joystick
slouken@0
   109
 */
slouken@1895
   110
const char *
slouken@6690
   111
SDL_JoystickNameForIndex(int device_index)
slouken@0
   112
{
slouken@10934
   113
    if (device_index < 0 || device_index >= SDL_NumJoysticks()) {
slouken@6690
   114
        SDL_SetError("There are %d joysticks available", SDL_NumJoysticks());
slouken@1895
   115
        return (NULL);
slouken@1895
   116
    }
slouken@6707
   117
    return (SDL_SYS_JoystickNameForDeviceIndex(device_index));
slouken@0
   118
}
slouken@0
   119
slouken@0
   120
/*
slouken@10745
   121
 * Return true if this joystick is known to have all axes centered at zero
slouken@10745
   122
 * This isn't generally needed unless the joystick never generates an initial axis value near zero,
slouken@10745
   123
 * e.g. it's emulating axes with digital buttons
slouken@10745
   124
 */
slouken@10745
   125
static SDL_bool
slouken@10745
   126
SDL_JoystickAxesCenteredAtZero(SDL_Joystick *joystick)
slouken@10745
   127
{
slouken@10855
   128
    static Uint32 zero_centered_joysticks[] = {
slouken@10855
   129
        MAKE_VIDPID(0x0e8f, 0x3013),    /* HuiJia SNES USB adapter */
slouken@10855
   130
        MAKE_VIDPID(0x05a0, 0x3232),    /* 8Bitdo Zero Gamepad */
slouken@10745
   131
    };
slouken@10745
   132
slouken@10745
   133
    int i;
slouken@10855
   134
    Uint32 id = MAKE_VIDPID(SDL_JoystickGetVendor(joystick),
slouken@10855
   135
                            SDL_JoystickGetProduct(joystick));
slouken@10745
   136
slouken@10823
   137
/*printf("JOYSTICK '%s' VID/PID 0x%.4x/0x%.4x AXES: %d\n", joystick->name, vendor, product, joystick->naxes);*/
slouken@10823
   138
slouken@10751
   139
    if (joystick->naxes == 2) {
slouken@10751
   140
        /* Assume D-pad or thumbstick style axes are centered at 0 */
slouken@10751
   141
        return SDL_TRUE;
slouken@10751
   142
    }
slouken@10751
   143
slouken@10745
   144
    for (i = 0; i < SDL_arraysize(zero_centered_joysticks); ++i) {
slouken@10855
   145
        if (id == zero_centered_joysticks[i]) {
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@10934
   175
     * it is important that we have a single joystick * for each instance id
slouken@10934
   176
     */
slouken@8920
   177
    while (joysticklist) {
slouken@10934
   178
        if (SDL_JoystickGetDeviceInstanceID(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@10855
   188
    joystick = (SDL_Joystick *) SDL_calloc(sizeof(*joystick), 1);
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
slouken@6690
   195
    if (SDL_SYS_JoystickOpen(joystick, device_index) < 0) {
icculus@3608
   196
        SDL_free(joystick);
slouken@10659
   197
        SDL_UnlockJoystickList();
icculus@3608
   198
        return NULL;
icculus@3608
   199
    }
slouken@6690
   200
slouken@8920
   201
    joystickname = SDL_SYS_JoystickNameForDeviceIndex(device_index);
slouken@8920
   202
    if (joystickname)
slouken@8920
   203
        joystick->name = SDL_strdup(joystickname);
slouken@7191
   204
    else
slouken@7191
   205
        joystick->name = NULL;
slouken@6690
   206
icculus@3608
   207
    if (joystick->naxes > 0) {
slouken@10713
   208
        joystick->axes = (SDL_JoystickAxisInfo *) SDL_calloc(joystick->naxes, sizeof(SDL_JoystickAxisInfo));
icculus@3608
   209
    }
icculus@3608
   210
    if (joystick->nhats > 0) {
slouken@10713
   211
        joystick->hats = (Uint8 *) SDL_calloc(joystick->nhats, sizeof(Uint8));
icculus@3608
   212
    }
icculus@3608
   213
    if (joystick->nballs > 0) {
slouken@10713
   214
        joystick->balls = (struct balldelta *) SDL_calloc(joystick->nballs, sizeof(*joystick->balls));
icculus@3608
   215
    }
icculus@3608
   216
    if (joystick->nbuttons > 0) {
slouken@10713
   217
        joystick->buttons = (Uint8 *) SDL_calloc(joystick->nbuttons, sizeof(Uint8));
slouken@1895
   218
    }
icculus@3608
   219
    if (((joystick->naxes > 0) && !joystick->axes)
icculus@3608
   220
        || ((joystick->nhats > 0) && !joystick->hats)
icculus@3608
   221
        || ((joystick->nballs > 0) && !joystick->balls)
icculus@3608
   222
        || ((joystick->nbuttons > 0) && !joystick->buttons)) {
icculus@3608
   223
        SDL_OutOfMemory();
icculus@3608
   224
        SDL_JoystickClose(joystick);
slouken@10659
   225
        SDL_UnlockJoystickList();
icculus@3608
   226
        return NULL;
icculus@3608
   227
    }
slouken@9884
   228
    joystick->epowerlevel = SDL_JOYSTICK_POWER_UNKNOWN;
icculus@3608
   229
slouken@10745
   230
    /* If this joystick is known to have all zero centered axes, skip the auto-centering code */
slouken@10745
   231
    if (SDL_JoystickAxesCenteredAtZero(joystick)) {
slouken@10745
   232
        int i;
slouken@10745
   233
slouken@10745
   234
        for (i = 0; i < joystick->naxes; ++i) {
slouken@10745
   235
            joystick->axes[i].has_initial_value = SDL_TRUE;
slouken@10745
   236
        }
slouken@10745
   237
    }
slouken@10745
   238
slouken@10855
   239
    joystick->is_game_controller = SDL_IsGameController(device_index);
slouken@10855
   240
icculus@3608
   241
    /* Add joystick to list */
icculus@3608
   242
    ++joystick->ref_count;
slouken@7191
   243
    /* Link the joystick in the list */
slouken@7191
   244
    joystick->next = SDL_joysticks;
slouken@7191
   245
    SDL_joysticks = joystick;
slouken@6690
   246
slouken@10688
   247
    SDL_UnlockJoystickList();
icculus@3608
   248
slouken@10688
   249
    SDL_SYS_JoystickUpdate(joystick);
slouken@10659
   250
slouken@1895
   251
    return (joystick);
slouken@0
   252
}
slouken@0
   253
slouken@2713
   254
slouken@2713
   255
/*
slouken@2713
   256
 * Checks to make sure the joystick is valid.
slouken@2713
   257
 */
slouken@2713
   258
int
slouken@6690
   259
SDL_PrivateJoystickValid(SDL_Joystick * joystick)
slouken@0
   260
{
slouken@1895
   261
    int valid;
slouken@0
   262
slouken@8920
   263
    if (joystick == NULL) {
slouken@1895
   264
        SDL_SetError("Joystick hasn't been opened yet");
slouken@1895
   265
        valid = 0;
slouken@1895
   266
    } else {
slouken@1895
   267
        valid = 1;
slouken@1895
   268
    }
slouken@7191
   269
slouken@1895
   270
    return valid;
slouken@0
   271
}
slouken@0
   272
slouken@0
   273
/*
slouken@0
   274
 * Get the number of multi-dimensional axis controls on a joystick
slouken@0
   275
 */
slouken@1895
   276
int
slouken@1895
   277
SDL_JoystickNumAxes(SDL_Joystick * joystick)
slouken@0
   278
{
slouken@6690
   279
    if (!SDL_PrivateJoystickValid(joystick)) {
slouken@1895
   280
        return (-1);
slouken@1895
   281
    }
slouken@1895
   282
    return (joystick->naxes);
slouken@0
   283
}
slouken@0
   284
slouken@0
   285
/*
slouken@0
   286
 * Get the number of hats on a joystick
slouken@0
   287
 */
slouken@1895
   288
int
slouken@1895
   289
SDL_JoystickNumHats(SDL_Joystick * joystick)
slouken@0
   290
{
slouken@6690
   291
    if (!SDL_PrivateJoystickValid(joystick)) {
slouken@1895
   292
        return (-1);
slouken@1895
   293
    }
slouken@1895
   294
    return (joystick->nhats);
slouken@0
   295
}
slouken@0
   296
slouken@0
   297
/*
slouken@0
   298
 * Get the number of trackballs on a joystick
slouken@0
   299
 */
slouken@1895
   300
int
slouken@1895
   301
SDL_JoystickNumBalls(SDL_Joystick * joystick)
slouken@0
   302
{
slouken@6690
   303
    if (!SDL_PrivateJoystickValid(joystick)) {
slouken@1895
   304
        return (-1);
slouken@1895
   305
    }
slouken@1895
   306
    return (joystick->nballs);
slouken@0
   307
}
slouken@0
   308
slouken@0
   309
/*
slouken@0
   310
 * Get the number of buttons on a joystick
slouken@0
   311
 */
slouken@1895
   312
int
slouken@1895
   313
SDL_JoystickNumButtons(SDL_Joystick * joystick)
slouken@0
   314
{
slouken@6690
   315
    if (!SDL_PrivateJoystickValid(joystick)) {
slouken@1895
   316
        return (-1);
slouken@1895
   317
    }
slouken@1895
   318
    return (joystick->nbuttons);
slouken@0
   319
}
slouken@0
   320
slouken@0
   321
/*
slouken@0
   322
 * Get the current state of an axis control on a joystick
slouken@0
   323
 */
slouken@1895
   324
Sint16
slouken@1895
   325
SDL_JoystickGetAxis(SDL_Joystick * joystick, int axis)
slouken@0
   326
{
slouken@1895
   327
    Sint16 state;
slouken@0
   328
slouken@6690
   329
    if (!SDL_PrivateJoystickValid(joystick)) {
slouken@1895
   330
        return (0);
slouken@1895
   331
    }
slouken@1895
   332
    if (axis < joystick->naxes) {
slouken@10713
   333
        state = joystick->axes[axis].value;
slouken@1895
   334
    } else {
slouken@1895
   335
        SDL_SetError("Joystick only has %d axes", joystick->naxes);
slouken@1895
   336
        state = 0;
slouken@1895
   337
    }
slouken@1895
   338
    return (state);
slouken@0
   339
}
slouken@0
   340
slouken@0
   341
/*
slouken@10752
   342
 * Get the initial state of an axis control on a joystick
slouken@10752
   343
 */
slouken@10752
   344
SDL_bool
slouken@10752
   345
SDL_JoystickGetAxisInitialState(SDL_Joystick * joystick, int axis, Sint16 *state)
slouken@10752
   346
{
slouken@10752
   347
    if (!SDL_PrivateJoystickValid(joystick)) {
slouken@10752
   348
        return SDL_FALSE;
slouken@10752
   349
    }
slouken@10752
   350
    if (axis >= joystick->naxes) {
slouken@10752
   351
        SDL_SetError("Joystick only has %d axes", joystick->naxes);
slouken@10752
   352
        return SDL_FALSE;
slouken@10752
   353
    }
slouken@10752
   354
    if (state) {
slouken@10752
   355
        *state = joystick->axes[axis].initial_value;
slouken@10752
   356
    }
slouken@10752
   357
    return joystick->axes[axis].has_initial_value;
slouken@10752
   358
}
slouken@10752
   359
slouken@10752
   360
/*
slouken@0
   361
 * Get the current state of a hat on a joystick
slouken@0
   362
 */
slouken@1895
   363
Uint8
slouken@1895
   364
SDL_JoystickGetHat(SDL_Joystick * joystick, int hat)
slouken@0
   365
{
slouken@1895
   366
    Uint8 state;
slouken@0
   367
slouken@6690
   368
    if (!SDL_PrivateJoystickValid(joystick)) {
slouken@1895
   369
        return (0);
slouken@1895
   370
    }
slouken@1895
   371
    if (hat < joystick->nhats) {
slouken@1895
   372
        state = joystick->hats[hat];
slouken@1895
   373
    } else {
slouken@1895
   374
        SDL_SetError("Joystick only has %d hats", joystick->nhats);
slouken@1895
   375
        state = 0;
slouken@1895
   376
    }
slouken@1895
   377
    return (state);
slouken@0
   378
}
slouken@0
   379
slouken@0
   380
/*
slouken@0
   381
 * Get the ball axis change since the last poll
slouken@0
   382
 */
slouken@1895
   383
int
slouken@1895
   384
SDL_JoystickGetBall(SDL_Joystick * joystick, int ball, int *dx, int *dy)
slouken@0
   385
{
slouken@1895
   386
    int retval;
slouken@0
   387
slouken@6690
   388
    if (!SDL_PrivateJoystickValid(joystick)) {
slouken@1895
   389
        return (-1);
slouken@1895
   390
    }
slouken@0
   391
slouken@1895
   392
    retval = 0;
slouken@1895
   393
    if (ball < joystick->nballs) {
slouken@1895
   394
        if (dx) {
slouken@1895
   395
            *dx = joystick->balls[ball].dx;
slouken@1895
   396
        }
slouken@1895
   397
        if (dy) {
slouken@1895
   398
            *dy = joystick->balls[ball].dy;
slouken@1895
   399
        }
slouken@1895
   400
        joystick->balls[ball].dx = 0;
slouken@1895
   401
        joystick->balls[ball].dy = 0;
slouken@1895
   402
    } else {
icculus@7037
   403
        return SDL_SetError("Joystick only has %d balls", joystick->nballs);
slouken@1895
   404
    }
slouken@1895
   405
    return (retval);
slouken@0
   406
}
slouken@0
   407
slouken@0
   408
/*
slouken@0
   409
 * Get the current state of a button on a joystick
slouken@0
   410
 */
slouken@1895
   411
Uint8
slouken@1895
   412
SDL_JoystickGetButton(SDL_Joystick * joystick, int button)
slouken@0
   413
{
slouken@1895
   414
    Uint8 state;
slouken@0
   415
slouken@6690
   416
    if (!SDL_PrivateJoystickValid(joystick)) {
slouken@1895
   417
        return (0);
slouken@1895
   418
    }
slouken@1895
   419
    if (button < joystick->nbuttons) {
slouken@1895
   420
        state = joystick->buttons[button];
slouken@1895
   421
    } else {
slouken@1895
   422
        SDL_SetError("Joystick only has %d buttons", joystick->nbuttons);
slouken@1895
   423
        state = 0;
slouken@1895
   424
    }
slouken@1895
   425
    return (state);
slouken@0
   426
}
slouken@0
   427
slouken@0
   428
/*
slouken@6690
   429
 * Return if the joystick in question is currently attached to the system,
philipp@7500
   430
 *  \return SDL_FALSE if not plugged in, SDL_TRUE if still present.
slouken@6690
   431
 */
slouken@6707
   432
SDL_bool
slouken@6707
   433
SDL_JoystickGetAttached(SDL_Joystick * joystick)
slouken@6690
   434
{
slouken@7191
   435
    if (!SDL_PrivateJoystickValid(joystick)) {
slouken@6707
   436
        return SDL_FALSE;
slouken@6690
   437
    }
slouken@6690
   438
slouken@7191
   439
    return SDL_SYS_JoystickAttached(joystick);
slouken@6690
   440
}
slouken@6690
   441
slouken@6690
   442
/*
slouken@6690
   443
 * Get the instance id for this opened joystick
slouken@6690
   444
 */
slouken@7191
   445
SDL_JoystickID
slouken@6707
   446
SDL_JoystickInstanceID(SDL_Joystick * joystick)
slouken@6690
   447
{
slouken@7191
   448
    if (!SDL_PrivateJoystickValid(joystick)) {
slouken@6690
   449
        return (-1);
slouken@6690
   450
    }
slouken@6690
   451
slouken@7191
   452
    return (joystick->instance_id);
slouken@6690
   453
}
slouken@6690
   454
slouken@6690
   455
/*
icculus@9916
   456
 * Find the SDL_Joystick that owns this instance id
icculus@9916
   457
 */
icculus@9916
   458
SDL_Joystick *
icculus@9916
   459
SDL_JoystickFromInstanceID(SDL_JoystickID joyid)
icculus@9916
   460
{
slouken@10659
   461
    SDL_Joystick *joystick;
slouken@10659
   462
slouken@10659
   463
    SDL_LockJoystickList();
slouken@10659
   464
    for (joystick = SDL_joysticks; joystick; joystick = joystick->next) {
icculus@9916
   465
        if (joystick->instance_id == joyid) {
slouken@10659
   466
            SDL_UnlockJoystickList();
icculus@9916
   467
            return joystick;
icculus@9916
   468
        }
icculus@9916
   469
    }
slouken@10659
   470
    SDL_UnlockJoystickList();
icculus@9916
   471
    return NULL;
icculus@9916
   472
}
icculus@9916
   473
icculus@9916
   474
/*
slouken@6690
   475
 * Get the friendly name of this joystick
slouken@6690
   476
 */
slouken@6690
   477
const char *
slouken@6690
   478
SDL_JoystickName(SDL_Joystick * joystick)
slouken@6690
   479
{
slouken@6690
   480
    if (!SDL_PrivateJoystickValid(joystick)) {
slouken@6690
   481
        return (NULL);
slouken@6690
   482
    }
slouken@7191
   483
slouken@6690
   484
    return (joystick->name);
slouken@6690
   485
}
slouken@6690
   486
slouken@6690
   487
/*
slouken@0
   488
 * Close a joystick previously opened with SDL_JoystickOpen()
slouken@0
   489
 */
slouken@1895
   490
void
slouken@1895
   491
SDL_JoystickClose(SDL_Joystick * joystick)
slouken@0
   492
{
slouken@7191
   493
    SDL_Joystick *joysticklist;
slouken@7191
   494
    SDL_Joystick *joysticklistprev;
slouken@0
   495
slouken@6690
   496
    if (!joystick) {
slouken@1895
   497
        return;
slouken@1895
   498
    }
slouken@0
   499
slouken@10659
   500
    SDL_LockJoystickList();
slouken@10659
   501
slouken@1895
   502
    /* First decrement ref count */
slouken@1895
   503
    if (--joystick->ref_count > 0) {
slouken@10659
   504
        SDL_UnlockJoystickList();
slouken@1895
   505
        return;
slouken@1895
   506
    }
slouken@0
   507
slouken@10704
   508
    if (SDL_updating_joystick) {
slouken@10659
   509
        SDL_UnlockJoystickList();
slouken@6712
   510
        return;
slouken@6712
   511
    }
slouken@6712
   512
slouken@1895
   513
    SDL_SYS_JoystickClose(joystick);
icculus@9433
   514
    joystick->hwdata = NULL;
slouken@0
   515
slouken@7191
   516
    joysticklist = SDL_joysticks;
slouken@7191
   517
    joysticklistprev = NULL;
slouken@8920
   518
    while (joysticklist) {
slouken@8920
   519
        if (joystick == joysticklist) {
slouken@8920
   520
            if (joysticklistprev) {
slouken@7191
   521
                /* unlink this entry */
slouken@7191
   522
                joysticklistprev->next = joysticklist->next;
slouken@8920
   523
            } else {
slouken@7191
   524
                SDL_joysticks = joystick->next;
slouken@7191
   525
            }
slouken@7191
   526
            break;
slouken@7191
   527
        }
slouken@7191
   528
        joysticklistprev = joysticklist;
slouken@7191
   529
        joysticklist = joysticklist->next;
slouken@7191
   530
    }
slouken@7191
   531
slouken@7719
   532
    SDL_free(joystick->name);
slouken@0
   533
slouken@1895
   534
    /* Free the data associated with this joystick */
slouken@7719
   535
    SDL_free(joystick->axes);
slouken@7719
   536
    SDL_free(joystick->hats);
slouken@7719
   537
    SDL_free(joystick->balls);
slouken@7719
   538
    SDL_free(joystick->buttons);
slouken@1895
   539
    SDL_free(joystick);
slouken@10659
   540
slouken@10659
   541
    SDL_UnlockJoystickList();
slouken@0
   542
}
slouken@0
   543
slouken@1895
   544
void
slouken@1895
   545
SDL_JoystickQuit(void)
slouken@0
   546
{
slouken@6712
   547
    /* Make sure we're not getting called in the middle of updating joysticks */
slouken@6712
   548
    SDL_assert(!SDL_updating_joystick);
slouken@6712
   549
slouken@10659
   550
    SDL_LockJoystickList();
slouken@10659
   551
slouken@1895
   552
    /* Stop the event polling */
slouken@8920
   553
    while (SDL_joysticks) {
slouken@7191
   554
        SDL_joysticks->ref_count = 1;
slouken@6690
   555
        SDL_JoystickClose(SDL_joysticks);
slouken@7191
   556
    }
icculus@5856
   557
slouken@1895
   558
    /* Quit the joystick setup */
slouken@1895
   559
    SDL_SYS_JoystickQuit();
slouken@7360
   560
slouken@10659
   561
    SDL_UnlockJoystickList();
slouken@10659
   562
slouken@7360
   563
#if !SDL_EVENTS_DISABLED
slouken@7360
   564
    SDL_QuitSubSystem(SDL_INIT_EVENTS);
slouken@7360
   565
#endif
slouken@10659
   566
slouken@11201
   567
    SDL_DelHintCallback(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS,
slouken@11201
   568
                        SDL_JoystickAllowBackgroundEventsChanged, NULL);
slouken@11201
   569
slouken@10659
   570
    if (SDL_joystick_lock) {
slouken@10659
   571
        SDL_DestroyMutex(SDL_joystick_lock);
slouken@10659
   572
        SDL_joystick_lock = NULL;
slouken@10659
   573
    }
slouken@11201
   574
slouken@11201
   575
    SDL_GameControllerQuitMappings();
slouken@0
   576
}
slouken@0
   577
slouken@0
   578
jorgen@7279
   579
static SDL_bool
jorgen@7279
   580
SDL_PrivateJoystickShouldIgnoreEvent()
jorgen@7279
   581
{
slouken@8920
   582
    if (SDL_joystick_allows_background_events) {
jorgen@7279
   583
        return SDL_FALSE;
jorgen@7279
   584
    }
jorgen@7279
   585
slouken@11255
   586
    if (SDL_HasWindows() && SDL_GetKeyboardFocus() == NULL) {
slouken@11255
   587
        /* We have windows but we don't have focus, ignore the event. */
slouken@11255
   588
        return SDL_TRUE;
jorgen@7279
   589
    }
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@11201
   935
void SDL_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@10868
   970
static SDL_bool SDL_IsJoystickProductWheel(Uint32 vidpid)
slouken@10855
   971
{
slouken@10855
   972
    static Uint32 wheel_joysticks[] = {
slouken@10855
   973
        MAKE_VIDPID(0x046d, 0xc294),    /* Logitech generic wheel */
slouken@10855
   974
        MAKE_VIDPID(0x046d, 0xc295),    /* Logitech Momo Force */
slouken@10855
   975
        MAKE_VIDPID(0x046d, 0xc298),    /* Logitech Driving Force Pro */
slouken@10855
   976
        MAKE_VIDPID(0x046d, 0xc299),    /* Logitech G25 */
slouken@10855
   977
        MAKE_VIDPID(0x046d, 0xc29a),    /* Logitech Driving Force GT */
slouken@10855
   978
        MAKE_VIDPID(0x046d, 0xc29b),    /* Logitech G27 */
slouken@10855
   979
        MAKE_VIDPID(0x046d, 0xc261),    /* Logitech G920 (initial mode) */
slouken@10855
   980
        MAKE_VIDPID(0x046d, 0xc262),    /* Logitech G920 (active mode) */
slouken@10855
   981
        MAKE_VIDPID(0x044f, 0xb65d),    /* Thrustmaster Wheel FFB */
slouken@10856
   982
        MAKE_VIDPID(0x044f, 0xb66d),    /* Thrustmaster Wheel FFB */
slouken@10855
   983
        MAKE_VIDPID(0x044f, 0xb677),    /* Thrustmaster T150 */
slouken@10855
   984
        MAKE_VIDPID(0x044f, 0xb664),    /* Thrustmaster TX (initial mode) */
slouken@10855
   985
        MAKE_VIDPID(0x044f, 0xb669),    /* Thrustmaster TX (active mode) */
slouken@10855
   986
    };
slouken@10855
   987
    int i;
slouken@10855
   988
slouken@10867
   989
    for (i = 0; i < SDL_arraysize(wheel_joysticks); ++i) {
slouken@10867
   990
        if (vidpid == wheel_joysticks[i]) {
slouken@10867
   991
            return SDL_TRUE;
slouken@10867
   992
        }
slouken@10867
   993
    }
slouken@10867
   994
    return SDL_FALSE;
slouken@10867
   995
}
slouken@10855
   996
slouken@10868
   997
static SDL_bool SDL_IsJoystickProductFlightStick(Uint32 vidpid)
slouken@10867
   998
{
slouken@10867
   999
    static Uint32 flightstick_joysticks[] = {
slouken@10869
  1000
        MAKE_VIDPID(0x044f, 0x0402),    /* HOTAS Warthog Joystick */
slouken@10869
  1001
        MAKE_VIDPID(0x0738, 0x2221),    /* Saitek Pro Flight X-56 Rhino Stick */
slouken@10867
  1002
    };
slouken@10867
  1003
    int i;
slouken@10867
  1004
slouken@10867
  1005
    for (i = 0; i < SDL_arraysize(flightstick_joysticks); ++i) {
slouken@10867
  1006
        if (vidpid == flightstick_joysticks[i]) {
slouken@10855
  1007
            return SDL_TRUE;
slouken@10855
  1008
        }
slouken@10855
  1009
    }
slouken@10855
  1010
    return SDL_FALSE;
slouken@10855
  1011
}
slouken@10855
  1012
slouken@10868
  1013
static SDL_bool SDL_IsJoystickProductThrottle(Uint32 vidpid)
slouken@10868
  1014
{
slouken@10868
  1015
    static Uint32 throttle_joysticks[] = {
slouken@10869
  1016
        MAKE_VIDPID(0x044f, 0x0404),    /* HOTAS Warthog Throttle */
slouken@10869
  1017
        MAKE_VIDPID(0x0738, 0xa221),    /* Saitek Pro Flight X-56 Rhino Throttle */
slouken@10868
  1018
    };
slouken@10868
  1019
    int i;
slouken@10868
  1020
slouken@10868
  1021
    for (i = 0; i < SDL_arraysize(throttle_joysticks); ++i) {
slouken@10868
  1022
        if (vidpid == throttle_joysticks[i]) {
slouken@10868
  1023
            return SDL_TRUE;
slouken@10868
  1024
        }
slouken@10868
  1025
    }
slouken@10868
  1026
    return SDL_FALSE;
slouken@10868
  1027
}
slouken@10868
  1028
slouken@10855
  1029
static SDL_JoystickType SDL_GetJoystickGUIDType(SDL_JoystickGUID guid)
slouken@10855
  1030
{
slouken@10867
  1031
    Uint16 vendor;
slouken@10867
  1032
    Uint16 product;
slouken@10867
  1033
    Uint32 vidpid;
slouken@10867
  1034
slouken@10855
  1035
    if (guid.data[14] == 'x') {
slouken@10855
  1036
        /* XInput GUID, get the type based on the XInput device subtype */
slouken@10855
  1037
        switch (guid.data[15]) {
slouken@10855
  1038
        case 0x01:  /* XINPUT_DEVSUBTYPE_GAMEPAD */
slouken@10855
  1039
            return SDL_JOYSTICK_TYPE_GAMECONTROLLER;
slouken@10855
  1040
        case 0x02:  /* XINPUT_DEVSUBTYPE_WHEEL */
slouken@10855
  1041
            return SDL_JOYSTICK_TYPE_WHEEL;
slouken@10855
  1042
        case 0x03:  /* XINPUT_DEVSUBTYPE_ARCADE_STICK */
slouken@10855
  1043
            return SDL_JOYSTICK_TYPE_ARCADE_STICK;
slouken@10855
  1044
        case 0x04:  /* XINPUT_DEVSUBTYPE_FLIGHT_STICK */
slouken@10855
  1045
            return SDL_JOYSTICK_TYPE_FLIGHT_STICK;
slouken@10855
  1046
        case 0x05:  /* XINPUT_DEVSUBTYPE_DANCE_PAD */
slouken@10855
  1047
            return SDL_JOYSTICK_TYPE_DANCE_PAD;
slouken@10855
  1048
        case 0x06:  /* XINPUT_DEVSUBTYPE_GUITAR */
slouken@10855
  1049
        case 0x07:  /* XINPUT_DEVSUBTYPE_GUITAR_ALTERNATE */
slouken@10855
  1050
        case 0x0B:  /* XINPUT_DEVSUBTYPE_GUITAR_BASS */
slouken@10855
  1051
            return SDL_JOYSTICK_TYPE_GUITAR;
slouken@10855
  1052
        case 0x08:  /* XINPUT_DEVSUBTYPE_DRUM_KIT */
slouken@10855
  1053
            return SDL_JOYSTICK_TYPE_DRUM_KIT;
slouken@10855
  1054
        case 0x13:  /* XINPUT_DEVSUBTYPE_ARCADE_PAD */
slouken@10855
  1055
            return SDL_JOYSTICK_TYPE_ARCADE_PAD;
slouken@10855
  1056
        default:
slouken@10855
  1057
            return SDL_JOYSTICK_TYPE_UNKNOWN;
slouken@10855
  1058
        }
slouken@10855
  1059
    }
slouken@10855
  1060
slouken@10867
  1061
    SDL_GetJoystickGUIDInfo(guid, &vendor, &product, NULL);
slouken@10867
  1062
    vidpid = MAKE_VIDPID(vendor, product);
slouken@10867
  1063
slouken@10868
  1064
    if (SDL_IsJoystickProductWheel(vidpid)) {
slouken@10855
  1065
        return SDL_JOYSTICK_TYPE_WHEEL;
slouken@10855
  1066
    }
slouken@10855
  1067
slouken@10868
  1068
    if (SDL_IsJoystickProductFlightStick(vidpid)) {
slouken@10867
  1069
        return SDL_JOYSTICK_TYPE_FLIGHT_STICK;
slouken@10867
  1070
    }
slouken@10867
  1071
slouken@10868
  1072
    if (SDL_IsJoystickProductThrottle(vidpid)) {
slouken@10868
  1073
        return SDL_JOYSTICK_TYPE_THROTTLE;
slouken@10868
  1074
    }
slouken@10868
  1075
slouken@10855
  1076
    return SDL_JOYSTICK_TYPE_UNKNOWN;
slouken@10855
  1077
}
slouken@10855
  1078
slouken@6693
  1079
/* return the guid for this index */
slouken@6738
  1080
SDL_JoystickGUID SDL_JoystickGetDeviceGUID(int device_index)
slouken@6690
  1081
{
slouken@10934
  1082
    if (device_index < 0 || device_index >= SDL_NumJoysticks()) {
slouken@7294
  1083
        SDL_JoystickGUID emptyGUID;
slouken@7294
  1084
        SDL_SetError("There are %d joysticks available", SDL_NumJoysticks());
slouken@8920
  1085
        SDL_zero(emptyGUID);
slouken@7294
  1086
        return emptyGUID;
slouken@7294
  1087
    }
slouken@8920
  1088
    return SDL_SYS_JoystickGetDeviceGUID(device_index);
slouken@6690
  1089
}
slouken@6690
  1090
slouken@10595
  1091
Uint16 SDL_JoystickGetDeviceVendor(int device_index)
slouken@10595
  1092
{
slouken@10595
  1093
    Uint16 vendor;
slouken@10595
  1094
    SDL_JoystickGUID guid = SDL_JoystickGetDeviceGUID(device_index);
slouken@10595
  1095
slouken@10855
  1096
    SDL_GetJoystickGUIDInfo(guid, &vendor, NULL, NULL);
slouken@10595
  1097
    return vendor;
slouken@10595
  1098
}
slouken@10595
  1099
slouken@10595
  1100
Uint16 SDL_JoystickGetDeviceProduct(int device_index)
slouken@10595
  1101
{
slouken@10595
  1102
    Uint16 product;
slouken@10595
  1103
    SDL_JoystickGUID guid = SDL_JoystickGetDeviceGUID(device_index);
slouken@10595
  1104
slouken@10855
  1105
    SDL_GetJoystickGUIDInfo(guid, NULL, &product, NULL);
slouken@10595
  1106
    return product;
slouken@10595
  1107
}
slouken@10595
  1108
slouken@10595
  1109
Uint16 SDL_JoystickGetDeviceProductVersion(int device_index)
slouken@10595
  1110
{
slouken@10595
  1111
    Uint16 version;
slouken@10595
  1112
    SDL_JoystickGUID guid = SDL_JoystickGetDeviceGUID(device_index);
slouken@10595
  1113
slouken@10855
  1114
    SDL_GetJoystickGUIDInfo(guid, NULL, NULL, &version);
slouken@10595
  1115
    return version;
slouken@10595
  1116
}
slouken@10595
  1117
slouken@10855
  1118
SDL_JoystickType SDL_JoystickGetDeviceType(int device_index)
slouken@10855
  1119
{
slouken@10855
  1120
    SDL_JoystickType type;
slouken@10855
  1121
    SDL_JoystickGUID guid = SDL_JoystickGetDeviceGUID(device_index);
slouken@10855
  1122
slouken@10855
  1123
    type = SDL_GetJoystickGUIDType(guid);
slouken@10855
  1124
    if (type == SDL_JOYSTICK_TYPE_UNKNOWN) {
slouken@10855
  1125
        if (SDL_IsGameController(device_index)) {
slouken@10855
  1126
            type = SDL_JOYSTICK_TYPE_GAMECONTROLLER;
slouken@10855
  1127
        }
slouken@10855
  1128
    }
slouken@10855
  1129
    return type;
slouken@10855
  1130
}
slouken@10855
  1131
slouken@10934
  1132
SDL_JoystickID SDL_JoystickGetDeviceInstanceID(int device_index)
slouken@10934
  1133
{
slouken@10934
  1134
    if (device_index < 0 || device_index >= SDL_NumJoysticks()) {
slouken@10934
  1135
        SDL_SetError("There are %d joysticks available", SDL_NumJoysticks());
slouken@10934
  1136
        return -1;
slouken@10934
  1137
    }
slouken@10934
  1138
    return SDL_SYS_GetInstanceIdOfDeviceIndex(device_index);
slouken@10934
  1139
}
slouken@10934
  1140
slouken@6738
  1141
SDL_JoystickGUID SDL_JoystickGetGUID(SDL_Joystick * joystick)
slouken@6690
  1142
{
slouken@7789
  1143
    if (!SDL_PrivateJoystickValid(joystick)) {
slouken@7789
  1144
        SDL_JoystickGUID emptyGUID;
slouken@8920
  1145
        SDL_zero(emptyGUID);
slouken@7789
  1146
        return emptyGUID;
slouken@7789
  1147
    }
slouken@8920
  1148
    return SDL_SYS_JoystickGetGUID(joystick);
slouken@6690
  1149
}
slouken@6690
  1150
slouken@10595
  1151
Uint16 SDL_JoystickGetVendor(SDL_Joystick * joystick)
slouken@10595
  1152
{
slouken@10595
  1153
    Uint16 vendor;
slouken@10595
  1154
    SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
slouken@10595
  1155
slouken@10855
  1156
    SDL_GetJoystickGUIDInfo(guid, &vendor, NULL, NULL);
slouken@10595
  1157
    return vendor;
slouken@10595
  1158
}
slouken@10595
  1159
slouken@10595
  1160
Uint16 SDL_JoystickGetProduct(SDL_Joystick * joystick)
slouken@10595
  1161
{
slouken@10595
  1162
    Uint16 product;
slouken@10595
  1163
    SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
slouken@10595
  1164
slouken@10855
  1165
    SDL_GetJoystickGUIDInfo(guid, NULL, &product, NULL);
slouken@10595
  1166
    return product;
slouken@10595
  1167
}
slouken@10595
  1168
slouken@10595
  1169
Uint16 SDL_JoystickGetProductVersion(SDL_Joystick * joystick)
slouken@10595
  1170
{
slouken@10595
  1171
    Uint16 version;
slouken@10595
  1172
    SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
slouken@10595
  1173
slouken@10855
  1174
    SDL_GetJoystickGUIDInfo(guid, NULL, NULL, &version);
slouken@10595
  1175
    return version;
slouken@10595
  1176
}
slouken@10595
  1177
slouken@10855
  1178
SDL_JoystickType SDL_JoystickGetType(SDL_Joystick * joystick)
slouken@10855
  1179
{
slouken@10855
  1180
    SDL_JoystickType type;
slouken@10855
  1181
    SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
slouken@10855
  1182
slouken@10855
  1183
    type = SDL_GetJoystickGUIDType(guid);
slouken@10855
  1184
    if (type == SDL_JOYSTICK_TYPE_UNKNOWN) {
slouken@10855
  1185
        if (joystick && joystick->is_game_controller) {
slouken@10855
  1186
            type = SDL_JOYSTICK_TYPE_GAMECONTROLLER;
slouken@10855
  1187
        }
slouken@10855
  1188
    }
slouken@10855
  1189
    return type;
slouken@10855
  1190
}
slouken@10855
  1191
slouken@6690
  1192
/* convert the guid to a printable string */
slouken@8920
  1193
void SDL_JoystickGetGUIDString(SDL_JoystickGUID guid, char *pszGUID, int cbGUID)
slouken@6690
  1194
{
slouken@7191
  1195
    static const char k_rgchHexToASCII[] = "0123456789abcdef";
slouken@7191
  1196
    int i;
slouken@6690
  1197
icculus@6748
  1198
    if ((pszGUID == NULL) || (cbGUID <= 0)) {
icculus@6748
  1199
        return;
icculus@6748
  1200
    }
icculus@6748
  1201
slouken@8920
  1202
    for (i = 0; i < sizeof(guid.data) && i < (cbGUID-1)/2; i++) {
slouken@7191
  1203
        /* each input byte writes 2 ascii chars, and might write a null byte. */
slouken@7191
  1204
        /* If we don't have room for next input byte, stop */
slouken@7191
  1205
        unsigned char c = guid.data[i];
slouken@6690
  1206
slouken@8920
  1207
        *pszGUID++ = k_rgchHexToASCII[c >> 4];
slouken@8920
  1208
        *pszGUID++ = k_rgchHexToASCII[c & 0x0F];
slouken@7191
  1209
    }
slouken@7191
  1210
    *pszGUID = '\0';
slouken@6690
  1211
}
slouken@6690
  1212
slouken@6690
  1213
slouken@7191
  1214
/*-----------------------------------------------------------------------------
slouken@7191
  1215
 * Purpose: Returns the 4 bit nibble for a hex character
slouken@7191
  1216
 * Input  : c -
slouken@7191
  1217
 * Output : unsigned char
slouken@7191
  1218
 *-----------------------------------------------------------------------------*/
slouken@8920
  1219
static unsigned char nibble(char c)
slouken@6690
  1220
{
slouken@8920
  1221
    if ((c >= '0') && (c <= '9')) {
slouken@7191
  1222
        return (unsigned char)(c - '0');
slouken@7191
  1223
    }
slouken@6690
  1224
slouken@8920
  1225
    if ((c >= 'A') && (c <= 'F')) {
slouken@7191
  1226
        return (unsigned char)(c - 'A' + 0x0a);
slouken@7191
  1227
    }
slouken@6690
  1228
slouken@8920
  1229
    if ((c >= 'a') && (c <= 'f')) {
slouken@7191
  1230
        return (unsigned char)(c - 'a' + 0x0a);
slouken@7191
  1231
    }
slouken@6690
  1232
slouken@7191
  1233
    /* received an invalid character, and no real way to return an error */
slouken@8920
  1234
    /* AssertMsg1(false, "Q_nibble invalid hex character '%c' ", c); */
slouken@7191
  1235
    return 0;
slouken@6690
  1236
}
slouken@6690
  1237
slouken@6690
  1238
slouken@6690
  1239
/* convert the string version of a joystick guid to the struct */
slouken@6738
  1240
SDL_JoystickGUID SDL_JoystickGetGUIDFromString(const char *pchGUID)
slouken@6690
  1241
{
slouken@7191
  1242
    SDL_JoystickGUID guid;
slouken@7191
  1243
    int maxoutputbytes= sizeof(guid);
slouken@8920
  1244
    size_t len = SDL_strlen(pchGUID);
slouken@7191
  1245
    Uint8 *p;
slouken@7922
  1246
    size_t i;
slouken@6690
  1247
slouken@7191
  1248
    /* Make sure it's even */
slouken@8920
  1249
    len = (len) & ~0x1;
slouken@6690
  1250
slouken@8920
  1251
    SDL_memset(&guid, 0x00, sizeof(guid));
slouken@6690
  1252
slouken@7191
  1253
    p = (Uint8 *)&guid;
slouken@8920
  1254
    for (i = 0; (i < len) && ((p - (Uint8 *)&guid) < maxoutputbytes); i+=2, p++) {
slouken@8920
  1255
        *p = (nibble(pchGUID[i]) << 4) | nibble(pchGUID[i+1]);
slouken@7191
  1256
    }
slouken@6690
  1257
slouken@7191
  1258
    return guid;
slouken@6690
  1259
}
slouken@6690
  1260
slouken@6690
  1261
slouken@9884
  1262
/* update the power level for this joystick */
slouken@9884
  1263
void SDL_PrivateJoystickBatteryLevel(SDL_Joystick * joystick, SDL_JoystickPowerLevel ePowerLevel)
slouken@9884
  1264
{
slouken@9884
  1265
    joystick->epowerlevel = ePowerLevel;
slouken@9884
  1266
}
slouken@9884
  1267
slouken@9884
  1268
slouken@9884
  1269
/* return its power level */
slouken@9884
  1270
SDL_JoystickPowerLevel SDL_JoystickCurrentPowerLevel(SDL_Joystick * joystick)
slouken@9884
  1271
{
slouken@9884
  1272
    if (!SDL_PrivateJoystickValid(joystick)) {
slouken@9884
  1273
        return (SDL_JOYSTICK_POWER_UNKNOWN);
slouken@9884
  1274
    }
slouken@9884
  1275
    return joystick->epowerlevel;
slouken@9884
  1276
}
slouken@9884
  1277
slouken@1895
  1278
/* vi: set ts=4 sw=4 expandtab: */