src/joystick/SDL_joystick.c
author Sam Lantinga <slouken@libsdl.org>
Tue, 24 Jun 2014 13:31:25 -0700
changeset 8920 21ccd40c778a
parent 8903 8e09eceea61e
child 9433 bd062398b648
permissions -rw-r--r--
Fixed bug 2553 - Add support to all XInput devices

This adds support for all XInput devices, exposed through the SDL joystick API.
The button and axis reporting for XInput devices has been changed to match DirectInput and other platforms.
The game controller xinput mapping has been updated so this change is seamless.
There is a new hint, SDL_HINT_XINPUT_USE_OLD_JOYSTICK_MAPPING, for any applications that have hardcoded the old xinput button and axis set. This hint will be removed in SDL 2.1.
slouken@0
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@8149
     3
  Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
slouken@0
     4
slouken@5535
     5
  This software is provided 'as-is', without any express or implied
slouken@5535
     6
  warranty.  In no event will the authors be held liable for any damages
slouken@5535
     7
  arising from the use of this software.
slouken@0
     8
slouken@5535
     9
  Permission is granted to anyone to use this software for any purpose,
slouken@5535
    10
  including commercial applications, and to alter it and redistribute it
slouken@5535
    11
  freely, subject to the following restrictions:
slouken@0
    12
slouken@5535
    13
  1. The origin of this software must not be misrepresented; you must not
slouken@5535
    14
     claim that you wrote the original software. If you use this software
slouken@5535
    15
     in a product, an acknowledgment in the product documentation would be
slouken@5535
    16
     appreciated but is not required.
slouken@5535
    17
  2. Altered source versions must be plainly marked as such, and must not be
slouken@5535
    18
     misrepresented as being the original software.
slouken@5535
    19
  3. This notice may not be removed or altered from any source distribution.
slouken@0
    20
*/
icculus@8093
    21
#include "../SDL_internal.h"
slouken@0
    22
slouken@0
    23
/* This is the joystick API for Simple DirectMedia Layer */
slouken@0
    24
slouken@7337
    25
#include "SDL.h"
slouken@0
    26
#include "SDL_events.h"
slouken@1361
    27
#include "SDL_sysjoystick.h"
icculus@5861
    28
#include "SDL_assert.h"
jorgen@7279
    29
#include "SDL_hints.h"
icculus@5861
    30
slouken@1361
    31
#if !SDL_EVENTS_DISABLED
slouken@1361
    32
#include "../events/SDL_events_c.h"
slouken@0
    33
#endif
slouken@0
    34
slouken@7337
    35
static SDL_bool SDL_joystick_allows_background_events = SDL_FALSE;
slouken@6712
    36
static SDL_Joystick *SDL_joysticks = NULL;
slouken@6712
    37
static SDL_Joystick *SDL_updating_joystick = NULL;
slouken@0
    38
slouken@7432
    39
static void
slouken@7432
    40
SDL_JoystickAllowBackgroundEventsChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
slouken@7432
    41
{
slouken@7432
    42
    if (hint && *hint == '1') {
slouken@7432
    43
        SDL_joystick_allows_background_events = SDL_TRUE;
slouken@7432
    44
    } else {
slouken@7432
    45
        SDL_joystick_allows_background_events = SDL_FALSE;
slouken@7432
    46
    }
slouken@7432
    47
}
slouken@7432
    48
slouken@1895
    49
int
slouken@1895
    50
SDL_JoystickInit(void)
slouken@0
    51
{
slouken@1895
    52
    int status;
philipp@7500
    53
slouken@7432
    54
    /* See if we should allow joystick events while in the background */
slouken@7432
    55
    SDL_AddHintCallback(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS,
slouken@7432
    56
                        SDL_JoystickAllowBackgroundEventsChanged, NULL);
slouken@0
    57
slouken@7360
    58
#if !SDL_EVENTS_DISABLED
slouken@7360
    59
    if (SDL_InitSubSystem(SDL_INIT_EVENTS) < 0) {
slouken@7360
    60
        return -1;
slouken@7360
    61
    }
slouken@7360
    62
#endif /* !SDL_EVENTS_DISABLED */
slouken@7360
    63
slouken@1895
    64
    status = SDL_SYS_JoystickInit();
slouken@1895
    65
    if (status >= 0) {
slouken@7337
    66
        status = 0;
slouken@1895
    67
    }
slouken@1895
    68
    return (status);
slouken@0
    69
}
slouken@0
    70
slouken@0
    71
/*
slouken@0
    72
 * Count the number of joysticks attached to the system
slouken@0
    73
 */
slouken@1895
    74
int
slouken@1895
    75
SDL_NumJoysticks(void)
slouken@0
    76
{
slouken@6690
    77
    return SDL_SYS_NumJoysticks();
slouken@0
    78
}
slouken@0
    79
slouken@0
    80
/*
slouken@0
    81
 * Get the implementation dependent name of a joystick
slouken@0
    82
 */
slouken@1895
    83
const char *
slouken@6690
    84
SDL_JoystickNameForIndex(int device_index)
slouken@0
    85
{
slouken@6690
    86
    if ((device_index < 0) || (device_index >= SDL_NumJoysticks())) {
slouken@6690
    87
        SDL_SetError("There are %d joysticks available", SDL_NumJoysticks());
slouken@1895
    88
        return (NULL);
slouken@1895
    89
    }
slouken@6707
    90
    return (SDL_SYS_JoystickNameForDeviceIndex(device_index));
slouken@0
    91
}
slouken@0
    92
slouken@0
    93
