| 1 | /* |
| 2 | SDL - Simple DirectMedia Layer |
| 3 | Copyright (C) 1997-2009 Sam Lantinga |
| 4 | |
| 5 | This library is free software; you can redistribute it and/or |
| 6 | modify it under the terms of the GNU Lesser General Public |
| 7 | License as published by the Free Software Foundation; either |
| 8 | version 2.1 of the License, or (at your option) any later version. |
| 9 | |
| 10 | This library is distributed in the hope that it will be useful, |
| 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 13 | Lesser General Public License for more details. |
| 14 | |
| 15 | You should have received a copy of the GNU Lesser General Public |
| 16 | License along with this library; if not, write to the Free Software |
| 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| 18 | |
| 19 | Sam Lantinga |
| 20 | slouken@libsdl.org |
| 21 | */ |
| 22 | #include "SDL_config.h" |
| 23 | |
| 24 | #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 a joystick to use */ |
| 421 | if ( SDL_getenv("SDL_JOYSTICK_DEVICE") != NULL ) { |
| 422 | SDL_strlcpy(path, SDL_getenv("SDL_JOYSTICK_DEVICE"), sizeof(path)); |
| 423 | if ( stat(path, &sb) == 0 ) { |
| 424 | fd = open(path, O_RDONLY, 0); |
| 425 | if ( fd >= 0 ) { |
| 426 | /* Assume the user knows what they're doing. */ |
| 427 | SDL_joylist[numjoysticks].fname = SDL_strdup(path); |
| 428 | if ( SDL_joylist[numjoysticks].fname ) { |
| 429 | dev_nums[numjoysticks] = sb.st_rdev; |
| 430 | ++numjoysticks; |
| 431 | } |
| 432 | close(fd); |
| 433 | } |
| 434 | } |
| 435 | } |
| 436 | |
| 437 | for ( i=0; i<SDL_arraysize(joydev_pattern); ++i ) { |
| 438 | for ( j=0; j < MAX_JOYSTICKS; ++j ) { |
| 439 | SDL_snprintf(path, SDL_arraysize(path), joydev_pattern[i], j); |
| 440 | |
| 441 | /* rcg06302000 replaced access(F_OK) call with stat(). |
| 442 | * stat() will fail if the file doesn't exist, so it's |
| 443 | * equivalent behaviour. |
| 444 | */ |
| 445 | if ( stat(path, &sb) == 0 ) { |
| 446 | /* Check to make sure it's not already in list. |
| 447 | * This happens when we see a stick via symlink. |
| 448 | */ |
| 449 | duplicate = 0; |
| 450 | for (n=0; (n<numjoysticks) && !duplicate; ++n) { |
| 451 | if ( sb.st_rdev == dev_nums[n] ) { |
| 452 | duplicate = 1; |
| 453 | } |
| 454 | } |
| 455 | if (duplicate) { |
| 456 | continue; |
| 457 | } |
| 458 | |
| 459 | fd = open(path, O_RDONLY, 0); |
| 460 | if ( fd < 0 ) { |
| 461 | continue; |
| 462 | } |
| 463 | #if SDL_INPUT_LINUXEV |
| 464 | #ifdef DEBUG_INPUT_EVENTS |
| 465 | printf("Checking %s\n", path); |
| 466 | #endif |
| 467 | if ( (i == 0) && ! EV_IsJoystick(fd) ) { |
| 468 | close(fd); |
| 469 | continue; |
| 470 | } |
| 471 | #endif |
| 472 | close(fd); |
| 473 | |
| 474 | /* We're fine, add this joystick */ |
| 475 | SDL_joylist[numjoysticks].fname = SDL_strdup(path); |
| 476 | if ( SDL_joylist[numjoysticks].fname ) { |
| 477 | dev_nums[numjoysticks] = sb.st_rdev; |
| 478 | ++numjoysticks; |
| 479 | } |
| 480 | } |
| 481 | } |
| 482 | |
| 483 | #if SDL_INPUT_LINUXEV |
| 484 | /* This is a special case... |
| 485 | If the event devices are valid then the joystick devices |
| 486 | will be duplicates but without extra information about their |
| 487 | hats or balls. Unfortunately, the event devices can't |
| 488 | currently be calibrated, so it's a win-lose situation. |
| 489 | So : /dev/input/eventX = /dev/input/jsY = /dev/jsY |
| 490 | */ |
| 491 | if ( (i == 0) && (numjoysticks > 0) ) |
| 492 | break; |
| 493 | #endif |
| 494 | } |
| 495 | #ifndef NO_LOGICAL_JOYSTICKS |
| 496 | numjoysticks += CountLogicalJoysticks(numjoysticks); |
| 497 | #endif |
| 498 | |
| 499 | return(numjoysticks); |
| 500 | } |
| 501 | |
| 502 | /* Function to get the device-dependent name of a joystick */ |
| 503 | const char *SDL_SYS_JoystickName(int index) |
| 504 | { |
| 505 | int fd; |
| 506 | static char namebuf[128]; |
| 507 | char *name; |
| 508 | SDL_logical_joydecl(int oindex = index); |
| 509 | |
| 510 | #ifndef NO_LOGICAL_JOYSTICKS |
| 511 | SDL_joylist_head(index, index); |
| 512 | #endif |
| 513 | name = NULL; |
| 514 | fd = open(SDL_joylist[index].fname, O_RDONLY, 0); |
| 515 | if ( fd >= 0 ) { |
| 516 | if ( |
| 517 | #if SDL_INPUT_LINUXEV |
| 518 | (ioctl(fd, EVIOCGNAME(sizeof(namebuf)), namebuf) <= 0) && |
| 519 | #endif |
| 520 | (ioctl(fd, JSIOCGNAME(sizeof(namebuf)), namebuf) <= 0) ) { |
| 521 | name = SDL_joylist[index].fname; |
| 522 | } else { |
| 523 | name = namebuf; |
| 524 | } |
| 525 | close(fd); |
| 526 | |
| 527 | |
| 528 | #ifndef NO_LOGICAL_JOYSTICKS |
| 529 | if (SDL_joylist[oindex].prev || SDL_joylist[oindex].next || index!=oindex) |
| 530 | { |
| 531 | LogicalSuffix(SDL_joylist[oindex].logicalno, namebuf, 128); |
| 532 | } |
| 533 | #endif |
| 534 | } |
| 535 | return name; |
| 536 | } |
| 537 | |
| 538 | static int allocate_hatdata(SDL_Joystick *joystick) |
| 539 | { |
| 540 | int i; |
| 541 | |
| 542 | joystick->hwdata->hats = (struct hwdata_hat *)SDL_malloc( |
| 543 | joystick->nhats * sizeof(struct hwdata_hat)); |
| 544 | if ( joystick->hwdata->hats == NULL ) { |
| 545 | return(-1); |
| 546 | } |
| 547 | for ( i=0; i<joystick->nhats; ++i ) { |
| 548 | joystick->hwdata->hats[i].axis[0] = 1; |
| 549 | joystick->hwdata->hats[i].axis[1] = 1; |
| 550 | } |
| 551 | return(0); |
| 552 | } |
| 553 | |
| 554 | static int allocate_balldata(SDL_Joystick *joystick) |
| 555 | { |
| 556 | int i; |
| 557 | |
| 558 | joystick->hwdata->balls = (struct hwdata_ball *)SDL_malloc( |
| 559 | joystick->nballs * sizeof(struct hwdata_ball)); |
| 560 | if ( joystick->hwdata->balls == NULL ) { |
| 561 | return(-1); |
| 562 | } |
| 563 | for ( i=0; i<joystick->nballs; ++i ) { |
| 564 | joystick->hwdata->balls[i].axis[0] = 0; |
| 565 | joystick->hwdata->balls[i].axis[1] = 0; |
| 566 | } |
| 567 | return(0); |
| 568 | } |
| 569 | |
| 570 | static SDL_bool JS_ConfigJoystick(SDL_Joystick *joystick, int fd) |
| 571 | { |
| 572 | SDL_bool handled; |
| 573 | unsigned char n; |
| 574 | int old_axes, tmp_naxes, tmp_nhats, tmp_nballs; |
| 575 | const char *name; |
| 576 | char *env, env_name[128]; |
| 577 | int i; |
| 578 | |
| 579 | handled = SDL_FALSE; |
| 580 | |
| 581 | /* Default joystick device settings */ |
| 582 | if ( ioctl(fd, JSIOCGAXES, &n) < 0 ) { |
| 583 | joystick->naxes = 2; |
| 584 | } else { |
| 585 | joystick->naxes = n; |
| 586 | } |
| 587 | if ( ioctl(fd, JSIOCGBUTTONS, &n) < 0 ) { |
| 588 | joystick->nbuttons = 2; |
| 589 | } else { |
| 590 | joystick->nbuttons = n; |
| 591 | } |
| 592 | |
| 593 | name = SDL_SYS_JoystickName(joystick->index); |
| 594 | old_axes = joystick->naxes; |
| 595 | |
| 596 | /* Generic analog joystick support */ |
| 597 | if ( SDL_strstr(name, "Analog") == name && SDL_strstr(name, "-hat") ) { |
| 598 | if ( SDL_sscanf(name,"Analog %d-axis %*d-button %d-hat", |
| 599 | &tmp_naxes, &tmp_nhats) == 2 ) { |
| 600 | |
| 601 | joystick->naxes = tmp_naxes; |
| 602 | joystick->nhats = tmp_nhats; |
| 603 | |
| 604 | handled = SDL_TRUE; |
| 605 | } |
| 606 | } |
| 607 | |
| 608 | /* Special joystick support */ |
| 609 | for ( i=0; i < SDL_arraysize(special_joysticks); ++i ) { |
| 610 | if ( SDL_strcmp(name, special_joysticks[i].name) == 0 ) { |
| 611 | |
| 612 | joystick->naxes = special_joysticks[i].naxes; |
| 613 | joystick->nhats = special_joysticks[i].nhats; |
| 614 | joystick->nballs = special_joysticks[i].nballs; |
| 615 | |
| 616 | handled = SDL_TRUE; |
| 617 | break; |
| 618 | } |
| 619 | } |
| 620 | |
| 621 | /* User environment joystick support */ |
| 622 | if ( (env = SDL_getenv("SDL_LINUX_JOYSTICK")) ) { |
| 623 | *env_name = '\0'; |
| 624 | if ( *env == '\'' && SDL_sscanf(env, "'%[^']s'", env_name) == 1 ) |
| 625 | env += SDL_strlen(env_name)+2; |
| 626 | else if ( SDL_sscanf(env, "%s", env_name) == 1 ) |
| 627 | env += SDL_strlen(env_name); |
| 628 | |
| 629 | if ( SDL_strcmp(name, env_name) == 0 ) { |
| 630 | |
| 631 | if ( SDL_sscanf(env, "%d %d %d", &tmp_naxes, &tmp_nhats, |
| 632 | &tmp_nballs) == 3 ) { |
| 633 | |
| 634 | joystick->naxes = tmp_naxes; |
| 635 | joystick->nhats = tmp_nhats; |
| 636 | joystick->nballs = tmp_nballs; |
| 637 | |
| 638 | handled = SDL_TRUE; |
| 639 | } |
| 640 | } |
| 641 | } |
| 642 | |
| 643 | /* Remap hats and balls */ |
| 644 | if (handled) { |
| 645 | if ( joystick->nhats > 0 ) { |
| 646 | if ( allocate_hatdata(joystick) < 0 ) { |
| 647 | joystick->nhats = 0; |
| 648 | } |
| 649 | } |
| 650 | if ( joystick->nballs > 0 ) { |
| 651 | if ( allocate_balldata(joystick) < 0 ) { |
| 652 | joystick->nballs = 0; |
| 653 | } |
| 654 | } |
| 655 | } |
| 656 | |
| 657 | return(handled); |
| 658 | } |
| 659 | |
| 660 | #if SDL_INPUT_LINUXEV |
| 661 | |
| 662 | static SDL_bool EV_ConfigJoystick(SDL_Joystick *joystick, int fd) |
| 663 | { |
| 664 | int i, t; |
| 665 | unsigned long keybit[NBITS(KEY_MAX)] = { 0 }; |
| 666 | unsigned long absbit[NBITS(ABS_MAX)] = { 0 }; |
| 667 | unsigned long relbit[NBITS(REL_MAX)] = { 0 }; |
| 668 | |
| 669 | /* See if this device uses the new unified event API */ |
| 670 | if ( (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) >= 0) && |
| 671 | (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) >= 0) && |
| 672 | (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(relbit)), relbit) >= 0) ) { |
| 673 | joystick->hwdata->is_hid = SDL_TRUE; |
| 674 | |
| 675 | /* Get the number of buttons, axes, and other thingamajigs */ |
| 676 | for ( i=BTN_JOYSTICK; i < KEY_MAX; ++i ) { |
| 677 | if ( test_bit(i, keybit) ) { |
| 678 | #ifdef DEBUG_INPUT_EVENTS |
| 679 | printf("Joystick has button: 0x%x\n", i); |
| 680 | #endif |
| 681 | joystick->hwdata->key_map[i-BTN_MISC] = |
| 682 | joystick->nbuttons; |
| 683 | ++joystick->nbuttons; |
| 684 | } |
| 685 | } |
| 686 | for ( i=BTN_MISC; i < BTN_JOYSTICK; ++i ) { |
| 687 | if ( test_bit(i, keybit) ) { |
| 688 | #ifdef DEBUG_INPUT_EVENTS |
| 689 | printf("Joystick has button: 0x%x\n", i); |
| 690 | #endif |
| 691 | joystick->hwdata->key_map[i-BTN_MISC] = |
| 692 | joystick->nbuttons; |
| 693 | ++joystick->nbuttons; |
| 694 | } |
| 695 | } |
| 696 | for ( i=0; i<ABS_MAX; ++i ) { |
| 697 | /* Skip hats */ |
| 698 | if ( i == ABS_HAT0X ) { |
| 699 | i = ABS_HAT3Y; |
| 700 | continue; |
| 701 | } |
| 702 | if ( test_bit(i, absbit) ) { |
| 703 | int values[5]; |
| 704 | |
| 705 | if ( ioctl(fd, EVIOCGABS(i), values) < 0 ) |
| 706 | continue; |
| 707 | #ifdef DEBUG_INPUT_EVENTS |
| 708 | printf("Joystick has absolute axis: %x\n", i); |
| 709 | printf("Values = { %d, %d, %d, %d, %d }\n", |
| 710 | values[0], values[1], |
| 711 | values[2], values[3], values[4]); |
| 712 | #endif /* DEBUG_INPUT_EVENTS */ |
| 713 | joystick->hwdata->abs_map[i] = joystick->naxes; |
| 714 | if ( values[1] == values[2] ) { |
| 715 | joystick->hwdata->abs_correct[i].used = 0; |
| 716 | } else { |
| 717 | joystick->hwdata->abs_correct[i].used = 1; |
| 718 | joystick->hwdata->abs_correct[i].coef[0] = |
| 719 | (values[2] + values[1]) / 2 - values[4]; |
| 720 | joystick->hwdata->abs_correct[i].coef[1] = |
| 721 | (values[2] + values[1]) / 2 + values[4]; |
| 722 | t = ((values[2] - values[1]) / 2 - 2 * values[4]); |
| 723 | if ( t != 0 ) { |
| 724 | joystick->hwdata->abs_correct[i].coef[2] = (1 << 29) / t; |
| 725 | } else { |
| 726 | joystick->hwdata->abs_correct[i].coef[2] = 0; |
| 727 | } |
| 728 | } |
| 729 | ++joystick->naxes; |
| 730 | } |
| 731 | } |
| 732 | for ( i=ABS_HAT0X; i <= ABS_HAT3Y; i += 2 ) { |
| 733 | if ( test_bit(i, absbit) || test_bit(i+1, absbit) ) { |
| 734 | #ifdef DEBUG_INPUT_EVENTS |
| 735 | printf("Joystick has hat %d\n",(i-ABS_HAT0X)/2); |
| 736 | #endif |
| 737 | ++joystick->nhats; |
| 738 | } |
| 739 | } |
| 740 | if ( test_bit(REL_X, relbit) || test_bit(REL_Y, relbit) ) { |
| 741 | ++joystick->nballs; |
| 742 | } |
| 743 | |
| 744 | /* Allocate data to keep track of these thingamajigs */ |
| 745 | if ( joystick->nhats > 0 ) { |
| 746 | if ( allocate_hatdata(joystick) < 0 ) { |
| 747 | joystick->nhats = 0; |
| 748 | } |
| 749 | } |
| 750 | if ( joystick->nballs > 0 ) { |
| 751 | if ( allocate_balldata(joystick) < 0 ) { |
| 752 | joystick->nballs = 0; |
| 753 | } |
| 754 | } |
| 755 | } |
| 756 | return(joystick->hwdata->is_hid); |
| 757 | } |
| 758 | |
| 759 | #endif /* SDL_INPUT_LINUXEV */ |
| 760 | |
| 761 | #ifndef NO_LOGICAL_JOYSTICKS |
| 762 | static void ConfigLogicalJoystick(SDL_Joystick *joystick) |
| 763 | { |
| 764 | struct joystick_logical_layout* layout; |
| 765 | |
| 766 | layout = SDL_joylist[joystick->index].map->layout + |
| 767 | SDL_joylist[joystick->index].logicalno; |
| 768 | |
| 769 | joystick->nbuttons = layout->nbuttons; |
| 770 | joystick->nhats = layout->nhats; |
| 771 | joystick->naxes = layout->naxes; |
| 772 | joystick->nballs = layout->nballs; |
| 773 | } |
| 774 | #endif |
| 775 | |
| 776 | |
| 777 | /* Function to open a joystick for use. |
| 778 | The joystick to open is specified by the index field of the joystick. |
| 779 | This should fill the nbuttons and naxes fields of the joystick structure. |
| 780 | It returns 0, or -1 if there is an error. |
| 781 | */ |
| 782 | int SDL_SYS_JoystickOpen(SDL_Joystick *joystick) |
| 783 | { |
| 784 | int fd; |
| 785 | SDL_logical_joydecl(int realindex); |
| 786 | SDL_logical_joydecl(SDL_Joystick *realjoy = NULL); |
| 787 | |
| 788 | /* Open the joystick and set the joystick file descriptor */ |
| 789 | #ifndef NO_LOGICAL_JOYSTICKS |
| 790 | if (SDL_joylist[joystick->index].fname == NULL) { |
| 791 | SDL_joylist_head(realindex, joystick->index); |
| 792 | realjoy = SDL_JoystickOpen(realindex); |
| 793 | |
| 794 | if (realjoy == NULL) |
| 795 | return(-1); |
| 796 | |
| 797 | fd = realjoy->hwdata->fd; |
| 798 | |
| 799 | } else { |
| 800 | fd = open(SDL_joylist[joystick->index].fname, O_RDONLY, 0); |
| 801 | } |
| 802 | SDL_joylist[joystick->index].joy = joystick; |
| 803 | #else |
| 804 | fd = open(SDL_joylist[joystick->index].fname, O_RDONLY, 0); |
| 805 | #endif |
| 806 | |
| 807 | if ( fd < 0 ) { |
| 808 | SDL_SetError("Unable to open %s\n", |
| 809 | SDL_joylist[joystick->index]); |
| 810 | return(-1); |
| 811 | } |
| 812 | joystick->hwdata = (struct joystick_hwdata *) |
| 813 | SDL_malloc(sizeof(*joystick->hwdata)); |
| 814 | if ( joystick->hwdata == NULL ) { |
| 815 | SDL_OutOfMemory(); |
| 816 | close(fd); |
| 817 | return(-1); |
| 818 | } |
| 819 | SDL_memset(joystick->hwdata, 0, sizeof(*joystick->hwdata)); |
| 820 | joystick->hwdata->fd = fd; |
| 821 | |
| 822 | /* Set the joystick to non-blocking read mode */ |
| 823 | fcntl(fd, F_SETFL, O_NONBLOCK); |
| 824 | |
| 825 | /* Get the number of buttons and axes on the joystick */ |
| 826 | #ifndef NO_LOGICAL_JOYSTICKS |
| 827 | if (realjoy) |
| 828 | ConfigLogicalJoystick(joystick); |
| 829 | else |
| 830 | #endif |
| 831 | #if SDL_INPUT_LINUXEV |
| 832 | if ( ! EV_ConfigJoystick(joystick, fd) ) |
| 833 | #endif |
| 834 | JS_ConfigJoystick(joystick, fd); |
| 835 | |
| 836 | return(0); |
| 837 | } |
| 838 | |
| 839 | #ifndef NO_LOGICAL_JOYSTICKS |
| 840 | |
| 841 | static SDL_Joystick* FindLogicalJoystick( |
| 842 | SDL_Joystick *joystick, struct joystick_logical_mapping* v) |
| 843 | { |
| 844 | SDL_Joystick *logicaljoy; |
| 845 | register int i; |
| 846 | |
| 847 | i = joystick->index; |
| 848 | logicaljoy = NULL; |
| 849 | |
| 850 | /* get the fake joystick that will receive the event |
| 851 | */ |
| 852 | for(;;) { |
| 853 | |
| 854 | if (SDL_joylist[i].logicalno == v->njoy) { |
| 855 | logicaljoy = SDL_joylist[i].joy; |
| 856 | break; |
| 857 | } |
| 858 | |
| 859 | if (SDL_joylist[i].next == 0) |
| 860 | break; |
| 861 | |
| 862 | i = SDL_joylist[i].next; |
| 863 | |
| 864 | } |
| 865 | |
| 866 | return logicaljoy; |
| 867 | } |
| 868 | |
| 869 | static int LogicalJoystickButton( |
| 870 | SDL_Joystick *joystick, Uint8 button, Uint8 state){ |
| 871 | struct joystick_logical_mapping* buttons; |
| 872 | SDL_Joystick *logicaljoy = NULL; |
| 873 | |
| 874 | /* if there's no map then this is just a regular joystick |
| 875 | */ |
| 876 | if (SDL_joylist[joystick->index].map == NULL) |
| 877 | return 0; |
| 878 | |
| 879 | /* get the logical joystick that will receive the event |
| 880 | */ |
| 881 | buttons = SDL_joylist[joystick->index].map->buttonmap+button; |
| 882 | logicaljoy = FindLogicalJoystick(joystick, buttons); |
| 883 | |
| 884 | if (logicaljoy == NULL) |
| 885 | return 1; |
| 886 | |
| 887 | SDL_PrivateJoystickButton(logicaljoy, buttons->nthing, state); |
| 888 | |
| 889 | return 1; |
| 890 | } |
| 891 | |
| 892 | static int LogicalJoystickAxis( |
| 893 | SDL_Joystick *joystick, Uint8 axis, Sint16 value) |
| 894 | { |
| 895 | struct joystick_logical_mapping* axes; |
| 896 | SDL_Joystick *logicaljoy = NULL; |
| 897 | |
| 898 | /* if there's no map then this is just a regular joystick |
| 899 | */ |
| 900 | if (SDL_joylist[joystick->index].map == NULL) |
| 901 | return 0; |
| 902 | |
| 903 | /* get the logical joystick that will receive the event |
| 904 | */ |
| 905 | axes = SDL_joylist[joystick->index].map->axismap+axis; |
| 906 | logicaljoy = FindLogicalJoystick(joystick, axes); |
| 907 | |
| 908 | if (logicaljoy == NULL) |
| 909 | return 1; |
| 910 | |
| 911 | SDL_PrivateJoystickAxis(logicaljoy, axes->nthing, value); |
| 912 | |
| 913 | return 1; |
| 914 | } |
| 915 | #endif /* USE_LOGICAL_JOYSTICKS */ |
| 916 | |
| 917 | static __inline__ |
| 918 | void HandleHat(SDL_Joystick *stick, Uint8 hat, int axis, int value) |
| 919 | { |
| 920 | struct hwdata_hat *the_hat; |
| 921 | const Uint8 position_map[3][3] = { |
| 922 | { SDL_HAT_LEFTUP, SDL_HAT_UP, SDL_HAT_RIGHTUP }, |
| 923 | { SDL_HAT_LEFT, SDL_HAT_CENTERED, SDL_HAT_RIGHT }, |
| 924 | { SDL_HAT_LEFTDOWN, SDL_HAT_DOWN, SDL_HAT_RIGHTDOWN } |
| 925 | }; |
| 926 | SDL_logical_joydecl(SDL_Joystick *logicaljoy = NULL); |
| 927 | SDL_logical_joydecl(struct joystick_logical_mapping* hats = NULL); |
| 928 | |
| 929 | the_hat = &stick->hwdata->hats[hat]; |
| 930 | if ( value < 0 ) { |
| 931 | value = 0; |
| 932 | } else |
| 933 | if ( value == 0 ) { |
| 934 | value = 1; |
| 935 | } else |
| 936 | if ( value > 0 ) { |
| 937 | value = 2; |
| 938 | } |
| 939 | if ( value != the_hat->axis[axis] ) { |
| 940 | the_hat->axis[axis] = value; |
| 941 | |
| 942 | #ifndef NO_LOGICAL_JOYSTICKS |
| 943 | /* if there's no map then this is just a regular joystick |
| 944 | */ |
| 945 | if (SDL_joylist[stick->index].map != NULL) { |
| 946 | |
| 947 | /* get the fake joystick that will receive the event |
| 948 | */ |
| 949 | hats = SDL_joylist[stick->index].map->hatmap+hat; |
| 950 | logicaljoy = FindLogicalJoystick(stick, hats); |
| 951 | } |
| 952 | |
| 953 | if (logicaljoy) { |
| 954 | stick = logicaljoy; |
| 955 | hat = hats->nthing; |
| 956 | } |
| 957 | #endif /* USE_LOGICAL_JOYSTICKS */ |
| 958 | |
| 959 | SDL_PrivateJoystickHat(stick, hat, |
| 960 | position_map[the_hat->axis[1]][the_hat->axis[0]]); |
| 961 | } |
| 962 | } |
| 963 | |
| 964 | static __inline__ |
| 965 | void HandleBall(SDL_Joystick *stick, Uint8 ball, int axis, int value) |
| 966 | { |
| 967 | stick->hwdata->balls[ball].axis[axis] += value; |
| 968 | } |
| 969 | |
| 970 | /* Function to update the state of a joystick - called as a device poll. |
| 971 | * This function shouldn't update the joystick structure directly, |
| 972 | * but instead should call SDL_PrivateJoystick*() to deliver events |
| 973 | * and update joystick device state. |
| 974 | */ |
| 975 | static __inline__ void JS_HandleEvents(SDL_Joystick *joystick) |
| 976 | { |
| 977 | struct js_event events[32]; |
| 978 | int i, len; |
| 979 | Uint8 other_axis; |
| 980 | |
| 981 | #ifndef NO_LOGICAL_JOYSTICKS |
| 982 | if (SDL_joylist[joystick->index].fname == NULL) { |
| 983 | SDL_joylist_head(i, joystick->index); |
| 984 | JS_HandleEvents(SDL_joylist[i].joy); |
| 985 | return; |
| 986 | } |
| 987 | #endif |
| 988 | |
| 989 | while ((len=read(joystick->hwdata->fd, events, (sizeof events))) > 0) { |
| 990 | len /= sizeof(events[0]); |
| 991 | for ( i=0; i<len; ++i ) { |
| 992 | switch (events[i].type & ~JS_EVENT_INIT) { |
| 993 | case JS_EVENT_AXIS: |
| 994 | if ( events[i].number < joystick->naxes ) { |
| 995 | #ifndef NO_LOGICAL_JOYSTICKS |
| 996 | if (!LogicalJoystickAxis(joystick, |
| 997 | events[i].number, events[i].value)) |
| 998 | #endif |
| 999 | SDL_PrivateJoystickAxis(joystick, |
| 1000 | events[i].number, events[i].value); |
| 1001 | break; |
| 1002 | } |
| 1003 | events[i].number -= joystick->naxes; |
| 1004 | other_axis = (events[i].number / 2); |
| 1005 | if ( other_axis < joystick->nhats ) { |
| 1006 | HandleHat(joystick, other_axis, |
| 1007 | events[i].number%2, |
| 1008 | events[i].value); |
| 1009 | break; |
| 1010 | } |
| 1011 | events[i].number -= joystick->nhats*2; |
| 1012 | other_axis = (events[i].number / 2); |
| 1013 | if ( other_axis < joystick->nballs ) { |
| 1014 | HandleBall(joystick, other_axis, |
| 1015 | events[i].number%2, |
| 1016 | events[i].value); |
| 1017 | break; |
| 1018 | } |
| 1019 | break; |
| 1020 | case JS_EVENT_BUTTON: |
| 1021 | #ifndef NO_LOGICAL_JOYSTICKS |
| 1022 | if (!LogicalJoystickButton(joystick, |
| 1023 | events[i].number, events[i].value)) |
| 1024 | #endif |
| 1025 | SDL_PrivateJoystickButton(joystick, |
| 1026 | events[i].number, events[i].value); |
| 1027 | break; |
| 1028 | default: |
| 1029 | /* ?? */ |
| 1030 | break; |
| 1031 | } |
| 1032 | } |
| 1033 | } |
| 1034 | } |
| 1035 | #if SDL_INPUT_LINUXEV |
| 1036 | static __inline__ int EV_AxisCorrect(SDL_Joystick *joystick, int which, int value) |
| 1037 | { |
| 1038 | struct axis_correct *correct; |
| 1039 | |
| 1040 | correct = &joystick->hwdata->abs_correct[which]; |
| 1041 | if ( correct->used ) { |
| 1042 | if ( value > correct->coef[0] ) { |
| 1043 | if ( value < correct->coef[1] ) { |
| 1044 | return 0; |
| 1045 | } |
| 1046 | value -= correct->coef[1]; |
| 1047 | } else { |
| 1048 | value -= correct->coef[0]; |
| 1049 | } |
| 1050 | value *= correct->coef[2]; |
| 1051 | value >>= 14; |
| 1052 | } |
| 1053 | |
| 1054 | /* Clamp and return */ |
| 1055 | if ( value < -32768 ) return -32768; |
| 1056 | if ( value > 32767 ) return 32767; |
| 1057 | |
| 1058 | return value; |
| 1059 | } |
| 1060 | |
| 1061 | static __inline__ void EV_HandleEvents(SDL_Joystick *joystick) |
| 1062 | { |
| 1063 | struct input_event events[32]; |
| 1064 | int i, len; |
| 1065 | int code; |
| 1066 | |
| 1067 | #ifndef NO_LOGICAL_JOYSTICKS |
| 1068 | if (SDL_joylist[joystick->index].fname == NULL) { |
| 1069 | SDL_joylist_head(i, joystick->index); |
| 1070 | return EV_HandleEvents(SDL_joylist[i].joy); |
| 1071 | } |
| 1072 | #endif |
| 1073 | |
| 1074 | while ((len=read(joystick->hwdata->fd, events, (sizeof events))) > 0) { |
| 1075 | len /= sizeof(events[0]); |
| 1076 | for ( i=0; i<len; ++i ) { |
| 1077 | code = events[i].code; |
| 1078 | switch (events[i].type) { |
| 1079 | case EV_KEY: |
| 1080 | if ( code >= BTN_MISC ) { |
| 1081 | code -= BTN_MISC; |
| 1082 | #ifndef NO_LOGICAL_JOYSTICKS |
| 1083 | if (!LogicalJoystickButton(joystick, |
| 1084 | joystick->hwdata->key_map[code], |
| 1085 | events[i].value)) |
| 1086 | #endif |
| 1087 | SDL_PrivateJoystickButton(joystick, |
| 1088 | joystick->hwdata->key_map[code], |
| 1089 | events[i].value); |
| 1090 | } |
| 1091 | break; |
| 1092 | case EV_ABS: |
| 1093 | switch (code) { |
| 1094 | case ABS_HAT0X: |
| 1095 | case ABS_HAT0Y: |
| 1096 | case ABS_HAT1X: |
| 1097 | case ABS_HAT1Y: |
| 1098 | case ABS_HAT2X: |
| 1099 | case ABS_HAT2Y: |
| 1100 | case ABS_HAT3X: |
| 1101 | case ABS_HAT3Y: |
| 1102 | code -= ABS_HAT0X; |
| 1103 | HandleHat(joystick, code/2, code%2, |
| 1104 | events[i].value); |
| 1105 | break; |
| 1106 | default: |
| 1107 | events[i].value = EV_AxisCorrect(joystick, code, events[i].value); |
| 1108 | #ifndef NO_LOGICAL_JOYSTICKS |
| 1109 | if (!LogicalJoystickAxis(joystick, |
| 1110 | joystick->hwdata->abs_map[code], |
| 1111 | events[i].value)) |
| 1112 | #endif |
| 1113 | SDL_PrivateJoystickAxis(joystick, |
| 1114 | joystick->hwdata->abs_map[code], |
| 1115 | events[i].value); |
| 1116 | break; |
| 1117 | } |
| 1118 | break; |
| 1119 | case EV_REL: |
| 1120 | switch (code) { |
| 1121 | case REL_X: |
| 1122 | case REL_Y: |
| 1123 | code -= REL_X; |
| 1124 | HandleBall(joystick, code/2, code%2, |
| 1125 | events[i].value); |
| 1126 | break; |
| 1127 | default: |
| 1128 | break; |
| 1129 | } |
| 1130 | break; |
| 1131 | default: |
| 1132 | break; |
| 1133 | } |
| 1134 | } |
| 1135 | } |
| 1136 | } |
| 1137 | #endif /* SDL_INPUT_LINUXEV */ |
| 1138 | |
| 1139 | void SDL_SYS_JoystickUpdate(SDL_Joystick *joystick) |
| 1140 | { |
| 1141 | int i; |
| 1142 | |
| 1143 | #if SDL_INPUT_LINUXEV |
| 1144 | if ( joystick->hwdata->is_hid ) |
| 1145 | EV_HandleEvents(joystick); |
| 1146 | else |
| 1147 | #endif |
| 1148 | JS_HandleEvents(joystick); |
| 1149 | |
| 1150 | /* Deliver ball motion updates */ |
| 1151 | for ( i=0; i<joystick->nballs; ++i ) { |
| 1152 | int xrel, yrel; |
| 1153 | |
| 1154 | xrel = joystick->hwdata->balls[i].axis[0]; |
| 1155 | yrel = joystick->hwdata->balls[i].axis[1]; |
| 1156 | if ( xrel || yrel ) { |
| 1157 | joystick->hwdata->balls[i].axis[0] = 0; |
| 1158 | joystick->hwdata->balls[i].axis[1] = 0; |
| 1159 | SDL_PrivateJoystickBall(joystick, (Uint8)i, xrel, yrel); |
| 1160 | } |
| 1161 | } |
| 1162 | } |
| 1163 | |
| 1164 | /* Function to close a joystick after use */ |
| 1165 | void SDL_SYS_JoystickClose(SDL_Joystick *joystick) |
| 1166 | { |
| 1167 | #ifndef NO_LOGICAL_JOYSTICKS |
| 1168 | register int i; |
| 1169 | if (SDL_joylist[joystick->index].fname == NULL) { |
| 1170 | SDL_joylist_head(i, joystick->index); |
| 1171 | SDL_JoystickClose(SDL_joylist[i].joy); |
| 1172 | } |
| 1173 | #endif |
| 1174 | |
| 1175 | if ( joystick->hwdata ) { |
| 1176 | #ifndef NO_LOGICAL_JOYSTICKS |
| 1177 | if (SDL_joylist[joystick->index].fname != NULL) |
| 1178 | #endif |
| 1179 | close(joystick->hwdata->fd); |
| 1180 | if ( joystick->hwdata->hats ) { |
| 1181 | SDL_free(joystick->hwdata->hats); |
| 1182 | } |
| 1183 | if ( joystick->hwdata->balls ) { |
| 1184 | SDL_free(joystick->hwdata->balls); |
| 1185 | } |
| 1186 | SDL_free(joystick->hwdata); |
| 1187 | joystick->hwdata = NULL; |
| 1188 | } |
| 1189 | } |
| 1190 | |
| 1191 | /* Function to perform any system-specific joystick related cleanup */ |
| 1192 | void SDL_SYS_JoystickQuit(void) |
| 1193 | { |
| 1194 | int i; |
| 1195 | |
| 1196 | for ( i=0; SDL_joylist[i].fname; ++i ) { |
| 1197 | SDL_free(SDL_joylist[i].fname); |
| 1198 | SDL_joylist[i].fname = NULL; |
| 1199 | } |
| 1200 | } |
| 1201 | |
| 1202 | #endif /* SDL_JOYSTICK_LINUX */ |