Added HIDAPI joystick drivers for more consistent support for Xbox, PS4 and Nintendo Switch Pro controller support across platforms.
Added SDL_GameControllerRumble() and SDL_JoystickRumble() for simple force feedback outside of the SDL haptics API
This commit is contained in:
parent
ba90412cda
commit
d2042e1ed4
53 changed files with 6827 additions and 1367 deletions
|
@ -29,10 +29,11 @@
|
|||
/* This is the Linux implementation of the SDL joystick API */
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h> /* errno, strerror */
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <limits.h> /* For the definition of PATH_MAX */
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
#include <linux/joystick.h>
|
||||
|
||||
#include "SDL_assert.h"
|
||||
|
@ -43,6 +44,7 @@
|
|||
#include "../SDL_joystick_c.h"
|
||||
#include "../steam/SDL_steamcontroller.h"
|
||||
#include "SDL_sysjoystick_c.h"
|
||||
#include "../hidapi/SDL_hidapijoystick_c.h"
|
||||
|
||||
/* This isn't defined in older Linux kernel headers */
|
||||
#ifndef SYN_DROPPED
|
||||
|
@ -76,7 +78,6 @@ typedef struct SDL_joylist_item
|
|||
static SDL_joylist_item *SDL_joylist = NULL;
|
||||
static SDL_joylist_item *SDL_joylist_tail = NULL;
|
||||
static int numjoysticks = 0;
|
||||
static int instance_counter = 0;
|
||||
|
||||
|
||||
#define test_bit(nr, addr) \
|
||||
|
@ -209,6 +210,13 @@ IsJoystick(int fd, char *namebuf, const size_t namebuflen, SDL_JoystickGUID *gui
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef SDL_JOYSTICK_HIDAPI
|
||||
if (HIDAPI_IsDevicePresent(inpid.vendor, inpid.product)) {
|
||||
/* The HIDAPI driver is taking care of this device */
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Check the joystick blacklist */
|
||||
id = MAKE_VIDPID(inpid.vendor, inpid.product);
|
||||
for (i = 0; i < SDL_arraysize(joystick_blacklist); ++i) {
|
||||
|
@ -239,8 +247,7 @@ IsJoystick(int fd, char *namebuf, const size_t namebuflen, SDL_JoystickGUID *gui
|
|||
SDL_strlcpy((char*)guid16, namebuf, sizeof(guid->data) - 4);
|
||||
}
|
||||
|
||||
if (SDL_IsGameControllerNameAndGUID(namebuf, *guid) &&
|
||||
SDL_ShouldIgnoreGameController(namebuf, *guid)) {
|
||||
if (SDL_ShouldIgnoreJoystick(namebuf, *guid)) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
|
@ -325,14 +332,14 @@ MaybeAddDevice(const char *path)
|
|||
item->name = SDL_strdup(namebuf);
|
||||
item->guid = guid;
|
||||
|
||||
if ( (item->path == NULL) || (item->name == NULL) ) {
|
||||
if ((item->path == NULL) || (item->name == NULL)) {
|
||||
SDL_free(item->path);
|
||||
SDL_free(item->name);
|
||||
SDL_free(item);
|
||||
return -1;
|
||||
}
|
||||
|
||||
item->device_instance = instance_counter++;
|
||||
item->device_instance = SDL_GetNextJoystickInstanceID();
|
||||
if (SDL_joylist_tail == NULL) {
|
||||
SDL_joylist = SDL_joylist_tail = item;
|
||||
} else {
|
||||
|
@ -343,7 +350,7 @@ MaybeAddDevice(const char *path)
|
|||
/* Need to increment the joystick count before we post the event */
|
||||
++numjoysticks;
|
||||
|
||||
SDL_PrivateJoystickAdded(numjoysticks - 1);
|
||||
SDL_PrivateJoystickAdded(item->device_instance);
|
||||
|
||||
return numjoysticks;
|
||||
}
|
||||
|
@ -409,7 +416,7 @@ JoystickInitWithoutUdev(void)
|
|||
MaybeAddDevice(path);
|
||||
}
|
||||
|
||||
return numjoysticks;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -430,7 +437,7 @@ JoystickInitWithUdev(void)
|
|||
/* Force a scan to build the initial device list */
|
||||
SDL_UDEV_Scan();
|
||||
|
||||
return numjoysticks;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -455,7 +462,7 @@ static SDL_bool SteamControllerConnectedCallback(const char *name, SDL_JoystickG
|
|||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
*device_instance = item->device_instance = instance_counter++;
|
||||
*device_instance = item->device_instance = SDL_GetNextJoystickInstanceID();
|
||||
if (SDL_joylist_tail == NULL) {
|
||||
SDL_joylist = SDL_joylist_tail = item;
|
||||
} else {
|
||||
|
@ -466,7 +473,7 @@ static SDL_bool SteamControllerConnectedCallback(const char *name, SDL_JoystickG
|
|||
/* Need to increment the joystick count before we post the event */
|
||||
++numjoysticks;
|
||||
|
||||
SDL_PrivateJoystickAdded(numjoysticks - 1);
|
||||
SDL_PrivateJoystickAdded(item->device_instance);
|
||||
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
@ -505,8 +512,8 @@ static void SteamControllerDisconnectedCallback(int device_instance)
|
|||
}
|
||||
}
|
||||
|
||||
int
|
||||
SDL_SYS_JoystickInit(void)
|
||||
static int
|
||||
LINUX_JoystickInit(void)
|
||||
{
|
||||
/* First see if the user specified one or more joysticks to use */
|
||||
if (SDL_getenv("SDL_JOYSTICK_DEVICE") != NULL) {
|
||||
|
@ -534,14 +541,14 @@ SDL_SYS_JoystickInit(void)
|
|||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
SDL_SYS_NumJoysticks(void)
|
||||
static int
|
||||
LINUX_JoystickGetCount(void)
|
||||
{
|
||||
return numjoysticks;
|
||||
}
|
||||
|
||||
void
|
||||
SDL_SYS_JoystickDetect(void)
|
||||
static void
|
||||
LINUX_JoystickDetect(void)
|
||||
{
|
||||
#if SDL_USE_LIBUDEV
|
||||
SDL_UDEV_Poll();
|
||||
|
@ -569,14 +576,21 @@ JoystickByDevIndex(int device_index)
|
|||
}
|
||||
|
||||
/* Function to get the device-dependent name of a joystick */
|
||||
const char *
|
||||
SDL_SYS_JoystickNameForDeviceIndex(int device_index)
|
||||
static const char *
|
||||
LINUX_JoystickGetDeviceName(int device_index)
|
||||
{
|
||||
return JoystickByDevIndex(device_index)->name;
|
||||
}
|
||||
|
||||
static SDL_JoystickGUID
|
||||
LINUX_JoystickGetDeviceGUID( int device_index )
|
||||
{
|
||||
return JoystickByDevIndex(device_index)->guid;
|
||||
}
|
||||
|
||||
/* Function to perform the mapping from device index to the instance id for this index */
|
||||
SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index)
|
||||
static SDL_JoystickID
|
||||
LINUX_JoystickGetDeviceInstanceID(int device_index)
|
||||
{
|
||||
return JoystickByDevIndex(device_index)->device_instance;
|
||||
}
|
||||
|
@ -624,6 +638,7 @@ ConfigJoystick(SDL_Joystick * joystick, int fd)
|
|||
unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
|
||||
unsigned long absbit[NBITS(ABS_MAX)] = { 0 };
|
||||
unsigned long relbit[NBITS(REL_MAX)] = { 0 };
|
||||
unsigned long ffbit[NBITS(FF_MAX)] = { 0 };
|
||||
|
||||
/* See if this device uses the new unified event API */
|
||||
if ((ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) >= 0) &&
|
||||
|
@ -719,6 +734,15 @@ ConfigJoystick(SDL_Joystick * joystick, int fd)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ioctl(fd, EVIOCGBIT(EV_FF, sizeof(ffbit)), ffbit) >= 0) {
|
||||
if (test_bit(FF_RUMBLE, ffbit)) {
|
||||
joystick->hwdata->ff_rumble = SDL_TRUE;
|
||||
}
|
||||
if (test_bit(FF_SINE, ffbit)) {
|
||||
joystick->hwdata->ff_sine = SDL_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -727,8 +751,8 @@ ConfigJoystick(SDL_Joystick * joystick, int fd)
|
|||
This should fill the nbuttons and naxes fields of the joystick structure.
|
||||
It returns 0, or -1 if there is an error.
|
||||
*/
|
||||
int
|
||||
SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index)
|
||||
static int
|
||||
LINUX_JoystickOpen(SDL_Joystick * joystick, int device_index)
|
||||
{
|
||||
SDL_joylist_item *item = JoystickByDevIndex(device_index);
|
||||
|
||||
|
@ -744,6 +768,7 @@ SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index)
|
|||
}
|
||||
joystick->hwdata->item = item;
|
||||
joystick->hwdata->guid = item->guid;
|
||||
joystick->hwdata->effect.id = -1;
|
||||
joystick->hwdata->m_bSteamController = item->m_bSteamController;
|
||||
|
||||
if (item->m_bSteamController) {
|
||||
|
@ -752,7 +777,7 @@ SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index)
|
|||
&joystick->naxes,
|
||||
&joystick->nhats);
|
||||
} else {
|
||||
int fd = open(item->path, O_RDONLY, 0);
|
||||
int fd = open(item->path, O_RDWR, 0);
|
||||
if (fd < 0) {
|
||||
SDL_free(joystick->hwdata);
|
||||
joystick->hwdata = NULL;
|
||||
|
@ -785,11 +810,52 @@ SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index)
|
|||
}
|
||||
|
||||
/* Function to determine if this joystick is attached to the system right now */
|
||||
SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick)
|
||||
static SDL_bool
|
||||
LINUX_JoystickIsAttached(SDL_Joystick *joystick)
|
||||
{
|
||||
return joystick->hwdata->item != NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
LINUX_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
|
||||
{
|
||||
struct input_event event;
|
||||
|
||||
if (joystick->hwdata->effect.id < 0) {
|
||||
if (joystick->hwdata->ff_rumble) {
|
||||
struct ff_effect *effect = &joystick->hwdata->effect;
|
||||
|
||||
effect->type = FF_RUMBLE;
|
||||
effect->replay.length = SDL_min(duration_ms, 32767);
|
||||
effect->u.rumble.strong_magnitude = low_frequency_rumble;
|
||||
effect->u.rumble.weak_magnitude = high_frequency_rumble;
|
||||
} else if (joystick->hwdata->ff_sine) {
|
||||
/* Scale and average the two rumble strengths */
|
||||
Sint16 magnitude = (Sint16)(((low_frequency_rumble / 2) + (high_frequency_rumble / 2)) / 2);
|
||||
struct ff_effect *effect = &joystick->hwdata->effect;
|
||||
|
||||
effect->type = FF_PERIODIC;
|
||||
effect->replay.length = SDL_min(duration_ms, 32767);
|
||||
effect->u.periodic.waveform = FF_SINE;
|
||||
effect->u.periodic.magnitude = magnitude;
|
||||
} else {
|
||||
return SDL_Unsupported();
|
||||
}
|
||||
}
|
||||
|
||||
if (ioctl(joystick->hwdata->fd, EVIOCSFF, &joystick->hwdata->effect) < 0) {
|
||||
return SDL_SetError("Couldn't update rumble effect: %s", strerror(errno));
|
||||
}
|
||||
|
||||
event.type = EV_FF;
|
||||
event.code = joystick->hwdata->effect.id;
|
||||
event.value = 1;
|
||||
if (write(joystick->hwdata->fd, &event, sizeof(event)) < 0) {
|
||||
return SDL_SetError("Couldn't start rumble effect: %s", strerror(errno));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SDL_INLINE void
|
||||
HandleHat(SDL_Joystick * stick, Uint8 hat, int axis, int value)
|
||||
{
|
||||
|
@ -963,8 +1029,8 @@ HandleInputEvents(SDL_Joystick * joystick)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
|
||||
static void
|
||||
LINUX_JoystickUpdate(SDL_Joystick * joystick)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
@ -990,10 +1056,14 @@ SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
|
|||
}
|
||||
|
||||
/* Function to close a joystick after use */
|
||||
void
|
||||
SDL_SYS_JoystickClose(SDL_Joystick * joystick)
|
||||
static void
|
||||
LINUX_JoystickClose(SDL_Joystick * joystick)
|
||||
{
|
||||
if (joystick->hwdata) {
|
||||
if (joystick->hwdata->effect.id >= 0) {
|
||||
ioctl(joystick->hwdata->fd, EVIOCRMFF, joystick->hwdata->effect.id);
|
||||
joystick->hwdata->effect.id = -1;
|
||||
}
|
||||
if (joystick->hwdata->fd >= 0) {
|
||||
close(joystick->hwdata->fd);
|
||||
}
|
||||
|
@ -1008,8 +1078,8 @@ SDL_SYS_JoystickClose(SDL_Joystick * joystick)
|
|||
}
|
||||
|
||||
/* Function to perform any system-specific joystick related cleanup */
|
||||
void
|
||||
SDL_SYS_JoystickQuit(void)
|
||||
static void
|
||||
LINUX_JoystickQuit(void)
|
||||
{
|
||||
SDL_joylist_item *item = NULL;
|
||||
SDL_joylist_item *next = NULL;
|
||||
|
@ -1024,7 +1094,6 @@ SDL_SYS_JoystickQuit(void)
|
|||
SDL_joylist = SDL_joylist_tail = NULL;
|
||||
|
||||
numjoysticks = 0;
|
||||
instance_counter = 0;
|
||||
|
||||
#if SDL_USE_LIBUDEV
|
||||
SDL_UDEV_DelCallback(joystick_udev_callback);
|
||||
|
@ -1034,15 +1103,21 @@ SDL_SYS_JoystickQuit(void)
|
|||
SDL_QuitSteamControllers();
|
||||
}
|
||||
|
||||
SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID( int device_index )
|
||||
SDL_JoystickDriver SDL_LINUX_JoystickDriver =
|
||||
{
|
||||
return JoystickByDevIndex(device_index)->guid;
|
||||
}
|
||||
|
||||
SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick)
|
||||
{
|
||||
return joystick->hwdata->guid;
|
||||
}
|
||||
LINUX_JoystickInit,
|
||||
LINUX_JoystickGetCount,
|
||||
LINUX_JoystickDetect,
|
||||
LINUX_JoystickGetDeviceName,
|
||||
LINUX_JoystickGetDeviceGUID,
|
||||
LINUX_JoystickGetDeviceInstanceID,
|
||||
LINUX_JoystickOpen,
|
||||
LINUX_JoystickIsAttached,
|
||||
LINUX_JoystickRumble,
|
||||
LINUX_JoystickUpdate,
|
||||
LINUX_JoystickClose,
|
||||
LINUX_JoystickQuit,
|
||||
};
|
||||
|
||||
#endif /* SDL_JOYSTICK_LINUX */
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue