mirror of https://github.com/encounter/SDL.git
Added game controller support for virtual joysticks
Fixes https://github.com/libsdl-org/SDL/issues/5662
This commit is contained in:
parent
996b3dc37a
commit
7ad15c5b8f
|
@ -464,6 +464,100 @@ static int SDLCALL SDL_GameControllerEventWatcher(void *userdata, SDL_Event * ev
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Helper function to guess at a mapping for virtual controllers
|
||||||
|
*/
|
||||||
|
static ControllerMapping_t *SDL_CreateMappingForVirtualController(SDL_JoystickGUID guid)
|
||||||
|
{
|
||||||
|
const int face_button_mask = ((1 << SDL_CONTROLLER_BUTTON_A) |
|
||||||
|
(1 << SDL_CONTROLLER_BUTTON_B) |
|
||||||
|
(1 << SDL_CONTROLLER_BUTTON_X) |
|
||||||
|
(1 << SDL_CONTROLLER_BUTTON_Y));
|
||||||
|
SDL_bool existing;
|
||||||
|
char mapping_string[1024];
|
||||||
|
int button_mask;
|
||||||
|
int axis_mask;
|
||||||
|
|
||||||
|
button_mask = SDL_SwapLE16(*(Uint16*)(&guid.data[sizeof(guid.data)-4]));
|
||||||
|
axis_mask = SDL_SwapLE16(*(Uint16*)(&guid.data[sizeof(guid.data)-2]));
|
||||||
|
if (!button_mask && !axis_mask) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (!(button_mask & face_button_mask)) {
|
||||||
|
/* We don't know what buttons or axes are supported, don't make up a mapping */
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_strlcpy(mapping_string, "none,*,", sizeof(mapping_string));
|
||||||
|
|
||||||
|
if (button_mask & (1 << SDL_CONTROLLER_BUTTON_A)) {
|
||||||
|
SDL_strlcat(mapping_string, "a:b0,", sizeof(mapping_string));
|
||||||
|
}
|
||||||
|
if (button_mask & (1 << SDL_CONTROLLER_BUTTON_B)) {
|
||||||
|
SDL_strlcat(mapping_string, "b:b1,", sizeof(mapping_string));
|
||||||
|
}
|
||||||
|
if (button_mask & (1 << SDL_CONTROLLER_BUTTON_X)) {
|
||||||
|
SDL_strlcat(mapping_string, "x:b2,", sizeof(mapping_string));
|
||||||
|
}
|
||||||
|
if (button_mask & (1 << SDL_CONTROLLER_BUTTON_Y)) {
|
||||||
|
SDL_strlcat(mapping_string, "y:b3,", sizeof(mapping_string));
|
||||||
|
}
|
||||||
|
if (button_mask & (1 << SDL_CONTROLLER_BUTTON_BACK)) {
|
||||||
|
SDL_strlcat(mapping_string, "back:b4,", sizeof(mapping_string));
|
||||||
|
}
|
||||||
|
if (button_mask & (1 << SDL_CONTROLLER_BUTTON_GUIDE)) {
|
||||||
|
SDL_strlcat(mapping_string, "guide:b5,", sizeof(mapping_string));
|
||||||
|
}
|
||||||
|
if (button_mask & (1 << SDL_CONTROLLER_BUTTON_START)) {
|
||||||
|
SDL_strlcat(mapping_string, "start:b6,", sizeof(mapping_string));
|
||||||
|
}
|
||||||
|
if (button_mask & (1 << SDL_CONTROLLER_BUTTON_LEFTSTICK)) {
|
||||||
|
SDL_strlcat(mapping_string, "leftstick:b7,", sizeof(mapping_string));
|
||||||
|
}
|
||||||
|
if (button_mask & (1 << SDL_CONTROLLER_BUTTON_RIGHTSTICK)) {
|
||||||
|
SDL_strlcat(mapping_string, "rightstick:b8,", sizeof(mapping_string));
|
||||||
|
}
|
||||||
|
if (button_mask & (1 << SDL_CONTROLLER_BUTTON_LEFTSHOULDER)) {
|
||||||
|
SDL_strlcat(mapping_string, "leftshoulder:b9,", sizeof(mapping_string));
|
||||||
|
}
|
||||||
|
if (button_mask & (1 << SDL_CONTROLLER_BUTTON_RIGHTSHOULDER)) {
|
||||||
|
SDL_strlcat(mapping_string, "rightshoulder:b10,", sizeof(mapping_string));
|
||||||
|
}
|
||||||
|
if (button_mask & (1 << SDL_CONTROLLER_BUTTON_DPAD_UP)) {
|
||||||
|
SDL_strlcat(mapping_string, "dpup:b11,", sizeof(mapping_string));
|
||||||
|
}
|
||||||
|
if (button_mask & (1 << SDL_CONTROLLER_BUTTON_DPAD_DOWN)) {
|
||||||
|
SDL_strlcat(mapping_string, "dpdown:b12,", sizeof(mapping_string));
|
||||||
|
}
|
||||||
|
if (button_mask & (1 << SDL_CONTROLLER_BUTTON_DPAD_LEFT)) {
|
||||||
|
SDL_strlcat(mapping_string, "dpleft:b13,", sizeof(mapping_string));
|
||||||
|
}
|
||||||
|
if (button_mask & (1 << SDL_CONTROLLER_BUTTON_DPAD_RIGHT)) {
|
||||||
|
SDL_strlcat(mapping_string, "dpright:b14,", sizeof(mapping_string));
|
||||||
|
}
|
||||||
|
if (axis_mask & (1 << SDL_CONTROLLER_AXIS_LEFTX)) {
|
||||||
|
SDL_strlcat(mapping_string, "leftx:a0,", sizeof(mapping_string));
|
||||||
|
}
|
||||||
|
if (axis_mask & (1 << SDL_CONTROLLER_AXIS_LEFTY)) {
|
||||||
|
SDL_strlcat(mapping_string, "lefty:a1,", sizeof(mapping_string));
|
||||||
|
}
|
||||||
|
if (axis_mask & (1 << SDL_CONTROLLER_AXIS_RIGHTX)) {
|
||||||
|
SDL_strlcat(mapping_string, "rightx:a2,", sizeof(mapping_string));
|
||||||
|
}
|
||||||
|
if (axis_mask & (1 << SDL_CONTROLLER_AXIS_RIGHTY)) {
|
||||||
|
SDL_strlcat(mapping_string, "righty:a3,", sizeof(mapping_string));
|
||||||
|
}
|
||||||
|
if (axis_mask & (1 << SDL_CONTROLLER_AXIS_TRIGGERLEFT)) {
|
||||||
|
SDL_strlcat(mapping_string, "lefttrigger:a4,", sizeof(mapping_string));
|
||||||
|
}
|
||||||
|
if (axis_mask & (1 << SDL_CONTROLLER_AXIS_TRIGGERRIGHT)) {
|
||||||
|
SDL_strlcat(mapping_string, "righttrigger:a5,", sizeof(mapping_string));
|
||||||
|
}
|
||||||
|
|
||||||
|
return SDL_PrivateAddMappingForGUID(guid, mapping_string,
|
||||||
|
&existing, SDL_CONTROLLER_MAPPING_PRIORITY_DEFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef __ANDROID__
|
#ifdef __ANDROID__
|
||||||
/*
|
/*
|
||||||
* Helper function to guess at a mapping based on the elements reported for this controller
|
* Helper function to guess at a mapping based on the elements reported for this controller
|
||||||
|
@ -696,6 +790,9 @@ static ControllerMapping_t *SDL_PrivateGetControllerMappingForGUID(SDL_JoystickG
|
||||||
return s_pXInputMapping;
|
return s_pXInputMapping;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
if (!mapping && SDL_IsJoystickVirtual(guid)) {
|
||||||
|
mapping = SDL_CreateMappingForVirtualController(guid);
|
||||||
|
}
|
||||||
#ifdef __ANDROID__
|
#ifdef __ANDROID__
|
||||||
if (!mapping && !SDL_IsJoystickHIDAPI(guid)) {
|
if (!mapping && !SDL_IsJoystickHIDAPI(guid)) {
|
||||||
mapping = SDL_CreateMappingForAndroidController(guid);
|
mapping = SDL_CreateMappingForAndroidController(guid);
|
||||||
|
|
|
@ -119,6 +119,7 @@ struct _SDL_Joystick
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Device bus definitions */
|
/* Device bus definitions */
|
||||||
|
#define SDL_HARDWARE_BUS_VIRTUAL 0x00
|
||||||
#define SDL_HARDWARE_BUS_USB 0x03
|
#define SDL_HARDWARE_BUS_USB 0x03
|
||||||
#define SDL_HARDWARE_BUS_BLUETOOTH 0x05
|
#define SDL_HARDWARE_BUS_BLUETOOTH 0x05
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
|
|
||||||
/* This is the virtual implementation of the SDL joystick API */
|
/* This is the virtual implementation of the SDL joystick API */
|
||||||
|
|
||||||
|
#include "SDL_endian.h"
|
||||||
#include "SDL_virtualjoystick_c.h"
|
#include "SDL_virtualjoystick_c.h"
|
||||||
#include "../SDL_sysjoystick.h"
|
#include "../SDL_sysjoystick.h"
|
||||||
#include "../SDL_joystick_c.h"
|
#include "../SDL_joystick_c.h"
|
||||||
|
@ -94,6 +95,11 @@ SDL_JoystickAttachVirtualInner(SDL_JoystickType type,
|
||||||
{
|
{
|
||||||
joystick_hwdata *hwdata = NULL;
|
joystick_hwdata *hwdata = NULL;
|
||||||
int device_index = -1;
|
int device_index = -1;
|
||||||
|
const Uint16 vendor_id = 0;
|
||||||
|
const Uint16 product_id = 0;
|
||||||
|
Uint16 button_mask = 0;
|
||||||
|
Uint16 axis_mask = 0;
|
||||||
|
Uint16 *guid16;
|
||||||
|
|
||||||
hwdata = SDL_calloc(1, sizeof(joystick_hwdata));
|
hwdata = SDL_calloc(1, sizeof(joystick_hwdata));
|
||||||
if (!hwdata) {
|
if (!hwdata) {
|
||||||
|
@ -104,7 +110,69 @@ SDL_JoystickAttachVirtualInner(SDL_JoystickType type,
|
||||||
hwdata->naxes = naxes;
|
hwdata->naxes = naxes;
|
||||||
hwdata->nbuttons = nbuttons;
|
hwdata->nbuttons = nbuttons;
|
||||||
hwdata->nhats = nhats;
|
hwdata->nhats = nhats;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case SDL_JOYSTICK_TYPE_GAMECONTROLLER:
|
||||||
|
hwdata->name = "Virtual Controller";
|
||||||
|
break;
|
||||||
|
case SDL_JOYSTICK_TYPE_WHEEL:
|
||||||
|
hwdata->name = "Virtual Wheel";
|
||||||
|
break;
|
||||||
|
case SDL_JOYSTICK_TYPE_ARCADE_STICK:
|
||||||
|
hwdata->name = "Virtual Arcade Stick";
|
||||||
|
break;
|
||||||
|
case SDL_JOYSTICK_TYPE_FLIGHT_STICK:
|
||||||
|
hwdata->name = "Virtual Flight Stick";
|
||||||
|
break;
|
||||||
|
case SDL_JOYSTICK_TYPE_DANCE_PAD:
|
||||||
|
hwdata->name = "Virtual Dance Pad";
|
||||||
|
break;
|
||||||
|
case SDL_JOYSTICK_TYPE_GUITAR:
|
||||||
|
hwdata->name = "Virtual Guitar";
|
||||||
|
break;
|
||||||
|
case SDL_JOYSTICK_TYPE_DRUM_KIT:
|
||||||
|
hwdata->name = "Virtual Drum Kit";
|
||||||
|
break;
|
||||||
|
case SDL_JOYSTICK_TYPE_ARCADE_PAD:
|
||||||
|
hwdata->name = "Virtual Arcade Pad";
|
||||||
|
break;
|
||||||
|
case SDL_JOYSTICK_TYPE_THROTTLE:
|
||||||
|
hwdata->name = "Virtual Throttle";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
hwdata->name = "Virtual Joystick";
|
hwdata->name = "Virtual Joystick";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == SDL_JOYSTICK_TYPE_GAMECONTROLLER) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (naxes >= 2) {
|
||||||
|
axis_mask |= ((1 << SDL_CONTROLLER_AXIS_LEFTX) | (1 << SDL_CONTROLLER_AXIS_LEFTY));
|
||||||
|
}
|
||||||
|
if (naxes >= 4) {
|
||||||
|
axis_mask |= ((1 << SDL_CONTROLLER_AXIS_RIGHTX) | (1 << SDL_CONTROLLER_AXIS_RIGHTY));
|
||||||
|
}
|
||||||
|
if (naxes >= 6) {
|
||||||
|
axis_mask |= ((1 << SDL_CONTROLLER_AXIS_TRIGGERLEFT) | (1 << SDL_CONTROLLER_AXIS_TRIGGERRIGHT));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < nbuttons && i < sizeof(Uint16)*8; ++i) {
|
||||||
|
button_mask |= (1 << i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We only need 16 bits for each of these; space them out to fill 128. */
|
||||||
|
/* Byteswap so devices get same GUID on little/big endian platforms. */
|
||||||
|
guid16 = (Uint16 *)hwdata->guid.data;
|
||||||
|
*guid16++ = SDL_SwapLE16(SDL_HARDWARE_BUS_VIRTUAL);
|
||||||
|
*guid16++ = 0;
|
||||||
|
*guid16++ = SDL_SwapLE16(vendor_id);
|
||||||
|
*guid16++ = 0;
|
||||||
|
*guid16++ = SDL_SwapLE16(product_id);
|
||||||
|
*guid16++ = 0;
|
||||||
|
*guid16++ = SDL_SwapLE16(button_mask);
|
||||||
|
*guid16++ = SDL_SwapLE16(axis_mask);
|
||||||
|
|
||||||
/* Note that this is a Virtual device and what subtype it is */
|
/* Note that this is a Virtual device and what subtype it is */
|
||||||
hwdata->guid.data[14] = 'v';
|
hwdata->guid.data[14] = 'v';
|
||||||
|
@ -326,6 +394,7 @@ VIRTUAL_JoystickOpen(SDL_Joystick *joystick, int device_index)
|
||||||
return SDL_SetError("No such device");
|
return SDL_SetError("No such device");
|
||||||
}
|
}
|
||||||
if (hwdata->opened) {
|
if (hwdata->opened) {
|
||||||
|
/* This should never happen, it's handled by the higher joystick code */
|
||||||
return SDL_SetError("Joystick already opened");
|
return SDL_SetError("Joystick already opened");
|
||||||
}
|
}
|
||||||
joystick->instance_id = hwdata->instance_id;
|
joystick->instance_id = hwdata->instance_id;
|
||||||
|
|
Loading…
Reference in New Issue