mirror of
https://github.com/glfw/glfw.git
synced 2025-06-15 20:22:15 +00:00
Merge 9bd85109d5
into 6ed5294223
This commit is contained in:
commit
9d33cce145
@ -5611,6 +5611,37 @@ GLFWAPI const char* glfwGetGamepadName(int jid);
|
|||||||
*/
|
*/
|
||||||
GLFWAPI int glfwGetGamepadState(int jid, GLFWgamepadstate* state);
|
GLFWAPI int glfwGetGamepadState(int jid, GLFWgamepadstate* state);
|
||||||
|
|
||||||
|
/*! @brief Sets the intensity of a joystick's rumble effect.
|
||||||
|
*
|
||||||
|
* This function sends vibration data to joysticks that implement haptic feedback
|
||||||
|
* effects using two vibration motors: a low-frequency motor, and a
|
||||||
|
* high-frequency motor.
|
||||||
|
*
|
||||||
|
* Vibration intensity is a value between 0.0 and 1.0 inclusive, where 0.0 is no
|
||||||
|
* vibration, and 1.0 is maximum vibration. It is set separately for the
|
||||||
|
* joystick's low frequency and high frequency rumble motors.
|
||||||
|
*
|
||||||
|
* If the specified joystick is not present or does not support the rumble effect,
|
||||||
|
* this function will return `GLFW_FALSE` but will not generate an error.
|
||||||
|
*
|
||||||
|
* @param[in] jid The [joystick](@ref joysticks) to vibrate.
|
||||||
|
* @param[in] slowMotorIntensity The low frequency vibration intensity.
|
||||||
|
* @param[in] fastMotorIntensity The high frequency vibration intensity.
|
||||||
|
* @return `GLFW_TRUE` if successful, or `GLFW_FALSE` if no joystick is connected,
|
||||||
|
* or the joystick does not support the rumble effect.
|
||||||
|
*
|
||||||
|
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
|
||||||
|
* GLFW_INVALID_ENUM.
|
||||||
|
*
|
||||||
|
* @thread_safety This function must only be called from the main thread.
|
||||||
|
*
|
||||||
|
* @note @win32 This function is only implemented for XInput devices.
|
||||||
|
* @note @macos This function is not implemented.
|
||||||
|
*
|
||||||
|
* @ingroup input
|
||||||
|
*/
|
||||||
|
GLFWAPI int glfwSetJoystickRumble(int jid, float slowMotorIntensity, float fastMotorIntensity);
|
||||||
|
|
||||||
/*! @brief Sets the clipboard to the specified string.
|
/*! @brief Sets the clipboard to the specified string.
|
||||||
*
|
*
|
||||||
* This function sets the system clipboard to the specified, UTF-8 encoded
|
* This function sets the system clipboard to the specified, UTF-8 encoded
|
||||||
|
@ -481,3 +481,8 @@ void _glfwPlatformUpdateGamepadGUID(char* guid)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int _glfwPlatformSetJoystickRumble(_GLFWjoystick* js, float slowMotorIntensity, float fastMotorIntensity)
|
||||||
|
{
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
28
src/input.c
28
src/input.c
@ -1362,6 +1362,34 @@ GLFWAPI int glfwGetGamepadState(int jid, GLFWgamepadstate* state)
|
|||||||
return GLFW_TRUE;
|
return GLFW_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GLFWAPI int glfwSetJoystickRumble(int jid, float slowMotorIntensity, float fastMotorIntensity)
|
||||||
|
{
|
||||||
|
_GLFWjoystick* js;
|
||||||
|
|
||||||
|
assert(jid >= GLFW_JOYSTICK_1);
|
||||||
|
assert(jid <= GLFW_JOYSTICK_LAST);
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);
|
||||||
|
|
||||||
|
if (jid < 0 || jid > GLFW_JOYSTICK_LAST)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid);
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
js = _glfw.joysticks + jid;
|
||||||
|
if (!js->present)
|
||||||
|
return GLFW_FALSE;
|
||||||
|
|
||||||
|
slowMotorIntensity = slowMotorIntensity < 0.0f ? 0.0f : slowMotorIntensity;
|
||||||
|
slowMotorIntensity = slowMotorIntensity > 1.0f ? 1.0f : slowMotorIntensity;
|
||||||
|
|
||||||
|
fastMotorIntensity = fastMotorIntensity < 0.0f ? 0.0f : fastMotorIntensity;
|
||||||
|
fastMotorIntensity = fastMotorIntensity > 1.0f ? 1.0f : fastMotorIntensity;
|
||||||
|
|
||||||
|
return _glfwPlatformSetJoystickRumble(js, slowMotorIntensity, fastMotorIntensity);
|
||||||
|
}
|
||||||
|
|
||||||
GLFWAPI void glfwSetClipboardString(GLFWwindow* handle, const char* string)
|
GLFWAPI void glfwSetClipboardString(GLFWwindow* handle, const char* string)
|
||||||
{
|
{
|
||||||
assert(string != NULL);
|
assert(string != NULL);
|
||||||
|
@ -642,6 +642,7 @@ GLFWbool _glfwPlatformInitJoysticks(void);
|
|||||||
void _glfwPlatformTerminateJoysticks(void);
|
void _glfwPlatformTerminateJoysticks(void);
|
||||||
int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode);
|
int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode);
|
||||||
void _glfwPlatformUpdateGamepadGUID(char* guid);
|
void _glfwPlatformUpdateGamepadGUID(char* guid);
|
||||||
|
int _glfwPlatformSetJoystickRumble(_GLFWjoystick* js, float slowMotorIntensity, float fastMotorIntensity);
|
||||||
|
|
||||||
uint64_t _glfwPlatformGetTimerValue(void);
|
uint64_t _glfwPlatformGetTimerValue(void);
|
||||||
uint64_t _glfwPlatformGetTimerFrequency(void);
|
uint64_t _glfwPlatformGetTimerFrequency(void);
|
||||||
|
@ -122,6 +122,48 @@ static void pollAbsState(_GLFWjoystick* js)
|
|||||||
|
|
||||||
#define isBitSet(bit, arr) (arr[(bit) / 8] & (1 << ((bit) % 8)))
|
#define isBitSet(bit, arr) (arr[(bit) / 8] & (1 << ((bit) % 8)))
|
||||||
|
|
||||||
|
static void initJoystickForceFeedback(_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);
|
||||||
|
} else {
|
||||||
|
linjs->rumble = effect;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 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)
|
||||||
@ -135,7 +177,7 @@ static GLFWbool openJoystickDevice(const char* path)
|
|||||||
}
|
}
|
||||||
|
|
||||||
_GLFWjoystickLinux linjs = {0};
|
_GLFWjoystickLinux linjs = {0};
|
||||||
linjs.fd = open(path, O_RDONLY | O_NONBLOCK);
|
linjs.fd = open(path, O_RDWR | O_NONBLOCK);
|
||||||
if (linjs.fd == -1)
|
if (linjs.fd == -1)
|
||||||
return GLFW_FALSE;
|
return GLFW_FALSE;
|
||||||
|
|
||||||
@ -222,6 +264,8 @@ static GLFWbool openJoystickDevice(const char* path)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
initJoystickForceFeedback(&linjs);
|
||||||
|
|
||||||
_GLFWjoystick* js =
|
_GLFWjoystick* js =
|
||||||
_glfwAllocJoystick(name, guid, axisCount, buttonCount, hatCount);
|
_glfwAllocJoystick(name, guid, axisCount, buttonCount, hatCount);
|
||||||
if (!js)
|
if (!js)
|
||||||
@ -246,6 +290,8 @@ static GLFWbool openJoystickDevice(const char* path)
|
|||||||
static void closeJoystick(_GLFWjoystick* js)
|
static void closeJoystick(_GLFWjoystick* js)
|
||||||
{
|
{
|
||||||
close(js->linjs.fd);
|
close(js->linjs.fd);
|
||||||
|
if (js->linjs.rumble)
|
||||||
|
free(js->linjs.rumble);
|
||||||
_glfwFreeJoystick(js);
|
_glfwFreeJoystick(js);
|
||||||
_glfwInputJoystick(js, GLFW_DISCONNECTED);
|
_glfwInputJoystick(js, GLFW_DISCONNECTED);
|
||||||
}
|
}
|
||||||
@ -426,3 +472,31 @@ void _glfwPlatformUpdateGamepadGUID(char* guid)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int _glfwPlatformSetJoystickRumble(_GLFWjoystick* js, float slowMotorIntensity, float fastMotorIntensity)
|
||||||
|
{
|
||||||
|
_GLFWjoystickLinux *linjs = &js->linjs;
|
||||||
|
|
||||||
|
if (!js->linjs.rumble)
|
||||||
|
return GLFW_FALSE;
|
||||||
|
|
||||||
|
js->linjs.rumble->u.rumble = (struct ff_rumble_effect)
|
||||||
|
{
|
||||||
|
.strong_magnitude = 65535 * slowMotorIntensity,
|
||||||
|
.weak_magnitude = 65535 * fastMotorIntensity
|
||||||
|
};
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
@ -44,6 +44,7 @@ typedef struct _GLFWjoystickLinux
|
|||||||
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];
|
||||||
|
struct ff_effect *rumble;
|
||||||
} _GLFWjoystickLinux;
|
} _GLFWjoystickLinux;
|
||||||
|
|
||||||
// Linux-specific joystick API data
|
// Linux-specific joystick API data
|
||||||
|
@ -51,3 +51,8 @@ void _glfwPlatformUpdateGamepadGUID(char* guid)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int _glfwPlatformSetJoystickRumble(_GLFWjoystick* js, float slowMotorIntensity, float fastMotorIntensity)
|
||||||
|
{
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -131,6 +131,8 @@ static GLFWbool loadLibraries(void)
|
|||||||
GetProcAddress(_glfw.win32.xinput.instance, "XInputGetCapabilities");
|
GetProcAddress(_glfw.win32.xinput.instance, "XInputGetCapabilities");
|
||||||
_glfw.win32.xinput.GetState = (PFN_XInputGetState)
|
_glfw.win32.xinput.GetState = (PFN_XInputGetState)
|
||||||
GetProcAddress(_glfw.win32.xinput.instance, "XInputGetState");
|
GetProcAddress(_glfw.win32.xinput.instance, "XInputGetState");
|
||||||
|
_glfw.win32.xinput.SetState = (PFN_XInputSetState)
|
||||||
|
GetProcAddress(_glfw.win32.xinput.instance, "XInputSetState");
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -751,3 +751,17 @@ void _glfwPlatformUpdateGamepadGUID(char* guid)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int _glfwPlatformSetJoystickRumble(_GLFWjoystick* js, float slowMotorIntensity, float fastMotorIntensity)
|
||||||
|
{
|
||||||
|
XINPUT_VIBRATION effect;
|
||||||
|
|
||||||
|
if (js->win32.device)
|
||||||
|
return GLFW_FALSE;
|
||||||
|
|
||||||
|
ZeroMemory(&effect, sizeof(XINPUT_VIBRATION));
|
||||||
|
|
||||||
|
effect.wLeftMotorSpeed = (WORD)(65535.0f * slowMotorIntensity);
|
||||||
|
effect.wRightMotorSpeed = (WORD)(65535.0f * fastMotorIntensity);
|
||||||
|
|
||||||
|
return (int) (XInputSetState(js->win32.index, &effect) == ERROR_SUCCESS);
|
||||||
|
}
|
||||||
|
@ -222,8 +222,10 @@ typedef DWORD (WINAPI * PFN_timeGetTime)(void);
|
|||||||
// xinput.dll function pointer typedefs
|
// xinput.dll function pointer typedefs
|
||||||
typedef DWORD (WINAPI * PFN_XInputGetCapabilities)(DWORD,DWORD,XINPUT_CAPABILITIES*);
|
typedef DWORD (WINAPI * PFN_XInputGetCapabilities)(DWORD,DWORD,XINPUT_CAPABILITIES*);
|
||||||
typedef DWORD (WINAPI * PFN_XInputGetState)(DWORD,XINPUT_STATE*);
|
typedef DWORD (WINAPI * PFN_XInputGetState)(DWORD,XINPUT_STATE*);
|
||||||
|
typedef DWORD (WINAPI * PFN_XInputSetState)(DWORD,XINPUT_VIBRATION*);
|
||||||
#define XInputGetCapabilities _glfw.win32.xinput.GetCapabilities
|
#define XInputGetCapabilities _glfw.win32.xinput.GetCapabilities
|
||||||
#define XInputGetState _glfw.win32.xinput.GetState
|
#define XInputGetState _glfw.win32.xinput.GetState
|
||||||
|
#define XInputSetState _glfw.win32.xinput.SetState
|
||||||
|
|
||||||
// dinput8.dll function pointer typedefs
|
// dinput8.dll function pointer typedefs
|
||||||
typedef HRESULT (WINAPI * PFN_DirectInput8Create)(HINSTANCE,DWORD,REFIID,LPVOID*,LPUNKNOWN);
|
typedef HRESULT (WINAPI * PFN_DirectInput8Create)(HINSTANCE,DWORD,REFIID,LPVOID*,LPUNKNOWN);
|
||||||
@ -358,6 +360,7 @@ typedef struct _GLFWlibraryWin32
|
|||||||
HINSTANCE instance;
|
HINSTANCE instance;
|
||||||
PFN_XInputGetCapabilities GetCapabilities;
|
PFN_XInputGetCapabilities GetCapabilities;
|
||||||
PFN_XInputGetState GetState;
|
PFN_XInputGetState GetState;
|
||||||
|
PFN_XInputSetState SetState;
|
||||||
} xinput;
|
} xinput;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
|
@ -58,6 +58,9 @@ static GLFWwindow* window;
|
|||||||
static int joysticks[GLFW_JOYSTICK_LAST + 1];
|
static int joysticks[GLFW_JOYSTICK_LAST + 1];
|
||||||
static int joystick_count = 0;
|
static int joystick_count = 0;
|
||||||
|
|
||||||
|
static float slowRumble[GLFW_JOYSTICK_LAST + 1];
|
||||||
|
static float fastRumble[GLFW_JOYSTICK_LAST + 1];
|
||||||
|
|
||||||
static void error_callback(int error, const char* description)
|
static void error_callback(int error, const char* description)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Error: %s\n", description);
|
fprintf(stderr, "Error: %s\n", description);
|
||||||
@ -175,7 +178,9 @@ int main(void)
|
|||||||
struct nk_context* nk;
|
struct nk_context* nk;
|
||||||
struct nk_font_atlas* atlas;
|
struct nk_font_atlas* atlas;
|
||||||
|
|
||||||
memset(joysticks, 0, sizeof(joysticks));
|
memset(joysticks, 0, sizeof(joysticks));
|
||||||
|
memset(slowRumble, 0, sizeof(slowRumble));
|
||||||
|
memset(fastRumble, 0, sizeof(fastRumble));
|
||||||
|
|
||||||
glfwSetErrorCallback(error_callback);
|
glfwSetErrorCallback(error_callback);
|
||||||
|
|
||||||
@ -326,6 +331,16 @@ int main(void)
|
|||||||
|
|
||||||
nk_layout_row_dynamic(nk, 30, 8);
|
nk_layout_row_dynamic(nk, 30, 8);
|
||||||
hat_widget(nk, hat);
|
hat_widget(nk, hat);
|
||||||
|
|
||||||
|
nk_layout_row_dynamic(nk, 30, 2);
|
||||||
|
nk_label(nk, "Slow rumble motor intensity", NK_TEXT_LEFT);
|
||||||
|
nk_label(nk, "Fast rumble motor intensity", NK_TEXT_LEFT);
|
||||||
|
|
||||||
|
nk_layout_row_dynamic(nk, 30, 2);
|
||||||
|
slowRumble[i] = nk_slide_float(nk, 0.0f, slowRumble[i], 1.0f, 0.05f);
|
||||||
|
fastRumble[i] = nk_slide_float(nk, 0.0f, fastRumble[i], 1.0f, 0.05f);
|
||||||
|
|
||||||
|
glfwSetJoystickRumble(joysticks[i], slowRumble[i], fastRumble[i]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
nk_label(nk, "Joystick has no gamepad mapping", NK_TEXT_LEFT);
|
nk_label(nk, "Joystick has no gamepad mapping", NK_TEXT_LEFT);
|
||||||
|
Loading…
Reference in New Issue
Block a user