src/joystick/SDL_joystick.c
author Sam Lantinga <slouken@libsdl.org>
Fri, 07 Oct 2016 16:13:37 -0700
changeset 10477 dc4bec0fc176
parent 10226 cb13d22b7f09
child 10595 9da2701eeb4a
permissions -rw-r--r--
Fixed recentering triggers when the application doesn't have focus
slouken@0
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@9998
     3
  Copyright (C) 1997-2016 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) {
slouken@10477
   145
        joystick->axes = (Sint16 *) SDL_malloc(joystick->naxes * sizeof(Sint16));
slouken@10477
   146
        joystick->axes_zero = (Sint16 *) SDL_malloc(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));
slouken@10477
   170
        SDL_memset(joystick->axes_zero, 0, joystick->naxes * sizeof(Sint16));
icculus@3608
   171
    }
icculus@3608
   172
    if (joystick->hats) {
icculus@3608
   173
        SDL_memset(joystick->hats, 0, joystick->nhats * sizeof(Uint8));
icculus@3608
   174
    }
icculus@3608
   175
    if (joystick->balls) {
icculus@3608
   176
        SDL_memset(joystick->balls, 0,
icculus@3608
   177
            joystick->nballs * sizeof(*joystick->balls));
icculus@3608
   178
    }
icculus@3608
   179
    if (joystick->buttons) {
icculus@3608
   180
        SDL_memset(joystick->buttons, 0, joystick->nbuttons * sizeof(Uint8));
icculus@3608
   181
    }
slouken@9884
   182
    joystick->epowerlevel = SDL_JOYSTICK_POWER_UNKNOWN;
icculus@3608
   183
icculus@3608
   184
    /* Add joystick to list */
icculus@3608
   185
    ++joystick->ref_count;
slouken@7191
   186
    /* Link the joystick in the list */
slouken@7191
   187
    joystick->next = SDL_joysticks;
slouken@7191
   188
    SDL_joysticks = joystick;
slouken@6690
   189
slouken@8920
   190
    SDL_SYS_JoystickUpdate(joystick);
icculus@3608
   191
slouken@1895
   192
    return (joystick);
slouken@0
   193
}
slouken@0
   194
slouken@2713
   195
slouken@2713
   196
/*
slouken@2713
   197
 * Checks to make sure the joystick is valid.
slouken@2713
   198
 */
slouken@2713
   199
int
slouken@6690
   200
SDL_PrivateJoystickValid(SDL_Joystick * joystick)
slouken@0
   201
{
slouken@1895
   202
    int valid;
slouken@0
   203
slouken@8920
   204
    if (joystick == NULL) {
slouken@1895
   205
        SDL_SetError("Joystick hasn't been opened yet");
slouken@1895
   206
        valid = 0;
slouken@1895
   207
    } else {
slouken@1895
   208
        valid = 1;
slouken@1895
   209
    }
slouken@7191
   210
slouken@1895
   211
    return valid;
slouken@0
   212
}
slouken@0
   213
slouken@0
   214
/*
slouken@0
   215
 * Get the number of multi-dimensional axis controls on a joystick
slouken@0
   216
 */
slouken@1895
   217
int
slouken@1895
   218
SDL_JoystickNumAxes(SDL_Joystick * joystick)
slouken@0
   219
{
slouken@6690
   220
    if (!SDL_PrivateJoystickValid(joystick)) {
slouken@1895
   221
        return (-1);
slouken@1895
   222
    }
slouken@1895
   223
    return (joystick->naxes);
slouken@0
   224
}
slouken@0
   225
slouken@0
   226
/*
slouken@0
   227
 * Get the number of hats on a joystick
slouken@0
   228
 */
slouken@1895
   229
int
slouken@1895
   230
SDL_JoystickNumHats(SDL_Joystick * joystick)
slouken@0
   231
{
slouken@6690
   232
    if (!SDL_PrivateJoystickValid(joystick)) {
slouken@1895
   233
        return (-1);
slouken@1895
   234
    }
slouken@1895
   235
    return (joystick->nhats);
slouken@0
   236
}
slouken@0
   237
slouken@0
   238
/*
slouken@0
   239
 * Get the number of trackballs on a joystick
slouken@0
   240
 */
slouken@1895
   241
int
slouken@1895
   242
SDL_JoystickNumBalls(SDL_Joystick * joystick)
slouken@0
   243
{
slouken@6690
   244
    if (!SDL_PrivateJoystickValid(joystick)) {
slouken@1895
   245
        return (-1);
slouken@1895
   246
    }
slouken@1895
   247
    return (joystick->nballs);
slouken@0
   248
}
slouken@0
   249
slouken@0
   250
/*
slouken@0
   251
 * Get the number of buttons on a joystick
slouken@0
   252
 */
slouken@1895
   253
int
slouken@1895
   254
SDL_JoystickNumButtons(SDL_Joystick * joystick)
slouken@0
   255
{
slouken@6690
   256
    if (!SDL_PrivateJoystickValid(joystick)) {
slouken@1895
   257
        return (-1);
slouken@1895
   258
    }
slouken@1895
   259
    return (joystick->nbuttons);
slouken@0
   260
}
slouken@0
   261
