mirror of https://github.com/encounter/SDL.git
First pass at extending virtual controller functionality
Added the ability to specify a name and the product VID/PID for a virtual controller Also added a test case to testgamecontroller, if you pass --virtual as a parameter
This commit is contained in:
parent
7ad15c5b8f
commit
94eeb587c1
|
@ -348,6 +348,44 @@ extern DECLSPEC int SDLCALL SDL_JoystickAttachVirtual(SDL_JoystickType type,
|
||||||
int nbuttons,
|
int nbuttons,
|
||||||
int nhats);
|
int nhats);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The structure that defines an extended virtual joystick description
|
||||||
|
*
|
||||||
|
* The caller must zero the structure and then initialize the version with `SDL_VIRTUAL_JOYSTICK_DESC_VERSION` before passing it to SDL_JoystickAttachVirtualEx()
|
||||||
|
*
|
||||||
|
* \sa SDL_JoystickAttachVirtualEx
|
||||||
|
*/
|
||||||
|
typedef struct SDL_VirtualJoystickDesc
|
||||||
|
{
|
||||||
|
Uint16 version; /**< `SDL_VIRTUAL_JOYSTICK_DESC_VERSION` */
|
||||||
|
Uint16 type; /**< `SDL_JoystickType` */
|
||||||
|
Uint16 naxes; /**< the number of axes on this joystick */
|
||||||
|
Uint16 nbuttons; /**< the number of buttons on this joystick */
|
||||||
|
Uint16 nhats; /**< the number of hats on this joystick */
|
||||||
|
Uint16 vendor_id; /**< the USB vendor ID of this joystick */
|
||||||
|
Uint16 product_id; /**< the USB product ID of this joystick */
|
||||||
|
Uint16 padding; /**< unused */
|
||||||
|
const char *name; /**< the name of the joystick */
|
||||||
|
|
||||||
|
void *userdata; /**< User data pointer passed to callbacks */
|
||||||
|
void (*Update)(void *userdata); /**< Called when the joystick state should be updated */
|
||||||
|
|
||||||
|
} SDL_VirtualJoystickDesc;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief The current version of the SDL_VirtualJoystickDesc structure
|
||||||
|
*/
|
||||||
|
#define SDL_VIRTUAL_JOYSTICK_DESC_VERSION 1
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attach a new virtual joystick with extended properties.
|
||||||
|
*
|
||||||
|
* \returns the joystick's device index, or -1 if an error occurred.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 2.24.0.
|
||||||
|
*/
|
||||||
|
extern DECLSPEC int SDLCALL SDL_JoystickAttachVirtualEx(const SDL_VirtualJoystickDesc *desc);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Detach a virtual joystick.
|
* Detach a virtual joystick.
|
||||||
*
|
*
|
||||||
|
|
|
@ -870,3 +870,4 @@
|
||||||
#define SDL_GameControllerPath SDL_GameControllerPath_REAL
|
#define SDL_GameControllerPath SDL_GameControllerPath_REAL
|
||||||
#define SDL_JoystickPathForIndex SDL_JoystickPathForIndex_REAL
|
#define SDL_JoystickPathForIndex SDL_JoystickPathForIndex_REAL
|
||||||
#define SDL_JoystickPath SDL_JoystickPath_REAL
|
#define SDL_JoystickPath SDL_JoystickPath_REAL
|
||||||
|
#define SDL_JoystickAttachVirtualEx SDL_JoystickAttachVirtualEx_REAL
|
||||||
|
|
|
@ -941,3 +941,4 @@ SDL_DYNAPI_PROC(const char*,SDL_GameControllerPathForIndex,(int a),(a),return)
|
||||||
SDL_DYNAPI_PROC(const char*,SDL_GameControllerPath,(SDL_GameController *a),(a),return)
|
SDL_DYNAPI_PROC(const char*,SDL_GameControllerPath,(SDL_GameController *a),(a),return)
|
||||||
SDL_DYNAPI_PROC(const char*,SDL_JoystickPathForIndex,(int a),(a),return)
|
SDL_DYNAPI_PROC(const char*,SDL_JoystickPathForIndex,(int a),(a),return)
|
||||||
SDL_DYNAPI_PROC(const char*,SDL_JoystickPath,(SDL_Joystick *a),(a),return)
|
SDL_DYNAPI_PROC(const char*,SDL_JoystickPath,(SDL_Joystick *a),(a),return)
|
||||||
|
SDL_DYNAPI_PROC(int,SDL_JoystickAttachVirtualEx,(const SDL_VirtualJoystickDesc *a),(a),return)
|
||||||
|
|
|
@ -464,100 +464,6 @@ 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
|
||||||
|
@ -790,9 +696,6 @@ 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);
|
||||||
|
@ -1355,6 +1258,11 @@ static ControllerMapping_t *SDL_PrivateGenerateAutomaticControllerMapping(const
|
||||||
SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "dpdown", &raw_map->dpdown);
|
SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "dpdown", &raw_map->dpdown);
|
||||||
SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "dpleft", &raw_map->dpleft);
|
SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "dpleft", &raw_map->dpleft);
|
||||||
SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "dpright", &raw_map->dpright);
|
SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "dpright", &raw_map->dpright);
|
||||||
|
SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "misc1", &raw_map->misc1);
|
||||||
|
SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "paddle1", &raw_map->paddle1);
|
||||||
|
SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "paddle2", &raw_map->paddle2);
|
||||||
|
SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "paddle3", &raw_map->paddle3);
|
||||||
|
SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "paddle4", &raw_map->paddle4);
|
||||||
SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "leftx", &raw_map->leftx);
|
SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "leftx", &raw_map->leftx);
|
||||||
SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "lefty", &raw_map->lefty);
|
SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "lefty", &raw_map->lefty);
|
||||||
SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "rightx", &raw_map->rightx);
|
SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "rightx", &raw_map->rightx);
|
||||||
|
|
|
@ -522,9 +522,23 @@ SDL_JoystickOpen(int device_index)
|
||||||
int
|
int
|
||||||
SDL_JoystickAttachVirtual(SDL_JoystickType type,
|
SDL_JoystickAttachVirtual(SDL_JoystickType type,
|
||||||
int naxes, int nbuttons, int nhats)
|
int naxes, int nbuttons, int nhats)
|
||||||
|
{
|
||||||
|
SDL_VirtualJoystickDesc desc;
|
||||||
|
|
||||||
|
SDL_zero(desc);
|
||||||
|
desc.version = SDL_VIRTUAL_JOYSTICK_DESC_VERSION;
|
||||||
|
desc.type = (Uint16)type;
|
||||||
|
desc.naxes = (Uint16)naxes;
|
||||||
|
desc.nbuttons = (Uint16)nbuttons;
|
||||||
|
desc.nhats = (Uint16)nhats;
|
||||||
|
return SDL_JoystickAttachVirtualEx(&desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
SDL_JoystickAttachVirtualEx(const SDL_VirtualJoystickDesc *desc)
|
||||||
{
|
{
|
||||||
#if SDL_JOYSTICK_VIRTUAL
|
#if SDL_JOYSTICK_VIRTUAL
|
||||||
return SDL_JoystickAttachVirtualInner(type, naxes, nbuttons, nhats);
|
return SDL_JoystickAttachVirtualInner(desc);
|
||||||
#else
|
#else
|
||||||
return SDL_SetError("SDL not built with virtual-joystick support");
|
return SDL_SetError("SDL not built with virtual-joystick support");
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -168,6 +168,11 @@ typedef struct _SDL_GamepadMapping
|
||||||
SDL_InputMapping dpdown;
|
SDL_InputMapping dpdown;
|
||||||
SDL_InputMapping dpleft;
|
SDL_InputMapping dpleft;
|
||||||
SDL_InputMapping dpright;
|
SDL_InputMapping dpright;
|
||||||
|
SDL_InputMapping misc1;
|
||||||
|
SDL_InputMapping paddle1;
|
||||||
|
SDL_InputMapping paddle2;
|
||||||
|
SDL_InputMapping paddle3;
|
||||||
|
SDL_InputMapping paddle4;
|
||||||
SDL_InputMapping leftx;
|
SDL_InputMapping leftx;
|
||||||
SDL_InputMapping lefty;
|
SDL_InputMapping lefty;
|
||||||
SDL_InputMapping rightx;
|
SDL_InputMapping rightx;
|
||||||
|
|
|
@ -56,18 +56,6 @@ VIRTUAL_FreeHWData(joystick_hwdata *hwdata)
|
||||||
if (!hwdata) {
|
if (!hwdata) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (hwdata->axes) {
|
|
||||||
SDL_free((void *)hwdata->axes);
|
|
||||||
hwdata->axes = NULL;
|
|
||||||
}
|
|
||||||
if (hwdata->buttons) {
|
|
||||||
SDL_free((void *)hwdata->buttons);
|
|
||||||
hwdata->buttons = NULL;
|
|
||||||
}
|
|
||||||
if (hwdata->hats) {
|
|
||||||
SDL_free(hwdata->hats);
|
|
||||||
hwdata->hats = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Remove hwdata from SDL-global list */
|
/* Remove hwdata from SDL-global list */
|
||||||
while (cur) {
|
while (cur) {
|
||||||
|
@ -83,81 +71,103 @@ VIRTUAL_FreeHWData(joystick_hwdata *hwdata)
|
||||||
cur = cur->next;
|
cur = cur->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hwdata->name) {
|
||||||
|
SDL_free(hwdata->name);
|
||||||
|
hwdata->name = NULL;
|
||||||
|
}
|
||||||
|
if (hwdata->axes) {
|
||||||
|
SDL_free((void *)hwdata->axes);
|
||||||
|
hwdata->axes = NULL;
|
||||||
|
}
|
||||||
|
if (hwdata->buttons) {
|
||||||
|
SDL_free((void *)hwdata->buttons);
|
||||||
|
hwdata->buttons = NULL;
|
||||||
|
}
|
||||||
|
if (hwdata->hats) {
|
||||||
|
SDL_free(hwdata->hats);
|
||||||
|
hwdata->hats = NULL;
|
||||||
|
}
|
||||||
SDL_free(hwdata);
|
SDL_free(hwdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
SDL_JoystickAttachVirtualInner(SDL_JoystickType type,
|
SDL_JoystickAttachVirtualInner(const SDL_VirtualJoystickDesc *desc)
|
||||||
int naxes,
|
|
||||||
int nbuttons,
|
|
||||||
int nhats)
|
|
||||||
{
|
{
|
||||||
joystick_hwdata *hwdata = NULL;
|
joystick_hwdata *hwdata = NULL;
|
||||||
int device_index = -1;
|
int device_index = -1;
|
||||||
const Uint16 vendor_id = 0;
|
const char *name = NULL;
|
||||||
const Uint16 product_id = 0;
|
|
||||||
Uint16 button_mask = 0;
|
Uint16 button_mask = 0;
|
||||||
Uint16 axis_mask = 0;
|
Uint16 axis_mask = 0;
|
||||||
Uint16 *guid16;
|
Uint16 *guid16;
|
||||||
|
|
||||||
|
if (!desc) {
|
||||||
|
return SDL_InvalidParamError("desc");
|
||||||
|
}
|
||||||
|
if (desc->version != SDL_VIRTUAL_JOYSTICK_DESC_VERSION) {
|
||||||
|
/* Is this an old version that we can support? */
|
||||||
|
return SDL_SetError("Unsupported virtual joystick description version %d", desc->version);
|
||||||
|
}
|
||||||
|
|
||||||
hwdata = SDL_calloc(1, sizeof(joystick_hwdata));
|
hwdata = SDL_calloc(1, sizeof(joystick_hwdata));
|
||||||
if (!hwdata) {
|
if (!hwdata) {
|
||||||
VIRTUAL_FreeHWData(hwdata);
|
VIRTUAL_FreeHWData(hwdata);
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
}
|
}
|
||||||
|
SDL_memcpy(&hwdata->desc, desc, sizeof(*desc));
|
||||||
|
|
||||||
hwdata->naxes = naxes;
|
if (desc->name) {
|
||||||
hwdata->nbuttons = nbuttons;
|
name = desc->name;
|
||||||
hwdata->nhats = nhats;
|
} else {
|
||||||
|
switch (desc->type) {
|
||||||
switch (type) {
|
case SDL_JOYSTICK_TYPE_GAMECONTROLLER:
|
||||||
case SDL_JOYSTICK_TYPE_GAMECONTROLLER:
|
name = "Virtual Controller";
|
||||||
hwdata->name = "Virtual Controller";
|
break;
|
||||||
break;
|
case SDL_JOYSTICK_TYPE_WHEEL:
|
||||||
case SDL_JOYSTICK_TYPE_WHEEL:
|
name = "Virtual Wheel";
|
||||||
hwdata->name = "Virtual Wheel";
|
break;
|
||||||
break;
|
case SDL_JOYSTICK_TYPE_ARCADE_STICK:
|
||||||
case SDL_JOYSTICK_TYPE_ARCADE_STICK:
|
name = "Virtual Arcade Stick";
|
||||||
hwdata->name = "Virtual Arcade Stick";
|
break;
|
||||||
break;
|
case SDL_JOYSTICK_TYPE_FLIGHT_STICK:
|
||||||
case SDL_JOYSTICK_TYPE_FLIGHT_STICK:
|
name = "Virtual Flight Stick";
|
||||||
hwdata->name = "Virtual Flight Stick";
|
break;
|
||||||
break;
|
case SDL_JOYSTICK_TYPE_DANCE_PAD:
|
||||||
case SDL_JOYSTICK_TYPE_DANCE_PAD:
|
name = "Virtual Dance Pad";
|
||||||
hwdata->name = "Virtual Dance Pad";
|
break;
|
||||||
break;
|
case SDL_JOYSTICK_TYPE_GUITAR:
|
||||||
case SDL_JOYSTICK_TYPE_GUITAR:
|
name = "Virtual Guitar";
|
||||||
hwdata->name = "Virtual Guitar";
|
break;
|
||||||
break;
|
case SDL_JOYSTICK_TYPE_DRUM_KIT:
|
||||||
case SDL_JOYSTICK_TYPE_DRUM_KIT:
|
name = "Virtual Drum Kit";
|
||||||
hwdata->name = "Virtual Drum Kit";
|
break;
|
||||||
break;
|
case SDL_JOYSTICK_TYPE_ARCADE_PAD:
|
||||||
case SDL_JOYSTICK_TYPE_ARCADE_PAD:
|
name = "Virtual Arcade Pad";
|
||||||
hwdata->name = "Virtual Arcade Pad";
|
break;
|
||||||
break;
|
case SDL_JOYSTICK_TYPE_THROTTLE:
|
||||||
case SDL_JOYSTICK_TYPE_THROTTLE:
|
name = "Virtual Throttle";
|
||||||
hwdata->name = "Virtual Throttle";
|
break;
|
||||||
break;
|
default:
|
||||||
default:
|
name = "Virtual Joystick";
|
||||||
hwdata->name = "Virtual Joystick";
|
break;
|
||||||
break;
|
}
|
||||||
}
|
}
|
||||||
|
hwdata->name = SDL_strdup(name);
|
||||||
|
|
||||||
if (type == SDL_JOYSTICK_TYPE_GAMECONTROLLER) {
|
if (desc->type == SDL_JOYSTICK_TYPE_GAMECONTROLLER) {
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (naxes >= 2) {
|
if (desc->naxes >= 2) {
|
||||||
axis_mask |= ((1 << SDL_CONTROLLER_AXIS_LEFTX) | (1 << SDL_CONTROLLER_AXIS_LEFTY));
|
axis_mask |= ((1 << SDL_CONTROLLER_AXIS_LEFTX) | (1 << SDL_CONTROLLER_AXIS_LEFTY));
|
||||||
}
|
}
|
||||||
if (naxes >= 4) {
|
if (desc->naxes >= 4) {
|
||||||
axis_mask |= ((1 << SDL_CONTROLLER_AXIS_RIGHTX) | (1 << SDL_CONTROLLER_AXIS_RIGHTY));
|
axis_mask |= ((1 << SDL_CONTROLLER_AXIS_RIGHTX) | (1 << SDL_CONTROLLER_AXIS_RIGHTY));
|
||||||
}
|
}
|
||||||
if (naxes >= 6) {
|
if (desc->naxes >= 6) {
|
||||||
axis_mask |= ((1 << SDL_CONTROLLER_AXIS_TRIGGERLEFT) | (1 << SDL_CONTROLLER_AXIS_TRIGGERRIGHT));
|
axis_mask |= ((1 << SDL_CONTROLLER_AXIS_TRIGGERLEFT) | (1 << SDL_CONTROLLER_AXIS_TRIGGERRIGHT));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < nbuttons && i < sizeof(Uint16)*8; ++i) {
|
for (i = 0; i < desc->nbuttons && i < sizeof(Uint16)*8; ++i) {
|
||||||
button_mask |= (1 << i);
|
button_mask |= (1 << i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -167,34 +177,41 @@ SDL_JoystickAttachVirtualInner(SDL_JoystickType type,
|
||||||
guid16 = (Uint16 *)hwdata->guid.data;
|
guid16 = (Uint16 *)hwdata->guid.data;
|
||||||
*guid16++ = SDL_SwapLE16(SDL_HARDWARE_BUS_VIRTUAL);
|
*guid16++ = SDL_SwapLE16(SDL_HARDWARE_BUS_VIRTUAL);
|
||||||
*guid16++ = 0;
|
*guid16++ = 0;
|
||||||
*guid16++ = SDL_SwapLE16(vendor_id);
|
*guid16++ = SDL_SwapLE16(desc->vendor_id);
|
||||||
*guid16++ = 0;
|
*guid16++ = 0;
|
||||||
*guid16++ = SDL_SwapLE16(product_id);
|
*guid16++ = SDL_SwapLE16(desc->product_id);
|
||||||
*guid16++ = 0;
|
*guid16++ = 0;
|
||||||
*guid16++ = SDL_SwapLE16(button_mask);
|
*guid16++ = SDL_SwapLE16(button_mask);
|
||||||
*guid16++ = SDL_SwapLE16(axis_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';
|
||||||
hwdata->guid.data[15] = (Uint8)type;
|
hwdata->guid.data[15] = (Uint8)desc->type;
|
||||||
|
|
||||||
/* Allocate fields for different control-types */
|
/* Allocate fields for different control-types */
|
||||||
if (naxes > 0) {
|
if (desc->naxes > 0) {
|
||||||
hwdata->axes = SDL_calloc(naxes, sizeof(Sint16));
|
hwdata->axes = SDL_calloc(desc->naxes, sizeof(Sint16));
|
||||||
if (!hwdata->axes) {
|
if (!hwdata->axes) {
|
||||||
VIRTUAL_FreeHWData(hwdata);
|
VIRTUAL_FreeHWData(hwdata);
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Trigger axes are at minimum value at rest */
|
||||||
|
if (desc->type == SDL_JOYSTICK_TYPE_GAMECONTROLLER &&
|
||||||
|
desc->naxes > SDL_CONTROLLER_AXIS_TRIGGERRIGHT) {
|
||||||
|
hwdata->axes[SDL_CONTROLLER_AXIS_TRIGGERLEFT] = SDL_JOYSTICK_AXIS_MIN;
|
||||||
|
hwdata->axes[SDL_CONTROLLER_AXIS_TRIGGERRIGHT] = SDL_JOYSTICK_AXIS_MIN;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (nbuttons > 0) {
|
if (desc->nbuttons > 0) {
|
||||||
hwdata->buttons = SDL_calloc(nbuttons, sizeof(Uint8));
|
hwdata->buttons = SDL_calloc(desc->nbuttons, sizeof(Uint8));
|
||||||
if (!hwdata->buttons) {
|
if (!hwdata->buttons) {
|
||||||
VIRTUAL_FreeHWData(hwdata);
|
VIRTUAL_FreeHWData(hwdata);
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (nhats > 0) {
|
if (desc->nhats > 0) {
|
||||||
hwdata->hats = SDL_calloc(nhats, sizeof(Uint8));
|
hwdata->hats = SDL_calloc(desc->nhats, sizeof(Uint8));
|
||||||
if (!hwdata->hats) {
|
if (!hwdata->hats) {
|
||||||
VIRTUAL_FreeHWData(hwdata);
|
VIRTUAL_FreeHWData(hwdata);
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
|
@ -243,7 +260,7 @@ SDL_JoystickSetVirtualAxisInner(SDL_Joystick *joystick, int axis, Sint16 value)
|
||||||
}
|
}
|
||||||
|
|
||||||
hwdata = (joystick_hwdata *)joystick->hwdata;
|
hwdata = (joystick_hwdata *)joystick->hwdata;
|
||||||
if (axis < 0 || axis >= hwdata->naxes) {
|
if (axis < 0 || axis >= hwdata->desc.naxes) {
|
||||||
SDL_UnlockJoysticks();
|
SDL_UnlockJoysticks();
|
||||||
return SDL_SetError("Invalid axis index");
|
return SDL_SetError("Invalid axis index");
|
||||||
}
|
}
|
||||||
|
@ -268,7 +285,7 @@ SDL_JoystickSetVirtualButtonInner(SDL_Joystick *joystick, int button, Uint8 valu
|
||||||
}
|
}
|
||||||
|
|
||||||
hwdata = (joystick_hwdata *)joystick->hwdata;
|
hwdata = (joystick_hwdata *)joystick->hwdata;
|
||||||
if (button < 0 || button >= hwdata->nbuttons) {
|
if (button < 0 || button >= hwdata->desc.nbuttons) {
|
||||||
SDL_UnlockJoysticks();
|
SDL_UnlockJoysticks();
|
||||||
return SDL_SetError("Invalid button index");
|
return SDL_SetError("Invalid button index");
|
||||||
}
|
}
|
||||||
|
@ -293,7 +310,7 @@ SDL_JoystickSetVirtualHatInner(SDL_Joystick *joystick, int hat, Uint8 value)
|
||||||
}
|
}
|
||||||
|
|
||||||
hwdata = (joystick_hwdata *)joystick->hwdata;
|
hwdata = (joystick_hwdata *)joystick->hwdata;
|
||||||
if (hat < 0 || hat >= hwdata->nhats) {
|
if (hat < 0 || hat >= hwdata->desc.nhats) {
|
||||||
SDL_UnlockJoysticks();
|
SDL_UnlockJoysticks();
|
||||||
return SDL_SetError("Invalid hat index");
|
return SDL_SetError("Invalid hat index");
|
||||||
}
|
}
|
||||||
|
@ -338,7 +355,7 @@ VIRTUAL_JoystickGetDeviceName(int device_index)
|
||||||
if (!hwdata) {
|
if (!hwdata) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return hwdata->name ? hwdata->name : "";
|
return hwdata->name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -399,9 +416,9 @@ VIRTUAL_JoystickOpen(SDL_Joystick *joystick, int device_index)
|
||||||
}
|
}
|
||||||
joystick->instance_id = hwdata->instance_id;
|
joystick->instance_id = hwdata->instance_id;
|
||||||
joystick->hwdata = hwdata;
|
joystick->hwdata = hwdata;
|
||||||
joystick->naxes = hwdata->naxes;
|
joystick->naxes = hwdata->desc.naxes;
|
||||||
joystick->nbuttons = hwdata->nbuttons;
|
joystick->nbuttons = hwdata->desc.nbuttons;
|
||||||
joystick->nhats = hwdata->nhats;
|
joystick->nhats = hwdata->desc.nhats;
|
||||||
hwdata->opened = SDL_TRUE;
|
hwdata->opened = SDL_TRUE;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -461,13 +478,17 @@ VIRTUAL_JoystickUpdate(SDL_Joystick *joystick)
|
||||||
|
|
||||||
hwdata = (joystick_hwdata *)joystick->hwdata;
|
hwdata = (joystick_hwdata *)joystick->hwdata;
|
||||||
|
|
||||||
for (i = 0; i < hwdata->naxes; ++i) {
|
if (hwdata->desc.Update) {
|
||||||
|
hwdata->desc.Update(hwdata->desc.userdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < hwdata->desc.naxes; ++i) {
|
||||||
SDL_PrivateJoystickAxis(joystick, i, hwdata->axes[i]);
|
SDL_PrivateJoystickAxis(joystick, i, hwdata->axes[i]);
|
||||||
}
|
}
|
||||||
for (i = 0; i < hwdata->nbuttons; ++i) {
|
for (i = 0; i < hwdata->desc.nbuttons; ++i) {
|
||||||
SDL_PrivateJoystickButton(joystick, i, hwdata->buttons[i]);
|
SDL_PrivateJoystickButton(joystick, i, hwdata->buttons[i]);
|
||||||
}
|
}
|
||||||
for (i = 0; i < hwdata->nhats; ++i) {
|
for (i = 0; i < hwdata->desc.nhats; ++i) {
|
||||||
SDL_PrivateJoystickHat(joystick, i, hwdata->hats[i]);
|
SDL_PrivateJoystickHat(joystick, i, hwdata->hats[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -501,7 +522,134 @@ VIRTUAL_JoystickQuit(void)
|
||||||
static SDL_bool
|
static SDL_bool
|
||||||
VIRTUAL_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out)
|
VIRTUAL_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out)
|
||||||
{
|
{
|
||||||
return SDL_FALSE;
|
joystick_hwdata *hwdata = VIRTUAL_HWDataForIndex(device_index);
|
||||||
|
|
||||||
|
if (hwdata->desc.type != SDL_JOYSTICK_TYPE_GAMECONTROLLER) {
|
||||||
|
return SDL_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hwdata->desc.nbuttons > SDL_CONTROLLER_BUTTON_A) {
|
||||||
|
out->a.kind = EMappingKind_Button;
|
||||||
|
out->a.target = SDL_CONTROLLER_BUTTON_A;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hwdata->desc.nbuttons > SDL_CONTROLLER_BUTTON_B) {
|
||||||
|
out->b.kind = EMappingKind_Button;
|
||||||
|
out->b.target = SDL_CONTROLLER_BUTTON_B;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hwdata->desc.nbuttons > SDL_CONTROLLER_BUTTON_X) {
|
||||||
|
out->x.kind = EMappingKind_Button;
|
||||||
|
out->x.target = SDL_CONTROLLER_BUTTON_X;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hwdata->desc.nbuttons > SDL_CONTROLLER_BUTTON_Y) {
|
||||||
|
out->y.kind = EMappingKind_Button;
|
||||||
|
out->y.target = SDL_CONTROLLER_BUTTON_Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hwdata->desc.nbuttons > SDL_CONTROLLER_BUTTON_BACK) {
|
||||||
|
out->back.kind = EMappingKind_Button;
|
||||||
|
out->back.target = SDL_CONTROLLER_BUTTON_BACK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hwdata->desc.nbuttons > SDL_CONTROLLER_BUTTON_GUIDE) {
|
||||||
|
out->guide.kind = EMappingKind_Button;
|
||||||
|
out->guide.target = SDL_CONTROLLER_BUTTON_GUIDE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hwdata->desc.nbuttons > SDL_CONTROLLER_BUTTON_START) {
|
||||||
|
out->start.kind = EMappingKind_Button;
|
||||||
|
out->start.target = SDL_CONTROLLER_BUTTON_START;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hwdata->desc.nbuttons > SDL_CONTROLLER_BUTTON_LEFTSTICK) {
|
||||||
|
out->leftstick.kind = EMappingKind_Button;
|
||||||
|
out->leftstick.target = SDL_CONTROLLER_BUTTON_LEFTSTICK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hwdata->desc.nbuttons > SDL_CONTROLLER_BUTTON_RIGHTSTICK) {
|
||||||
|
out->rightstick.kind = EMappingKind_Button;
|
||||||
|
out->rightstick.target = SDL_CONTROLLER_BUTTON_RIGHTSTICK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hwdata->desc.nbuttons > SDL_CONTROLLER_BUTTON_LEFTSHOULDER) {
|
||||||
|
out->leftshoulder.kind = EMappingKind_Button;
|
||||||
|
out->leftshoulder.target = SDL_CONTROLLER_BUTTON_LEFTSHOULDER;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hwdata->desc.nbuttons > SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) {
|
||||||
|
out->rightshoulder.kind = EMappingKind_Button;
|
||||||
|
out->rightshoulder.target = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hwdata->desc.nbuttons > SDL_CONTROLLER_BUTTON_DPAD_UP) {
|
||||||
|
out->dpup.kind = EMappingKind_Button;
|
||||||
|
out->dpup.target = SDL_CONTROLLER_BUTTON_DPAD_UP;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hwdata->desc.nbuttons > SDL_CONTROLLER_BUTTON_DPAD_DOWN) {
|
||||||
|
out->dpdown.kind = EMappingKind_Button;
|
||||||
|
out->dpdown.target = SDL_CONTROLLER_BUTTON_DPAD_DOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hwdata->desc.nbuttons > SDL_CONTROLLER_BUTTON_DPAD_LEFT) {
|
||||||
|
out->dpleft.kind = EMappingKind_Button;
|
||||||
|
out->dpleft.target = SDL_CONTROLLER_BUTTON_DPAD_LEFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hwdata->desc.nbuttons > SDL_CONTROLLER_BUTTON_DPAD_RIGHT) {
|
||||||
|
out->dpright.kind = EMappingKind_Button;
|
||||||
|
out->dpright.target = SDL_CONTROLLER_BUTTON_DPAD_RIGHT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hwdata->desc.nbuttons > SDL_CONTROLLER_BUTTON_MISC1) {
|
||||||
|
out->misc1.kind = EMappingKind_Button;
|
||||||
|
out->misc1.target = SDL_CONTROLLER_BUTTON_MISC1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hwdata->desc.nbuttons > SDL_CONTROLLER_BUTTON_PADDLE1) {
|
||||||
|
out->paddle1.kind = EMappingKind_Button;
|
||||||
|
out->paddle1.target = SDL_CONTROLLER_BUTTON_PADDLE1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hwdata->desc.nbuttons > SDL_CONTROLLER_BUTTON_PADDLE2) {
|
||||||
|
out->paddle2.kind = EMappingKind_Button;
|
||||||
|
out->paddle2.target = SDL_CONTROLLER_BUTTON_PADDLE2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hwdata->desc.nbuttons > SDL_CONTROLLER_BUTTON_PADDLE3) {
|
||||||
|
out->paddle3.kind = EMappingKind_Button;
|
||||||
|
out->paddle3.target = SDL_CONTROLLER_BUTTON_PADDLE3;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hwdata->desc.nbuttons > SDL_CONTROLLER_BUTTON_PADDLE4) {
|
||||||
|
out->paddle4.kind = EMappingKind_Button;
|
||||||
|
out->paddle4.target = SDL_CONTROLLER_BUTTON_PADDLE4;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hwdata->desc.naxes > SDL_CONTROLLER_AXIS_LEFTY) {
|
||||||
|
out->leftx.kind = EMappingKind_Axis;
|
||||||
|
out->lefty.kind = EMappingKind_Axis;
|
||||||
|
out->leftx.target = SDL_CONTROLLER_AXIS_LEFTX;
|
||||||
|
out->lefty.target = SDL_CONTROLLER_AXIS_LEFTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hwdata->desc.naxes > SDL_CONTROLLER_AXIS_RIGHTY) {
|
||||||
|
out->rightx.kind = EMappingKind_Axis;
|
||||||
|
out->righty.kind = EMappingKind_Axis;
|
||||||
|
out->rightx.target = SDL_CONTROLLER_AXIS_RIGHTX;
|
||||||
|
out->righty.target = SDL_CONTROLLER_AXIS_RIGHTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hwdata->desc.naxes > SDL_CONTROLLER_AXIS_TRIGGERRIGHT) {
|
||||||
|
out->lefttrigger.kind = EMappingKind_Axis;
|
||||||
|
out->righttrigger.kind = EMappingKind_Axis;
|
||||||
|
out->lefttrigger.target = SDL_CONTROLLER_AXIS_TRIGGERLEFT;
|
||||||
|
out->righttrigger.target = SDL_CONTROLLER_AXIS_TRIGGERRIGHT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SDL_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_JoystickDriver SDL_VIRTUAL_JoystickDriver =
|
SDL_JoystickDriver SDL_VIRTUAL_JoystickDriver =
|
||||||
|
|
|
@ -34,24 +34,18 @@ typedef struct joystick_hwdata
|
||||||
{
|
{
|
||||||
SDL_JoystickType type;
|
SDL_JoystickType type;
|
||||||
SDL_bool attached;
|
SDL_bool attached;
|
||||||
const char *name;
|
char *name;
|
||||||
SDL_JoystickGUID guid;
|
SDL_JoystickGUID guid;
|
||||||
int naxes;
|
SDL_VirtualJoystickDesc desc;
|
||||||
Sint16 *axes;
|
Sint16 *axes;
|
||||||
int nbuttons;
|
|
||||||
Uint8 *buttons;
|
Uint8 *buttons;
|
||||||
int nhats;
|
|
||||||
Uint8 *hats;
|
Uint8 *hats;
|
||||||
SDL_JoystickID instance_id;
|
SDL_JoystickID instance_id;
|
||||||
SDL_bool opened;
|
SDL_bool opened;
|
||||||
struct joystick_hwdata *next;
|
struct joystick_hwdata *next;
|
||||||
} joystick_hwdata;
|
} joystick_hwdata;
|
||||||
|
|
||||||
int SDL_JoystickAttachVirtualInner(SDL_JoystickType type,
|
int SDL_JoystickAttachVirtualInner(const SDL_VirtualJoystickDesc *desc);
|
||||||
int naxes,
|
|
||||||
int nbuttons,
|
|
||||||
int nhats);
|
|
||||||
|
|
||||||
int SDL_JoystickDetachVirtualInner(int device_index);
|
int SDL_JoystickDetachVirtualInner(int device_index);
|
||||||
|
|
||||||
int SDL_JoystickSetVirtualAxisInner(SDL_Joystick * joystick, int axis, Sint16 value);
|
int SDL_JoystickSetVirtualAxisInner(SDL_Joystick * joystick, int axis, Sint16 value);
|
||||||
|
@ -59,4 +53,7 @@ int SDL_JoystickSetVirtualButtonInner(SDL_Joystick * joystick, int button, Uint8
|
||||||
int SDL_JoystickSetVirtualHatInner(SDL_Joystick * joystick, int hat, Uint8 value);
|
int SDL_JoystickSetVirtualHatInner(SDL_Joystick * joystick, int hat, Uint8 value);
|
||||||
|
|
||||||
#endif /* SDL_JOYSTICK_VIRTUAL */
|
#endif /* SDL_JOYSTICK_VIRTUAL */
|
||||||
|
|
||||||
#endif /* SDL_VIRTUALJOYSTICK_C_H */
|
#endif /* SDL_VIRTUALJOYSTICK_C_H */
|
||||||
|
|
||||||
|
/* vi: set ts=4 sw=4 expandtab: */
|
||||||
|
|
|
@ -28,6 +28,10 @@
|
||||||
#define SCREEN_WIDTH 512
|
#define SCREEN_WIDTH 512
|
||||||
#define SCREEN_HEIGHT 320
|
#define SCREEN_HEIGHT 320
|
||||||
|
|
||||||
|
#define BUTTON_SIZE 50
|
||||||
|
#define AXIS_SIZE 50
|
||||||
|
|
||||||
|
|
||||||
/* This is indexed by SDL_GameControllerButton. */
|
/* This is indexed by SDL_GameControllerButton. */
|
||||||
static const struct { int x; int y; } button_positions[] = {
|
static const struct { int x; int y; } button_positions[] = {
|
||||||
{387, 167}, /* SDL_CONTROLLER_BUTTON_A */
|
{387, 167}, /* SDL_CONTROLLER_BUTTON_A */
|
||||||
|
@ -50,7 +54,9 @@ static const struct { int x; int y; } button_positions[] = {
|
||||||
{330, 135}, /* SDL_CONTROLLER_BUTTON_PADDLE2 */
|
{330, 135}, /* SDL_CONTROLLER_BUTTON_PADDLE2 */
|
||||||
{132, 175}, /* SDL_CONTROLLER_BUTTON_PADDLE3 */
|
{132, 175}, /* SDL_CONTROLLER_BUTTON_PADDLE3 */
|
||||||
{330, 175}, /* SDL_CONTROLLER_BUTTON_PADDLE4 */
|
{330, 175}, /* SDL_CONTROLLER_BUTTON_PADDLE4 */
|
||||||
|
{0, 0}, /* SDL_CONTROLLER_BUTTON_TOUCHPAD */
|
||||||
};
|
};
|
||||||
|
SDL_COMPILE_TIME_ASSERT(button_positions, SDL_arraysize(button_positions) == SDL_CONTROLLER_BUTTON_MAX);
|
||||||
|
|
||||||
/* This is indexed by SDL_GameControllerAxis. */
|
/* This is indexed by SDL_GameControllerAxis. */
|
||||||
static const struct { int x; int y; double angle; } axis_positions[] = {
|
static const struct { int x; int y; double angle; } axis_positions[] = {
|
||||||
|
@ -61,6 +67,7 @@ static const struct { int x; int y; double angle; } axis_positions[] = {
|
||||||
{91, -20, 0.0}, /* TRIGGERLEFT */
|
{91, -20, 0.0}, /* TRIGGERLEFT */
|
||||||
{375, -20, 0.0}, /* TRIGGERRIGHT */
|
{375, -20, 0.0}, /* TRIGGERRIGHT */
|
||||||
};
|
};
|
||||||
|
SDL_COMPILE_TIME_ASSERT(axis_positions, SDL_arraysize(axis_positions) == SDL_CONTROLLER_AXIS_MAX);
|
||||||
|
|
||||||
static SDL_Window *window = NULL;
|
static SDL_Window *window = NULL;
|
||||||
static SDL_Renderer *screen = NULL;
|
static SDL_Renderer *screen = NULL;
|
||||||
|
@ -72,6 +79,11 @@ static SDL_Texture *background_front, *background_back, *button, *axis;
|
||||||
static SDL_GameController *gamecontroller;
|
static SDL_GameController *gamecontroller;
|
||||||
static SDL_GameController **gamecontrollers;
|
static SDL_GameController **gamecontrollers;
|
||||||
static int num_controllers = 0;
|
static int num_controllers = 0;
|
||||||
|
static SDL_Joystick *virtual_joystick = NULL;
|
||||||
|
static SDL_GameControllerAxis virtual_axis_active = SDL_CONTROLLER_AXIS_INVALID;
|
||||||
|
static int virtual_axis_start_x;
|
||||||
|
static int virtual_axis_start_y;
|
||||||
|
static SDL_GameControllerButton virtual_button_active = SDL_CONTROLLER_BUTTON_INVALID;
|
||||||
|
|
||||||
static void UpdateWindowTitle()
|
static void UpdateWindowTitle()
|
||||||
{
|
{
|
||||||
|
@ -280,12 +292,170 @@ static void CyclePS5TriggerEffect()
|
||||||
SDL_GameControllerSendEffect(gamecontroller, &state, sizeof(state));
|
SDL_GameControllerSendEffect(gamecontroller, &state, sizeof(state));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static SDL_bool ShowingFront()
|
||||||
|
{
|
||||||
|
SDL_bool showing_front = SDL_TRUE;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (gamecontroller) {
|
||||||
|
/* Show the back of the controller if the paddles are being held */
|
||||||
|
for (i = SDL_CONTROLLER_BUTTON_PADDLE1; i <= SDL_CONTROLLER_BUTTON_PADDLE4; ++i) {
|
||||||
|
if (SDL_GameControllerGetButton(gamecontroller, (SDL_GameControllerButton)i) == SDL_PRESSED) {
|
||||||
|
showing_front = SDL_FALSE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((SDL_GetModState() & KMOD_SHIFT) != 0) {
|
||||||
|
showing_front = SDL_FALSE;
|
||||||
|
}
|
||||||
|
return showing_front;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int OpenVirtualController()
|
||||||
|
{
|
||||||
|
SDL_VirtualJoystickDesc desc;
|
||||||
|
|
||||||
|
SDL_zero(desc);
|
||||||
|
desc.version = SDL_VIRTUAL_JOYSTICK_DESC_VERSION;
|
||||||
|
desc.type = SDL_JOYSTICK_TYPE_GAMECONTROLLER;
|
||||||
|
desc.naxes = SDL_CONTROLLER_AXIS_MAX;
|
||||||
|
desc.nbuttons = SDL_CONTROLLER_BUTTON_MAX;
|
||||||
|
return SDL_JoystickAttachVirtualEx(&desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static SDL_GameControllerButton FindButtonAtPosition(int x, int y)
|
||||||
|
{
|
||||||
|
SDL_Point point;
|
||||||
|
int i;
|
||||||
|
SDL_bool showing_front = ShowingFront();
|
||||||
|
|
||||||
|
point.x = x;
|
||||||
|
point.y = y;
|
||||||
|
for (i = 0; i < SDL_CONTROLLER_BUTTON_TOUCHPAD; ++i) {
|
||||||
|
SDL_bool on_front = (i < SDL_CONTROLLER_BUTTON_PADDLE1 || i > SDL_CONTROLLER_BUTTON_PADDLE4);
|
||||||
|
if (on_front == showing_front) {
|
||||||
|
SDL_Rect rect;
|
||||||
|
rect.x = button_positions[i].x;
|
||||||
|
rect.y = button_positions[i].y;
|
||||||
|
rect.w = BUTTON_SIZE;
|
||||||
|
rect.h = BUTTON_SIZE;
|
||||||
|
if (SDL_PointInRect(&point, &rect)) {
|
||||||
|
return (SDL_GameControllerButton)i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return SDL_CONTROLLER_BUTTON_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
static SDL_GameControllerAxis FindAxisAtPosition(int x, int y)
|
||||||
|
{
|
||||||
|
SDL_Point point;
|
||||||
|
int i;
|
||||||
|
SDL_bool showing_front = ShowingFront();
|
||||||
|
|
||||||
|
point.x = x;
|
||||||
|
point.y = y;
|
||||||
|
for (i = 0; i < SDL_CONTROLLER_AXIS_MAX; ++i) {
|
||||||
|
if (showing_front) {
|
||||||
|
SDL_Rect rect;
|
||||||
|
rect.x = axis_positions[i].x;
|
||||||
|
rect.y = axis_positions[i].y;
|
||||||
|
rect.w = AXIS_SIZE;
|
||||||
|
rect.h = AXIS_SIZE;
|
||||||
|
if (SDL_PointInRect(&point, &rect)) {
|
||||||
|
return (SDL_GameControllerAxis)i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return SDL_CONTROLLER_AXIS_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void VirtualControllerMouseMotion(int x, int y)
|
||||||
|
{
|
||||||
|
if (virtual_button_active != SDL_CONTROLLER_BUTTON_INVALID) {
|
||||||
|
if (virtual_axis_active != SDL_CONTROLLER_AXIS_INVALID) {
|
||||||
|
const int MOVING_DISTANCE = 2;
|
||||||
|
if (SDL_abs(x - virtual_axis_start_x) >= MOVING_DISTANCE ||
|
||||||
|
SDL_abs(y - virtual_axis_start_y) >= MOVING_DISTANCE) {
|
||||||
|
SDL_JoystickSetVirtualButton(virtual_joystick, virtual_button_active, SDL_RELEASED);
|
||||||
|
virtual_button_active = SDL_CONTROLLER_BUTTON_INVALID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (virtual_axis_active != SDL_CONTROLLER_AXIS_INVALID) {
|
||||||
|
if (virtual_axis_active == SDL_CONTROLLER_AXIS_TRIGGERLEFT ||
|
||||||
|
virtual_axis_active == SDL_CONTROLLER_AXIS_TRIGGERRIGHT) {
|
||||||
|
int range = (SDL_JOYSTICK_AXIS_MAX - SDL_JOYSTICK_AXIS_MIN);
|
||||||
|
float distance = SDL_clamp(((float)y - virtual_axis_start_y) / AXIS_SIZE, 0.0f, 1.0f);
|
||||||
|
Sint16 value = (Sint16)(SDL_JOYSTICK_AXIS_MIN + (distance * range));
|
||||||
|
SDL_JoystickSetVirtualAxis(virtual_joystick, virtual_axis_active, value);
|
||||||
|
} else {
|
||||||
|
float distanceX = SDL_clamp(((float)x - virtual_axis_start_x) / AXIS_SIZE, -1.0f, 1.0f);
|
||||||
|
float distanceY = SDL_clamp(((float)y - virtual_axis_start_y) / AXIS_SIZE, -1.0f, 1.0f);
|
||||||
|
Sint16 valueX, valueY;
|
||||||
|
|
||||||
|
if (distanceX >= 0) {
|
||||||
|
valueX = (Sint16)(distanceX * SDL_JOYSTICK_AXIS_MAX);
|
||||||
|
} else {
|
||||||
|
valueX = (Sint16)(distanceX * -SDL_JOYSTICK_AXIS_MIN);
|
||||||
|
}
|
||||||
|
if (distanceY >= 0) {
|
||||||
|
valueY = (Sint16)(distanceY * SDL_JOYSTICK_AXIS_MAX);
|
||||||
|
} else {
|
||||||
|
valueY = (Sint16)(distanceY * -SDL_JOYSTICK_AXIS_MIN);
|
||||||
|
}
|
||||||
|
SDL_JoystickSetVirtualAxis(virtual_joystick, virtual_axis_active, valueX);
|
||||||
|
SDL_JoystickSetVirtualAxis(virtual_joystick, virtual_axis_active+1, valueY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void VirtualControllerMouseDown(int x, int y)
|
||||||
|
{
|
||||||
|
SDL_GameControllerButton button;
|
||||||
|
SDL_GameControllerAxis axis;
|
||||||
|
|
||||||
|
button = FindButtonAtPosition(x, y);
|
||||||
|
if (button != SDL_CONTROLLER_BUTTON_INVALID) {
|
||||||
|
virtual_button_active = button;
|
||||||
|
SDL_JoystickSetVirtualButton(virtual_joystick, virtual_button_active, SDL_PRESSED);
|
||||||
|
}
|
||||||
|
|
||||||
|
axis = FindAxisAtPosition(x, y);
|
||||||
|
if (axis != SDL_CONTROLLER_AXIS_INVALID) {
|
||||||
|
virtual_axis_active = axis;
|
||||||
|
virtual_axis_start_x = x;
|
||||||
|
virtual_axis_start_y = y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void VirtualControllerMouseUp(int x, int y)
|
||||||
|
{
|
||||||
|
if (virtual_button_active != SDL_CONTROLLER_BUTTON_INVALID) {
|
||||||
|
SDL_JoystickSetVirtualButton(virtual_joystick, virtual_button_active, SDL_RELEASED);
|
||||||
|
virtual_button_active = SDL_CONTROLLER_BUTTON_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (virtual_axis_active != SDL_CONTROLLER_AXIS_INVALID) {
|
||||||
|
if (virtual_axis_active == SDL_CONTROLLER_AXIS_TRIGGERLEFT ||
|
||||||
|
virtual_axis_active == SDL_CONTROLLER_AXIS_TRIGGERRIGHT) {
|
||||||
|
SDL_JoystickSetVirtualAxis(virtual_joystick, virtual_axis_active, SDL_JOYSTICK_AXIS_MIN);
|
||||||
|
} else {
|
||||||
|
SDL_JoystickSetVirtualAxis(virtual_joystick, virtual_axis_active, 0);
|
||||||
|
SDL_JoystickSetVirtualAxis(virtual_joystick, virtual_axis_active+1, 0);
|
||||||
|
}
|
||||||
|
virtual_axis_active = SDL_CONTROLLER_AXIS_INVALID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
loop(void *arg)
|
loop(void *arg)
|
||||||
{
|
{
|
||||||
SDL_Event event;
|
SDL_Event event;
|
||||||
int i;
|
int i;
|
||||||
SDL_bool showing_front = SDL_TRUE;
|
SDL_bool showing_front;
|
||||||
|
|
||||||
/* Update to get the current event state */
|
/* Update to get the current event state */
|
||||||
SDL_PumpEvents();
|
SDL_PumpEvents();
|
||||||
|
@ -356,6 +526,24 @@ loop(void *arg)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case SDL_MOUSEBUTTONDOWN:
|
||||||
|
if (virtual_joystick) {
|
||||||
|
VirtualControllerMouseDown(event.button.x, event.button.y);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDL_MOUSEBUTTONUP:
|
||||||
|
if (virtual_joystick) {
|
||||||
|
VirtualControllerMouseUp(event.button.x, event.button.y);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDL_MOUSEMOTION:
|
||||||
|
if (virtual_joystick) {
|
||||||
|
VirtualControllerMouseMotion(event.motion.x, event.motion.y);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case SDL_KEYDOWN:
|
case SDL_KEYDOWN:
|
||||||
if (event.key.keysym.sym >= SDLK_0 && event.key.keysym.sym <= SDLK_9) {
|
if (event.key.keysym.sym >= SDLK_0 && event.key.keysym.sym <= SDLK_9) {
|
||||||
if (gamecontroller) {
|
if (gamecontroller) {
|
||||||
|
@ -377,15 +565,7 @@ loop(void *arg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gamecontroller) {
|
showing_front = ShowingFront();
|
||||||
/* Show the back of the controller if the paddles are being held */
|
|
||||||
for (i = SDL_CONTROLLER_BUTTON_PADDLE1; i <= SDL_CONTROLLER_BUTTON_PADDLE4; ++i) {
|
|
||||||
if (SDL_GameControllerGetButton(gamecontroller, (SDL_GameControllerButton)i) == SDL_PRESSED) {
|
|
||||||
showing_front = SDL_FALSE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* blank screen, set up for drawing this frame. */
|
/* blank screen, set up for drawing this frame. */
|
||||||
SDL_SetRenderDrawColor(screen, 0xFF, 0xFF, 0xFF, SDL_ALPHA_OPAQUE);
|
SDL_SetRenderDrawColor(screen, 0xFF, 0xFF, 0xFF, SDL_ALPHA_OPAQUE);
|
||||||
|
@ -401,8 +581,8 @@ loop(void *arg)
|
||||||
SDL_Rect dst;
|
SDL_Rect dst;
|
||||||
dst.x = button_positions[i].x;
|
dst.x = button_positions[i].x;
|
||||||
dst.y = button_positions[i].y;
|
dst.y = button_positions[i].y;
|
||||||
dst.w = 50;
|
dst.w = BUTTON_SIZE;
|
||||||
dst.h = 50;
|
dst.h = BUTTON_SIZE;
|
||||||
SDL_RenderCopyEx(screen, button, NULL, &dst, 0, NULL, SDL_FLIP_NONE);
|
SDL_RenderCopyEx(screen, button, NULL, &dst, 0, NULL, SDL_FLIP_NONE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -417,16 +597,16 @@ loop(void *arg)
|
||||||
SDL_Rect dst;
|
SDL_Rect dst;
|
||||||
dst.x = axis_positions[i].x;
|
dst.x = axis_positions[i].x;
|
||||||
dst.y = axis_positions[i].y;
|
dst.y = axis_positions[i].y;
|
||||||
dst.w = 50;
|
dst.w = AXIS_SIZE;
|
||||||
dst.h = 50;
|
dst.h = AXIS_SIZE;
|
||||||
SDL_RenderCopyEx(screen, axis, NULL, &dst, angle, NULL, SDL_FLIP_NONE);
|
SDL_RenderCopyEx(screen, axis, NULL, &dst, angle, NULL, SDL_FLIP_NONE);
|
||||||
} else if (value > deadzone) {
|
} else if (value > deadzone) {
|
||||||
const double angle = axis_positions[i].angle + 180.0;
|
const double angle = axis_positions[i].angle + 180.0;
|
||||||
SDL_Rect dst;
|
SDL_Rect dst;
|
||||||
dst.x = axis_positions[i].x;
|
dst.x = axis_positions[i].x;
|
||||||
dst.y = axis_positions[i].y;
|
dst.y = axis_positions[i].y;
|
||||||
dst.w = 50;
|
dst.w = AXIS_SIZE;
|
||||||
dst.h = 50;
|
dst.h = AXIS_SIZE;
|
||||||
SDL_RenderCopyEx(screen, axis, NULL, &dst, angle, NULL, SDL_FLIP_NONE);
|
SDL_RenderCopyEx(screen, axis, NULL, &dst, angle, NULL, SDL_FLIP_NONE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -627,8 +807,22 @@ main(int argc, char *argv[])
|
||||||
/* !!! FIXME: */
|
/* !!! FIXME: */
|
||||||
/*SDL_RenderSetLogicalSize(screen, background->w, background->h);*/
|
/*SDL_RenderSetLogicalSize(screen, background->w, background->h);*/
|
||||||
|
|
||||||
if (argv[1] && *argv[1] != '-') {
|
for (i = 1; i < argc; ++i) {
|
||||||
controller_index = SDL_atoi(argv[1]);
|
if (SDL_strcmp(argv[i], "--virtual") == 0) {
|
||||||
|
int virtual_index = OpenVirtualController();
|
||||||
|
if (virtual_index < 0) {
|
||||||
|
SDL_Log("Couldn't open virtual device: %s\n", SDL_GetError());
|
||||||
|
} else {
|
||||||
|
virtual_joystick = SDL_JoystickOpen(virtual_index);
|
||||||
|
if (!virtual_joystick) {
|
||||||
|
SDL_Log("Couldn't open virtual device: %s\n", SDL_GetError());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (argv[i] && *argv[i] != '-') {
|
||||||
|
controller_index = SDL_atoi(argv[1]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (controller_index < num_controllers) {
|
if (controller_index < num_controllers) {
|
||||||
gamecontroller = gamecontrollers[controller_index];
|
gamecontroller = gamecontrollers[controller_index];
|
||||||
|
|
Loading…
Reference in New Issue