src/joystick/SDL_joystick.c
author Ryan C. Gordon <icculus@icculus.org>
Fri, 10 Aug 2018 14:42:40 -0400
changeset 12105 997ec56425a8
parent 12104 fc8ab202b5a8
child 12107 7c7cee9f2bc4
permissions -rw-r--r--
bsd: Update joystick code for new interfaces.

(this is an untested push to see if buildbot likes it.)
slouken@0
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@11811
     3
  Copyright (C) 1997-2018 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@12088
    26
#include "SDL_atomic.h"
slouken@0
    27
#include "SDL_events.h"
slouken@1361
    28
#include "SDL_sysjoystick.h"
icculus@5861
    29
#include "SDL_assert.h"
jorgen@7279
    30
#include "SDL_hints.h"
icculus@5861
    31
slouken@1361
    32
#if !SDL_EVENTS_DISABLED
slouken@1361
    33
#include "../events/SDL_events_c.h"
slouken@0
    34
#endif
slouken@11255
    35
#include "../video/SDL_sysvideo.h"
slouken@0
    36
slouken@12088
    37
/* This is included in only one place because it has a large static list of controllers */
slouken@12088
    38
#include "controller_type.h"
slouken@10855
    39
slouken@12088
    40
#ifdef __WIN32__
slouken@12088
    41
/* Needed for checking for input remapping programs */
slouken@12089
    42
#include "../core/windows/SDL_windows.h"
slouken@12088
    43
slouken@12088
    44
#undef UNICODE          /* We want ASCII functions */
slouken@12088
    45
#include <tlhelp32.h>
slouken@12088
    46
#endif
slouken@12088
    47
slouken@12088
    48
static SDL_JoystickDriver *SDL_joystick_drivers[] = {
slouken@12088
    49
#if defined(SDL_JOYSTICK_DINPUT) || defined(SDL_JOYSTICK_XINPUT)
slouken@12088
    50
    &SDL_WINDOWS_JoystickDriver,
slouken@12088
    51
#endif
slouken@12088
    52
#ifdef SDL_JOYSTICK_LINUX
slouken@12088
    53
    &SDL_LINUX_JoystickDriver,
slouken@12088
    54
#endif
slouken@12088
    55
#ifdef SDL_JOYSTICK_IOKIT
slouken@12088
    56
    &SDL_DARWIN_JoystickDriver,
slouken@12088
    57
#endif
slouken@12088
    58
#if defined(__IPHONEOS__) || defined(__TVOS__)
slouken@12088
    59
    &SDL_IOS_JoystickDriver,
slouken@12088
    60
#endif
slouken@12088
    61
#ifdef SDL_JOYSTICK_ANDROID
slouken@12088
    62
    &SDL_ANDROID_JoystickDriver,
slouken@12088
    63
#endif
icculus@12104
    64
#ifdef SDL_JOYSTICK_EMSCRIPTEN
icculus@12104
    65
    &SDL_EMSCRIPTEN_JoystickDriver,
icculus@12104
    66
#endif
icculus@12105
    67
#ifdef SDL_JOYSTICK_USBHID  /* !!! FIXME: "USBHID" is a generic name, and doubly-confusing with HIDAPI next to it. This is the *BSD interface, rename this. */
icculus@12105
    68
    &SDL_BSD_JoystickDriver,
icculus@12105
    69
#endif
slouken@12088
    70
#ifdef SDL_JOYSTICK_HIDAPI
slouken@12088
    71
    &SDL_HIDAPI_JoystickDriver,
slouken@12088
    72
#endif
slouken@12088
    73
#if defined(SDL_JOYSTICK_DUMMY) || defined(SDL_JOYSTICK_DISABLED)
slouken@12088
    74
    &SDL_DUMMY_JoystickDriver
slouken@12088
    75
#endif
slouken@12088
    76
};
slouken@7337
    77
static SDL_bool SDL_joystick_allows_background_events = SDL_FALSE;
slouken@6712
    78
static SDL_Joystick *SDL_joysticks = NULL;
slouken@10704
    79
static SDL_bool SDL_updating_joystick = SDL_FALSE;
slouken@10659
    80
static SDL_mutex *SDL_joystick_lock = NULL; /* This needs to support recursive locks */
slouken@12088
    81
static SDL_atomic_t SDL_next_joystick_instance_id;
slouken@10659
    82
slouken@10688
    83
void
slouken@11581
    84
SDL_LockJoysticks(void)
slouken@10659
    85
{
slouken@10659
    86
    if (SDL_joystick_lock) {
slouken@10659
    87
        SDL_LockMutex(SDL_joystick_lock);
slouken@10659
    88
    }
slouken@10659
    89
}
slouken@10659
    90
slouken@10688
    91
void
slouken@11581
    92
SDL_UnlockJoysticks(void)
slouken@10659
    93
{
slouken@10659
    94
    if (SDL_joystick_lock) {
slouken@10659
    95
        SDL_UnlockMutex(SDL_joystick_lock);
slouken@10659
    96
    }
slouken@10659
    97
}
slouken@10659
    98
slouken@0
    99
slouken@11284
   100
static void SDLCALL
slouken@7432
   101
SDL_JoystickAllowBackgroundEventsChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
slouken@7432
   102
{
slouken@7432
   103
    if (hint && *hint == '1') {
slouken@7432
   104
        SDL_joystick_allows_background_events = SDL_TRUE;
slouken@7432
   105
    } else {
slouken@7432
   106
        SDL_joystick_allows_background_events = SDL_FALSE;
slouken@7432
   107
    }
slouken@7432
   108
}
slouken@7432
   109
slouken@1895
   110
int
slouken@1895
   111
SDL_JoystickInit(void)
slouken@0
   112
{
slouken@12088
   113
    int i, status;
philipp@7500
   114
slouken@11201
   115
    SDL_GameControllerInitMappings();
slouken@11201
   116
slouken@10659
   117
    /* Create the joystick list lock */
slouken@10659
   118
    if (!SDL_joystick_lock) {
slouken@10659
   119
        SDL_joystick_lock = SDL_CreateMutex();
slouken@10659
   120
    }
slouken@10659
   121
slouken@7432
   122
    /* See if we should allow joystick events while in the background */
slouken@7432
   123
    SDL_AddHintCallback(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS,
slouken@7432
   124
                        SDL_JoystickAllowBackgroundEventsChanged, NULL);
slouken@0
   125
slouken@7360
   126
#if !SDL_EVENTS_DISABLED
slouken@7360
   127
    if (SDL_InitSubSystem(SDL_INIT_EVENTS) < 0) {
slouken@7360
   128
        return -1;
slouken@7360
   129
    }
slouken@7360
   130
#endif /* !SDL_EVENTS_DISABLED */
slouken@7360
   131
slouken@12088
   132
    status = -1;
slouken@12088
   133
    for (i = 0; i < SDL_arraysize(SDL_joystick_drivers); ++i) {
slouken@12088
   134
        if (SDL_joystick_drivers[i]->Init() >= 0) {
slouken@12088
   135
            status = 0;
slouken@12088
   136
        }
slouken@1895
   137
    }
slouken@12088
   138
    return status;
slouken@0
   139
}
slouken@0
   140
slouken@0
   141
/*
slouken@0
   142
 * Count the number of joysticks attached to the system
slouken@0
   143
 */
slouken@1895
   144
int
slouken@1895
   145
SDL_NumJoysticks(void)
slouken@0
   146
{
slouken@12088
   147
    int i, total_joysticks = 0;
slouken@12088
   148
    SDL_LockJoysticks();
slouken@12088
   149
    for (i = 0; i < SDL_arraysize(SDL_joystick_drivers); ++i) {
slouken@12088
   150
        total_joysticks += SDL_joystick_drivers[i]->GetCount();
slouken@12088
   151
    }
slouken@12088
   152
    SDL_UnlockJoysticks();
slouken@12088
   153
    return total_joysticks;
slouken@12088
   154
}
slouken@12088
   155
slouken@12088
   156
/*
slouken@12088
   157
 * Return the next available joystick instance ID
slouken@12088
   158
 * This may be called by drivers from multiple threads, unprotected by any locks
slouken@12088
   159
 */
slouken@12088
   160
SDL_JoystickID SDL_GetNextJoystickInstanceID()
slouken@12088
   161
{
slouken@12088
   162
    return SDL_AtomicIncRef(&SDL_next_joystick_instance_id);
slouken@12088
   163
}
slouken@12088
   164
slouken@12088
   165
/*
slouken@12088
   166
 * Get the driver and device index for an API device index
slouken@12088
   167
 * This should be called while the joystick lock is held, to prevent another thread from updating the list
slouken@12088
   168
 */
slouken@12088
   169
SDL_bool
slouken@12088
   170
SDL_GetDriverAndJoystickIndex(int device_index, SDL_JoystickDriver **driver, int *driver_index)
slouken@12088
   171
{
slouken@12088
   172
    int i, num_joysticks, total_joysticks = 0;
slouken@12088
   173
slouken@12088
   174
    if (device_index >= 0) {
slouken@12088
   175
        for (i = 0; i < SDL_arraysize(SDL_joystick_drivers); ++i) {
slouken@12088
   176
            num_joysticks = SDL_joystick_drivers[i]->GetCount();
slouken@12088
   177
            if (device_index < num_joysticks) {
slouken@12088
   178
                *driver = SDL_joystick_drivers[i];
slouken@12088
   179
                *driver_index = device_index;
slouken@12088
   180
                return SDL_TRUE;
slouken@12088
   181
            }
slouken@12088
   182
            device_index -= num_joysticks;
slouken@12088
   183
            total_joysticks += num_joysticks;
slouken@12088
   184
        }
slouken@12088
   185
    }
slouken@12088
   186
slouken@12088
   187
    SDL_SetError("There are %d joysticks available", total_joysticks);
slouken@12088
   188
    return SDL_FALSE;
slouken@0
   189
}
slouken@0
   190
slouken@0
   191
/*
slouken@11921
   192
 * Perform any needed fixups for joystick names
slouken@11921
   193
 */
slouken@11921
   194
static const char *
slouken@11921
   195
SDL_FixupJoystickName(const char *name)
slouken@11921
   196
{
slouken@11921
   197
    if (name) {
slouken@11921
   198
        const char *skip_prefix = "NVIDIA Corporation ";
slouken@11921
   199
slouken@11921
   200
        if (SDL_strncmp(name, skip_prefix, SDL_strlen(skip_prefix)) == 0) {
slouken@11921
   201
            name += SDL_strlen(skip_prefix);
slouken@11921
   202
        }
slouken@11921
   203
    }
slouken@11921
   204
    return name;
slouken@11921
   205
}
slouken@11921
   206
slouken@11921
   207
slouken@11921
   208
/*
slouken@0
   209
 * Get the implementation dependent name of a joystick
slouken@0
   210
 */
