comparison src/joystick/linux/SDL_sysjoystick.c @ 554:38b1a98aeb11

Linux joystick cleanups from Alan Swanson
author Sam Lantinga <slouken@libsdl.org>
date Mon, 02 Dec 2002 03:11:36 +0000
parents b2c97d579dfe
children 2e58ece48b61
comparison
equal deleted inserted replaced
553:417f8709e648 554:38b1a98aeb11
46 #include "SDL_error.h" 46 #include "SDL_error.h"
47 #include "SDL_joystick.h" 47 #include "SDL_joystick.h"
48 #include "SDL_sysjoystick.h" 48 #include "SDL_sysjoystick.h"
49 #include "SDL_joystick_c.h" 49 #include "SDL_joystick_c.h"
50 50
51 /* Define this if you want to map axes to hats and trackballs */ 51 /* Special joystick configurations */
52 #define FANCY_HATS_AND_BALLS 52 static struct {
53 53 const char *name;
54 #ifdef FANCY_HATS_AND_BALLS 54 int naxes;
55 /* Special joystick configurations: 55 int nhats;
56 'JoystickName' Naxes Nhats Nballs 56 int nballs;
57 */ 57 } special_joysticks[] = {
58 static const char *special_joysticks[] = { 58 { "MadCatz Panther XL", 3, 2, 1 }, /* We don't handle rudder (axis 8) */
59 "'MadCatz Panther XL' 3 2 1", /* We don't handle a rudder (axis 8) */ 59 { "SideWinder Precision Pro", 4, 1, 0 },
60 "'SideWinder Precision Pro' 4 1 0", 60 { "SideWinder 3D Pro", 4, 1, 0 },
61 "'SideWinder 3D Pro' 4 1 0", 61 { "Microsoft SideWinder 3D Pro", 4, 1, 0 },
62 "'Microsoft SideWinder 3D Pro' 4 1 0", 62 { "Microsoft SideWinder Dual Strike USB version 1.0", 2, 1, 0 },
63 "'Microsoft SideWinder Dual Strike USB version 1.0' 2 1 0", 63 { "WingMan Interceptor", 3, 3, 0 },
64 "'WingMan Interceptor' 3 3 0", 64 { "WingMan Extreme Digital 3D", 4, 1, 0 },
65 /* WingMan Extreme Analog - not recognized by default 65 { "Microsoft SideWinder Precision 2 Joystick", 4, 1, 0 },
66 "'Analog 3-axis 4-button joystick' 2 1 0", 66 { "Logitech Inc. WingMan Extreme Digital 3D", 4, 1, 0 },
67 */ 67 { "Saitek Saitek X45", 6, 1, 0 }
68 "'WingMan Extreme Digital 3D' 4 1 0",
69 "'Analog 2-axis 4-button 1-hat FCS joystick' 2 1 0",
70 "'Microsoft SideWinder Precision 2 Joystick' 4 1 0",
71 "'Logitech Inc. WingMan Extreme Digital 3D' 4 1 0",
72 "'Saitek Saitek X45' 6 1 0",
73 NULL
74 }; 68 };
75 #else
76 #undef USE_INPUT_EVENTS
77 #endif
78 69
79 /* The maximum number of joysticks we'll detect */ 70 /* The maximum number of joysticks we'll detect */
80 #define MAX_JOYSTICKS 32 71 #define MAX_JOYSTICKS 32
81 72
82 /* A list of available joysticks */ 73 /* A list of available joysticks */
94 struct hwdata_ball { 85 struct hwdata_ball {
95 int axis[2]; 86 int axis[2];
96 } *balls; 87 } *balls;
97 88
98 /* Support for the Linux 2.4 unified input interface */ 89 /* Support for the Linux 2.4 unified input interface */
90 #ifdef USE_INPUT_EVENTS
99 SDL_bool is_hid; 91 SDL_bool is_hid;
100 #ifdef USE_INPUT_EVENTS
101 Uint8 key_map[KEY_MAX-BTN_MISC]; 92 Uint8 key_map[KEY_MAX-BTN_MISC];
102 Uint8 abs_map[ABS_MAX]; 93 Uint8 abs_map[ABS_MAX];
103 struct axis_correct { 94 struct axis_correct {
104 int used; 95 int used;
105 int coef[3]; 96 int coef[3];
144 /* Function to scan the system for joysticks */ 135 /* Function to scan the system for joysticks */
145 int SDL_SYS_JoystickInit(void) 136 int SDL_SYS_JoystickInit(void)
146 { 137 {
147 /* The base path of the joystick devices */ 138 /* The base path of the joystick devices */
148 const char *joydev_pattern[] = { 139 const char *joydev_pattern[] = {
149 "/dev/js%d",
150 #ifdef USE_INPUT_EVENTS 140 #ifdef USE_INPUT_EVENTS
151 "/dev/input/event%d", 141 "/dev/input/event%d",
152 #endif 142 #endif
153 "/dev/input/js%d" 143 "/dev/input/js%d",
144 "/dev/js%d"
154 }; 145 };
155 int numjoysticks; 146 int numjoysticks;
156 int i, j, done; 147 int i, j;
157 int fd; 148 int fd;
158 char path[PATH_MAX]; 149 char path[PATH_MAX];
159 dev_t dev_nums[MAX_JOYSTICKS]; /* major/minor device numbers */ 150 dev_t dev_nums[MAX_JOYSTICKS]; /* major/minor device numbers */
160 struct stat sb; 151 struct stat sb;
161 int n, duplicate; 152 int n, duplicate;
177 } 168 }
178 close(fd); 169 close(fd);
179 } 170 }
180 } 171 }
181 } 172 }
173
182 for ( i=0; i<SDL_TABLESIZE(joydev_pattern); ++i ) { 174 for ( i=0; i<SDL_TABLESIZE(joydev_pattern); ++i ) {
183 done = 0; 175 for ( j=0; j < MAX_JOYSTICKS; ++j ) {
184 for ( j=0; (j < MAX_JOYSTICKS) && !done; ++j ) {
185 sprintf(path, joydev_pattern[i], j); 176 sprintf(path, joydev_pattern[i], j);
186 177
187 /* rcg06302000 replaced access(F_OK) call with stat(). 178 /* rcg06302000 replaced access(F_OK) call with stat().
188 * stat() will fail if the file doesn't exist, so it's 179 * stat() will fail if the file doesn't exist, so it's
189 * equivalent behaviour. 180 * equivalent behaviour.
208 } 199 }
209 #ifdef USE_INPUT_EVENTS 200 #ifdef USE_INPUT_EVENTS
210 #ifdef DEBUG_INPUT_EVENTS 201 #ifdef DEBUG_INPUT_EVENTS
211 printf("Checking %s\n", path); 202 printf("Checking %s\n", path);
212 #endif 203 #endif
213 if ( (i > 0) && ! EV_IsJoystick(fd) ) { 204 if ( (i == 0) && ! EV_IsJoystick(fd) ) {
214 close(fd); 205 close(fd);
215 continue; 206 continue;
216 } 207 }
217 #endif 208 #endif
218 close(fd); 209 close(fd);
221 SDL_joylist[numjoysticks] = mystrdup(path); 212 SDL_joylist[numjoysticks] = mystrdup(path);
222 if ( SDL_joylist[numjoysticks] ) { 213 if ( SDL_joylist[numjoysticks] ) {
223 dev_nums[numjoysticks] = sb.st_rdev; 214 dev_nums[numjoysticks] = sb.st_rdev;
224 ++numjoysticks; 215 ++numjoysticks;
225 } 216 }
226 } else { 217 } else
227 done = 1; 218 break;
228 } 219 }
229 } 220
230 /* This is a special case... 221 #ifdef USE_INPUT_EVENTS
231 If we're looking at the /dev/input event devices, and we found 222 /* This is a special case...
232 at least one, then we don't want to look at the input joystick 223 If the event devices are valid then the joystick devices
233 devices, since they're built on top of devices that we've already 224 will be duplicates but without extra information about their
234 seen, so we're done. 225 hats or balls. Unfortunately, the event devices can't
235 */ 226 currently be calibrated, so it's a win-lose situation.
236 if ( i > 0 && j > 0 ) { 227 So : /dev/input/eventX = /dev/input/jsY = /dev/jsY
237 done = 1; 228 */
238 } 229 if ( (i == 0) && (numjoysticks > 0) )
239 } 230 break;
231 #endif
232 }
233
240 return(numjoysticks); 234 return(numjoysticks);
241 } 235 }
242 236
243 /* Function to get the device-dependent name of a joystick */ 237 /* Function to get the device-dependent name of a joystick */
244 const char *SDL_SYS_JoystickName(int index) 238 const char *SDL_SYS_JoystickName(int index)
262 close(fd); 256 close(fd);
263 } 257 }
264 return name; 258 return name;
265 } 259 }
266 260
267 #ifdef FANCY_HATS_AND_BALLS
268
269 static int allocate_hatdata(SDL_Joystick *joystick) 261 static int allocate_hatdata(SDL_Joystick *joystick)
270 { 262 {
271 int i; 263 int i;
272 264
273 joystick->hwdata->hats = (struct hwdata_hat *)malloc( 265 joystick->hwdata->hats = (struct hwdata_hat *)malloc(
296 joystick->hwdata->balls[i].axis[1] = 0; 288 joystick->hwdata->balls[i].axis[1] = 0;
297 } 289 }
298 return(0); 290 return(0);
299 } 291 }
300 292
301 static SDL_bool ConfigJoystick(SDL_Joystick *joystick, 293 static SDL_bool JS_ConfigJoystick(SDL_Joystick *joystick, int fd)
302 const char *name, const char *config) 294 {
303 {
304 char cfg_name[128];
305 SDL_bool handled; 295 SDL_bool handled;
306 296 unsigned char n;
307 if ( config == NULL ) { 297 int old_axes, tmp_naxes, tmp_nhats, tmp_nballs;
308 return(SDL_FALSE); 298 const char *name;
309 } 299 char *env, env_name[128];
310 strcpy(cfg_name, ""); 300 int i;
311 if ( *config == '\'' ) { 301
312 sscanf(config, "'%[^']s'", cfg_name); 302 handled = SDL_FALSE;
313 config += strlen(cfg_name)+2; 303
304 /* Default joystick device settings */
305 if ( ioctl(fd, JSIOCGAXES, &n) < 0 ) {
306 joystick->naxes = 2;
314 } else { 307 } else {
315 sscanf(config, "%s", cfg_name); 308 joystick->naxes = n;
316 config += strlen(cfg_name); 309 }
317 } 310 if ( ioctl(fd, JSIOCGBUTTONS, &n) < 0 ) {
318 handled = SDL_FALSE; 311 joystick->nbuttons = 2;
319 if ( strcmp(cfg_name, name) == 0 ) { 312 } else {
320 /* Get the number of axes, hats and balls for this joystick */ 313 joystick->nbuttons = n;
321 int joystick_axes = joystick->naxes; 314 }
322 sscanf(config, "%d %d %d", 315
323 &joystick->naxes, &joystick->nhats, &joystick->nballs); 316 name = SDL_SYS_JoystickName(joystick->index);
324 317 old_axes = joystick->naxes;
325 /* Allocate the extra data for mapping them */ 318
319 /* Generic analog joystick support */
320 if ( strstr(name, "Analog") == name && strstr(name, "-hat") ) {
321 if ( sscanf(name,"Analog %d-axis %*d-button %d-hat",
322 &tmp_naxes, &tmp_nhats) == 2 ) {
323
324 joystick->naxes = tmp_naxes;
325 joystick->nhats = tmp_nhats;
326
327 handled = SDL_TRUE;
328 }
329 }
330
331 /* Special joystick support */
332 for ( i=0; i < SDL_TABLESIZE(special_joysticks); ++i ) {
333 if ( strcmp(name, special_joysticks[i].name) == 0 ) {
334
335 joystick->naxes = special_joysticks[i].naxes;
336 joystick->nhats = special_joysticks[i].nhats;
337 joystick->nballs = special_joysticks[i].nballs;
338
339 handled = SDL_TRUE;
340 break;
341 }
342 }
343
344 /* User environment joystick support */
345 if ( (env = getenv("SDL_LINUX_JOYSTICK")) ) {
346 strcpy(env_name, "");
347 if ( *env == '\'' && sscanf(env, "'%[^']s'", env_name) == 1 )
348 env += strlen(env_name)+2;
349 else if ( sscanf(env, "%s", env_name) == 1 )
350 env += strlen(env_name);
351
352 if ( strcmp(name, env_name) == 0 ) {
353
354 if ( sscanf(env, "%d %d %d", &tmp_naxes, &tmp_nhats,
355 &tmp_nballs) == 3 ) {
356
357 joystick->naxes = tmp_naxes;
358 joystick->nhats = tmp_nhats;
359 joystick->nballs = tmp_nballs;
360
361 handled = SDL_TRUE;
362 }
363 }
364 }
365
366 /* Remap hats and balls */
367 if (handled) {
326 if ( joystick->nhats > 0 ) { 368 if ( joystick->nhats > 0 ) {
327 /* HACK: Analog hats map to only one axis */ 369 /* HACK: Analog hats map to only one axis */
328 if (joystick_axes == (joystick->naxes+joystick->nhats)){ 370 if (old_axes == (joystick->naxes+joystick->nhats)){
329 joystick->hwdata->analog_hat = 1; 371 joystick->hwdata->analog_hat = 1;
330 } else { 372 } else {
331 if ( allocate_hatdata(joystick) < 0 ) { 373 if ( allocate_hatdata(joystick) < 0 ) {
332 joystick->nhats = 0; 374 joystick->nhats = 0;
333 } 375 }
337 if ( joystick->nballs > 0 ) { 379 if ( joystick->nballs > 0 ) {
338 if ( allocate_balldata(joystick) < 0 ) { 380 if ( allocate_balldata(joystick) < 0 ) {
339 joystick->nballs = 0; 381 joystick->nballs = 0;
340 } 382 }
341 } 383 }
342 handled = SDL_TRUE; 384 }
343 } 385
344 return(handled); 386 return(handled);
345 } 387 }
346 388
347 #ifdef USE_INPUT_EVENTS 389 #ifdef USE_INPUT_EVENTS
348 390
438 return(joystick->hwdata->is_hid); 480 return(joystick->hwdata->is_hid);
439 } 481 }
440 482
441 #endif /* USE_INPUT_EVENTS */ 483 #endif /* USE_INPUT_EVENTS */
442 484
443 #endif /* FANCY_HATS_AND_BALLS */
444
445 /* Function to open a joystick for use. 485 /* Function to open a joystick for use.
446 The joystick to open is specified by the index field of the joystick. 486 The joystick to open is specified by the index field of the joystick.
447 This should fill the nbuttons and naxes fields of the joystick structure. 487 This should fill the nbuttons and naxes fields of the joystick structure.
448 It returns 0, or -1 if there is an error. 488 It returns 0, or -1 if there is an error.
449 */ 489 */
450 int SDL_SYS_JoystickOpen(SDL_Joystick *joystick) 490 int SDL_SYS_JoystickOpen(SDL_Joystick *joystick)
451 { 491 {
452 #ifdef FANCY_HATS_AND_BALLS
453 const char *name;
454 int i;
455 #endif
456 int fd; 492 int fd;
457 unsigned char n;
458 493
459 /* Open the joystick and set the joystick file descriptor */ 494 /* Open the joystick and set the joystick file descriptor */
460 fd = open(SDL_joylist[joystick->index], O_RDONLY, 0); 495 fd = open(SDL_joylist[joystick->index], O_RDONLY, 0);
461 if ( fd < 0 ) { 496 if ( fd < 0 ) {
462 SDL_SetError("Unable to open %s\n", 497 SDL_SetError("Unable to open %s\n",
478 513
479 /* Get the number of buttons and axes on the joystick */ 514 /* Get the number of buttons and axes on the joystick */
480 #ifdef USE_INPUT_EVENTS 515 #ifdef USE_INPUT_EVENTS
481 if ( ! EV_ConfigJoystick(joystick, fd) ) 516 if ( ! EV_ConfigJoystick(joystick, fd) )
482 #endif 517 #endif
483 { 518 JS_ConfigJoystick(joystick, fd);
484 if ( ioctl(fd, JSIOCGAXES, &n) < 0 ) { 519
485 joystick->naxes = 2;
486 } else {
487 joystick->naxes = n;
488 }
489 if ( ioctl(fd, JSIOCGBUTTONS, &n) < 0 ) {
490 joystick->nbuttons = 2;
491 } else {
492 joystick->nbuttons = n;
493 }
494 #ifdef FANCY_HATS_AND_BALLS
495 /* Check for special joystick support */
496 name = SDL_SYS_JoystickName(joystick->index);
497 for ( i=0; special_joysticks[i]; ++i ) {
498 if (ConfigJoystick(joystick,name,special_joysticks[i])){
499 break;
500 }
501 }
502 if ( special_joysticks[i] == NULL ) {
503 ConfigJoystick(joystick, name,
504 getenv("SDL_LINUX_JOYSTICK"));
505 }
506 #endif /* FANCY_HATS_AND_BALLS */
507 }
508 return(0); 520 return(0);
509 } 521 }
510 522
511 static __inline__ 523 static __inline__
512 void HandleHat(SDL_Joystick *stick, Uint8 hat, int axis, int value) 524 void HandleHat(SDL_Joystick *stick, Uint8 hat, int axis, int value)
629 value -= correct->coef[0]; 641 value -= correct->coef[0];
630 } 642 }
631 value *= correct->coef[2]; 643 value *= correct->coef[2];
632 value >>= 14; 644 value >>= 14;
633 } 645 }
646
634 /* Clamp and return */ 647 /* Clamp and return */
635 if ( value < -32767 ) { 648 if ( value < -32767 ) return -32767;
636 value = -32767; 649 if ( value > 32767 ) return 32767;
637 } else 650
638 if ( value > 32767 ) {
639 value = 32767;
640 }
641 return value; 651 return value;
642 } 652 }
643 653
644 static __inline__ void EV_HandleEvents(SDL_Joystick *joystick) 654 static __inline__ void EV_HandleEvents(SDL_Joystick *joystick)
645 { 655 {