early-access version 1667
This commit is contained in:
+229
-42
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2021 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "SDL_thread.h"
|
||||
#include "SDL_timer.h"
|
||||
#include "SDL_joystick.h"
|
||||
#include "SDL_log.h"
|
||||
#include "../SDL_sysjoystick.h"
|
||||
#include "SDL_hidapijoystick_c.h"
|
||||
#include "SDL_hidapi_rumble.h"
|
||||
@@ -51,6 +52,24 @@
|
||||
#ifdef SDL_USE_LIBUDEV
|
||||
#include <poll.h>
|
||||
#endif
|
||||
#ifdef HAVE_INOTIFY
|
||||
#include <errno.h> /* errno, strerror */
|
||||
#include <fcntl.h>
|
||||
#include <limits.h> /* For the definition of NAME_MAX */
|
||||
#include <sys/inotify.h>
|
||||
#endif
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if defined(SDL_USE_LIBUDEV)
|
||||
typedef enum
|
||||
{
|
||||
ENUMERATION_UNSET,
|
||||
ENUMERATION_LIBUDEV,
|
||||
ENUMERATION_FALLBACK
|
||||
} LinuxEnumerationMethod;
|
||||
|
||||
static LinuxEnumerationMethod linux_enumeration_method = ENUMERATION_UNSET;
|
||||
#endif
|
||||
|
||||
struct joystick_hwdata
|
||||
@@ -59,12 +78,18 @@ struct joystick_hwdata
|
||||
};
|
||||
|
||||
static SDL_HIDAPI_DeviceDriver *SDL_HIDAPI_drivers[] = {
|
||||
#ifdef SDL_JOYSTICK_HIDAPI_GAMECUBE
|
||||
&SDL_HIDAPI_DriverGameCube,
|
||||
#endif
|
||||
#ifdef SDL_JOYSTICK_HIDAPI_PS4
|
||||
&SDL_HIDAPI_DriverPS4,
|
||||
#endif
|
||||
#ifdef SDL_JOYSTICK_HIDAPI_PS5
|
||||
&SDL_HIDAPI_DriverPS5,
|
||||
#endif
|
||||
#ifdef SDL_JOYSTICK_HIDAPI_STADIA
|
||||
&SDL_HIDAPI_DriverStadia,
|
||||
#endif
|
||||
#ifdef SDL_JOYSTICK_HIDAPI_STEAM
|
||||
&SDL_HIDAPI_DriverSteam,
|
||||
#endif
|
||||
@@ -78,9 +103,6 @@ static SDL_HIDAPI_DeviceDriver *SDL_HIDAPI_drivers[] = {
|
||||
#ifdef SDL_JOYSTICK_HIDAPI_XBOXONE
|
||||
&SDL_HIDAPI_DriverXboxOne,
|
||||
#endif
|
||||
#ifdef SDL_JOYSTICK_HIDAPI_GAMECUBE
|
||||
&SDL_HIDAPI_DriverGameCube,
|
||||
#endif
|
||||
};
|
||||
static int SDL_HIDAPI_numdrivers = 0;
|
||||
static SDL_SpinLock SDL_HIDAPI_spinlock;
|
||||
@@ -89,6 +111,10 @@ static int SDL_HIDAPI_numjoysticks = 0;
|
||||
static SDL_bool initialized = SDL_FALSE;
|
||||
static SDL_bool shutting_down = SDL_FALSE;
|
||||
|
||||
#if defined(HAVE_INOTIFY)
|
||||
static int inotify_fd = -1;
|
||||
#endif
|
||||
|
||||
#if defined(SDL_USE_LIBUDEV)
|
||||
static const SDL_UDEV_Symbols * usyms = NULL;
|
||||
#endif
|
||||
@@ -181,6 +207,46 @@ static void CallbackIOServiceFunc(void *context, io_iterator_t portIterator)
|
||||
}
|
||||
#endif /* __MACOSX__ */
|
||||
|
||||
#ifdef HAVE_INOTIFY
|
||||
#ifdef HAVE_INOTIFY_INIT1
|
||||
static int SDL_inotify_init1(void) {
|
||||
return inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
|
||||
}
|
||||
#else
|
||||
static int SDL_inotify_init1(void) {
|
||||
int fd = inotify_init();
|
||||
if (fd < 0) return -1;
|
||||
fcntl(fd, F_SETFL, O_NONBLOCK);
|
||||
fcntl(fd, F_SETFD, FD_CLOEXEC);
|
||||
return fd;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
StrHasPrefix(const char *string, const char *prefix)
|
||||
{
|
||||
return (SDL_strncmp(string, prefix, SDL_strlen(prefix)) == 0);
|
||||
}
|
||||
|
||||
static int
|
||||
StrIsInteger(const char *string)
|
||||
{
|
||||
const char *p;
|
||||
|
||||
if (*string == '\0') {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (p = string; *p != '\0'; p++) {
|
||||
if (*p < '0' || *p > '9') {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
HIDAPI_InitializeDiscovery()
|
||||
{
|
||||
@@ -270,24 +336,55 @@ HIDAPI_InitializeDiscovery()
|
||||
#endif // __MACOSX__
|
||||
|
||||
#if defined(SDL_USE_LIBUDEV)
|
||||
SDL_HIDAPI_discovery.m_pUdev = NULL;
|
||||
SDL_HIDAPI_discovery.m_pUdevMonitor = NULL;
|
||||
SDL_HIDAPI_discovery.m_nUdevFd = -1;
|
||||
if (linux_enumeration_method == ENUMERATION_LIBUDEV) {
|
||||
SDL_HIDAPI_discovery.m_pUdev = NULL;
|
||||
SDL_HIDAPI_discovery.m_pUdevMonitor = NULL;
|
||||
SDL_HIDAPI_discovery.m_nUdevFd = -1;
|
||||
|
||||
usyms = SDL_UDEV_GetUdevSyms();
|
||||
if (usyms) {
|
||||
SDL_HIDAPI_discovery.m_pUdev = usyms->udev_new();
|
||||
}
|
||||
if (SDL_HIDAPI_discovery.m_pUdev) {
|
||||
SDL_HIDAPI_discovery.m_pUdevMonitor = usyms->udev_monitor_new_from_netlink(SDL_HIDAPI_discovery.m_pUdev, "udev");
|
||||
if (SDL_HIDAPI_discovery.m_pUdevMonitor) {
|
||||
usyms->udev_monitor_enable_receiving(SDL_HIDAPI_discovery.m_pUdevMonitor);
|
||||
SDL_HIDAPI_discovery.m_nUdevFd = usyms->udev_monitor_get_fd(SDL_HIDAPI_discovery.m_pUdevMonitor);
|
||||
SDL_HIDAPI_discovery.m_bCanGetNotifications = SDL_TRUE;
|
||||
usyms = SDL_UDEV_GetUdevSyms();
|
||||
if (usyms) {
|
||||
SDL_HIDAPI_discovery.m_pUdev = usyms->udev_new();
|
||||
}
|
||||
if (SDL_HIDAPI_discovery.m_pUdev) {
|
||||
SDL_HIDAPI_discovery.m_pUdevMonitor = usyms->udev_monitor_new_from_netlink(SDL_HIDAPI_discovery.m_pUdev, "udev");
|
||||
if (SDL_HIDAPI_discovery.m_pUdevMonitor) {
|
||||
usyms->udev_monitor_enable_receiving(SDL_HIDAPI_discovery.m_pUdevMonitor);
|
||||
SDL_HIDAPI_discovery.m_nUdevFd = usyms->udev_monitor_get_fd(SDL_HIDAPI_discovery.m_pUdevMonitor);
|
||||
SDL_HIDAPI_discovery.m_bCanGetNotifications = SDL_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
#endif /* SDL_USE_LIBUDEV */
|
||||
{
|
||||
#if defined(HAVE_INOTIFY)
|
||||
inotify_fd = SDL_inotify_init1();
|
||||
|
||||
if (inotify_fd < 0) {
|
||||
SDL_LogWarn(SDL_LOG_CATEGORY_INPUT,
|
||||
"Unable to initialize inotify, falling back to polling: %s",
|
||||
strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
/* We need to watch for attribute changes in addition to
|
||||
* creation, because when a device is first created, it has
|
||||
* permissions that we can't read. When udev chmods it to
|
||||
* something that we maybe *can* read, we'll get an
|
||||
* IN_ATTRIB event to tell us. */
|
||||
if (inotify_add_watch(inotify_fd, "/dev",
|
||||
IN_CREATE | IN_DELETE | IN_MOVE | IN_ATTRIB) < 0) {
|
||||
close(inotify_fd);
|
||||
inotify_fd = -1;
|
||||
SDL_LogWarn(SDL_LOG_CATEGORY_INPUT,
|
||||
"Unable to add inotify watch, falling back to polling: %s",
|
||||
strerror (errno));
|
||||
return;
|
||||
}
|
||||
|
||||
SDL_HIDAPI_discovery.m_bCanGetNotifications = SDL_TRUE;
|
||||
#endif /* HAVE_INOTIFY */
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -328,31 +425,78 @@ HIDAPI_UpdateDiscovery()
|
||||
#endif
|
||||
|
||||
#if defined(SDL_USE_LIBUDEV)
|
||||
if (SDL_HIDAPI_discovery.m_nUdevFd >= 0) {
|
||||
/* Drain all notification events.
|
||||
* We don't expect a lot of device notifications so just
|
||||
* do a new discovery on any kind or number of notifications.
|
||||
* This could be made more restrictive if necessary.
|
||||
*/
|
||||
for (;;) {
|
||||
struct pollfd PollUdev;
|
||||
struct udev_device *pUdevDevice;
|
||||
if (linux_enumeration_method == ENUMERATION_LIBUDEV) {
|
||||
if (SDL_HIDAPI_discovery.m_nUdevFd >= 0) {
|
||||
/* Drain all notification events.
|
||||
* We don't expect a lot of device notifications so just
|
||||
* do a new discovery on any kind or number of notifications.
|
||||
* This could be made more restrictive if necessary.
|
||||
*/
|
||||
for (;;) {
|
||||
struct pollfd PollUdev;
|
||||
struct udev_device *pUdevDevice;
|
||||
|
||||
PollUdev.fd = SDL_HIDAPI_discovery.m_nUdevFd;
|
||||
PollUdev.events = POLLIN;
|
||||
if (poll(&PollUdev, 1, 0) != 1) {
|
||||
break;
|
||||
}
|
||||
PollUdev.fd = SDL_HIDAPI_discovery.m_nUdevFd;
|
||||
PollUdev.events = POLLIN;
|
||||
if (poll(&PollUdev, 1, 0) != 1) {
|
||||
break;
|
||||
}
|
||||
|
||||
SDL_HIDAPI_discovery.m_bHaveDevicesChanged = SDL_TRUE;
|
||||
|
||||
pUdevDevice = usyms->udev_monitor_receive_device(SDL_HIDAPI_discovery.m_pUdevMonitor);
|
||||
if (pUdevDevice) {
|
||||
usyms->udev_device_unref(pUdevDevice);
|
||||
pUdevDevice = usyms->udev_monitor_receive_device(SDL_HIDAPI_discovery.m_pUdevMonitor);
|
||||
if (pUdevDevice) {
|
||||
const char *action = NULL;
|
||||
action = usyms->udev_device_get_action(pUdevDevice);
|
||||
if (!action || SDL_strcmp(action, "add") == 0 || SDL_strcmp(action, "remove") == 0) {
|
||||
SDL_HIDAPI_discovery.m_bHaveDevicesChanged = SDL_TRUE;
|
||||
}
|
||||
usyms->udev_device_unref(pUdevDevice);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else
|
||||
#endif /* SDL_USE_LIBUDEV */
|
||||
{
|
||||
#if defined(HAVE_INOTIFY)
|
||||
if (inotify_fd >= 0) {
|
||||
union
|
||||
{
|
||||
struct inotify_event event;
|
||||
char storage[4096];
|
||||
char enough_for_inotify[sizeof (struct inotify_event) + NAME_MAX + 1];
|
||||
} buf;
|
||||
ssize_t bytes;
|
||||
size_t remain = 0;
|
||||
size_t len;
|
||||
|
||||
bytes = read(inotify_fd, &buf, sizeof (buf));
|
||||
|
||||
if (bytes > 0) {
|
||||
remain = (size_t) bytes;
|
||||
}
|
||||
|
||||
while (remain > 0) {
|
||||
if (buf.event.len > 0 &&
|
||||
!SDL_HIDAPI_discovery.m_bHaveDevicesChanged) {
|
||||
if (StrHasPrefix(buf.event.name, "hidraw") &&
|
||||
StrIsInteger(buf.event.name + strlen ("hidraw"))) {
|
||||
SDL_HIDAPI_discovery.m_bHaveDevicesChanged = SDL_TRUE;
|
||||
/* We found an hidraw change. We still continue to
|
||||
* drain the inotify fd to avoid leaving old
|
||||
* notifications in the queue. */
|
||||
}
|
||||
}
|
||||
|
||||
len = sizeof (struct inotify_event) + buf.event.len;
|
||||
remain -= len;
|
||||
|
||||
if (remain != 0) {
|
||||
memmove(&buf.storage[0], &buf.storage[len], remain);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* HAVE_INOTIFY */
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -376,7 +520,8 @@ HIDAPI_ShutdownDiscovery()
|
||||
#endif
|
||||
|
||||
#if defined(SDL_USE_LIBUDEV)
|
||||
if (usyms) {
|
||||
if (linux_enumeration_method == ENUMERATION_LIBUDEV &&
|
||||
usyms) {
|
||||
if (SDL_HIDAPI_discovery.m_pUdevMonitor) {
|
||||
usyms->udev_monitor_unref(SDL_HIDAPI_discovery.m_pUdevMonitor);
|
||||
}
|
||||
@@ -410,6 +555,12 @@ HIDAPI_DumpPacket(const char *prefix, Uint8 *data, int size)
|
||||
SDL_free(buffer);
|
||||
}
|
||||
|
||||
float
|
||||
HIDAPI_RemapVal(float val, float val_min, float val_max, float output_min, float output_max)
|
||||
{
|
||||
return output_min + (output_max - output_min) * (val - val_min) / (val_max - val_min);
|
||||
}
|
||||
|
||||
static void HIDAPI_JoystickDetect(void);
|
||||
static void HIDAPI_JoystickClose(SDL_Joystick * joystick);
|
||||
|
||||
@@ -437,8 +588,14 @@ HIDAPI_GetDeviceDriver(SDL_HIDAPI_Device *device)
|
||||
const Uint16 USAGE_MULTIAXISCONTROLLER = 0x0008;
|
||||
int i;
|
||||
SDL_GameControllerType type;
|
||||
SDL_JoystickGUID check_guid;
|
||||
|
||||
if (SDL_ShouldIgnoreJoystick(device->name, device->guid)) {
|
||||
/* Make sure we have a generic GUID here, otherwise if we pass a HIDAPI
|
||||
guid, this call will create a game controller mapping for the device.
|
||||
*/
|
||||
check_guid = device->guid;
|
||||
check_guid.data[14] = 0;
|
||||
if (SDL_ShouldIgnoreJoystick(device->name, check_guid)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -585,6 +742,28 @@ HIDAPI_JoystickInit(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(SDL_USE_LIBUDEV)
|
||||
if (linux_enumeration_method == ENUMERATION_UNSET) {
|
||||
if (SDL_getenv("SDL_HIDAPI_JOYSTICK_DISABLE_UDEV") != NULL) {
|
||||
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
|
||||
"udev disabled by SDL_HIDAPI_JOYSTICK_DISABLE_UDEV");
|
||||
linux_enumeration_method = ENUMERATION_FALLBACK;
|
||||
} else if (access("/.flatpak-info", F_OK) == 0
|
||||
|| access("/run/host/container-manager", F_OK) == 0) {
|
||||
/* Explicitly check `/.flatpak-info` because, for old versions of
|
||||
* Flatpak, this was the only available way to tell if we were in
|
||||
* a Flatpak container. */
|
||||
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
|
||||
"Container detected, disabling HIDAPI udev integration");
|
||||
linux_enumeration_method = ENUMERATION_FALLBACK;
|
||||
} else {
|
||||
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
|
||||
"Using udev for HIDAPI joystick device discovery");
|
||||
linux_enumeration_method = ENUMERATION_LIBUDEV;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__MACOSX__) || defined(__IPHONEOS__) || defined(__TVOS__)
|
||||
/* The hidapi framwork is weak-linked on Apple platforms */
|
||||
int HID_API_EXPORT HID_API_CALL hid_init(void) __attribute__((weak_import));
|
||||
@@ -883,12 +1062,13 @@ HIDAPI_UpdateDeviceList(void)
|
||||
}
|
||||
}
|
||||
|
||||
/* Remove any devices that weren't seen */
|
||||
/* Remove any devices that weren't seen or have been disconnected due to read errors */
|
||||
device = SDL_HIDAPI_devices;
|
||||
while (device) {
|
||||
SDL_HIDAPI_Device *next = device->next;
|
||||
|
||||
if (!device->seen) {
|
||||
if (!device->seen ||
|
||||
(device->driver && device->num_joysticks == 0 && !device->dev)) {
|
||||
HIDAPI_DelDevice(device);
|
||||
}
|
||||
device = next;
|
||||
@@ -1239,6 +1419,13 @@ HIDAPI_JoystickQuit(void)
|
||||
|
||||
SDL_HIDAPI_QuitRumble();
|
||||
|
||||
#if defined(HAVE_INOTIFY)
|
||||
if (inotify_fd >= 0) {
|
||||
close(inotify_fd);
|
||||
inotify_fd = -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
while (SDL_HIDAPI_devices) {
|
||||
HIDAPI_DelDevice(SDL_HIDAPI_devices);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user