/*
slouken@0
    94
 * Open a joystick for use - the index passed as an argument refers to
slouken@0
    95
 * the N'th joystick on the system.  This index is the value which will
slouken@0
    96
 * identify this joystick in future joystick events.
slouken@0
    97
 *
slouken@0
    98
 * This function returns a joystick identifier, or NULL if an error occurred.
slouken@0
    99
 */
slouken@1895
   100
SDL_Joystick *
slouken@1895
   101
SDL_JoystickOpen(int device_index)
slouken@0
   102
{
slouken@1895
   103
    SDL_Joystick *joystick;
slouken@7191
   104
    SDL_Joystick *joysticklist;
slouken@7191
   105
    const char *joystickname = NULL;
slouken@0
   106
slouken@6690
   107
    if ((device_index < 0) || (device_index >= SDL_NumJoysticks())) {
slouken@6690
   108
        SDL_SetError("There are %d joysticks available", SDL_NumJoysticks());
slouken@1895
   109
        return (NULL);
slouken@1895
   110
    }
slouken@0
   111
slouken@7191
   112
    joysticklist = SDL_joysticks;
slouken@7191
   113
    /* If the joystick is already open, return it
slouken@7191
   114
    * it is important that we have a single joystick * for each instance id
slouken@7191
   115
    */
slouken@8920
   116
    while (joysticklist) {
slouken@8920
   117
        if (SDL_SYS_GetInstanceIdOfDeviceIndex(device_index) == joysticklist->instance_id) {
slouken@7191
   118
                joystick = joysticklist;
slouken@7191
   119
                ++joystick->ref_count;
slouken@7191
   120
                return (joystick);
slouken@7191
   121
        }
slouken@7191
   122
        joysticklist = joysticklist->next;
slouken@1895
   123
    }
slouken@0
   124
slouken@1895
   125
    /* Create and initialize the joystick */
slouken@1895
   126
    joystick = (SDL_Joystick *) SDL_malloc((sizeof *joystick));
icculus@3608
   127
    if (joystick == NULL) {
icculus@3608
   128
        SDL_OutOfMemory();
icculus@3608
   129
        return NULL;
slouken@1895
   130
    }
icculus@3608
   131
icculus@3608
   132
    SDL_memset(joystick, 0, (sizeof *joystick));
slouken@6690
   133
    if (SDL_SYS_JoystickOpen(joystick, device_index) < 0) {
icculus@3608
   134
        SDL_free(joystick);
icculus@3608
   135
        return NULL;
slouken@1895
   136
    }
slouken@6690
   137
slouken@8920
   138
    joystickname = SDL_SYS_JoystickNameForDeviceIndex(device_index);
slouken@8920
   139
    if (joystickname)
slouken@8920
   140
        joystick->name = SDL_strdup(joystickname);
slouken@7191
   141
    else
slouken@7191
   142
        joystick->name = NULL;
slouken@6690
   143
icculus@3608
   144
    if (joystick->naxes > 0) {
icculus@3608
   145
        joystick->axes = (Sint16 *) SDL_malloc
icculus@3608
   146
            (joystick->naxes * sizeof(Sint16));
icculus@3608
   147
    }
icculus@3608
   148
    if (joystick->nhats > 0) {
icculus@3608
   149
        joystick->hats = (Uint8 *) SDL_malloc
icculus@3608
   150
            (joystick->nhats * sizeof(Uint8));
icculus@3608
   151
    }
icculus@3608
   152
    if (joystick->nballs > 0) {
icculus@3608
   153
        joystick->balls = (struct balldelta *) SDL_malloc
icculus@3608
   154
            (joystick->nballs * sizeof(*joystick->balls));
icculus@3608
   155
    }
icculus@3608
   156
    if (joystick->nbuttons > 0) {
icculus@3608
   157
        joystick->buttons = (Uint8 *) SDL_malloc
icculus@3608
   158
            (joystick->nbuttons * sizeof(Uint8));
icculus@3608
   159
    }
icculus@3608
   160
    if (((joystick->naxes > 0) && !joystick->axes)
icculus@3608
   161
        || ((joystick->nhats > 0) && !joystick->hats)
icculus@3608
   162
        || ((joystick->nballs > 0) && !joystick->balls)
icculus@3608
   163
        || ((joystick->nbuttons > 0) && !joystick->buttons)) {
icculus@3608
   164
        SDL_OutOfMemory();
icculus@3608
   165
        SDL_JoystickClose(joystick);
icculus@3608
   166
        return NULL;
icculus@3608
   167
    }
icculus@3608
   168
    if (joystick->axes) {
icculus@3608
   169
        SDL_memset(joystick->axes, 0, joystick->naxes * sizeof(Sint16));
icculus@3608
   170
    }
icculus@3608
   171
    if (joystick->hats) {
icculus@3608
   172
        SDL_memset(joystick->hats, 0, joystick->nhats * sizeof(Uint8));
icculus@3608
   173
    }
icculus@3608
   174
    if (joystick->balls) {
icculus@3608
   175
        SDL_memset(joystick->balls, 0,
icculus@3608
   176
            joystick->nballs * sizeof(*joystick->balls));
icculus@3608
   177
    }
icculus@3608
   178
    if (joystick->buttons) {
icculus@3608
   179
        SDL_memset(joystick->buttons, 0, joystick->nbuttons * sizeof(Uint8));
icculus@3608
   180
    }
icculus@3608
   181
icculus@3608
   182
    /* Add joystick to list */
icculus@3608
   183
    ++joystick->ref_count;
slouken@7191
   184
    /* Link the joystick in the list */
slouken@7191
   185
    joystick->next = SDL_joysticks;
slouken@7191
   186
    SDL_joysticks = joystick;
slouken@6690
   187
slouken@8920
   188
    SDL_SYS_JoystickUpdate(joystick);
icculus@3608
   189
slouken@1895
   190
    return (joystick);
slouken@0
   191
}
slouken@0
   192