slouken@0
   262
/*
slouken@0
   263
 * Get the current state of an axis control on a joystick
slouken@0
   264
 */
slouken@1895
   265
Sint16
slouken@1895
   266
SDL_JoystickGetAxis(SDL_Joystick * joystick, int axis)
slouken@0
   267
{
slouken@1895
   268
    Sint16 state;
slouken@0
   269
slouken@6690
   270
    if (!SDL_PrivateJoystickValid(joystick)) {
slouken@1895
   271
        return (0);
slouken@1895
   272
    }
slouken@1895
   273
    if (axis < joystick->naxes) {
slouken@1895
   274
        state = joystick->axes[axis];
slouken@1895
   275
    } else {
slouken@1895
   276
        SDL_SetError("Joystick only has %d axes", joystick->naxes);
slouken@1895
   277
        state = 0;
slouken@1895
   278
    }
slouken@1895
   279
    return (state);
slouken@0
   280
}
slouken@0
   281
slouken@0
   282
/*
slouken@0
   283
 * Get the current state of a hat on a joystick
slouken@0
   284
 */
slouken@1895
   285
Uint8
slouken@1895
   286
SDL_JoystickGetHat(SDL_Joystick * joystick, int hat)
slouken@0
   287
{
slouken@1895
   288
    Uint8 state;
slouken@0
   289
slouken@6690
   290
    if (!SDL_PrivateJoystickValid(joystick)) {
slouken@1895
   291
        return (0);
slouken@1895
   292
    }
slouken@1895
   293
    if (hat < joystick->nhats) {
slouken@1895
   294
        state = joystick->hats[hat];
slouken@1895
   295
    } else {
slouken@1895
   296
        SDL_SetError("Joystick only has %d hats", joystick->nhats);
slouken@1895
   297
        state = 0;
slouken@1895
   298
    }
slouken@1895
   299
    return (state);
slouken@0
   300
}
slouken@0
   301
slouken@0
   302
/*
slouken@0
   303
 * Get the ball axis change since the last poll
slouken@0
   304
 */
slouken@1895
   305
int
slouken@1895
   306
SDL_JoystickGetBall(SDL_Joystick * joystick, int ball, int *dx, int *dy)
slouken@0
   307
{
slouken@1895
   308
    int retval;
slouken@0
   309
slouken@6690
   310
    if (!SDL_PrivateJoystickValid(joystick)) {
slouken@1895
   311
        return (-1);
slouken@1895
   312
    }
slouken@0
   313
slouken@1895
   314
    retval = 0;
slouken@1895
   315
    if (ball < joystick->nballs) {
slouken@1895
   316
        if (dx) {
slouken@1895
   317
            *dx = joystick->balls[ball].dx;
slouken@1895
   318
        }
slouken@1895
   319
        if (dy) {
slouken@1895
   320
            *dy = joystick->balls[ball].dy;
slouken@1895
   321
        }
slouken@1895
   322
        joystick->balls[ball].dx = 0;
slouken@1895
   323
        joystick->balls[ball].dy = 0;
slouken@1895
   324
    } else {
icculus@7037
   325
        return SDL_SetError("Joystick only has %d balls", joystick->nballs);
slouken@1895
   326
    }
slouken@1895
   327
    return (retval);
slouken@0
   328
}
slouken@0
   329
slouken@0
   330
/*
slouken@0
   331
 * Get the current state of a button on a joystick
slouken@0
   332
 */
slouken@1895
   333
Uint8
slouken@1895
   334
SDL_JoystickGetButton(SDL_Joystick * joystick, int button)
slouken@0
   335
{
slouken@1895
   336
    Uint8 state;
slouken@0
   337
slouken@6690
   338
    if (!SDL_PrivateJoystickValid(joystick)) {
slouken@1895
   339
        return (0);
slouken@1895
   340
    }
slouken@1895
   341
    if (button < joystick->nbuttons) {
slouken@1895
   342
        state = joystick->buttons[button];
slouken@1895
   343
    } else {
slouken@1895
   344
        SDL_SetError("Joystick only has %d buttons", joystick->nbuttons);
slouken@1895
   345
        state = 0;
slouken@1895
   346
    }
slouken@1895
   347
    return (state);
slouken@0
   348
}
slouken@0
   349
slouken@0
   350
/*
slouken@6690
   351
 * Return if the joystick in question is currently attached to the system,
philipp@7500
   352
 *  \return SDL_FALSE if not plugged in, SDL_TRUE if still present.
slouken@6690
   353
 */
slouken@6707
   354
SDL_bool
slouken@6707
   355
SDL_JoystickGetAttached(SDL_Joystick * joystick)
slouken@6690
   356
{
slouken@7191
   357
    if (!SDL_PrivateJoystickValid(joystick)) {
slouken@6707
   358
        return SDL_FALSE;
slouken@6690
   359
    }
slouken@6690
   360
slouken@7191
   361
    return SDL_SYS_JoystickAttached(joystick);
slouken@6690
   362
}
slouken@6690
   363
slouken@6690
   364
/*
slouken@6690
   365
 * Get the instance id for this opened joystick
slouken@6690
   366
 */
