src/joystick/win32/SDL_mmjoystick.c
author Sam Lantinga
Mon, 10 Jul 2006 21:04:37 +0000
changeset 1895 c121d94672cb
parent 1748 5e86e34453d4
child 2061 6051761b5934
permissions -rw-r--r--
SDL 1.2 is moving to a branch, and SDL 1.3 is becoming the head.
slouken@0
     1
/*
slouken@0
     2
    SDL - Simple DirectMedia Layer
slouken@1312
     3
    Copyright (C) 1997-2006 Sam Lantinga
slouken@0
     4
slouken@0
     5
    This library is free software; you can redistribute it and/or
slouken@1312
     6
    modify it under the terms of the GNU Lesser General Public
slouken@0
     7
    License as published by the Free Software Foundation; either
slouken@1312
     8
    version 2.1 of the License, or (at your option) any later version.
slouken@0
     9
slouken@0
    10
    This library is distributed in the hope that it will be useful,
slouken@0
    11
    but WITHOUT ANY WARRANTY; without even the implied warranty of
slouken@0
    12
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
slouken@1312
    13
    Lesser General Public License for more details.
slouken@0
    14
slouken@1312
    15
    You should have received a copy of the GNU Lesser General Public
slouken@1312
    16
    License along with this library; if not, write to the Free Software
slouken@1312
    17
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
slouken@0
    18
slouken@0
    19
    Sam Lantinga
slouken@252
    20
    slouken@libsdl.org
slouken@0
    21
*/
slouken@1402
    22
#include "SDL_config.h"
slouken@0
    23
slouken@1635
    24
#ifdef SDL_JOYSTICK_WINMM
slouken@1635
    25
slouken@0
    26
/* Win32 MultiMedia Joystick driver, contributed by Andrei de A. Formiga */
slouken@0
    27
slouken@1433
    28
#define WIN32_LEAN_AND_MEAN
slouken@1433
    29
#include <windows.h>
slouken@1358
    30
#include <mmsystem.h>
slouken@1358
    31
#include <regstr.h>
slouken@1358
    32
slouken@1330
    33
#include "SDL_events.h"
slouken@0
    34
#include "SDL_joystick.h"
slouken@1361
    35
#include "../SDL_sysjoystick.h"
slouken@1361
    36
#include "../SDL_joystick_c.h"
slouken@0
    37
slouken@531
    38
#define MAX_JOYSTICKS	16
slouken@1895
    39
#define MAX_AXES	6       /* each joystick can have up to 6 axes */
slouken@1895
    40
#define MAX_BUTTONS	32      /* and 32 buttons                      */
slouken@0
    41
#define AXIS_MIN	-32768  /* minimum value for axis coordinate */
slouken@0
    42
#define AXIS_MAX	32767   /* maximum value for axis coordinate */
slouken@834
    43
/* limit axis to 256 possible positions to filter out noise */
slouken@834
    44
#define JOY_AXIS_THRESHOLD      (((AXIS_MAX)-(AXIS_MIN))/256)
slouken@0
    45
#define JOY_BUTTON_FLAG(n)	(1<<n)
slouken@0
    46
slouken@0
    47
slouken@0
    48
/* array to hold joystick ID values */
slouken@1895
    49
static UINT SYS_JoystickID[MAX_JOYSTICKS];
slouken@1895
    50
static JOYCAPS SYS_Joystick[MAX_JOYSTICKS];
slouken@1895
    51
static char *SYS_JoystickName[MAX_JOYSTICKS];
slouken@0
    52
slouken@0
    53
/* The private structure used to keep track of a joystick */
slouken@0
    54
struct joystick_hwdata
slouken@0
    55
{
slouken@1895
    56
    /* joystick ID */
slouken@1895
    57
    UINT id;
slouken@0
    58
slouken@1895
    59
    /* values used to translate device-specific coordinates into
slouken@1895
    60
       SDL-standard ranges */
slouken@1895
    61
    struct _transaxis
slouken@1895
    62
    {
slouken@1895
    63
        int offset;
slouken@1895
    64
        float scale;
slouken@1895
    65
    } transaxis[6];
slouken@0
    66
};
slouken@0
    67
slouken@0
    68
/* Convert a win32 Multimedia API return code to a text message */
slouken@0
    69
