cscg22-gearboy

CSCG 2022 Challenge 'Gearboy'
git clone https://git.sinitax.com/sinitax/cscg22-gearboy
Log | Files | Refs | sfeed.txt

SDL_mmjoystick.c (14266B)


      1/*
      2  Simple DirectMedia Layer
      3  Copyright (C) 1997-2014 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 */
     52static UINT SYS_JoystickID[MAX_JOYSTICKS];
     53static JOYCAPSA SYS_Joystick[MAX_JOYSTICKS];
     54static char *SYS_JoystickName[MAX_JOYSTICKS];
     55
     56/* The private structure used to keep track of a joystick */
     57struct 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 */
     72static void SetMMerror(char *function, int code);
     73
     74
     75static char *
     76GetJoystickName(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
    143static int SDL_SYS_numjoysticks = 0;
    144
    145/* Function to scan the system for joysticks.
    146 * This function should set SDL_numjoysticks to the number of available
    147 * joysticks.  Joystick 0 should be the system default joystick.
    148 * It should return 0, or -1 on an unrecoverable fatal error.
    149 */
    150int
    151SDL_SYS_JoystickInit(void)
    152{
    153    int i;
    154    int maxdevs;
    155    JOYINFOEX joyinfo;
    156    JOYCAPSA joycaps;
    157    MMRESULT result;
    158
    159    /* Reset the joystick ID & name mapping tables */
    160    for (i = 0; i < MAX_JOYSTICKS; ++i) {
    161        SYS_JoystickID[i] = 0;
    162        SYS_JoystickName[i] = NULL;
    163    }
    164
    165    /* Loop over all potential joystick devices */
    166    SDL_SYS_numjoysticks = 0;
    167    maxdevs = joyGetNumDevs();
    168    for (i = JOYSTICKID1; i < maxdevs && SDL_SYS_numjoysticks < MAX_JOYSTICKS; ++i) {
    169
    170        joyinfo.dwSize = sizeof(joyinfo);
    171        joyinfo.dwFlags = JOY_RETURNALL;
    172        result = joyGetPosEx(i, &joyinfo);
    173        if (result == JOYERR_NOERROR) {
    174            result = joyGetDevCapsA(i, &joycaps, sizeof(joycaps));
    175            if (result == JOYERR_NOERROR) {
    176                SYS_JoystickID[SDL_SYS_numjoysticks] = i;
    177                SYS_Joystick[SDL_SYS_numjoysticks] = joycaps;
    178                SYS_JoystickName[SDL_SYS_numjoysticks] =
    179                    GetJoystickName(i, joycaps.szRegKey);
    180                SDL_SYS_numjoysticks++;
    181            }
    182        }
    183    }
    184    return (SDL_SYS_numjoysticks);
    185}
    186
    187int SDL_SYS_NumJoysticks()
    188{
    189    return SDL_SYS_numjoysticks;
    190}
    191
    192void SDL_SYS_JoystickDetect()
    193{
    194}
    195
    196/* Function to get the device-dependent name of a joystick */
    197const char *
    198SDL_SYS_JoystickNameForDeviceIndex(int device_index)
    199{
    200    if (SYS_JoystickName[device_index] != NULL) {
    201        return (SYS_JoystickName[device_index]);
    202    } else {
    203        return (SYS_Joystick[device_index].szPname);
    204    }
    205}
    206
    207/* Function to perform the mapping from device index to the instance id for this index */
    208SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index)
    209{
    210    return device_index;
    211}
    212
    213/* Function to open a joystick for use.
    214   The joystick to open is specified by the index field of the joystick.
    215   This should fill the nbuttons and naxes fields of the joystick structure.
    216   It returns 0, or -1 if there is an error.
    217 */
    218int
    219SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index)
    220{
    221    int index, i;
    222    int caps_flags[MAX_AXES - 2] =
    223        { JOYCAPS_HASZ, JOYCAPS_HASR, JOYCAPS_HASU, JOYCAPS_HASV };
    224    int axis_min[MAX_AXES], axis_max[MAX_AXES];
    225
    226
    227    /* shortcut */
    228    index = device_index;
    229    axis_min[0] = SYS_Joystick[index].wXmin;
    230    axis_max[0] = SYS_Joystick[index].wXmax;
    231    axis_min[1] = SYS_Joystick[index].wYmin;
    232    axis_max[1] = SYS_Joystick[index].wYmax;
    233    axis_min[2] = SYS_Joystick[index].wZmin;
    234    axis_max[2] = SYS_Joystick[index].wZmax;
    235    axis_min[3] = SYS_Joystick[index].wRmin;
    236    axis_max[3] = SYS_Joystick[index].wRmax;
    237    axis_min[4] = SYS_Joystick[index].wUmin;
    238    axis_max[4] = SYS_Joystick[index].wUmax;
    239    axis_min[5] = SYS_Joystick[index].wVmin;
    240    axis_max[5] = SYS_Joystick[index].wVmax;
    241
    242    /* allocate memory for system specific hardware data */
    243    joystick->instance_id = device_index;
    244    joystick->hwdata =
    245        (struct joystick_hwdata *) SDL_malloc(sizeof(*joystick->hwdata));
    246    if (joystick->hwdata == NULL) {
    247        return SDL_OutOfMemory();
    248    }
    249    SDL_memset(joystick->hwdata, 0, sizeof(*joystick->hwdata));
    250
    251    /* set hardware data */
    252    joystick->hwdata->id = SYS_JoystickID[index];
    253    for (i = 0; i < MAX_AXES; ++i) {
    254        if ((i < 2) || (SYS_Joystick[index].wCaps & caps_flags[i - 2])) {
    255            joystick->hwdata->transaxis[i].offset = AXIS_MIN - axis_min[i];
    256            joystick->hwdata->transaxis[i].scale =
    257                (float) (AXIS_MAX - AXIS_MIN) / (axis_max[i] - axis_min[i]);
    258        } else {
    259            joystick->hwdata->transaxis[i].offset = 0;
    260            joystick->hwdata->transaxis[i].scale = 1.0; /* Just in case */
    261        }
    262    }
    263
    264    /* fill nbuttons, naxes, and nhats fields */
    265    joystick->nbuttons = SYS_Joystick[index].wNumButtons;
    266    joystick->naxes = SYS_Joystick[index].wNumAxes;
    267    if (SYS_Joystick[index].wCaps & JOYCAPS_HASPOV) {
    268        joystick->nhats = 1;
    269    } else {
    270        joystick->nhats = 0;
    271    }
    272    return (0);
    273}
    274
    275/* Function to determine is this joystick is attached to the system right now */
    276SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick)
    277{
    278    return SDL_TRUE;
    279}
    280
    281static Uint8
    282TranslatePOV(DWORD value)
    283{
    284    Uint8 pos;
    285
    286    pos = SDL_HAT_CENTERED;
    287    if (value != JOY_POVCENTERED) {
    288        if ((value > JOY_POVLEFT) || (value < JOY_POVRIGHT)) {
    289            pos |= SDL_HAT_UP;
    290        }
    291        if ((value > JOY_POVFORWARD) && (value < JOY_POVBACKWARD)) {
    292            pos |= SDL_HAT_RIGHT;
    293        }
    294        if ((value > JOY_POVRIGHT) && (value < JOY_POVLEFT)) {
    295            pos |= SDL_HAT_DOWN;
    296        }
    297        if (value > JOY_POVBACKWARD) {
    298            pos |= SDL_HAT_LEFT;
    299        }
    300    }
    301    return (pos);
    302}
    303
    304/* Function to update the state of a joystick - called as a device poll.
    305 * This function shouldn't update the joystick structure directly,
    306 * but instead should call SDL_PrivateJoystick*() to deliver events
    307 * and update joystick device state.
    308 */
    309void
    310SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
    311{
    312    MMRESULT result;
    313    int i;
    314    DWORD flags[MAX_AXES] = { JOY_RETURNX, JOY_RETURNY, JOY_RETURNZ,
    315        JOY_RETURNR, JOY_RETURNU, JOY_RETURNV
    316    };
    317    DWORD pos[MAX_AXES];
    318    struct _transaxis *transaxis;
    319    int value, change;
    320    JOYINFOEX joyinfo;
    321
    322    joyinfo.dwSize = sizeof(joyinfo);
    323    joyinfo.dwFlags = JOY_RETURNALL | JOY_RETURNPOVCTS;
    324    if (!joystick->hats) {
    325        joyinfo.dwFlags &= ~(JOY_RETURNPOV | JOY_RETURNPOVCTS);
    326    }
    327    result = joyGetPosEx(joystick->hwdata->id, &joyinfo);
    328    if (result != JOYERR_NOERROR) {
    329        SetMMerror("joyGetPosEx", result);
    330        return;
    331    }
    332
    333    /* joystick motion events */
    334    pos[0] = joyinfo.dwXpos;
    335    pos[1] = joyinfo.dwYpos;
    336    pos[2] = joyinfo.dwZpos;
    337    pos[3] = joyinfo.dwRpos;
    338    pos[4] = joyinfo.dwUpos;
    339    pos[5] = joyinfo.dwVpos;
    340
    341    transaxis = joystick->hwdata->transaxis;
    342    for (i = 0; i < joystick->naxes; i++) {
    343        if (joyinfo.dwFlags & flags[i]) {
    344            value =
    345                (int) (((float) pos[i] +
    346                        transaxis[i].offset) * transaxis[i].scale);
    347            change = (value - joystick->axes[i]);
    348            if ((change < -JOY_AXIS_THRESHOLD)
    349                || (change > JOY_AXIS_THRESHOLD)) {
    350                SDL_PrivateJoystickAxis(joystick, (Uint8) i, (Sint16) value);
    351            }
    352        }
    353    }
    354
    355    /* joystick button events */
    356    if (joyinfo.dwFlags & JOY_RETURNBUTTONS) {
    357        for (i = 0; i < joystick->nbuttons; ++i) {
    358            if (joyinfo.dwButtons & JOY_BUTTON_FLAG(i)) {
    359                if (!joystick->buttons[i]) {
    360                    SDL_PrivateJoystickButton(joystick, (Uint8) i,
    361                                              SDL_PRESSED);
    362                }
    363            } else {
    364                if (joystick->buttons[i]) {
    365                    SDL_PrivateJoystickButton(joystick, (Uint8) i,
    366                                              SDL_RELEASED);
    367                }
    368            }
    369        }
    370    }
    371
    372    /* joystick hat events */
    373    if (joyinfo.dwFlags & JOY_RETURNPOV) {
    374        Uint8 pos;
    375
    376        pos = TranslatePOV(joyinfo.dwPOV);
    377        if (pos != joystick->hats[0]) {
    378            SDL_PrivateJoystickHat(joystick, 0, pos);
    379        }
    380    }
    381}
    382
    383/* Function to close a joystick after use */
    384void
    385SDL_SYS_JoystickClose(SDL_Joystick * joystick)
    386{
    387    /* free system specific hardware data */
    388    SDL_free(joystick->hwdata);
    389    joystick->hwdata = NULL;
    390}
    391
    392/* Function to perform any system-specific joystick related cleanup */
    393void
    394SDL_SYS_JoystickQuit(void)
    395{
    396    int i;
    397    for (i = 0; i < MAX_JOYSTICKS; i++) {
    398        SDL_free(SYS_JoystickName[i]);
    399        SYS_JoystickName[i] = NULL;
    400    }
    401}
    402
    403SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID( int device_index )
    404{
    405    SDL_JoystickGUID guid;
    406    /* the GUID is just the first 16 chars of the name for now */
    407    const char *name = SDL_SYS_JoystickNameForDeviceIndex( device_index );
    408    SDL_zero( guid );
    409    SDL_memcpy( &guid, name, SDL_min( sizeof(guid), SDL_strlen( name ) ) );
    410    return guid;
    411}
    412
    413SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick)
    414{
    415    SDL_JoystickGUID guid;
    416    /* the GUID is just the first 16 chars of the name for now */
    417    const char *name = joystick->name;
    418    SDL_zero( guid );
    419    SDL_memcpy( &guid, name, SDL_min( sizeof(guid), SDL_strlen( name ) ) );
    420    return guid;
    421}
    422
    423
    424/* implementation functions */
    425void
    426SetMMerror(char *function, int code)
    427{
    428    static char *error;
    429    static char errbuf[1024];
    430
    431    errbuf[0] = 0;
    432    switch (code) {
    433    case MMSYSERR_NODRIVER:
    434        error = "Joystick driver not present";
    435        break;
    436
    437    case MMSYSERR_INVALPARAM:
    438    case JOYERR_PARMS:
    439        error = "Invalid parameter(s)";
    440        break;
    441
    442    case MMSYSERR_BADDEVICEID:
    443        error = "Bad device ID";
    444        break;
    445
    446    case JOYERR_UNPLUGGED:
    447        error = "Joystick not attached";
    448        break;
    449
    450    case JOYERR_NOCANDO:
    451        error = "Can't capture joystick input";
    452        break;
    453
    454    default:
    455        SDL_snprintf(errbuf, SDL_arraysize(errbuf),
    456                     "%s: Unknown Multimedia system error: 0x%x",
    457                     function, code);
    458        break;
    459    }
    460
    461    if (!errbuf[0]) {
    462        SDL_snprintf(errbuf, SDL_arraysize(errbuf), "%s: %s", function,
    463                     error);
    464    }
    465    SDL_SetError("%s", errbuf);
    466}
    467
    468#endif /* SDL_JOYSTICK_WINMM */
    469
    470/* vi: set ts=4 sw=4 expandtab: */