1 /* 2 SDL - Simple DirectMedia Layer 3 Copyright (C) 1997-2006 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 /* This is the joystick API for Simple DirectMedia Layer */ 25 26 #include "SDL_events.h" 27 #include "SDL_sysjoystick.h" 28 #include "SDL_joystick_c.h" 29 #if !SDL_EVENTS_DISABLED 30 #include "../events/SDL_events_c.h" 31 #endif 32 33 /* This is used for Quake III Arena */ 34 #if SDL_EVENTS_DISABLED 35 #define SDL_Lock_EventThread() 36 #define SDL_Unlock_EventThread() 37 #endif 38 39 Uint8 SDL_numjoysticks = 0; 40 SDL_Joystick **SDL_joysticks = NULL; 41 static SDL_Joystick *default_joystick = NULL; 42 43 int SDL_JoystickInit(void) 44 { 45 int arraylen; 46 int status; 47 48 SDL_numjoysticks = 0; 49 status = SDL_SYS_JoystickInit(); 50 if ( status >= 0 ) { 51 arraylen = (status+1)*sizeof(*SDL_joysticks); 52 SDL_joysticks = (SDL_Joystick **)SDL_malloc(arraylen); 53 if ( SDL_joysticks == NULL ) { 54 SDL_numjoysticks = 0; 55 } else { 56 SDL_memset(SDL_joysticks, 0, arraylen); 57 SDL_numjoysticks = status; 58 } 59 status = 0; 60 } 61 default_joystick = NULL; 62 return(status); 63 } 64 65 /* 66 * Count the number of joysticks attached to the system 67 */ 68 int SDL_NumJoysticks(void) 69 { 70 return SDL_numjoysticks; 71 } 72 73 /* 74 * Get the implementation dependent name of a joystick 75 */ 76 const char *SDL_JoystickName(int device_index) 77 { 78 if ( (device_index < 0) || (device_index >= SDL_numjoysticks) ) { 79 SDL_SetError("There are %d joysticks available", 80 SDL_numjoysticks); 81 return(NULL); 82 } 83 return(SDL_SYS_JoystickName(device_index)); 84 } 85 86 /* 87 * Open a joystick for use - the index passed as an argument refers to 88 * the N'th joystick on the system. This index is the value which will 89 * identify this joystick in future joystick events. 90 * 91 * This function returns a joystick identifier, or NULL if an error occurred. 92 */ 93 SDL_Joystick *SDL_JoystickOpen(int device_index) 94 { 95 int i; 96 SDL_Joystick *joystick; 97 98 if ( (device_index < 0) || (device_index >= SDL_numjoysticks) ) { 99 SDL_SetError("There are %d joysticks available", 100 SDL_numjoysticks); 101 return(NULL); 102 } 103 104 /* If the joystick is already open, return it */ 105 for ( i=0; SDL_joysticks[i]; ++i ) { 106 if ( device_index == SDL_joysticks[i]->index ) { 107 joystick = SDL_joysticks[i]; 108 ++joystick->ref_count; 109 return(joystick); 110 } 111 } 112 113 /* Create and initialize the joystick */ 114 joystick = (SDL_Joystick *)SDL_malloc((sizeof *joystick)); 115 if ( joystick != NULL ) { 116 SDL_memset(joystick, 0, (sizeof *joystick)); 117 joystick->index = device_index; 118 if ( SDL_SYS_JoystickOpen(joystick) < 0 ) { 119 SDL_free(joystick); 120 joystick = NULL; 121 } else { 122 if ( joystick->naxes > 0 ) { 123 joystick->axes = (Sint16 *)SDL_malloc 124 (joystick->naxes*sizeof(Sint16)); 125 } 126 if ( joystick->nhats > 0 ) { 127 joystick->hats = (Uint8 *)SDL_malloc 128 (joystick->nhats*sizeof(Uint8)); 129 } 130 if ( joystick->nballs > 0 ) { 131 joystick->balls = (struct balldelta *)SDL_malloc 132 (joystick->nballs*sizeof(*joystick->balls)); 133 } 134 if ( joystick->nbuttons > 0 ) { 135 joystick->buttons = (Uint8 *)SDL_malloc 136 (joystick->nbuttons*sizeof(Uint8)); 137 } 138 if ( ((joystick->naxes > 0) && !joystick->axes) 139 || ((joystick->nhats > 0) && !joystick->hats) 140 || ((joystick->nballs > 0) && !joystick->balls) 141 || ((joystick->nbuttons > 0) && !joystick->buttons)) { 142 SDL_OutOfMemory(); 143 SDL_JoystickClose(joystick); 144 joystick = NULL; 145 } 146 if ( joystick->axes ) { 147 SDL_memset(joystick->axes, 0, 148 joystick->naxes*sizeof(Sint16)); 149 } 150 if ( joystick->hats ) { 151 SDL_memset(joystick->hats, 0, 152 joystick->nhats*sizeof(Uint8)); 153 } 154 if ( joystick->balls ) { 155 SDL_memset(joystick->balls, 0, 156 joystick->nballs*sizeof(*joystick->balls)); 157 } 158 if ( joystick->buttons ) { 159 SDL_memset(joystick->buttons, 0, 160 joystick->nbuttons*sizeof(Uint8)); 161 } 162 } 163 } 164 if ( joystick ) { 165 /* Add joystick to list */ 166 ++joystick->ref_count; 167 SDL_Lock_EventThread(); 168 for ( i=0; SDL_joysticks[i]; ++i ) 169 /* Skip to next joystick */; 170 SDL_joysticks[i] = joystick; 171 SDL_Unlock_EventThread(); 172 } 173 return(joystick); 174 } 175 176 /* 177 * Returns 1 if the joystick has been opened, or 0 if it has not. 178 */ 179 int SDL_JoystickOpened(int device_index) 180 { 181 int i, opened; 182 183 opened = 0; 184 for ( i=0; SDL_joysticks[i]; ++i ) { 185 if ( SDL_joysticks[i]->index == (Uint8)device_index ) { 186 opened = 1; 187 break; 188 } 189 } 190 return(opened); 191 } 192 193 static int ValidJoystick(SDL_Joystick **joystick) 194 { 195 int valid; 196 197 if ( *joystick == NULL ) { 198 *joystick = default_joystick; 199 } 200 if ( *joystick == NULL ) { 201 SDL_SetError("Joystick hasn't been opened yet"); 202 valid = 0; 203 } else { 204 valid = 1; 205 } 206 return valid; 207 } 208 209 /* 210 * Get the device index of an opened joystick. 211 */ 212 int SDL_JoystickIndex(SDL_Joystick *joystick) 213 { 214 if ( ! ValidJoystick(&joystick) ) { 215 return(-1); 216 } 217 return(joystick->index); 218 } 219 220 /* 221 * Get the number of multi-dimensional axis controls on a joystick 222 */ 223 int SDL_JoystickNumAxes(SDL_Joystick *joystick) 224 { 225 if ( ! ValidJoystick(&joystick) ) { 226 return(-1); 227 } 228 return(joystick->naxes); 229 } 230 231 /* 232 * Get the number of hats on a joystick 233 */ 234 int SDL_JoystickNumHats(SDL_Joystick *joystick) 235 { 236 if ( ! ValidJoystick(&joystick) ) { 237 return(-1); 238 } 239 return(joystick->nhats); 240 } 241 242 /* 243 * Get the number of trackballs on a joystick 244 */ 245 int SDL_JoystickNumBalls(SDL_Joystick *joystick) 246 { 247 if ( ! ValidJoystick(&joystick) ) { 248 return(-1); 249 } 250 return(joystick->nballs); 251 } 252 253 /* 254 * Get the number of buttons on a joystick 255 */ 256 int SDL_JoystickNumButtons(SDL_Joystick *joystick) 257 { 258 if ( ! ValidJoystick(&joystick) ) { 259 return(-1); 260 } 261 return(joystick->nbuttons); 262 } 263 264 /* 265 * Get the current state of an axis control on a joystick 266 */ 267 Sint16 SDL_JoystickGetAxis(SDL_Joystick *joystick, int axis) 268 { 269 Sint16 state; 270 271 if ( ! ValidJoystick(&joystick) ) { 272 return(0); 273 } 274 if ( axis < joystick->naxes ) { 275 state = joystick->axes[axis]; 276 } else { 277 SDL_SetError("Joystick only has %d axes", joystick->naxes); 278 state = 0; 279 } 280 return(state); 281 } 282 283 /* 284 * Get the current state of a hat on a joystick 285 */ 286 Uint8 SDL_JoystickGetHat(SDL_Joystick *joystick, int hat) 287 { 288 Uint8 state; 289 290 if ( ! ValidJoystick(&joystick) ) { 291 return(0); 292 } 293 if ( hat < joystick->nhats ) { 294 state = joystick->hats[hat]; 295 } else { 296 SDL_SetError("Joystick only has %d hats", joystick->nhats); 297 state = 0; 298 } 299 return(state); 300 } 301 302 /* 303 * Get the ball axis change since the last poll 304 */ 305 int SDL_JoystickGetBall(SDL_Joystick *joystick, int ball, int *dx, int *dy) 306 { 307 int retval; 308 309 if ( ! ValidJoystick(&joystick) ) { 310 return(-1); 311 } 312 313 retval = 0; 314 if ( ball < joystick->nballs ) { 315 if ( dx ) { 316 *dx = joystick->balls[ball].dx; 317 } 318 if ( dy ) { 319 *dy = joystick->balls[ball].dy; 320 } 321 joystick->balls[ball].dx = 0; 322 joystick->balls[ball].dy = 0; 323 } else { 324 SDL_SetError("Joystick only has %d balls", joystick->nballs); 325 retval = -1; 326 } 327 return(retval); 328 } 329 330 /* 331 * Get the current state of a button on a joystick 332 */ 333 Uint8 SDL_JoystickGetButton(SDL_Joystick *joystick, int button) 334 { 335 Uint8 state; 336 337 if ( ! ValidJoystick(&joystick) ) { 338 return(0); 339 } 340 if ( button < joystick->nbuttons ) { 341 state = joystick->buttons[button]; 342 } else { 343 SDL_SetError("Joystick only has %d buttons",joystick->nbuttons); 344 state = 0; 345 } 346 return(state); 347 } 348 349 /* 350 * Close a joystick previously opened with SDL_JoystickOpen() 351 */ 352 void SDL_JoystickClose(SDL_Joystick *joystick) 353 { 354 int i; 355 356 if ( ! ValidJoystick(&joystick) ) { 357 return; 358 } 359 360 /* First decrement ref count */ 361 if ( --joystick->ref_count > 0 ) { 362 return; 363 } 364 365 /* Lock the event queue - prevent joystick polling */ 366 SDL_Lock_EventThread(); 367 368 if ( joystick == default_joystick ) { 369 default_joystick = NULL; 370 } 371 SDL_SYS_JoystickClose(joystick); 372 373 /* Remove joystick from list */ 374 for ( i=0; SDL_joysticks[i]; ++i ) { 375 if ( joystick == SDL_joysticks[i] ) { 376 SDL_memcpy(&SDL_joysticks[i], &SDL_joysticks[i+1], 377 (SDL_numjoysticks-i)*sizeof(joystick)); 378 break; 379 } 380 } 381 382 /* Let the event thread keep running */ 383 SDL_Unlock_EventThread(); 384 385 /* Free the data associated with this joystick */ 386 if ( joystick->axes ) { 387 SDL_free(joystick->axes); 388 } 389 if ( joystick->hats ) { 390 SDL_free(joystick->hats); 391 } 392 if ( joystick->balls ) { 393 SDL_free(joystick->balls); 394 } 395 if ( joystick->buttons ) { 396 SDL_free(joystick->buttons); 397 } 398 SDL_free(joystick); 399 } 400 401 void SDL_JoystickQuit(void) 402 { 403 /* Stop the event polling */ 404 SDL_Lock_EventThread(); 405 SDL_numjoysticks = 0; 406 SDL_Unlock_EventThread(); 407 408 /* Quit the joystick setup */ 409 SDL_SYS_JoystickQuit(); 410 if ( SDL_joysticks ) { 411 SDL_free(SDL_joysticks); 412 SDL_joysticks = NULL; 413 } 414 } 415 416 417 /* These are global for SDL_sysjoystick.c and SDL_events.c */ 418 419 int SDL_PrivateJoystickAxis(SDL_Joystick *joystick, Uint8 axis, Sint16 value) 420 { 421 int posted; 422 423 /* Update internal joystick state */ 424 joystick->axes[axis] = value; 425 426 /* Post the event, if desired */ 427 posted = 0; 428 #if !SDL_EVENTS_DISABLED 429 if ( SDL_ProcessEvents[SDL_JOYAXISMOTION] == SDL_ENABLE ) { 430 SDL_Event event; 431 event.type = SDL_JOYAXISMOTION; 432 event.jaxis.which = joystick->index; 433 event.jaxis.axis = axis; 434 event.jaxis.value = value; 435 if ( (SDL_EventOK == NULL) || (*SDL_EventOK)(&event) ) { 436 posted = 1; 437 SDL_PushEvent(&event); 438 } 439 } 440 #endif /* !SDL_EVENTS_DISABLED */ 441 return(posted); 442 } 443 444 int SDL_PrivateJoystickHat(SDL_Joystick *joystick, Uint8 hat, Uint8 value) 445 { 446 int posted; 447 448 /* Update internal joystick state */ 449 joystick->hats[hat] = value; 450 451 /* Post the event, if desired */ 452 posted = 0; 453 #if !SDL_EVENTS_DISABLED 454 if ( SDL_ProcessEvents[SDL_JOYHATMOTION] == SDL_ENABLE ) { 455 SDL_Event event; 456 event.jhat.type = SDL_JOYHATMOTION; 457 event.jhat.which = joystick->index; 458 event.jhat.hat = hat; 459 event.jhat.value = value; 460 if ( (SDL_EventOK == NULL) || (*SDL_EventOK)(&event) ) { 461 posted = 1; 462 SDL_PushEvent(&event); 463 } 464 } 465 #endif /* !SDL_EVENTS_DISABLED */ 466 return(posted); 467 } 468 469 int SDL_PrivateJoystickBall(SDL_Joystick *joystick, Uint8 ball, 470 Sint16 xrel, Sint16 yrel) 471 { 472 int posted; 473 474 /* Update internal mouse state */ 475 joystick->balls[ball].dx += xrel; 476 joystick->balls[ball].dy += yrel; 477 478 /* Post the event, if desired */ 479 posted = 0; 480 #if !SDL_EVENTS_DISABLED 481 if ( SDL_ProcessEvents[SDL_JOYBALLMOTION] == SDL_ENABLE ) { 482 SDL_Event event; 483 event.jball.type = SDL_JOYBALLMOTION; 484 event.jball.which = joystick->index; 485 event.jball.ball = ball; 486 event.jball.xrel = xrel; 487 event.jball.yrel = yrel; 488 if ( (SDL_EventOK == NULL) || (*SDL_EventOK)(&event) ) { 489 posted = 1; 490 SDL_PushEvent(&event); 491 } 492 } 493 #endif /* !SDL_EVENTS_DISABLED */ 494 return(posted); 495 } 496 497 int SDL_PrivateJoystickButton(SDL_Joystick *joystick, Uint8 button, Uint8 state) 498 { 499 int posted; 500 #if !SDL_EVENTS_DISABLED 501 SDL_Event event; 502 503 switch ( state ) { 504 case SDL_PRESSED: 505 event.type = SDL_JOYBUTTONDOWN; 506 break; 507 case SDL_RELEASED: 508 event.type = SDL_JOYBUTTONUP; 509 break; 510 default: 511 /* Invalid state -- bail */ 512 return(0); 513 } 514 #endif /* !SDL_EVENTS_DISABLED */ 515 516 /* Update internal joystick state */ 517 joystick->buttons[button] = state; 518 519 /* Post the event, if desired */ 520 posted = 0; 521 #if !SDL_EVENTS_DISABLED 522 if ( SDL_ProcessEvents[event.type] == SDL_ENABLE ) { 523 event.jbutton.which = joystick->index; 524 event.jbutton.button = button; 525 event.jbutton.state = state; 526 if ( (SDL_EventOK == NULL) || (*SDL_EventOK)(&event) ) { 527 posted = 1; 528 SDL_PushEvent(&event); 529 } 530 } 531 #endif /* !SDL_EVENTS_DISABLED */ 532 return(posted); 533 } 534 535 void SDL_JoystickUpdate(void) 536 { 537 int i; 538 539 for ( i=0; SDL_joysticks[i]; ++i ) { 540 SDL_SYS_JoystickUpdate(SDL_joysticks[i]); 541 } 542 } 543 544 int SDL_JoystickEventState(int state) 545 { 546 #if SDL_EVENTS_DISABLED 547 return SDL_IGNORE; 548 #else 549 const Uint8 event_list[] = { 550 SDL_JOYAXISMOTION, SDL_JOYBALLMOTION, SDL_JOYHATMOTION, 551 SDL_JOYBUTTONDOWN, SDL_JOYBUTTONUP, 552 }; 553 unsigned int i; 554 555 switch (state) { 556 case SDL_QUERY: 557 state = SDL_IGNORE; 558 for ( i=0; i<SDL_arraysize(event_list); ++i ) { 559 state = SDL_EventState(event_list[i],SDL_QUERY); 560 if ( state == SDL_ENABLE ) { 561 break; 562 } 563 } 564 break; 565 default: 566 for ( i=0; i<SDL_arraysize(event_list); ++i ) { 567 SDL_EventState(event_list[i], state); 568 } 569 break; 570 } 571 return(state); 572 #endif /* SDL_EVENTS_DISABLED */ 573 } 574