slouken@1895
   211
const char *
slouken@6690
   212
SDL_JoystickNameForIndex(int device_index)
slouken@0
   213
{
slouken@12088
   214
    SDL_JoystickDriver *driver;
slouken@12088
   215
    const char *name = NULL;
slouken@12088
   216
slouken@12088
   217
    SDL_LockJoysticks();
slouken@12088
   218
    if (SDL_GetDriverAndJoystickIndex(device_index, &driver, &device_index)) {
slouken@12088
   219
        name = SDL_FixupJoystickName(driver->GetDeviceName(device_index));
slouken@1895
   220
    }
slouken@12088
   221
    SDL_UnlockJoysticks();
slouken@12088
   222
slouken@12088
   223
    /* FIXME: Really we should reference count this name so it doesn't go away after unlock */
slouken@12088
   224
    return name;
slouken@0
   225
}
slouken@0
   226
slouken@0
   227
/*
slouken@10745
   228
 * Return true if this joystick is known to have all axes centered at zero
slouken@10745
   229
 * This isn't generally needed unless the joystick never generates an initial axis value near zero,
slouken@10745
   230
 * e.g. it's emulating axes with digital buttons
slouken@10745
   231
 */
slouken@10745
   232
static SDL_bool
slouken@10745
   233
SDL_JoystickAxesCenteredAtZero(SDL_Joystick *joystick)
slouken@10745
   234
{
slouken@10855
   235
    static Uint32 zero_centered_joysticks[] = {
slouken@10855
   236
        MAKE_VIDPID(0x0e8f, 0x3013),    /* HuiJia SNES USB adapter */
slouken@10855
   237
        MAKE_VIDPID(0x05a0, 0x3232),    /* 8Bitdo Zero Gamepad */
slouken@10745
   238
    };
slouken@10745
   239
slouken@10745
   240
    int i;
slouken@10855
   241
    Uint32 id = MAKE_VIDPID(SDL_JoystickGetVendor(joystick),
slouken@10855
   242
                            SDL_JoystickGetProduct(joystick));
slouken@10745
   243
slouken@10823
   244
/*printf("JOYSTICK '%s' VID/PID 0x%.4x/0x%.4x AXES: %d\n", joystick->name, vendor, product, joystick->naxes);*/
slouken@10823
   245
slouken@10751
   246
    if (joystick->naxes == 2) {
slouken@10751
   247
        /* Assume D-pad or thumbstick style axes are centered at 0 */
slouken@10751
   248
        return SDL_TRUE;
slouken@10751
   249
    }
slouken@10751
   250
slouken@10745
   251
    for (i = 0; i < SDL_arraysize(zero_centered_joysticks); ++i) {
slouken@10855
   252
        if (id == zero_centered_joysticks[i]) {
slouken@10745
   253
            return SDL_TRUE;
slouken@10745
   254
        }
slouken@10745
   255
    }
slouken@10745
   256
    return SDL_FALSE;
slouken@10745
   257
}
slouken@10745
   258
slouken@10745
   259
/*
slouken@0
   260
 * Open a joystick for use - the index passed as an argument refers to
slouken@0
   261
 * the N'th joystick on the system.  This index is the value which will
slouken@0
   262
 * identify this joystick in future joystick events.
slouken@0
   263
 *
slouken@0
   264
 * This function returns a joystick identifier, or NULL if an error occurred.
slouken@0
   265
 */
slouken@1895
   266
SDL_Joystick *
slouken@1895
   267
SDL_JoystickOpen(int device_index)
slouken@0
   268
{
slouken@12088
   269
    SDL_JoystickDriver *driver;
slouken@12088
   270
    SDL_JoystickID instance_id;
slouken@1895
   271
    SDL_Joystick *joystick;
slouken@7191
   272
    SDL_Joystick *joysticklist;
slouken@7191
   273
    const char *joystickname = NULL;
slouken@0
   274
slouken@12088
   275
    SDL_LockJoysticks();
slouken@12088
   276
slouken@12088
   277
    if (!SDL_GetDriverAndJoystickIndex(device_index, &driver, &device_index)) {
slouken@12088
   278
        SDL_UnlockJoysticks();
slouken@12088
   279
        return NULL;
slouken@1895
   280
    }
slouken@0
   281
slouken@7191
   282
    joysticklist = SDL_joysticks;
slouken@7191
   283
    /* If the joystick is already open, return it
slouken@10934
   284
     * it is important that we have a single joystick * for each instance id
slouken@10934
   285
     */
slouken@12088
   286
    instance_id = driver->GetDeviceInstanceID(device_index);
slouken@8920
   287
    while (joysticklist) {
slouken@12088
   288
        if (instance_id == joysticklist->instance_id) {
slouken@7191
   289
                joystick = joysticklist;
slouken@7191
   290
                ++joystick->ref_count;
slouken@11581
   291
                SDL_UnlockJoysticks();
slouken@12088
   292
                return joystick;
slouken@7191
   293
        }
slouken@7191
   294
        joysticklist = joysticklist->next;
slouken@1895
   295
    }
slouken@0
   296
slouken@1895
   297
    /* Create and initialize the joystick */
slouken@10855
   298
    joystick = (SDL_Joystick *) SDL_calloc(sizeof(*joystick), 1);
icculus@3608
   299
    if (joystick == NULL) {
icculus@3608
   300
        SDL_OutOfMemory();
slouken@11581
   301
        SDL_UnlockJoysticks();
icculus@3608
   302
        return NULL;
slouken@1895
   303
    }
slouken@12088
   304
    joystick->driver = driver;
slouken@12088
   305
    joystick->instance_id = instance_id;
slouken@12090
   306
    joystick->attached = SDL_TRUE;
icculus@3608
   307
slouken@12088
   308
    if (driver->Open(joystick, device_index) < 0) {
icculus@3608
   309
        SDL_free(joystick);
slouken@11581
   310
        SDL_UnlockJoysticks();
icculus@3608
   311
        return NULL;
slouken@1895
   312
    }
slouken@6690
   313
slouken@12088
   314
    joystickname = driver->GetDeviceName(device_index);
slouken@12088
   315
    if (joystickname) {
slouken@8920
   316
        joystick->name = SDL_strdup(joystickname);
slouken@12088
   317
    } else {
slouken@7191
   318
        joystick->name = NULL;
slouken@12088
   319
    }
slouken@12088
   320
slouken@12088
   321
    joystick->guid = driver->GetDeviceGUID(device_index);
slouken@6690
   322
icculus@3608
   323
    if (joystick->naxes > 0) {
slouken@10713
   324
        joystick->axes = (SDL_JoystickAxisInfo *) SDL_calloc(joystick->naxes, sizeof(SDL_JoystickAxisInfo));
icculus@3608
   325
    }
icculus@3608
   326
    if (joystick->nhats > 0) {
slouken@10713
   327
        joystick->hats = (Uint8 *) SDL_calloc(joystick->nhats, sizeof(Uint8));
icculus@3608
   328
    }
icculus@3608
   329
    if (joystick->nballs > 0) {
slouken@10713
   330
        joystick->balls = (struct balldelta *) SDL_calloc(joystick->nballs, sizeof(*joystick->balls));
icculus@3608
   331
    }
icculus@3608
   332
    if (joystick->nbuttons > 0) {
slouken@10713
   333
        joystick->buttons = (Uint8 *) SDL_calloc(joystick->nbuttons, sizeof(Uint8));
icculus@3608
   334
    }
icculus@3608
   335
    if (((joystick->naxes > 0) && !joystick->axes)
icculus@3608
   336
        || ((joystick->nhats > 0) && !joystick->hats)
icculus@3608
   337
        || ((joystick->nballs > 0) && !joystick->balls)
icculus@3608
   338
        || ((joystick->nbuttons > 0) && !joystick->buttons)) {
icculus@3608
   339
        SDL_OutOfMemory();
icculus@3608
   340
        SDL_JoystickClose(joystick);
slouken@11581
   341
        SDL_UnlockJoysticks();
icculus@3608
   342
        return NULL;
icculus@3608
   343
    }
slouken@9884
   344
    joystick->epowerlevel = SDL_JOYSTICK_POWER_UNKNOWN;
icculus@3608
   345
slouken@10745
   346
    /* If this joystick is known to have all zero centered axes, skip the auto-centering code */
slouken@10745
   347
    if (SDL_JoystickAxesCenteredAtZero(joystick)) {
slouken@10745
   348
        int i;
slouken@10745
   349
slouken@10745
   350
        for (i = 0; i < joystick->naxes; ++i) {
slouken@10745
   351
            joystick->axes[i].has_initial_value = SDL_TRUE;
slouken@10745
   352
        }
slouken@10745
   353
    }
slouken@10745
   354
slouken@10855
   355
    joystick->is_game_controller = SDL_IsGameController(device_index);
slouken@10855
   356
icculus@3608
   357
    /* Add joystick to list */
icculus@3608
   358
    ++joystick->ref_count;
slouken@7191
   359
    /* Link the joystick in the list */
slouken@7191
   360
    joystick->next = SDL_joysticks;
slouken@7191
   361
    SDL_joysticks = joystick;
slouken@6690
   362
slouken@11581
   363
    SDL_UnlockJoysticks();
slouken@10688
   364
slouken@12088
   365
    driver->Update(joystick);
icculus@3608
   366
slouken@12088
   367
    return joystick;
slouken@0
   368
}
slouken@0
   369
slouken@2713
   370
slouken@2713
   371
/*
slouken@2713
   372
 * Checks to make sure the joystick is valid.
slouken@2713
   373
 */
slouken@2713
   374
int
slouken@6690
   375
SDL_PrivateJoystickValid(SDL_Joystick * joystick)
slouken@0
   376
{
slouken@1895
   377
    int valid;
slouken@0
   378
slouken@8920
   379
    if (joystick == NULL) {
slouken@1895
   380
        SDL_SetError("Joystick hasn't been opened yet");
slouken@1895
   381
        valid = 0;
slouken@1895
   382
    } else {
slouken@1895
   383
        valid = 1;
slouken@1895
   384
    }
slouken@7191
   385
slouken@1895
   386
    return valid;
slouken@0
   387
}
slouken@0
   388
slouken@0
   389
/*
slouken@0
   390
 * Get the number of multi-dimensional axis controls on a joystick
slouken@0
   391
 */
slouken@1895
   392
int
slouken@1895
   393
SDL_JoystickNumAxes(SDL_Joystick * joystick)
slouken@0
   394
{
slouken@6690
   395
    if (!SDL_PrivateJoystickValid(joystick)) {
slouken@12088
   396
        return -1;
slouken@1895
   397
    }
slouken@12088
   398
    return joystick->naxes;
slouken@0
   399
}
slouken@0
   400
slouken@0
   401
/*
slouken@0
   402
 * Get the number of hats on a joystick
slouken@0
   403
 */
