21 #include "../../SDL_internal.h" 23 #ifdef SDL_JOYSTICK_LINUX 25 #ifndef SDL_INPUT_LINUXEV 26 #error SDL now requires a Linux 2.4+ kernel with /dev/input/event support. 34 #include <sys/ioctl.h> 36 #include <linux/joystick.h> 41 #include "../../events/SDL_events_c.h" 42 #include "../SDL_sysjoystick.h" 43 #include "../SDL_joystick_c.h" 44 #include "../steam/SDL_steamcontroller.h" 45 #include "SDL_sysjoystick_c.h" 52 #include "../../core/linux/SDL_udev.h" 54 static int MaybeAddDevice(
const char *
path);
56 static int MaybeRemoveDevice(
const char *
path);
57 static void joystick_udev_callback(SDL_UDEV_deviceevent udev_type,
int udev_class,
const char *devpath);
62 typedef struct SDL_joylist_item
70 struct SDL_joylist_item *next;
76 static SDL_joylist_item *SDL_joylist =
NULL;
77 static SDL_joylist_item *SDL_joylist_tail =
NULL;
79 static int instance_counter = 0;
82 #define test_bit(nr, addr) \ 83 (((1UL << ((nr) % (sizeof(long) * 8))) & ((addr)[(nr) / (sizeof(long) * 8)])) != 0) 84 #define NBITS(x) ((((x)-1)/(sizeof(long) * 8))+1) 92 static Uint32 joystick_blacklist[] = {
181 struct input_id inpid;
188 unsigned long evbit[NBITS(EV_MAX)] = { 0 };
189 unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
190 unsigned long absbit[NBITS(ABS_MAX)] = { 0 };
192 if ((ioctl(fd, EVIOCGBIT(0,
sizeof(evbit)), evbit) < 0) ||
193 (ioctl(fd, EVIOCGBIT(EV_KEY,
sizeof(keybit)), keybit) < 0) ||
194 (ioctl(fd, EVIOCGBIT(EV_ABS,
sizeof(absbit)), absbit) < 0)) {
198 if (!(test_bit(EV_KEY, evbit) && test_bit(EV_ABS, evbit) &&
199 test_bit(ABS_X, absbit) && test_bit(ABS_Y, absbit))) {
204 if (ioctl(fd, EVIOCGNAME(namebuflen), namebuf) < 0) {
208 if (ioctl(fd, EVIOCGID, &inpid) < 0) {
215 if (
id == joystick_blacklist[i]) {
220 #ifdef DEBUG_JOYSTICK 221 printf(
"Joystick: %s, bustype = %d, vendor = 0x%.4x, product = 0x%.4x, version = %d\n", namebuf, inpid.bustype, inpid.vendor, inpid.product, inpid.version);
231 if (inpid.vendor && inpid.product) {
250 static void joystick_udev_callback(SDL_UDEV_deviceevent udev_type,
int udev_class,
const char *devpath)
252 if (devpath ==
NULL) {
257 case SDL_UDEV_DEVICEADDED:
258 if (!(udev_class & SDL_UDEV_DEVICE_JOYSTICK)) {
261 MaybeAddDevice(devpath);
264 case SDL_UDEV_DEVICEREMOVED:
265 MaybeRemoveDevice(devpath);
278 MaybeAddDevice(
const char *
path)
285 SDL_joylist_item *item;
291 if (stat(path, &sb) == -1) {
296 for (item = SDL_joylist; item !=
NULL; item = item->next) {
297 if (sb.st_rdev == item->devnum) {
302 fd = open(path, O_RDONLY, 0);
307 #ifdef DEBUG_INPUT_EVENTS 308 printf(
"Checking %s\n", path);
311 isstick = IsJoystick(fd, namebuf,
sizeof (namebuf), &guid);
317 item = (SDL_joylist_item *)
SDL_malloc(
sizeof (SDL_joylist_item));
323 item->devnum = sb.st_rdev;
328 if ( (item->path ==
NULL) || (item->name ==
NULL) ) {
335 item->device_instance = instance_counter++;
336 if (SDL_joylist_tail ==
NULL) {
337 SDL_joylist = SDL_joylist_tail = item;
339 SDL_joylist_tail->next = item;
340 SDL_joylist_tail = item;
354 MaybeRemoveDevice(
const char *path)
356 SDL_joylist_item *item;
357 SDL_joylist_item *prev =
NULL;
363 for (item = SDL_joylist; item !=
NULL; item = item->next) {
366 const int retval = item->device_instance;
368 item->hwdata->item =
NULL;
371 prev->next = item->next;
374 SDL_joylist = item->next;
376 if (item == SDL_joylist_tail) {
377 SDL_joylist_tail = prev;
397 #if ! SDL_USE_LIBUDEV 399 JoystickInitWithoutUdev(
void)
407 for (i = 0; i < 32; i++) {
409 MaybeAddDevice(path);
418 JoystickInitWithUdev(
void)
420 if (SDL_UDEV_Init() < 0) {
425 if (SDL_UDEV_AddCallback(joystick_udev_callback) < 0) {
427 return SDL_SetError(
"Could not set up joystick <-> udev callback");
439 SDL_joylist_item *item;
441 item = (SDL_joylist_item *)
SDL_calloc(1,
sizeof (SDL_joylist_item));
449 item->m_bSteamController =
SDL_TRUE;
451 if ((item->path ==
NULL) || (item->name ==
NULL)) {
458 *device_instance = item->device_instance = instance_counter++;
459 if (SDL_joylist_tail ==
NULL) {
460 SDL_joylist = SDL_joylist_tail = item;
462 SDL_joylist_tail->next = item;
463 SDL_joylist_tail = item;
476 SDL_joylist_item *item;
477 SDL_joylist_item *prev =
NULL;
479 for (item = SDL_joylist; item !=
NULL; item = item->next) {
481 if (item->device_instance == device_instance) {
483 item->hwdata->item =
NULL;
486 prev->next = item->next;
489 SDL_joylist = item->next;
491 if (item == SDL_joylist_tail) {
492 SDL_joylist_tail = prev;
513 char *envcopy, *envpath, *delim;
516 while (envpath !=
NULL) {
521 MaybeAddDevice(envpath);
531 return JoystickInitWithUdev();
533 return JoystickInitWithoutUdev();
553 static SDL_joylist_item *
554 JoystickByDevIndex(
int device_index)
556 SDL_joylist_item *item = SDL_joylist;
558 if ((device_index < 0) || (device_index >=
numjoysticks)) {
562 while (device_index > 0) {
575 return JoystickByDevIndex(device_index)->name;
581 return JoystickByDevIndex(device_index)->device_instance;
585 allocate_hatdata(SDL_Joystick * joystick)
589 joystick->hwdata->hats =
590 (
struct hwdata_hat *)
SDL_malloc(joystick->nhats *
591 sizeof(
struct hwdata_hat));
592 if (joystick->hwdata->hats ==
NULL) {
595 for (i = 0; i < joystick->nhats; ++
i) {
596 joystick->hwdata->hats[
i].axis[0] = 1;
597 joystick->hwdata->hats[
i].axis[1] = 1;
603 allocate_balldata(SDL_Joystick * joystick)
607 joystick->hwdata->balls =
608 (
struct hwdata_ball *)
SDL_malloc(joystick->nballs *
609 sizeof(
struct hwdata_ball));
610 if (joystick->hwdata->balls ==
NULL) {
613 for (i = 0; i < joystick->nballs; ++
i) {
614 joystick->hwdata->balls[
i].axis[0] = 0;
615 joystick->hwdata->balls[
i].axis[1] = 0;
621 ConfigJoystick(SDL_Joystick * joystick,
int fd)
624 unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
625 unsigned long absbit[NBITS(ABS_MAX)] = { 0 };
626 unsigned long relbit[NBITS(REL_MAX)] = { 0 };
629 if ((ioctl(fd, EVIOCGBIT(EV_KEY,
sizeof(keybit)), keybit) >= 0) &&
630 (ioctl(fd, EVIOCGBIT(EV_ABS,
sizeof(absbit)), absbit) >= 0) &&
631 (ioctl(fd, EVIOCGBIT(EV_REL,
sizeof(relbit)), relbit) >= 0)) {
634 for (i = BTN_JOYSTICK; i < KEY_MAX; ++
i) {
635 if (test_bit(i, keybit)) {
636 #ifdef DEBUG_INPUT_EVENTS 637 printf(
"Joystick has button: 0x%x\n", i);
639 joystick->hwdata->key_map[
i] = joystick->nbuttons;
640 ++joystick->nbuttons;
643 for (i = 0; i < BTN_JOYSTICK; ++
i) {
644 if (test_bit(i, keybit)) {
645 #ifdef DEBUG_INPUT_EVENTS 646 printf(
"Joystick has button: 0x%x\n", i);
648 joystick->hwdata->key_map[
i] = joystick->nbuttons;
649 ++joystick->nbuttons;
652 for (i = 0; i < ABS_MAX; ++
i) {
654 if (i == ABS_HAT0X) {
658 if (test_bit(i, absbit)) {
659 struct input_absinfo absinfo;
661 if (ioctl(fd, EVIOCGABS(i), &absinfo) < 0) {
664 #ifdef DEBUG_INPUT_EVENTS 665 printf(
"Joystick has absolute axis: 0x%.2x\n", i);
666 printf(
"Values = { %d, %d, %d, %d, %d }\n",
667 absinfo.value, absinfo.minimum, absinfo.maximum,
668 absinfo.fuzz, absinfo.flat);
670 joystick->hwdata->abs_map[
i] = joystick->naxes;
671 if (absinfo.minimum == absinfo.maximum) {
672 joystick->hwdata->abs_correct[
i].used = 0;
674 joystick->hwdata->abs_correct[
i].used = 1;
675 joystick->hwdata->abs_correct[
i].coef[0] =
676 (absinfo.maximum + absinfo.minimum) - 2 * absinfo.flat;
677 joystick->hwdata->abs_correct[i].coef[1] =
678 (absinfo.maximum + absinfo.minimum) + 2 * absinfo.flat;
679 t = ((absinfo.maximum - absinfo.minimum) - 4 * absinfo.flat);
681 joystick->hwdata->abs_correct[
i].coef[2] =
684 joystick->hwdata->abs_correct[
i].coef[2] = 0;
690 for (i = ABS_HAT0X; i <= ABS_HAT3Y; i += 2) {
691 if (test_bit(i, absbit) || test_bit(i + 1, absbit)) {
692 struct input_absinfo absinfo;
694 if (ioctl(fd, EVIOCGABS(i), &absinfo) < 0) {
697 #ifdef DEBUG_INPUT_EVENTS 698 printf(
"Joystick has hat %d\n", (i - ABS_HAT0X) / 2);
699 printf(
"Values = { %d, %d, %d, %d, %d }\n",
700 absinfo.value, absinfo.minimum, absinfo.maximum,
701 absinfo.fuzz, absinfo.flat);
706 if (test_bit(REL_X, relbit) || test_bit(REL_Y, relbit)) {
711 if (joystick->nhats > 0) {
712 if (allocate_hatdata(joystick) < 0) {
716 if (joystick->nballs > 0) {
717 if (allocate_balldata(joystick) < 0) {
718 joystick->nballs = 0;
733 SDL_joylist_item *item = JoystickByDevIndex(device_index);
739 joystick->instance_id = item->device_instance;
742 if (joystick->hwdata ==
NULL) {
745 joystick->hwdata->item =
item;
746 joystick->hwdata->guid = item->guid;
747 joystick->hwdata->m_bSteamController = item->m_bSteamController;
749 if (item->m_bSteamController) {
750 joystick->hwdata->fd = -1;
755 int fd = open(item->path, O_RDONLY, 0);
758 joystick->hwdata =
NULL;
762 joystick->hwdata->fd =
fd;
763 joystick->hwdata->fname =
SDL_strdup(item->path);
764 if (joystick->hwdata->fname ==
NULL) {
766 joystick->hwdata =
NULL;
772 fcntl(fd, F_SETFL, O_NONBLOCK);
775 ConfigJoystick(joystick, fd);
779 item->hwdata = joystick->hwdata;
782 joystick->hwdata->fresh = 1;
790 return joystick->hwdata->item !=
NULL;
796 struct hwdata_hat *the_hat;
797 const Uint8 position_map[3][3] = {
803 the_hat = &stick->hwdata->hats[hat];
806 }
else if (value == 0) {
808 }
else if (value > 0) {
811 if (value != the_hat->axis[axis]) {
814 position_map[the_hat->
815 axis[1]][the_hat->axis[0]]);
820 HandleBall(SDL_Joystick * stick,
Uint8 ball,
int axis,
int value)
822 stick->hwdata->balls[ball].axis[
axis] +=
value;
827 AxisCorrect(SDL_Joystick * joystick,
int which,
int value)
829 struct axis_correct *correct;
831 correct = &joystick->hwdata->abs_correct[which];
834 if (value > correct->coef[0]) {
838 value -= correct->coef[1];
840 value -= correct->coef[0];
842 value *= correct->coef[2];
856 PollAllValues(SDL_Joystick * joystick)
858 struct input_absinfo absinfo;
862 for (a = ABS_X; b < ABS_MAX; a++) {
875 if (joystick->hwdata->abs_correct[b].used) {
876 if (ioctl(joystick->hwdata->fd, EVIOCGABS(a), &absinfo) >= 0) {
877 absinfo.value = AxisCorrect(joystick, b, absinfo.value);
879 #ifdef DEBUG_INPUT_EVENTS 880 printf(
"Joystick : Re-read Axis %d (%d) val= %d\n",
881 joystick->hwdata->abs_map[b], a, absinfo.value);
884 joystick->hwdata->abs_map[b],
894 HandleInputEvents(SDL_Joystick * joystick)
896 struct input_event
events[32];
900 if (joystick->hwdata->fresh) {
901 PollAllValues(joystick);
902 joystick->hwdata->fresh = 0;
905 while ((len = read(joystick->hwdata->fd,
events, (
sizeof events))) > 0) {
907 for (i = 0; i <
len; ++
i) {
912 joystick->hwdata->key_map[code],
926 HandleHat(joystick, code / 2, code % 2,
events[i].value);
930 AxisCorrect(joystick, code,
events[i].value);
932 joystick->hwdata->abs_map[code],
942 HandleBall(joystick, code / 2, code % 2,
events[i].value);
951 #ifdef DEBUG_INPUT_EVENTS 952 printf(
"Event SYN_DROPPED detected\n");
954 PollAllValues(joystick);
971 if (joystick->hwdata->m_bSteamController) {
976 HandleInputEvents(joystick);
979 for (i = 0; i < joystick->nballs; ++
i) {
982 xrel = joystick->hwdata->balls[
i].axis[0];
983 yrel = joystick->hwdata->balls[
i].axis[1];
985 joystick->hwdata->balls[
i].axis[0] = 0;
986 joystick->hwdata->balls[
i].axis[1] = 0;
996 if (joystick->hwdata) {
997 if (joystick->hwdata->fd >= 0) {
998 close(joystick->hwdata->fd);
1000 if (joystick->hwdata->item) {
1001 joystick->hwdata->item->hwdata =
NULL;
1014 SDL_joylist_item *item =
NULL;
1015 SDL_joylist_item *next =
NULL;
1017 for (item = SDL_joylist; item; item = next) {
1024 SDL_joylist = SDL_joylist_tail =
NULL;
1027 instance_counter = 0;
1030 SDL_UDEV_DelCallback(joystick_udev_callback);
1039 return JoystickByDevIndex(device_index)->guid;
1044 return joystick->hwdata->guid;
void SDL_UpdateSteamControllers(void)
#define MAKE_VIDPID(VID, PID)
void SDL_PrivateJoystickRemoved(SDL_JoystickID device_instance)
int SDL_PrivateJoystickHat(SDL_Joystick *joystick, Uint8 hat, Uint8 value)
void SDL_InitSteamControllers(SteamControllerConnectedCallback_t connectedCallback, SteamControllerDisconnectedCallback_t disconnectedCallback)
static void SteamControllerDisconnectedCallback(int device_instance)
void SDL_QuitSteamControllers(void)
static SDL_Event events[EVENT_BUF_SIZE]
int SDL_PrivateJoystickButton(SDL_Joystick *joystick, Uint8 button, Uint8 state)
void SDL_SYS_JoystickQuit(void)
int SDL_PrivateJoystickAxis(SDL_Joystick *joystick, Uint8 axis, Sint16 value)
GLuint const GLchar * name
int SDL_PrivateJoystickBall(SDL_Joystick *joystick, Uint8 ball, Sint16 xrel, Sint16 yrel)
#define SDL_HAT_RIGHTDOWN
SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick)
SDL_bool SDL_ShouldIgnoreGameController(const char *name, SDL_JoystickGUID guid)
GLsizei const GLfloat * value
void SDL_PrivateJoystickAdded(int device_index)
const char * SDL_SYS_JoystickNameForDeviceIndex(int device_index)
void SDL_SYS_JoystickUpdate(SDL_Joystick *joystick)
SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick *joystick)
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
SDL_bool SDL_IsGameControllerNameAndGUID(const char *name, SDL_JoystickGUID guid)
static SDL_bool SteamControllerConnectedCallback(const char *name, SDL_JoystickGUID guid, int *device_instance)
#define SDL_assert(condition)
int SDL_SYS_JoystickInit(void)
void SDL_UpdateSteamController(SDL_Joystick *joystick)
#define SDL_OutOfMemory()
int SDL_SYS_NumJoysticks(void)
struct SDL_joylist_item * item
SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index)
GLuint GLuint GLsizei GLenum type
void SDL_GetSteamControllerInputs(int *nbuttons, int *naxes, int *nhats)
#define SDL_arraysize(array)
int SDL_SYS_JoystickOpen(SDL_Joystick *joystick, int device_index)
GLsizei const GLchar *const * path
void SDL_SYS_JoystickClose(SDL_Joystick *joystick)
GLboolean GLboolean GLboolean GLboolean a
GLboolean GLboolean GLboolean b
SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID(int device_index)
void SDL_SYS_JoystickDetect(void)