slouken@7191
   367
SDL_JoystickID
slouken@6707
   368
SDL_JoystickInstanceID(SDL_Joystick * joystick)
slouken@6690
   369
{
slouken@7191
   370
    if (!SDL_PrivateJoystickValid(joystick)) {
slouken@6690
   371
        return (-1);
slouken@6690
   372
    }
slouken@6690
   373
slouken@7191
   374
    return (joystick->instance_id);
slouken@6690
   375
}
slouken@6690
   376
slouken@6690
   377
/*
icculus@9916
   378
 * Find the SDL_Joystick that owns this instance id
icculus@9916
   379
 */
icculus@9916
   380
SDL_Joystick *
icculus@9916
   381
SDL_JoystickFromInstanceID(SDL_JoystickID joyid)
icculus@9916
   382
{
icculus@9916
   383
    SDL_Joystick *joystick = SDL_joysticks;
icculus@9916
   384
    while (joystick) {
icculus@9916
   385
        if (joystick->instance_id == joyid) {
icculus@9916
   386
            return joystick;
icculus@9916
   387
        }
icculus@9916
   388
        joystick = joystick->next;
icculus@9916
   389
    }
icculus@9916
   390
icculus@9916
   391
    return NULL;
icculus@9916
   392
}
icculus@9916
   393
icculus@9916
   394
/*
slouken@6690
   395
 * Get the friendly name of this joystick
slouken@6690
   396
 */
slouken@6690
   397
const char *
slouken@6690
   398
SDL_JoystickName(SDL_Joystick * joystick)
slouken@6690
   399
{
slouken@6690
   400
    if (!SDL_PrivateJoystickValid(joystick)) {
slouken@6690
   401
        return (NULL);
slouken@6690
   402
    }
slouken@7191
   403
slouken@6690
   404
    return (joystick->name);
slouken@6690
   405
}
slouken@6690
   406
slouken@6690
   407
/*
slouken@0
   408
 * Close a joystick previously opened with SDL_JoystickOpen()
slouken@0
   409
 */
slouken@1895
   410
void
slouken@1895
   411
SDL_JoystickClose(SDL_Joystick * joystick)
slouken@0
   412
{
slouken@7191
   413
    SDL_Joystick *joysticklist;
slouken@7191
   414
    SDL_Joystick *joysticklistprev;
slouken@0
   415
slouken@6690
   416
    if (!joystick) {
slouken@1895
   417
        return;
slouken@1895
   418
    }
slouken@0
   419
slouken@1895
   420
    /* First decrement ref count */
slouken@1895
   421
    if (--joystick->ref_count > 0) {
slouken@1895
   422
        return;
slouken@1895
   423
    }
slouken@0
   424
slouken@6712
   425
    if (joystick == SDL_updating_joystick) {
slouken@6712
   426
        return;
slouken@6712
   427
    }
slouken@6712
   428
slouken@1895
   429
    SDL_SYS_JoystickClose(joystick);
icculus@9433
   430
    joystick->hwdata = NULL;
slouken@0
   431
slouken@7191
   432
    joysticklist = SDL_joysticks;
slouken@7191
   433
    joysticklistprev = NULL;
slouken@8920
   434
    while (joysticklist) {
slouken@8920
   435
        if (joystick == joysticklist) {
slouken@8920
   436
            if (joysticklistprev) {
slouken@7191
   437
                /* unlink this entry */
slouken@7191
   438
                joysticklistprev->next = joysticklist->next;
slouken@8920
   439
            } else {
slouken@7191
   440
                SDL_joysticks = joystick->next;
slouken@7191
   441
            }
slouken@7191
   442
            break;
slouken@7191
   443
        }
slouken@7191
   444
        joysticklistprev = joysticklist;
slouken@7191
   445
        joysticklist = joysticklist->next;
slouken@7191
   446
    }
slouken@7191
   447
slouken@7719
   448
    SDL_free(joystick->name);
slouken@0
   449
slouken@1895
   450
    /* Free the data associated with this joystick */
slouken@7719
   451
    SDL_free(joystick->axes);
slouken@7719
   452
    SDL_free(joystick->hats);
slouken@7719
   453
    SDL_free(joystick->balls);
slouken@7719
   454
    SDL_free(joystick->buttons);
slouken@1895
   455
    SDL_free(joystick);
slouken@0
   456
}
slouken@0
   457
slouken@1895
   458
void
slouken@1895
   459
SDL_JoystickQuit(void)
slouken@0
   460
{
slouken@6712
   461
    /* Make sure we're not getting called in the middle of updating joysticks */
slouken@6712
   462
    SDL_assert(!SDL_updating_joystick);
slouken@6712
   463
slouken@1895
   464
    /* Stop the event polling */
slouken@8920
   465
    while (SDL_joysticks) {
slouken@7191
   466
        SDL_joysticks->ref_count = 1;
slouken@6690
   467
        SDL_JoystickClose(SDL_joysticks);
slouken@7191
   468
    }
icculus@5856
   469
slouken@1895
   470
    /* Quit the joystick setup */
slouken@1895
   471
    SDL_SYS_JoystickQuit();
slouken@7360
   472
slouken@7360
   473
#if !SDL_EVENTS_DISABLED
slouken@7360
   474
    SDL_QuitSubSystem(SDL_INIT_EVENTS);
slouken@7360
   475
#endif
slouken@0
   476
}
slouken@0
   477