slouken@1895
   404
int
slouken@1895
   405
SDL_JoystickNumHats(SDL_Joystick * joystick)
slouken@0
   406
{
slouken@6690
   407
    if (!SDL_PrivateJoystickValid(joystick)) {
slouken@12088
   408
        return -1;
slouken@1895
   409
    }
slouken@12088
   410
    return joystick->nhats;
slouken@0
   411
}
slouken@0
   412
slouken@0
   413
/*
slouken@0
   414
 * Get the number of trackballs on a joystick
slouken@0
   415
 */
slouken@1895
   416
int
slouken@1895
   417
SDL_JoystickNumBalls(SDL_Joystick * joystick)
slouken@0
   418
{
slouken@6690
   419
    if (!SDL_PrivateJoystickValid(joystick)) {
slouken@12088
   420
        return -1;
slouken@1895
   421
    }
slouken@12088
   422
    return joystick->nballs;
slouken@0
   423
}
slouken@0
   424
slouken@0
   425
/*
slouken@0
   426
 * Get the number of buttons on a joystick
slouken@0
   427
 */
slouken@1895
   428
int
slouken@1895
   429
SDL_JoystickNumButtons(SDL_Joystick * joystick)
slouken@0
   430
{
slouken@6690
   431
    if (!SDL_PrivateJoystickValid(joystick)) {
slouken@12088
   432
        return -1;
slouken@1895
   433
    }
slouken@12088
   434
    return joystick->nbuttons;
slouken@0
   435
}
slouken@0
   436
slouken@0
   437
/*
slouken@0
   438
 * Get the current state of an axis control on a joystick
slouken@0
   439
 */
slouken@1895
   440
Sint16
slouken@1895
   441
SDL_JoystickGetAxis(SDL_Joystick * joystick, int axis)
slouken@0
   442
{
slouken@1895
   443
    Sint16 state;
slouken@0
   444
slouken@6690
   445
    if (!SDL_PrivateJoystickValid(joystick)) {
slouken@12088
   446
        return 0;
slouken@1895
   447
    }
slouken@1895
   448
    if (axis < joystick->naxes) {
slouken@10713
   449
        state = joystick->axes[axis].value;
slouken@1895
   450
    } else {
slouken@1895
   451
        SDL_SetError("Joystick only has %d axes", joystick->naxes);
slouken@1895
   452
        state = 0;
slouken@1895
   453
    }
slouken@12088
   454
    return state;
slouken@0
   455
}
slouken@0
   456
slouken@0
   457
/*
slouken@10752
   458
 * Get the initial state of an axis control on a joystick
slouken@10752
   459
 */
slouken@10752
   460
SDL_bool
slouken@10752
   461
SDL_JoystickGetAxisInitialState(SDL_Joystick * joystick, int axis, Sint16 *state)
slouken@10752
   462
{
slouken@10752
   463
    if (!SDL_PrivateJoystickValid(joystick)) {
slouken@10752
   464
        return SDL_FALSE;
slouken@10752
   465
    }
slouken@10752
   466
    if (axis >= joystick->naxes) {
slouken@10752
   467
        SDL_SetError("Joystick only has %d axes", joystick->naxes);
slouken@10752
   468
        return SDL_FALSE;
slouken@10752
   469
    }
slouken@10752
   470
    if (state) {
slouken@10752
   471
        *state = joystick->axes[axis].initial_value;
slouken@10752
   472
    }
slouken@10752
   473
    return joystick->axes[axis].has_initial_value;
slouken@10752
   474
}
slouken@10752
   475
slouken@10752
   476
/*
slouken@0
   477
 * Get the current state of a hat on a joystick
slouken@0
   478
 */
slouken@1895
   479
Uint8
slouken@1895
   480
SDL_JoystickGetHat(SDL_Joystick * joystick, int hat)
slouken@0
   481
{
slouken@1895
   482
    Uint8 state;
slouken@0
   483
slouken@6690
   484
    if (!SDL_PrivateJoystickValid(joystick)) {
slouken@12088
   485
        return 0;
slouken@1895
   486
    }
slouken@1895
   487
    if (hat < joystick->nhats) {
slouken@1895
   488
        state = joystick->hats[hat];
slouken@1895
   489
    } else {
slouken@1895
   490
        SDL_SetError("Joystick only has %d hats", joystick->nhats);
slouken@1895
   491
        state = 0;
slouken@1895
   492
    }
slouken@12088
   493
    return state;
slouken@0
   494
}
slouken@0
   495
slouken@0
   496
/*
slouken@0
   497
 * Get the ball axis change since the last poll
slouken@0
   498
 */
slouken@1895
   499
int
slouken@1895
   500
SDL_JoystickGetBall(SDL_Joystick * joystick, int ball, int *dx, int *dy)
slouken@0
   501
{
slouken@1895
   502
    int retval;
slouken@0
   503
slouken@6690
   504
    if (!SDL_PrivateJoystickValid(joystick)) {
slouken@12088
   505
        return -1;
slouken@1895
   506
    }
slouken@0
   507
slouken@1895
   508
    retval = 0;
slouken@1895
   509
    if (ball < joystick->nballs) {
slouken@1895
   510
        if (dx) {
slouken@1895
   511
            *dx = joystick->balls[ball].dx;
slouken@1895
   512
        }
slouken@1895
   513
        if (dy) {
slouken@1895
   514
            *dy = joystick->balls[ball].dy;
slouken@1895
   515
        }
slouken@1895
   516
        joystick->balls[ball].dx = 0;
slouken@1895
   517
        joystick->balls[ball].dy = 0;
slouken@1895
   518
    } else {
icculus@7037
   519
        return SDL_SetError("Joystick only has %d balls", joystick->nballs);
slouken@1895
   520
    }
slouken@12088
   521
    return retval;
slouken@0
   522
}
slouken@0
   523
slouken@0
   524
/*
slouken@0
   525
 * Get the current state of a button on a joystick
slouken@0
   526
 */
slouken@1895
   527
Uint8
slouken@1895
   528
SDL_JoystickGetButton(SDL_Joystick * joystick, int button)
slouken@0
   529
{
slouken@1895
   530
    Uint8 state;
slouken@0
   531
slouken@6690
   532
    if (!SDL_PrivateJoystickValid(joystick)) {
slouken@12088
   533
        return 0;
slouken@1895
   534
    }
slouken@1895
   535
    if (button < joystick->nbuttons) {
slouken@1895
   536
        state = joystick->buttons[button];
slouken@1895
   537
    } else {
slouken@1895
   538
        SDL_SetError("Joystick only has %d buttons", joystick->nbuttons);
slouken@1895
   539
        state = 0;
slouken@1895
   540
    }
slouken@12088
   541
    return state;
slouken@0
   542
}
slouken@0
   543
slouken@0
   544
/*
slouken@6690
   545
 * Return if the joystick in question is currently attached to the system,
philipp@7500
   546
 *  \return SDL_FALSE if not plugged in, SDL_TRUE if still present.
slouken@6690
   547
 */
slouken@6707
   548
SDL_bool
slouken@6707
   549
SDL_JoystickGetAttached(SDL_Joystick * joystick)
slouken@6690
   550
{
slouken@7191
   551
    if (!SDL_PrivateJoystickValid(joystick)) {
slouken@6707
   552
        return SDL_FALSE;
slouken@6690
   553
    }
slouken@6690
   554
slouken@12090
   555
    return joystick->attached;
slouken@6690
   556
}
slouken@6690
   557
slouken@6690
   558
/*
slouken@6690
   559
 * Get the instance id for this opened joystick
slouken@6690
   560
 */
slouken@7191
   561
SDL_JoystickID
slouken@6707
   562
SDL_JoystickInstanceID(SDL_Joystick * joystick)
slouken@6690
   563
{
slouken@7191
   564
    if (!SDL_PrivateJoystickValid(joystick)) {
slouken@12088
   565
        return -1;
slouken@6690
   566
    }
slouken@6690
   567
slouken@12088
   568
    return joystick->instance_id;
slouken@6690
   569
}
slouken@6690
   570
slouken@6690
   571
/*
icculus@9916
   572
 * Find the SDL_Joystick that owns this instance id
icculus@9916
   573
 */
icculus@9916
   574
SDL_Joystick *
icculus@9916
   575
SDL_JoystickFromInstanceID(SDL_JoystickID joyid)
icculus@9916
   576
{
slouken@10659
   577
    SDL_Joystick *joystick;
slouken@10659
   578
slouken@11581
   579
    SDL_LockJoysticks();
slouken@10659
   580
    for (joystick = SDL_joysticks; joystick; joystick = joystick->next) {
icculus@9916
   581
        if (joystick->instance_id == joyid) {
slouken@11581
   582
            SDL_UnlockJoysticks();
icculus@9916
   583
            return joystick;
icculus@9916
   584
        }
icculus@9916
   585
    }
slouken@11581
   586
    SDL_UnlockJoysticks();
icculus@9916
   587
    return NULL;
icculus@9916
   588
}
icculus@9916
   589
icculus@9916
   590
/*
slouken@6690
   591
 * Get the friendly name of this joystick
slouken@6690
   592
 */
slouken@6690
   593
const char *
slouken@6690
   594
SDL_JoystickName(SDL_Joystick * joystick)
slouken@6690
   595
{
slouken@6690
   596
    if (!SDL_PrivateJoystickValid(joystick)) {
slouken@12088
   597
        return NULL;
slouken@6690
   598
    }
slouken@7191
   599
slouken@11921
   600
    return SDL_FixupJoystickName(joystick->name);
slouken@6690
   601
}
slouken@6690
   602
slouken@12088
   603
int
slouken@12088
   604
SDL_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
slouken@12088
   605
{
slouken@12088
   606
    if (!SDL_PrivateJoystickValid(joystick)) {
slouken@12088
   607
        return -1;
slouken@12088
   608
    }
slouken@12088
   609
    return joystick->driver->Rumble(joystick, low_frequency_rumble, high_frequency_rumble, duration_ms);
slouken@12088
   610
}
slouken@12088
   611
slouken@6690
   612
/*
slouken@0
   613
 * Close a joystick previously opened with SDL_JoystickOpen()
slouken@0
   614
 */
slouken@1895
   615
void
slouken@1895
   616