static void SetMMerror(char *function, int code);
slouken@0
    70
slouken@0
    71
slouken@1895
    72
static char *
slouken@1895
    73
GetJoystickName(int index, const char *szRegKey)
slouken@937
    74
{
slouken@1895
    75
    /* added 7/24/2004 by Eckhard Stolberg */
slouken@1895
    76
    /*
slouken@1895
    77
       see if there is a joystick for the current
slouken@1895
    78
       index (1-16) listed in the registry
slouken@1895
    79
     */
slouken@1895
    80
    char *name = NULL;
slouken@1895
    81
    HKEY hKey;
slouken@1895
    82
    DWORD regsize;
slouken@1895
    83
    LONG regresult;
slouken@1895
    84
    unsigned char regkey[256];
slouken@1895
    85
    unsigned char regvalue[256];
slouken@1895
    86
    unsigned char regname[256];
slouken@937
    87
slouken@1895
    88
    SDL_snprintf((char *) regkey, SDL_arraysize(regkey), "%s\\%s\\%s",
slouken@1895
    89
                 REGSTR_PATH_JOYCONFIG, szRegKey, REGSTR_KEY_JOYCURR);
slouken@1895
    90
    regresult = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
slouken@1895
    91
                              (LPTSTR) & regkey, 0, KEY_READ, &hKey);
slouken@1895
    92
    if (regresult == ERROR_SUCCESS) {
slouken@1895
    93
        /*
slouken@1895
    94
           find the registry key name for the
slouken@1895
    95
           joystick's properties
slouken@1895
    96
         */
slouken@1895
    97
        regsize = sizeof(regname);
slouken@1895
    98
        SDL_snprintf((char *) regvalue, SDL_arraysize(regvalue),
slouken@1895
    99
                     "Joystick%d%s", index + 1, REGSTR_VAL_JOYOEMNAME);
slouken@1895
   100
        regresult = RegQueryValueExA(hKey,
slouken@1895
   101
                                     (char *) regvalue, 0, 0,
slouken@1895
   102
                                     (LPBYTE) & regname, (LPDWORD) & regsize);
slouken@1895
   103
        RegCloseKey(hKey);
slouken@1895
   104
        if (regresult == ERROR_SUCCESS) {
slouken@1895
   105
            /* open that registry key */
slouken@1895
   106
            SDL_snprintf((char *) regkey, SDL_arraysize(regkey),
slouken@1895
   107
                         "%s\\%s", REGSTR_PATH_JOYOEM, regname);
slouken@1895
   108
            regresult =
slouken@1895
   109
                RegOpenKeyExA(HKEY_LOCAL_MACHINE, (char *) regkey, 0,
slouken@1895
   110
                              KEY_READ, &hKey);
slouken@1895
   111
            if (regresult == ERROR_SUCCESS) {
slouken@1895
   112
                /* find the size for the OEM name text */
slouken@1895
   113
                regsize = sizeof(regvalue);
slouken@1895
   114
                regresult =
slouken@1895
   115
                    RegQueryValueExA(hKey,
slouken@1895
   116
                                     REGSTR_VAL_JOYOEMNAME,
slouken@1895
   117
                                     0, 0, NULL, (LPDWORD) & regsize);
slouken@1895
   118
                if (regresult == ERROR_SUCCESS) {
slouken@1895
   119
                    /*
slouken@1895
   120
                       allocate enough memory
slouken@1895
   121
                       for the OEM name text ...
slouken@1895
   122
                     */
slouken@1895
   123
                    name = (char *) SDL_malloc(regsize);
slouken@1895
   124
                    /* ... and read it from the registry */
slouken@1895
   125
                    regresult =
slouken@1895
   126
                        RegQueryValueExA(hKey,
slouken@1895
   127
                                         REGSTR_VAL_JOYOEMNAME, 0, 0,
slouken@1895
   128
                                         (LPBYTE) name, (LPDWORD) & regsize);
slouken@1895
   129
                    RegCloseKey(hKey);
slouken@1895
   130
                }
slouken@1895
   131
            }
slouken@1895
   132
        }
slouken@1895
   133
    }
slouken@1895
   134
    return (name);
slouken@937
   135
}
slouken@937
   136
slouken@0
   137