slouken@0
   478
jorgen@7279
   479
static SDL_bool
jorgen@7279
   480
SDL_PrivateJoystickShouldIgnoreEvent()
jorgen@7279
   481
{
slouken@8920
   482
    if (SDL_joystick_allows_background_events) {
jorgen@7279
   483
        return SDL_FALSE;
jorgen@7279
   484
    }
jorgen@7279
   485
slouken@7337
   486
    if (SDL_WasInit(SDL_INIT_VIDEO)) {
slouken@7337
   487
        if (SDL_GetKeyboardFocus() == NULL) {
gabomdq@7677
   488
            /* Video is initialized and we don't have focus, ignore the event. */
slouken@7337
   489
            return SDL_TRUE;
slouken@7337
   490
        } else {
slouken@7337
   491
            return SDL_FALSE;
slouken@7337
   492
        }
jorgen@7279
   493
    }
jorgen@7279
   494
gabomdq@7677
   495
    /* Video subsystem wasn't initialized, always allow the event */
slouken@7337
   496
    return SDL_FALSE;
jorgen@7279
   497
}
jorgen@7279
   498
slouken@0
   499
/* These are global for SDL_sysjoystick.c and SDL_events.c */
slouken@0
   500
slouken@10226
   501
void SDL_PrivateJoystickAdded(int device_index)
slouken@10226
   502
{
slouken@10226
   503
#if !SDL_EVENTS_DISABLED
slouken@10226
   504
    SDL_Event event;
slouken@10226
   505
slouken@10226
   506
    event.type = SDL_JOYDEVICEADDED;
slouken@10226
   507
slouken@10226
   508
    if (SDL_GetEventState(event.type) == SDL_ENABLE) {
slouken@10226
   509
        event.jdevice.which = device_index;
slouken@10226
   510
        if ( (SDL_EventOK == NULL) ||
slouken@10226
   511
             (*SDL_EventOK) (SDL_EventOKParam, &event) ) {
slouken@10226
   512
            SDL_PushEvent(&event);
slouken@10226
   513
        }
slouken@10226
   514
    }
slouken@10226
   515
#endif /* !SDL_EVENTS_DISABLED */
slouken@10226
   516
}
slouken@10226
   517
slouken@10226
   518
/*
slouken@10226
   519
 * If there is an existing add event in the queue, it needs to be modified
slouken@10226
   520
 * to have the right value for which, because the number of controllers in
slouken@10226
   521
 * the system is now one less.
slouken@10226
   522
 */
slouken@10226
   523
static void UpdateEventsForDeviceRemoval()
slouken@10226
   524
{
slouken@10226
   525
    int i, num_events;
slouken@10226
   526
    SDL_Event *events;
slouken@10226
   527
slouken@10226
   528
    num_events = SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, SDL_JOYDEVICEADDED, SDL_JOYDEVICEADDED);
slouken@10226
   529
    if (num_events <= 0) {
slouken@10226
   530
        return;
slouken@10226
   531
    }
slouken@10226
   532
slouken@10226
   533
    events = SDL_stack_alloc(SDL_Event, num_events);
slouken@10226
   534
    if (!events) {
slouken@10226
   535
        return;
slouken@10226
   536
    }
slouken@10226
   537
slouken@10226
   538
    num_events = SDL_PeepEvents(events, num_events, SDL_GETEVENT, SDL_JOYDEVICEADDED, SDL_JOYDEVICEADDED);
slouken@10226
   539
    for (i = 0; i < num_events; ++i) {
slouken@10226
   540
        --events[i].jdevice.which;
slouken@10226
   541
    }
slouken@10226
   542
    SDL_PeepEvents(events, num_events, SDL_ADDEVENT, 0, 0);
slouken@10226
   543
slouken@10226
   544
    SDL_stack_free(events);
slouken@10226
   545
}
slouken@10226
   546
slouken@10226
   547
void SDL_PrivateJoystickRemoved(SDL_JoystickID device_instance)
slouken@10226
   548
{
slouken@10226
   549
#if !SDL_EVENTS_DISABLED
slouken@10226
   550
    SDL_Event event;
slouken@10226
   551
slouken@10226
   552
    event.type = SDL_JOYDEVICEREMOVED;
slouken@10226
   553
slouken@10226
   554
    if (SDL_GetEventState(event.type) == SDL_ENABLE) {
slouken@10226
   555
        event.jdevice.which = device_instance;
slouken@10226
   556
        if ( (SDL_EventOK == NULL) ||
slouken@10226
   557
             (*SDL_EventOK) (SDL_EventOKParam, &event) ) {
slouken@10226
   558
            SDL_PushEvent(&event);
slouken@10226
   559
        }
slouken@10226
   560
    }
slouken@10226
   561
slouken@10226
   562
    UpdateEventsForDeviceRemoval();
slouken@10226
   563
#endif /* !SDL_EVENTS_DISABLED */
slouken@10226
   564
}
slouken@10226
   565