slouken@2713
   193
slouken@2713
   194
/*
slouken@2713
   195
 * Checks to make sure the joystick is valid.
slouken@2713
   196
 */
slouken@2713
   197
int
slouken@6690
   198
SDL_PrivateJoystickValid(SDL_Joystick * joystick)
slouken@0
   199
{
slouken@1895
   200
    int valid;
slouken@0
   201
slouken@8920
   202
    if (joystick == NULL) {
slouken@1895
   203
        SDL_SetError("Joystick hasn't been opened yet");
slouken@1895
   204
        valid = 0;
slouken@1895
   205
    } else {
slouken@1895
   206
        valid = 1;
slouken@1895
   207
    }
slouken@7191
   208
slouken@8920
   209
    if (joystick && joystick->closed) {
slouken@7191
   210
        valid = 0;
slouken@7191
   211
    }
slouken@7191
   212
slouken@1895
   213
    return valid;
slouken@0
   214
}
slouken@0
   215
slouken@0
   216
/*
slouken@0
   217
 * Get the number of multi-dimensional axis controls on a joystick
slouken@0
   218
 */
slouken@1895
   219
int
slouken@1895
   220
SDL_JoystickNumAxes(SDL_Joystick * joystick)
slouken@0
   221
{
slouken@6690
   222
    if (!SDL_PrivateJoystickValid(joystick)) {
slouken@1895
   223
        return (-1);
slouken@1895
   224
    }
slouken@1895
   225
    return (joystick->naxes);
slouken@0
   226
}
slouken@0
   227
slouken@0
   228
/*
slouken@0
   229
 * Get the number of hats on a joystick
slouken@0
   230
 */
slouken@1895
   231
int
slouken@1895
   232
SDL_JoystickNumHats(SDL_Joystick * joystick)
slouken@0
   233
{
slouken@6690
   234
    if (!SDL_PrivateJoystickValid(joystick)) {
slouken@1895
   235
        return (-1);
slouken@1895
   236
    }
slouken@1895
   237
    return (joystick->nhats);
slouken@0
   238
}
slouken@0
   239
slouken@0
   240
/*
slouken@0
   241
 * Get the number of trackballs on a joystick
slouken@0
   242
 */
slouken@1895
   243
int
slouken@1895
   244
SDL_JoystickNumBalls(SDL_Joystick * joystick)
slouken@0
   245
{
slouken@6690
   246
    if (!SDL_PrivateJoystickValid(joystick)) {
slouken@1895
   247
        return (-1);
slouken@1895
   248
    }
slouken@1895
   249
    return (joystick->nballs);
slouken@0
   250
}
slouken@0
   251
slouken@0
   252
/*
slouken@0
   253
 * Get the number of buttons on a joystick
slouken@0
   254
 */
slouken@1895
   255
int
slouken@1895
   256
SDL_JoystickNumButtons(SDL_Joystick * joystick)
slouken@0
   257
{
slouken@6690
   258
    if (!SDL_PrivateJoystickValid(joystick)) {
slouken@1895
   259
        return (-1);
slouken@1895
   260
    }
slouken@1895
   261
    return (joystick->nbuttons);
slouken@0
   262
}
slouken@0
   263
slouken@0
   264
/*
slouken@0
   265
 * Get the current state of an axis control on a joystick
slouken@0
   266
 */
slouken@1895
   267
Sint16
slouken@1895
   268
SDL_JoystickGetAxis(SDL_Joystick * joystick, int axis)
slouken@0
   269
{
slouken@1895
   270
    Sint16 state;
slouken@0
   271
slouken@6690
   272
    if (!SDL_PrivateJoystickValid(joystick)) {
slouken@1895
   273
        return (0);
slouken@1895
   274
    }
slouken@1895
   275
    if (axis < joystick->naxes) {
slouken@1895
   276
        state = joystick->axes[axis];
slouken@1895
   277
    } else {
slouken@1895
   278
        SDL_SetError("Joystick only has %d axes", joystick->naxes);
slouken@1895
   279
        state = 0;
slouken@1895
   280
    }
slouken@1895
   281
    return (state);
slouken@0
   282
}
slouken@0
   283
slouken@0
   284
/*
slouken@0
   285
 * Get the current state of a hat on a joystick
slouken@0
   286
 */
slouken@1895
   287
Uint8
slouken@1895
   288
SDL_JoystickGetHat(SDL_Joystick * joystick, int hat)
slouken@0
   289
{
slouken@1895
   290
    Uint8 state;
slouken@0
   291
slouken@6690
   292
    if (!SDL_PrivateJoystickValid(joystick)) {
slouken@1895
   293
        return (0);
slouken@1895
   294
    }
slouken@1895
   295
    if (hat < joystick->nhats) {
slouken@1895
   296
        state = joystick->hats[hat];
slouken@1895
   297
    } else {
slouken@1895
   298
        SDL_SetError("Joystick only has %d hats", joystick->nhats);
slouken@1895
   299
        state = 0;
slouken@1895
   300
    }
slouken@1895
   301
    return (state);
slouken@0
   302
}
slouken@0
   303
slouken@0
   304
/*
slouken@0
   305
 * Get the ball axis change since the last poll
slouken@0
   306
 */
slouken@1895
   307
int
slouken@1895
   308
