From 3b734f0d6b9e28c1f2c4ae54e3f46e573e02f4a5 Mon Sep 17 00:00:00 2001 From: Andreas Grois Date: Fri, 9 Mar 2018 21:36:10 +0100 Subject: Initial Commit --- glfw-3.2.1/src/linux_joystick.c | 341 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 341 insertions(+) create mode 100644 glfw-3.2.1/src/linux_joystick.c (limited to 'glfw-3.2.1/src/linux_joystick.c') diff --git a/glfw-3.2.1/src/linux_joystick.c b/glfw-3.2.1/src/linux_joystick.c new file mode 100644 index 0000000..561b1eb --- /dev/null +++ b/glfw-3.2.1/src/linux_joystick.c @@ -0,0 +1,341 @@ +//======================================================================== +// GLFW 3.2 Linux - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2016 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +#if defined(__linux__) +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif // __linux__ + + +// Attempt to open the specified joystick device +// +#if defined(__linux__) +static GLFWbool openJoystickDevice(const char* path) +{ + char axisCount, buttonCount; + char name[256] = ""; + int joy, fd, version; + _GLFWjoystickLinux* js; + + for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++) + { + if (!_glfw.linux_js.js[joy].present) + continue; + + if (strcmp(_glfw.linux_js.js[joy].path, path) == 0) + return GLFW_FALSE; + } + + for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++) + { + if (!_glfw.linux_js.js[joy].present) + break; + } + + if (joy > GLFW_JOYSTICK_LAST) + return GLFW_FALSE; + + fd = open(path, O_RDONLY | O_NONBLOCK); + if (fd == -1) + return GLFW_FALSE; + + // Verify that the joystick driver version is at least 1.0 + ioctl(fd, JSIOCGVERSION, &version); + if (version < 0x010000) + { + // It's an old 0.x interface (we don't support it) + close(fd); + return GLFW_FALSE; + } + + if (ioctl(fd, JSIOCGNAME(sizeof(name)), name) < 0) + strncpy(name, "Unknown", sizeof(name)); + + js = _glfw.linux_js.js + joy; + js->present = GLFW_TRUE; + js->name = strdup(name); + js->path = strdup(path); + js->fd = fd; + + ioctl(fd, JSIOCGAXES, &axisCount); + js->axisCount = (int) axisCount; + js->axes = calloc(axisCount, sizeof(float)); + + ioctl(fd, JSIOCGBUTTONS, &buttonCount); + js->buttonCount = (int) buttonCount; + js->buttons = calloc(buttonCount, 1); + + _glfwInputJoystickChange(joy, GLFW_CONNECTED); + return GLFW_TRUE; +} +#endif // __linux__ + +// Polls for and processes events the specified joystick +// +static GLFWbool pollJoystickEvents(_GLFWjoystickLinux* js) +{ +#if defined(__linux__) + _glfwPollJoystickEvents(); + + if (!js->present) + return GLFW_FALSE; + + // Read all queued events (non-blocking) + for (;;) + { + struct js_event e; + + errno = 0; + if (read(js->fd, &e, sizeof(e)) < 0) + { + // Reset the joystick slot if the device was disconnected + if (errno == ENODEV) + { + free(js->axes); + free(js->buttons); + free(js->name); + free(js->path); + + memset(js, 0, sizeof(_GLFWjoystickLinux)); + + _glfwInputJoystickChange(js - _glfw.linux_js.js, + GLFW_DISCONNECTED); + } + + break; + } + + // Clear the initial-state bit + e.type &= ~JS_EVENT_INIT; + + if (e.type == JS_EVENT_AXIS) + js->axes[e.number] = (float) e.value / 32767.0f; + else if (e.type == JS_EVENT_BUTTON) + js->buttons[e.number] = e.value ? GLFW_PRESS : GLFW_RELEASE; + } +#endif // __linux__ + return js->present; +} + +// Lexically compare joysticks by name; used by qsort +// +#if defined(__linux__) +static int compareJoysticks(const void* fp, const void* sp) +{ + const _GLFWjoystickLinux* fj = fp; + const _GLFWjoystickLinux* sj = sp; + return strcmp(fj->path, sj->path); +} +#endif // __linux__ + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Initialize joystick interface +// +GLFWbool _glfwInitJoysticksLinux(void) +{ +#if defined(__linux__) + DIR* dir; + int count = 0; + const char* dirname = "/dev/input"; + + _glfw.linux_js.inotify = inotify_init1(IN_NONBLOCK | IN_CLOEXEC); + if (_glfw.linux_js.inotify == -1) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Linux: Failed to initialize inotify: %s", + strerror(errno)); + return GLFW_FALSE; + } + + // HACK: Register for IN_ATTRIB as well to get notified when udev is done + // This works well in practice but the true way is libudev + + _glfw.linux_js.watch = inotify_add_watch(_glfw.linux_js.inotify, + dirname, + IN_CREATE | IN_ATTRIB); + if (_glfw.linux_js.watch == -1) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Linux: Failed to watch for joystick connections in %s: %s", + dirname, + strerror(errno)); + // Continue without device connection notifications + } + + if (regcomp(&_glfw.linux_js.regex, "^js[0-9]\\+$", 0) != 0) + { + _glfwInputError(GLFW_PLATFORM_ERROR, "Linux: Failed to compile regex"); + return GLFW_FALSE; + } + + dir = opendir(dirname); + if (dir) + { + struct dirent* entry; + + while ((entry = readdir(dir))) + { + char path[20]; + regmatch_t match; + + if (regexec(&_glfw.linux_js.regex, entry->d_name, 1, &match, 0) != 0) + continue; + + snprintf(path, sizeof(path), "%s/%s", dirname, entry->d_name); + if (openJoystickDevice(path)) + count++; + } + + closedir(dir); + } + else + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Linux: Failed to open joystick device directory %s: %s", + dirname, + strerror(errno)); + // Continue with no joysticks detected + } + + qsort(_glfw.linux_js.js, count, sizeof(_GLFWjoystickLinux), compareJoysticks); +#endif // __linux__ + + return GLFW_TRUE; +} + +// Close all opened joystick handles +// +void _glfwTerminateJoysticksLinux(void) +{ +#if defined(__linux__) + int i; + + for (i = 0; i <= GLFW_JOYSTICK_LAST; i++) + { + if (_glfw.linux_js.js[i].present) + { + close(_glfw.linux_js.js[i].fd); + free(_glfw.linux_js.js[i].axes); + free(_glfw.linux_js.js[i].buttons); + free(_glfw.linux_js.js[i].name); + free(_glfw.linux_js.js[i].path); + } + } + + regfree(&_glfw.linux_js.regex); + + if (_glfw.linux_js.inotify > 0) + { + if (_glfw.linux_js.watch > 0) + inotify_rm_watch(_glfw.linux_js.inotify, _glfw.linux_js.watch); + + close(_glfw.linux_js.inotify); + } +#endif // __linux__ +} + +void _glfwPollJoystickEvents(void) +{ +#if defined(__linux__) + ssize_t offset = 0; + char buffer[16384]; + + const ssize_t size = read(_glfw.linux_js.inotify, buffer, sizeof(buffer)); + + while (size > offset) + { + regmatch_t match; + const struct inotify_event* e = (struct inotify_event*) (buffer + offset); + + if (regexec(&_glfw.linux_js.regex, e->name, 1, &match, 0) == 0) + { + char path[20]; + snprintf(path, sizeof(path), "/dev/input/%s", e->name); + openJoystickDevice(path); + } + + offset += sizeof(struct inotify_event) + e->len; + } +#endif +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +int _glfwPlatformJoystickPresent(int joy) +{ + _GLFWjoystickLinux* js = _glfw.linux_js.js + joy; + return pollJoystickEvents(js); +} + +const float* _glfwPlatformGetJoystickAxes(int joy, int* count) +{ + _GLFWjoystickLinux* js = _glfw.linux_js.js + joy; + if (!pollJoystickEvents(js)) + return NULL; + + *count = js->axisCount; + return js->axes; +} + +const unsigned char* _glfwPlatformGetJoystickButtons(int joy, int* count) +{ + _GLFWjoystickLinux* js = _glfw.linux_js.js + joy; + if (!pollJoystickEvents(js)) + return NULL; + + *count = js->buttonCount; + return js->buttons; +} + +const char* _glfwPlatformGetJoystickName(int joy) +{ + _GLFWjoystickLinux* js = _glfw.linux_js.js + joy; + if (!pollJoystickEvents(js)) + return NULL; + + return js->name; +} + -- cgit v1.2.3