30 #include <sys/types.h> 32 #include <sys/inotify.h> 41 #ifndef SYN_DROPPED // < v2.6.39 kernel headers 51 js->linjs.keyMap[code - BTN_MISC],
59 const int index = js->linjs.absMap[code];
61 if (code >= ABS_HAT0X && code <= ABS_HAT3Y)
63 static const char stateMap[3][3] =
70 const int hat = (code - ABS_HAT0X) / 2;
71 const int axis = (code - ABS_HAT0X) % 2;
87 const struct input_absinfo*
info = &js->linjs.absInfo[code];
90 const int range = info->maximum - info->minimum;
94 normalized = (normalized - info->minimum) / range;
96 normalized = normalized * 2.0f - 1.0f;
109 for (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)
123 #define isBitSet(bit, arr) (arr[(bit) / 8] & (1 << ((bit) % 8))) 132 char evBits[(EV_CNT + 7) / 8] = {0};
133 char keyBits[(KEY_CNT + 7) / 8] = {0};
134 char absBits[(ABS_CNT + 7) / 8] = {0};
135 int axisCount = 0, buttonCount = 0, hatCount = 0;
148 linjs.fd = open(path, O_RDONLY | O_NONBLOCK);
152 if (ioctl(linjs.fd, EVIOCGBIT(0,
sizeof(evBits)), evBits) < 0 ||
153 ioctl(linjs.fd, EVIOCGBIT(EV_KEY,
sizeof(keyBits)), keyBits) < 0 ||
154 ioctl(linjs.fd, EVIOCGBIT(EV_ABS,
sizeof(absBits)), absBits) < 0 ||
155 ioctl(linjs.fd, EVIOCGID, &
id) < 0)
158 "Linux: Failed to query input device: %s",
171 if (ioctl(linjs.fd, EVIOCGNAME(
sizeof(name)), name) < 0)
172 strncpy(name,
"Unknown",
sizeof(name));
175 if (
id.vendor &&
id.product &&
id.version)
177 sprintf(guid,
"%02x%02x0000%02x%02x0000%02x%02x0000%02x%02x0000",
178 id.bustype & 0xff,
id.bustype >> 8,
179 id.vendor & 0xff,
id.vendor >> 8,
180 id.product & 0xff,
id.product >> 8,
181 id.version & 0xff,
id.version >> 8);
185 sprintf(guid,
"%02x%02x0000%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x00",
186 id.bustype & 0xff,
id.bustype >> 8,
187 name[0], name[1], name[2], name[3],
188 name[4], name[5], name[6], name[7],
189 name[8], name[9], name[10]);
192 for (code = BTN_MISC; code < KEY_CNT; code++)
197 linjs.keyMap[code - BTN_MISC] = buttonCount;
201 for (code = 0; code < ABS_CNT; code++)
203 linjs.absMap[code] = -1;
207 if (code >= ABS_HAT0X && code <= ABS_HAT3Y)
209 linjs.absMap[code] = hatCount;
216 if (ioctl(linjs.fd, EVIOCGABS(code), &linjs.absInfo[code]) < 0)
219 linjs.absMap[code] = axisCount;
231 strncpy(linjs.path, path,
sizeof(linjs.path) - 1);
232 memcpy(&js->linjs, &linjs,
sizeof(linjs));
257 return strcmp(fj->linjs.path, sj->linjs.path);
271 const char* dirname =
"/dev/input";
273 _glfw.linjs.inotify = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
274 if (
_glfw.linjs.inotify > 0)
279 _glfw.linjs.watch = inotify_add_watch(
_glfw.linjs.inotify,
281 IN_CREATE | IN_ATTRIB | IN_DELETE);
286 if (regcomp(&
_glfw.linjs.regex,
"^event[0-9]\\+$", 0) != 0)
292 dir = opendir(dirname);
295 struct dirent*
entry;
297 while ((entry = readdir(dir)))
301 if (regexec(&
_glfw.linjs.regex, entry->d_name, 1, &match, 0) != 0)
306 snprintf(path,
sizeof(path),
"%s/%s", dirname, entry->d_name);
334 regfree(&
_glfw.linjs.regex);
336 if (
_glfw.linjs.inotify > 0)
338 if (
_glfw.linjs.watch > 0)
339 inotify_rm_watch(
_glfw.linjs.inotify,
_glfw.linjs.watch);
341 close(
_glfw.linjs.inotify);
350 if (
_glfw.linjs.inotify <= 0)
353 const ssize_t
size = read(
_glfw.linjs.inotify, buffer,
sizeof(buffer));
355 while (size > offset)
358 const struct inotify_event*
e = (
struct inotify_event*) (buffer + offset);
360 offset +=
sizeof(
struct inotify_event) + e->len;
362 if (regexec(&
_glfw.linjs.regex, e->name, 1, &match, 0) != 0)
366 snprintf(path,
sizeof(path),
"/dev/input/%s", e->name);
368 if (e->mask & (IN_CREATE | IN_ATTRIB))
370 else if (e->mask & IN_DELETE)
396 struct input_event e;
399 if (read(js->linjs.fd, &e,
sizeof(e)) < 0)
408 if (e.type == EV_SYN)
412 else if (e.code == SYN_REPORT)
419 if (
_glfw.linjs.dropped)
422 if (e.type == EV_KEY)
424 else if (e.type == EV_ABS)
void _glfwDetectJoystickConnectionLinux(void)
void _glfwPlatformUpdateGamepadGUID(char *guid)
GLuint const GLchar * name
static int compareJoysticks(const void *fp, const void *sp)
GLsizei const GLchar *const * path
static void pollAbsState(_GLFWjoystick *js)
def info(name, value, persistent=False)
#define GLFW_DISCONNECTED
static void closeJoystick(_GLFWjoystick *js)
#define GLFW_PLATFORM_ERROR
A platform-specific error occurred that does not match any of the more specific categories.
int _glfwPlatformPollJoystick(_GLFWjoystick *js, int mode)
static void handleAbsEvent(_GLFWjoystick *js, int code, int value)
#define isBitSet(bit, arr)
#define GLFW_JOYSTICK_LAST
#define GLFW_HAT_RIGHT_DOWN
void _glfwInputError(int code, const char *format,...)
#define GLFW_HAT_RIGHT_UP
#define GLFW_HAT_LEFT_DOWN
static void handleKeyEvent(_GLFWjoystick *js, int code, int value)
GLint GLenum GLboolean normalized
#define GLFW_HAT_CENTERED
void _glfwTerminateJoysticksLinux(void)
_GLFWjoystick joysticks[GLFW_JOYSTICK_LAST+1]
GLFWbool _glfwInitJoysticksLinux(void)
static GLFWbool openJoystickDevice(const char *path)