SDL_JoystickClose(SDL_Joystick * joystick)
slouken@0
   617
{
slouken@7191
   618
    SDL_Joystick *joysticklist;
slouken@7191
   619
    SDL_Joystick *joysticklistprev;
slouken@0
   620
slouken@12088
   621
    if (!SDL_PrivateJoystickValid(joystick)) {
slouken@1895
   622
        return;
slouken@1895
   623
    }
slouken@0
   624
slouken@11581
   625
    SDL_LockJoysticks();
slouken@10659
   626
slouken@1895
   627
    /* First decrement ref count */
slouken@1895
   628
    if (--joystick->ref_count > 0) {
slouken@11581
   629
        SDL_UnlockJoysticks();
slouken@1895
   630
        return;
slouken@1895
   631
    }
slouken@0
   632
slouken@10704
   633
    if (SDL_updating_joystick) {
slouken@11581
   634
        SDL_UnlockJoysticks();
slouken@6712
   635
        return;
slouken@6712
   636
    }
slouken@6712
   637
slouken@12088
   638
    joystick->driver->Close(joystick);
icculus@9433
   639
    joystick->hwdata = NULL;
slouken@0
   640
slouken@7191
   641
    joysticklist = SDL_joysticks;
slouken@7191
   642
    joysticklistprev = NULL;
slouken@8920
   643
    while (joysticklist) {
slouken@8920
   644
        if (joystick == joysticklist) {
slouken@8920
   645
            if (joysticklistprev) {
slouken@7191
   646
                /* unlink this entry */
slouken@7191
   647
                joysticklistprev->next = joysticklist->next;
slouken@8920
   648
            } else {
slouken@7191
   649
                SDL_joysticks = joystick->next;
slouken@7191
   650
            }
slouken@7191
   651
            break;
slouken@7191
   652
        }
slouken@7191
   653
        joysticklistprev = joysticklist;
slouken@7191
   654
        joysticklist = joysticklist->next;
slouken@7191
   655
    }
slouken@7191
   656
slouken@7719
   657
    SDL_free(joystick->name);
slouken@0
   658
slouken@1895
   659
    /* Free the data associated with this joystick */
slouken@7719
   660
    SDL_free(joystick->axes);
slouken@7719
   661
    SDL_free(joystick->hats);
slouken@7719
   662
    SDL_free(joystick->balls);
slouken@7719
   663
    SDL_free(joystick->buttons);
slouken@1895
   664
    SDL_free(joystick);
slouken@10659
   665
slouken@11581
   666
    SDL_UnlockJoysticks();
slouken@0
   667
}
slouken@0
   668
slouken@1895
   669
void
slouken@1895
   670
SDL_JoystickQuit(void)
slouken@0
   671
{
slouken@12088
   672
    int i;
slouken@12088
   673
slouken@6712
   674
    /* Make sure we're not getting called in the middle of updating joysticks */
slouken@6712
   675
    SDL_assert(!SDL_updating_joystick);
slouken@6712
   676
slouken@11581
   677
    SDL_LockJoysticks();
slouken@10659
   678
slouken@1895
   679
    /* Stop the event polling */
slouken@8920
   680
    while (SDL_joysticks) {
slouken@7191
   681
        SDL_joysticks->ref_count = 1;
slouken@6690
   682
        SDL_JoystickClose(SDL_joysticks);
slouken@7191
   683
    }
icculus@5856
   684
slouken@1895
   685
    /* Quit the joystick setup */
slouken@12088
   686
    for (i = 0; i < SDL_arraysize(SDL_joystick_drivers); ++i) {
slouken@12088
   687
       SDL_joystick_drivers[i]->Quit();
slouken@12088
   688
    }
slouken@7360
   689
slouken@11581
   690
    SDL_UnlockJoysticks();
slouken@10659
   691
slouken@7360
   692
#if !SDL_EVENTS_DISABLED
slouken@7360
   693
    SDL_QuitSubSystem(SDL_INIT_EVENTS);
slouken@7360
   694
#endif
slouken@10659
   695
slouken@11201
   696
    SDL_DelHintCallback(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS,
slouken@11201
   697
                        SDL_JoystickAllowBackgroundEventsChanged, NULL);
slouken@11201
   698
slouken@10659
   699
    if (SDL_joystick_lock) {
slouken@10659
   700
        SDL_DestroyMutex(SDL_joystick_lock);
slouken@10659
   701
        SDL_joystick_lock = NULL;
slouken@10659
   702
    }
slouken@11201
   703
slouken@11201
   704
    SDL_GameControllerQuitMappings();
slouken@0
   705
}
slouken@0
   706
slouken@0
   707
jorgen@7279
   708
static SDL_bool
jorgen@7279
   709
SDL_PrivateJoystickShouldIgnoreEvent()
jorgen@7279
   710
{
slouken@8920
   711
    if (SDL_joystick_allows_background_events) {
jorgen@7279
   712
        return SDL_FALSE;
jorgen@7279
   713
    }
jorgen@7279
   714
slouken@11255
   715
    if (SDL_HasWindows() && SDL_GetKeyboardFocus() == NULL) {
slouken@11255
   716
        /* We have windows but we don't have focus, ignore the event. */
slouken@11255
   717
        return SDL_TRUE;
jorgen@7279
   718
    }
slouken@7337
   719
    return SDL_FALSE;
jorgen@7279
   720
}
jorgen@7279
   721
slouken@0
   722
/* These are global for SDL_sysjoystick.c and SDL_events.c */
slouken@0
   723
slouken@12088
   724
void SDL_PrivateJoystickAdded(SDL_JoystickID device_instance)
slouken@10226
   725
{
slouken@10226
   726
#if !SDL_EVENTS_DISABLED
slouken@10226
   727
    SDL_Event event;
slouken@12088
   728
    int device_index;
slouken@12088
   729
slouken@12088
   730
    device_index = SDL_JoystickGetDeviceIndexFromInstanceID(device_instance);
slouken@12088
   731
    if (device_index < 0) {
slouken@12088
   732
        return;
slouken@12088
   733
    }
slouken@10226
   734
slouken@10226
   735
    event.type = SDL_JOYDEVICEADDED;
slouken@10226
   736
slouken@10226
   737
    if (SDL_GetEventState(event.type) == SDL_ENABLE) {
slouken@10226
   738
        event.jdevice.which = device_index;
slouken@11584
   739
        SDL_PushEvent(&event);
slouken@10226
   740
    }
slouken@10226
   741
#endif /* !SDL_EVENTS_DISABLED */
slouken@10226
   742
}
slouken@10226
   743
slouken@10226
   744
/*
slouken@10226
   745
 * If there is an existing add event in the queue, it needs to be modified
slouken@10226
   746
 * to have the right value for which, because the number of controllers in
slouken@10226
   747
 * the system is now one less.
slouken@10226
   748
 */
slouken@10226
   749
static void UpdateEventsForDeviceRemoval()
slouken@10226
   750
{
slouken@10226
   751
    int i, num_events;
slouken@10226
   752
    SDL_Event *events;
slouken@10226
   753
slouken@10226
   754
    num_events = SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, SDL_JOYDEVICEADDED, SDL_JOYDEVICEADDED);
slouken@10226
   755
    if (num_events <= 0) {
slouken@10226
   756
        return;
slouken@10226
   757
    }
slouken@10226
   758
slouken@10226
   759
    events = SDL_stack_alloc(SDL_Event, num_events);
slouken@10226
   760
    if (!events) {
slouken@10226
   761
        return;
slouken@10226
   762
    }
slouken@10226
   763
slouken@10226
   764
    num_events = SDL_PeepEvents(events, num_events, SDL_GETEVENT, SDL_JOYDEVICEADDED, SDL_JOYDEVICEADDED);
slouken@10226
   765
    for (i = 0; i < num_events; ++i) {
slouken@10226
   766
        --events[i].jdevice.which;
slouken@10226
   767
    }
slouken@10226
   768
    SDL_PeepEvents(events, num_events, SDL_ADDEVENT, 0, 0);
slouken@10226
   769
slouken@10226
   770
    SDL_stack_free(events);
slouken@10226
   771
}
slouken@10226
   772
slouken@10226
   773
void SDL_PrivateJoystickRemoved(SDL_JoystickID device_instance)
slouken@10226
   774
{
slouken@12090
   775
    SDL_Joystick *joystick;
slouken@12090
   776
slouken@10226
   777
#if !SDL_EVENTS_DISABLED
slouken@10226
   778
    SDL_Event event;
slouken@10226
   779
slouken@10226
   780
    event.type = SDL_JOYDEVICEREMOVED;
slouken@10226
   781
slouken@10226
   782
    if (SDL_GetEventState(event.type) == SDL_ENABLE) {
slouken@10226
   783
        event.jdevice.which = device_instance;
slouken@11584
   784
        SDL_PushEvent(&event);
slouken@10226
   785
    }
slouken@10226
   786
slouken@10226
   787
    UpdateEventsForDeviceRemoval();
slouken@10226
   788
#endif /* !SDL_EVENTS_DISABLED */
slouken@12090
   789
slouken@12090
   790
    /* Mark this joystick as no longer attached */
slouken@12090
   791
    for (joystick = SDL_joysticks; joystick; joystick = joystick->next) {
slouken@12090
   792
        if (joystick->instance_id == device_instance) {
slouken@12090
   793
            joystick->attached = SDL_FALSE;
slouken@12090
   794
            joystick->force_recentering = SDL_TRUE;
slouken@12090
   795
            break;
slouken@12090
   796
        }
slouken@12090
   797
    }
slouken@10226
   798
}
slouken@10226
   799
slouken@1895
   800
int
slouken@1895
   801
SDL_PrivateJoystickAxis(SDL_Joystick * joystick, Uint8 axis, Sint16 value)
slouken@0
   802
{
slouken@1895
   803
    int posted;
slouken@0
   804
slouken@8920
   805
    /* Make sure we're not getting garbage or duplicate events */
slouken@6145
   806
    if (axis >= joystick->naxes) {
slouken@6145
   807
        return 0;
slouken@6145
   808
    }
slouken@10745
   809
    if (!joystick->axes[axis].has_initial_value) {
slouken@10752
   810
        joystick->axes[axis].initial_value = value;
slouken@10745
   811
        joystick->axes[axis].value = value;
slouken@10745
   812
        joystick->axes[axis].zero = value;
slouken@10745
   813
        joystick->axes[axis].has_initial_value = SDL_TRUE;
slouken@10745
   814
    }
slouken@11520
   815
    if (value == joystick->axes[axis].value) {
slouken@11520
   816
        return 0;
slouken@11520
   817
    }
slouken@10745
   818
    if (!joystick->axes[axis].sent_initial_value) {
slouken@11512
   819
        /* Make sure we don't send motion until there's real activity on this axis */
slouken@11512
   820
        const int MAX_ALLOWED_JITTER = SDL_JOYSTICK_AXIS_MAX / 80;  /* ShanWan PS3 controller needed 96 */
slouken@11512
   821
        if (SDL_abs(value - joystick->axes[axis].value) <= MAX_ALLOWED_JITTER) {
slouken@11512
   822
            return 0;
slouken@11512
   823
        }
slouken@10745
   824
        joystick->axes[axis].sent_initial_value = SDL_TRUE;
slouken@10745
   825
        joystick->axes[axis].value = value; /* Just so we pass the check above */
slouken@10752
   826
        SDL_PrivateJoystickAxis(joystick, axis, joystick->axes[axis].initial_value);
slouken@10713
   827
    }
slouken@6145
   828
slouken@8903
   829
    /* We ignore events if we don't have keyboard focus, except for centering
slouken@8903
   830
     * events.
slouken@8903
   831
     */
slouken@8903
   832
    if (SDL_PrivateJoystickShouldIgnoreEvent()) {
slouken@10713
   833
        if ((value > joystick->axes[axis].zero && value >= joystick->axes[axis].value) ||
slouken@10713
   834
            (value < joystick->axes[axis].zero && value <= joystick->axes[axis].value)) {
slouken@8903
   835
            return 0;
slouken@8903
   836
        }
slouken@8903
   837
    }
slouken@8903
   838
slouken@1895
   839
    /* Update internal joystick state */
slouken@10713
   840
    joystick->axes[axis].value = value;
slouken@0
   841
slouken@1895
   842
    /* Post the event, if desired */
slouken@1895
   843
    posted = 0;
slouken@1361
   844
#if !SDL_EVENTS_DISABLED
slouken@4429
   845
    if (SDL_GetEventState(SDL_JOYAXISMOTION) == SDL_ENABLE) {
slouken@1895
   846
        SDL_Event event;
slouken@1895
   847
        event.type = SDL_JOYAXISMOTION;
slouken@6690
   848
        event.jaxis.which = joystick->instance_id;
slouken@1895
   849
        event.jaxis.axis = axis;
slouken@1895
   850
        event.jaxis.value = value;
slouken@6690
   851
        posted = SDL_PushEvent(&event) == 1;
slouken@1895
   852
    }
slouken@1361
   853
#endif /* !SDL_EVENTS_DISABLED */
slouken@12088
   854
    return posted;
slouken@0
   855
}
slouken@0
   856