/* Function to scan the system for joysticks.
slouken@0
   138
 * This function should set SDL_numjoysticks to the number of available
slouken@0
   139
 * joysticks.  Joystick 0 should be the system default joystick.
slouken@0
   140
 * It should return 0, or -1 on an unrecoverable fatal error.
slouken@0
   141
 */
slouken@1895
   142
int
slouken@1895
   143
SDL_SYS_JoystickInit(void)
slouken@0
   144
{
slouken@1895
   145
    int i;
slouken@1895
   146
    int maxdevs;
slouken@1895
   147
    int numdevs;
slouken@1895
   148
    JOYINFOEX joyinfo;
slouken@1895
   149
    JOYCAPS joycaps;
slouken@1895
   150
    MMRESULT result;
slouken@0
   151
slouken@1895
   152
    /* Reset the joystick ID & name mapping tables */
slouken@1895
   153
    for (i = 0; i < MAX_JOYSTICKS; ++i) {
slouken@1895
   154
        SYS_JoystickID[i] = 0;
slouken@1895
   155
        SYS_JoystickName[i] = NULL;
slouken@1895
   156
    }
slouken@531
   157
slouken@1895
   158
    /* Loop over all potential joystick devices */
slouken@1895
   159
    numdevs = 0;
slouken@1895
   160
    maxdevs = joyGetNumDevs();
slouken@1895
   161
    for (i = JOYSTICKID1; i < maxdevs && numdevs < MAX_JOYSTICKS; ++i) {
slouken@1895
   162
slouken@1895
   163
        joyinfo.dwSize = sizeof(joyinfo);
slouken@1895
   164
        joyinfo.dwFlags = JOY_RETURNALL;
slouken@1895
   165
        result = joyGetPosEx(SYS_JoystickID[i], &joyinfo);
slouken@1895
   166
        if (result == JOYERR_NOERROR) {
slouken@1895
   167
            result = joyGetDevCaps(i, &joycaps, sizeof(joycaps));
slouken@1895
   168
            if (result == JOYERR_NOERROR) {
slouken@1895
   169
                SYS_JoystickID[numdevs] = i;
slouken@1895
   170
                SYS_Joystick[numdevs] = joycaps;
slouken@1895
   171
                SYS_JoystickName[numdevs] =
slouken@1895
   172
                    GetJoystickName(i, joycaps.szRegKey);
slouken@1895
   173
                numdevs++;
slouken@1895
   174
            }
slouken@1895
   175
        }
slouken@1895
   176
    }
slouken@1895
   177
    return (numdevs);
slouken@0
   178
}
slouken@0
   179
slouken@0
   180
/* Function to get the device-dependent name of a joystick */
slouken@1895
   181
const char *
slouken@1895
   182
SDL_SYS_JoystickName(int index)
slouken@0
   183
{
slouken@1895
   184
    if (SYS_JoystickName[index] != NULL) {
slouken@1895
   185
        return (SYS_JoystickName[index]);
slouken@1895
   186
    } else {
slouken@1895
   187
        return (SYS_Joystick[index].szPname);
slouken@1895
   188
    }
slouken@0
   189
}
slouken@0
   190
slouken@0
   191
/* Function to open a joystick for use.
slouken@0
   192
   The joystick to open is specified by the index field of the joystick.
slouken@0
   193
   This should fill the nbuttons and naxes fields of the joystick structure.
slouken@0
   194
   It returns 0, or -1 if there is an error.
slouken@0
   195
 */
slouken@1895
   196
int
slouken@1895
   197