SDL_JoystickGetBall(SDL_Joystick * joystick, int ball, int *dx, int *dy)
slouken@0
   309
{
slouken@1895
   310
    int retval;
slouken@0
   311
slouken@6690
   312
    if (!SDL_PrivateJoystickValid(joystick)) {
slouken@1895
   313
        return (-1);
slouken@1895
   314
    }
slouken@0
   315
slouken@1895
   316
    retval = 0;
slouken@1895
   317
    if (ball < joystick->nballs) {
slouken@1895
   318
        if (dx) {
slouken@1895
   319
            *dx = joystick->balls[ball].dx;
slouken@1895
   320
        }
slouken@1895
   321
        if (dy) {
slouken@1895
   322
            *dy = joystick->balls[ball].dy;
slouken@1895
   323
        }
slouken@1895
   324
        joystick->balls[ball].dx = 0;
slouken@1895
   325
        joystick->balls[ball].dy = 0;
slouken@1895
   326
    } else {
icculus@7037
   327
        return SDL_SetError("Joystick only has %d balls", joystick->nballs);
slouken@1895
   328
    }
slouken@1895
   329
    return (retval);
slouken@0
   330
}
slouken@0
   331
slouken@0
   332
/*
slouken@0
   333
 * Get the current state of a button on a joystick
slouken@0
   334
 */
slouken@1895
   335
Uint8
slouken@1895
   336
SDL_JoystickGetButton(SDL_Joystick * joystick, int button)
slouken@0
   337
{
slouken@1895
   338
    Uint8 state;
slouken@0
   339
slouken@6690
   340
    if (!SDL_PrivateJoystickValid(joystick)) {
slouken@1895
   341
        return (0);
slouken@1895
   342
    }
slouken@1895
   343
    if (button < joystick->nbuttons) {
slouken@1895
   344
        state = joystick->buttons[button];
slouken@1895
   345
    } else {
slouken@1895
   346
        SDL_SetError("Joystick only has %d buttons", joystick->nbuttons);
slouken@1895
   347
        state = 0;
slouken@1895
   348
    }
slouken@1895
   349
    return (state);
slouken@0
   350
}
slouken@0
   351
slouken@0
   352
/*
slouken@6690
   353
 * Return if the joystick in question is currently attached to the system,
philipp@7500
   354
 *  \return SDL_FALSE if not plugged in, SDL_TRUE if still present.
slouken@6690
   355
 */
slouken@6707
   356
SDL_bool
slouken@6707
   357
SDL_JoystickGetAttached(SDL_Joystick * joystick)
slouken@6690
   358
{
slouken@7191
   359
    if (!SDL_PrivateJoystickValid(joystick)) {
slouken@6707
   360
        return SDL_FALSE;
slouken@6690
   361
    }
slouken@6690
   362
slouken@7191
   363
    return SDL_SYS_JoystickAttached(joystick);
slouken@6690
   364
}
slouken@6690
   365
slouken@6690
   366
/*
slouken@6690
   367
 * Get the instance id for this opened joystick
slouken@6690
   368
 */
slouken@7191
   369
SDL_JoystickID
slouken@6707
   370
SDL_JoystickInstanceID(SDL_Joystick * joystick)
slouken@6690
   371
{
slouken@7191
   372
    if (!SDL_PrivateJoystickValid(joystick)) {
slouken@6690
   373
        return (-1);
slouken@6690
   374
    }
slouken@6690
   375
slouken@7191
   376
    return (joystick->instance_id);
slouken@6690
   377
}
slouken@6690
   378
slouken@6690
   379
/*
slouken@6690
   380
 * Get the friendly name of this joystick
slouken@6690
   381
 */
slouken@6690
   382
const char *
slouken@6690
   383
SDL_JoystickName(SDL_Joystick * joystick)
slouken@6690
   384
{
slouken@6690
   385
    if (!SDL_PrivateJoystickValid(joystick)) {
slouken@6690
   386
        return (NULL);
slouken@6690
   387
    }
slouken@7191
   388
slouken@6690
   389
    return (joystick->name);
slouken@6690
   390
}
slouken@6690
   391
slouken@6690
   392
/*
slouken@0
   393
 * Close a joystick previously opened with SDL_JoystickOpen()
slouken@0
   394
 */
slouken@1895
   395
void
slouken@1895
   396
SDL_JoystickClose(SDL_Joystick * joystick)
slouken@0
   397
{
slouken@7191
   398
    SDL_Joystick *joysticklist;
slouken@7191
   399
    SDL_Joystick *joysticklistprev;
slouken@0
   400
slouken@6690
   401
    if (!joystick) {
slouken@1895
   402
        return;
slouken@1895
   403
    }
slouken@0
   404
slouken@1895
   405
    /* First decrement ref count */
slouken@1895
   406
    if (--joystick->ref_count > 0) {
slouken@1895
   407
        return;
slouken@1895
   408
    }
slouken@0
   409
slouken@6712
   410
    if (joystick == SDL_updating_joystick) {
slouken@6712
   411
        return;
slouken@6712
   412
    }
slouken@6712
   413
slouken@1895
   414
    SDL_SYS_JoystickClose(joystick);
slouken@0
   415
slouken@7191
   416
    joysticklist = SDL_joysticks;
slouken@7191
   417
    joysticklistprev = NULL;
slouken@8920
   418
    while (joysticklist) {
slouken@8920
   419
        if (joystick == joysticklist) {
slouken@8920
   420
            if (joysticklistprev) {
slouken@7191
   421
                /* unlink this entry */
slouken@7191
   422
                joysticklistprev->next = joysticklist->next;
slouken@8920
   423
            } else {
slouken@7191
   424
                SDL_joysticks = joystick->next;
slouken@7191
   425
            }
slouken@7191
   426
            break;
slouken@7191
   427
        }
slouken@7191
   428
        joysticklistprev = joysticklist;
slouken@7191
   429
        joysticklist = joysticklist->next;
slouken@7191
   430
    }
slouken@7191
   431
slouken@7719
   432
    SDL_free(joystick->name);
slouken@0
   433
slouken@1895
   434
    /* Free the data associated with this joystick */
slouken@7719
   435
    SDL_free(joystick->axes);
slouken@7719
   436
    SDL_free(joystick->hats);
slouken@7719
   437
    SDL_free(joystick->balls);
slouken@7719
   438
    SDL_free(joystick->buttons);
slouken@1895
   439
    SDL_free(joystick);
slouken@0
   440
}
slouken@0
   441
