Home | History | Annotate | Download | only in joystick
      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