mirror of
https://github.com/glfw/glfw.git
synced 2024-11-26 03:52:01 +00:00
parent
206f9ca4bc
commit
d2952e4e92
@ -184,6 +184,7 @@ information on what to include when reporting a bug.
|
|||||||
- [X11] Bugfix: IM-duplicated key events would leak at low polling rates (#747)
|
- [X11] Bugfix: IM-duplicated key events would leak at low polling rates (#747)
|
||||||
- [X11] Bugfix: Gamma ramp setting via RandR did not validate ramp size
|
- [X11] Bugfix: Gamma ramp setting via RandR did not validate ramp size
|
||||||
- [X11] Bugfix: Key name string encoding depended on current locale (#981,#983)
|
- [X11] Bugfix: Key name string encoding depended on current locale (#981,#983)
|
||||||
|
- [Linux] Moved to evdev for joystick input (#906,#1005)
|
||||||
- [Linux] Bugfix: Event processing did not detect joystick disconnection (#932)
|
- [Linux] Bugfix: Event processing did not detect joystick disconnection (#932)
|
||||||
- [Linux] Bugfix: The joystick device path could be truncated (#1025)
|
- [Linux] Bugfix: The joystick device path could be truncated (#1025)
|
||||||
- [Cocoa] Added support for Vulkan window surface creation via
|
- [Cocoa] Added support for Vulkan window surface creation via
|
||||||
@ -314,6 +315,7 @@ skills.
|
|||||||
- Peoro
|
- Peoro
|
||||||
- Braden Pellett
|
- Braden Pellett
|
||||||
- Arturo J. Pérez
|
- Arturo J. Pérez
|
||||||
|
- Anthony Pesch
|
||||||
- Orson Peters
|
- Orson Peters
|
||||||
- Emmanuel Gil Peyrot
|
- Emmanuel Gil Peyrot
|
||||||
- Cyril Pichard
|
- Cyril Pichard
|
||||||
|
@ -4234,8 +4234,6 @@ GLFWAPI const unsigned char* glfwGetJoystickButtons(int jid, int* count);
|
|||||||
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
|
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
|
||||||
* GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR.
|
* GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR.
|
||||||
*
|
*
|
||||||
* @bug @linux Joystick hats are currently unimplemented.
|
|
||||||
*
|
|
||||||
* @pointer_lifetime The returned array is allocated and freed by GLFW. You
|
* @pointer_lifetime The returned array is allocated and freed by GLFW. You
|
||||||
* should not free it yourself. It is valid until the specified joystick is
|
* should not free it yourself. It is valid until the specified joystick is
|
||||||
* disconnected, this function is called again for that joystick or the library
|
* disconnected, this function is called again for that joystick or the library
|
||||||
|
@ -38,20 +38,21 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.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)
|
static void handleKeyEvent(_GLFWjoystick* js, int code, int value)
|
||||||
{
|
{
|
||||||
int jid = js - _glfw.joysticks;
|
_glfwInputJoystickButton(_GLFW_JOYSTICK_ID(js),
|
||||||
int button = js->linjs.keyMap[code];
|
js->linjs.keyMap[code - BTN_MISC],
|
||||||
|
value ? GLFW_PRESS : GLFW_RELEASE);
|
||||||
_glfwInputJoystickButton(jid, button, value ? 1 : 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Apply an EV_ABS event to the specified joystick
|
||||||
|
//
|
||||||
static void handleAbsEvent(_GLFWjoystick* js, int code, int value)
|
static void handleAbsEvent(_GLFWjoystick* js, int code, int value)
|
||||||
{
|
{
|
||||||
int jid = js - _glfw.joysticks;
|
const int jid = _GLFW_JOYSTICK_ID(js);
|
||||||
int index = js->linjs.absMap[code];
|
const int index = js->linjs.absMap[code];
|
||||||
|
|
||||||
if (code >= ABS_HAT0X && code <= ABS_HAT3Y)
|
if (code >= ABS_HAT0X && code <= ABS_HAT3Y)
|
||||||
{
|
{
|
||||||
@ -62,11 +63,11 @@ static void handleAbsEvent(_GLFWjoystick* js, int code, int value)
|
|||||||
{ GLFW_HAT_RIGHT, GLFW_HAT_RIGHT_UP, GLFW_HAT_RIGHT_DOWN },
|
{ GLFW_HAT_RIGHT, GLFW_HAT_RIGHT_UP, GLFW_HAT_RIGHT_DOWN },
|
||||||
};
|
};
|
||||||
|
|
||||||
int hat = (code - ABS_HAT0X) / 2;
|
const int hat = (code - ABS_HAT0X) / 2;
|
||||||
int axis = (code - ABS_HAT0X) % 2;
|
const int axis = (code - ABS_HAT0X) % 2;
|
||||||
int* state = js->linjs.hats[hat];
|
int* state = js->linjs.hats[hat];
|
||||||
|
|
||||||
// Looking at several input drivers, it seems all hat events use
|
// NOTE: Looking at several input drivers, it seems all hat events use
|
||||||
// -1 for left / up, 0 for centered and 1 for right / down
|
// -1 for left / up, 0 for centered and 1 for right / down
|
||||||
if (value == 0)
|
if (value == 0)
|
||||||
state[axis] = 0;
|
state[axis] = 0;
|
||||||
@ -79,15 +80,15 @@ static void handleAbsEvent(_GLFWjoystick* js, int code, int value)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
struct input_absinfo *info = &js->linjs.absInfo[code];
|
const struct input_absinfo* info = &js->linjs.absInfo[code];
|
||||||
int range = info->maximum - info->minimum;
|
|
||||||
float normalized = value;
|
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;
|
normalized = (normalized - info->minimum) / range;
|
||||||
// Normalize from -1.0 -> 1.0
|
// Normalize to -1.0 -> 1.0
|
||||||
normalized = normalized * 2.0f - 1.0f;
|
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;
|
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;
|
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
|
// Attempt to open the specified joystick device
|
||||||
//
|
//
|
||||||
static GLFWbool openJoystickDevice(const char* path)
|
static GLFWbool openJoystickDevice(const char* path)
|
||||||
{
|
{
|
||||||
int jid, fd, i;
|
int jid, code;
|
||||||
char name[256] = "";
|
char name[256] = "";
|
||||||
char evBits[(EV_CNT + 7) / 8] = {0};
|
char evBits[(EV_CNT + 7) / 8] = {0};
|
||||||
char keyBits[(KEY_CNT + 7) / 8] = {0};
|
char keyBits[(KEY_CNT + 7) / 8] = {0};
|
||||||
char absBits[(ABS_CNT + 7) / 8] = {0};
|
char absBits[(ABS_CNT + 7) / 8] = {0};
|
||||||
int axisCount = 0;
|
int axisCount = 0, buttonCount = 0, hatCount = 0;
|
||||||
int buttonCount = 0;
|
|
||||||
int hatCount = 0;
|
|
||||||
_GLFWjoystickLinux linjs = {0};
|
_GLFWjoystickLinux linjs = {0};
|
||||||
_GLFWjoystick* js = NULL;
|
_GLFWjoystick* js = NULL;
|
||||||
|
|
||||||
@ -136,71 +139,81 @@ static GLFWbool openJoystickDevice(const char* path)
|
|||||||
return GLFW_FALSE;
|
return GLFW_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
fd = open(path, O_RDONLY | O_NONBLOCK);
|
linjs.fd = open(path, O_RDONLY | O_NONBLOCK);
|
||||||
if (fd == -1)
|
if (linjs.fd == -1)
|
||||||
return GLFW_FALSE;
|
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
|
// Ensure this device supports the events expected of a joystick
|
||||||
if (ioctl(fd, EVIOCGBIT(0, sizeof(evBits)), evBits) < 0 ||
|
if (!isBitSet(EV_KEY, evBits) || !isBitSet(EV_ABS, evBits))
|
||||||
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))
|
|
||||||
{
|
{
|
||||||
close(fd);
|
close(linjs.fd);
|
||||||
return GLFW_FALSE;
|
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));
|
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;
|
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;
|
linjs.absMap[code] = -1;
|
||||||
if (!TEST_BIT(i, absBits))
|
if (!isBitSet(code, absBits))
|
||||||
continue;
|
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
|
// Skip the Y axis
|
||||||
i++;
|
code++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (ioctl(fd, EVIOCGABS(i), &linjs.absInfo[i]) < 0)
|
if (ioctl(linjs.fd, EVIOCGABS(code), &linjs.absInfo[code]) < 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
linjs.absMap[i] = axisCount++;
|
linjs.absMap[code] = axisCount;
|
||||||
|
axisCount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
js = _glfwAllocJoystick(name, axisCount, buttonCount, hatCount);
|
js = _glfwAllocJoystick(name, axisCount, buttonCount, hatCount);
|
||||||
if (!js)
|
if (!js)
|
||||||
{
|
{
|
||||||
close(fd);
|
close(linjs.fd);
|
||||||
return GLFW_FALSE;
|
return GLFW_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
linjs.fd = fd;
|
|
||||||
strncpy(linjs.path, path, sizeof(linjs.path));
|
strncpy(linjs.path, path, sizeof(linjs.path));
|
||||||
memcpy(&js->linjs, &linjs, sizeof(linjs));
|
memcpy(&js->linjs, &linjs, sizeof(linjs));
|
||||||
|
|
||||||
// Set initial values for absolute axes
|
pollAbsState(js);
|
||||||
pollJoystick(js);
|
|
||||||
|
|
||||||
_glfwInputJoystick(_GLFW_JOYSTICK_ID(js), GLFW_CONNECTED);
|
_glfwInputJoystick(_GLFW_JOYSTICK_ID(js), GLFW_CONNECTED);
|
||||||
return GLFW_TRUE;
|
return GLFW_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#undef isBitSet
|
||||||
|
|
||||||
// Frees all resources associated with the specified joystick
|
// Frees all resources associated with the specified joystick
|
||||||
//
|
//
|
||||||
static void closeJoystick(_GLFWjoystick* js)
|
static void closeJoystick(_GLFWjoystick* js)
|
||||||
@ -391,8 +404,7 @@ int _glfwPlatformPollJoystick(int jid, int mode)
|
|||||||
else if (e.type == EV_ABS)
|
else if (e.type == EV_ABS)
|
||||||
handleAbsEvent(js, e.code, e.value);
|
handleAbsEvent(js, e.code, e.value);
|
||||||
else if (e.type == EV_SYN && e.code == SYN_DROPPED)
|
else if (e.type == EV_SYN && e.code == SYN_DROPPED)
|
||||||
// Refresh axes
|
pollAbsState(js);
|
||||||
pollJoystick(js);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return js->present;
|
return js->present;
|
||||||
|
@ -37,7 +37,7 @@ typedef struct _GLFWjoystickLinux
|
|||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
char path[PATH_MAX];
|
char path[PATH_MAX];
|
||||||
int keyMap[KEY_CNT];
|
int keyMap[KEY_CNT - BTN_MISC];
|
||||||
int absMap[ABS_CNT];
|
int absMap[ABS_CNT];
|
||||||
struct input_absinfo absInfo[ABS_CNT];
|
struct input_absinfo absInfo[ABS_CNT];
|
||||||
int hats[4][2];
|
int hats[4][2];
|
||||||
|
Loading…
Reference in New Issue
Block a user