SDL_SYS_JoystickOpen(SDL_Joystick * joystick)
slouken@0
   198
{
slouken@1895
   199
    int index, i;
slouken@1895
   200
    int caps_flags[MAX_AXES - 2] =
slouken@1895
   201
        { JOYCAPS_HASZ, JOYCAPS_HASR, JOYCAPS_HASU, JOYCAPS_HASV };
slouken@1895
   202
    int axis_min[MAX_AXES], axis_max[MAX_AXES];
slouken@0
   203
slouken@0
   204
slouken@1895
   205
    /* shortcut */
slouken@1895
   206
    index = joystick->index;
slouken@1895
   207
    axis_min[0] = SYS_Joystick[index].wXmin;
slouken@1895
   208
    axis_max[0] = SYS_Joystick[index].wXmax;
slouken@1895
   209
    axis_min[1] = SYS_Joystick[index].wYmin;
slouken@1895
   210
    axis_max[1] = SYS_Joystick[index].wYmax;
slouken@1895
   211
    axis_min[2] = SYS_Joystick[index].wZmin;
slouken@1895
   212
    axis_max[2] = SYS_Joystick[index].wZmax;
slouken@1895
   213
    axis_min[3] = SYS_Joystick[index].wRmin;
slouken@1895
   214
    axis_max[3] = SYS_Joystick[index].wRmax;
slouken@1895
   215
    axis_min[4] = SYS_Joystick[index].wUmin;
slouken@1895
   216
    axis_max[4] = SYS_Joystick[index].wUmax;
slouken@1895
   217
    axis_min[5] = SYS_Joystick[index].wVmin;
slouken@1895
   218
    axis_max[5] = SYS_Joystick[index].wVmax;
slouken@0
   219
slouken@1895
   220
    /* allocate memory for system specific hardware data */
slouken@1895
   221
    joystick->hwdata =
slouken@1895
   222
        (struct joystick_hwdata *) SDL_malloc(sizeof(*joystick->hwdata));
slouken@1895
   223
    if (joystick->hwdata == NULL) {
slouken@1895
   224
        SDL_OutOfMemory();
slouken@1895
   225
        return (-1);
slouken@1895
   226
    }
slouken@1895
   227
    SDL_memset(joystick->hwdata, 0, sizeof(*joystick->hwdata));
slouken@0
   228
slouken@1895
   229
    /* set hardware data */
slouken@1895
   230
    joystick->hwdata->id = SYS_JoystickID[index];
slouken@1895
   231
    for (i = 0; i < MAX_AXES; ++i) {
slouken@1895
   232
        if ((i < 2) || (SYS_Joystick[index].wCaps & caps_flags[i - 2])) {
slouken@1895
   233
            joystick->hwdata->transaxis[i].offset = AXIS_MIN - axis_min[i];
slouken@1895
   234
            joystick->hwdata->transaxis[i].scale =
slouken@1895
   235
                (float) (AXIS_MAX - AXIS_MIN) / (axis_max[i] - axis_min[i]);
slouken@1895
   236
        } else {
slouken@1895
   237
            joystick->hwdata->transaxis[i].offset = 0;
slouken@1895
   238
            joystick->hwdata->transaxis[i].scale = 1.0; /* Just in case */
slouken@1895
   239
        }
slouken@1895
   240
    }
slouken@1895
   241
slouken@1895
   242
    /* fill nbuttons, naxes, and nhats fields */
slouken@1895
   243
    joystick->nbuttons = SYS_Joystick[index].wNumButtons;
slouken@1895
   244
    joystick->naxes = SYS_Joystick[index].wNumAxes;
slouken@1895
   245
    if (SYS_Joystick[index].wCaps & JOYCAPS_HASPOV) {
slouken@1895
   246
        joystick->nhats = 1;
slouken@1895
   247
    } else {
slouken@1895
   248
        joystick->nhats = 0;
slouken@1895
   249
    }
slouken@1895
   250
    return (0);
slouken@0
   251
}
slouken@0
   252
slouken@1895
   253
static Uint8
slouken@1895
   254
TranslatePOV(DWORD value)
slouken@0
   255
{
slouken@1895
   256
    Uint8 pos;
slouken@0
   257
slouken@1895
   258
    pos = SDL_HAT_CENTERED;
slouken@1895
   259
    if (value != JOY_POVCENTERED) {
slouken@1895
   260
        if ((value > JOY_POVLEFT) || (value < JOY_POVRIGHT)) {
slouken@1895
   261
            pos |= SDL_HAT_UP;
slouken@1895
   262
        }
slouken@1895
   263
        if ((value > JOY_POVFORWARD) && (value < JOY_POVBACKWARD)) {
slouken@1895
   264
            pos |= SDL_HAT_RIGHT;
slouken@1895
   265
        }
slouken@1895
   266
        if ((value > JOY_POVRIGHT) && (value < JOY_POVLEFT)) {
slouken@1895
   267
            pos |= SDL_HAT_DOWN;
slouken@1895
   268
        }
slouken@1895
   269
        if (value > JOY_POVBACKWARD) {
slouken@1895
   270
            pos |= SDL_HAT_LEFT;
slouken@1895
   271
        }
slouken@1895
   272
    }
slouken@1895
   273
    return (pos);
slouken@0
   274
}
slouken@0
   275
