joystick: Improve Xbox controller mapping with xpad quirks (#13305)
xpad has a series of questionable design choices when it comes to button mapping. Notably, BTN_TRIGGER_HAPPY1-4 are used for the D-pad on dance mats instead of the typical BTN_DPAD_*, and maps the paddles to BTN_TRIGGER_HAPPY5-8. This commit plumbs through driver detection for a udev device and adds special exceptions for xpad's quirks. Newer kernels (6.17+) add the BTN_GRIP* mappings for paddles on controllers. We should prefer that if available, as its meaning and mapping is unambiguous. However, since it's only in new kernels, we need to maintain the older mappings where we know they exist. It also exposes KEY_RECORD as the share button regardless of vendor, which had previously been gated behind being a Microsoft controller. All Xbox Series controllers can include this button, and many third party ones do.
This commit is contained in:
@@ -68,6 +68,7 @@ static bool SDL_UDEV_load_syms(void)
|
||||
|
||||
SDL_UDEV_SYM(udev_device_get_action);
|
||||
SDL_UDEV_SYM(udev_device_get_devnode);
|
||||
SDL_UDEV_SYM(udev_device_get_driver);
|
||||
SDL_UDEV_SYM(udev_device_get_syspath);
|
||||
SDL_UDEV_SYM(udev_device_get_subsystem);
|
||||
SDL_UDEV_SYM(udev_device_get_parent_with_subsystem_devtype);
|
||||
@@ -219,7 +220,7 @@ bool SDL_UDEV_Scan(void)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SDL_UDEV_GetProductInfo(const char *device_path, Uint16 *vendor, Uint16 *product, Uint16 *version, int *class)
|
||||
bool SDL_UDEV_GetProductInfo(const char *device_path, struct input_id *inpid, int *class, char **driver)
|
||||
{
|
||||
struct stat statbuf;
|
||||
char type;
|
||||
@@ -253,17 +254,27 @@ bool SDL_UDEV_GetProductInfo(const char *device_path, Uint16 *vendor, Uint16 *pr
|
||||
|
||||
val = _this->syms.udev_device_get_property_value(dev, "ID_VENDOR_ID");
|
||||
if (val) {
|
||||
*vendor = (Uint16)SDL_strtol(val, NULL, 16);
|
||||
inpid->vendor = (Uint16)SDL_strtol(val, NULL, 16);
|
||||
}
|
||||
|
||||
val = _this->syms.udev_device_get_property_value(dev, "ID_MODEL_ID");
|
||||
if (val) {
|
||||
*product = (Uint16)SDL_strtol(val, NULL, 16);
|
||||
inpid->product = (Uint16)SDL_strtol(val, NULL, 16);
|
||||
}
|
||||
|
||||
val = _this->syms.udev_device_get_property_value(dev, "ID_REVISION");
|
||||
if (val) {
|
||||
*version = (Uint16)SDL_strtol(val, NULL, 16);
|
||||
inpid->version = (Uint16)SDL_strtol(val, NULL, 16);
|
||||
}
|
||||
|
||||
if (driver) {
|
||||
val = _this->syms.udev_device_get_driver(dev);
|
||||
if (!val) {
|
||||
val = _this->syms.udev_device_get_property_value(dev, "ID_USB_DRIVER");
|
||||
}
|
||||
if (val) {
|
||||
*driver = SDL_strdup(val);
|
||||
}
|
||||
}
|
||||
|
||||
class_temp = device_class(dev);
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#endif
|
||||
|
||||
#include <libudev.h>
|
||||
#include <linux/input.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
@@ -56,6 +57,7 @@ typedef struct SDL_UDEV_Symbols
|
||||
{
|
||||
const char *(*udev_device_get_action)(struct udev_device *);
|
||||
const char *(*udev_device_get_devnode)(struct udev_device *);
|
||||
const char *(*udev_device_get_driver)(struct udev_device *);
|
||||
const char *(*udev_device_get_syspath)(struct udev_device *);
|
||||
const char *(*udev_device_get_subsystem)(struct udev_device *);
|
||||
struct udev_device *(*udev_device_get_parent_with_subsystem_devtype)(struct udev_device *udev_device, const char *subsystem, const char *devtype);
|
||||
@@ -102,7 +104,7 @@ extern void SDL_UDEV_UnloadLibrary(void);
|
||||
extern bool SDL_UDEV_LoadLibrary(void);
|
||||
extern void SDL_UDEV_Poll(void);
|
||||
extern bool SDL_UDEV_Scan(void);
|
||||
extern bool SDL_UDEV_GetProductInfo(const char *device_path, Uint16 *vendor, Uint16 *product, Uint16 *version, int *class);
|
||||
extern bool SDL_UDEV_GetProductInfo(const char *device_path, struct input_id *inpid, int *class, char **driver);
|
||||
extern bool SDL_UDEV_AddCallback(SDL_UDEV_Callback cb);
|
||||
extern void SDL_UDEV_DelCallback(SDL_UDEV_Callback cb);
|
||||
extern const SDL_UDEV_Symbols *SDL_UDEV_GetUdevSyms(void);
|
||||
|
||||
Reference in New Issue
Block a user