src/joystick/windows/SDL_mmjoystick.c
author Ryan C. Gordon
Tue, 24 Jan 2017 16:18:25 -0500
changeset 10850 c9dc0068b0e7
parent 10818 7e06b0e4dbe0
child 11811 5d94cb6b24d3
permissions -rw-r--r--
configure: report libsamplerate support status.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 #include "../../SDL_internal.h"
    22 
    23 #ifdef SDL_JOYSTICK_WINMM
    24 
    25 /* Win32 MultiMedia Joystick driver, contributed by Andrei de A. Formiga */
    26 
    27 #include "../../core/windows/SDL_windows.h"
    28 #include <mmsystem.h>
    29 #include <regstr.h>
    30 
    31 #include "SDL_events.h"
    32 #include "SDL_joystick.h"
    33 #include "../SDL_sysjoystick.h"
    34 #include "../SDL_joystick_c.h"
    35 
    36 #ifdef REGSTR_VAL_JOYOEMNAME 
    37 #undef REGSTR_VAL_JOYOEMNAME 
    38 #endif
    39 #define REGSTR_VAL_JOYOEMNAME "OEMName"
    40 
    41 #define MAX_JOYSTICKS   16
    42 #define MAX_AXES    6       /* each joystick can have up to 6 axes */
    43 #define MAX_BUTTONS 32      /* and 32 buttons                      */
    44 #define JOY_BUTTON_FLAG(n)  (1<<n)
    45 
    46 
    47 /* array to hold joystick ID values */
    48 static UINT SYS_JoystickID[MAX_JOYSTICKS];
    49 static JOYCAPSA SYS_Joystick[MAX_JOYSTICKS];
    50 static char *SYS_JoystickName[MAX_JOYSTICKS];
    51 
    52 /* The private structure used to keep track of a joystick */
    53 struct joystick_hwdata
    54 {
    55     /* joystick ID */
    56     UINT id;
    57 
    58     /* values used to translate device-specific coordinates into
    59        SDL-standard ranges */
    60     struct _transaxis
    61     {
    62         int offset;
    63         float scale;
    64     } transaxis[6];
    65 };
    66 
    67 /* Convert a Windows Multimedia API return code to a text message */
    68 static void SetMMerror(char *function, int code);
    69 
    70 
    71 static char *
    72 GetJoystickName(int index, const char *szRegKey)
    73 {
    74     /* added 7/24/2004 by Eckhard Stolberg */
    75     /*
    76        see if there is a joystick for the current
    77        index (1-16) listed in the registry
    78      */
    79     char *name = NULL;
    80     HKEY hTopKey;
    81     HKEY hKey;
    82     DWORD regsize;
    83     LONG regresult;
    84     char regkey[256];
    85     char regvalue[256];
    86     char regname[256];
    87 
    88     SDL_snprintf(regkey, SDL_arraysize(regkey),
    89 #ifdef UNICODE
    90                  "%S\\%s\\%S",
    91 #else
    92                  "%s\\%s\\%s",
    93 #endif
    94                  REGSTR_PATH_JOYCONFIG, szRegKey, REGSTR_KEY_JOYCURR);
    95     hTopKey = HKEY_LOCAL_MACHINE;
    96     regresult = RegOpenKeyExA(hTopKey, regkey, 0, KEY_READ, &hKey);
    97     if (regresult != ERROR_SUCCESS) {
    98         hTopKey = HKEY_CURRENT_USER;
    99         regresult = RegOpenKeyExA(hTopKey, regkey, 0, KEY_READ, &hKey);
   100     }
   101     if (regresult != ERROR_SUCCESS) {
   102         return NULL;
   103     }
   104 
   105     /* find the registry key name for the joystick's properties */
   106     regsize = sizeof(regname);
   107     SDL_snprintf(regvalue, SDL_arraysize(regvalue), "Joystick%d%s", index + 1,
   108                  REGSTR_VAL_JOYOEMNAME);
   109     regresult =
   110         RegQueryValueExA(hKey, regvalue, 0, 0, (LPBYTE) regname, &regsize);
   111     RegCloseKey(hKey);
   112 
   113     if (regresult != ERROR_SUCCESS) {
   114         return NULL;
   115     }
   116 
   117     /* open that registry key */
   118     SDL_snprintf(regkey, SDL_arraysize(regkey),
   119 #ifdef UNICODE
   120                  "%S\\%s",
   121 #else
   122                  "%s\\%s",
   123 #endif
   124                  REGSTR_PATH_JOYOEM, regname);
   125     regresult = RegOpenKeyExA(hTopKey, regkey, 0, KEY_READ, &hKey);
   126     if (regresult != ERROR_SUCCESS) {
   127         return NULL;
   128     }
   129 
   130     /* find the size for the OEM name text */
   131     regsize = sizeof(regvalue);
   132     regresult =
   133         RegQueryValueExA(hKey, REGSTR_VAL_JOYOEMNAME, 0, 0, NULL, &regsize);
   134     if (regresult == ERROR_SUCCESS) {
   135         /* allocate enough memory for the OEM name text ... */
   136         name = (char *) SDL_malloc(regsize);
   137         if (name) {
   138             /* ... and read it from the registry */
   139             regresult = RegQueryValueExA(hKey,
   140                                          REGSTR_VAL_JOYOEMNAME, 0, 0,
   141                                          (LPBYTE) name, &regsize);
   142         }
   143     }
   144     RegCloseKey(hKey);
   145 
   146     return (name);
   147 }
   148 
   149 static int SDL_SYS_numjoysticks = 0;
   150 
   151 /* Function to scan the system for joysticks.
   152  * Joystick 0 should be the system default joystick.
   153  * It should return 0, or -1 on an unrecoverable fatal error.
   154  */
   155 int
   156 SDL_SYS_JoystickInit(void)
   157 {
   158     int i;
   159     int maxdevs;
   160     JOYINFOEX joyinfo;
   161     JOYCAPSA joycaps;
   162     MMRESULT result;
   163 
   164     /* Reset the joystick ID & name mapping tables */
   165     for (i = 0; i < MAX_JOYSTICKS; ++i) {
   166         SYS_JoystickID[i] = 0;
   167         SYS_JoystickName[i] = NULL;
   168     }
   169 
   170     /* Loop over all potential joystick devices */
   171     SDL_SYS_numjoysticks = 0;
   172     maxdevs = joyGetNumDevs();
   173     for (i = JOYSTICKID1; i < maxdevs && SDL_SYS_numjoysticks < MAX_JOYSTICKS; ++i) {
   174 
   175         joyinfo.dwSize = sizeof(joyinfo);
   176         joyinfo.dwFlags = JOY_RETURNALL;
   177         result = joyGetPosEx(i, &joyinfo);
   178         if (result == JOYERR_NOERROR) {
   179             result = joyGetDevCapsA(i, &joycaps, sizeof(joycaps));
   180             if (result == JOYERR_NOERROR) {
   181                 SYS_JoystickID[SDL_SYS_numjoysticks] = i;
   182                 SYS_Joystick[SDL_SYS_numjoysticks] = joycaps;
   183                 SYS_JoystickName[SDL_SYS_numjoysticks] =
   184                     GetJoystickName(i, joycaps.szRegKey);
   185                 SDL_SYS_numjoysticks++;
   186             }
   187         }
   188     }
   189     return (SDL_SYS_numjoysticks);
   190 }
   191 
   192 int
   193 SDL_SYS_NumJoysticks(void)
   194 {
   195     return SDL_SYS_numjoysticks;
   196 }
   197 
   198 void
   199 SDL_SYS_JoystickDetect(void)
   200 {
   201 }
   202 
   203 /* Function to get the device-dependent name of a joystick */
   204 const char *
   205 SDL_SYS_JoystickNameForDeviceIndex(int device_index)
   206 {
   207     if (SYS_JoystickName[device_index] != NULL) {
   208         return (SYS_JoystickName[device_index]);
   209     } else {
   210         return (SYS_Joystick[device_index].szPname);
   211     }
   212 }
   213 
   214 /* Function to perform the mapping from device index to the instance id for this index */
   215 SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index)
   216 {
   217     return device_index;
   218 }
   219 
   220 /* Function to open a joystick for use.
   221    The joystick to open is specified by the device index.
   222    This should fill the nbuttons and naxes fields of the joystick structure.
   223    It returns 0, or -1 if there is an error.
   224  */
   225 int
   226 SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index)
   227 {
   228     int index, i;
   229     int caps_flags[MAX_AXES - 2] =
   230         { JOYCAPS_HASZ, JOYCAPS_HASR, JOYCAPS_HASU, JOYCAPS_HASV };
   231     int axis_min[MAX_AXES], axis_max[MAX_AXES];
   232 
   233 
   234     /* shortcut */
   235     index = device_index;
   236     axis_min[0] = SYS_Joystick[index].wXmin;
   237     axis_max[0] = SYS_Joystick[index].wXmax;
   238     axis_min[1] = SYS_Joystick[index].wYmin;
   239     axis_max[1] = SYS_Joystick[index].wYmax;
   240     axis_min[2] = SYS_Joystick[index].wZmin;
   241     axis_max[2] = SYS_Joystick[index].wZmax;
   242     axis_min[3] = SYS_Joystick[index].wRmin;
   243     axis_max[3] = SYS_Joystick[index].wRmax;
   244     axis_min[4] = SYS_Joystick[index].wUmin;
   245     axis_max[4] = SYS_Joystick[index].wUmax;
   246     axis_min[5] = SYS_Joystick[index].wVmin;
   247     axis_max[5] = SYS_Joystick[index].wVmax;
   248 
   249     /* allocate memory for system specific hardware data */
   250     joystick->instance_id = device_index;
   251     joystick->hwdata =
   252         (struct joystick_hwdata *) SDL_malloc(sizeof(*joystick->hwdata));
   253     if (joystick->hwdata == NULL) {
   254         return SDL_OutOfMemory();
   255     }
   256     SDL_memset(joystick->hwdata, 0, sizeof(*joystick->hwdata));
   257 
   258     /* set hardware data */
   259     joystick->hwdata->id = SYS_JoystickID[index];
   260     for (i = 0; i < MAX_AXES; ++i) {
   261         if ((i < 2) || (SYS_Joystick[index].wCaps & caps_flags[i - 2])) {
   262             joystick->hwdata->transaxis[i].offset = SDL_JOYSTICK_AXIS_MIN - axis_min[i];
   263             joystick->hwdata->transaxis[i].scale =
   264                 (float) (SDL_JOYSTICK_AXIS_MAX - SDL_JOYSTICK_AXIS_MIN) / (axis_max[i] - axis_min[i]);
   265         } else {
   266             joystick->hwdata->transaxis[i].offset = 0;
   267             joystick->hwdata->transaxis[i].scale = 1.0; /* Just in case */
   268         }
   269     }
   270 
   271     /* fill nbuttons, naxes, and nhats fields */
   272     joystick->nbuttons = SYS_Joystick[index].wNumButtons;
   273     joystick->naxes = SYS_Joystick[index].wNumAxes;
   274     if (SYS_Joystick[index].wCaps & JOYCAPS_HASPOV) {
   275         joystick->nhats = 1;
   276     } else {
   277         joystick->nhats = 0;
   278     }
   279     return (0);
   280 }
   281 
   282 /* Function to determine if this joystick is attached to the system right now */
   283 SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick)
   284 {
   285     return SDL_TRUE;
   286 }
   287 
   288 static Uint8
   289 TranslatePOV(DWORD value)
   290 {
   291     Uint8 pos;
   292 
   293     pos = SDL_HAT_CENTERED;
   294     if (value != JOY_POVCENTERED) {
   295         if ((value > JOY_POVLEFT) || (value < JOY_POVRIGHT)) {
   296             pos |= SDL_HAT_UP;
   297         }
   298         if ((value > JOY_POVFORWARD) && (value < JOY_POVBACKWARD)) {
   299             pos |= SDL_HAT_RIGHT;
   300         }
   301         if ((value > JOY_POVRIGHT) && (value < JOY_POVLEFT)) {
   302             pos |= SDL_HAT_DOWN;
   303         }
   304         if (value > JOY_POVBACKWARD) {
   305             pos |= SDL_HAT_LEFT;
   306         }
   307     }
   308     return (pos);
   309 }
   310 
   311 /* Function to update the state of a joystick - called as a device poll.
   312  * This function shouldn't update the joystick structure directly,
   313  * but instead should call SDL_PrivateJoystick*() to deliver events
   314  * and update joystick device state.
   315  */
   316 void
   317 SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
   318 {
   319     MMRESULT result;
   320     int i;
   321     DWORD flags[MAX_AXES] = { JOY_RETURNX, JOY_RETURNY, JOY_RETURNZ,
   322         JOY_RETURNR, JOY_RETURNU, JOY_RETURNV
   323     };
   324     DWORD pos[MAX_AXES];
   325     struct _transaxis *transaxis;
   326     int value;
   327     JOYINFOEX joyinfo;
   328 
   329     joyinfo.dwSize = sizeof(joyinfo);
   330     joyinfo.dwFlags = JOY_RETURNALL | JOY_RETURNPOVCTS;
   331     if (!joystick->hats) {
   332         joyinfo.dwFlags &= ~(JOY_RETURNPOV | JOY_RETURNPOVCTS);
   333     }
   334     result = joyGetPosEx(joystick->hwdata->id, &joyinfo);
   335     if (result != JOYERR_NOERROR) {
   336         SetMMerror("joyGetPosEx", result);
   337         return;
   338     }
   339 
   340     /* joystick motion events */
   341     pos[0] = joyinfo.dwXpos;
   342     pos[1] = joyinfo.dwYpos;
   343     pos[2] = joyinfo.dwZpos;
   344     pos[3] = joyinfo.dwRpos;
   345     pos[4] = joyinfo.dwUpos;
   346     pos[5] = joyinfo.dwVpos;
   347 
   348     transaxis = joystick->hwdata->transaxis;
   349     for (i = 0; i < joystick->naxes; i++) {
   350         if (joyinfo.dwFlags & flags[i]) {
   351             value = (int) (((float) pos[i] + transaxis[i].offset) * transaxis[i].scale);
   352             SDL_PrivateJoystickAxis(joystick, (Uint8) i, (Sint16) value);
   353         }
   354     }
   355 
   356     /* joystick button events */
   357     if (joyinfo.dwFlags & JOY_RETURNBUTTONS) {
   358         for (i = 0; i < joystick->nbuttons; ++i) {
   359             if (joyinfo.dwButtons & JOY_BUTTON_FLAG(i)) {
   360                 SDL_PrivateJoystickButton(joystick, (Uint8) i, SDL_PRESSED);
   361             } else {
   362                 SDL_PrivateJoystickButton(joystick, (Uint8) i, SDL_RELEASED);
   363             }
   364         }
   365     }
   366 
   367     /* joystick hat events */
   368     if (joyinfo.dwFlags & JOY_RETURNPOV) {
   369         Uint8 pos;
   370 
   371         pos = TranslatePOV(joyinfo.dwPOV);
   372         SDL_PrivateJoystickHat(joystick, 0, pos);
   373     }
   374 }
   375 
   376 /* Function to close a joystick after use */
   377 void
   378 SDL_SYS_JoystickClose(SDL_Joystick * joystick)
   379 {
   380     SDL_free(joystick->hwdata);
   381 }
   382 
   383 /* Function to perform any system-specific joystick related cleanup */
   384 void
   385 SDL_SYS_JoystickQuit(void)
   386 {
   387     int i;
   388     for (i = 0; i < MAX_JOYSTICKS; i++) {
   389         SDL_free(SYS_JoystickName[i]);
   390         SYS_JoystickName[i] = NULL;
   391     }
   392 }
   393 
   394 SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID( int device_index )
   395 {
   396     SDL_JoystickGUID guid;
   397     /* the GUID is just the first 16 chars of the name for now */
   398     const char *name = SDL_SYS_JoystickNameForDeviceIndex( device_index );
   399     SDL_zero( guid );
   400     SDL_memcpy( &guid, name, SDL_min( sizeof(guid), SDL_strlen( name ) ) );
   401     return guid;
   402 }
   403 
   404 SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick)
   405 {
   406     SDL_JoystickGUID guid;
   407     /* the GUID is just the first 16 chars of the name for now */
   408     const char *name = joystick->name;
   409     SDL_zero( guid );
   410     SDL_memcpy( &guid, name, SDL_min( sizeof(guid), SDL_strlen( name ) ) );
   411     return guid;
   412 }
   413 
   414 
   415 /* implementation functions */
   416 void
   417 SetMMerror(char *function, int code)
   418 {
   419     static char *error;
   420     static char errbuf[1024];
   421 
   422     errbuf[0] = 0;
   423     switch (code) {
   424     case MMSYSERR_NODRIVER:
   425         error = "Joystick driver not present";
   426         break;
   427 
   428     case MMSYSERR_INVALPARAM:
   429     case JOYERR_PARMS:
   430         error = "Invalid parameter(s)";
   431         break;
   432 
   433     case MMSYSERR_BADDEVICEID:
   434         error = "Bad device ID";
   435         break;
   436 
   437     case JOYERR_UNPLUGGED:
   438         error = "Joystick not attached";
   439         break;
   440 
   441     case JOYERR_NOCANDO:
   442         error = "Can't capture joystick input";
   443         break;
   444 
   445     default:
   446         SDL_snprintf(errbuf, SDL_arraysize(errbuf),
   447                      "%s: Unknown Multimedia system error: 0x%x",
   448                      function, code);
   449         break;
   450     }
   451 
   452     if (!errbuf[0]) {
   453         SDL_snprintf(errbuf, SDL_arraysize(errbuf), "%s: %s", function,
   454                      error);
   455     }
   456     SDL_SetError("%s", errbuf);
   457 }
   458 
   459 #endif /* SDL_JOYSTICK_WINMM */
   460 
   461 /* vi: set ts=4 sw=4 expandtab: */