|
@@ -38,36 +38,37 @@
|
|
|
#include <string.h>
|
|
|
#include <unistd.h>
|
|
|
|
|
|
-#define TEST_BIT(bit, arr) (arr[(bit) / 8] & (1 << ((bit) % 8)))
|
|
|
-
|
|
|
+// Apply an EV_KEY event to the specified joystick
|
|
|
+//
|
|
|
static void handleKeyEvent(_GLFWjoystick* js, int code, int value)
|
|
|
{
|
|
|
- int jid = js - _glfw.joysticks;
|
|
|
- int button = js->linjs.keyMap[code];
|
|
|
-
|
|
|
- _glfwInputJoystickButton(jid, button, value ? 1 : 0);
|
|
|
+ _glfwInputJoystickButton(_GLFW_JOYSTICK_ID(js),
|
|
|
+ js->linjs.keyMap[code - BTN_MISC],
|
|
|
+ value ? GLFW_PRESS : GLFW_RELEASE);
|
|
|
}
|
|
|
|
|
|
+// Apply an EV_ABS event to the specified joystick
|
|
|
+//
|
|
|
static void handleAbsEvent(_GLFWjoystick* js, int code, int value)
|
|
|
{
|
|
|
- int jid = js - _glfw.joysticks;
|
|
|
- int index = js->linjs.absMap[code];
|
|
|
+ const int jid = _GLFW_JOYSTICK_ID(js);
|
|
|
+ const int index = js->linjs.absMap[code];
|
|
|
|
|
|
if (code >= ABS_HAT0X && code <= ABS_HAT3Y)
|
|
|
{
|
|
|
static const char stateMap[3][3] =
|
|
|
{
|
|
|
- {GLFW_HAT_CENTERED, GLFW_HAT_UP, GLFW_HAT_DOWN},
|
|
|
- {GLFW_HAT_LEFT, GLFW_HAT_LEFT_UP, GLFW_HAT_LEFT_DOWN},
|
|
|
- {GLFW_HAT_RIGHT, GLFW_HAT_RIGHT_UP, GLFW_HAT_RIGHT_DOWN},
|
|
|
+ { GLFW_HAT_CENTERED, GLFW_HAT_UP, GLFW_HAT_DOWN },
|
|
|
+ { GLFW_HAT_LEFT, GLFW_HAT_LEFT_UP, GLFW_HAT_LEFT_DOWN },
|
|
|
+ { GLFW_HAT_RIGHT, GLFW_HAT_RIGHT_UP, GLFW_HAT_RIGHT_DOWN },
|
|
|
};
|
|
|
|
|
|
- int hat = (code - ABS_HAT0X) / 2;
|
|
|
- int axis = (code - ABS_HAT0X) % 2;
|
|
|
- int *state = js->linjs.hats[hat];
|
|
|
+ const int hat = (code - ABS_HAT0X) / 2;
|
|
|
+ const int axis = (code - ABS_HAT0X) % 2;
|
|
|
+ int* state = js->linjs.hats[hat];
|
|
|
|
|
|
- // Looking at several input drivers, it seems all hat events use
|
|
|
- // -1 for left / up, 0 for centered and 1 for right / down
|
|
|
+ // NOTE: Looking at several input drivers, it seems all hat events use
|
|
|
+ // -1 for left / up, 0 for centered and 1 for right / down
|
|
|
if (value == 0)
|
|
|
state[axis] = 0;
|
|
|
else if (value < 0)
|
|
@@ -79,15 +80,15 @@ static void handleAbsEvent(_GLFWjoystick* js, int code, int value)
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- struct input_absinfo *info = &js->linjs.absInfo[code];
|
|
|
- int range = info->maximum - info->minimum;
|
|
|
+ const struct input_absinfo* info = &js->linjs.absInfo[code];
|
|
|
float normalized = value;
|
|
|
|
|
|
- if (range != 0)
|
|
|
+ const int range = info->maximum - info->minimum;
|
|
|
+ if (range)
|
|
|
{
|
|
|
- // Normalize from 0.0 -> 1.0
|
|
|
+ // Normalize to 0.0 -> 1.0
|
|
|
normalized = (normalized - info->minimum) / range;
|
|
|
- // Normalize from -1.0 -> 1.0
|
|
|
+ // Normalize to -1.0 -> 1.0
|
|
|
normalized = normalized * 2.0f - 1.0f;
|
|
|
}
|
|
|
|
|
@@ -95,36 +96,38 @@ static void handleAbsEvent(_GLFWjoystick* js, int code, int value)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static void pollJoystick(_GLFWjoystick* js)
|
|
|
+// Poll state of absolute axes
|
|
|
+//
|
|
|
+static void pollAbsState(_GLFWjoystick* js)
|
|
|
{
|
|
|
- int i;
|
|
|
+ int code;
|
|
|
|
|
|
- for (i = 0; i < ABS_CNT; i++)
|
|
|
+ for (code = 0; code < ABS_CNT; code++)
|
|
|
{
|
|
|
- if (js->linjs.absMap[i] < 0)
|
|
|
+ if (js->linjs.absMap[code] < 0)
|
|
|
continue;
|
|
|
|
|
|
- struct input_absinfo *info = &js->linjs.absInfo[i];
|
|
|
+ struct input_absinfo* info = &js->linjs.absInfo[code];
|
|
|
|
|
|
- if (ioctl(js->linjs.fd, EVIOCGABS(i), info) < 0)
|
|
|
+ if (ioctl(js->linjs.fd, EVIOCGABS(code), info) < 0)
|
|
|
continue;
|
|
|
|
|
|
- handleAbsEvent(js, i, info->value);
|
|
|
+ handleAbsEvent(js, code, info->value);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+#define isBitSet(bit, arr) (arr[(bit) / 8] & (1 << ((bit) % 8)))
|
|
|
+
|
|
|
// Attempt to open the specified joystick device
|
|
|
//
|
|
|
static GLFWbool openJoystickDevice(const char* path)
|
|
|
{
|
|
|
- int jid, fd, i;
|
|
|
+ int jid, code;
|
|
|
char name[256] = "";
|
|
|
char evBits[(EV_CNT + 7) / 8] = {0};
|
|
|
char keyBits[(KEY_CNT + 7) / 8] = {0};
|
|
|
char absBits[(ABS_CNT + 7) / 8] = {0};
|
|
|
- int axisCount = 0;
|
|
|
- int buttonCount = 0;
|
|
|
- int hatCount = 0;
|
|
|
+ int axisCount = 0, buttonCount = 0, hatCount = 0;
|
|
|
_GLFWjoystickLinux linjs = {0};
|
|
|
_GLFWjoystick* js = NULL;
|
|
|
|
|
@@ -136,71 +139,81 @@ static GLFWbool openJoystickDevice(const char* path)
|
|
|
return GLFW_FALSE;
|
|
|
}
|
|
|
|
|
|
- fd = open(path, O_RDONLY | O_NONBLOCK);
|
|
|
- if (fd == -1)
|
|
|
+ linjs.fd = open(path, O_RDONLY | O_NONBLOCK);
|
|
|
+ if (linjs.fd == -1)
|
|
|
+ return GLFW_FALSE;
|
|
|
+
|
|
|
+ if (ioctl(linjs.fd, EVIOCGBIT(0, sizeof(evBits)), evBits) < 0 ||
|
|
|
+ ioctl(linjs.fd, EVIOCGBIT(EV_KEY, sizeof(keyBits)), keyBits) < 0 ||
|
|
|
+ ioctl(linjs.fd, EVIOCGBIT(EV_ABS, sizeof(absBits)), absBits) < 0)
|
|
|
+ {
|
|
|
+ _glfwInputError(GLFW_PLATFORM_ERROR,
|
|
|
+ "Linux: Failed to query input device elements: %s",
|
|
|
+ strerror(errno));
|
|
|
+ close(linjs.fd);
|
|
|
return GLFW_FALSE;
|
|
|
+ }
|
|
|
|
|
|
// Ensure this device supports the events expected of a joystick
|
|
|
- if (ioctl(fd, EVIOCGBIT(0, sizeof(evBits)), evBits) < 0 ||
|
|
|
- ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keyBits)), keyBits) < 0 ||
|
|
|
- ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absBits)), absBits) < 0 ||
|
|
|
- !TEST_BIT(EV_KEY, evBits) || !TEST_BIT(EV_ABS, evBits))
|
|
|
+ if (!isBitSet(EV_KEY, evBits) || !isBitSet(EV_ABS, evBits))
|
|
|
{
|
|
|
- close(fd);
|
|
|
+ close(linjs.fd);
|
|
|
return GLFW_FALSE;
|
|
|
}
|
|
|
|
|
|
- if (ioctl(fd, EVIOCGNAME(sizeof(name)), name) < 0)
|
|
|
+ if (ioctl(linjs.fd, EVIOCGNAME(sizeof(name)), name) < 0)
|
|
|
strncpy(name, "Unknown", sizeof(name));
|
|
|
|
|
|
- for (i = BTN_MISC; i < KEY_CNT; i++)
|
|
|
+ for (code = BTN_MISC; code < KEY_CNT; code++)
|
|
|
{
|
|
|
- if (!TEST_BIT(i, keyBits))
|
|
|
+ if (!isBitSet(code, keyBits))
|
|
|
continue;
|
|
|
|
|
|
- linjs.keyMap[i] = buttonCount++;
|
|
|
+ linjs.keyMap[code - BTN_MISC] = buttonCount;
|
|
|
+ buttonCount++;
|
|
|
}
|
|
|
|
|
|
- for (i = 0; i < ABS_CNT; i++)
|
|
|
+ for (code = 0; code < ABS_CNT; code++)
|
|
|
{
|
|
|
- linjs.absMap[i] = -1;
|
|
|
- if (!TEST_BIT(i, absBits))
|
|
|
+ linjs.absMap[code] = -1;
|
|
|
+ if (!isBitSet(code, absBits))
|
|
|
continue;
|
|
|
|
|
|
- if (i >= ABS_HAT0X && i <= ABS_HAT3Y)
|
|
|
+ if (code >= ABS_HAT0X && code <= ABS_HAT3Y)
|
|
|
{
|
|
|
- linjs.absMap[i] = hatCount++;
|
|
|
-
|
|
|
+ linjs.absMap[code] = hatCount;
|
|
|
+ hatCount++;
|
|
|
// Skip the Y axis
|
|
|
- i++;
|
|
|
+ code++;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- if (ioctl(fd, EVIOCGABS(i), &linjs.absInfo[i]) < 0)
|
|
|
+ if (ioctl(linjs.fd, EVIOCGABS(code), &linjs.absInfo[code]) < 0)
|
|
|
continue;
|
|
|
|
|
|
- linjs.absMap[i] = axisCount++;
|
|
|
+ linjs.absMap[code] = axisCount;
|
|
|
+ axisCount++;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
js = _glfwAllocJoystick(name, axisCount, buttonCount, hatCount);
|
|
|
if (!js)
|
|
|
{
|
|
|
- close(fd);
|
|
|
+ close(linjs.fd);
|
|
|
return GLFW_FALSE;
|
|
|
}
|
|
|
|
|
|
- linjs.fd = fd;
|
|
|
strncpy(linjs.path, path, sizeof(linjs.path));
|
|
|
memcpy(&js->linjs, &linjs, sizeof(linjs));
|
|
|
|
|
|
- // Set initial values for absolute axes
|
|
|
- pollJoystick(js);
|
|
|
+ pollAbsState(js);
|
|
|
|
|
|
_glfwInputJoystick(_GLFW_JOYSTICK_ID(js), GLFW_CONNECTED);
|
|
|
return GLFW_TRUE;
|
|
|
}
|
|
|
|
|
|
+#undef isBitSet
|
|
|
+
|
|
|
// Frees all resources associated with the specified joystick
|
|
|
//
|
|
|
static void closeJoystick(_GLFWjoystick* js)
|
|
@@ -391,8 +404,7 @@ int _glfwPlatformPollJoystick(int jid, int mode)
|
|
|
else if (e.type == EV_ABS)
|
|
|
handleAbsEvent(js, e.code, e.value);
|
|
|
else if (e.type == EV_SYN && e.code == SYN_DROPPED)
|
|
|
- // Refresh axes
|
|
|
- pollJoystick(js);
|
|
|
+ pollAbsState(js);
|
|
|
}
|
|
|
|
|
|
return js->present;
|