slouken@1895
   442
void
slouken@1895
   443
SDL_JoystickQuit(void)
slouken@0
   444
{
slouken@6712
   445
    /* Make sure we're not getting called in the middle of updating joysticks */
slouken@6712
   446
    SDL_assert(!SDL_updating_joystick);
slouken@6712
   447
slouken@1895
   448
    /* Stop the event polling */
slouken@8920
   449
    while (SDL_joysticks) {
slouken@7191
   450
        SDL_joysticks->ref_count = 1;
slouken@6690
   451
        SDL_JoystickClose(SDL_joysticks);
slouken@7191
   452
    }
icculus@5856
   453
slouken@1895
   454
    /* Quit the joystick setup */
slouken@1895
   455
    SDL_SYS_JoystickQuit();
slouken@7360
   456
slouken@7360
   457
#if !SDL_EVENTS_DISABLED
slouken@7360
   458
    SDL_QuitSubSystem(SDL_INIT_EVENTS);
slouken@7360
   459
#endif
slouken@0
   460
}
slouken@0
   461
slouken@0
   462
jorgen@7279
   463
static SDL_bool
jorgen@7279
   464
SDL_PrivateJoystickShouldIgnoreEvent()
jorgen@7279
   465
{
slouken@8920
   466
    if (SDL_joystick_allows_background_events) {
jorgen@7279
   467
        return SDL_FALSE;
jorgen@7279
   468
    }
jorgen@7279
   469
slouken@7337
   470
    if (SDL_WasInit(SDL_INIT_VIDEO)) {
slouken@7337
   471
        if (SDL_GetKeyboardFocus() == NULL) {
gabomdq@7677
   472
            /* Video is initialized and we don't have focus, ignore the event. */
slouken@7337
   473
            return SDL_TRUE;
slouken@7337
   474
        } else {
slouken@7337
   475
            return SDL_FALSE;
slouken@7337
   476
        }
jorgen@7279
   477
    }
jorgen@7279
   478
gabomdq@7677
   479
    /* Video subsystem wasn't initialized, always allow the event */
slouken@7337
   480
    return SDL_FALSE;
jorgen@7279
   481
}
jorgen@7279
   482
slouken@0
   483
/* These are global for SDL_sysjoystick.c and SDL_events.c */
slouken@0
   484
slouken@1895
   485
int
slouken@1895
   486
SDL_PrivateJoystickAxis(SDL_Joystick * joystick, Uint8 axis, Sint16 value)
slouken@0
   487
{
slouken@1895
   488
    int posted;
slouken@0
   489
slouken@8920
   490
    /* Make sure we're not getting garbage or duplicate events */
slouken@6145
   491
    if (axis >= joystick->naxes) {
slouken@6145
   492
        return 0;
slouken@6145
   493
    }
slouken@8920
   494
    if (value == joystick->axes[axis]) {
slouken@8920
   495
        return 0;
slouken@8920
   496
    }
slouken@6145
   497
slouken@8903
   498
    /* We ignore events if we don't have keyboard focus, except for centering
slouken@8903
   499
     * events.
slouken@8903
   500
     */
slouken@8903
   501
    if (SDL_PrivateJoystickShouldIgnoreEvent()) {
slouken@8903
   502
        if ((value > 0 && value >= joystick->axes[axis]) ||
slouken@8903
   503
            (value < 0 && value <= joystick->axes[axis])) {
slouken@8903
   504
            return 0;
slouken@8903
   505
        }
slouken@8903
   506
    }
slouken@8903
   507
slouken@1895
   508
    /* Update internal joystick state */
slouken@1895
   509
    joystick->axes[axis] = value;
slouken@0
   510
slouken@1895
   511
    /* Post the event, if desired */
slouken@1895
   512
    posted = 0;
slouken@1361
   513
#if !SDL_EVENTS_DISABLED
slouken@4429
   514
    if (SDL_GetEventState(SDL_JOYAXISMOTION) == SDL_ENABLE) {
slouken@1895
   515
        SDL_Event event;
slouken@1895
   516
        event.type = SDL_JOYAXISMOTION;
slouken@6690
   517
        event.jaxis.which = joystick->instance_id;
slouken@1895
   518
        event.jaxis.axis = axis;
slouken@1895
   519
        event.jaxis.value = value;
slouken@6690
   520
        posted = SDL_PushEvent(&event) == 1;
slouken@1895
   521
    }
slouken@1361
   522
#endif /* !SDL_EVENTS_DISABLED */
slouken@1895
   523
    return (posted);
slouken@0
   524
}
slouken@0
   525
slouken@1895
   526
int
slouken@1895
   527