slouken@1895
   857
int
slouken@1895
   858
SDL_PrivateJoystickHat(SDL_Joystick * joystick, Uint8 hat, Uint8 value)
slouken@0
   859
{
slouken@1895
   860
    int posted;
slouken@0
   861
slouken@8920
   862
    /* Make sure we're not getting garbage or duplicate events */
slouken@6145
   863
    if (hat >= joystick->nhats) {
slouken@6145
   864
        return 0;
slouken@6145
   865
    }
slouken@8920
   866
    if (value == joystick->hats[hat]) {
slouken@8920
   867
        return 0;
slouken@8920
   868
    }
slouken@6145
   869
jorgen@7279
   870
    /* We ignore events if we don't have keyboard focus, except for centering
jorgen@7279
   871
     * events.
jorgen@7279
   872
     */
jorgen@7279
   873
    if (SDL_PrivateJoystickShouldIgnoreEvent()) {
slouken@8903
   874
        if (value != SDL_HAT_CENTERED) {
jorgen@7279
   875
            return 0;
jorgen@7279
   876
        }
jorgen@7279
   877
    }
jorgen@7279
   878
slouken@8903
   879
    /* Update internal joystick state */
slouken@8903
   880
    joystick->hats[hat] = value;
jorgen@7279
   881
slouken@1895
   882
    /* Post the event, if desired */
slouken@1895
   883
    posted = 0;
slouken@1361
   884
#if !SDL_EVENTS_DISABLED
slouken@4429
   885
    if (SDL_GetEventState(SDL_JOYHATMOTION) == SDL_ENABLE) {
slouken@1895
   886
        SDL_Event event;
slouken@1895
   887
        event.jhat.type = SDL_JOYHATMOTION;
slouken@6690
   888
        event.jhat.which = joystick->instance_id;
slouken@1895
   889
        event.jhat.hat = hat;
slouken@1895
   890
        event.jhat.value = value;
slouken@6690
   891
        posted = SDL_PushEvent(&event) == 1;
slouken@1895
   892
    }
slouken@1361
   893
#endif /* !SDL_EVENTS_DISABLED */
slouken@12088
   894
    return posted;
slouken@0
   895
}
slouken@0
   896
slouken@1895
   897
int
slouken@1895
   898
SDL_PrivateJoystickBall(SDL_Joystick * joystick, Uint8 ball,
slouken@1895
   899
                        Sint16 xrel, Sint16 yrel)
slouken@0
   900
{
slouken@1895
   901
    int posted;
slouken@0
   902
slouken@6145
   903
    /* Make sure we're not getting garbage events */
slouken@6145
   904
    if (ball >= joystick->nballs) {
slouken@6145
   905
        return 0;
slouken@6145
   906
    }
slouken@6145
   907
jorgen@7279
   908
    /* We ignore events if we don't have keyboard focus. */
jorgen@7279
   909
    if (SDL_PrivateJoystickShouldIgnoreEvent()) {
jorgen@7279
   910
        return 0;
jorgen@7279
   911
    }
jorgen@7279
   912
slouken@1895
   913
    /* Update internal mouse state */
slouken@1895
   914
    joystick->balls[ball].dx += xrel;
slouken@1895
   915
    joystick->balls[ball].dy += yrel;
slouken@0
   916
slouken@1895
   917
    /* Post the event, if desired */
slouken@1895
   918
    posted = 0;
slouken@1361
   919
#if !SDL_EVENTS_DISABLED
slouken@4429
   920
    if (SDL_GetEventState(SDL_JOYBALLMOTION) == SDL_ENABLE) {
slouken@1895
   921
        SDL_Event event;
slouken@1895
   922
        event.jball.type = SDL_JOYBALLMOTION;
slouken@6690
   923
        event.jball.which = joystick->instance_id;
slouken@1895
   924
        event.jball.ball = ball;
slouken@1895
   925
        event.jball.xrel = xrel;
slouken@1895
   926
        event.jball.yrel = yrel;
slouken@6690
   927
        posted = SDL_PushEvent(&event) == 1;
slouken@1895
   928
    }
slouken@1361
   929
#endif /* !SDL_EVENTS_DISABLED */
slouken@12088
   930
    return posted;
slouken@0
   931
}
slouken@0
   932
slouken@1895
   933
int
slouken@1895
   934
SDL_PrivateJoystickButton(SDL_Joystick * joystick, Uint8 button, Uint8 state)
slouken@0
   935
{
slouken@1895
   936
    int posted;
slouken@1361
   937
#if !SDL_EVENTS_DISABLED
slouken@1895
   938
    SDL_Event event;
slouken@0
   939
slouken@1895
   940
    switch (state) {
slouken@1895
   941
    case SDL_PRESSED:
slouken@1895
   942
        event.type = SDL_JOYBUTTONDOWN;
slouken@1895
   943
        break;
slouken@1895
   944
    case SDL_RELEASED:
slouken@1895
   945
        event.type = SDL_JOYBUTTONUP;
slouken@1895
   946
        break;
slouken@1895
   947
    default:
slouken@1895
   948
        /* Invalid state -- bail */
slouken@12088
   949
        return 0;
slouken@1895
   950
    }
slouken@1361
   951
#endif /* !SDL_EVENTS_DISABLED */
slouken@0
   952
slouken@8920
   953
    /* Make sure we're not getting garbage or duplicate events */
slouken@6145
   954
    if (button >= joystick->nbuttons) {
slouken@6145
   955
        return 0;
slouken@9884
   956
    }
slouken@9884
   957
    if (state == joystick->buttons[button]) {
slouken@9884
   958
        return 0;
slouken@9884
   959
    }
slouken@6145
   960
jorgen@7279
   961
    /* We ignore events if we don't have keyboard focus, except for button
jorgen@7279
   962
     * release. */
slouken@8903
   963
    if (SDL_PrivateJoystickShouldIgnoreEvent()) {
slouken@8903
   964
        if (state == SDL_PRESSED) {
slouken@8903
   965
            return 0;
slouken@8903
   966
        }
jorgen@7279
   967
    }
jorgen@7279
   968
slouken@1895
   969
    /* Update internal joystick state */
slouken@1895
   970
    joystick->buttons[button] = state;
slouken@0
   971
slouken@1895
   972
    /* Post the event, if desired */
slouken@1895
   973
    posted = 0;
slouken@1361
   974
#if !SDL_EVENTS_DISABLED
slouken@4429
   975
    if (SDL_GetEventState(event.type) == SDL_ENABLE) {
slouken@6690
   976
        event.jbutton.which = joystick->instance_id;
slouken@1895
   977
        event.jbutton.button = button;
slouken@1895
   978
        event.jbutton.state = state;
slouken@6690
   979
        posted = SDL_PushEvent(&event) == 1;
slouken@1895
   980
    }
slouken@1361
   981
#endif /* !SDL_EVENTS_DISABLED */
slouken@12088
   982
    return posted;
slouken@0
   983
}
slouken@0
   984
slouken@1895
   985
void
slouken@1895
   986
SDL_JoystickUpdate(void)
slouken@0
   987
{
slouken@12088
   988
    int i;
slouken@10704
   989
    SDL_Joystick *joystick;
slouken@7191
   990
slouken@11581
   991
    SDL_LockJoysticks();
slouken@10659
   992
slouken@10688
   993
    if (SDL_updating_joystick) {
slouken@10688
   994
        /* The joysticks are already being updated */
slouken@11581
   995
        SDL_UnlockJoysticks();
slouken@10688
   996
        return;
slouken@10688
   997
    }
slouken@10688
   998
slouken@10704
   999
    SDL_updating_joystick = SDL_TRUE;
slouken@0
  1000
slouken@10704
  1001
    /* Make sure the list is unlocked while dispatching events to prevent application deadlocks */
slouken@11581
  1002
    SDL_UnlockJoysticks();
slouken@6712
  1003
slouken@10704
  1004
    for (joystick = SDL_joysticks; joystick; joystick = joystick->next) {
slouken@12090
  1005
        if (joystick->attached) {
slouken@12090
  1006
            joystick->driver->Update(joystick);
slouken@6690
  1007
slouken@12090
  1008
            if (joystick->delayed_guide_button) {
slouken@12090
  1009
                SDL_GameControllerHandleDelayedGuideButton(joystick);
slouken@12090
  1010
            }
slouken@11934
  1011
        }
slouken@11934
  1012
icculus@9433
  1013
        if (joystick->force_recentering) {
slouken@10745
  1014
            /* Tell the app that everything is centered/unpressed... */
slime73@9876
  1015
            for (i = 0; i < joystick->naxes; i++) {
slouken@10745
  1016
                if (joystick->axes[i].has_initial_value) {
slouken@10745
  1017
                    SDL_PrivateJoystickAxis(joystick, i, joystick->axes[i].zero);
slouken@10745
  1018
                }
slime73@9876
  1019
            }
slouken@6690
  1020
slime73@9876
  1021
            for (i = 0; i < joystick->nbuttons; i++) {
slouken@6690
  1022
                SDL_PrivateJoystickButton(joystick, i, 0);
slime73@9876
  1023
            }
slouken@6690
  1024
slime73@9876
  1025
            for (i = 0; i < joystick->nhats; i++) {
slouken@6690
  1026
                SDL_PrivateJoystickHat(joystick, i, SDL_HAT_CENTERED);
slime73@9876
  1027
            }
slouken@6712
  1028
icculus@9433
  1029
            joystick->force_recentering = SDL_FALSE;
slouken@7191
  1030
        }
slouken@10704
  1031
    }
slouken@6690
  1032
slouken@11581
  1033
    SDL_LockJoysticks();
slouken@10688
  1034
slouken@10704
  1035
    SDL_updating_joystick = SDL_FALSE;
slouken@6712
  1036
slouken@10704
  1037
    /* If any joysticks were closed while updating, free them here */
slouken@10704
  1038
    for (joystick = SDL_joysticks; joystick; joystick = joystick->next) {
slouken@8920
  1039
        if (joystick->ref_count <= 0) {
slouken@6712
  1040
            SDL_JoystickClose(joystick);
slouken@6712
  1041
        }
slouken@7191
  1042
    }
slouken@6690
  1043
slouken@7191
  1044
    /* this needs to happen AFTER walking the joystick list above, so that any
slouken@7191
  1045
       dangling hardware data from removed devices can be free'd
slouken@7191
  1046
     */
slouken@12088
  1047
    for (i = 0; i < SDL_arraysize(SDL_joystick_drivers); ++i) {
slouken@12088
  1048
        SDL_joystick_drivers[i]->Detect();
slouken@12088
  1049
    }
slouken@10659
  1050
slouken@11581
  1051
    SDL_UnlockJoysticks();
slouken@0
  1052
}
slouken@0
  1053