slouken@1895
   566
int
slouken@1895
   567
SDL_PrivateJoystickAxis(SDL_Joystick * joystick, Uint8 axis, Sint16 value)
slouken@0
   568
{
slouken@1895
   569
    int posted;
slouken@0
   570
slouken@8920
   571
    /* Make sure we're not getting garbage or duplicate events */
slouken@6145
   572
    if (axis >= joystick->naxes) {
slouken@6145
   573
        return 0;
slouken@6145
   574
    }
slouken@8920
   575
    if (value == joystick->axes[axis]) {
slouken@8920
   576
        return 0;
slouken@8920
   577
    }
slouken@6145
   578
slouken@8903
   579
    /* We ignore events if we don't have keyboard focus, except for centering
slouken@8903
   580
     * events.
slouken@8903
   581
     */
slouken@8903
   582
    if (SDL_PrivateJoystickShouldIgnoreEvent()) {
slouken@10477
   583
        if ((value > joystick->axes_zero[axis] && value >= joystick->axes[axis]) ||
slouken@10477
   584
            (value < joystick->axes_zero[axis] && value <= joystick->axes[axis])) {
slouken@8903
   585
            return 0;
slouken@8903
   586
        }
slouken@8903
   587
    }
slouken@8903
   588
slouken@1895
   589
    /* Update internal joystick state */
slouken@1895
   590
    joystick->axes[axis] = value;
slouken@0
   591
slouken@1895
   592
    /* Post the event, if desired */
slouken@1895
   593
    posted = 0;
slouken@1361
   594
#if !SDL_EVENTS_DISABLED
slouken@4429
   595
    if (SDL_GetEventState(SDL_JOYAXISMOTION) == SDL_ENABLE) {
slouken@1895
   596
        SDL_Event event;
slouken@1895
   597
        event.type = SDL_JOYAXISMOTION;
slouken@6690
   598
        event.jaxis.which = joystick->instance_id;
slouken@1895
   599
        event.jaxis.axis = axis;
slouken@1895
   600
        event.jaxis.value = value;
slouken@6690
   601
        posted = SDL_PushEvent(&event) == 1;
slouken@1895
   602
    }
slouken@1361
   603
#endif /* !SDL_EVENTS_DISABLED */
slouken@1895
   604
    return (posted);
slouken@0
   605
}
slouken@0
   606
slouken@1895
   607
int
slouken@1895
   608
SDL_PrivateJoystickHat(SDL_Joystick * joystick, Uint8 hat, Uint8 value)
slouken@0
   609
{
slouken@1895
   610
    int posted;
slouken@0
   611
slouken@8920
   612
    /* Make sure we're not getting garbage or duplicate events */
slouken@6145
   613
    if (hat >= joystick->nhats) {
slouken@6145
   614
        return 0;
slouken@6145
   615
    }
slouken@8920
   616
    if (value == joystick->hats[hat]) {
slouken@8920
   617
        return 0;
slouken@8920
   618
    }
slouken@6145
   619
jorgen@7279
   620
    /* We ignore events if we don't have keyboard focus, except for centering
jorgen@7279
   621
     * events.
jorgen@7279
   622
     */
jorgen@7279
   623
    if (SDL_PrivateJoystickShouldIgnoreEvent()) {
slouken@8903
   624
        if (value != SDL_HAT_CENTERED) {
jorgen@7279
   625
            return 0;
jorgen@7279
   626
        }
jorgen@7279
   627
    }
jorgen@7279
   628
slouken@8903
   629
    /* Update internal joystick state */
slouken@8903
   630
    joystick->hats[hat] = value;
jorgen@7279
   631
slouken@1895
   632
    /* Post the event, if desired */
slouken@1895
   633
    posted = 0;
slouken@1361
   634
#if !SDL_EVENTS_DISABLED
slouken@4429
   635
    if (SDL_GetEventState(SDL_JOYHATMOTION) == SDL_ENABLE) {
slouken@1895
   636
        SDL_Event event;
slouken@1895
   637
        event.jhat.type = SDL_JOYHATMOTION;
slouken@6690
   638
        event.jhat.which = joystick->instance_id;
slouken@1895
   639
        event.jhat.hat = hat;
slouken@1895
   640
        event.jhat.value = value;
slouken@6690
   641
        posted = SDL_PushEvent(&event) == 1;
slouken@1895
   642
    }
slouken@1361
   643
#endif /* !SDL_EVENTS_DISABLED */
slouken@1895
   644
    return (posted);
slouken@0
   645
}
slouken@0
   646
slouken@1895
   647
int
slouken@1895
   648
SDL_PrivateJoystickBall(SDL_Joystick * joystick, Uint8 ball,
slouken@1895
   649
                        Sint16 xrel, Sint16 yrel)
