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