1 /* 2 SDL - Simple DirectMedia Layer 3 Copyright (C) 1997-2012 Sam Lantinga 4 5 This library is free software; you can redistribute it and/or 6 modify it under the terms of the GNU Lesser General Public 7 License as published by the Free Software Foundation; either 8 version 2.1 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 Lesser General Public License for more details. 14 15 You should have received a copy of the GNU Lesser General Public 16 License along with this library; if not, write to the Free Software 17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 19 Sam Lantinga 20 slouken (at) libsdl.org 21 */ 22 #include "SDL_config.h" 23 24 #ifdef SDL_JOYSTICK_WINMM 25 26 /* Win32 MultiMedia Joystick driver, contributed by Andrei de A. Formiga */ 27 28 #define WIN32_LEAN_AND_MEAN 29 #include <windows.h> 30 #include <mmsystem.h> 31 #include <regstr.h> 32 33 #include "SDL_events.h" 34 #include "SDL_joystick.h" 35 #include "../SDL_sysjoystick.h" 36 #include "../SDL_joystick_c.h" 37 38 #define MAX_JOYSTICKS 16 39 #define MAX_AXES 6 /* each joystick can have up to 6 axes */ 40 #define MAX_BUTTONS 32 /* and 32 buttons */ 41 #define AXIS_MIN -32768 /* minimum value for axis coordinate */ 42 #define AXIS_MAX 32767 /* maximum value for axis coordinate */ 43 /* limit axis to 256 possible positions to filter out noise */ 44 #define JOY_AXIS_THRESHOLD (((AXIS_MAX)-(AXIS_MIN))/256) 45 #define JOY_BUTTON_FLAG(n) (1<<n) 46 47 48 /* array to hold joystick ID values */ 49 static UINT SYS_JoystickID[MAX_JOYSTICKS]; 50 static JOYCAPS SYS_Joystick[MAX_JOYSTICKS]; 51 static char *SYS_JoystickName[MAX_JOYSTICKS]; 52 53 /* The private structure used to keep track of a joystick */ 54 struct joystick_hwdata 55 { 56 /* joystick ID */ 57 UINT id; 58 59 /* values used to translate device-specific coordinates into 60 SDL-standard ranges */ 61 struct _transaxis { 62 int offset; 63 float scale; 64 } transaxis[6]; 65 }; 66 67 /* Convert a win32 Multimedia API return code to a text message */ 68 static void SetMMerror(char *function, int code); 69 70 71 static char *GetJoystickName(int index, const char *szRegKey) 72 { 73 /* added 7/24/2004 by Eckhard Stolberg */ 74 /* 75 see if there is a joystick for the current 76 index (1-16) listed in the registry 77 */ 78 char *name = NULL; 79 HKEY hTopKey; 80 HKEY hKey; 81 DWORD regsize; 82 LONG regresult; 83 char regkey[256]; 84 char regvalue[256]; 85 char regname[256]; 86 87 SDL_snprintf(regkey, SDL_arraysize(regkey), "%s\\%s\\%s", 88 REGSTR_PATH_JOYCONFIG, szRegKey, REGSTR_KEY_JOYCURR); 89 hTopKey = HKEY_LOCAL_MACHINE; 90 regresult = RegOpenKeyExA(hTopKey, regkey, 0, KEY_READ, &hKey); 91 if (regresult != ERROR_SUCCESS) { 92 hTopKey = HKEY_CURRENT_USER; 93 regresult = RegOpenKeyExA(hTopKey, regkey, 0, KEY_READ, &hKey); 94 } 95 if (regresult != ERROR_SUCCESS) { 96 return NULL; 97 } 98 99 /* find the registry key name for the joystick's properties */ 100 regsize = sizeof(regname); 101 SDL_snprintf(regvalue, SDL_arraysize(regvalue), "Joystick%d%s", index+1, REGSTR_VAL_JOYOEMNAME); 102 regresult = RegQueryValueExA(hKey, regvalue, 0, 0, (LPBYTE)regname, ®size); 103 RegCloseKey(hKey); 104 105 if (regresult != ERROR_SUCCESS) { 106 return NULL; 107 } 108 109 /* open that registry key */ 110 SDL_snprintf(regkey, SDL_arraysize(regkey), "%s\\%s", REGSTR_PATH_JOYOEM, regname); 111 regresult = RegOpenKeyExA(hTopKey, regkey, 0, KEY_READ, &hKey); 112 if (regresult != ERROR_SUCCESS) { 113 return NULL; 114 } 115 116 /* find the size for the OEM name text */ 117 regsize = sizeof(regvalue); 118 regresult = RegQueryValueExA(hKey, REGSTR_VAL_JOYOEMNAME, 0, 0, NULL, ®size); 119 if (regresult == ERROR_SUCCESS) { 120 /* allocate enough memory for the OEM name text ... */ 121 name = (char *) SDL_malloc(regsize); 122 if ( name ) { 123 /* ... and read it from the registry */ 124 regresult = RegQueryValueExA(hKey, 125 REGSTR_VAL_JOYOEMNAME, 0, 0, 126 (LPBYTE) name, ®size); 127 } 128 } 129 RegCloseKey(hKey); 130 131 return(name); 132 } 133 134 /* Function to scan the system for joysticks. 135 * This function should set SDL_numjoysticks to the number of available 136 * joysticks. Joystick 0 should be the system default joystick. 137 * It should return 0, or -1 on an unrecoverable fatal error. 138 */ 139 int SDL_SYS_JoystickInit(void) 140 { 141 int i; 142 int maxdevs; 143 int numdevs; 144 JOYINFOEX joyinfo; 145 JOYCAPS joycaps; 146 MMRESULT result; 147 148 /* Reset the joystick ID & name mapping tables */ 149 for ( i = 0; i < MAX_JOYSTICKS; ++i ) { 150 SYS_JoystickID[i] = 0; 151 SYS_JoystickName[i] = NULL; 152 } 153 154 /* Loop over all potential joystick devices */ 155 numdevs = 0; 156 maxdevs = joyGetNumDevs(); 157 for ( i = JOYSTICKID1; i < maxdevs && numdevs < MAX_JOYSTICKS; ++i ) { 158 159 joyinfo.dwSize = sizeof(joyinfo); 160 joyinfo.dwFlags = JOY_RETURNALL; 161 result = joyGetPosEx(i, &joyinfo); 162 if ( result == JOYERR_NOERROR ) { 163 result = joyGetDevCaps(i, &joycaps, sizeof(joycaps)); 164 if ( result == JOYERR_NOERROR ) { 165 SYS_JoystickID[numdevs] = i; 166 SYS_Joystick[numdevs] = joycaps; 167 SYS_JoystickName[numdevs] = GetJoystickName(i, joycaps.szRegKey); 168 numdevs++; 169 } 170 } 171 } 172 return(numdevs); 173 } 174 175 /* Function to get the device-dependent name of a joystick */ 176 const char *SDL_SYS_JoystickName(int index) 177 { 178 if ( SYS_JoystickName[index] != NULL ) { 179 return(SYS_JoystickName[index]); 180 } else { 181 return(SYS_Joystick[index].szPname); 182 } 183 } 184 185 /* Function to open a joystick for use. 186 The joystick to open is specified by the index field of the joystick. 187 This should fill the nbuttons and naxes fields of the joystick structure. 188 It returns 0, or -1 if there is an error. 189 */ 190 int SDL_SYS_JoystickOpen(SDL_Joystick *joystick) 191 { 192 int index, i; 193 int caps_flags[MAX_AXES-2] = 194 { JOYCAPS_HASZ, JOYCAPS_HASR, JOYCAPS_HASU, JOYCAPS_HASV }; 195 int axis_min[MAX_AXES], axis_max[MAX_AXES]; 196 197 198 /* shortcut */ 199 index = joystick->index; 200 axis_min[0] = SYS_Joystick[index].wXmin; 201 axis_max[0] = SYS_Joystick[index].wXmax; 202 axis_min[1] = SYS_Joystick[index].wYmin; 203 axis_max[1] = SYS_Joystick[index].wYmax; 204 axis_min[2] = SYS_Joystick[index].wZmin; 205 axis_max[2] = SYS_Joystick[index].wZmax; 206 axis_min[3] = SYS_Joystick[index].wRmin; 207 axis_max[3] = SYS_Joystick[index].wRmax; 208 axis_min[4] = SYS_Joystick[index].wUmin; 209 axis_max[4] = SYS_Joystick[index].wUmax; 210 axis_min[5] = SYS_Joystick[index].wVmin; 211 axis_max[5] = SYS_Joystick[index].wVmax; 212 213 /* allocate memory for system specific hardware data */ 214 joystick->hwdata = (struct joystick_hwdata *) SDL_malloc(sizeof(*joystick->hwdata)); 215 if (joystick->hwdata == NULL) 216 { 217 SDL_OutOfMemory(); 218 return(-1); 219 } 220 SDL_memset(joystick->hwdata, 0, sizeof(*joystick->hwdata)); 221 222 /* set hardware data */ 223 joystick->hwdata->id = SYS_JoystickID[index]; 224 for ( i = 0; i < MAX_AXES; ++i ) { 225 if ( (i<2) || (SYS_Joystick[index].wCaps & caps_flags[i-2]) ) { 226 joystick->hwdata->transaxis[i].offset = 227 AXIS_MIN - axis_min[i]; 228 joystick->hwdata->transaxis[i].scale = 229 (float)(AXIS_MAX - AXIS_MIN) / (axis_max[i] - axis_min[i]); 230 } else { 231 joystick->hwdata->transaxis[i].offset = 0; 232 joystick->hwdata->transaxis[i].scale = 1.0; /* Just in case */ 233 } 234 } 235 236 /* fill nbuttons, naxes, and nhats fields */ 237 joystick->nbuttons = SYS_Joystick[index].wNumButtons; 238 joystick->naxes = SYS_Joystick[index].wNumAxes; 239 if ( SYS_Joystick[index].wCaps & JOYCAPS_HASPOV ) { 240 joystick->nhats = 1; 241 } else { 242 joystick->nhats = 0; 243 } 244 return(0); 245 } 246 247 static Uint8 TranslatePOV(DWORD value) 248 { 249 Uint8 pos; 250 251 pos = SDL_HAT_CENTERED; 252 if ( value != JOY_POVCENTERED ) { 253 if ( (value > JOY_POVLEFT) || (value < JOY_POVRIGHT) ) { 254 pos |= SDL_HAT_UP; 255 } 256 if ( (value > JOY_POVFORWARD) && (value < JOY_POVBACKWARD) ) { 257 pos |= SDL_HAT_RIGHT; 258 } 259 if ( (value > JOY_POVRIGHT) && (value < JOY_POVLEFT) ) { 260 pos |= SDL_HAT_DOWN; 261 } 262 if ( value > JOY_POVBACKWARD ) { 263 pos |= SDL_HAT_LEFT; 264 } 265 } 266 return(pos); 267 } 268 269 /* Function to update the state of a joystick - called as a device poll. 270 * This function shouldn't update the joystick structure directly, 271 * but instead should call SDL_PrivateJoystick*() to deliver events 272 * and update joystick device state. 273 */ 274 void SDL_SYS_JoystickUpdate(SDL_Joystick *joystick) 275 { 276 MMRESULT result; 277 int i; 278 DWORD flags[MAX_AXES] = { JOY_RETURNX, JOY_RETURNY, JOY_RETURNZ, 279 JOY_RETURNR, JOY_RETURNU, JOY_RETURNV }; 280 DWORD pos[MAX_AXES]; 281 struct _transaxis *transaxis; 282 int value, change; 283 JOYINFOEX joyinfo; 284 285 joyinfo.dwSize = sizeof(joyinfo); 286 joyinfo.dwFlags = JOY_RETURNALL|JOY_RETURNPOVCTS; 287 if ( ! joystick->hats ) { 288 joyinfo.dwFlags &= ~(JOY_RETURNPOV|JOY_RETURNPOVCTS); 289 } 290 result = joyGetPosEx(joystick->hwdata->id, &joyinfo); 291 if ( result != JOYERR_NOERROR ) { 292 SetMMerror("joyGetPosEx", result); 293 return; 294 } 295 296 /* joystick motion events */ 297 pos[0] = joyinfo.dwXpos; 298 pos[1] = joyinfo.dwYpos; 299 pos[2] = joyinfo.dwZpos; 300 pos[3] = joyinfo.dwRpos; 301 pos[4] = joyinfo.dwUpos; 302 pos[5] = joyinfo.dwVpos; 303 304 transaxis = joystick->hwdata->transaxis; 305 for (i = 0; i < joystick->naxes; i++) { 306 if (joyinfo.dwFlags & flags[i]) { 307 value = (int)(((float)pos[i] + transaxis[i].offset) * transaxis[i].scale); 308 change = (value - joystick->axes[i]); 309 if ( (change < -JOY_AXIS_THRESHOLD) || (change > JOY_AXIS_THRESHOLD) ) { 310 SDL_PrivateJoystickAxis(joystick, (Uint8)i, (Sint16)value); 311 } 312 } 313 } 314 315 /* joystick button events */ 316 if ( joyinfo.dwFlags & JOY_RETURNBUTTONS ) { 317 for ( i = 0; i < joystick->nbuttons; ++i ) { 318 if ( joyinfo.dwButtons & JOY_BUTTON_FLAG(i) ) { 319 if ( ! joystick->buttons[i] ) { 320 SDL_PrivateJoystickButton(joystick, (Uint8)i, SDL_PRESSED); 321 } 322 } else { 323 if ( joystick->buttons[i] ) { 324 SDL_PrivateJoystickButton(joystick, (Uint8)i, SDL_RELEASED); 325 } 326 } 327 } 328 } 329 330 /* joystick hat events */ 331 if ( joyinfo.dwFlags & JOY_RETURNPOV ) { 332 Uint8 pos; 333 334 pos = TranslatePOV(joyinfo.dwPOV); 335 if ( pos != joystick->hats[0] ) { 336 SDL_PrivateJoystickHat(joystick, 0, pos); 337 } 338 } 339 } 340 341 /* Function to close a joystick after use */ 342 void SDL_SYS_JoystickClose(SDL_Joystick *joystick) 343 { 344 if (joystick->hwdata != NULL) { 345 /* free system specific hardware data */ 346 SDL_free(joystick->hwdata); 347 joystick->hwdata = NULL; 348 } 349 } 350 351 /* Function to perform any system-specific joystick related cleanup */ 352 void SDL_SYS_JoystickQuit(void) 353 { 354 int i; 355 for (i = 0; i < MAX_JOYSTICKS; i++) { 356 if ( SYS_JoystickName[i] != NULL ) { 357 SDL_free(SYS_JoystickName[i]); 358 SYS_JoystickName[i] = NULL; 359 } 360 } 361 } 362 363 364 /* implementation functions */ 365 void SetMMerror(char *function, int code) 366 { 367 static char *error; 368 static char errbuf[1024]; 369 370 errbuf[0] = 0; 371 switch (code) 372 { 373 case MMSYSERR_NODRIVER: 374 error = "Joystick driver not present"; 375 break; 376 377 case MMSYSERR_INVALPARAM: 378 case JOYERR_PARMS: 379 error = "Invalid parameter(s)"; 380 break; 381 382 case MMSYSERR_BADDEVICEID: 383 error = "Bad device ID"; 384 break; 385 386 case JOYERR_UNPLUGGED: 387 error = "Joystick not attached"; 388 break; 389 390 case JOYERR_NOCANDO: 391 error = "Can't capture joystick input"; 392 break; 393 394 default: 395 SDL_snprintf(errbuf, SDL_arraysize(errbuf), 396 "%s: Unknown Multimedia system error: 0x%x", 397 function, code); 398 break; 399 } 400 401 if ( ! errbuf[0] ) { 402 SDL_snprintf(errbuf, SDL_arraysize(errbuf), "%s: %s", function, error); 403 } 404 SDL_SetError("%s", errbuf); 405 } 406 407 #endif /* SDL_JOYSTICK_WINMM */ 408