1 /*
2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 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 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public
16 License along with this library; if not, write to the Free
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
19 Sam Lantinga
20 slouken@libsdl.org
21 */
22
23 #ifdef SAVE_RCSID
24 static char rcsid =
25 "@(#) $Id: SDL_sysjoystick.c,v 1.10 2002/06/12 23:49:31 slouken Exp $";
26 #endif
27
28 /* This is the system specific header for the SDL joystick API */
29
30 #include <stdio.h> /* For the definition of NULL */
31 #include <stdlib.h> /* For getenv() prototype */
32 #include <string.h>
33 #include <sys/stat.h>
34 #include <unistd.h>
35 #include <fcntl.h>
36 #include <sys/ioctl.h>
37 #include <limits.h> /* For the definition of PATH_MAX */
38 #ifdef __arm__
39 #include <linux/limits.h> /* Arm cross-compiler needs this */
40 #endif
41 #include <linux/joystick.h>
42 #ifdef USE_INPUT_EVENTS
43 #include <linux/input.h>
44 #endif
45
46 #include "../../mysnprintf.h"
47 #include "../../maxpath.h"
48
49 #include "SDL_error.h"
50 #include "SDL_joystick.h"
51 #include "SDL_sysjoystick.h"
52 #include "SDL_joystick_c.h"
53
54 /* Define this if you want to map axes to hats and trackballs */
55 #define FANCY_HATS_AND_BALLS
56
57 #ifdef FANCY_HATS_AND_BALLS
58 /* Special joystick configurations:
59 'JoystickName' Naxes Nhats Nballs
60 */
61 static const char *special_joysticks[] = {
62 "'MadCatz Panther XL' 3 2 1", /* We don't handle a rudder (axis 8) */
63 "'SideWinder Precision Pro' 4 1 0",
64 "'SideWinder 3D Pro' 4 1 0",
65 "'Microsoft SideWinder 3D Pro' 4 1 0",
66 "'Microsoft SideWinder Dual Strike USB version 1.0' 2 1 0",
67 "'WingMan Interceptor' 3 3 0",
68 /* WingMan Extreme Analog - not recognized by default
69 "'Analog 3-axis 4-button joystick' 2 1 0",
70 */
71 "'WingMan Extreme Digital 3D' 4 1 0",
72 "'Analog 2-axis 4-button 1-hat FCS joystick' 2 1 0",
73 "'Microsoft SideWinder Precision 2 Joystick' 4 1 0",
74 "'Logitech Inc. WingMan Extreme Digital 3D' 4 1 0",
75 "'Saitek Saitek X45' 6 1 0",
76 NULL
77 };
78 #else
79 #undef USE_INPUT_EVENTS
80 #endif
81
82 /* The maximum number of joysticks we'll detect */
83 #define MAX_JOYSTICKS 32
84
85 /* A list of available joysticks */
86 static char *SDL_joylist[MAX_JOYSTICKS];
87
88 /* The private structure used to keep track of a joystick */
89 struct joystick_hwdata {
90 int fd;
91 /* The current linux joystick driver maps hats to two axes */
92 int analog_hat; /* Well, except for analog hats */
93 struct hwdata_hat {
94 int axis[2];
95 } *hats;
96 /* The current linux joystick driver maps balls to two axes */
97 struct hwdata_ball {
98 int axis[2];
99 } *balls;
100
101 /* Support for the Linux 2.4 unified input interface */
102 SDL_bool is_hid;
103 #ifdef USE_INPUT_EVENTS
104 Uint8 key_map[KEY_MAX-BTN_MISC];
105 Uint8 abs_map[ABS_MAX];
106 struct axis_correct {
107 int used;
108 int coef[3];
109 } abs_correct[ABS_MAX];
110 #endif
111 };
112
113 #ifdef USE_INPUT_EVENTS
114 #define test_bit(nr, addr) \
115 (((1UL << ((nr) & 31)) & (((const unsigned int *) addr)[(nr) >> 5])) != 0)
116
EV_IsJoystick(int fd)117 static int EV_IsJoystick(int fd)
118 {
119 unsigned long evbit[40];
120 unsigned long keybit[40];
121 unsigned long absbit[40];
122
123 if ( (ioctl(fd, EVIOCGBIT(0, sizeof(evbit)), evbit) < 0) ||
124 (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) < 0) ||
125 (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) < 0) ) {
126 return(0);
127 }
128 if (!(test_bit(EV_KEY, evbit) && test_bit(EV_ABS, evbit) &&
129 test_bit(ABS_X, absbit) && test_bit(ABS_Y, absbit) &&
130 (test_bit(BTN_TRIGGER, keybit) || test_bit(BTN_A, keybit) || test_bit(BTN_1, keybit)))) return 0;
131 return(1);
132 }
133
134 #endif /* USE_INPUT_EVENTS */
135
136 /* Function to scan the system for joysticks */
SDL_SYS_JoystickInit(void)137 int SDL_SYS_JoystickInit(void)
138 {
139 /* The base path of the joystick devices */
140 const char *joydev_pattern[] = {
141 "/dev/js%d",
142 #ifdef USE_INPUT_EVENTS
143 "/dev/input/event%d",
144 #endif
145 "/dev/input/js%d"
146 };
147 int numjoysticks;
148 int i, j, done;
149 int fd;
150 char path[MY_MAX_PATH];
151 dev_t dev_nums[MAX_JOYSTICKS]; /* major/minor device numbers */
152 struct stat sb;
153 int n, duplicate;
154
155 numjoysticks = 0;
156
157 /* First see if the user specified a joystick to use */
158 if ( getenv("SDL_JOYSTICK_DEVICE") != NULL ) {
159 strncpy(path, getenv("SDL_JOYSTICK_DEVICE"), sizeof(path));
160 path[sizeof(path)-1] = '\0';
161 if ( stat(path, &sb) == 0 ) {
162 fd = open(path, O_RDONLY, 0);
163 if ( fd >= 0 ) {
164 /* Assume the user knows what they're doing. */
165 SDL_joylist[numjoysticks] = mystrdup(path);
166 if ( SDL_joylist[numjoysticks] ) {
167 dev_nums[numjoysticks] = sb.st_rdev;
168 ++numjoysticks;
169 }
170 close(fd);
171 }
172 }
173 }
174 for ( i=0; i<SDL_TABLESIZE(joydev_pattern); ++i ) {
175 done = 0;
176 for ( j=0; (j < MAX_JOYSTICKS) && !done; ++j ) {
177 mysnprintf(path, MY_MAX_PATH, joydev_pattern[i], j);
178
179 /* rcg06302000 replaced access(F_OK) call with stat().
180 * stat() will fail if the file doesn't exist, so it's
181 * equivalent behaviour.
182 */
183 if ( stat(path, &sb) == 0 ) {
184 /* Check to make sure it's not already in list.
185 * This happens when we see a stick via symlink.
186 */
187 duplicate = 0;
188 for (n=0; (n<numjoysticks) && !duplicate; ++n) {
189 if ( sb.st_rdev == dev_nums[n] ) {
190 duplicate = 1;
191 }
192 }
193 if (duplicate) {
194 continue;
195 }
196
197 fd = open(path, O_RDONLY, 0);
198 if ( fd < 0 ) {
199 continue;
200 }
201 #ifdef USE_INPUT_EVENTS
202 #ifdef DEBUG_INPUT_EVENTS
203 printf("Checking %s\n", path);
204 #endif
205 if ( (i > 0) && ! EV_IsJoystick(fd) ) {
206 close(fd);
207 continue;
208 }
209 #endif
210 close(fd);
211
212 /* We're fine, add this joystick */
213 SDL_joylist[numjoysticks] = mystrdup(path);
214 if ( SDL_joylist[numjoysticks] ) {
215 dev_nums[numjoysticks] = sb.st_rdev;
216 ++numjoysticks;
217 }
218 } else {
219 done = 1;
220 }
221 }
222 /* This is a special case...
223 If we're looking at the /dev/input event devices, and we found
224 at least one, then we don't want to look at the input joystick
225 devices, since they're built on top of devices that we've already
226 seen, so we're done.
227 */
228 if ( i > 0 && j > 0 ) {
229 done = 1;
230 }
231 }
232 return(numjoysticks);
233 }
234
235 /* Function to get the device-dependent name of a joystick */
SDL_SYS_JoystickName(int index)236 const char *SDL_SYS_JoystickName(int index)
237 {
238 int fd;
239 static char namebuf[128];
240 char *name;
241
242 name = NULL;
243 fd = open(SDL_joylist[index], O_RDONLY, 0);
244 if ( fd >= 0 ) {
245 if (
246 #ifdef USE_INPUT_EVENTS
247 (ioctl(fd, EVIOCGNAME(sizeof(namebuf)), namebuf) <= 0) &&
248 #endif
249 (ioctl(fd, JSIOCGNAME(sizeof(namebuf)), namebuf) <= 0) ) {
250 name = SDL_joylist[index];
251 } else {
252 name = namebuf;
253 }
254 close(fd);
255 }
256 return name;
257 }
258
259 #ifdef FANCY_HATS_AND_BALLS
260
allocate_hatdata(SDL_Joystick * joystick)261 static int allocate_hatdata(SDL_Joystick *joystick)
262 {
263 int i;
264
265 joystick->hwdata->hats = (struct hwdata_hat *)malloc(
266 joystick->nhats * sizeof(struct hwdata_hat));
267 if ( joystick->hwdata->hats == NULL ) {
268 return(-1);
269 }
270 for ( i=0; i<joystick->nhats; ++i ) {
271 joystick->hwdata->hats[i].axis[0] = 1;
272 joystick->hwdata->hats[i].axis[1] = 1;
273 }
274 return(0);
275 }
276
allocate_balldata(SDL_Joystick * joystick)277 static int allocate_balldata(SDL_Joystick *joystick)
278 {
279 int i;
280
281 joystick->hwdata->balls = (struct hwdata_ball *)malloc(
282 joystick->nballs * sizeof(struct hwdata_ball));
283 if ( joystick->hwdata->balls == NULL ) {
284 return(-1);
285 }
286 for ( i=0; i<joystick->nballs; ++i ) {
287 joystick->hwdata->balls[i].axis[0] = 0;
288 joystick->hwdata->balls[i].axis[1] = 0;
289 }
290 return(0);
291 }
292
ConfigJoystick(SDL_Joystick * joystick,const char * name,const char * config)293 static SDL_bool ConfigJoystick(SDL_Joystick *joystick,
294 const char *name, const char *config)
295 {
296 char cfg_name[128];
297 SDL_bool handled;
298
299 if ( config == NULL ) {
300 return(SDL_FALSE);
301 }
302 strcpy(cfg_name, "");
303 if ( *config == '\'' ) {
304 sscanf(config, "'%[^']s'", cfg_name);
305 config += strlen(cfg_name)+2;
306 } else {
307 sscanf(config, "%s", cfg_name);
308 config += strlen(cfg_name);
309 }
310 handled = SDL_FALSE;
311 if ( strcmp(cfg_name, name) == 0 ) {
312 /* Get the number of axes, hats and balls for this joystick */
313 int joystick_axes = joystick->naxes;
314 sscanf(config, "%d %d %d",
315 &joystick->naxes, &joystick->nhats, &joystick->nballs);
316
317 /* Allocate the extra data for mapping them */
318 if ( joystick->nhats > 0 ) {
319 /* HACK: Analog hats map to only one axis */
320 if (joystick_axes == (joystick->naxes+joystick->nhats)){
321 joystick->hwdata->analog_hat = 1;
322 } else {
323 if ( allocate_hatdata(joystick) < 0 ) {
324 joystick->nhats = 0;
325 }
326 joystick->hwdata->analog_hat = 0;
327 }
328 }
329 if ( joystick->nballs > 0 ) {
330 if ( allocate_balldata(joystick) < 0 ) {
331 joystick->nballs = 0;
332 }
333 }
334 handled = SDL_TRUE;
335 }
336 return(handled);
337 }
338
339 #ifdef USE_INPUT_EVENTS
340
EV_ConfigJoystick(SDL_Joystick * joystick,int fd)341 static SDL_bool EV_ConfigJoystick(SDL_Joystick *joystick, int fd)
342 {
343 int i;
344 unsigned long keybit[40];
345 unsigned long absbit[40];
346 unsigned long relbit[40];
347
348 /* See if this device uses the new unified event API */
349 if ( (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) >= 0) &&
350 (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) >= 0) &&
351 (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(relbit)), relbit) >= 0) ) {
352 joystick->hwdata->is_hid = SDL_TRUE;
353
354 /* Get the number of buttons, axes, and other thingamajigs */
355 for ( i=BTN_JOYSTICK; i < KEY_MAX; ++i ) {
356 if ( test_bit(i, keybit) ) {
357 #ifdef DEBUG_INPUT_EVENTS
358 printf("Joystick has button: 0x%x\n", i);
359 #endif
360 joystick->hwdata->key_map[i-BTN_MISC] =
361 joystick->nbuttons;
362 ++joystick->nbuttons;
363 }
364 }
365 for ( i=BTN_MISC; i < BTN_JOYSTICK; ++i ) {
366 if ( test_bit(i, keybit) ) {
367 #ifdef DEBUG_INPUT_EVENTS
368 printf("Joystick has button: 0x%x\n", i);
369 #endif
370 joystick->hwdata->key_map[i-BTN_MISC] =
371 joystick->nbuttons;
372 ++joystick->nbuttons;
373 }
374 }
375 for ( i=0; i<ABS_MAX; ++i ) {
376 /* Skip hats */
377 if ( i == ABS_HAT0X ) {
378 i = ABS_HAT3Y;
379 continue;
380 }
381 if ( test_bit(i, absbit) ) {
382 int values[5];
383
384 ioctl(fd, EVIOCGABS(i), values);
385 #ifdef DEBUG_INPUT_EVENTS
386 printf("Joystick has absolute axis: %x\n", i);
387 printf("Values = { %d, %d, %d, %d, %d }\n",
388 values[0], values[1],
389 values[2], values[3], values[4]);
390 #endif /* DEBUG_INPUT_EVENTS */
391 joystick->hwdata->abs_map[i] = joystick->naxes;
392 if ( values[1] == values[2] ) {
393 joystick->hwdata->abs_correct[i].used = 0;
394 } else {
395 joystick->hwdata->abs_correct[i].used = 1;
396 joystick->hwdata->abs_correct[i].coef[0] =
397 (values[2] + values[1]) / 2 - values[4];
398 joystick->hwdata->abs_correct[i].coef[1] =
399 (values[2] + values[1]) / 2 + values[4];
400 joystick->hwdata->abs_correct[i].coef[2] =
401 (1 << 29) / ((values[2] - values[1]) / 2 - 2 * values[4]);
402 }
403 ++joystick->naxes;
404 }
405 }
406 for ( i=ABS_HAT0X; i <= ABS_HAT3Y; i += 2 ) {
407 if ( test_bit(i, absbit) || test_bit(i+1, absbit) ) {
408 #ifdef DEBUG_INPUT_EVENTS
409 printf("Joystick has hat %d\n",(i-ABS_HAT0X)/2);
410 #endif
411 ++joystick->nhats;
412 }
413 }
414 if ( test_bit(REL_X, relbit) || test_bit(REL_Y, relbit) ) {
415 ++joystick->nballs;
416 }
417
418 /* Allocate data to keep track of these thingamajigs */
419 if ( joystick->nhats > 0 ) {
420 if ( allocate_hatdata(joystick) < 0 ) {
421 joystick->nhats = 0;
422 }
423 }
424 if ( joystick->nballs > 0 ) {
425 if ( allocate_balldata(joystick) < 0 ) {
426 joystick->nballs = 0;
427 }
428 }
429 }
430 return(joystick->hwdata->is_hid);
431 }
432
433 #endif /* USE_INPUT_EVENTS */
434
435 #endif /* FANCY_HATS_AND_BALLS */
436
437 /* Function to open a joystick for use.
438 The joystick to open is specified by the index field of the joystick.
439 This should fill the nbuttons and naxes fields of the joystick structure.
440 It returns 0, or -1 if there is an error.
441 */
SDL_SYS_JoystickOpen(SDL_Joystick * joystick)442 int SDL_SYS_JoystickOpen(SDL_Joystick *joystick)
443 {
444 #ifdef FANCY_HATS_AND_BALLS
445 const char *name;
446 int i;
447 #endif
448 int fd;
449 unsigned char n;
450
451 /* Open the joystick and set the joystick file descriptor */
452 fd = open(SDL_joylist[joystick->index], O_RDONLY, 0);
453 if ( fd < 0 ) {
454 SDL_SetError("Unable to open %s\n",
455 SDL_joylist[joystick->index]);
456 return(-1);
457 }
458 joystick->hwdata = (struct joystick_hwdata *)
459 malloc(sizeof(*joystick->hwdata));
460 if ( joystick->hwdata == NULL ) {
461 SDL_OutOfMemory();
462 close(fd);
463 return(-1);
464 }
465 memset(joystick->hwdata, 0, sizeof(*joystick->hwdata));
466 joystick->hwdata->fd = fd;
467
468 /* Set the joystick to non-blocking read mode */
469 fcntl(fd, F_SETFL, O_NONBLOCK);
470
471 /* Get the number of buttons and axes on the joystick */
472 #ifdef USE_INPUT_EVENTS
473 if ( ! EV_ConfigJoystick(joystick, fd) )
474 #endif
475 {
476 if ( ioctl(fd, JSIOCGAXES, &n) < 0 ) {
477 joystick->naxes = 2;
478 } else {
479 joystick->naxes = n;
480 }
481 if ( ioctl(fd, JSIOCGBUTTONS, &n) < 0 ) {
482 joystick->nbuttons = 2;
483 } else {
484 joystick->nbuttons = n;
485 }
486 #ifdef FANCY_HATS_AND_BALLS
487 /* Check for special joystick support */
488 name = SDL_SYS_JoystickName(joystick->index);
489 for ( i=0; special_joysticks[i]; ++i ) {
490 if (ConfigJoystick(joystick,name,special_joysticks[i])){
491 break;
492 }
493 }
494 if ( special_joysticks[i] == NULL ) {
495 ConfigJoystick(joystick, name,
496 getenv("SDL_LINUX_JOYSTICK"));
497 }
498 #endif /* FANCY_HATS_AND_BALLS */
499 }
500 return(0);
501 }
502
503 static __inline__
HandleHat(SDL_Joystick * stick,Uint8 hat,int axis,int value)504 void HandleHat(SDL_Joystick *stick, Uint8 hat, int axis, int value)
505 {
506 struct hwdata_hat *the_hat;
507 const Uint8 position_map[3][3] = {
508 { SDL_HAT_LEFTUP, SDL_HAT_UP, SDL_HAT_RIGHTUP },
509 { SDL_HAT_LEFT, SDL_HAT_CENTERED, SDL_HAT_RIGHT },
510 { SDL_HAT_LEFTDOWN, SDL_HAT_DOWN, SDL_HAT_RIGHTDOWN }
511 };
512
513 the_hat = &stick->hwdata->hats[hat];
514 if ( value < 0 ) {
515 value = 0;
516 } else
517 if ( value == 0 ) {
518 value = 1;
519 } else
520 if ( value > 0 ) {
521 value = 2;
522 }
523 if ( value != the_hat->axis[axis] ) {
524 the_hat->axis[axis] = value;
525 // SDL_PrivateJoystickHat(stick, hat,
526 // position_map[the_hat->axis[1]][the_hat->axis[0]]);
527 }
528 }
529
530 /* This was necessary for the Wingman Extreme Analog joystick */
531 static __inline__
HandleAnalogHat(SDL_Joystick * stick,Uint8 hat,int value)532 void HandleAnalogHat(SDL_Joystick *stick, Uint8 hat, int value)
533 {
534 const Uint8 position_map[] = {
535 SDL_HAT_UP,
536 SDL_HAT_RIGHT,
537 SDL_HAT_DOWN,
538 SDL_HAT_LEFT,
539 SDL_HAT_CENTERED
540 };
541 // SDL_PrivateJoystickHat(stick, hat, position_map[(value/16000)+2]);
542 }
543
544 static __inline__
HandleBall(SDL_Joystick * stick,Uint8 ball,int axis,int value)545 void HandleBall(SDL_Joystick *stick, Uint8 ball, int axis, int value)
546 {
547 stick->hwdata->balls[ball].axis[axis] += value;
548 }
549
550 /* Function to update the state of a joystick - called as a device poll.
551 * This function shouldn't update the joystick structure directly,
552 * but instead should call SDL_PrivateJoystick*() to deliver events
553 * and update joystick device state.
554 */
JS_HandleEvents(SDL_Joystick * joystick)555 static __inline__ void JS_HandleEvents(SDL_Joystick *joystick)
556 {
557 struct js_event events[32];
558 int i, len;
559 Uint8 other_axis;
560
561 while ((len=read(joystick->hwdata->fd, events, (sizeof events))) > 0) {
562 len /= sizeof(events[0]);
563 for ( i=0; i<len; ++i ) {
564 switch (events[i].type & ~JS_EVENT_INIT) {
565 case JS_EVENT_AXIS:
566 if ( events[i].number < joystick->naxes ) {
567 SDL_PrivateJoystickAxis(joystick,
568 events[i].number, events[i].value);
569 break;
570 }
571 events[i].number -= joystick->naxes;
572 if ( joystick->hwdata->analog_hat ) {
573 other_axis = events[i].number;
574 if ( other_axis < joystick->nhats ) {
575 HandleAnalogHat(joystick, other_axis,
576 events[i].value);
577 break;
578 }
579 } else {
580 other_axis = (events[i].number / 2);
581 if ( other_axis < joystick->nhats ) {
582 HandleHat(joystick, other_axis,
583 events[i].number%2,
584 events[i].value);
585 break;
586 }
587 }
588 events[i].number -= joystick->nhats*2;
589 other_axis = (events[i].number / 2);
590 if ( other_axis < joystick->nballs ) {
591 HandleBall(joystick, other_axis,
592 events[i].number%2,
593 events[i].value);
594 break;
595 }
596 break;
597 case JS_EVENT_BUTTON:
598 SDL_PrivateJoystickButton(joystick,
599 events[i].number, events[i].value);
600 break;
601 default:
602 /* ?? */
603 break;
604 }
605 }
606 }
607 }
608 #ifdef USE_INPUT_EVENTS
EV_AxisCorrect(SDL_Joystick * joystick,int which,int value)609 static __inline__ int EV_AxisCorrect(SDL_Joystick *joystick, int which, int value)
610 {
611 struct axis_correct *correct;
612
613 correct = &joystick->hwdata->abs_correct[which];
614 if ( correct->used ) {
615 if ( value > correct->coef[0] ) {
616 if ( value < correct->coef[1] ) {
617 return 0;
618 }
619 value -= correct->coef[1];
620 } else {
621 value -= correct->coef[0];
622 }
623 value *= correct->coef[2];
624 value >>= 14;
625 }
626 /* Clamp and return */
627 if ( value < -32767 ) {
628 value = -32767;
629 } else
630 if ( value > 32767 ) {
631 value = 32767;
632 }
633 return value;
634 }
635
EV_HandleEvents(SDL_Joystick * joystick)636 static __inline__ void EV_HandleEvents(SDL_Joystick *joystick)
637 {
638 struct input_event events[32];
639 int i, len;
640 int code;
641
642 while ((len=read(joystick->hwdata->fd, events, (sizeof events))) > 0) {
643 len /= sizeof(events[0]);
644 for ( i=0; i<len; ++i ) {
645 code = events[i].code;
646 switch (events[i].type) {
647 case EV_KEY:
648 if ( code >= BTN_MISC ) {
649 code -= BTN_MISC;
650 SDL_PrivateJoystickButton(joystick,
651 joystick->hwdata->key_map[code],
652 events[i].value);
653 }
654 break;
655 case EV_ABS:
656 switch (code) {
657 case ABS_HAT0X:
658 case ABS_HAT0Y:
659 case ABS_HAT1X:
660 case ABS_HAT1Y:
661 case ABS_HAT2X:
662 case ABS_HAT2Y:
663 case ABS_HAT3X:
664 case ABS_HAT3Y:
665 code -= ABS_HAT0X;
666 HandleHat(joystick, code/2, code%2,
667 events[i].value);
668 break;
669 default:
670 events[i].value = EV_AxisCorrect(joystick, code, events[i].value);
671 SDL_PrivateJoystickAxis(joystick,
672 joystick->hwdata->abs_map[code],
673 events[i].value);
674 break;
675 }
676 break;
677 case EV_REL:
678 switch (code) {
679 case REL_X:
680 case REL_Y:
681 code -= REL_X;
682 HandleBall(joystick, code/2, code%2,
683 events[i].value);
684 break;
685 default:
686 break;
687 }
688 break;
689 default:
690 break;
691 }
692 }
693 }
694 }
695 #endif /* USE_INPUT_EVENTS */
696
SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)697 void SDL_SYS_JoystickUpdate(SDL_Joystick *joystick)
698 {
699 int i;
700
701 #ifdef USE_INPUT_EVENTS
702 if ( joystick->hwdata->is_hid )
703 EV_HandleEvents(joystick);
704 else
705 #endif
706 JS_HandleEvents(joystick);
707
708 /* Deliver ball motion updates */
709 for ( i=0; i<joystick->nballs; ++i ) {
710 int xrel, yrel;
711
712 xrel = joystick->hwdata->balls[i].axis[0];
713 yrel = joystick->hwdata->balls[i].axis[1];
714 if ( xrel || yrel ) {
715 joystick->hwdata->balls[i].axis[0] = 0;
716 joystick->hwdata->balls[i].axis[1] = 0;
717 SDL_PrivateJoystickBall(joystick, (Uint8)i, xrel, yrel);
718 }
719 }
720 }
721
722 /* Function to close a joystick after use */
SDL_SYS_JoystickClose(SDL_Joystick * joystick)723 void SDL_SYS_JoystickClose(SDL_Joystick *joystick)
724 {
725 if ( joystick->hwdata ) {
726 close(joystick->hwdata->fd);
727 if ( joystick->hwdata->hats ) {
728 free(joystick->hwdata->hats);
729 }
730 if ( joystick->hwdata->balls ) {
731 free(joystick->hwdata->balls);
732 }
733 free(joystick->hwdata);
734 joystick->hwdata = NULL;
735 }
736 }
737
738 /* Function to perform any system-specific joystick related cleanup */
SDL_SYS_JoystickQuit(void)739 void SDL_SYS_JoystickQuit(void)
740 {
741 int i;
742
743 for ( i=0; SDL_joylist[i]; ++i ) {
744 free(SDL_joylist[i]);
745 }
746 SDL_joylist[0] = NULL;
747 }
748
749