slouken@0
   276
/* Function to update the state of a joystick - called as a device poll.
slouken@0
   277
 * This function shouldn't update the joystick structure directly,
slouken@0
   278
 * but instead should call SDL_PrivateJoystick*() to deliver events
slouken@0
   279
 * and update joystick device state.
slouken@0
   280
 */
slouken@1895
   281
void
slouken@1895
   282
SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
slouken@0
   283
{
slouken@1895
   284
    MMRESULT result;
slouken@1895
   285
    int i;
slouken@1895
   286
    DWORD flags[MAX_AXES] = { JOY_RETURNX, JOY_RETURNY, JOY_RETURNZ,
slouken@1895
   287
        JOY_RETURNR, JOY_RETURNU, JOY_RETURNV
slouken@1895
   288
    };
slouken@1895
   289
    DWORD pos[MAX_AXES];
slouken@1895
   290
    struct _transaxis *transaxis;
slouken@1895
   291
    int value, change;
slouken@1895
   292
    JOYINFOEX joyinfo;
slouken@0
   293
slouken@1895
   294
    joyinfo.dwSize = sizeof(joyinfo);
slouken@1895
   295
    joyinfo.dwFlags = JOY_RETURNALL | JOY_RETURNPOVCTS;
slouken@1895
   296
    if (!joystick->hats) {
slouken@1895
   297
        joyinfo.dwFlags &= ~(JOY_RETURNPOV | JOY_RETURNPOVCTS);
slouken@1895
   298
    }
slouken@1895
   299
    result = joyGetPosEx(joystick->hwdata->id, &joyinfo);
slouken@1895
   300
    if (result != JOYERR_NOERROR) {
slouken@1895
   301
        SetMMerror("joyGetPosEx", result);
slouken@1895
   302
        return;
slouken@1895
   303
    }
slouken@0
   304
slouken@1895
   305
    /* joystick motion events */
slouken@1895
   306
    pos[0] = joyinfo.dwXpos;
slouken@1895
   307
    pos[1] = joyinfo.dwYpos;
slouken@1895
   308
    pos[2] = joyinfo.dwZpos;
slouken@1895
   309
    pos[3] = joyinfo.dwRpos;
slouken@1895
   310
    pos[4] = joyinfo.dwUpos;
slouken@1895
   311
    pos[5] = joyinfo.dwVpos;
slouken@0
   312
slouken@1895
   313
    transaxis = joystick->hwdata->transaxis;
slouken@1895
   314
    for (i = 0; i < joystick->naxes; i++) {
slouken@1895
   315
        if (joyinfo.dwFlags & flags[i]) {
slouken@1895
   316
            value =
slouken@1895
   317
                (int) (((float) pos[i] +
slouken@1895
   318
                        transaxis[i].offset) * transaxis[i].scale);
slouken@1895
   319
            change = (value - joystick->axes[i]);
slouken@1895
   320
            if ((change < -JOY_AXIS_THRESHOLD)
slouken@1895
   321
                || (change > JOY_AXIS_THRESHOLD)) {
slouken@1895
   322
                SDL_PrivateJoystickAxis(joystick, (Uint8) i, (Sint16) value);
slouken@1895
   323
            }
slouken@1895
   324
        }
slouken@1895
   325
    }
slouken@0
   326
slouken@1895
   327
    /* joystick button events */
slouken@1895
   328
    if (joyinfo.dwFlags & JOY_RETURNBUTTONS) {
slouken@1895
   329
        for (i = 0; i < joystick->nbuttons; ++i) {
slouken@1895
   330
            if (joyinfo.dwButtons & JOY_BUTTON_FLAG(i)) {
slouken@1895
   331
                if (!joystick->buttons[i]) {
slouken@1895
   332
                    SDL_PrivateJoystickButton(joystick, (Uint8) i,
slouken@1895
   333
                                              SDL_PRESSED);
slouken@1895
   334
                }
slouken@1895
   335
            } else {
slouken@1895
   336
                if (joystick->buttons[i]) {
slouken@1895
   337
                    SDL_PrivateJoystickButton(joystick, (Uint8) i,
slouken@1895
   338
                                              SDL_RELEASED);
slouken@1895
   339
                }
slouken@1895
   340
            }
slouken@1895
   341
        }
slouken@1895
   342
    }
slouken@0
   343
slouken@1895
   344
    /* joystick hat events */
slouken@1895
   345
    if (joyinfo.dwFlags & JOY_RETURNPOV) {
slouken@1895
   346
        Uint8 pos;
slouken@0
   347
slouken@1895
   348
        pos = TranslatePOV(joyinfo.dwPOV);
slouken@1895
   349
        if (pos != joystick->hats[0]) {
slouken@1895
   350
            SDL_PrivateJoystickHat(joystick, 0, pos);
slouken@1895
   351
        }
slouken@1895
   352
    }
slouken@0
   353
}
slouken@0
   354
