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