src/joystick/win32/SDL_mmjoystick.c

/* [<][>]
[^][v][top][bottom][index][help] */

FUNCTIONS

This source file includes following functions.
  1. JOY_BUTTON_FLAG
  2. SDL_SYS_JoystickInit
  3. SDL_SYS_JoystickName
  4. SDL_SYS_JoystickOpen
  5. TranslatePOV
  6. SDL_SYS_JoystickUpdate
  7. SDL_SYS_JoystickClose
  8. SDL_SYS_JoystickQuit
  9. SetMMerror

   1 /*
   2     SDL - Simple DirectMedia Layer
   3     Copyright (C) 1997, 1998, 1999, 2000, 2001  Sam Lantinga
   4 
   5     This library is free software; you can redistribute it and/or
   6     modify it under the terms of the GNU Library General Public
   7     License as published by the Free Software Foundation; either
   8     version 2 of the License, or (at your option) any later version.
   9 
  10     This library is distributed in the hope that it will be useful,
  11     but WITHOUT ANY WARRANTY; without even the implied warranty of
  12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13     Library General Public License for more details.
  14 
  15     You should have received a copy of the GNU Library General Public
  16     License along with this library; if not, write to the Free
  17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18 
  19     Sam Lantinga
  20     slouken@devolution.com
  21 */
  22 
  23 #ifdef SAVE_RCSID
  24 static char rcsid =
  25  "@(#) $Id: SDL_mmjoystick.c,v 1.1.2.11 2001/02/28 12:12:36 hercules Exp $";
  26 #endif
  27 
  28 /* Win32 MultiMedia Joystick driver, contributed by Andrei de A. Formiga */
  29 
  30 #include <stdlib.h>
  31 #include <stdio.h>              /* For the definition of NULL */
  32 
  33 #include "SDL_error.h"
  34 #include "SDL_joystick.h"
  35 #include "SDL_sysjoystick.h"
  36 #include "SDL_joystick_c.h"
  37 
  38 #include <windows.h>
  39 #include <mmsystem.h>
  40 
  41 #define MAX_JOYSTICKS   2       /* only 2 are supported in the multimedia API */
  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 #define JOY_AXIS_THRESHOLD      (((AXIS_MAX)-(AXIS_MIN))/100) /* 1% motion */
  47 #define JOY_BUTTON_FLAG(n)      (1<<n)
     /* [<][>][^][v][top][bottom][index][help] */
  48 
  49 
  50 /* array to hold joystick ID values */
  51 static UINT     SYS_JoystickID[MAX_JOYSTICKS];
  52 static JOYCAPS  SYS_Joystick[MAX_JOYSTICKS];
  53 
  54 /* The private structure used to keep track of a joystick */
  55 struct joystick_hwdata
  56 {
  57         /* joystick ID */
  58         UINT    id;
  59 
  60         /* values used to translate device-specific coordinates into
  61            SDL-standard ranges */
  62         struct _transaxis {
  63                 int offset;
  64                 float scale;
  65         } transaxis[6];
  66 };
  67 
  68 /* Convert a win32 Multimedia API return code to a text message */
  69 static void SetMMerror(char *function, int code);
  70 
  71 
  72 /* Function to scan the system for joysticks.
  73  * This function should set SDL_numjoysticks to the number of available
  74  * joysticks.  Joystick 0 should be the system default joystick.
  75  * It should return 0, or -1 on an unrecoverable fatal error.
  76  */
  77 int SDL_SYS_JoystickInit(void)
     /* [<][>][^][v][top][bottom][index][help] */
  78 {
  79         int     i;
  80         int maxdevs;
  81         int numdevs;
  82         JOYINFOEX joyinfo;
  83         JOYCAPS joycaps;
  84         MMRESULT result;
  85 
  86         numdevs = 0;
  87         maxdevs = joyGetNumDevs();
  88         if ( maxdevs > MAX_JOYSTICKS ) {
  89                 maxdevs = MAX_JOYSTICKS;
  90         }
  91 
  92         SYS_JoystickID[0] = JOYSTICKID1;
  93         SYS_JoystickID[1] = JOYSTICKID2;
  94 
  95         for ( i = 0; (i < maxdevs); ++i ) {
  96                 result = joyGetPosEx(SYS_JoystickID[i], &joyinfo);
  97                 if ( result == JOYERR_NOERROR ) {
  98                         result = joyGetDevCaps(SYS_JoystickID[i], &joycaps, sizeof(joycaps));
  99                         if ( result == JOYERR_NOERROR ) {
 100                                 SYS_JoystickID[numdevs] = SYS_JoystickID[i];
 101                                 SYS_Joystick[numdevs] = joycaps;
 102                                 numdevs++;
 103                         }
 104                 }
 105         }
 106         return(numdevs);
 107 }
 108 
 109 /* Function to get the device-dependent name of a joystick */
 110 const char *SDL_SYS_JoystickName(int index)
     /* [<][>][^][v][top][bottom][index][help] */
 111 {
 112         /***-> test for invalid index ? */
 113         return(SYS_Joystick[index].szPname);
 114 }
 115 
 116 /* Function to open a joystick for use.
 117    The joystick to open is specified by the index field of the joystick.
 118    This should fill the nbuttons and naxes fields of the joystick structure.
 119    It returns 0, or -1 if there is an error.
 120  */
 121 int SDL_SYS_JoystickOpen(SDL_Joystick *joystick)
     /* [<][>][^][v][top][bottom][index][help] */
 122 {
 123         int index, i;
 124         int caps_flags[MAX_AXES-2] =
 125                 { JOYCAPS_HASZ, JOYCAPS_HASR, JOYCAPS_HASU, JOYCAPS_HASV };
 126         int axis_min[MAX_AXES], axis_max[MAX_AXES];
 127 
 128 
 129         /* shortcut */
 130         index = joystick->index;
 131         axis_min[0] = SYS_Joystick[index].wXmin;
 132         axis_max[0] = SYS_Joystick[index].wXmax;
 133         axis_min[1] = SYS_Joystick[index].wYmin;
 134         axis_max[1] = SYS_Joystick[index].wYmax;
 135         axis_min[2] = SYS_Joystick[index].wZmin;
 136         axis_max[2] = SYS_Joystick[index].wZmax;
 137         axis_min[3] = SYS_Joystick[index].wRmin;
 138         axis_max[3] = SYS_Joystick[index].wRmax;
 139         axis_min[4] = SYS_Joystick[index].wUmin;
 140         axis_max[4] = SYS_Joystick[index].wUmax;
 141         axis_min[5] = SYS_Joystick[index].wVmin;
 142         axis_max[5] = SYS_Joystick[index].wVmax;
 143 
 144         /* allocate memory for system specific hardware data */
 145         joystick->hwdata = (struct joystick_hwdata *) malloc(sizeof(*joystick->hwdata));
 146         if (joystick->hwdata == NULL)
 147         {
 148                 SDL_OutOfMemory();
 149                 return(-1);
 150         }
 151         memset(joystick->hwdata, 0, sizeof(*joystick->hwdata));
 152 
 153         /* set hardware data */
 154         joystick->hwdata->id = SYS_JoystickID[index];
 155         for ( i = 0; i < MAX_AXES; ++i ) {
 156                 if ( (i<2) || (SYS_Joystick[index].wCaps & caps_flags[i-2]) ) {
 157                         joystick->hwdata->transaxis[i].offset =
 158                                 AXIS_MIN - axis_min[i];
 159                         joystick->hwdata->transaxis[i].scale =
 160                                 (float)(AXIS_MAX - AXIS_MIN) / (axis_max[i] - axis_min[i]);
 161                 } else {
 162                         joystick->hwdata->transaxis[i].offset = 0;
 163                         joystick->hwdata->transaxis[i].scale = 1.0; /* Just in case */
 164                 }
 165         }
 166 
 167         /* fill nbuttons, naxes, and nhats fields */
 168         joystick->nbuttons = SYS_Joystick[index].wNumButtons;
 169         joystick->naxes = SYS_Joystick[index].wNumAxes;
 170         if ( SYS_Joystick[index].wCaps & JOYCAPS_HASPOV ) {
 171                 joystick->nhats = 1;
 172         } else {
 173                 joystick->nhats = 0;
 174         }
 175         return(0);
 176 }
 177 
 178 static Uint8 TranslatePOV(DWORD value)
     /* [<][>][^][v][top][bottom][index][help] */
 179 {
 180         Uint8 pos;
 181 
 182         pos = SDL_HAT_CENTERED;
 183         if ( value != JOY_POVCENTERED ) {
 184                 if ( (value > JOY_POVLEFT) || (value < JOY_POVRIGHT) ) {
 185                         pos |= SDL_HAT_UP;
 186                 }
 187                 if ( (value > JOY_POVFORWARD) && (value < JOY_POVBACKWARD) ) {
 188                         pos |= SDL_HAT_RIGHT;
 189                 }
 190                 if ( (value > JOY_POVRIGHT) && (value < JOY_POVLEFT) ) {
 191                         pos |= SDL_HAT_DOWN;
 192                 }
 193                 if ( value > JOY_POVBACKWARD ) {
 194                         pos |= SDL_HAT_LEFT;
 195                 }
 196         }
 197         return(pos);
 198 }
 199 
 200 /* Function to update the state of a joystick - called as a device poll.
 201  * This function shouldn't update the joystick structure directly,
 202  * but instead should call SDL_PrivateJoystick*() to deliver events
 203  * and update joystick device state.
 204  */
 205 void SDL_SYS_JoystickUpdate(SDL_Joystick *joystick)
     /* [<][>][^][v][top][bottom][index][help] */
 206 {
 207         MMRESULT result;
 208         int i;
 209         DWORD flags[MAX_AXES] = { JOY_RETURNX, JOY_RETURNY, JOY_RETURNZ, 
 210                                   JOY_RETURNR, JOY_RETURNU, JOY_RETURNV };
 211         DWORD pos[MAX_AXES];
 212         struct _transaxis *transaxis;
 213         int value, change;
 214         JOYINFOEX joyinfo;
 215 
 216         joyinfo.dwSize = sizeof(joyinfo);
 217         joyinfo.dwFlags = JOY_RETURNALL|JOY_RETURNPOVCTS;
 218         if ( ! joystick->hats ) {
 219                 joyinfo.dwFlags &= ~(JOY_RETURNPOV|JOY_RETURNPOVCTS);
 220         }
 221         result = joyGetPosEx(joystick->hwdata->id, &joyinfo);
 222         if ( result != JOYERR_NOERROR ) {
 223                 SetMMerror("joyGetPosEx", result);
 224                 return;
 225         }
 226 
 227         /* joystick motion events */
 228         pos[0] = joyinfo.dwXpos;
 229         pos[1] = joyinfo.dwYpos;
 230         pos[2] = joyinfo.dwZpos;
 231         pos[3] = joyinfo.dwRpos;
 232         pos[4] = joyinfo.dwUpos;
 233         pos[5] = joyinfo.dwVpos;
 234 
 235         transaxis = joystick->hwdata->transaxis;
 236         for (i = 0; i < joystick->naxes; i++) {
 237                 if (joyinfo.dwFlags & flags[i]) {
 238                         value = (int)((float)(pos[i] + transaxis[i].offset) * transaxis[i].scale);
 239                         change = (value - joystick->axes[i]);
 240                         if ( (change < -JOY_AXIS_THRESHOLD) || (change > JOY_AXIS_THRESHOLD) ) {
 241                                 SDL_PrivateJoystickAxis(joystick, (Uint8)i, (Sint16)value);
 242                         }
 243                 }
 244         }
 245 
 246         /* joystick button events */
 247         if ( joyinfo.dwFlags & JOY_RETURNBUTTONS ) {
 248                 for ( i = 0; i < joystick->nbuttons; ++i ) {
 249                         if ( joyinfo.dwButtons & JOY_BUTTON_FLAG(i) ) {
 250                                 if ( ! joystick->buttons[i] ) {
 251                                         SDL_PrivateJoystickButton(joystick, (Uint8)i, SDL_PRESSED);
 252                                 }
 253                         } else {
 254                                 if ( joystick->buttons[i] ) {
 255                                         SDL_PrivateJoystickButton(joystick, (Uint8)i, SDL_RELEASED);
 256                                 }
 257                         }
 258                 }
 259         }
 260 
 261         /* joystick hat events */
 262         if ( joyinfo.dwFlags & JOY_RETURNPOV ) {
 263                 Uint8 pos;
 264 
 265                 pos = TranslatePOV(joyinfo.dwPOV);
 266                 if ( pos != joystick->hats[0] ) {
 267                         SDL_PrivateJoystickHat(joystick, 0, pos);
 268                 }
 269         }
 270 }
 271 
 272 /* Function to close a joystick after use */
 273 void SDL_SYS_JoystickClose(SDL_Joystick *joystick)
     /* [<][>][^][v][top][bottom][index][help] */
 274 {
 275         if (joystick->hwdata != NULL) {
 276                 /* free system specific hardware data */
 277                 free(joystick->hwdata);
 278         }
 279 }
 280 
 281 /* Function to perform any system-specific joystick related cleanup */
 282 void SDL_SYS_JoystickQuit(void)
     /* [<][>][^][v][top][bottom][index][help] */
 283 {
 284         return;
 285 }
 286 
 287 
 288 /* implementation functions */
 289 void SetMMerror(char *function, int code)
     /* [<][>][^][v][top][bottom][index][help] */
 290 {
 291         static char *error;
 292         static char  errbuf[BUFSIZ];
 293 
 294         errbuf[0] = 0;
 295         switch (code) 
 296         {
 297                 case MMSYSERR_NODRIVER:
 298                         error = "Joystick driver not present";
 299                 break;
 300 
 301                 case MMSYSERR_INVALPARAM:
 302                 case JOYERR_PARMS:
 303                         error = "Invalid parameter(s)";
 304                 break;
 305                 
 306                 case MMSYSERR_BADDEVICEID:
 307                         error = "Bad device ID";
 308                 break;
 309 
 310                 case JOYERR_UNPLUGGED:
 311                         error = "Joystick not attached";
 312                 break;
 313 
 314                 case JOYERR_NOCANDO:
 315                         error = "Can't capture joystick input";
 316                 break;
 317 
 318                 default:
 319                         sprintf(errbuf, "%s: Unknown Multimedia system error: 0x%x",
 320                                                                 function, code);
 321                 break;
 322         }
 323 
 324         if ( ! errbuf[0] ) {
 325                 sprintf(errbuf, "%s: %s", function, error);
 326         }
 327         SDL_SetError("%s", errbuf);
 328 }

/* [<][>][^][v][top][bottom][index][help] */