slouken@1895
  1054
int
slouken@1895
  1055
SDL_JoystickEventState(int state)
slouken@0
  1056
{
slouken@1361
  1057
#if SDL_EVENTS_DISABLED
slouken@6753
  1058
    return SDL_DISABLE;
slouken@0
  1059
#else
slouken@4429
  1060
    const Uint32 event_list[] = {
slouken@1895
  1061
        SDL_JOYAXISMOTION, SDL_JOYBALLMOTION, SDL_JOYHATMOTION,
slouken@6690
  1062
        SDL_JOYBUTTONDOWN, SDL_JOYBUTTONUP, SDL_JOYDEVICEADDED, SDL_JOYDEVICEREMOVED
slouken@1895
  1063
    };
slouken@1895
  1064
    unsigned int i;
slouken@0
  1065
slouken@1895
  1066
    switch (state) {
slouken@1895
  1067
    case SDL_QUERY:
slouken@6753
  1068
        state = SDL_DISABLE;
slouken@1895
  1069
        for (i = 0; i < SDL_arraysize(event_list); ++i) {
slouken@1895
  1070
            state = SDL_EventState(event_list[i], SDL_QUERY);
slouken@1895
  1071
            if (state == SDL_ENABLE) {
slouken@1895
  1072
                break;
slouken@1895
  1073
            }
slouken@1895
  1074
        }
slouken@1895
  1075
        break;
slouken@1895
  1076
    default:
slouken@1895
  1077
        for (i = 0; i < SDL_arraysize(event_list); ++i) {
slouken@1895
  1078
            SDL_EventState(event_list[i], state);
slouken@1895
  1079
        }
slouken@1895
  1080
        break;
slouken@1895
  1081
    }
slouken@12088
  1082
    return state;
slouken@1361
  1083
#endif /* SDL_EVENTS_DISABLED */
slouken@0
  1084
}
slouken@1895
  1085
slouken@11201
  1086
void SDL_GetJoystickGUIDInfo(SDL_JoystickGUID guid, Uint16 *vendor, Uint16 *product, Uint16 *version)
slouken@10595
  1087
{
slouken@10595
  1088
    Uint16 *guid16 = (Uint16 *)guid.data;
slouken@10595
  1089
slouken@10595
  1090
    /* If the GUID fits the form of BUS 0000 VENDOR 0000 PRODUCT 0000, return the data */
slouken@10595
  1091
    if (/* guid16[0] is device bus type */
slouken@10647
  1092
        guid16[1] == 0x0000 &&
slouken@10595
  1093
        /* guid16[2] is vendor ID */
slouken@10647
  1094
        guid16[3] == 0x0000 &&
slouken@10595
  1095
        /* guid16[4] is product ID */
slouken@10647
  1096
        guid16[5] == 0x0000
slouken@10595
  1097
        /* guid16[6] is product version */
slouken@12088
  1098
   ) {
slouken@10595
  1099
        if (vendor) {
slouken@10595
  1100
            *vendor = guid16[2];
slouken@10595
  1101
        }
slouken@10595
  1102
        if (product) {
slouken@10595
  1103
            *product = guid16[4];
slouken@10595
  1104
        }
slouken@10595
  1105
        if (version) {
slouken@10595
  1106
            *version = guid16[6];
slouken@10595
  1107
        }
slouken@10595
  1108
    } else {
slouken@10595
  1109
        if (vendor) {
slouken@10595
  1110
            *vendor = 0;
slouken@10595
  1111
        }
slouken@10595
  1112
        if (product) {
slouken@10595
  1113
            *product = 0;
slouken@10595
  1114
        }
slouken@10595
  1115
        if (version) {
slouken@10595
  1116
            *version = 0;
slouken@10595
  1117
        }
slouken@10595
  1118
    }
slouken@10595
  1119
}
slouken@10595
  1120
slouken@12088
  1121
SDL_bool
slouken@12088
  1122
SDL_IsJoystickPS4(Uint16 vendor, Uint16 product)
slouken@12088
  1123
{
slouken@12088
  1124
    return (GuessControllerType(vendor, product) == k_eControllerType_PS4Controller);
slouken@12088
  1125
}
slouken@12088
  1126
slouken@12088
  1127
SDL_bool
slouken@12088
  1128
SDL_IsJoystickNintendoSwitchPro(Uint16 vendor, Uint16 product)
slouken@12088
  1129
{
slouken@12088
  1130
    return (GuessControllerType(vendor, product) == k_eControllerType_SwitchProController);
slouken@12088
  1131
}
slouken@12088
  1132
slouken@12088
  1133
SDL_bool
slouken@12088
  1134
SDL_IsJoystickSteamController(Uint16 vendor, Uint16 product)
slouken@12088
  1135
{
slouken@12088
  1136
    return BIsSteamController(GuessControllerType(vendor, product)) ? SDL_TRUE : SDL_FALSE;
slouken@12088
  1137
}
slouken@12088
  1138
slouken@12088
  1139
SDL_bool
slouken@12088
  1140
SDL_IsJoystickXbox360(Uint16 vendor, Uint16 product)
slouken@12088
  1141
{
slouken@12088
  1142
	/* Filter out some bogus values here */
slouken@12088
  1143
	if (vendor == 0x0000 && product == 0x0000) {
slouken@12088
  1144
		return SDL_FALSE;
slouken@12088
  1145
	}
slouken@12088
  1146
	if (vendor == 0x0001 && product == 0x0001) {
slouken@12088
  1147
		return SDL_FALSE;
slouken@12088
  1148
	}
slouken@12088
  1149
    return (GuessControllerType(vendor, product) == k_eControllerType_XBox360Controller);
slouken@12088
  1150
}
slouken@12088
  1151
slouken@12088
  1152
SDL_bool
slouken@12088
  1153
SDL_IsJoystickXboxOne(Uint16 vendor, Uint16 product)
slouken@12088
  1154
{
slouken@12088
  1155
    return (GuessControllerType(vendor, product) == k_eControllerType_XBoxOneController);
slouken@12088
  1156
}
slouken@12088
  1157
slouken@10868
  1158
static SDL_bool SDL_IsJoystickProductWheel(Uint32 vidpid)
slouken@10855
  1159
{
slouken@10855
  1160
    static Uint32 wheel_joysticks[] = {
slouken@10855
  1161
        MAKE_VIDPID(0x046d, 0xc294),    /* Logitech generic wheel */
slouken@10855
  1162
        MAKE_VIDPID(0x046d, 0xc295),    /* Logitech Momo Force */
slouken@10855
  1163
        MAKE_VIDPID(0x046d, 0xc298),    /* Logitech Driving Force Pro */
slouken@10855
  1164
        MAKE_VIDPID(0x046d, 0xc299),    /* Logitech G25 */
slouken@10855
  1165
        MAKE_VIDPID(0x046d, 0xc29a),    /* Logitech Driving Force GT */
slouken@10855
  1166
        MAKE_VIDPID(0x046d, 0xc29b),    /* Logitech G27 */
slouken@10855
  1167
        MAKE_VIDPID(0x046d, 0xc261),    /* Logitech G920 (initial mode) */
slouken@10855
  1168
        MAKE_VIDPID(0x046d, 0xc262),    /* Logitech G920 (active mode) */
slouken@10855
  1169
        MAKE_VIDPID(0x044f, 0xb65d),    /* Thrustmaster Wheel FFB */
slouken@10856
  1170
        MAKE_VIDPID(0x044f, 0xb66d),    /* Thrustmaster Wheel FFB */
slouken@10855
  1171
        MAKE_VIDPID(0x044f, 0xb677),    /* Thrustmaster T150 */
slouken@10855
  1172
        MAKE_VIDPID(0x044f, 0xb664),    /* Thrustmaster TX (initial mode) */
slouken@10855
  1173
        MAKE_VIDPID(0x044f, 0xb669),    /* Thrustmaster TX (active mode) */
slouken@10855
  1174
    };
slouken@10855
  1175
    int i;
slouken@10855
  1176
slouken@10867
  1177
    for (i = 0; i < SDL_arraysize(wheel_joysticks); ++i) {
slouken@10867
  1178
        if (vidpid == wheel_joysticks[i]) {
slouken@10867
  1179
            return SDL_TRUE;
slouken@10867
  1180
        }
slouken@10867
  1181
    }
slouken@10867
  1182
    return SDL_FALSE;
slouken@10867
  1183
}
slouken@10855
  1184
slouken@10868
  1185
static SDL_bool SDL_IsJoystickProductFlightStick(Uint32 vidpid)
slouken@10867
  1186
{
slouken@10867
  1187
    static Uint32 flightstick_joysticks[] = {
slouken@10869
  1188
        MAKE_VIDPID(0x044f, 0x0402),    /* HOTAS Warthog Joystick */
slouken@10869
  1189
        MAKE_VIDPID(0x0738, 0x2221),    /* Saitek Pro Flight X-56 Rhino Stick */
slouken@10867
  1190
    };
slouken@10867
  1191
    int i;
slouken@10867
  1192
slouken@10867
  1193
    for (i = 0; i < SDL_arraysize(flightstick_joysticks); ++i) {
slouken@10867
  1194
        if (vidpid == flightstick_joysticks[i]) {
slouken@10855
  1195
            return SDL_TRUE;
slouken@10855
  1196
        }
slouken@10855
  1197
    }
slouken@10855
  1198
    return SDL_FALSE;
slouken@10855
  1199
}
slouken@10855
  1200
