diff src/joystick/windows/SDL_mmjoystick.c @ 5062:e8916fe9cfc8

Fixed bug #925 Changed "win32" to "windows"
author Sam Lantinga <slouken@libsdl.org>
date Thu, 20 Jan 2011 18:04:05 -0800
parents src/joystick/win32/SDL_mmjoystick.c@f7b03b6838cb
children 327f181542f1
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/joystick/windows/SDL_mmjoystick.c	Thu Jan 20 18:04:05 2011 -0800
@@ -0,0 +1,428 @@
+/*
+    SDL - Simple DirectMedia Layer
+    Copyright (C) 1997-2010 Sam Lantinga
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+    Sam Lantinga
+    slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+#ifdef SDL_JOYSTICK_WINMM
+
+/* Win32 MultiMedia Joystick driver, contributed by Andrei de A. Formiga */
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <mmsystem.h>
+#include <regstr.h>
+
+#include "SDL_events.h"
+#include "SDL_joystick.h"
+#include "../SDL_sysjoystick.h"
+#include "../SDL_joystick_c.h"
+
+#define MAX_JOYSTICKS	16
+#define MAX_AXES	6       /* each joystick can have up to 6 axes */
+#define MAX_BUTTONS	32      /* and 32 buttons                      */
+#define AXIS_MIN	-32768  /* minimum value for axis coordinate */
+#define AXIS_MAX	32767   /* maximum value for axis coordinate */
+/* limit axis to 256 possible positions to filter out noise */
+#define JOY_AXIS_THRESHOLD      (((AXIS_MAX)-(AXIS_MIN))/256)
+#define JOY_BUTTON_FLAG(n)	(1<<n)
+
+
+/* array to hold joystick ID values */
+static UINT SYS_JoystickID[MAX_JOYSTICKS];
+static JOYCAPS SYS_Joystick[MAX_JOYSTICKS];
+static char *SYS_JoystickName[MAX_JOYSTICKS];
+
+/* The private structure used to keep track of a joystick */
+struct joystick_hwdata
+{
+    /* joystick ID */
+    UINT id;
+
+    /* values used to translate device-specific coordinates into
+       SDL-standard ranges */
+    struct _transaxis
+    {
+        int offset;
+        float scale;
+    } transaxis[6];
+};
+
+/* Convert a Windows Multimedia API return code to a text message */
+static void SetMMerror(char *function, int code);
+
+
+static char *
+GetJoystickName(int index, const char *szRegKey)
+{
+    /* added 7/24/2004 by Eckhard Stolberg */
+    /*
+       see if there is a joystick for the current
+       index (1-16) listed in the registry
+     */
+    char *name = NULL;
+    HKEY hTopKey;
+    HKEY hKey;
+    DWORD regsize;
+    LONG regresult;
+    char regkey[256];
+    char regvalue[256];
+    char regname[256];
+
+    SDL_snprintf(regkey, SDL_arraysize(regkey), "%s\\%s\\%s",
+                 REGSTR_PATH_JOYCONFIG, szRegKey, REGSTR_KEY_JOYCURR);
+    hTopKey = HKEY_LOCAL_MACHINE;
+    regresult = RegOpenKeyExA(hTopKey, regkey, 0, KEY_READ, &hKey);
+    if (regresult != ERROR_SUCCESS) {
+        hTopKey = HKEY_CURRENT_USER;
+        regresult = RegOpenKeyExA(hTopKey, regkey, 0, KEY_READ, &hKey);
+    }
+    if (regresult != ERROR_SUCCESS) {
+        return NULL;
+    }
+
+    /* find the registry key name for the joystick's properties */
+    regsize = sizeof(regname);
+    SDL_snprintf(regvalue, SDL_arraysize(regvalue), "Joystick%d%s", index + 1,
+                 REGSTR_VAL_JOYOEMNAME);
+    regresult =
+        RegQueryValueExA(hKey, regvalue, 0, 0, (LPBYTE) regname, &regsize);
+    RegCloseKey(hKey);
+
+    if (regresult != ERROR_SUCCESS) {
+        return NULL;
+    }
+
+    /* open that registry key */
+    SDL_snprintf(regkey, SDL_arraysize(regkey), "%s\\%s", REGSTR_PATH_JOYOEM,
+                 regname);
+    regresult = RegOpenKeyExA(hTopKey, regkey, 0, KEY_READ, &hKey);
+    if (regresult != ERROR_SUCCESS) {
+        return NULL;
+    }
+
+    /* find the size for the OEM name text */
+    regsize = sizeof(regvalue);
+    regresult =
+        RegQueryValueExA(hKey, REGSTR_VAL_JOYOEMNAME, 0, 0, NULL, &regsize);
+    if (regresult == ERROR_SUCCESS) {
+        /* allocate enough memory for the OEM name text ... */
+        name = (char *) SDL_malloc(regsize);
+        if (name) {
+            /* ... and read it from the registry */
+            regresult = RegQueryValueExA(hKey,
+                                         REGSTR_VAL_JOYOEMNAME, 0, 0,
+                                         (LPBYTE) name, &regsize);
+        }
+    }
+    RegCloseKey(hKey);
+
+    return (name);
+}
+
+/* Function to scan the system for joysticks.
+ * This function should set SDL_numjoysticks to the number of available
+ * joysticks.  Joystick 0 should be the system default joystick.
+ * It should return 0, or -1 on an unrecoverable fatal error.
+ */
+int
+SDL_SYS_JoystickInit(void)
+{
+    int i;
+    int maxdevs;
+    int numdevs;
+    JOYINFOEX joyinfo;
+    JOYCAPS joycaps;
+    MMRESULT result;
+
+    /* Reset the joystick ID & name mapping tables */
+    for (i = 0; i < MAX_JOYSTICKS; ++i) {
+        SYS_JoystickID[i] = 0;
+        SYS_JoystickName[i] = NULL;
+    }
+
+    /* Loop over all potential joystick devices */
+    numdevs = 0;
+    maxdevs = joyGetNumDevs();
+    for (i = JOYSTICKID1; i < maxdevs && numdevs < MAX_JOYSTICKS; ++i) {
+
+        joyinfo.dwSize = sizeof(joyinfo);
+        joyinfo.dwFlags = JOY_RETURNALL;
+        result = joyGetPosEx(i, &joyinfo);
+        if (result == JOYERR_NOERROR) {
+            result = joyGetDevCaps(i, &joycaps, sizeof(joycaps));
+            if (result == JOYERR_NOERROR) {
+                SYS_JoystickID[numdevs] = i;
+                SYS_Joystick[numdevs] = joycaps;
+                SYS_JoystickName[numdevs] =
+                    GetJoystickName(i, joycaps.szRegKey);
+                numdevs++;
+            }
+        }
+    }
+    return (numdevs);
+}
+
+/* Function to get the device-dependent name of a joystick */
+const char *
+SDL_SYS_JoystickName(int index)
+{
+    if (SYS_JoystickName[index] != NULL) {
+        return (SYS_JoystickName[index]);
+    } else {
+        return (SYS_Joystick[index].szPname);
+    }
+}
+
+/* Function to open a joystick for use.
+   The joystick to open is specified by the index field of the joystick.
+   This should fill the nbuttons and naxes fields of the joystick structure.
+   It returns 0, or -1 if there is an error.
+ */
+int
+SDL_SYS_JoystickOpen(SDL_Joystick * joystick)
+{
+    int index, i;
+    int caps_flags[MAX_AXES - 2] =
+        { JOYCAPS_HASZ, JOYCAPS_HASR, JOYCAPS_HASU, JOYCAPS_HASV };
+    int axis_min[MAX_AXES], axis_max[MAX_AXES];
+
+
+    /* shortcut */
+    index = joystick->index;
+    axis_min[0] = SYS_Joystick[index].wXmin;
+    axis_max[0] = SYS_Joystick[index].wXmax;
+    axis_min[1] = SYS_Joystick[index].wYmin;
+    axis_max[1] = SYS_Joystick[index].wYmax;
+    axis_min[2] = SYS_Joystick[index].wZmin;
+    axis_max[2] = SYS_Joystick[index].wZmax;
+    axis_min[3] = SYS_Joystick[index].wRmin;
+    axis_max[3] = SYS_Joystick[index].wRmax;
+    axis_min[4] = SYS_Joystick[index].wUmin;
+    axis_max[4] = SYS_Joystick[index].wUmax;
+    axis_min[5] = SYS_Joystick[index].wVmin;
+    axis_max[5] = SYS_Joystick[index].wVmax;
+
+    /* allocate memory for system specific hardware data */
+    joystick->hwdata =
+        (struct joystick_hwdata *) SDL_malloc(sizeof(*joystick->hwdata));
+    if (joystick->hwdata == NULL) {
+        SDL_OutOfMemory();
+        return (-1);
+    }
+    SDL_memset(joystick->hwdata, 0, sizeof(*joystick->hwdata));
+
+    /* set hardware data */
+    joystick->hwdata->id = SYS_JoystickID[index];
+    for (i = 0; i < MAX_AXES; ++i) {
+        if ((i < 2) || (SYS_Joystick[index].wCaps & caps_flags[i - 2])) {
+            joystick->hwdata->transaxis[i].offset = AXIS_MIN - axis_min[i];
+            joystick->hwdata->transaxis[i].scale =
+                (float) (AXIS_MAX - AXIS_MIN) / (axis_max[i] - axis_min[i]);
+        } else {
+            joystick->hwdata->transaxis[i].offset = 0;
+            joystick->hwdata->transaxis[i].scale = 1.0; /* Just in case */
+        }
+    }
+
+    /* fill nbuttons, naxes, and nhats fields */
+    joystick->nbuttons = SYS_Joystick[index].wNumButtons;
+    joystick->naxes = SYS_Joystick[index].wNumAxes;
+    if (SYS_Joystick[index].wCaps & JOYCAPS_HASPOV) {
+        joystick->nhats = 1;
+    } else {
+        joystick->nhats = 0;
+    }
+    return (0);
+}
+
+static Uint8
+TranslatePOV(DWORD value)
+{
+    Uint8 pos;
+
+    pos = SDL_HAT_CENTERED;
+    if (value != JOY_POVCENTERED) {
+        if ((value > JOY_POVLEFT) || (value < JOY_POVRIGHT)) {
+            pos |= SDL_HAT_UP;
+        }
+        if ((value > JOY_POVFORWARD) && (value < JOY_POVBACKWARD)) {
+            pos |= SDL_HAT_RIGHT;
+        }
+        if ((value > JOY_POVRIGHT) && (value < JOY_POVLEFT)) {
+            pos |= SDL_HAT_DOWN;
+        }
+        if (value > JOY_POVBACKWARD) {
+            pos |= SDL_HAT_LEFT;
+        }
+    }
+    return (pos);
+}
+
+/* Function to update the state of a joystick - called as a device poll.
+ * This function shouldn't update the joystick structure directly,
+ * but instead should call SDL_PrivateJoystick*() to deliver events
+ * and update joystick device state.
+ */
+void
+SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
+{
+    MMRESULT result;
+    int i;
+    DWORD flags[MAX_AXES] = { JOY_RETURNX, JOY_RETURNY, JOY_RETURNZ,
+        JOY_RETURNR, JOY_RETURNU, JOY_RETURNV
+    };
+    DWORD pos[MAX_AXES];
+    struct _transaxis *transaxis;
+    int value, change;
+    JOYINFOEX joyinfo;
+
+    joyinfo.dwSize = sizeof(joyinfo);
+    joyinfo.dwFlags = JOY_RETURNALL | JOY_RETURNPOVCTS;
+    if (!joystick->hats) {
+        joyinfo.dwFlags &= ~(JOY_RETURNPOV | JOY_RETURNPOVCTS);
+    }
+    result = joyGetPosEx(joystick->hwdata->id, &joyinfo);
+    if (result != JOYERR_NOERROR) {
+        SetMMerror("joyGetPosEx", result);
+        return;
+    }
+
+    /* joystick motion events */
+    pos[0] = joyinfo.dwXpos;
+    pos[1] = joyinfo.dwYpos;
+    pos[2] = joyinfo.dwZpos;
+    pos[3] = joyinfo.dwRpos;
+    pos[4] = joyinfo.dwUpos;
+    pos[5] = joyinfo.dwVpos;
+
+    transaxis = joystick->hwdata->transaxis;
+    for (i = 0; i < joystick->naxes; i++) {
+        if (joyinfo.dwFlags & flags[i]) {
+            value =
+                (int) (((float) pos[i] +
+                        transaxis[i].offset) * transaxis[i].scale);
+            change = (value - joystick->axes[i]);
+            if ((change < -JOY_AXIS_THRESHOLD)
+                || (change > JOY_AXIS_THRESHOLD)) {
+                SDL_PrivateJoystickAxis(joystick, (Uint8) i, (Sint16) value);
+            }
+        }
+    }
+
+    /* joystick button events */
+    if (joyinfo.dwFlags & JOY_RETURNBUTTONS) {
+        for (i = 0; i < joystick->nbuttons; ++i) {
+            if (joyinfo.dwButtons & JOY_BUTTON_FLAG(i)) {
+                if (!joystick->buttons[i]) {
+                    SDL_PrivateJoystickButton(joystick, (Uint8) i,
+                                              SDL_PRESSED);
+                }
+            } else {
+                if (joystick->buttons[i]) {
+                    SDL_PrivateJoystickButton(joystick, (Uint8) i,
+                                              SDL_RELEASED);
+                }
+            }
+        }
+    }
+
+    /* joystick hat events */
+    if (joyinfo.dwFlags & JOY_RETURNPOV) {
+        Uint8 pos;
+
+        pos = TranslatePOV(joyinfo.dwPOV);
+        if (pos != joystick->hats[0]) {
+            SDL_PrivateJoystickHat(joystick, 0, pos);
+        }
+    }
+}
+
+/* Function to close a joystick after use */
+void
+SDL_SYS_JoystickClose(SDL_Joystick * joystick)
+{
+    if (joystick->hwdata != NULL) {
+        /* free system specific hardware data */
+        SDL_free(joystick->hwdata);
+        joystick->hwdata = NULL;
+    }
+}
+
+/* Function to perform any system-specific joystick related cleanup */
+void
+SDL_SYS_JoystickQuit(void)
+{
+    int i;
+    for (i = 0; i < MAX_JOYSTICKS; i++) {
+        if (SYS_JoystickName[i] != NULL) {
+            SDL_free(SYS_JoystickName[i]);
+            SYS_JoystickName[i] = NULL;
+        }
+    }
+}
+
+
+/* implementation functions */
+void
+SetMMerror(char *function, int code)
+{
+    static char *error;
+    static char errbuf[1024];
+
+    errbuf[0] = 0;
+    switch (code) {
+    case MMSYSERR_NODRIVER:
+        error = "Joystick driver not present";
+        break;
+
+    case MMSYSERR_INVALPARAM:
+    case JOYERR_PARMS:
+        error = "Invalid parameter(s)";
+        break;
+
+    case MMSYSERR_BADDEVICEID:
+        error = "Bad device ID";
+        break;
+
+    case JOYERR_UNPLUGGED:
+        error = "Joystick not attached";
+        break;
+
+    case JOYERR_NOCANDO:
+        error = "Can't capture joystick input";
+        break;
+
+    default:
+        SDL_snprintf(errbuf, SDL_arraysize(errbuf),
+                     "%s: Unknown Multimedia system error: 0x%x",
+                     function, code);
+        break;
+    }
+
+    if (!errbuf[0]) {
+        SDL_snprintf(errbuf, SDL_arraysize(errbuf), "%s: %s", function,
+                     error);
+    }
+    SDL_SetError("%s", errbuf);
+}
+
+#endif /* SDL_JOYSTICK_WINMM */
+/* vi: set ts=4 sw=4 expandtab: */