mirror of
				https://github.com/glfw/glfw.git
				synced 2025-11-03 22:04:15 +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: Gamma ramp setting via RandR did not validate ramp size
 | 
			
		||||
- [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: The joystick device path could be truncated (#1025)
 | 
			
		||||
- [Cocoa] Added support for Vulkan window surface creation via
 | 
			
		||||
@ -314,6 +315,7 @@ skills.
 | 
			
		||||
 - Peoro
 | 
			
		||||
 - Braden Pellett
 | 
			
		||||
 - Arturo J. Pérez
 | 
			
		||||
 - Anthony Pesch
 | 
			
		||||
 - Orson Peters
 | 
			
		||||
 - Emmanuel Gil Peyrot
 | 
			
		||||
 - Cyril Pichard
 | 
			
		||||
 | 
			
		||||
@ -4234,8 +4234,6 @@ GLFWAPI const unsigned char* glfwGetJoystickButtons(int jid, int* count);
 | 
			
		||||
 *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
 | 
			
		||||
 *  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
 | 
			
		||||
 *  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
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
 | 
			
		||||
@ -35,21 +35,21 @@
 | 
			
		||||
//
 | 
			
		||||
typedef struct _GLFWjoystickLinux
 | 
			
		||||
{
 | 
			
		||||
    int                  fd;
 | 
			
		||||
    char                 path[PATH_MAX];
 | 
			
		||||
    int                  keyMap[KEY_CNT];
 | 
			
		||||
    int                  absMap[ABS_CNT];
 | 
			
		||||
    struct input_absinfo absInfo[ABS_CNT];
 | 
			
		||||
    int                  hats[4][2];
 | 
			
		||||
    int                     fd;
 | 
			
		||||
    char                    path[PATH_MAX];
 | 
			
		||||
    int                     keyMap[KEY_CNT - BTN_MISC];
 | 
			
		||||
    int                     absMap[ABS_CNT];
 | 
			
		||||
    struct input_absinfo    absInfo[ABS_CNT];
 | 
			
		||||
    int                     hats[4][2];
 | 
			
		||||
} _GLFWjoystickLinux;
 | 
			
		||||
 | 
			
		||||
// Linux-specific joystick API data
 | 
			
		||||
//
 | 
			
		||||
typedef struct _GLFWlibraryLinux
 | 
			
		||||
{
 | 
			
		||||
    int                  inotify;
 | 
			
		||||
    int                  watch;
 | 
			
		||||
    regex_t              regex;
 | 
			
		||||
    int                     inotify;
 | 
			
		||||
    int                     watch;
 | 
			
		||||
    regex_t                 regex;
 | 
			
		||||
} _GLFWlibraryLinux;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user