slouken@10868
  1201
static SDL_bool SDL_IsJoystickProductThrottle(Uint32 vidpid)
slouken@10868
  1202
{
slouken@10868
  1203
    static Uint32 throttle_joysticks[] = {
slouken@10869
  1204
        MAKE_VIDPID(0x044f, 0x0404),    /* HOTAS Warthog Throttle */
slouken@10869
  1205
        MAKE_VIDPID(0x0738, 0xa221),    /* Saitek Pro Flight X-56 Rhino Throttle */
slouken@10868
  1206
    };
slouken@10868
  1207
    int i;
slouken@10868
  1208
slouken@10868
  1209
    for (i = 0; i < SDL_arraysize(throttle_joysticks); ++i) {
slouken@10868
  1210
        if (vidpid == throttle_joysticks[i]) {
slouken@10868
  1211
            return SDL_TRUE;
slouken@10868
  1212
        }
slouken@10868
  1213
    }
slouken@10868
  1214
    return SDL_FALSE;
slouken@10868
  1215
}
slouken@10868
  1216
slouken@10855
  1217
static SDL_JoystickType SDL_GetJoystickGUIDType(SDL_JoystickGUID guid)
slouken@10855
  1218
{
slouken@10867
  1219
    Uint16 vendor;
slouken@10867
  1220
    Uint16 product;
slouken@10867
  1221
    Uint32 vidpid;
slouken@10867
  1222
slouken@10855
  1223
    if (guid.data[14] == 'x') {
slouken@10855
  1224
        /* XInput GUID, get the type based on the XInput device subtype */
slouken@10855
  1225
        switch (guid.data[15]) {
slouken@10855
  1226
        case 0x01:  /* XINPUT_DEVSUBTYPE_GAMEPAD */
slouken@10855
  1227
            return SDL_JOYSTICK_TYPE_GAMECONTROLLER;
slouken@10855
  1228
        case 0x02:  /* XINPUT_DEVSUBTYPE_WHEEL */
slouken@10855
  1229
            return SDL_JOYSTICK_TYPE_WHEEL;
slouken@10855
  1230
        case 0x03:  /* XINPUT_DEVSUBTYPE_ARCADE_STICK */
slouken@10855
  1231
            return SDL_JOYSTICK_TYPE_ARCADE_STICK;
slouken@10855
  1232
        case 0x04:  /* XINPUT_DEVSUBTYPE_FLIGHT_STICK */
slouken@10855
  1233
            return SDL_JOYSTICK_TYPE_FLIGHT_STICK;
slouken@10855
  1234
        case 0x05:  /* XINPUT_DEVSUBTYPE_DANCE_PAD */
slouken@10855
  1235
            return SDL_JOYSTICK_TYPE_DANCE_PAD;
slouken@10855
  1236
        case 0x06:  /* XINPUT_DEVSUBTYPE_GUITAR */
slouken@10855
  1237
        case 0x07:  /* XINPUT_DEVSUBTYPE_GUITAR_ALTERNATE */
slouken@10855
  1238
        case 0x0B:  /* XINPUT_DEVSUBTYPE_GUITAR_BASS */
slouken@10855
  1239
            return SDL_JOYSTICK_TYPE_GUITAR;
slouken@10855
  1240
        case 0x08:  /* XINPUT_DEVSUBTYPE_DRUM_KIT */
slouken@10855
  1241
            return SDL_JOYSTICK_TYPE_DRUM_KIT;
slouken@10855
  1242
        case 0x13:  /* XINPUT_DEVSUBTYPE_ARCADE_PAD */
slouken@10855
  1243
            return SDL_JOYSTICK_TYPE_ARCADE_PAD;
slouken@10855
  1244
        default:
slouken@10855
  1245
            return SDL_JOYSTICK_TYPE_UNKNOWN;
slouken@10855
  1246
        }
slouken@10855
  1247
    }
slouken@10855
  1248
slouken@10867
  1249
    SDL_GetJoystickGUIDInfo(guid, &vendor, &product, NULL);
slouken@10867
  1250
    vidpid = MAKE_VIDPID(vendor, product);
slouken@10867
  1251
slouken@10868
  1252
    if (SDL_IsJoystickProductWheel(vidpid)) {
slouken@10855
  1253
        return SDL_JOYSTICK_TYPE_WHEEL;
slouken@10855
  1254
    }
slouken@10855
  1255
slouken@10868
  1256
    if (SDL_IsJoystickProductFlightStick(vidpid)) {
slouken@10867
  1257
        return SDL_JOYSTICK_TYPE_FLIGHT_STICK;
slouken@10867
  1258
    }
slouken@10867
  1259
slouken@10868
  1260
    if (SDL_IsJoystickProductThrottle(vidpid)) {
slouken@10868
  1261
        return SDL_JOYSTICK_TYPE_THROTTLE;
slouken@10868
  1262
    }
slouken@10868
  1263
slouken@12088
  1264
    if (GuessControllerType(vendor, product) != k_eControllerType_UnknownNonSteamController) {
slouken@12088
  1265
        return SDL_JOYSTICK_TYPE_GAMECONTROLLER;
slouken@12088
  1266
    }
slouken@12088
  1267
slouken@10855
  1268
    return SDL_JOYSTICK_TYPE_UNKNOWN;
slouken@10855
  1269
}
slouken@10855
  1270
slouken@12088
  1271
static SDL_bool SDL_IsPS4RemapperRunning(void)
slouken@12088
  1272
{
slouken@12088
  1273
#ifdef __WIN32__
slouken@12088
  1274
    const char *mapper_processes[] = {
slouken@12088
  1275
        "DS4Windows.exe",
slouken@12088
  1276
        "InputMapper.exe",
slouken@12088
  1277
    };
slouken@12088
  1278
    int i;
slouken@12088
  1279
    PROCESSENTRY32 pe32;
slouken@12088
  1280
    SDL_bool found = SDL_FALSE;
slouken@12088
  1281
slouken@12088
  1282
    /* Take a snapshot of all processes in the system */
slouken@12088
  1283
    HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
slouken@12088
  1284
    if (hProcessSnap != INVALID_HANDLE_VALUE) {
slouken@12088
  1285
        pe32.dwSize = sizeof(PROCESSENTRY32);
slouken@12088
  1286
        if (Process32First(hProcessSnap, &pe32)) {
slouken@12088
  1287
            do
slouken@12088
  1288
            {
slouken@12088
  1289
                for (i = 0; i < SDL_arraysize(mapper_processes); ++i) {
slouken@12088
  1290
                    if (SDL_strcasecmp(pe32.szExeFile, mapper_processes[i]) == 0) {
slouken@12088
  1291
                        found = SDL_TRUE;
slouken@12088
  1292
                    }
slouken@12088
  1293
                }
slouken@12088
  1294
            } while (Process32Next(hProcessSnap, &pe32) && !found);
slouken@12088
  1295
        }
slouken@12088
  1296
        CloseHandle(hProcessSnap);
slouken@12088
  1297
    }
slouken@12088
  1298
    return found;
slouken@12088
  1299
#else
slouken@12088
  1300
    return SDL_FALSE;
slouken@12088
  1301
#endif
slouken@12088
  1302
}
slouken@12088
  1303
slouken@12088
  1304
SDL_bool SDL_ShouldIgnoreJoystick(const char *name, SDL_JoystickGUID guid)
slouken@12088
  1305
{
slouken@12088
  1306
    Uint16 vendor;
slouken@12088
  1307
    Uint16 product;
slouken@12088
  1308
slouken@12088
  1309
    SDL_GetJoystickGUIDInfo(guid, &vendor, &product, NULL);
slouken@12088
  1310
slouken@12088
  1311
    if (SDL_IsJoystickPS4(vendor, product) && SDL_IsPS4RemapperRunning()) {
slouken@12088
  1312
        return SDL_TRUE;
slouken@12088
  1313
    }
slouken@12088
  1314
slouken@12088
  1315
    if (SDL_IsGameControllerNameAndGUID(name, guid) &&
slouken@12088
  1316
        SDL_ShouldIgnoreGameController(name, guid)) {
slouken@12088
  1317
        return SDL_TRUE;
slouken@12088
  1318
    }
slouken@12088
  1319
slouken@12088
  1320
    return SDL_FALSE;
slouken@12088
  1321
}
slouken@12088
  1322
slouken@6693
  1323
/* return the guid for this index */
slouken@6738
  1324
SDL_JoystickGUID SDL_JoystickGetDeviceGUID(int device_index)
slouken@6690
  1325
{
slouken@12088
  1326
    SDL_JoystickDriver *driver;
slouken@12088
  1327
    SDL_JoystickGUID guid;
slouken@12088
  1328
slouken@12088
  1329
    SDL_LockJoysticks();
slouken@12088
  1330
    if (SDL_GetDriverAndJoystickIndex(device_index, &driver, &device_index)) {
slouken@12088
  1331
        guid = driver->GetDeviceGUID(device_index);
slouken@12088
  1332
    } else {
slouken@12088
  1333
        SDL_zero(guid);
slouken@7294
  1334
    }
slouken@12088
  1335
    SDL_UnlockJoysticks();
slouken@12088
  1336
slouken@12088
  1337
    return guid;
slouken@6690
  1338
}
slouken@6690
  1339
slouken@10595
  1340
Uint16 SDL_JoystickGetDeviceVendor(int device_index)
slouken@10595
  1341
{
slouken@10595
  1342
    Uint16 vendor;
slouken@10595
  1343
    SDL_JoystickGUID guid = SDL_JoystickGetDeviceGUID(device_index);
slouken@10595
  1344
slouken@10855
  1345
    SDL_GetJoystickGUIDInfo(guid, &vendor, NULL, NULL);
slouken@10595
  1346
    return vendor;
slouken@10595
  1347
}
slouken@10595
  1348
slouken@10595
  1349
Uint16 SDL_JoystickGetDeviceProduct(int device_index)
slouken@10595
  1350
{
slouken@10595
  1351
    Uint16 product;
slouken@10595
  1352
    SDL_JoystickGUID guid = SDL_JoystickGetDeviceGUID(device_index);
slouken@10595
  1353
slouken@10855
  1354
    SDL_GetJoystickGUIDInfo(guid, NULL, &product, NULL);
slouken@10595
  1355
    return product;
slouken@10595
  1356
}
slouken@10595
  1357
slouken@10595
  1358
Uint16 SDL_JoystickGetDeviceProductVersion(int device_index)
slouken@10595
  1359
{
slouken@10595
  1360
    Uint16 version;
slouken@10595
  1361
    SDL_JoystickGUID guid = SDL_JoystickGetDeviceGUID(device_index);
slouken@10595
  1362
slouken@10855
  1363
    SDL_GetJoystickGUIDInfo(guid, NULL, NULL, &version);
slouken@10595
  1364
    return version;
slouken@10595
  1365
}
slouken@10595
  1366
