34#include <sys/inotify.h>
50static void handleKeyEvent(
_GLFWjoystick* js,
int code,
int value)
53 js->linjs.keyMap[code - BTN_MISC],
59static void handleAbsEvent(
_GLFWjoystick* js,
int code,
int value)
61 const int index = js->linjs.absMap[code];
63 if (code >= ABS_HAT0X && code <= ABS_HAT3Y)
65 static const char stateMap[3][3] =
72 const int hat = (code - ABS_HAT0X) / 2;
73 const int axis = (code - ABS_HAT0X) % 2;
74 int* state = js->linjs.
hats[hat];
89 const struct input_absinfo* info = &js->linjs.absInfo[code];
90 float normalized = value;
92 const int range = info->maximum - info->minimum;
96 normalized = (normalized - info->minimum) / range;
98 normalized = normalized * 2.0f - 1.0f;
109 for (
int code = 0; code < ABS_CNT; code++)
111 if (js->linjs.absMap[code] < 0)
114 struct input_absinfo* info = &js->linjs.absInfo[code];
116 if (ioctl(js->linjs.fd, EVIOCGABS(code), info) < 0)
119 handleAbsEvent(js, code, info->value);
123#define isBitSet(bit, arr) (arr[(bit) / 8] & (1 << ((bit) % 8)))
127static GLFWbool openJoystickDevice(
const char* path)
138 linjs.
fd = open(path, O_RDONLY | O_NONBLOCK);
142 char evBits[(EV_CNT + 7) / 8] = {0};
143 char keyBits[(KEY_CNT + 7) / 8] = {0};
144 char absBits[(ABS_CNT + 7) / 8] = {0};
147 if (ioctl(linjs.
fd, EVIOCGBIT(0,
sizeof(evBits)), evBits) < 0 ||
148 ioctl(linjs.
fd, EVIOCGBIT(EV_KEY,
sizeof(keyBits)), keyBits) < 0 ||
149 ioctl(linjs.
fd, EVIOCGBIT(EV_ABS,
sizeof(absBits)), absBits) < 0 ||
150 ioctl(linjs.
fd, EVIOCGID, &
id) < 0)
153 "Linux: Failed to query input device: %s",
168 if (ioctl(linjs.
fd, EVIOCGNAME(
sizeof(name)), name) < 0)
169 strncpy(name,
"Unknown",
sizeof(name));
174 if (
id.vendor &&
id.product &&
id.version)
176 sprintf(guid,
"%02x%02x0000%02x%02x0000%02x%02x0000%02x%02x0000",
177 id.bustype & 0xff,
id.bustype >> 8,
178 id.vendor & 0xff,
id.vendor >> 8,
179 id.product & 0xff,
id.product >> 8,
180 id.version & 0xff,
id.version >> 8);
184 sprintf(guid,
"%02x%02x0000%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x00",
185 id.bustype & 0xff,
id.bustype >> 8,
186 name[0], name[1], name[2], name[3],
187 name[4], name[5], name[6], name[7],
188 name[8], name[9], name[10]);
191 int axisCount = 0, buttonCount = 0, hatCount = 0;
193 for (
int code = BTN_MISC; code < KEY_CNT; code++)
198 linjs.
keyMap[code - BTN_MISC] = buttonCount;
202 for (
int code = 0; code < ABS_CNT; code++)
208 if (code >= ABS_HAT0X && code <= ABS_HAT3Y)
210 linjs.
absMap[code] = hatCount;
217 if (ioctl(linjs.
fd, EVIOCGABS(code), &linjs.
absInfo[code]) < 0)
220 linjs.
absMap[code] = axisCount;
233 strncpy(linjs.
path, path,
sizeof(linjs.
path) - 1);
234 memcpy(&js->linjs, &linjs,
sizeof(linjs));
255static int compareJoysticks(
const void* fp,
const void* sp)
259 return strcmp(fj->linjs.path, sj->linjs.path);
269 if (
_glfw.linjs.inotify <= 0)
274 const ssize_t size = read(
_glfw.linjs.inotify, buffer,
sizeof(buffer));
276 while (size > offset)
279 const struct inotify_event* e = (
struct inotify_event*) (buffer + offset);
281 offset +=
sizeof(
struct inotify_event) + e->len;
283 if (regexec(&
_glfw.linjs.regex, e->name, 1, &match, 0) != 0)
287 snprintf(path,
sizeof(path),
"/dev/input/%s", e->name);
289 if (e->mask & (IN_CREATE | IN_ATTRIB))
290 openJoystickDevice(path);
291 else if (e->mask & IN_DELETE)
312 const char* dirname =
"/dev/input";
314 _glfw.linjs.inotify = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
315 if (
_glfw.linjs.inotify > 0)
320 _glfw.linjs.watch = inotify_add_watch(
_glfw.linjs.inotify,
322 IN_CREATE | IN_ATTRIB | IN_DELETE);
327 if (regcomp(&
_glfw.linjs.regex,
"^event[0-9]\\+$", 0) != 0)
344 if (regexec(&
_glfw.linjs.regex, entry->
d_name, 1, &match, 0) != 0)
349 snprintf(path,
sizeof(path),
"%s/%s", dirname, entry->
d_name);
351 if (openJoystickDevice(path))
375 if (
_glfw.linjs.inotify > 0)
377 if (
_glfw.linjs.watch > 0)
378 inotify_rm_watch(
_glfw.linjs.inotify,
_glfw.linjs.watch);
380 close(
_glfw.linjs.inotify);
381 regfree(&
_glfw.linjs.regex);
390 struct input_event e;
393 if (read(js->linjs.fd, &e,
sizeof(e)) < 0)
402 if (e.type == EV_SYN)
406 else if (e.code == SYN_REPORT)
413 if (
_glfw.linjs.dropped)
416 if (e.type == EV_KEY)
417 handleKeyEvent(js, e.code, e.value);
418 else if (e.type == EV_ABS)
419 handleAbsEvent(js, e.code, e.value);
DIR * opendir(const char *name)
struct dirent * readdir(DIR *dir)
#define GLFW_DISCONNECTED
#define GLFW_PLATFORM_ERROR
A platform-specific error occurred that does not match any of the more specific categories.
#define GLFW_HAT_LEFT_DOWN
#define GLFW_HAT_RIGHT_UP
#define GLFW_HAT_RIGHT_DOWN
#define GLFW_HAT_CENTERED
#define GLFW_JOYSTICK_LAST
void _glfwInputError(int code, const char *format,...)
void _glfwPlatformTerminateJoysticks(void)
int _glfwPlatformPollJoystick(_GLFWjoystick *js, int mode)
#define isBitSet(bit, arr)
GLFWbool _glfwPlatformInitJoysticks(void)
void _glfwPlatformUpdateGamepadGUID(char *guid)
void _glfwDetectJoystickConnectionLinux(void)
struct input_absinfo absInfo[ABS_CNT]
int keyMap[KEY_CNT - BTN_MISC]
_GLFWjoystick joysticks[GLFW_JOYSTICK_LAST+1]