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@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 39Uint8 SDL_numjoysticks = 0; 40SDL_Joystick **SDL_joysticks = NULL; 41static SDL_Joystick *default_joystick = NULL; 42 43int 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 */ 68int SDL_NumJoysticks(void) 69{ 70 return SDL_numjoysticks; 71} 72 73/* 74 * Get the implementation dependent name of a joystick 75 */ 76const 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 */ 93SDL_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 */ 179int 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 193static 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 */ 212int 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 */ 223int 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 */ 234int 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 */ 245int 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 */ 256int 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 */ 267Sint16 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 */ 286Uint8 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 */ 305int 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 */ 333Uint8 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 */ 352void 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 401void 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 419int 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 444int 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 469int 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 497int 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 535void 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 544int 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