slouken@0
   650
{
slouken@1895
   651
    int posted;
slouken@0
   652
slouken@6145
   653
    /* Make sure we're not getting garbage events */
slouken@6145
   654
    if (ball >= joystick->nballs) {
slouken@6145
   655
        return 0;
slouken@6145
   656
    }
slouken@6145
   657
jorgen@7279
   658
    /* We ignore events if we don't have keyboard focus. */
jorgen@7279
   659
    if (SDL_PrivateJoystickShouldIgnoreEvent()) {
jorgen@7279
   660
        return 0;
jorgen@7279
   661
    }
jorgen@7279
   662
slouken@1895
   663
    /* Update internal mouse state */
slouken@1895
   664
    joystick->balls[ball].dx += xrel;
slouken@1895
   665
    joystick->balls[ball].dy += yrel;
slouken@0
   666
slouken@1895
   667
    /* Post the event, if desired */
slouken@1895
   668
    posted = 0;
slouken@1361
   669
#if !SDL_EVENTS_DISABLED
slouken@4429
   670
    if (SDL_GetEventState(SDL_JOYBALLMOTION) == SDL_ENABLE) {
slouken@1895
   671
        SDL_Event event;
slouken@1895
   672
        event.jball.type = SDL_JOYBALLMOTION;
slouken@6690
   673
        event.jball.which = joystick->instance_id;
slouken@1895
   674
        event.jball.ball = ball;
slouken@1895
   675
        event.jball.xrel = xrel;
slouken@1895
   676
        event.jball.yrel = yrel;
slouken@6690
   677
        posted = SDL_PushEvent(&event) == 1;
slouken@1895
   678
    }
slouken@1361
   679
#endif /* !SDL_EVENTS_DISABLED */
slouken@1895
   680
    return (posted);
slouken@0
   681
}
slouken@0
   682
slouken@1895
   683
int
slouken@1895
   684
SDL_PrivateJoystickButton(SDL_Joystick * joystick, Uint8 button, Uint8 state)
slouken@0
   685
{
slouken@1895
   686
    int posted;
slouken@1361
   687
#if !SDL_EVENTS_DISABLED
slouken@1895
   688
    SDL_Event event;
slouken@0
   689
slouken@1895
   690
    switch (state) {
slouken@1895
   691
    case SDL_PRESSED:
slouken@1895
   692
        event.type = SDL_JOYBUTTONDOWN;
slouken@1895
   693
        break;
slouken@1895
   694
    case SDL_RELEASED:
slouken@1895
   695
        event.type = SDL_JOYBUTTONUP;
slouken@1895
   696
        break;
slouken@1895
   697
    default:
slouken@1895
   698
        /* Invalid state -- bail */
slouken@1895
   699
        return (0);
slouken@1895
   700
    }
slouken@1361
   701
#endif /* !SDL_EVENTS_DISABLED */
slouken@0
   702
slouken@8920
   703
    /* Make sure we're not getting garbage or duplicate events */
slouken@6145
   704
    if (button >= joystick->nbuttons) {
slouken@6145
   705
        return 0;
slouken@9884
   706
    }
slouken@9884
   707
    if (state == joystick->buttons[button]) {
slouken@9884
   708
        return 0;
slouken@9884
   709
    }
slouken@6145
   710
jorgen@7279
   711
    /* We ignore events if we don't have keyboard focus, except for button
jorgen@7279
   712
     * release. */
slouken@8903
   713
    if (SDL_PrivateJoystickShouldIgnoreEvent()) {
slouken@8903
   714
        if (state == SDL_PRESSED) {
slouken@8903
   715
            return 0;
slouken@8903
   716
        }
jorgen@7279
   717
    }
jorgen@7279
   718
slouken@1895
   719
    /* Update internal joystick state */
slouken@1895
   720
    joystick->buttons[button] = state;
slouken@0
   721
slouken@1895
   722
    /* Post the event, if desired */
slouken@1895
   723
    posted = 0;
slouken@1361
   724
#if !SDL_EVENTS_DISABLED
slouken@4429
   725
    if (SDL_GetEventState(event.type) == SDL_ENABLE) {
slouken@6690
   726
        event.jbutton.which = joystick->instance_id;
slouken@1895
   727
        event.jbutton.button = button;
slouken@1895
   728
        event.jbutton.state = state;
slouken@6690
   729
        posted = SDL_PushEvent(&event) == 1;
slouken@1895
   730
    }
slouken@1361
   731
#endif /* !SDL_EVENTS_DISABLED */
slouken@1895
   732
    return (posted);
slouken@0
   733
}
slouken@0
   734
slouken@1895
   735
void
slouken@1895
   736
