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