slouken@10855
  1367
SDL_JoystickType SDL_JoystickGetDeviceType(int device_index)
slouken@10855
  1368
{
slouken@10855
  1369
    SDL_JoystickType type;
slouken@10855
  1370
    SDL_JoystickGUID guid = SDL_JoystickGetDeviceGUID(device_index);
slouken@10855
  1371
slouken@10855
  1372
    type = SDL_GetJoystickGUIDType(guid);
slouken@10855
  1373
    if (type == SDL_JOYSTICK_TYPE_UNKNOWN) {
slouken@10855
  1374
        if (SDL_IsGameController(device_index)) {
slouken@10855
  1375
            type = SDL_JOYSTICK_TYPE_GAMECONTROLLER;
slouken@10855
  1376
        }
slouken@10855
  1377
    }
slouken@10855
  1378
    return type;
slouken@10855
  1379
}
slouken@10855
  1380
slouken@10934
  1381
SDL_JoystickID SDL_JoystickGetDeviceInstanceID(int device_index)
slouken@10934
  1382
{
slouken@12088
  1383
    SDL_JoystickDriver *driver;
slouken@12088
  1384
    SDL_JoystickID instance_id = -1;
slouken@12088
  1385
slouken@12088
  1386
    SDL_LockJoysticks();
slouken@12088
  1387
    if (SDL_GetDriverAndJoystickIndex(device_index, &driver, &device_index)) {
slouken@12088
  1388
        instance_id = driver->GetDeviceInstanceID(device_index);
slouken@10934
  1389
    }
slouken@12088
  1390
    SDL_UnlockJoysticks();
slouken@12088
  1391
slouken@12088
  1392
    return instance_id;
slouken@12088
  1393
}
slouken@12088
  1394
slouken@12088
  1395
int SDL_JoystickGetDeviceIndexFromInstanceID(SDL_JoystickID instance_id)
slouken@12088
  1396
{
slouken@12088
  1397
    int i, num_joysticks, device_index = -1;
slouken@12088
  1398
slouken@12088
  1399
    SDL_LockJoysticks();
slouken@12088
  1400
    num_joysticks = SDL_NumJoysticks();
slouken@12088
  1401
    for (i = 0; i < num_joysticks; ++i) {
slouken@12088
  1402
        if (SDL_JoystickGetDeviceInstanceID(i) == instance_id) {
slouken@12088
  1403
            device_index = i;
slouken@12088
  1404
            break;
slouken@12088
  1405
        }
slouken@12088
  1406
    }
slouken@12088
  1407
    SDL_UnlockJoysticks();
slouken@12088
  1408
slouken@12088
  1409
    return device_index;
slouken@10934
  1410
}
slouken@10934
  1411
slouken@6738
  1412
SDL_JoystickGUID SDL_JoystickGetGUID(SDL_Joystick * joystick)
slouken@6690
  1413
{
slouken@7789
  1414
    if (!SDL_PrivateJoystickValid(joystick)) {
slouken@7789
  1415
        SDL_JoystickGUID emptyGUID;
slouken@8920
  1416
        SDL_zero(emptyGUID);
slouken@7789
  1417
        return emptyGUID;
slouken@7789
  1418
    }
slouken@12088
  1419
    return joystick->guid;
slouken@6690
  1420
}
slouken@6690
  1421
slouken@10595
  1422
Uint16 SDL_JoystickGetVendor(SDL_Joystick * joystick)
slouken@10595
  1423
{
slouken@10595
  1424
    Uint16 vendor;
slouken@10595
  1425
    SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
slouken@10595
  1426
slouken@10855
  1427
    SDL_GetJoystickGUIDInfo(guid, &vendor, NULL, NULL);
slouken@10595
  1428
    return vendor;
slouken@10595
  1429
}
slouken@10595
  1430
slouken@10595
  1431
Uint16 SDL_JoystickGetProduct(SDL_Joystick * joystick)
slouken@10595
  1432
{
slouken@10595
  1433
    Uint16 product;
slouken@10595
  1434
    SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
slouken@10595
  1435
slouken@10855
  1436
    SDL_GetJoystickGUIDInfo(guid, NULL, &product, NULL);
slouken@10595
  1437
    return product;
slouken@10595
  1438
}
slouken@10595
  1439
slouken@10595
  1440
Uint16 SDL_JoystickGetProductVersion(SDL_Joystick * joystick)
slouken@10595
  1441
{
slouken@10595
  1442
    Uint16 version;
slouken@10595
  1443
    SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
slouken@10595
  1444
slouken@10855
  1445
    SDL_GetJoystickGUIDInfo(guid, NULL, NULL, &version);
slouken@10595
  1446
    return version;
slouken@10595
  1447
}
slouken@10595
  1448
slouken@10855
  1449
SDL_JoystickType SDL_JoystickGetType(SDL_Joystick * joystick)
slouken@10855
  1450
{
slouken@10855
  1451
    SDL_JoystickType type;
slouken@10855
  1452
    SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
slouken@10855
  1453
slouken@10855
  1454
    type = SDL_GetJoystickGUIDType(guid);
slouken@10855
  1455
    if (type == SDL_JOYSTICK_TYPE_UNKNOWN) {
slouken@10855
  1456
        if (joystick && joystick->is_game_controller) {
slouken@10855
  1457
            type = SDL_JOYSTICK_TYPE_GAMECONTROLLER;
slouken@10855
  1458
        }
slouken@10855
  1459
    }
slouken@10855
  1460
    return type;
slouken@10855
  1461
}
slouken@10855
  1462
slouken@6690
  1463
/* convert the guid to a printable string */
slouken@8920
  1464
void SDL_JoystickGetGUIDString(SDL_JoystickGUID guid, char *pszGUID, int cbGUID)
slouken@6690
  1465
{
slouken@7191
  1466
    static const char k_rgchHexToASCII[] = "0123456789abcdef";
slouken@7191
  1467
    int i;
slouken@6690
  1468
icculus@6748
  1469
    if ((pszGUID == NULL) || (cbGUID <= 0)) {
icculus@6748
  1470
        return;
icculus@6748
  1471
    }
icculus@6748
  1472
slouken@8920
  1473
    for (i = 0; i < sizeof(guid.data) && i < (cbGUID-1)/2; i++) {
slouken@7191
  1474
        /* each input byte writes 2 ascii chars, and might write a null byte. */
slouken@7191
  1475
        /* If we don't have room for next input byte, stop */
slouken@7191
  1476
        unsigned char c = guid.data[i];
slouken@6690
  1477
slouken@8920
  1478
        *pszGUID++ = k_rgchHexToASCII[c >> 4];
slouken@8920
  1479
        *pszGUID++ = k_rgchHexToASCII[c & 0x0F];
slouken@7191
  1480
    }
slouken@7191
  1481
    *pszGUID = '\0';
slouken@6690
  1482
}
slouken@6690
  1483
slouken@7191
  1484
/*-----------------------------------------------------------------------------
slouken@7191
  1485
 * Purpose: Returns the 4 bit nibble for a hex character
slouken@7191
  1486
 * Input  : c -
slouken@7191
  1487
 * Output : unsigned char
slouken@7191
  1488
 *-----------------------------------------------------------------------------*/
slouken@8920
  1489
static unsigned char nibble(char c)
slouken@6690
  1490
{
slouken@8920
  1491
    if ((c >= '0') && (c <= '9')) {
slouken@7191
  1492
        return (unsigned char)(c - '0');
slouken@7191
  1493
    }
slouken@6690
  1494
slouken@8920
  1495
    if ((c >= 'A') && (c <= 'F')) {
slouken@7191
  1496
        return (unsigned char)(c - 'A' + 0x0a);
slouken@7191
  1497
    }
slouken@6690
  1498
slouken@8920
  1499
    if ((c >= 'a') && (c <= 'f')) {
slouken@7191
  1500
        return (unsigned char)(c - 'a' + 0x0a);
slouken@7191
  1501
    }
slouken@6690
  1502
slouken@7191
  1503
    /* received an invalid character, and no real way to return an error */
slouken@8920
  1504
    /* AssertMsg1(false, "Q_nibble invalid hex character '%c' ", c); */
slouken@7191
  1505
    return 0;
slouken@6690
  1506
}
slouken@6690
  1507
slouken@6690
  1508
/* convert the string version of a joystick guid to the struct */
slouken@6738
  1509
SDL_JoystickGUID SDL_JoystickGetGUIDFromString(const char *pchGUID)
slouken@6690
  1510
{
slouken@7191
  1511
    SDL_JoystickGUID guid;
slouken@7191
  1512
    int maxoutputbytes= sizeof(guid);
slouken@8920
  1513
    size_t len = SDL_strlen(pchGUID);
slouken@7191
  1514
    Uint8 *p;
slouken@7922
  1515
    size_t i;
slouken@6690
  1516
slouken@7191
  1517
    /* Make sure it's even */
slouken@8920
  1518
    len = (len) & ~0x1;
slouken@6690
  1519
slouken@8920
  1520
    SDL_memset(&guid, 0x00, sizeof(guid));
slouken@6690
  1521
slouken@7191
  1522
    p = (Uint8 *)&guid;
slouken@8920
  1523
    for (i = 0; (i < len) && ((p - (Uint8 *)&guid) < maxoutputbytes); i+=2, p++) {
slouken@8920
  1524
        *p = (nibble(pchGUID[i]) << 4) | nibble(pchGUID[i+1]);
slouken@7191
  1525
    }
slouken@6690
  1526
slouken@7191
  1527
    return guid;
slouken@6690
  1528
}
slouken@6690
  1529
slouken@9884
  1530
/* update the power level for this joystick */
slouken@9884
  1531
void SDL_PrivateJoystickBatteryLevel(SDL_Joystick * joystick, SDL_JoystickPowerLevel ePowerLevel)
slouken@9884
  1532
{
slouken@9884
  1533
    joystick->epowerlevel = ePowerLevel;
slouken@9884
  1534
}
slouken@9884
  1535
slouken@9884
  1536
/* return its power level */
slouken@9884
  1537
SDL_JoystickPowerLevel SDL_JoystickCurrentPowerLevel(SDL_Joystick * joystick)
slouken@9884
  1538
{
slouken@9884
  1539
    if (!SDL_PrivateJoystickValid(joystick)) {
slouken@12088
  1540
        return SDL_JOYSTICK_POWER_UNKNOWN;
slouken@9884
  1541
    }
slouken@9884
  1542
    return joystick->epowerlevel;
slouken@9884
  1543
}
slouken@9884
  1544
slouken@1895
  1545
/* vi: set ts=4 sw=4 expandtab: */