slouken@0
   355
/* Function to close a joystick after use */
slouken@1895
   356
void
slouken@1895
   357
SDL_SYS_JoystickClose(SDL_Joystick * joystick)
slouken@0
   358
{
slouken@1895
   359
    if (joystick->hwdata != NULL) {
slouken@1895
   360
        /* free system specific hardware data */
slouken@1895
   361
        SDL_free(joystick->hwdata);
slouken@1895
   362
    }
slouken@0
   363
}
slouken@0
   364
slouken@0
   365
/* Function to perform any system-specific joystick related cleanup */
slouken@1895
   366
void
slouken@1895
   367
SDL_SYS_JoystickQuit(void)
slouken@0
   368
{
slouken@1895
   369
    int i;
slouken@1895
   370
    for (i = 0; i < MAX_JOYSTICKS; i++) {
slouken@1895
   371
        if (SYS_JoystickName[i] != NULL) {
slouken@1895
   372
            SDL_free(SYS_JoystickName[i]);
slouken@1895
   373
        }
slouken@1895
   374
    }
slouken@0
   375
}
slouken@0
   376
slouken@0
   377
slouken@0
   378
/* implementation functions */
slouken@1895
   379
void
slouken@1895
   380
SetMMerror(char *function, int code)
slouken@0
   381
{
slouken@1895
   382
    static char *error;
slouken@1895
   383
    static char errbuf[1024];
slouken@0
   384
slouken@1895
   385
    errbuf[0] = 0;
slouken@1895
   386
    switch (code) {
slouken@1895
   387
    case MMSYSERR_NODRIVER:
slouken@1895
   388
        error = "Joystick driver not present";
slouken@1895
   389
        break;
slouken@1895
   390
slouken@1895
   391
    case MMSYSERR_INVALPARAM:
slouken@1895
   392
    case JOYERR_PARMS:
slouken@1895
   393
        error = "Invalid parameter(s)";
slouken@1895
   394
        break;
slouken@1895
   395
slouken@1895
   396
    case MMSYSERR_BADDEVICEID:
slouken@1895
   397
        error = "Bad device ID";
slouken@1895
   398
        break;
slouken@0
   399
slouken@1895
   400
    case JOYERR_UNPLUGGED:
slouken@1895
   401
        error = "Joystick not attached";
slouken@1895
   402
        break;
slouken@0
   403
slouken@1895
   404
    case JOYERR_NOCANDO:
slouken@1895
   405
        error = "Can't capture joystick input";
slouken@1895
   406
        break;
slouken@0
   407
slouken@1895
   408
    default:
slouken@1895
   409
        SDL_snprintf(errbuf, SDL_arraysize(errbuf),
slouken@1895
   410
                     "%s: Unknown Multimedia system error: 0x%x",
slouken@1895
   411
                     function, code);
slouken@1895
   412
        break;
slouken@1895
   413
    }
slouken@0
   414
slouken@1895
   415
    if (!errbuf[0]) {
slouken@1895
   416
        SDL_snprintf(errbuf, SDL_arraysize(errbuf), "%s: %s", function,
slouken@1895
   417
                     error);
slouken@1895
   418
    }
slouken@1895
   419
    SDL_SetError("%s", errbuf);
slouken@0
   420
}
slouken@1635
   421
slouken@1635
   422
#endif /* SDL_JOYSTICK_WINMM */
slouken@1895
   423
/* vi: set ts=4 sw=4 expandtab: */