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 "../SDL_sysjoystick.h"
42 #include "../SDL_joystick_c.h"
43 #include "SDL_sysjoystick_c.h"
46 #if !SDL_EVENTS_DISABLED
47 #include "../../events/SDL_events_c.h"
60 #define SDL_USE_LIBUDEV 1
68 static const char *udev_library =
"libudev.so.0";
69 static void *udev_handle =
NULL;
73 load_udev_sym(
const char *fn,
void **
addr)
85 static const char *(*UDEV_udev_device_get_action)(
struct udev_device *) =
NULL;
86 static const char *(*UDEV_udev_device_get_devnode)(
struct udev_device *) =
NULL;
87 static const char *(*UDEV_udev_device_get_property_value)(
struct udev_device *,
const char *) =
NULL;
88 static struct udev_device *(*UDEV_udev_device_new_from_syspath)(
struct udev *,
const char *) =
NULL;
89 static void (*UDEV_udev_device_unref)(
struct udev_device *) =
NULL;
90 static int (*UDEV_udev_enumerate_add_match_property)(
struct udev_enumerate *,
const char *,
const char *) =
NULL;
91 static int (*UDEV_udev_enumerate_add_match_subsystem)(
struct udev_enumerate *,
const char *) =
NULL;
92 static struct udev_list_entry *(*UDEV_udev_enumerate_get_list_entry)(
struct udev_enumerate *) =
NULL;
93 static struct udev_enumerate *(*UDEV_udev_enumerate_new)(
struct udev *) =
NULL;
94 static int (*UDEV_udev_enumerate_scan_devices)(
struct udev_enumerate *) =
NULL;
95 static void (*UDEV_udev_enumerate_unref)(
struct udev_enumerate *) =
NULL;
96 static const char *(*UDEV_udev_list_entry_get_name)(
struct udev_list_entry *) =
NULL;
97 static struct udev_list_entry *(*UDEV_udev_list_entry_get_next)(
struct udev_list_entry *) =
NULL;
98 static int (*UDEV_udev_monitor_enable_receiving)(
struct udev_monitor *) =
NULL;
99 static int (*UDEV_udev_monitor_filter_add_match_subsystem_devtype)(
struct udev_monitor *,
const char *,
const char *) =
NULL;
100 static int (*UDEV_udev_monitor_get_fd)(
struct udev_monitor *) =
NULL;
101 static struct udev_monitor *(*UDEV_udev_monitor_new_from_netlink)(
struct udev *,
const char *) =
NULL;
102 static struct udev_device *(*UDEV_udev_monitor_receive_device)(
struct udev_monitor *) =
NULL;
103 static void (*UDEV_udev_monitor_unref)(
struct udev_monitor *) =
NULL;
104 static struct udev *(*UDEV_udev_new)(
void) =
NULL;
105 static void (*UDEV_udev_unref)(
struct udev *) =
NULL;
111 #define SDL_UDEV_SYM(x) \
112 if (!load_udev_sym(#x, (void **) (char *) &UDEV_##x)) return -1
114 SDL_UDEV_SYM(udev_device_get_action);
115 SDL_UDEV_SYM(udev_device_get_devnode);
116 SDL_UDEV_SYM(udev_device_get_property_value);
117 SDL_UDEV_SYM(udev_device_new_from_syspath);
118 SDL_UDEV_SYM(udev_device_unref);
119 SDL_UDEV_SYM(udev_enumerate_add_match_property);
120 SDL_UDEV_SYM(udev_enumerate_add_match_subsystem);
121 SDL_UDEV_SYM(udev_enumerate_get_list_entry);
122 SDL_UDEV_SYM(udev_enumerate_new);
123 SDL_UDEV_SYM(udev_enumerate_scan_devices);
124 SDL_UDEV_SYM(udev_enumerate_unref);
125 SDL_UDEV_SYM(udev_list_entry_get_name);
126 SDL_UDEV_SYM(udev_list_entry_get_next);
127 SDL_UDEV_SYM(udev_monitor_enable_receiving);
128 SDL_UDEV_SYM(udev_monitor_filter_add_match_subsystem_devtype);
129 SDL_UDEV_SYM(udev_monitor_get_fd);
130 SDL_UDEV_SYM(udev_monitor_new_from_netlink);
131 SDL_UDEV_SYM(udev_monitor_receive_device);
132 SDL_UDEV_SYM(udev_monitor_unref);
133 SDL_UDEV_SYM(udev_new);
134 SDL_UDEV_SYM(udev_unref);
142 UnloadUDEVLibrary(
void)
144 if (udev_handle !=
NULL) {
151 LoadUDEVLibrary(
void)
154 if (udev_handle ==
NULL) {
156 if (udev_handle ==
NULL) {
160 retval = load_udev_syms();
170 static struct udev *udev =
NULL;
171 static struct udev_monitor *udev_mon =
NULL;
176 typedef struct SDL_joylist_item
184 struct SDL_joylist_item *next;
187 static SDL_joylist_item *SDL_joylist =
NULL;
188 static SDL_joylist_item *SDL_joylist_tail =
NULL;
189 static int numjoysticks = 0;
190 static int instance_counter = 0;
192 #define test_bit(nr, addr) \
193 (((1UL << ((nr) % (sizeof(long) * 8))) & ((addr)[(nr) / (sizeof(long) * 8)])) != 0)
194 #define NBITS(x) ((((x)-1)/(sizeof(long) * 8))+1)
197 IsJoystick(
int fd,
char *namebuf,
const size_t namebuflen,
SDL_JoystickGUID *guid)
199 unsigned long evbit[NBITS(EV_MAX)] = { 0 };
200 unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
201 unsigned long absbit[NBITS(ABS_MAX)] = { 0 };
202 struct input_id inpid;
205 if ((ioctl(fd, EVIOCGBIT(0,
sizeof(evbit)), evbit) < 0) ||
206 (ioctl(fd, EVIOCGBIT(EV_KEY,
sizeof(keybit)), keybit) < 0) ||
207 (ioctl(fd, EVIOCGBIT(EV_ABS,
sizeof(absbit)), absbit) < 0)) {
211 if (!(test_bit(EV_KEY, evbit) && test_bit(EV_ABS, evbit) &&
212 test_bit(ABS_X, absbit) && test_bit(ABS_Y, absbit))) {
216 if (ioctl(fd, EVIOCGNAME(namebuflen), namebuf) < 0) {
220 if (ioctl(fd,
EVIOCGID, &inpid) < 0) {
224 #ifdef DEBUG_JOYSTICK
225 printf(
"Joystick: %s, bustype = %d, vendor = 0x%x, product = 0x%x, version = %d\n", namebuf, inpid.bustype, inpid.vendor, inpid.product, inpid.version);
235 if (inpid.vendor && inpid.product && inpid.version) {
252 MaybeAddDevice(
const char *
path)
259 SDL_joylist_item *item;
265 if (stat(path, &sb) == -1) {
270 for (item = SDL_joylist; item !=
NULL; item = item->next) {
271 if (sb.st_rdev == item->devnum) {
276 fd = open(path, O_RDONLY, 0);
281 #ifdef DEBUG_INPUT_EVENTS
282 printf(
"Checking %s\n", path);
285 isstick = IsJoystick(fd, namebuf,
sizeof (namebuf), &guid);
291 item = (SDL_joylist_item *)
SDL_malloc(
sizeof (SDL_joylist_item));
297 item->devnum = sb.st_rdev;
302 if ( (item->path ==
NULL) || (item->name ==
NULL) ) {
309 item->device_instance = instance_counter++;
310 if (SDL_joylist_tail ==
NULL) {
311 SDL_joylist = SDL_joylist_tail = item;
313 SDL_joylist_tail->next = item;
314 SDL_joylist_tail = item;
317 return numjoysticks++;
323 MaybeRemoveDevice(
const char *path)
325 SDL_joylist_item *item;
326 SDL_joylist_item *prev =
NULL;
332 for (item = SDL_joylist; item !=
NULL; item = item->next) {
335 const int retval = item->device_instance;
337 item->hwdata->item =
NULL;
340 prev->next = item->next;
343 SDL_joylist = item->next;
345 if (item == SDL_joylist_tail) {
346 SDL_joylist_tail = prev;
362 JoystickInitWithoutUdev(
void)
370 for (i = 0; i < 32; i++) {
372 MaybeAddDevice(path);
381 JoystickInitWithUdev(
void)
383 struct udev_enumerate *enumerate =
NULL;
384 struct udev_list_entry *devs =
NULL;
385 struct udev_list_entry *item =
NULL;
388 udev = UDEV_udev_new();
393 udev_mon = UDEV_udev_monitor_new_from_netlink(udev,
"udev");
394 if (udev_mon !=
NULL) {
395 UDEV_udev_monitor_filter_add_match_subsystem_devtype(udev_mon,
397 UDEV_udev_monitor_enable_receiving(udev_mon);
400 enumerate = UDEV_udev_enumerate_new(udev);
401 if (enumerate ==
NULL) {
405 UDEV_udev_enumerate_add_match_subsystem(enumerate,
"input");
406 UDEV_udev_enumerate_add_match_property(enumerate,
"ID_INPUT_JOYSTICK",
"1");
407 UDEV_udev_enumerate_scan_devices(enumerate);
408 devs = UDEV_udev_enumerate_get_list_entry(enumerate);
409 for (item = devs; item; item = UDEV_udev_list_entry_get_next(item)) {
410 const char *path = UDEV_udev_list_entry_get_name(item);
411 struct udev_device *dev = UDEV_udev_device_new_from_syspath(udev, path);
412 MaybeAddDevice(UDEV_udev_device_get_devnode(dev));
413 UDEV_udev_device_unref(dev);
416 UDEV_udev_enumerate_unref(enumerate);
427 char *envcopy, *envpath, *delim;
430 while (envpath !=
NULL) {
435 MaybeAddDevice(envpath);
442 if (LoadUDEVLibrary() == 0) {
443 return JoystickInitWithUdev();
447 return JoystickInitWithoutUdev();
456 HotplugUpdateAvailable(
void)
459 if (udev_mon !=
NULL) {
460 const int fd = UDEV_udev_monitor_get_fd(udev_mon);
468 if ((select(fd+1, &fds,
NULL,
NULL, &tv) > 0) && (FD_ISSET(fd, &fds))) {
480 struct udev_device *dev =
NULL;
481 const char *devnode =
NULL;
482 const char *action =
NULL;
485 while (HotplugUpdateAvailable()) {
486 dev = UDEV_udev_monitor_receive_device(udev_mon);
490 val = UDEV_udev_device_get_property_value(dev,
"ID_INPUT_JOYSTICK");
495 action = UDEV_udev_device_get_action(dev);
496 devnode = UDEV_udev_device_get_devnode(dev);
499 const int device_index = MaybeAddDevice(devnode);
500 if (device_index != -1) {
502 #if !SDL_EVENTS_DISABLED
507 event.jdevice.which = device_index;
515 }
else if (
SDL_strcmp(action,
"remove") == 0) {
516 const int inst = MaybeRemoveDevice(devnode);
519 #if !SDL_EVENTS_DISABLED
524 event.jdevice.which = inst;
533 UDEV_udev_device_unref(dev);
547 return HotplugUpdateAvailable();
550 static SDL_joylist_item *
551 JoystickByDevIndex(
int device_index)
553 SDL_joylist_item *item = SDL_joylist;
555 if ((device_index < 0) || (device_index >= numjoysticks)) {
559 while (device_index > 0) {
572 return JoystickByDevIndex(device_index)->name;
578 return JoystickByDevIndex(device_index)->device_instance;
588 sizeof(
struct hwdata_hat));
592 for (i = 0; i < joystick->
nhats; ++
i) {
606 sizeof(
struct hwdata_ball));
610 for (i = 0; i < joystick->
nballs; ++
i) {
621 unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
622 unsigned long absbit[NBITS(ABS_MAX)] = { 0 };
623 unsigned long relbit[NBITS(REL_MAX)] = { 0 };
626 if ((ioctl(fd, EVIOCGBIT(EV_KEY,
sizeof(keybit)), keybit) >= 0) &&
627 (ioctl(fd, EVIOCGBIT(EV_ABS,
sizeof(absbit)), absbit) >= 0) &&
628 (ioctl(fd, EVIOCGBIT(EV_REL,
sizeof(relbit)), relbit) >= 0)) {
631 for (i = BTN_JOYSTICK; i < KEY_MAX; ++
i) {
632 if (test_bit(i, keybit)) {
633 #ifdef DEBUG_INPUT_EVENTS
634 printf(
"Joystick has button: 0x%x\n", i);
640 for (i = BTN_MISC; i < BTN_JOYSTICK; ++
i) {
641 if (test_bit(i, keybit)) {
642 #ifdef DEBUG_INPUT_EVENTS
643 printf(
"Joystick has button: 0x%x\n", i);
649 for (i = 0; i < ABS_MISC; ++
i) {
651 if (i == ABS_HAT0X) {
655 if (test_bit(i, absbit)) {
656 struct input_absinfo absinfo;
658 if (ioctl(fd, EVIOCGABS(i), &absinfo) < 0)
660 #ifdef DEBUG_INPUT_EVENTS
661 printf(
"Joystick has absolute axis: %x\n", i);
662 printf(
"Values = { %d, %d, %d, %d, %d }\n",
663 absinfo.value, absinfo.minimum, absinfo.maximum,
664 absinfo.fuzz, absinfo.flat);
667 if (absinfo.minimum == absinfo.maximum) {
672 (absinfo.maximum + absinfo.minimum) - 2 * absinfo.flat;
674 (absinfo.maximum + absinfo.minimum) + 2 * absinfo.flat;
675 t = ((absinfo.maximum - absinfo.minimum) - 4 * absinfo.flat);
686 for (i = ABS_HAT0X; i <= ABS_HAT3Y; i += 2) {
687 if (test_bit(i, absbit) || test_bit(i + 1, absbit)) {
688 #ifdef DEBUG_INPUT_EVENTS
689 printf(
"Joystick has hat %d\n", (i - ABS_HAT0X) / 2);
694 if (test_bit(REL_X, relbit) || test_bit(REL_Y, relbit)) {
699 if (joystick->
nhats > 0) {
700 if (allocate_hatdata(joystick) < 0) {
704 if (joystick->
nballs > 0) {
705 if (allocate_balldata(joystick) < 0) {
721 SDL_joylist_item *item = JoystickByDevIndex(device_index);
730 fd = open(fname, O_RDONLY, 0);
755 item->hwdata = joystick->
hwdata;
758 fcntl(fd, F_SETFL, O_NONBLOCK);
761 ConfigJoystick(joystick, fd);
778 struct hwdata_hat *the_hat;
779 const Uint8 position_map[3][3] = {
788 }
else if (value == 0) {
790 }
else if (value > 0) {
793 if (value != the_hat->axis[axis]) {
794 the_hat->axis[axis] =
value;
796 position_map[the_hat->
797 axis[1]][the_hat->axis[0]]);
809 AxisCorrect(
SDL_Joystick * joystick,
int which,
int value)
811 struct axis_correct *correct;
816 if (value > correct->coef[0]) {
820 value -= correct->
coef[1];
822 value -= correct->coef[0];
824 value *= correct->coef[2];
840 struct input_absinfo absinfo;
844 for (a = ABS_X; b < ABS_MAX; a++) {
858 if (ioctl(joystick->
hwdata->
fd, EVIOCGABS(a), &absinfo) >= 0) {
859 absinfo.value = AxisCorrect(joystick, b, absinfo.value);
861 #ifdef DEBUG_INPUT_EVENTS
862 printf(
"Joystick : Re-read Axis %d (%d) val= %d\n",
878 struct input_event events[32];
883 PollAllValues(joystick);
887 while ((len = read(joystick->
hwdata->
fd, events, (
sizeof events))) > 0) {
888 len /=
sizeof(events[0]);
889 for (i = 0; i <
len; ++
i) {
890 code = events[
i].code;
891 switch (events[i].
type) {
893 if (code >= BTN_MISC) {
901 if (code >= ABS_MISC) {
915 HandleHat(joystick, code / 2, code % 2, events[i].value);
919 AxisCorrect(joystick, code, events[i].value);
931 HandleBall(joystick, code / 2, code % 2, events[i].value);
940 #ifdef DEBUG_INPUT_EVENTS
941 printf(
"Event SYN_DROPPED detected\n");
943 PollAllValues(joystick);
960 HandleInputEvents(joystick);
963 for (i = 0; i < joystick->
nballs; ++
i) {
998 SDL_joylist_item *item =
NULL;
999 SDL_joylist_item *next =
NULL;
1001 for (item = SDL_joylist; item; item = next) {
1008 SDL_joylist = SDL_joylist_tail =
NULL;
1011 instance_counter = 0;
1014 if (udev_mon !=
NULL) {
1015 UDEV_udev_monitor_unref(udev_mon);
1019 UDEV_udev_unref(udev);
1022 UnloadUDEVLibrary();
1028 return JoystickByDevIndex(device_index)->guid;
struct joystick_hwdata::hwdata_ball * balls
GLuint const GLfloat * val
DECLSPEC int SDLCALL SDL_PushEvent(SDL_Event *event)
Add an event to the event queue.
GLint GLenum GLsizei GLsizei GLsizei GLint GLenum GLenum type
GLvoid **typedef void(GLAPIENTRY *PFNGLGETVERTEXATTRIBDVPROC)(GLuint
int SDL_PrivateJoystickHat(SDL_Joystick *joystick, Uint8 hat, Uint8 value)
int SDL_SYS_NumJoysticks()
DECLSPEC int SDLCALL SDL_snprintf(char *text, size_t maxlen, const char *fmt,...)
DECLSPEC void SDLCALL SDL_free(void *mem)
int SDL_PrivateJoystickButton(SDL_Joystick *joystick, Uint8 button, Uint8 state)
GLboolean GLboolean GLboolean GLboolean a
EGLImageKHR EGLint * name
void SDL_SYS_JoystickQuit(void)
DECLSPEC char *SDLCALL SDL_strchr(const char *str, int c)
GLsizei const GLchar *const * path
struct joystick_hwdata * hwdata
int SDL_PrivateJoystickAxis(SDL_Joystick *joystick, Uint8 axis, Sint16 value)
int SDL_PrivateJoystickBall(SDL_Joystick *joystick, Uint8 ball, Sint16 xrel, Sint16 yrel)
#define SDL_HAT_RIGHTDOWN
#define SDL_GetEventState(type)
DECLSPEC char *SDLCALL SDL_strdup(const char *str)
SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick)
SDL_EventFilter SDL_EventOK
DECLSPEC void *SDLCALL SDL_LoadObject(const char *sofile)
DECLSPEC size_t SDLCALL SDL_strlcpy(char *dst, const char *src, size_t maxlen)
DECLSPEC void *SDLCALL SDL_memset(void *dst, int c, size_t len)
void SDL_SYS_JoystickDetect()
DECLSPEC void SDLCALL SDL_UnloadObject(void *handle)
DECLSPEC int SDLCALL SDL_SetError(const char *fmt,...)
DECLSPEC void *SDLCALL SDL_malloc(size_t size)
const char * SDL_SYS_JoystickNameForDeviceIndex(int device_index)
DECLSPEC int SDLCALL SDL_strcmp(const char *str1, const char *str2)
struct SDL_joylist_item * item
void SDL_SYS_JoystickUpdate(SDL_Joystick *joystick)
SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick *joystick)
SDL_bool SDL_SYS_JoystickNeedsPolling()
#define SDL_assert(condition)
int SDL_SYS_JoystickInit(void)
#define SDL_OutOfMemory()
#define SDL_arraysize(array)
Uint8 key_map[KEY_MAX-BTN_MISC]
EGLSurface EGLint void ** value
uint8_t Uint8
An unsigned 8-bit integer type.
SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index)
GLdouble GLdouble GLdouble b
int SDL_SYS_JoystickOpen(SDL_Joystick *joystick, int device_index)
uint16_t Uint16
An unsigned 16-bit integer type.
struct joystick_hwdata::axis_correct abs_correct[ABS_MAX]
DECLSPEC char *SDLCALL SDL_getenv(const char *name)
DECLSPEC void *SDLCALL SDL_LoadFunction(void *handle, const char *name)
void SDL_SYS_JoystickClose(SDL_Joystick *joystick)
SDL_JoystickID instance_id
SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID(int device_index)