SDL_JoystickUpdate(void)
slouken@0
   737
{
slouken@7191
   738
    SDL_Joystick *joystick;
slouken@7191
   739
slouken@7191
   740
    joystick = SDL_joysticks;
slouken@8920
   741
    while (joystick) {
slouken@7191
   742
        SDL_Joystick *joysticknext;
slouken@7191
   743
        /* save off the next pointer, the Update call may cause a joystick removed event
slouken@7191
   744
         * and cause our joystick pointer to be freed
slouken@7191
   745
         */
slouken@7191
   746
        joysticknext = joystick->next;
slouken@0
   747
slouken@6712
   748
        SDL_updating_joystick = joystick;
slouken@6712
   749
slouken@8920
   750
        SDL_SYS_JoystickUpdate(joystick);
slouken@6690
   751
icculus@9433
   752
        if (joystick->force_recentering) {
slouken@7191
   753
            int i;
slouken@6690
   754
slouken@6712
   755
            /* Tell the app that everything is centered/unpressed...  */
slime73@9876
   756
            for (i = 0; i < joystick->naxes; i++) {
slouken@10477
   757
                SDL_PrivateJoystickAxis(joystick, i, joystick->axes_zero[i]);
slime73@9876
   758
            }
slouken@6690
   759
slime73@9876
   760
            for (i = 0; i < joystick->nbuttons; i++) {
slouken@6690
   761
                SDL_PrivateJoystickButton(joystick, i, 0);
slime73@9876
   762
            }
slouken@6690
   763
slime73@9876
   764
            for (i = 0; i < joystick->nhats; i++) {
slouken@6690
   765
                SDL_PrivateJoystickHat(joystick, i, SDL_HAT_CENTERED);
slime73@9876
   766
            }
slouken@6712
   767
icculus@9433
   768
            joystick->force_recentering = SDL_FALSE;
slouken@7191
   769
        }
slouken@6690
   770
slouken@6712
   771
        SDL_updating_joystick = NULL;
slouken@6712
   772
slouken@6712
   773
        /* If the joystick was closed while updating, free it here */
slouken@8920
   774
        if (joystick->ref_count <= 0) {
slouken@6712
   775
            SDL_JoystickClose(joystick);
slouken@6712
   776
        }
slouken@6712
   777
slouken@7191
   778
        joystick = joysticknext;
slouken@7191
   779
    }
slouken@6690
   780
slouken@7191
   781
    /* this needs to happen AFTER walking the joystick list above, so that any
slouken@7191
   782
       dangling hardware data from removed devices can be free'd
slouken@7191
   783
     */
slouken@7191
   784
    SDL_SYS_JoystickDetect();
slouken@0
   785
}
slouken@0
   786
slouken@1895
   787
int
slouken@1895
   788
SDL_JoystickEventState(int state)
slouken@0
   789
{
slouken@1361
   790
#if SDL_EVENTS_DISABLED
slouken@6753
   791
    return SDL_DISABLE;
slouken@0
   792
#else
slouken@4429
   793
    const Uint32 event_list[] = {
slouken@1895
   794
        SDL_JOYAXISMOTION, SDL_JOYBALLMOTION, SDL_JOYHATMOTION,
slouken@6690
   795
        SDL_JOYBUTTONDOWN, SDL_JOYBUTTONUP, SDL_JOYDEVICEADDED, SDL_JOYDEVICEREMOVED
slouken@1895
   796
    };
slouken@1895
   797
    unsigned int i;
slouken@0
   798
slouken@1895
   799
    switch (state) {
slouken@1895
   800
    case SDL_QUERY:
slouken@6753
   801
        state = SDL_DISABLE;
slouken@1895
   802
        for (i = 0; i < SDL_arraysize(event_list); ++i) {
slouken@1895
   803
            state = SDL_EventState(event_list[i], SDL_QUERY);
slouken@1895
   804
            if (state == SDL_ENABLE) {
slouken@1895
   805
                break;
slouken@1895
   806
            }
slouken@1895
   807
        }
slouken@1895
   808
        break;
slouken@1895
   809
    default:
slouken@1895
   810
        for (i = 0; i < SDL_arraysize(event_list); ++i) {
slouken@1895
   811
            SDL_EventState(event_list[i], state);
slouken@1895
   812
        }
slouken@1895
   813
        break;
slouken@1895
   814
    }
slouken@1895
   815
    return (state);
slouken@1361
   816
#endif /* SDL_EVENTS_DISABLED */
slouken@0
   817
}
slouken@1895
   818
slouken@6693
   819
/* return the guid for this index */
slouken@6738
   820
SDL_JoystickGUID SDL_JoystickGetDeviceGUID(int device_index)
slouken@6690
   821
{
slouken@7294
   822
    if ((device_index < 0) || (device_index >= SDL_NumJoysticks())) {
slouken@7294
   823
        SDL_JoystickGUID emptyGUID;
slouken@7294
   824
        SDL_SetError("There are %d joysticks available", SDL_NumJoysticks());
slouken@8920
   825
        SDL_zero(emptyGUID);
slouken@7294
   826
        return emptyGUID;
slouken@7294
   827
    }
slouken@8920
   828
    return SDL_SYS_JoystickGetDeviceGUID(device_index);
slouken@6690
   829
}
slouken@6690
   830
slouken@6693
   831
/* return the guid for this opened device */
slouken@6738
   832
SDL_JoystickGUID SDL_JoystickGetGUID(SDL_Joystick * joystick)
slouken@6690
   833
{
slouken@7789
   834
    if (!SDL_PrivateJoystickValid(joystick)) {
slouken@7789
   835
        SDL_JoystickGUID emptyGUID;
slouken@8920
   836
        SDL_zero(emptyGUID);
slouken@7789
   837
        return emptyGUID;
slouken@7789
   838
    }
slouken@8920
   839
    return SDL_SYS_JoystickGetGUID(joystick);
slouken@6690
   840
}
slouken@6690
   841
