sdl

FORK: Simple Directmedia Layer
git clone https://git.neptards.moe/neptards/sdl.git
Log | Files | Refs

SDL_mmjoystick.c (13329B)


      1 /*
      2   Simple DirectMedia Layer
      3   Copyright (C) 1997-2020 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 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;
    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 = (int) (((float) pos[i] + transaxis[i].offset) * transaxis[i].scale);
    346             SDL_PrivateJoystickAxis(joystick, (Uint8) i, (Sint16) value);
    347         }
    348     }
    349 
    350     /* joystick button events */
    351     if (joyinfo.dwFlags & JOY_RETURNBUTTONS) {
    352         for (i = 0; i < joystick->nbuttons; ++i) {
    353             if (joyinfo.dwButtons & JOY_BUTTON_FLAG(i)) {
    354                 SDL_PrivateJoystickButton(joystick, (Uint8) i, SDL_PRESSED);
    355             } else {
    356                 SDL_PrivateJoystickButton(joystick, (Uint8) i, SDL_RELEASED);
    357             }
    358         }
    359     }
    360 
    361     /* joystick hat events */
    362     if (joyinfo.dwFlags & JOY_RETURNPOV) {
    363         SDL_PrivateJoystickHat(joystick, 0, TranslatePOV(joyinfo.dwPOV));
    364     }
    365 }
    366 
    367 /* Function to close a joystick after use */
    368 void
    369 SDL_SYS_JoystickClose(SDL_Joystick * joystick)
    370 {
    371     SDL_free(joystick->hwdata);
    372 }
    373 
    374 /* Function to perform any system-specific joystick related cleanup */
    375 void
    376 SDL_SYS_JoystickQuit(void)
    377 {
    378     int i;
    379     for (i = 0; i < MAX_JOYSTICKS; i++) {
    380         SDL_free(SYS_JoystickName[i]);
    381         SYS_JoystickName[i] = NULL;
    382     }
    383 }
    384 
    385 SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID( int device_index )
    386 {
    387     SDL_JoystickGUID guid;
    388     /* the GUID is just the first 16 chars of the name for now */
    389     const char *name = SDL_SYS_JoystickNameForDeviceIndex( device_index );
    390     SDL_zero( guid );
    391     SDL_memcpy( &guid, name, SDL_min( sizeof(guid), SDL_strlen( name ) ) );
    392     return guid;
    393 }
    394 
    395 SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick)
    396 {
    397     SDL_JoystickGUID guid;
    398     /* the GUID is just the first 16 chars of the name for now */
    399     const char *name = joystick->name;
    400     SDL_zero( guid );
    401     SDL_memcpy( &guid, name, SDL_min( sizeof(guid), SDL_strlen( name ) ) );
    402     return guid;
    403 }
    404 
    405 
    406 /* implementation functions */
    407 void
    408 SetMMerror(char *function, int code)
    409 {
    410     static char *error;
    411     static char errbuf[1024];
    412 
    413     errbuf[0] = 0;
    414     switch (code) {
    415     case MMSYSERR_NODRIVER:
    416         error = "Joystick driver not present";
    417         break;
    418 
    419     case MMSYSERR_INVALPARAM:
    420     case JOYERR_PARMS:
    421         error = "Invalid parameter(s)";
    422         break;
    423 
    424     case MMSYSERR_BADDEVICEID:
    425         error = "Bad device ID";
    426         break;
    427 
    428     case JOYERR_UNPLUGGED:
    429         error = "Joystick not attached";
    430         break;
    431 
    432     case JOYERR_NOCANDO:
    433         error = "Can't capture joystick input";
    434         break;
    435 
    436     default:
    437         SDL_snprintf(errbuf, SDL_arraysize(errbuf),
    438                      "%s: Unknown Multimedia system error: 0x%x",
    439                      function, code);
    440         break;
    441     }
    442 
    443     if (!errbuf[0]) {
    444         SDL_snprintf(errbuf, SDL_arraysize(errbuf), "%s: %s", function,
    445                      error);
    446     }
    447     SDL_SetError("%s", errbuf);
    448 }
    449 
    450 #endif /* SDL_JOYSTICK_WINMM */
    451 
    452 /* vi: set ts=4 sw=4 expandtab: */