SDL_PrivateJoystickHat(SDL_Joystick * joystick, Uint8 hat, Uint8 value)
slouken@0
   528
{
slouken@1895
   529
    int posted;
slouken@0
   530
slouken@8920
   531
    /* Make sure we're not getting garbage or duplicate events */
slouken@6145
   532
    if (hat >= joystick->nhats) {
slouken@6145
   533
        return 0;
slouken@6145
   534
    }
slouken@8920
   535
    if (value == joystick->hats[hat]) {
slouken@8920
   536
        return 0;
slouken@8920
   537
    }
slouken@6145
   538
jorgen@7279
   539
    /* We ignore events if we don't have keyboard focus, except for centering
jorgen@7279
   540
     * events.
jorgen@7279
   541
     */
jorgen@7279
   542
    if (SDL_PrivateJoystickShouldIgnoreEvent()) {
slouken@8903
   543
        if (value != SDL_HAT_CENTERED) {
jorgen@7279
   544
            return 0;
jorgen@7279
   545
        }
jorgen@7279
   546
    }
jorgen@7279
   547
slouken@8903
   548
    /* Update internal joystick state */
slouken@8903
   549
    joystick->hats[hat] = value;
jorgen@7279
   550
slouken@1895
   551
    /* Post the event, if desired */
slouken@1895
   552
    posted = 0;
slouken@1361
   553
#if !SDL_EVENTS_DISABLED
slouken@4429
   554
    if (SDL_GetEventState(SDL_JOYHATMOTION) == SDL_ENABLE) {
slouken@1895
   555
        SDL_Event event;
slouken@1895
   556
        event.jhat.type = SDL_JOYHATMOTION;
slouken@6690
   557
        event.jhat.which = joystick->instance_id;
slouken@1895
   558
        event.jhat.hat = hat;
slouken@1895
   559
        event.jhat.value = value;
slouken@6690
   560
        posted = SDL_PushEvent(&event) == 1;
slouken@1895
   561
    }
slouken@1361
   562
#endif /* !SDL_EVENTS_DISABLED */
slouken@1895
   563
    return (posted);
slouken@0
   564
}
slouken@0
   565
slouken@1895
   566
int
slouken@1895
   567
SDL_PrivateJoystickBall(SDL_Joystick * joystick, Uint8 ball,
slouken@1895
   568
                        Sint16 xrel, Sint16 yrel)
slouken@0
   569
{
slouken@1895
   570
    int posted;
slouken@0
   571
slouken@6145
   572
    /* Make sure we're not getting garbage events */
slouken@6145
   573
    if (ball >= joystick->nballs) {
slouken@6145
   574
        return 0;
slouken@6145
   575
    }
slouken@6145
   576
jorgen@7279
   577
    /* We ignore events if we don't have keyboard focus. */
jorgen@7279
   578
    if (SDL_PrivateJoystickShouldIgnoreEvent()) {
jorgen@7279
   579
        return 0;
jorgen@7279
   580
    }
jorgen@7279
   581
slouken@1895
   582
    /* Update internal mouse state */
slouken@1895
   583
    joystick->balls[ball].dx += xrel;
slouken@1895
   584
    joystick->balls[ball].dy += yrel;
slouken@0
   585
slouken@1895
   586
    /* Post the event, if desired */
slouken@1895
   587
    posted = 0;
slouken@1361
   588
#if !SDL_EVENTS_DISABLED
slouken@4429
   589
    if (SDL_GetEventState(SDL_JOYBALLMOTION) == SDL_ENABLE) {
slouken@1895
   590
        SDL_Event event;
slouken@1895
   591
        event.jball.type = SDL_JOYBALLMOTION;
slouken@6690
   592
        event.jball.which = joystick->instance_id;
slouken@1895
   593
        event.jball.ball = ball;
slouken@1895
   594
        event.jball.xrel = xrel;
slouken@1895
   595
        event.jball.yrel = yrel;
slouken@6690
   596
        posted = SDL_PushEvent(&event) == 1;
slouken@1895
   597
    }
slouken@1361
   598
#endif /* !SDL_EVENTS_DISABLED */
slouken@1895
   599
    return (posted);
slouken@0
   600
}
slouken@0
   601
slouken@1895
   602
int
slouken@1895
   603
SDL_PrivateJoystickButton(SDL_Joystick * joystick, Uint8 button, Uint8 state)
slouken@0
   604
{
slouken@1895
   605
    int posted;
slouken@1361
   606
#if !SDL_EVENTS_DISABLED
slouken@1895
   607
    SDL_Event event;
slouken@0
   608
slouken@1895
   609
    switch (state) {
slouken@1895
   610
    case SDL_PRESSED:
slouken@1895
   611
        event.type = SDL_JOYBUTTONDOWN;
slouken@1895
   612
        break;
slouken@1895
   613
    case SDL_RELEASED:
slouken@1895
   614
        event.type = SDL_JOYBUTTONUP;
slouken@1895
   615
        break;
slouken@1895
   616
    default:
slouken@1895
   617
        /* Invalid state -- bail */
slouken@1895
   618
        return (0);
slouken@1895
   619
    }
slouken@1361
   620
#endif /* !SDL_EVENTS_DISABLED */
slouken@0
   621
slouken@8920
   622
    /* Make sure we're not getting garbage or duplicate events */
slouken@6145
   623
    if (button >= joystick->nbuttons) {
slouken@6145
   624
        return 0;
slouken@8920
   625
	}
slouken@8920
   626
	if (state == joystick->buttons[button]) {
slouken@8920
   627
		return 0;
slouken@8920
   628
	}
slouken@6145
   629
jorgen@7279
   630
    /* We ignore events if we don't have keyboard focus, except for button
jorgen@7279
   631
     * release. */
slouken@8903
   632
    if (SDL_PrivateJoystickShouldIgnoreEvent()) {
slouken@8903
   633
        if (state == SDL_PRESSED) {
slouken@8903
   634
            return 0;
slouken@8903
   635
        }
jorgen@7279
   636
    }
jorgen@7279
   637
slouken@1895
   638
    /* Update internal joystick state */
slouken@1895
   639
    joystick->buttons[button] = state;
slouken@0
   640
slouken@1895
   641
    /* Post the event, if desired */
slouken@1895
   642
    posted = 0;
slouken@1361
   643
#if !SDL_EVENTS_DISABLED
slouken@4429
   644
    if (SDL_GetEventState(event.type) == SDL_ENABLE) {
slouken@6690
   645
        event.jbutton.which = joystick->instance_id;
slouken@1895
   646
        event.jbutton.button = button;
slouken@1895
   647
        event.jbutton.state = state;
slouken@6690
   648
        posted = SDL_PushEvent(&event) == 1;
slouken@1895
   649
    }
slouken@1361
   650
#endif /* !SDL_EVENTS_DISABLED */
slouken@1895
   651
    return (posted);
slouken@0
   652
}
slouken@0
   653