slouken@6690
   842
/* convert the guid to a printable string */
slouken@8920
   843
void SDL_JoystickGetGUIDString(SDL_JoystickGUID guid, char *pszGUID, int cbGUID)
slouken@6690
   844
{
slouken@7191
   845
    static const char k_rgchHexToASCII[] = "0123456789abcdef";
slouken@7191
   846
    int i;
slouken@6690
   847
icculus@6748
   848
    if ((pszGUID == NULL) || (cbGUID <= 0)) {
icculus@6748
   849
        return;
icculus@6748
   850
    }
icculus@6748
   851
slouken@8920
   852
    for (i = 0; i < sizeof(guid.data) && i < (cbGUID-1)/2; i++) {
slouken@7191
   853
        /* each input byte writes 2 ascii chars, and might write a null byte. */
slouken@7191
   854
        /* If we don't have room for next input byte, stop */
slouken@7191
   855
        unsigned char c = guid.data[i];
slouken@6690
   856
slouken@8920
   857
        *pszGUID++ = k_rgchHexToASCII[c >> 4];
slouken@8920
   858
        *pszGUID++ = k_rgchHexToASCII[c & 0x0F];
slouken@7191
   859
    }
slouken@7191
   860
    *pszGUID = '\0';
slouken@6690
   861
}
slouken@6690
   862
slouken@6690
   863
slouken@7191
   864
/*-----------------------------------------------------------------------------
slouken@7191
   865
 * Purpose: Returns the 4 bit nibble for a hex character
slouken@7191
   866
 * Input  : c -
slouken@7191
   867
 * Output : unsigned char
slouken@7191
   868
 *-----------------------------------------------------------------------------*/
slouken@8920
   869
static unsigned char nibble(char c)
slouken@6690
   870
{
slouken@8920
   871
    if ((c >= '0') && (c <= '9')) {
slouken@7191
   872
        return (unsigned char)(c - '0');
slouken@7191
   873
    }
slouken@6690
   874
slouken@8920
   875
    if ((c >= 'A') && (c <= 'F')) {
slouken@7191
   876
        return (unsigned char)(c - 'A' + 0x0a);
slouken@7191
   877
    }
slouken@6690
   878
slouken@8920
   879
    if ((c >= 'a') && (c <= 'f')) {
slouken@7191
   880
        return (unsigned char)(c - 'a' + 0x0a);
slouken@7191
   881
    }
slouken@6690
   882
slouken@7191
   883
    /* received an invalid character, and no real way to return an error */
slouken@8920
   884
    /* AssertMsg1(false, "Q_nibble invalid hex character '%c' ", c); */
slouken@7191
   885
    return 0;
slouken@6690
   886
}
slouken@6690
   887
slouken@6690
   888
slouken@6690
   889
/* convert the string version of a joystick guid to the struct */
slouken@6738
   890
SDL_JoystickGUID SDL_JoystickGetGUIDFromString(const char *pchGUID)
slouken@6690
   891
{
slouken@7191
   892
    SDL_JoystickGUID guid;
slouken@7191
   893
    int maxoutputbytes= sizeof(guid);
slouken@8920
   894
    size_t len = SDL_strlen(pchGUID);
slouken@7191
   895
    Uint8 *p;
slouken@7922
   896
    size_t i;
slouken@6690
   897
slouken@7191
   898
    /* Make sure it's even */
slouken@8920
   899
    len = (len) & ~0x1;
slouken@6690
   900
slouken@8920
   901
    SDL_memset(&guid, 0x00, sizeof(guid));
slouken@6690
   902
slouken@7191
   903
    p = (Uint8 *)&guid;
slouken@8920
   904
    for (i = 0; (i < len) && ((p - (Uint8 *)&guid) < maxoutputbytes); i+=2, p++) {
slouken@8920
   905
        *p = (nibble(pchGUID[i]) << 4) | nibble(pchGUID[i+1]);
slouken@7191
   906
    }
slouken@6690
   907
slouken@7191
   908
    return guid;
slouken@6690
   909
}
slouken@6690
   910
slouken@6690
   911
slouken@9884
   912
/* update the power level for this joystick */
slouken@9884
   913
void SDL_PrivateJoystickBatteryLevel(SDL_Joystick * joystick, SDL_JoystickPowerLevel ePowerLevel)
slouken@9884
   914
{
slouken@9884
   915
    joystick->epowerlevel = ePowerLevel;
slouken@9884
   916
}
slouken@9884
   917
slouken@9884
   918
slouken@9884
   919
/* return its power level */
slouken@9884
   920
SDL_JoystickPowerLevel SDL_JoystickCurrentPowerLevel(SDL_Joystick * joystick)
slouken@9884
   921
{
slouken@9884
   922
    if (!SDL_PrivateJoystickValid(joystick)) {
slouken@9884
   923
        return (SDL_JOYSTICK_POWER_UNKNOWN);
slouken@9884
   924
    }
slouken@9884
   925
    return joystick->epowerlevel;
slouken@9884
   926
}
slouken@9884
   927
slouken@9884
   928
slouken@1895
   929
/* vi: set ts=4 sw=4 expandtab: */