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