slouken@1895
   654
void
slouken@1895
   655
SDL_JoystickUpdate(void)
slouken@0
   656
{
slouken@7191
   657
    SDL_Joystick *joystick;
slouken@7191
   658
slouken@7191
   659
    joystick = SDL_joysticks;
slouken@8920
   660
    while (joystick) {
slouken@7191
   661
        SDL_Joystick *joysticknext;
slouken@7191
   662
        /* save off the next pointer, the Update call may cause a joystick removed event
slouken@7191
   663
         * and cause our joystick pointer to be freed
slouken@7191
   664
         */
slouken@7191
   665
        joysticknext = joystick->next;
slouken@0
   666
slouken@6712
   667
        SDL_updating_joystick = joystick;
slouken@6712
   668
slouken@8920
   669
        SDL_SYS_JoystickUpdate(joystick);
slouken@6690
   670
slouken@8920
   671
        if (joystick->closed && joystick->uncentered) {
slouken@7191
   672
            int i;
slouken@6690
   673
slouken@6712
   674
            /* Tell the app that everything is centered/unpressed...  */
slouken@6690
   675
            for (i = 0; i < joystick->naxes; i++)
slouken@6690
   676
                SDL_PrivateJoystickAxis(joystick, i, 0);
slouken@6690
   677
slouken@6690
   678
            for (i = 0; i < joystick->nbuttons; i++)
slouken@6690
   679
                SDL_PrivateJoystickButton(joystick, i, 0);
slouken@6690
   680
slouken@6690
   681
            for (i = 0; i < joystick->nhats; i++)
slouken@6690
   682
                SDL_PrivateJoystickHat(joystick, i, SDL_HAT_CENTERED);
slouken@6712
   683
slouken@8920
   684
            joystick->uncentered = SDL_FALSE;
slouken@7191
   685
        }
slouken@6690
   686
slouken@6712
   687
        SDL_updating_joystick = NULL;
slouken@6712
   688
slouken@6712
   689
        /* If the joystick was closed while updating, free it here */
slouken@8920
   690
        if (joystick->ref_count <= 0) {
slouken@6712
   691
            SDL_JoystickClose(joystick);
slouken@6712
   692
        }
slouken@6712
   693
slouken@7191
   694
        joystick = joysticknext;
slouken@7191
   695
    }
slouken@6690
   696
slouken@7191
   697
    /* this needs to happen AFTER walking the joystick list above, so that any
slouken@7191
   698
       dangling hardware data from removed devices can be free'd
slouken@7191
   699
     */
slouken@7191
   700
    SDL_SYS_JoystickDetect();
slouken@0
   701
}
slouken@0
   702
slouken@1895
   703
int
slouken@1895
   704
SDL_JoystickEventState(int state)
slouken@0
   705
{
slouken@1361
   706
#if SDL_EVENTS_DISABLED
slouken@6753
   707
    return SDL_DISABLE;
slouken@0
   708
#else
slouken@4429
   709
    const Uint32 event_list[] = {
slouken@1895
   710
        SDL_JOYAXISMOTION, SDL_JOYBALLMOTION, SDL_JOYHATMOTION,
slouken@6690
   711
        SDL_JOYBUTTONDOWN, SDL_JOYBUTTONUP, SDL_JOYDEVICEADDED, SDL_JOYDEVICEREMOVED
slouken@1895
   712
    };
slouken@1895
   713
    unsigned int i;
slouken@0
   714
slouken@1895
   715
    switch (state) {
slouken@1895
   716
    case SDL_QUERY:
slouken@6753
   717
        state = SDL_DISABLE;
slouken@1895
   718
        for (i = 0; i < SDL_arraysize(event_list); ++i) {
slouken@1895
   719
            state = SDL_EventState(event_list[i], SDL_QUERY);
slouken@1895
   720
            if (state == SDL_ENABLE) {
slouken@1895
   721
                break;
slouken@1895
   722
            }
slouken@1895
   723
        }
slouken@1895
   724
        break;
slouken@1895
   725
    default:
slouken@1895
   726
        for (i = 0; i < SDL_arraysize(event_list); ++i) {
slouken@1895
   727
            SDL_EventState(event_list[i], state);
slouken@1895
   728
        }
slouken@1895
   729
        break;
slouken@1895
   730
    }
slouken@1895
   731
    return (state);
slouken@1361
   732
#endif /* SDL_EVENTS_DISABLED */
slouken@0
   733
}
slouken@1895
   734
