diff options
Diffstat (limited to 'apps/plugins/sdl/src/joystick/linux')
-rw-r--r-- | apps/plugins/sdl/src/joystick/linux/SDL_sysjoystick.c | 1218 |
1 files changed, 1218 insertions, 0 deletions
diff --git a/apps/plugins/sdl/src/joystick/linux/SDL_sysjoystick.c b/apps/plugins/sdl/src/joystick/linux/SDL_sysjoystick.c new file mode 100644 index 0000000000..ee43974789 --- /dev/null +++ b/apps/plugins/sdl/src/joystick/linux/SDL_sysjoystick.c | |||
@@ -0,0 +1,1218 @@ | |||
1 | /* | ||
2 | SDL - Simple DirectMedia Layer | ||
3 | Copyright (C) 1997-2012 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 | #ifdef SDL_JOYSTICK_LINUX | ||
25 | |||
26 | /* This is the system specific header for the SDL joystick API */ | ||
27 | |||
28 | #include <sys/stat.h> | ||
29 | #include <unistd.h> | ||
30 | #include <fcntl.h> | ||
31 | #include <sys/ioctl.h> | ||
32 | #include <limits.h> /* For the definition of PATH_MAX */ | ||
33 | #include <linux/joystick.h> | ||
34 | #if SDL_INPUT_LINUXEV | ||
35 | #include <linux/input.h> | ||
36 | #endif | ||
37 | |||
38 | #include "SDL_joystick.h" | ||
39 | #include "../SDL_sysjoystick.h" | ||
40 | #include "../SDL_joystick_c.h" | ||
41 | |||
42 | /* Special joystick configurations */ | ||
43 | static struct { | ||
44 | const char *name; | ||
45 | int naxes; | ||
46 | int nhats; | ||
47 | int nballs; | ||
48 | } special_joysticks[] = { | ||
49 | { "MadCatz Panther XL", 3, 2, 1 }, /* We don't handle rudder (axis 8) */ | ||
50 | { "SideWinder Precision Pro", 4, 1, 0 }, | ||
51 | { "SideWinder 3D Pro", 4, 1, 0 }, | ||
52 | { "Microsoft SideWinder 3D Pro", 4, 1, 0 }, | ||
53 | { "Microsoft SideWinder Precision Pro", 4, 1, 0 }, | ||
54 | { "Microsoft SideWinder Dual Strike USB version 1.0", 2, 1, 0 }, | ||
55 | { "WingMan Interceptor", 3, 3, 0 }, | ||
56 | { "WingMan Extreme Digital 3D", 4, 1, 0 }, | ||
57 | { "Microsoft SideWinder Precision 2 Joystick", 4, 1, 0 }, | ||
58 | { "Logitech Inc. WingMan Extreme Digital 3D", 4, 1, 0 }, | ||
59 | { "Saitek Saitek X45", 6, 1, 0 } | ||
60 | }; | ||
61 | |||
62 | /* It looks like newer kernels have the logical mapping at the driver level */ | ||
63 | #define NO_LOGICAL_JOYSTICKS | ||
64 | |||
65 | #ifndef NO_LOGICAL_JOYSTICKS | ||
66 | |||
67 | /* | ||
68 | Some USB HIDs show up as a single joystick even though they actually | ||
69 | control 2 or more joysticks. | ||
70 | */ | ||
71 | /* | ||
72 | This code handles the MP-8800 (Quad) and MP-8866 (Dual), which can | ||
73 | be identified by their transparent blue design. It's quite trivial | ||
74 | to add other joysticks with similar quirky behavior. | ||
75 | -id | ||
76 | */ | ||
77 | |||
78 | struct joystick_logical_mapping { | ||
79 | int njoy; | ||
80 | int nthing; | ||
81 | }; | ||
82 | |||
83 | /* | ||
84 | {logical joy, logical axis}, | ||
85 | {logical joy, logical hat}, | ||
86 | {logical joy, logical ball}, | ||
87 | {logical joy, logical button} | ||
88 | */ | ||
89 | |||
90 | static struct joystick_logical_mapping mp88xx_1_logical_axismap[] = { | ||
91 | {0,0},{0,1},{0,2},{0,3},{0,4},{0,5} | ||
92 | }; | ||
93 | static struct joystick_logical_mapping mp88xx_1_logical_buttonmap[] = { | ||
94 | {0,0},{0,1},{0,2},{0,3},{0,4},{0,5},{0,6},{0,7},{0,8},{0,9},{0,10},{0,11} | ||
95 | }; | ||
96 | |||
97 | static struct joystick_logical_mapping mp88xx_2_logical_axismap[] = { | ||
98 | {0,0},{0,1},{0,2},{1,0},{1,1},{0,3}, | ||
99 | {1,2},{1,3},{0,4},{0,5},{1,4},{1,5} | ||
100 | }; | ||
101 | static struct joystick_logical_mapping mp88xx_2_logical_buttonmap[] = { | ||
102 | {0,0},{0,1},{0,2},{0,3},{0,4},{0,5},{0,6},{0,7},{0,8},{0,9},{0,10},{0,11}, | ||
103 | {1,0},{1,1},{1,2},{1,3},{1,4},{1,5},{1,6},{1,7},{1,8},{1,9},{1,10},{1,11} | ||
104 | }; | ||
105 | |||
106 | static struct joystick_logical_mapping mp88xx_3_logical_axismap[] = { | ||
107 | {0,0},{0,1},{0,2},{1,0},{1,1},{0,3}, | ||
108 | {1,2},{1,3},{2,0},{2,1},{2,2},{2,3}, | ||
109 | {0,4},{0,5},{1,4},{1,5},{2,4},{2,5} | ||
110 | }; | ||
111 | static struct joystick_logical_mapping mp88xx_3_logical_buttonmap[] = { | ||
112 | {0,0},{0,1},{0,2},{0,3},{0,4},{0,5},{0,6},{0,7},{0,8},{0,9},{0,10},{0,11}, | ||
113 | {1,0},{1,1},{1,2},{1,3},{1,4},{1,5},{1,6},{1,7},{1,8},{1,9},{1,10},{1,11}, | ||
114 | {2,0},{2,1},{2,2},{2,3},{2,4},{2,5},{2,6},{2,7},{2,8},{2,9},{2,10},{2,11} | ||
115 | }; | ||
116 | |||
117 | static struct joystick_logical_mapping mp88xx_4_logical_axismap[] = { | ||
118 | {0,0},{0,1},{0,2},{1,0},{1,1},{0,3}, | ||
119 | {1,2},{1,3},{2,0},{2,1},{2,2},{2,3}, | ||
120 | {3,0},{3,1},{3,2},{3,3},{0,4},{0,5}, | ||
121 | {1,4},{1,5},{2,4},{2,5},{3,4},{3,5} | ||
122 | }; | ||
123 | static struct joystick_logical_mapping mp88xx_4_logical_buttonmap[] = { | ||
124 | {0,0},{0,1},{0,2},{0,3},{0,4},{0,5},{0,6},{0,7},{0,8},{0,9},{0,10},{0,11}, | ||
125 | {1,0},{1,1},{1,2},{1,3},{1,4},{1,5},{1,6},{1,7},{1,8},{1,9},{1,10},{1,11}, | ||
126 | {2,0},{2,1},{2,2},{2,3},{2,4},{2,5},{2,6},{2,7},{2,8},{2,9},{2,10},{2,11}, | ||
127 | {3,0},{3,1},{3,2},{3,3},{3,4},{3,5},{3,6},{3,7},{3,8},{3,9},{3,10},{3,11} | ||
128 | }; | ||
129 | |||
130 | struct joystick_logical_layout { | ||
131 | int naxes; | ||
132 | int nhats; | ||
133 | int nballs; | ||
134 | int nbuttons; | ||
135 | }; | ||
136 | |||
137 | static struct joystick_logical_layout mp88xx_1_logical_layout[] = { | ||
138 | {6, 0, 0, 12} | ||
139 | }; | ||
140 | static struct joystick_logical_layout mp88xx_2_logical_layout[] = { | ||
141 | {6, 0, 0, 12}, | ||
142 | {6, 0, 0, 12} | ||
143 | }; | ||
144 | static struct joystick_logical_layout mp88xx_3_logical_layout[] = { | ||
145 | {6, 0, 0, 12}, | ||
146 | {6, 0, 0, 12}, | ||
147 | {6, 0, 0, 12} | ||
148 | }; | ||
149 | static struct joystick_logical_layout mp88xx_4_logical_layout[] = { | ||
150 | {6, 0, 0, 12}, | ||
151 | {6, 0, 0, 12}, | ||
152 | {6, 0, 0, 12}, | ||
153 | {6, 0, 0, 12} | ||
154 | }; | ||
155 | |||
156 | /* | ||
157 | This array sets up a means of mapping a single physical joystick to | ||
158 | multiple logical joysticks. (djm) | ||
159 | |||
160 | njoys | ||
161 | the number of logical joysticks | ||
162 | |||
163 | layouts | ||
164 | an array of layout structures, one to describe each logical joystick | ||
165 | |||
166 | axes, hats, balls, buttons | ||
167 | arrays that map a physical thingy to a logical thingy | ||
168 | */ | ||
169 | struct joystick_logicalmap { | ||
170 | const char *name; | ||
171 | int nbuttons; | ||
172 | int njoys; | ||
173 | struct joystick_logical_layout *layout; | ||
174 | struct joystick_logical_mapping *axismap; | ||
175 | struct joystick_logical_mapping *hatmap; | ||
176 | struct joystick_logical_mapping *ballmap; | ||
177 | struct joystick_logical_mapping *buttonmap; | ||
178 | }; | ||
179 | |||
180 | static struct joystick_logicalmap joystick_logicalmap[] = { | ||
181 | { | ||
182 | "WiseGroup.,Ltd MP-8866 Dual USB Joypad", | ||
183 | 12, | ||
184 | 1, | ||
185 | mp88xx_1_logical_layout, | ||
186 | mp88xx_1_logical_axismap, | ||
187 | NULL, | ||
188 | NULL, | ||
189 | mp88xx_1_logical_buttonmap | ||
190 | }, | ||
191 | { | ||
192 | "WiseGroup.,Ltd MP-8866 Dual USB Joypad", | ||
193 | 24, | ||
194 | 2, | ||
195 | mp88xx_2_logical_layout, | ||
196 | mp88xx_2_logical_axismap, | ||
197 | NULL, | ||
198 | NULL, | ||
199 | mp88xx_2_logical_buttonmap | ||
200 | }, | ||
201 | { | ||
202 | "WiseGroup.,Ltd MP-8800 Quad USB Joypad", | ||
203 | 12, | ||
204 | 1, | ||
205 | mp88xx_1_logical_layout, | ||
206 | mp88xx_1_logical_axismap, | ||
207 | NULL, | ||
208 | NULL, | ||
209 | mp88xx_1_logical_buttonmap | ||
210 | }, | ||
211 | { | ||
212 | "WiseGroup.,Ltd MP-8800 Quad USB Joypad", | ||
213 | 24, | ||
214 | 2, | ||
215 | mp88xx_2_logical_layout, | ||
216 | mp88xx_2_logical_axismap, | ||
217 | NULL, | ||
218 | NULL, | ||
219 | mp88xx_2_logical_buttonmap | ||
220 | }, | ||
221 | { | ||
222 | "WiseGroup.,Ltd MP-8800 Quad USB Joypad", | ||
223 | 36, | ||
224 | 3, | ||
225 | mp88xx_3_logical_layout, | ||
226 | mp88xx_3_logical_axismap, | ||
227 | NULL, | ||
228 | NULL, | ||
229 | mp88xx_3_logical_buttonmap | ||
230 | }, | ||
231 | { | ||
232 | "WiseGroup.,Ltd MP-8800 Quad USB Joypad", | ||
233 | 48, | ||
234 | 4, | ||
235 | mp88xx_4_logical_layout, | ||
236 | mp88xx_4_logical_axismap, | ||
237 | NULL, | ||
238 | NULL, | ||
239 | mp88xx_4_logical_buttonmap | ||
240 | } | ||
241 | }; | ||
242 | |||
243 | /* find the head of a linked list, given a point in it | ||
244 | */ | ||
245 | #define SDL_joylist_head(i, start)\ | ||
246 | for(i = start; SDL_joylist[i].fname == NULL;) i = SDL_joylist[i].prev; | ||
247 | |||
248 | #define SDL_logical_joydecl(d) d | ||
249 | |||
250 | |||
251 | #else | ||
252 | |||
253 | #define SDL_logical_joydecl(d) | ||
254 | |||
255 | #endif /* USE_LOGICAL_JOYSTICKS */ | ||
256 | |||
257 | /* The maximum number of joysticks we'll detect */ | ||
258 | #define MAX_JOYSTICKS 32 | ||
259 | |||
260 | /* A list of available joysticks */ | ||
261 | static struct | ||
262 | { | ||
263 | char* fname; | ||
264 | #ifndef NO_LOGICAL_JOYSTICKS | ||
265 | SDL_Joystick* joy; | ||
266 | struct joystick_logicalmap* map; | ||
267 | int prev; | ||
268 | int next; | ||
269 | int logicalno; | ||
270 | #endif /* USE_LOGICAL_JOYSTICKS */ | ||
271 | } SDL_joylist[MAX_JOYSTICKS]; | ||
272 | |||
273 | |||
274 | /* The private structure used to keep track of a joystick */ | ||
275 | struct joystick_hwdata { | ||
276 | int fd; | ||
277 | /* The current linux joystick driver maps hats to two axes */ | ||
278 | struct hwdata_hat { | ||
279 | int axis[2]; | ||
280 | } *hats; | ||
281 | /* The current linux joystick driver maps balls to two axes */ | ||
282 | struct hwdata_ball { | ||
283 | int axis[2]; | ||
284 | } *balls; | ||
285 | |||
286 | /* Support for the Linux 2.4 unified input interface */ | ||
287 | #if SDL_INPUT_LINUXEV | ||
288 | SDL_bool is_hid; | ||
289 | Uint8 key_map[KEY_MAX-BTN_MISC]; | ||
290 | Uint8 abs_map[ABS_MAX]; | ||
291 | struct axis_correct { | ||
292 | int used; | ||
293 | int coef[3]; | ||
294 | } abs_correct[ABS_MAX]; | ||
295 | #endif | ||
296 | }; | ||
297 | |||
298 | |||
299 | #ifndef NO_LOGICAL_JOYSTICKS | ||
300 | |||
301 | static int CountLogicalJoysticks(int max) | ||
302 | { | ||
303 | register int i, j, k, ret, prev; | ||
304 | const char* name; | ||
305 | int nbuttons, fd; | ||
306 | unsigned char n; | ||
307 | |||
308 | ret = 0; | ||
309 | |||
310 | for(i = 0; i < max; i++) { | ||
311 | name = SDL_SYS_JoystickName(i); | ||
312 | |||
313 | fd = open(SDL_joylist[i].fname, O_RDONLY, 0); | ||
314 | if ( fd >= 0 ) { | ||
315 | if ( ioctl(fd, JSIOCGBUTTONS, &n) < 0 ) { | ||
316 | nbuttons = -1; | ||
317 | } else { | ||
318 | nbuttons = n; | ||
319 | } | ||
320 | close(fd); | ||
321 | } | ||
322 | else { | ||
323 | nbuttons=-1; | ||
324 | } | ||
325 | |||
326 | if (name) { | ||
327 | for(j = 0; j < SDL_arraysize(joystick_logicalmap); j++) { | ||
328 | if (!SDL_strcmp(name, joystick_logicalmap[j].name) && (nbuttons==-1 || nbuttons==joystick_logicalmap[j].nbuttons)) { | ||
329 | prev = i; | ||
330 | SDL_joylist[prev].map = &(joystick_logicalmap[j]); | ||
331 | |||
332 | for(k = 1; k < joystick_logicalmap[j].njoys; k++) { | ||
333 | SDL_joylist[prev].next = max + ret; | ||
334 | SDL_joylist[max+ret].prev = prev; | ||
335 | |||
336 | prev = max + ret; | ||
337 | SDL_joylist[prev].logicalno = k; | ||
338 | SDL_joylist[prev].map = &(joystick_logicalmap[j]); | ||
339 | ret++; | ||
340 | } | ||
341 | |||
342 | break; | ||
343 | } | ||
344 | } | ||
345 | } | ||
346 | } | ||
347 | |||
348 | return ret; | ||
349 | } | ||
350 | |||
351 | static void LogicalSuffix(int logicalno, char* namebuf, int len) | ||
352 | { | ||
353 | register int slen; | ||
354 | const static char suffixs[] = | ||
355 | "01020304050607080910111213141516171819" | ||
356 | "20212223242526272829303132"; | ||
357 | const char* suffix; | ||
358 | slen = SDL_strlen(namebuf); | ||
359 | suffix = NULL; | ||
360 | |||
361 | if (logicalno*2<sizeof(suffixs)) | ||
362 | suffix = suffixs + (logicalno*2); | ||
363 | |||
364 | if (slen + 4 < len && suffix) { | ||
365 | namebuf[slen++] = ' '; | ||
366 | namebuf[slen++] = '#'; | ||
367 | namebuf[slen++] = suffix[0]; | ||
368 | namebuf[slen++] = suffix[1]; | ||
369 | namebuf[slen++] = 0; | ||
370 | } | ||
371 | } | ||
372 | |||
373 | #endif /* USE_LOGICAL_JOYSTICKS */ | ||
374 | |||
375 | #if SDL_INPUT_LINUXEV | ||
376 | #define test_bit(nr, addr) \ | ||
377 | (((1UL << ((nr) % (sizeof(long) * 8))) & ((addr)[(nr) / (sizeof(long) * 8)])) != 0) | ||
378 | #define NBITS(x) ((((x)-1)/(sizeof(long) * 8))+1) | ||
379 | |||
380 | static int EV_IsJoystick(int fd) | ||
381 | { | ||
382 | unsigned long evbit[NBITS(EV_MAX)] = { 0 }; | ||
383 | unsigned long keybit[NBITS(KEY_MAX)] = { 0 }; | ||
384 | unsigned long absbit[NBITS(ABS_MAX)] = { 0 }; | ||
385 | |||
386 | if ( (ioctl(fd, EVIOCGBIT(0, sizeof(evbit)), evbit) < 0) || | ||
387 | (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) < 0) || | ||
388 | (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) < 0) ) { | ||
389 | return(0); | ||
390 | } | ||
391 | if (!(test_bit(EV_KEY, evbit) && test_bit(EV_ABS, evbit) && | ||
392 | test_bit(ABS_X, absbit) && test_bit(ABS_Y, absbit) && | ||
393 | (test_bit(BTN_TRIGGER, keybit) || test_bit(BTN_A, keybit) || test_bit(BTN_1, keybit)))) return 0; | ||
394 | return(1); | ||
395 | } | ||
396 | |||
397 | #endif /* SDL_INPUT_LINUXEV */ | ||
398 | |||
399 | /* Function to scan the system for joysticks */ | ||
400 | int SDL_SYS_JoystickInit(void) | ||
401 | { | ||
402 | /* The base path of the joystick devices */ | ||
403 | const char *joydev_pattern[] = { | ||
404 | #if SDL_INPUT_LINUXEV | ||
405 | "/dev/input/event%d", | ||
406 | #endif | ||
407 | "/dev/input/js%d", | ||
408 | "/dev/js%d" | ||
409 | }; | ||
410 | int numjoysticks; | ||
411 | int i, j; | ||
412 | int fd; | ||
413 | char path[PATH_MAX]; | ||
414 | dev_t dev_nums[MAX_JOYSTICKS]; /* major/minor device numbers */ | ||
415 | struct stat sb; | ||
416 | int n, duplicate; | ||
417 | |||
418 | numjoysticks = 0; | ||
419 | |||
420 | /* First see if the user specified one or more joysticks to use */ | ||
421 | if ( SDL_getenv("SDL_JOYSTICK_DEVICE") != NULL ) { | ||
422 | char *envcopy, *envpath, *delim; | ||
423 | envcopy = SDL_strdup(SDL_getenv("SDL_JOYSTICK_DEVICE")); | ||
424 | envpath = envcopy; | ||
425 | while ( envpath != NULL ) { | ||
426 | delim = SDL_strchr(envpath, ':'); | ||
427 | if ( delim != NULL ) { | ||
428 | *delim++ = '\0'; | ||
429 | } | ||
430 | if ( stat(envpath, &sb) == 0 ) { | ||
431 | fd = open(envpath, O_RDONLY, 0); | ||
432 | if ( fd >= 0 ) { | ||
433 | /* Assume the user knows what they're doing. */ | ||
434 | SDL_joylist[numjoysticks].fname = SDL_strdup(envpath); | ||
435 | if ( SDL_joylist[numjoysticks].fname ) { | ||
436 | dev_nums[numjoysticks] = sb.st_rdev; | ||
437 | ++numjoysticks; | ||
438 | } | ||
439 | close(fd); | ||
440 | } | ||
441 | } | ||
442 | envpath = delim; | ||
443 | } | ||
444 | SDL_free(envcopy); | ||
445 | } | ||
446 | |||
447 | for ( i=0; i<SDL_arraysize(joydev_pattern); ++i ) { | ||
448 | for ( j=0; j < MAX_JOYSTICKS; ++j ) { | ||
449 | SDL_snprintf(path, SDL_arraysize(path), joydev_pattern[i], j); | ||
450 | |||
451 | /* rcg06302000 replaced access(F_OK) call with stat(). | ||
452 | * stat() will fail if the file doesn't exist, so it's | ||
453 | * equivalent behaviour. | ||
454 | */ | ||
455 | if ( stat(path, &sb) == 0 ) { | ||
456 | /* Check to make sure it's not already in list. | ||
457 | * This happens when we see a stick via symlink. | ||
458 | */ | ||
459 | duplicate = 0; | ||
460 | for (n=0; (n<numjoysticks) && !duplicate; ++n) { | ||
461 | if ( sb.st_rdev == dev_nums[n] ) { | ||
462 | duplicate = 1; | ||
463 | } | ||
464 | } | ||
465 | if (duplicate) { | ||
466 | continue; | ||
467 | } | ||
468 | |||
469 | fd = open(path, O_RDONLY, 0); | ||
470 | if ( fd < 0 ) { | ||
471 | continue; | ||
472 | } | ||
473 | #if SDL_INPUT_LINUXEV | ||
474 | #ifdef DEBUG_INPUT_EVENTS | ||
475 | printf("Checking %s\n", path); | ||
476 | #endif | ||
477 | if ( (i == 0) && ! EV_IsJoystick(fd) ) { | ||
478 | close(fd); | ||
479 | continue; | ||
480 | } | ||
481 | #endif | ||
482 | close(fd); | ||
483 | |||
484 | /* We're fine, add this joystick */ | ||
485 | SDL_joylist[numjoysticks].fname = SDL_strdup(path); | ||
486 | if ( SDL_joylist[numjoysticks].fname ) { | ||
487 | dev_nums[numjoysticks] = sb.st_rdev; | ||
488 | ++numjoysticks; | ||
489 | } | ||
490 | } | ||
491 | } | ||
492 | |||
493 | #if SDL_INPUT_LINUXEV | ||
494 | /* This is a special case... | ||
495 | If the event devices are valid then the joystick devices | ||
496 | will be duplicates but without extra information about their | ||
497 | hats or balls. Unfortunately, the event devices can't | ||
498 | currently be calibrated, so it's a win-lose situation. | ||
499 | So : /dev/input/eventX = /dev/input/jsY = /dev/jsY | ||
500 | */ | ||
501 | if ( (i == 0) && (numjoysticks > 0) ) | ||
502 | break; | ||
503 | #endif | ||
504 | } | ||
505 | #ifndef NO_LOGICAL_JOYSTICKS | ||
506 | numjoysticks += CountLogicalJoysticks(numjoysticks); | ||
507 | #endif | ||
508 | |||
509 | return(numjoysticks); | ||
510 | } | ||
511 | |||
512 | /* Function to get the device-dependent name of a joystick */ | ||
513 | const char *SDL_SYS_JoystickName(int index) | ||
514 | { | ||
515 | int fd; | ||
516 | static char namebuf[128]; | ||
517 | char *name; | ||
518 | SDL_logical_joydecl(int oindex = index); | ||
519 | |||
520 | #ifndef NO_LOGICAL_JOYSTICKS | ||
521 | SDL_joylist_head(index, index); | ||
522 | #endif | ||
523 | name = NULL; | ||
524 | fd = open(SDL_joylist[index].fname, O_RDONLY, 0); | ||
525 | if ( fd >= 0 ) { | ||
526 | if ( | ||
527 | #if SDL_INPUT_LINUXEV | ||
528 | (ioctl(fd, EVIOCGNAME(sizeof(namebuf)), namebuf) <= 0) && | ||
529 | #endif | ||
530 | (ioctl(fd, JSIOCGNAME(sizeof(namebuf)), namebuf) <= 0) ) { | ||
531 | name = SDL_joylist[index].fname; | ||
532 | } else { | ||
533 | name = namebuf; | ||
534 | } | ||
535 | close(fd); | ||
536 | |||
537 | |||
538 | #ifndef NO_LOGICAL_JOYSTICKS | ||
539 | if (SDL_joylist[oindex].prev || SDL_joylist[oindex].next || index!=oindex) | ||
540 | { | ||
541 | LogicalSuffix(SDL_joylist[oindex].logicalno, namebuf, 128); | ||
542 | } | ||
543 | #endif | ||
544 | } | ||
545 | return name; | ||
546 | } | ||
547 | |||
548 | static int allocate_hatdata(SDL_Joystick *joystick) | ||
549 | { | ||
550 | int i; | ||
551 | |||
552 | joystick->hwdata->hats = (struct hwdata_hat *)SDL_malloc( | ||
553 | joystick->nhats * sizeof(struct hwdata_hat)); | ||
554 | if ( joystick->hwdata->hats == NULL ) { | ||
555 | return(-1); | ||
556 | } | ||
557 | for ( i=0; i<joystick->nhats; ++i ) { | ||
558 | joystick->hwdata->hats[i].axis[0] = 1; | ||
559 | joystick->hwdata->hats[i].axis[1] = 1; | ||
560 | } | ||
561 | return(0); | ||
562 | } | ||
563 | |||
564 | static int allocate_balldata(SDL_Joystick *joystick) | ||
565 | { | ||
566 | int i; | ||
567 | |||
568 | joystick->hwdata->balls = (struct hwdata_ball *)SDL_malloc( | ||
569 | joystick->nballs * sizeof(struct hwdata_ball)); | ||
570 | if ( joystick->hwdata->balls == NULL ) { | ||
571 | return(-1); | ||
572 | } | ||
573 | for ( i=0; i<joystick->nballs; ++i ) { | ||
574 | joystick->hwdata->balls[i].axis[0] = 0; | ||
575 | joystick->hwdata->balls[i].axis[1] = 0; | ||
576 | } | ||
577 | return(0); | ||
578 | } | ||
579 | |||
580 | static SDL_bool JS_ConfigJoystick(SDL_Joystick *joystick, int fd) | ||
581 | { | ||
582 | SDL_bool handled; | ||
583 | unsigned char n; | ||
584 | int tmp_naxes, tmp_nhats, tmp_nballs; | ||
585 | const char *name; | ||
586 | char *env, env_name[128]; | ||
587 | int i; | ||
588 | |||
589 | handled = SDL_FALSE; | ||
590 | |||
591 | /* Default joystick device settings */ | ||
592 | if ( ioctl(fd, JSIOCGAXES, &n) < 0 ) { | ||
593 | joystick->naxes = 2; | ||
594 | } else { | ||
595 | joystick->naxes = n; | ||
596 | } | ||
597 | if ( ioctl(fd, JSIOCGBUTTONS, &n) < 0 ) { | ||
598 | joystick->nbuttons = 2; | ||
599 | } else { | ||
600 | joystick->nbuttons = n; | ||
601 | } | ||
602 | |||
603 | name = SDL_SYS_JoystickName(joystick->index); | ||
604 | |||
605 | /* Generic analog joystick support */ | ||
606 | if ( SDL_strstr(name, "Analog") == name && SDL_strstr(name, "-hat") ) { | ||
607 | if ( SDL_sscanf(name,"Analog %d-axis %*d-button %d-hat", | ||
608 | &tmp_naxes, &tmp_nhats) == 2 ) { | ||
609 | |||
610 | joystick->naxes = tmp_naxes; | ||
611 | joystick->nhats = tmp_nhats; | ||
612 | |||
613 | handled = SDL_TRUE; | ||
614 | } | ||
615 | } | ||
616 | |||
617 | /* Special joystick support */ | ||
618 | for ( i=0; i < SDL_arraysize(special_joysticks); ++i ) { | ||
619 | if ( SDL_strcmp(name, special_joysticks[i].name) == 0 ) { | ||
620 | |||
621 | joystick->naxes = special_joysticks[i].naxes; | ||
622 | joystick->nhats = special_joysticks[i].nhats; | ||
623 | joystick->nballs = special_joysticks[i].nballs; | ||
624 | |||
625 | handled = SDL_TRUE; | ||
626 | break; | ||
627 | } | ||
628 | } | ||
629 | |||
630 | /* User environment joystick support */ | ||
631 | if ( (env = SDL_getenv("SDL_LINUX_JOYSTICK")) ) { | ||
632 | *env_name = '\0'; | ||
633 | if ( *env == '\'' && SDL_sscanf(env, "'%[^']s'", env_name) == 1 ) | ||
634 | env += SDL_strlen(env_name)+2; | ||
635 | else if ( SDL_sscanf(env, "%s", env_name) == 1 ) | ||
636 | env += SDL_strlen(env_name); | ||
637 | |||
638 | if ( SDL_strcmp(name, env_name) == 0 ) { | ||
639 | |||
640 | if ( SDL_sscanf(env, "%d %d %d", &tmp_naxes, &tmp_nhats, | ||
641 | &tmp_nballs) == 3 ) { | ||
642 | |||
643 | joystick->naxes = tmp_naxes; | ||
644 | joystick->nhats = tmp_nhats; | ||
645 | joystick->nballs = tmp_nballs; | ||
646 | |||
647 | handled = SDL_TRUE; | ||
648 | } | ||
649 | } | ||
650 | } | ||
651 | |||
652 | /* Remap hats and balls */ | ||
653 | if (handled) { | ||
654 | if ( joystick->nhats > 0 ) { | ||
655 | if ( allocate_hatdata(joystick) < 0 ) { | ||
656 | joystick->nhats = 0; | ||
657 | } | ||
658 | } | ||
659 | if ( joystick->nballs > 0 ) { | ||
660 | if ( allocate_balldata(joystick) < 0 ) { | ||
661 | joystick->nballs = 0; | ||
662 | } | ||
663 | } | ||
664 | } | ||
665 | |||
666 | return(handled); | ||
667 | } | ||
668 | |||
669 | #if SDL_INPUT_LINUXEV | ||
670 | |||
671 | static SDL_bool EV_ConfigJoystick(SDL_Joystick *joystick, int fd) | ||
672 | { | ||
673 | int i, t; | ||
674 | unsigned long keybit[NBITS(KEY_MAX)] = { 0 }; | ||
675 | unsigned long absbit[NBITS(ABS_MAX)] = { 0 }; | ||
676 | unsigned long relbit[NBITS(REL_MAX)] = { 0 }; | ||
677 | |||
678 | /* See if this device uses the new unified event API */ | ||
679 | if ( (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) >= 0) && | ||
680 | (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) >= 0) && | ||
681 | (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(relbit)), relbit) >= 0) ) { | ||
682 | joystick->hwdata->is_hid = SDL_TRUE; | ||
683 | |||
684 | /* Get the number of buttons, axes, and other thingamajigs */ | ||
685 | for ( i=BTN_JOYSTICK; i < KEY_MAX; ++i ) { | ||
686 | if ( test_bit(i, keybit) ) { | ||
687 | #ifdef DEBUG_INPUT_EVENTS | ||
688 | printf("Joystick has button: 0x%x\n", i); | ||
689 | #endif | ||
690 | joystick->hwdata->key_map[i-BTN_MISC] = | ||
691 | joystick->nbuttons; | ||
692 | ++joystick->nbuttons; | ||
693 | } | ||
694 | } | ||
695 | for ( i=BTN_MISC; i < BTN_JOYSTICK; ++i ) { | ||
696 | if ( test_bit(i, keybit) ) { | ||
697 | #ifdef DEBUG_INPUT_EVENTS | ||
698 | printf("Joystick has button: 0x%x\n", i); | ||
699 | #endif | ||
700 | joystick->hwdata->key_map[i-BTN_MISC] = | ||
701 | joystick->nbuttons; | ||
702 | ++joystick->nbuttons; | ||
703 | } | ||
704 | } | ||
705 | for ( i=0; i<ABS_MISC; ++i ) { | ||
706 | /* Skip hats */ | ||
707 | if ( i == ABS_HAT0X ) { | ||
708 | i = ABS_HAT3Y; | ||
709 | continue; | ||
710 | } | ||
711 | if ( test_bit(i, absbit) ) { | ||
712 | struct input_absinfo absinfo; | ||
713 | |||
714 | if ( ioctl(fd, EVIOCGABS(i), &absinfo) < 0 ) | ||
715 | continue; | ||
716 | #ifdef DEBUG_INPUT_EVENTS | ||
717 | printf("Joystick has absolute axis: %x\n", i); | ||
718 | printf("Values = { %d, %d, %d, %d, %d }\n", | ||
719 | absinfo.value, absinfo.minimum, | ||
720 | absinfo.maximum, absinfo.fuzz, absinfo.flat); | ||
721 | #endif /* DEBUG_INPUT_EVENTS */ | ||
722 | joystick->hwdata->abs_map[i] = joystick->naxes; | ||
723 | if ( absinfo.minimum == absinfo.maximum ) { | ||
724 | joystick->hwdata->abs_correct[i].used = 0; | ||
725 | } else { | ||
726 | joystick->hwdata->abs_correct[i].used = 1; | ||
727 | joystick->hwdata->abs_correct[i].coef[0] = | ||
728 | (absinfo.maximum + absinfo.minimum) / 2 - absinfo.flat; | ||
729 | joystick->hwdata->abs_correct[i].coef[1] = | ||
730 | (absinfo.maximum + absinfo.minimum) / 2 + absinfo.flat; | ||
731 | t = ((absinfo.maximum - absinfo.minimum) / 2 - 2 * absinfo.flat); | ||
732 | if ( t != 0 ) { | ||
733 | joystick->hwdata->abs_correct[i].coef[2] = (1 << 29) / t; | ||
734 | } else { | ||
735 | joystick->hwdata->abs_correct[i].coef[2] = 0; | ||
736 | } | ||
737 | } | ||
738 | ++joystick->naxes; | ||
739 | } | ||
740 | } | ||
741 | for ( i=ABS_HAT0X; i <= ABS_HAT3Y; i += 2 ) { | ||
742 | if ( test_bit(i, absbit) || test_bit(i+1, absbit) ) { | ||
743 | #ifdef DEBUG_INPUT_EVENTS | ||
744 | printf("Joystick has hat %d\n",(i-ABS_HAT0X)/2); | ||
745 | #endif | ||
746 | ++joystick->nhats; | ||
747 | } | ||
748 | } | ||
749 | if ( test_bit(REL_X, relbit) || test_bit(REL_Y, relbit) ) { | ||
750 | ++joystick->nballs; | ||
751 | } | ||
752 | |||
753 | /* Allocate data to keep track of these thingamajigs */ | ||
754 | if ( joystick->nhats > 0 ) { | ||
755 | if ( allocate_hatdata(joystick) < 0 ) { | ||
756 | joystick->nhats = 0; | ||
757 | } | ||
758 | } | ||
759 | if ( joystick->nballs > 0 ) { | ||
760 | if ( allocate_balldata(joystick) < 0 ) { | ||
761 | joystick->nballs = 0; | ||
762 | } | ||
763 | } | ||
764 | } | ||
765 | return(joystick->hwdata->is_hid); | ||
766 | } | ||
767 | |||
768 | #endif /* SDL_INPUT_LINUXEV */ | ||
769 | |||
770 | #ifndef NO_LOGICAL_JOYSTICKS | ||
771 | static void ConfigLogicalJoystick(SDL_Joystick *joystick) | ||
772 | { | ||
773 | struct joystick_logical_layout* layout; | ||
774 | |||
775 | layout = SDL_joylist[joystick->index].map->layout + | ||
776 | SDL_joylist[joystick->index].logicalno; | ||
777 | |||
778 | joystick->nbuttons = layout->nbuttons; | ||
779 | joystick->nhats = layout->nhats; | ||
780 | joystick->naxes = layout->naxes; | ||
781 | joystick->nballs = layout->nballs; | ||
782 | } | ||
783 | #endif | ||
784 | |||
785 | |||
786 | /* Function to open a joystick for use. | ||
787 | The joystick to open is specified by the index field of the joystick. | ||
788 | This should fill the nbuttons and naxes fields of the joystick structure. | ||
789 | It returns 0, or -1 if there is an error. | ||
790 | */ | ||
791 | int SDL_SYS_JoystickOpen(SDL_Joystick *joystick) | ||
792 | { | ||
793 | int fd; | ||
794 | SDL_logical_joydecl(int realindex); | ||
795 | SDL_logical_joydecl(SDL_Joystick *realjoy = NULL); | ||
796 | |||
797 | /* Open the joystick and set the joystick file descriptor */ | ||
798 | #ifndef NO_LOGICAL_JOYSTICKS | ||
799 | if (SDL_joylist[joystick->index].fname == NULL) { | ||
800 | SDL_joylist_head(realindex, joystick->index); | ||
801 | realjoy = SDL_JoystickOpen(realindex); | ||
802 | |||
803 | if (realjoy == NULL) | ||
804 | return(-1); | ||
805 | |||
806 | fd = realjoy->hwdata->fd; | ||
807 | |||
808 | } else { | ||
809 | fd = open(SDL_joylist[joystick->index].fname, O_RDONLY, 0); | ||
810 | } | ||
811 | SDL_joylist[joystick->index].joy = joystick; | ||
812 | #else | ||
813 | fd = open(SDL_joylist[joystick->index].fname, O_RDONLY, 0); | ||
814 | #endif | ||
815 | |||
816 | if ( fd < 0 ) { | ||
817 | SDL_SetError("Unable to open %s\n", | ||
818 | SDL_joylist[joystick->index]); | ||
819 | return(-1); | ||
820 | } | ||
821 | joystick->hwdata = (struct joystick_hwdata *) | ||
822 | SDL_malloc(sizeof(*joystick->hwdata)); | ||
823 | if ( joystick->hwdata == NULL ) { | ||
824 | SDL_OutOfMemory(); | ||
825 | close(fd); | ||
826 | return(-1); | ||
827 | } | ||
828 | SDL_memset(joystick->hwdata, 0, sizeof(*joystick->hwdata)); | ||
829 | joystick->hwdata->fd = fd; | ||
830 | |||
831 | /* Set the joystick to non-blocking read mode */ | ||
832 | fcntl(fd, F_SETFL, O_NONBLOCK); | ||
833 | |||
834 | /* Get the number of buttons and axes on the joystick */ | ||
835 | #ifndef NO_LOGICAL_JOYSTICKS | ||
836 | if (realjoy) | ||
837 | ConfigLogicalJoystick(joystick); | ||
838 | else | ||
839 | #endif | ||
840 | #if SDL_INPUT_LINUXEV | ||
841 | if ( ! EV_ConfigJoystick(joystick, fd) ) | ||
842 | #endif | ||
843 | JS_ConfigJoystick(joystick, fd); | ||
844 | |||
845 | return(0); | ||
846 | } | ||
847 | |||
848 | #ifndef NO_LOGICAL_JOYSTICKS | ||
849 | |||
850 | static SDL_Joystick* FindLogicalJoystick( | ||
851 | SDL_Joystick *joystick, struct joystick_logical_mapping* v) | ||
852 | { | ||
853 | SDL_Joystick *logicaljoy; | ||
854 | register int i; | ||
855 | |||
856 | i = joystick->index; | ||
857 | logicaljoy = NULL; | ||
858 | |||
859 | /* get the fake joystick that will receive the event | ||
860 | */ | ||
861 | for(;;) { | ||
862 | |||
863 | if (SDL_joylist[i].logicalno == v->njoy) { | ||
864 | logicaljoy = SDL_joylist[i].joy; | ||
865 | break; | ||
866 | } | ||
867 | |||
868 | if (SDL_joylist[i].next == 0) | ||
869 | break; | ||
870 | |||
871 | i = SDL_joylist[i].next; | ||
872 | |||
873 | } | ||
874 | |||
875 | return logicaljoy; | ||
876 | } | ||
877 | |||
878 | static int LogicalJoystickButton( | ||
879 | SDL_Joystick *joystick, Uint8 button, Uint8 state){ | ||
880 | struct joystick_logical_mapping* buttons; | ||
881 | SDL_Joystick *logicaljoy = NULL; | ||
882 | |||
883 | /* if there's no map then this is just a regular joystick | ||
884 | */ | ||
885 | if (SDL_joylist[joystick->index].map == NULL) | ||
886 | return 0; | ||
887 | |||
888 | /* get the logical joystick that will receive the event | ||
889 | */ | ||
890 | buttons = SDL_joylist[joystick->index].map->buttonmap+button; | ||
891 | logicaljoy = FindLogicalJoystick(joystick, buttons); | ||
892 | |||
893 | if (logicaljoy == NULL) | ||
894 | return 1; | ||
895 | |||
896 | SDL_PrivateJoystickButton(logicaljoy, buttons->nthing, state); | ||
897 | |||
898 | return 1; | ||
899 | } | ||
900 | |||
901 | static int LogicalJoystickAxis( | ||
902 | SDL_Joystick *joystick, Uint8 axis, Sint16 value) | ||
903 | { | ||
904 | struct joystick_logical_mapping* axes; | ||
905 | SDL_Joystick *logicaljoy = NULL; | ||
906 | |||
907 | /* if there's no map then this is just a regular joystick | ||
908 | */ | ||
909 | if (SDL_joylist[joystick->index].map == NULL) | ||
910 | return 0; | ||
911 | |||
912 | /* get the logical joystick that will receive the event | ||
913 | */ | ||
914 | axes = SDL_joylist[joystick->index].map->axismap+axis; | ||
915 | logicaljoy = FindLogicalJoystick(joystick, axes); | ||
916 | |||
917 | if (logicaljoy == NULL) | ||
918 | return 1; | ||
919 | |||
920 | SDL_PrivateJoystickAxis(logicaljoy, axes->nthing, value); | ||
921 | |||
922 | return 1; | ||
923 | } | ||
924 | #endif /* USE_LOGICAL_JOYSTICKS */ | ||
925 | |||
926 | static __inline__ | ||
927 | void HandleHat(SDL_Joystick *stick, Uint8 hat, int axis, int value) | ||
928 | { | ||
929 | struct hwdata_hat *the_hat; | ||
930 | const Uint8 position_map[3][3] = { | ||
931 | { SDL_HAT_LEFTUP, SDL_HAT_UP, SDL_HAT_RIGHTUP }, | ||
932 | { SDL_HAT_LEFT, SDL_HAT_CENTERED, SDL_HAT_RIGHT }, | ||
933 | { SDL_HAT_LEFTDOWN, SDL_HAT_DOWN, SDL_HAT_RIGHTDOWN } | ||
934 | }; | ||
935 | SDL_logical_joydecl(SDL_Joystick *logicaljoy = NULL); | ||
936 | SDL_logical_joydecl(struct joystick_logical_mapping* hats = NULL); | ||
937 | |||
938 | if (stick->nhats <= hat) { | ||
939 | return; /* whoops, that shouldn't happen! */ | ||
940 | } | ||
941 | |||
942 | the_hat = &stick->hwdata->hats[hat]; | ||
943 | if ( value < 0 ) { | ||
944 | value = 0; | ||
945 | } else | ||
946 | if ( value == 0 ) { | ||
947 | value = 1; | ||
948 | } else | ||
949 | if ( value > 0 ) { | ||
950 | value = 2; | ||
951 | } | ||
952 | if ( value != the_hat->axis[axis] ) { | ||
953 | the_hat->axis[axis] = value; | ||
954 | |||
955 | #ifndef NO_LOGICAL_JOYSTICKS | ||
956 | /* if there's no map then this is just a regular joystick | ||
957 | */ | ||
958 | if (SDL_joylist[stick->index].map != NULL) { | ||
959 | |||
960 | /* get the fake joystick that will receive the event | ||
961 | */ | ||
962 | hats = SDL_joylist[stick->index].map->hatmap+hat; | ||
963 | logicaljoy = FindLogicalJoystick(stick, hats); | ||
964 | } | ||
965 | |||
966 | if (logicaljoy) { | ||
967 | stick = logicaljoy; | ||
968 | hat = hats->nthing; | ||
969 | } | ||
970 | #endif /* USE_LOGICAL_JOYSTICKS */ | ||
971 | |||
972 | SDL_PrivateJoystickHat(stick, hat, | ||
973 | position_map[the_hat->axis[1]][the_hat->axis[0]]); | ||
974 | } | ||
975 | } | ||
976 | |||
977 | static __inline__ | ||
978 | void HandleBall(SDL_Joystick *stick, Uint8 ball, int axis, int value) | ||
979 | { | ||
980 | if ((stick->nballs <= ball) || (axis >= 2)) { | ||
981 | return; /* whoops, that shouldn't happen! */ | ||
982 | } | ||
983 | stick->hwdata->balls[ball].axis[axis] += value; | ||
984 | } | ||
985 | |||
986 | /* Function to update the state of a joystick - called as a device poll. | ||
987 | * This function shouldn't update the joystick structure directly, | ||
988 | * but instead should call SDL_PrivateJoystick*() to deliver events | ||
989 | * and update joystick device state. | ||
990 | */ | ||
991 | static __inline__ void JS_HandleEvents(SDL_Joystick *joystick) | ||
992 | { | ||
993 | struct js_event events[32]; | ||
994 | int i, len; | ||
995 | Uint8 other_axis; | ||
996 | |||
997 | #ifndef NO_LOGICAL_JOYSTICKS | ||
998 | if (SDL_joylist[joystick->index].fname == NULL) { | ||
999 | SDL_joylist_head(i, joystick->index); | ||
1000 | JS_HandleEvents(SDL_joylist[i].joy); | ||
1001 | return; | ||
1002 | } | ||
1003 | #endif | ||
1004 | |||
1005 | while ((len=read(joystick->hwdata->fd, events, (sizeof events))) > 0) { | ||
1006 | len /= sizeof(events[0]); | ||
1007 | for ( i=0; i<len; ++i ) { | ||
1008 | switch (events[i].type & ~JS_EVENT_INIT) { | ||
1009 | case JS_EVENT_AXIS: | ||
1010 | if ( events[i].number < joystick->naxes ) { | ||
1011 | #ifndef NO_LOGICAL_JOYSTICKS | ||
1012 | if (!LogicalJoystickAxis(joystick, | ||
1013 | events[i].number, events[i].value)) | ||
1014 | #endif | ||
1015 | SDL_PrivateJoystickAxis(joystick, | ||
1016 | events[i].number, events[i].value); | ||
1017 | break; | ||
1018 | } | ||
1019 | events[i].number -= joystick->naxes; | ||
1020 | other_axis = (events[i].number / 2); | ||
1021 | if ( other_axis < joystick->nhats ) { | ||
1022 | HandleHat(joystick, other_axis, | ||
1023 | events[i].number%2, | ||
1024 | events[i].value); | ||
1025 | break; | ||
1026 | } | ||
1027 | events[i].number -= joystick->nhats*2; | ||
1028 | other_axis = (events[i].number / 2); | ||
1029 | if ( other_axis < joystick->nballs ) { | ||
1030 | HandleBall(joystick, other_axis, | ||
1031 | events[i].number%2, | ||
1032 | events[i].value); | ||
1033 | break; | ||
1034 | } | ||
1035 | break; | ||
1036 | case JS_EVENT_BUTTON: | ||
1037 | #ifndef NO_LOGICAL_JOYSTICKS | ||
1038 | if (!LogicalJoystickButton(joystick, | ||
1039 | events[i].number, events[i].value)) | ||
1040 | #endif | ||
1041 | SDL_PrivateJoystickButton(joystick, | ||
1042 | events[i].number, events[i].value); | ||
1043 | break; | ||
1044 | default: | ||
1045 | /* ?? */ | ||
1046 | break; | ||
1047 | } | ||
1048 | } | ||
1049 | } | ||
1050 | } | ||
1051 | #if SDL_INPUT_LINUXEV | ||
1052 | static __inline__ int EV_AxisCorrect(SDL_Joystick *joystick, int which, int value) | ||
1053 | { | ||
1054 | struct axis_correct *correct; | ||
1055 | |||
1056 | correct = &joystick->hwdata->abs_correct[which]; | ||
1057 | if ( correct->used ) { | ||
1058 | if ( value > correct->coef[0] ) { | ||
1059 | if ( value < correct->coef[1] ) { | ||
1060 | return 0; | ||
1061 | } | ||
1062 | value -= correct->coef[1]; | ||
1063 | } else { | ||
1064 | value -= correct->coef[0]; | ||
1065 | } | ||
1066 | value *= correct->coef[2]; | ||
1067 | value >>= 14; | ||
1068 | } | ||
1069 | |||
1070 | /* Clamp and return */ | ||
1071 | if ( value < -32768 ) return -32768; | ||
1072 | if ( value > 32767 ) return 32767; | ||
1073 | |||
1074 | return value; | ||
1075 | } | ||
1076 | |||
1077 | static __inline__ void EV_HandleEvents(SDL_Joystick *joystick) | ||
1078 | { | ||
1079 | struct input_event events[32]; | ||
1080 | int i, len; | ||
1081 | int code; | ||
1082 | |||
1083 | #ifndef NO_LOGICAL_JOYSTICKS | ||
1084 | if (SDL_joylist[joystick->index].fname == NULL) { | ||
1085 | SDL_joylist_head(i, joystick->index); | ||
1086 | return EV_HandleEvents(SDL_joylist[i].joy); | ||
1087 | } | ||
1088 | #endif | ||
1089 | |||
1090 | while ((len=read(joystick->hwdata->fd, events, (sizeof events))) > 0) { | ||
1091 | len /= sizeof(events[0]); | ||
1092 | for ( i=0; i<len; ++i ) { | ||
1093 | code = events[i].code; | ||
1094 | switch (events[i].type) { | ||
1095 | case EV_KEY: | ||
1096 | if ( code >= BTN_MISC ) { | ||
1097 | code -= BTN_MISC; | ||
1098 | #ifndef NO_LOGICAL_JOYSTICKS | ||
1099 | if (!LogicalJoystickButton(joystick, | ||
1100 | joystick->hwdata->key_map[code], | ||
1101 | events[i].value)) | ||
1102 | #endif | ||
1103 | SDL_PrivateJoystickButton(joystick, | ||
1104 | joystick->hwdata->key_map[code], | ||
1105 | events[i].value); | ||
1106 | } | ||
1107 | break; | ||
1108 | case EV_ABS: | ||
1109 | switch (code) { | ||
1110 | case ABS_HAT0X: | ||
1111 | case ABS_HAT0Y: | ||
1112 | case ABS_HAT1X: | ||
1113 | case ABS_HAT1Y: | ||
1114 | case ABS_HAT2X: | ||
1115 | case ABS_HAT2Y: | ||
1116 | case ABS_HAT3X: | ||
1117 | case ABS_HAT3Y: | ||
1118 | code -= ABS_HAT0X; | ||
1119 | HandleHat(joystick, code/2, code%2, | ||
1120 | events[i].value); | ||
1121 | break; | ||
1122 | default: | ||
1123 | events[i].value = EV_AxisCorrect(joystick, code, events[i].value); | ||
1124 | #ifndef NO_LOGICAL_JOYSTICKS | ||
1125 | if (!LogicalJoystickAxis(joystick, | ||
1126 | joystick->hwdata->abs_map[code], | ||
1127 | events[i].value)) | ||
1128 | #endif | ||
1129 | SDL_PrivateJoystickAxis(joystick, | ||
1130 | joystick->hwdata->abs_map[code], | ||
1131 | events[i].value); | ||
1132 | break; | ||
1133 | } | ||
1134 | break; | ||
1135 | case EV_REL: | ||
1136 | switch (code) { | ||
1137 | case REL_X: | ||
1138 | case REL_Y: | ||
1139 | code -= REL_X; | ||
1140 | HandleBall(joystick, code/2, code%2, | ||
1141 | events[i].value); | ||
1142 | break; | ||
1143 | default: | ||
1144 | break; | ||
1145 | } | ||
1146 | break; | ||
1147 | default: | ||
1148 | break; | ||
1149 | } | ||
1150 | } | ||
1151 | } | ||
1152 | } | ||
1153 | #endif /* SDL_INPUT_LINUXEV */ | ||
1154 | |||
1155 | void SDL_SYS_JoystickUpdate(SDL_Joystick *joystick) | ||
1156 | { | ||
1157 | int i; | ||
1158 | |||
1159 | #if SDL_INPUT_LINUXEV | ||
1160 | if ( joystick->hwdata->is_hid ) | ||
1161 | EV_HandleEvents(joystick); | ||
1162 | else | ||
1163 | #endif | ||
1164 | JS_HandleEvents(joystick); | ||
1165 | |||
1166 | /* Deliver ball motion updates */ | ||
1167 | for ( i=0; i<joystick->nballs; ++i ) { | ||
1168 | int xrel, yrel; | ||
1169 | |||
1170 | xrel = joystick->hwdata->balls[i].axis[0]; | ||
1171 | yrel = joystick->hwdata->balls[i].axis[1]; | ||
1172 | if ( xrel || yrel ) { | ||
1173 | joystick->hwdata->balls[i].axis[0] = 0; | ||
1174 | joystick->hwdata->balls[i].axis[1] = 0; | ||
1175 | SDL_PrivateJoystickBall(joystick, (Uint8)i, xrel, yrel); | ||
1176 | } | ||
1177 | } | ||
1178 | } | ||
1179 | |||
1180 | /* Function to close a joystick after use */ | ||
1181 | void SDL_SYS_JoystickClose(SDL_Joystick *joystick) | ||
1182 | { | ||
1183 | #ifndef NO_LOGICAL_JOYSTICKS | ||
1184 | register int i; | ||
1185 | if (SDL_joylist[joystick->index].fname == NULL) { | ||
1186 | SDL_joylist_head(i, joystick->index); | ||
1187 | SDL_JoystickClose(SDL_joylist[i].joy); | ||
1188 | } | ||
1189 | #endif | ||
1190 | |||
1191 | if ( joystick->hwdata ) { | ||
1192 | #ifndef NO_LOGICAL_JOYSTICKS | ||
1193 | if (SDL_joylist[joystick->index].fname != NULL) | ||
1194 | #endif | ||
1195 | close(joystick->hwdata->fd); | ||
1196 | if ( joystick->hwdata->hats ) { | ||
1197 | SDL_free(joystick->hwdata->hats); | ||
1198 | } | ||
1199 | if ( joystick->hwdata->balls ) { | ||
1200 | SDL_free(joystick->hwdata->balls); | ||
1201 | } | ||
1202 | SDL_free(joystick->hwdata); | ||
1203 | joystick->hwdata = NULL; | ||
1204 | } | ||
1205 | } | ||
1206 | |||
1207 | /* Function to perform any system-specific joystick related cleanup */ | ||
1208 | void SDL_SYS_JoystickQuit(void) | ||
1209 | { | ||
1210 | int i; | ||
1211 | |||
1212 | for ( i=0; SDL_joylist[i].fname; ++i ) { | ||
1213 | SDL_free(SDL_joylist[i].fname); | ||
1214 | SDL_joylist[i].fname = NULL; | ||
1215 | } | ||
1216 | } | ||
1217 | |||
1218 | #endif /* SDL_JOYSTICK_LINUX */ | ||