From b0840ad5bbe2c1de63534b74667eb18cc4c9911f Mon Sep 17 00:00:00 2001 From: Nikita Leonidov Date: Thu, 16 Apr 2020 10:17:16 -0400 Subject: [PATCH] add linux rumble support --- src/linux_joystick.c | 78 +++++++++++++++++++++++++++++++++++++++++++- src/linux_joystick.h | 1 + 2 files changed, 78 insertions(+), 1 deletion(-) diff --git a/src/linux_joystick.c b/src/linux_joystick.c index 1f9b35fe..9f278e83 100644 --- a/src/linux_joystick.c +++ b/src/linux_joystick.c @@ -122,6 +122,49 @@ static void pollAbsState(_GLFWjoystick* js) #define isBitSet(bit, arr) (arr[(bit) / 8] & (1 << ((bit) % 8))) +static void checkForceFeedback(_GLFWjoystickLinux *linjs) +{ + linjs->rumble = NULL; + struct ff_effect* effect = NULL; + + char ffBits[(FF_CNT + 7) / 8] = {0}; + if (ioctl(linjs->fd, EVIOCGBIT(EV_FF, sizeof(ffBits)), ffBits) < 0) + { + return; + } + + if (isBitSet(FF_RUMBLE, ffBits)) + { + effect = malloc(sizeof(struct ff_effect)); + *effect = (struct ff_effect) + { + .type = FF_RUMBLE, + .id = -1, + .direction = 0, + .trigger = { + .button = 0, + .interval = 0 + }, + .replay = { + .length = 2000, // xinput rumble lasts ~2 seconds + .delay = 0 + }, + .u.rumble = { + .strong_magnitude = 0, + .weak_magnitude = 0 + } + }; + + if (ioctl(linjs->fd, EVIOCSFF, effect) < 0) + { + free(effect); + return; + } else { + linjs->rumble = effect; + } + } +} + // Attempt to open the specified joystick device // static GLFWbool openJoystickDevice(const char* path) @@ -135,7 +178,7 @@ static GLFWbool openJoystickDevice(const char* path) } _GLFWjoystickLinux linjs = {0}; - linjs.fd = open(path, O_RDONLY | O_NONBLOCK); + linjs.fd = open(path, O_RDWR | O_NONBLOCK); if (linjs.fd == -1) return GLFW_FALSE; @@ -222,6 +265,8 @@ static GLFWbool openJoystickDevice(const char* path) } } + checkForceFeedback(&linjs); + _GLFWjoystick* js = _glfwAllocJoystick(name, guid, axisCount, buttonCount, hatCount); if (!js) @@ -246,6 +291,8 @@ static GLFWbool openJoystickDevice(const char* path) static void closeJoystick(_GLFWjoystick* js) { close(js->linjs.fd); + if (js->linjs.rumble) + free(js->linjs.rumble); _glfwFreeJoystick(js); _glfwInputJoystick(js, GLFW_DISCONNECTED); } @@ -431,3 +478,32 @@ void _glfwPlatformUpdateGamepadGUID(char* guid) { } + +int _glfwPlatformSetGamepadRumble(_GLFWjoystick* js, float slowMotorSpeed, float fastMotorSpeed) +{ + _GLFWjoystickLinux *linjs = &js->linjs; + + if (!js->linjs.rumble) + return GLFW_FALSE; + + js->linjs.rumble->u.rumble = (struct ff_rumble_effect) + { + .strong_magnitude = 65535 * slowMotorSpeed, + .weak_magnitude = 65535 * fastMotorSpeed + }; + + struct input_event play = + { + .type = EV_FF, + .code = linjs->rumble->id, + .value = 1 + }; + + if (ioctl(linjs->fd, EVIOCSFF, linjs->rumble) < 0 || + write(linjs->fd, (const void*) &play, sizeof(play)) < 0) + { + return GLFW_FALSE; + } + + return GLFW_TRUE; +} \ No newline at end of file diff --git a/src/linux_joystick.h b/src/linux_joystick.h index 7373f130..c40f9843 100644 --- a/src/linux_joystick.h +++ b/src/linux_joystick.h @@ -43,6 +43,7 @@ typedef struct _GLFWjoystickLinux int absMap[ABS_CNT]; struct input_absinfo absInfo[ABS_CNT]; int hats[4][2]; + struct ff_effect *rumble; } _GLFWjoystickLinux; // Linux-specific joystick API data