slouken@6693
   735
/* return the guid for this index */
slouken@6738
   736
SDL_JoystickGUID SDL_JoystickGetDeviceGUID(int device_index)
slouken@6690
   737
{
slouken@7294
   738
    if ((device_index < 0) || (device_index >= SDL_NumJoysticks())) {
slouken@7294
   739
        SDL_JoystickGUID emptyGUID;
slouken@7294
   740
        SDL_SetError("There are %d joysticks available", SDL_NumJoysticks());
slouken@8920
   741
        SDL_zero(emptyGUID);
slouken@7294
   742
        return emptyGUID;
slouken@7294
   743
    }
slouken@8920
   744
    return SDL_SYS_JoystickGetDeviceGUID(device_index);
slouken@6690
   745
}
slouken@6690
   746
slouken@6693
   747
/* return the guid for this opened device */
slouken@6738
   748
SDL_JoystickGUID SDL_JoystickGetGUID(SDL_Joystick * joystick)
slouken@6690
   749
{
slouken@7789
   750
    if (!SDL_PrivateJoystickValid(joystick)) {
slouken@7789
   751
        SDL_JoystickGUID emptyGUID;
slouken@8920
   752
        SDL_zero(emptyGUID);
slouken@7789
   753
        return emptyGUID;
slouken@7789
   754
    }
slouken@8920
   755
    return SDL_SYS_JoystickGetGUID(joystick);
slouken@6690
   756
}
slouken@6690
   757
slouken@6690
   758
/* convert the guid to a printable string */
slouken@8920
   759
void SDL_JoystickGetGUIDString(SDL_JoystickGUID guid, char *pszGUID, int cbGUID)
slouken@6690
   760
{
slouken@7191
   761
    static const char k_rgchHexToASCII[] = "0123456789abcdef";
slouken@7191
   762
    int i;
slouken@6690
   763
icculus@6748
   764
    if ((pszGUID == NULL) || (cbGUID <= 0)) {
icculus@6748
   765
        return;
icculus@6748
   766
    }
icculus@6748
   767
slouken@8920
   768
    for (i = 0; i < sizeof(guid.data) && i < (cbGUID-1)/2; i++) {
slouken@7191
   769
        /* each input byte writes 2 ascii chars, and might write a null byte. */
slouken@7191
   770
        /* If we don't have room for next input byte, stop */
slouken@7191
   771
        unsigned char c = guid.data[i];
slouken@6690
   772
slouken@8920
   773
        *pszGUID++ = k_rgchHexToASCII[c >> 4];
slouken@8920
   774
        *pszGUID++ = k_rgchHexToASCII[c & 0x0F];
slouken@7191
   775
    }
slouken@7191
   776
    *pszGUID = '\0';
slouken@6690
   777
}
slouken@6690
   778
slouken@6690
   779
slouken@7191
   780
/*-----------------------------------------------------------------------------
slouken@7191
   781
 * Purpose: Returns the 4 bit nibble for a hex character
slouken@7191
   782
 * Input  : c -
slouken@7191
   783
 * Output : unsigned char
slouken@7191
   784
 *-----------------------------------------------------------------------------*/
slouken@8920
   785
static unsigned char nibble(char c)
slouken@6690
   786
{
slouken@8920
   787
    if ((c >= '0') && (c <= '9')) {
slouken@7191
   788
        return (unsigned char)(c - '0');
slouken@7191
   789
    }
slouken@6690
   790
slouken@8920
   791
    if ((c >= 'A') && (c <= 'F')) {
slouken@7191
   792
        return (unsigned char)(c - 'A' + 0x0a);
slouken@7191
   793
    }
slouken@6690
   794
slouken@8920
   795
    if ((c >= 'a') && (c <= 'f')) {
slouken@7191
   796
        return (unsigned char)(c - 'a' + 0x0a);
slouken@7191
   797
    }
slouken@6690
   798
slouken@7191
   799
    /* received an invalid character, and no real way to return an error */
slouken@8920
   800
    /* AssertMsg1(false, "Q_nibble invalid hex character '%c' ", c); */
slouken@7191
   801
    return 0;
slouken@6690
   802
}
slouken@6690
   803
slouken@6690
   804
slouken@6690
   805
/* convert the string version of a joystick guid to the struct */
slouken@6738
   806
SDL_JoystickGUID SDL_JoystickGetGUIDFromString(const char *pchGUID)
slouken@6690
   807
{
slouken@7191
   808
    SDL_JoystickGUID guid;
slouken@7191
   809
    int maxoutputbytes= sizeof(guid);
slouken@8920
   810
    size_t len = SDL_strlen(pchGUID);
slouken@7191
   811
    Uint8 *p;
slouken@7922
   812
    size_t i;
slouken@6690
   813
slouken@7191
   814
    /* Make sure it's even */
slouken@8920
   815
    len = (len) & ~0x1;
slouken@6690
   816
slouken@8920
   817
    SDL_memset(&guid, 0x00, sizeof(guid));
slouken@6690
   818
slouken@7191
   819
    p = (Uint8 *)&guid;
slouken@8920
   820
    for (i = 0; (i < len) && ((p - (Uint8 *)&guid) < maxoutputbytes); i+=2, p++) {
slouken@8920
   821
        *p = (nibble(pchGUID[i]) << 4) | nibble(pchGUID[i+1]);
slouken@7191
   822
    }
slouken@6690
   823
slouken@7191
   824
    return guid;
slouken@6690
   825
}
slouken@6690
   826
slouken@6690
   827
slouken@1895
   828
/* vi: set ts=4 sw=4 expandtab: */