mirror of
https://github.com/Ryujinx/SDL.git
synced 2024-12-22 19:25:33 +00:00
Fixed bug 5028 - Virtual Joysticks (new joystick backend)
David Ludwig I have created a new driver for SDL's Joystick and Game-Controller subsystem: a Virtual driver. This driver allows one to create a software-based joystick, which to SDL applications will look and react like a real joystick, but whose state can be set programmatically. A primary use case for this is to help enable developers to add touch-screen joysticks to their apps. The driver comes with a set of new, public APIs, with functions to attach and detach joysticks, set virtual-joystick state, and to determine if a joystick is a virtual-one. Use of virtual joysticks goes as such: 1. Attach one or more virtual joysticks by calling SDL_JoystickAttachVirtual. If successful, this returns the virtual-device's joystick-index. 2. Open the virtual joysticks (using indicies returned by SDL_JoystickAttachVirtual). 3. Call any of the SDL_JoystickSetVirtual* functions when joystick-state changes. Please note that virtual-joystick state will only get applied on the next call to SDL_JoystickUpdate, or when pumping or polling for SDL events (via SDL_PumpEvents or SDL_PollEvent). Here is a listing of the new, public APIs, at present and subject to change: ------------------------------------------------------------ /** * Attaches a new virtual joystick. * Returns the joystick's device index, or -1 if an error occurred. */ extern DECLSPEC int SDLCALL SDL_JoystickAttachVirtual(SDL_JoystickType type, int naxes, int nballs, int nbuttons, int nhats); /** * Detaches a virtual joystick * Returns 0 on success, or -1 if an error occurred. */ extern DECLSPEC int SDLCALL SDL_JoystickDetachVirtual(int device_index); /** * Indicates whether or not a virtual-joystick is at a given device index. */ extern DECLSPEC SDL_bool SDLCALL SDL_JoystickIsVirtual(int device_index); /** * Set values on an opened, virtual-joystick's controls. * Returns 0 on success, -1 on error. */ extern DECLSPEC int SDLCALL SDL_JoystickSetVirtualAxis(SDL_Joystick * joystick, int axis, Sint16 value); extern DECLSPEC int SDLCALL SDL_JoystickSetVirtualBall(SDL_Joystick * joystick, int ball, Sint16 xrel, Sint16 yrel); extern DECLSPEC int SDLCALL SDL_JoystickSetVirtualButton(SDL_Joystick * joystick, int button, Uint8 value); extern DECLSPEC int SDLCALL SDL_JoystickSetVirtualHat(SDL_Joystick * joystick, int hat, Uint8 value); ------------------------------------------------------------ Miscellaneous notes on the initial patch, which are also subject to change: 1. no test code is present in SDL, yet. This should, perhaps, change. Initial development was done with an ImGui-based app, which potentially is too thick for use in SDL-official. If tests are to be added, what kind of tests? Automated? Graphical? 2. virtual game controllers can be created by calling SDL_JoystickAttachVirtual with a joystick-type of SDL_JOYSTICK_TYPE_GAME_CONTROLLER, with naxes (num axes) set to SDL_CONTROLLER_AXIS_MAX, and with nbuttons (num buttons) set to SDL_CONTROLLER_BUTTON_MAX. When updating their state, values of type SDL_GameControllerAxis or SDL_GameControllerButton can be casted to an int and used for the control-index (in calls to SDL_JoystickSetVirtual* functions). 3. virtual joysticks' guids are mostly all-zeros with the exception of the last two bytes, the first of which is a 'v', to indicate that the guid is a virtual one, and the second of which is a SDL_JoystickType that has been converted into a Uint8. 4. virtual joysticks are ONLY turned into virtual game-controllers if and when their joystick-type is set to SDL_JOYSTICK_TYPE_GAMECONTROLLER. This is controlled by having SDL's default list of game-controllers have a single entry for a virtual game controller (of guid, "00000000000000000000000000007601", which is subject to the guid-encoding described above). 5. regarding having to call SDL_JoystickUpdate, either directly or indirectly via SDL_PumpEvents or SDL_PollEvents, before new virtual-joystick state becomes active (as specified via SDL_JoystickSetVirtual* function-calls), this was done to match behavior found in SDL's other joystick drivers, almost all of which will only update SDL-state during SDL_JoystickUpdate. 6. the initial patch is based off of SDL 2.0.12 7. the virtual joystick subsystem is disabled by default. It should be possible to enable it by building with SDL_JOYSTICK_VIRTUAL=1 Questions, comments, suggestions, or bug reports very welcome!
This commit is contained in:
parent
879f137aec
commit
2be75c6a61
|
@ -387,6 +387,7 @@ set_option(VIDEO_OFFSCREEN "Use offscreen video driver" OFF)
|
|||
option_string(BACKGROUNDING_SIGNAL "number to use for magic backgrounding signal or 'OFF'" "OFF")
|
||||
option_string(FOREGROUNDING_SIGNAL "number to use for magic foregrounding signal or 'OFF'" "OFF")
|
||||
set_option(HIDAPI "Use HIDAPI for low level joystick drivers" ${OPT_DEF_HIDAPI})
|
||||
set_option(JOYSTICK_VIRTUAL "Enable the virtual-joystick driver" ON)
|
||||
|
||||
set(SDL_SHARED ${SDL_SHARED_ENABLED_BY_DEFAULT} CACHE BOOL "Build a shared version of the library")
|
||||
set(SDL_STATIC ${SDL_STATIC_ENABLED_BY_DEFAULT} CACHE BOOL "Build a static version of the library")
|
||||
|
@ -905,6 +906,14 @@ if(SDL_DLOPEN)
|
|||
endif()
|
||||
endif()
|
||||
|
||||
if(SDL_JOYSTICK)
|
||||
if(JOYSTICK_VIRTUAL)
|
||||
set(SDL_JOYSTICK_VIRTUAL 1)
|
||||
file(GLOB JOYSTICK_VIRTUAL_SOURCES ${SDL2_SOURCE_DIR}/src/joystick/virtual/*.c)
|
||||
set(SOURCE_FILES ${SOURCE_FILES} ${JOYSTICK_VIRTUAL_SOURCES})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(SDL_VIDEO)
|
||||
if(VIDEO_DUMMY)
|
||||
set(SDL_VIDEO_DRIVER_DUMMY 1)
|
||||
|
|
|
@ -293,6 +293,7 @@
|
|||
#cmakedefine SDL_JOYSTICK_USBHID_MACHINE_JOYSTICK_H @SDL_JOYSTICK_USBHID_MACHINE_JOYSTICK_H@
|
||||
#cmakedefine SDL_JOYSTICK_HIDAPI @SDL_JOYSTICK_HIDAPI@
|
||||
#cmakedefine SDL_JOYSTICK_EMSCRIPTEN @SDL_JOYSTICK_EMSCRIPTEN@
|
||||
#cmakedefine SDL_JOYSTICK_VIRTUAL @SDL_JOYSTICK_VIRTUAL@
|
||||
#cmakedefine SDL_HAPTIC_DUMMY @SDL_HAPTIC_DUMMY@
|
||||
#cmakedefine SDL_HAPTIC_LINUX @SDL_HAPTIC_LINUX@
|
||||
#cmakedefine SDL_HAPTIC_IOKIT @SDL_HAPTIC_IOKIT@
|
||||
|
|
|
@ -64,7 +64,8 @@ typedef enum
|
|||
SDL_CONTROLLER_TYPE_XBOXONE,
|
||||
SDL_CONTROLLER_TYPE_PS3,
|
||||
SDL_CONTROLLER_TYPE_PS4,
|
||||
SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO
|
||||
SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO,
|
||||
SDL_CONTROLLER_TYPE_VIRTUAL
|
||||
} SDL_GameControllerType;
|
||||
|
||||
typedef enum
|
||||
|
|
|
@ -105,6 +105,7 @@ typedef enum
|
|||
SDL_JOYSTICK_POWER_MAX
|
||||
} SDL_JoystickPowerLevel;
|
||||
|
||||
|
||||
/* Function prototypes */
|
||||
|
||||
/**
|
||||
|
@ -199,6 +200,36 @@ extern DECLSPEC SDL_Joystick *SDLCALL SDL_JoystickFromInstanceID(SDL_JoystickID
|
|||
*/
|
||||
extern DECLSPEC SDL_Joystick *SDLCALL SDL_JoystickFromPlayerIndex(int player_index);
|
||||
|
||||
/**
|
||||
* Attaches a new virtual joystick.
|
||||
* Returns the joystick's device index, or -1 if an error occurred.
|
||||
*/
|
||||
extern DECLSPEC int SDLCALL SDL_JoystickAttachVirtual(SDL_JoystickType type,
|
||||
int naxes,
|
||||
int nballs,
|
||||
int nbuttons,
|
||||
int nhats);
|
||||
|
||||
/**
|
||||
* Detaches a virtual joystick
|
||||
* Returns 0 on success, or -1 if an error occurred.
|
||||
*/
|
||||
extern DECLSPEC int SDLCALL SDL_JoystickDetachVirtual(int device_index);
|
||||
|
||||
/**
|
||||
* Indicates whether or not a virtual-joystick is at a given device index.
|
||||
*/
|
||||
extern DECLSPEC SDL_bool SDLCALL SDL_JoystickIsVirtual(int device_index);
|
||||
|
||||
/**
|
||||
* Set values on an opened, virtual-joystick's controls.
|
||||
* Returns 0 on success, -1 on error.
|
||||
*/
|
||||
extern DECLSPEC int SDLCALL SDL_JoystickSetVirtualAxis(SDL_Joystick * joystick, int axis, Sint16 value);
|
||||
extern DECLSPEC int SDLCALL SDL_JoystickSetVirtualBall(SDL_Joystick * joystick, int ball, Sint16 xrel, Sint16 yrel);
|
||||
extern DECLSPEC int SDLCALL SDL_JoystickSetVirtualButton(SDL_Joystick * joystick, int button, Uint8 value);
|
||||
extern DECLSPEC int SDLCALL SDL_JoystickSetVirtualHat(SDL_Joystick * joystick, int hat, Uint8 value);
|
||||
|
||||
/**
|
||||
* Return the name for this currently opened joystick.
|
||||
* If no name can be found, this function returns NULL.
|
||||
|
|
|
@ -749,3 +749,10 @@
|
|||
#define SDL_GetAndroidSDKVersion SDL_GetAndroidSDKVersion_REAL
|
||||
#define SDL_isupper SDL_isupper_REAL
|
||||
#define SDL_islower SDL_islower_REAL
|
||||
#define SDL_JoystickAttachVirtual SDL_JoystickAttachVirtual_REAL
|
||||
#define SDL_JoystickDetachVirtual SDL_JoystickDetachVirtual_REAL
|
||||
#define SDL_JoystickIsVirtual SDL_JoystickIsVirtual_REAL
|
||||
#define SDL_JoystickSetVirtualAxis SDL_JoystickSetVirtualAxis_REAL
|
||||
#define SDL_JoystickSetVirtualBall SDL_JoystickSetVirtualBall_REAL
|
||||
#define SDL_JoystickSetVirtualButton SDL_JoystickSetVirtualButton_REAL
|
||||
#define SDL_JoystickSetVirtualHat SDL_JoystickSetVirtualHat_REAL
|
||||
|
|
|
@ -809,3 +809,10 @@ SDL_DYNAPI_PROC(int,SDL_GetAndroidSDKVersion,(void),(),return)
|
|||
#endif
|
||||
SDL_DYNAPI_PROC(int,SDL_isupper,(int a),(a),return)
|
||||
SDL_DYNAPI_PROC(int,SDL_islower,(int a),(a),return)
|
||||
SDL_DYNAPI_PROC(int,SDL_JoystickAttachVirtual,(SDL_JoystickType a, int b, int c, int d, int e),(a,b,c,d,e),return)
|
||||
SDL_DYNAPI_PROC(int,SDL_JoystickDetachVirtual,(int a),(a),return)
|
||||
SDL_DYNAPI_PROC(SDL_bool,SDL_JoystickIsVirtual,(int a),(a),return)
|
||||
SDL_DYNAPI_PROC(int,SDL_JoystickSetVirtualAxis,(SDL_Joystick *a, int b, Sint16 c),(a,b,c),return)
|
||||
SDL_DYNAPI_PROC(int,SDL_JoystickSetVirtualBall,(SDL_Joystick *a, int b, Sint16 c, Sint16 d),(a,b,c,d),return)
|
||||
SDL_DYNAPI_PROC(int,SDL_JoystickSetVirtualButton,(SDL_Joystick *a, int b, Uint8 c),(a,b,c),return)
|
||||
SDL_DYNAPI_PROC(int,SDL_JoystickSetVirtualHat,(SDL_Joystick *a, int b, Uint8 c),(a,b,c),return)
|
||||
|
|
|
@ -707,6 +707,9 @@ static const char *s_ControllerMappings [] =
|
|||
"05000000de2800000611000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,",
|
||||
"050000005e040000e0020000df070000,Xbox Wireless Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,",
|
||||
#endif
|
||||
#if defined(SDL_JOYSTICK_VIRTUAL)
|
||||
"00000000000000000000000000007601,Virtual Joystick,a:b0,b:b1,x:b2,y:b3,back:b4,guide:b5,start:b6,leftstick:b7,rightstick:b8,leftshoulder:b9,rightshoulder:b10,dpup:b11,dpdown:b12,dpleft:b13,dpright:b14,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5",
|
||||
#endif
|
||||
#if defined(SDL_JOYSTICK_EMSCRIPTEN)
|
||||
"default,Standard Gamepad,a:b0,b:b1,back:b8,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b16,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
|
||||
#endif
|
||||
|
|
|
@ -46,6 +46,10 @@
|
|||
#include <tlhelp32.h>
|
||||
#endif
|
||||
|
||||
#if SDL_JOYSTICK_VIRTUAL
|
||||
#include "./virtual/SDL_sysjoystick_c.h"
|
||||
#endif
|
||||
|
||||
static SDL_JoystickDriver *SDL_joystick_drivers[] = {
|
||||
#if defined(SDL_JOYSTICK_DINPUT) || defined(SDL_JOYSTICK_XINPUT)
|
||||
&SDL_WINDOWS_JoystickDriver,
|
||||
|
@ -74,6 +78,9 @@ static SDL_JoystickDriver *SDL_joystick_drivers[] = {
|
|||
#ifdef SDL_JOYSTICK_HIDAPI
|
||||
&SDL_HIDAPI_JoystickDriver,
|
||||
#endif
|
||||
#ifdef SDL_JOYSTICK_VIRTUAL
|
||||
&SDL_VIRTUAL_JoystickDriver,
|
||||
#endif
|
||||
#if defined(SDL_JOYSTICK_DUMMY) || defined(SDL_JOYSTICK_DISABLED)
|
||||
&SDL_DUMMY_JoystickDriver
|
||||
#endif
|
||||
|
@ -456,6 +463,115 @@ SDL_JoystickOpen(int device_index)
|
|||
}
|
||||
|
||||
|
||||
int
|
||||
SDL_JoystickAttachVirtual(SDL_JoystickType type,
|
||||
int naxes,
|
||||
int nballs,
|
||||
int nbuttons,
|
||||
int nhats)
|
||||
{
|
||||
#if SDL_JOYSTICK_VIRTUAL
|
||||
return SDL_JoystickAttachVirtualInner(type,
|
||||
naxes,
|
||||
nballs,
|
||||
nbuttons,
|
||||
nhats);
|
||||
#else
|
||||
return SDL_SetError("SDL not built with virtual-joystick support");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
SDL_JoystickDetachVirtual(int device_index)
|
||||
{
|
||||
#if SDL_JOYSTICK_VIRTUAL
|
||||
SDL_JoystickDriver *driver;
|
||||
|
||||
SDL_LockJoysticks();
|
||||
if (SDL_GetDriverAndJoystickIndex(device_index, &driver, &device_index)) {
|
||||
if (driver == &SDL_VIRTUAL_JoystickDriver) {
|
||||
const int result = SDL_JoystickDetachVirtualInner(device_index);
|
||||
SDL_UnlockJoysticks();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
SDL_UnlockJoysticks();
|
||||
|
||||
return SDL_SetError("Virtual joystick not found at provided index");
|
||||
#else
|
||||
return SDL_SetError("SDL not built with virtual-joystick support");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
SDL_bool
|
||||
SDL_JoystickIsVirtual(int device_index)
|
||||
{
|
||||
#if SDL_JOYSTICK_VIRTUAL
|
||||
SDL_JoystickDriver *driver;
|
||||
int driver_device_index;
|
||||
SDL_bool is_virtual = SDL_FALSE;
|
||||
|
||||
SDL_LockJoysticks();
|
||||
if (SDL_GetDriverAndJoystickIndex(device_index, &driver, &driver_device_index)) {
|
||||
if (driver == &SDL_VIRTUAL_JoystickDriver) {
|
||||
is_virtual = SDL_TRUE;
|
||||
}
|
||||
}
|
||||
SDL_UnlockJoysticks();
|
||||
|
||||
return is_virtual;
|
||||
#else
|
||||
return SDL_FALSE;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
SDL_JoystickSetVirtualAxis(SDL_Joystick * joystick, int axis, Sint16 value)
|
||||
{
|
||||
#if SDL_JOYSTICK_VIRTUAL
|
||||
return SDL_JoystickSetVirtualAxisInner(joystick, axis, value);
|
||||
#else
|
||||
return SDL_SetError("SDL not built with virtual-joystick support");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
SDL_JoystickSetVirtualBall(SDL_Joystick * joystick, int axis, Sint16 xrel, Sint16 yrel)
|
||||
{
|
||||
#if SDL_JOYSTICK_VIRTUAL
|
||||
return SDL_JoystickSetVirtualBallInner(joystick, axis, xrel, yrel);
|
||||
#else
|
||||
return SDL_SetError("SDL not built with virtual-joystick support");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
SDL_JoystickSetVirtualButton(SDL_Joystick * joystick, int button, Uint8 value)
|
||||
{
|
||||
#if SDL_JOYSTICK_VIRTUAL
|
||||
return SDL_JoystickSetVirtualButtonInner(joystick, button, value);
|
||||
#else
|
||||
return SDL_SetError("SDL not built with virtual-joystick support");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
SDL_JoystickSetVirtualHat(SDL_Joystick * joystick, int hat, Uint8 value)
|
||||
{
|
||||
#if SDL_JOYSTICK_VIRTUAL
|
||||
return SDL_JoystickSetVirtualHatInner(joystick, hat, value);
|
||||
#else
|
||||
return SDL_SetError("SDL not built with virtual-joystick support");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Checks to make sure the joystick is valid.
|
||||
*/
|
||||
|
@ -1563,6 +1679,8 @@ SDL_GetJoystickGameControllerType(const char *name, Uint16 vendor, Uint16 produc
|
|||
SDL_strcmp(name, "Wireless Gamepad") == 0) {
|
||||
/* HORI or PowerA Switch Pro Controller clone */
|
||||
type = SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO;
|
||||
} else if (SDL_strcmp(name, "Virtual Joystick") == 0) {
|
||||
type = SDL_CONTROLLER_TYPE_VIRTUAL;
|
||||
} else {
|
||||
type = SDL_CONTROLLER_TYPE_UNKNOWN;
|
||||
}
|
||||
|
@ -1624,6 +1742,12 @@ SDL_IsJoystickHIDAPI(SDL_JoystickGUID guid)
|
|||
return (guid.data[14] == 'h') ? SDL_TRUE : SDL_FALSE;
|
||||
}
|
||||
|
||||
SDL_bool
|
||||
SDL_IsJoystickVirtual(SDL_JoystickGUID guid)
|
||||
{
|
||||
return (guid.data[14] == 'v') ? SDL_TRUE : SDL_FALSE;
|
||||
}
|
||||
|
||||
static SDL_bool SDL_IsJoystickProductWheel(Uint32 vidpid)
|
||||
{
|
||||
static Uint32 wheel_joysticks[] = {
|
||||
|
@ -1715,6 +1839,10 @@ static SDL_JoystickType SDL_GetJoystickGUIDType(SDL_JoystickGUID guid)
|
|||
}
|
||||
}
|
||||
|
||||
if (SDL_IsJoystickVirtual(guid)) {
|
||||
return (SDL_JoystickType)guid.data[15];
|
||||
}
|
||||
|
||||
SDL_GetJoystickGUIDInfo(guid, &vendor, &product, NULL);
|
||||
vidpid = MAKE_VIDPID(vendor, product);
|
||||
|
||||
|
|
|
@ -73,6 +73,9 @@ extern SDL_bool SDL_IsJoystickXInput(SDL_JoystickGUID guid);
|
|||
/* Function to return whether a joystick guid comes from the HIDAPI driver */
|
||||
extern SDL_bool SDL_IsJoystickHIDAPI(SDL_JoystickGUID guid);
|
||||
|
||||
/* Function to return whether a joystick guid comes from the Virtual driver */
|
||||
extern SDL_bool SDL_IsJoystickVirtual(SDL_JoystickGUID guid);
|
||||
|
||||
/* Function to return whether a joystick should be ignored */
|
||||
extern SDL_bool SDL_ShouldIgnoreJoystick(const char *name, SDL_JoystickGUID guid);
|
||||
|
||||
|
|
|
@ -152,6 +152,7 @@ extern SDL_JoystickDriver SDL_HAIKU_JoystickDriver;
|
|||
extern SDL_JoystickDriver SDL_HIDAPI_JoystickDriver;
|
||||
extern SDL_JoystickDriver SDL_IOS_JoystickDriver;
|
||||
extern SDL_JoystickDriver SDL_LINUX_JoystickDriver;
|
||||
extern SDL_JoystickDriver SDL_VIRTUAL_JoystickDriver;
|
||||
extern SDL_JoystickDriver SDL_WINDOWS_JoystickDriver;
|
||||
|
||||
#endif /* SDL_sysjoystick_h_ */
|
||||
|
|
455
src/joystick/virtual/SDL_sysjoystick.c
Normal file
455
src/joystick/virtual/SDL_sysjoystick.c
Normal file
|
@ -0,0 +1,455 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2020 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
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#if defined(SDL_JOYSTICK_VIRTUAL)
|
||||
|
||||
/* This is the virtual implementation of the SDL joystick API */
|
||||
|
||||
#include "SDL_sysjoystick_c.h"
|
||||
#include "../SDL_sysjoystick.h"
|
||||
#include "../SDL_joystick_c.h"
|
||||
|
||||
extern SDL_JoystickDriver SDL_VIRTUAL_JoystickDriver;
|
||||
|
||||
static joystick_hwdata * g_VJoys = NULL;
|
||||
|
||||
|
||||
static joystick_hwdata *
|
||||
VIRTUAL_HWDataForIndex(int device_index)
|
||||
{
|
||||
joystick_hwdata *vjoy = g_VJoys;
|
||||
while (vjoy) {
|
||||
if (device_index == 0)
|
||||
break;
|
||||
--device_index;
|
||||
vjoy = vjoy->next;
|
||||
}
|
||||
return vjoy;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
VIRTUAL_FreeHWData(joystick_hwdata *hwdata)
|
||||
{
|
||||
if (!hwdata) {
|
||||
return;
|
||||
}
|
||||
if (hwdata->axes) {
|
||||
SDL_free((void *)hwdata->axes);
|
||||
hwdata->axes = NULL;
|
||||
}
|
||||
if (hwdata->balls) {
|
||||
SDL_free((void *)hwdata->balls);
|
||||
hwdata->balls = 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 */
|
||||
joystick_hwdata * cur = g_VJoys;
|
||||
joystick_hwdata * prev = NULL;
|
||||
while (cur) {
|
||||
if (hwdata == cur) {
|
||||
if (prev) {
|
||||
prev->next = cur->next;
|
||||
} else {
|
||||
g_VJoys = cur->next;
|
||||
}
|
||||
break;
|
||||
}
|
||||
prev = cur;
|
||||
cur = cur->next;
|
||||
}
|
||||
|
||||
SDL_free(hwdata);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
SDL_JoystickAttachVirtualInner(SDL_JoystickType type,
|
||||
int naxes,
|
||||
int nballs,
|
||||
int nbuttons,
|
||||
int nhats)
|
||||
{
|
||||
joystick_hwdata *hwdata = NULL;
|
||||
int device_index = -1;
|
||||
|
||||
hwdata = SDL_calloc(1, sizeof(joystick_hwdata));
|
||||
if (!hwdata) {
|
||||
VIRTUAL_FreeHWData(hwdata);
|
||||
return SDL_OutOfMemory();
|
||||
}
|
||||
|
||||
hwdata->naxes = naxes;
|
||||
hwdata->nballs = nballs;
|
||||
hwdata->nbuttons = nbuttons;
|
||||
hwdata->nhats = nhats;
|
||||
hwdata->name = "Virtual Joystick";
|
||||
|
||||
/* Note that this is a Virtual device and what subtype it is */
|
||||
hwdata->guid.data[14] = 'v';
|
||||
hwdata->guid.data[15] = (Uint8)type;
|
||||
|
||||
/* Allocate fields for different control-types */
|
||||
if (naxes > 0) {
|
||||
hwdata->axes = SDL_calloc(naxes, sizeof(Sint16));
|
||||
if (!hwdata->axes) {
|
||||
VIRTUAL_FreeHWData(hwdata);
|
||||
return SDL_OutOfMemory();
|
||||
}
|
||||
}
|
||||
if (nballs > 0) {
|
||||
hwdata->balls = SDL_calloc(nballs, sizeof(hwdata->balls[0]));
|
||||
if (!hwdata->balls) {
|
||||
VIRTUAL_FreeHWData(hwdata);
|
||||
return SDL_OutOfMemory();
|
||||
}
|
||||
}
|
||||
if (nbuttons > 0) {
|
||||
hwdata->buttons = SDL_calloc(nbuttons, sizeof(Uint8));
|
||||
if (!hwdata->buttons) {
|
||||
VIRTUAL_FreeHWData(hwdata);
|
||||
return SDL_OutOfMemory();
|
||||
}
|
||||
}
|
||||
if (nhats > 0) {
|
||||
hwdata->hats = SDL_calloc(nhats, sizeof(Uint8));
|
||||
if (!hwdata->hats) {
|
||||
VIRTUAL_FreeHWData(hwdata);
|
||||
return SDL_OutOfMemory();
|
||||
}
|
||||
}
|
||||
|
||||
/* Allocate an instance ID for this device */
|
||||
hwdata->instance_id = SDL_GetNextJoystickInstanceID();
|
||||
|
||||
/* Add virtual joystick to SDL-global lists */
|
||||
hwdata->next = g_VJoys;
|
||||
g_VJoys = hwdata;
|
||||
SDL_PrivateJoystickAdded(hwdata->instance_id);
|
||||
|
||||
/* Return the new virtual-device's index */
|
||||
device_index = SDL_JoystickGetDeviceIndexFromInstanceID(hwdata->instance_id);
|
||||
return device_index;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
SDL_JoystickDetachVirtualInner(int device_index)
|
||||
{
|
||||
SDL_JoystickID instance_id;
|
||||
joystick_hwdata *hwdata = VIRTUAL_HWDataForIndex(device_index);
|
||||
if (!hwdata) {
|
||||
return SDL_SetError("Virtual joystick data not found");
|
||||
}
|
||||
instance_id = hwdata->instance_id;
|
||||
VIRTUAL_FreeHWData(hwdata);
|
||||
SDL_PrivateJoystickRemoved(instance_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
SDL_JoystickSetVirtualAxisInner(SDL_Joystick * joystick, int axis, Sint16 value)
|
||||
{
|
||||
joystick_hwdata *hwdata;
|
||||
|
||||
SDL_LockJoysticks();
|
||||
|
||||
if (!joystick || !joystick->hwdata) {
|
||||
SDL_UnlockJoysticks();
|
||||
return SDL_SetError("Invalid joystick");
|
||||
}
|
||||
|
||||
hwdata = (joystick_hwdata *)joystick->hwdata;
|
||||
if (axis < 0 || axis >= hwdata->nbuttons) {
|
||||
SDL_UnlockJoysticks();
|
||||
return SDL_SetError("Invalid axis index");
|
||||
}
|
||||
|
||||
hwdata->axes[axis] = value;
|
||||
|
||||
SDL_UnlockJoysticks();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
SDL_JoystickSetVirtualBallInner(SDL_Joystick * joystick, int ball, Sint16 xrel, Sint16 yrel)
|
||||
{
|
||||
joystick_hwdata *hwdata;
|
||||
|
||||
SDL_LockJoysticks();
|
||||
|
||||
if (!joystick || !joystick->hwdata) {
|
||||
SDL_UnlockJoysticks();
|
||||
return SDL_SetError("Invalid joystick");
|
||||
}
|
||||
|
||||
hwdata = (joystick_hwdata *)joystick->hwdata;
|
||||
if (ball < 0 || ball >= hwdata->nbuttons) {
|
||||
SDL_UnlockJoysticks();
|
||||
return SDL_SetError("Invalid ball index");
|
||||
}
|
||||
|
||||
hwdata->balls[ball].xrel = xrel;
|
||||
hwdata->balls[ball].yrel = yrel;
|
||||
|
||||
SDL_UnlockJoysticks();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
SDL_JoystickSetVirtualButtonInner(SDL_Joystick * joystick, int button, Uint8 value)
|
||||
{
|
||||
joystick_hwdata *hwdata;
|
||||
|
||||
SDL_LockJoysticks();
|
||||
|
||||
if (!joystick || !joystick->hwdata) {
|
||||
SDL_UnlockJoysticks();
|
||||
return SDL_SetError("Invalid joystick");
|
||||
}
|
||||
|
||||
hwdata = (joystick_hwdata *)joystick->hwdata;
|
||||
if (button < 0 || button >= hwdata->nbuttons) {
|
||||
SDL_UnlockJoysticks();
|
||||
return SDL_SetError("Invalid button index");
|
||||
}
|
||||
|
||||
hwdata->buttons[button] = value;
|
||||
|
||||
SDL_UnlockJoysticks();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
SDL_JoystickSetVirtualHatInner(SDL_Joystick * joystick, int hat, Uint8 value)
|
||||
{
|
||||
joystick_hwdata *hwdata;
|
||||
|
||||
SDL_LockJoysticks();
|
||||
|
||||
if (!joystick || !joystick->hwdata) {
|
||||
SDL_UnlockJoysticks();
|
||||
return SDL_SetError("Invalid joystick");
|
||||
}
|
||||
|
||||
hwdata = (joystick_hwdata *)joystick->hwdata;
|
||||
if (hat < 0 || hat >= hwdata->nbuttons) {
|
||||
SDL_UnlockJoysticks();
|
||||
return SDL_SetError("Invalid hat index");
|
||||
}
|
||||
|
||||
hwdata->hats[hat] = value;
|
||||
|
||||
SDL_UnlockJoysticks();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
VIRTUAL_JoystickInit(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
VIRTUAL_JoystickGetCount(void)
|
||||
{
|
||||
int count = 0;
|
||||
joystick_hwdata *cur = g_VJoys;
|
||||
while (cur) {
|
||||
++count;
|
||||
cur = cur->next;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
VIRTUAL_JoystickDetect(void)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
static const char *
|
||||
VIRTUAL_JoystickGetDeviceName(int device_index)
|
||||
{
|
||||
joystick_hwdata *hwdata = VIRTUAL_HWDataForIndex(device_index);
|
||||
if (!hwdata) {
|
||||
return NULL;
|
||||
}
|
||||
return hwdata->name ? hwdata->name : "";
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
VIRTUAL_JoystickGetDevicePlayerIndex(int device_index)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
VIRTUAL_JoystickSetDevicePlayerIndex(int device_index, int player_index)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
static SDL_JoystickGUID
|
||||
VIRTUAL_JoystickGetDeviceGUID(int device_index)
|
||||
{
|
||||
joystick_hwdata *hwdata = VIRTUAL_HWDataForIndex(device_index);
|
||||
if (!hwdata) {
|
||||
SDL_JoystickGUID guid;
|
||||
SDL_zero(guid);
|
||||
return guid;
|
||||
}
|
||||
return hwdata->guid;
|
||||
}
|
||||
|
||||
|
||||
static SDL_JoystickID
|
||||
VIRTUAL_JoystickGetDeviceInstanceID(int device_index)
|
||||
{
|
||||
joystick_hwdata *hwdata = VIRTUAL_HWDataForIndex(device_index);
|
||||
if (!hwdata) {
|
||||
return -1;
|
||||
}
|
||||
return hwdata->instance_id;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
VIRTUAL_JoystickOpen(SDL_Joystick * joystick, int device_index)
|
||||
{
|
||||
joystick_hwdata *hwdata = VIRTUAL_HWDataForIndex(device_index);
|
||||
if (!hwdata) {
|
||||
return SDL_SetError("No such device");
|
||||
}
|
||||
if (hwdata->opened) {
|
||||
return SDL_SetError("Joystick already opened");
|
||||
}
|
||||
joystick->instance_id = hwdata->instance_id;
|
||||
joystick->hwdata = hwdata;
|
||||
joystick->naxes = hwdata->naxes;
|
||||
joystick->nballs = hwdata->nballs;
|
||||
joystick->nbuttons = hwdata->nbuttons;
|
||||
joystick->nhats = hwdata->nhats;
|
||||
hwdata->opened = SDL_TRUE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
VIRTUAL_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
|
||||
{
|
||||
return SDL_Unsupported();
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
VIRTUAL_JoystickUpdate(SDL_Joystick * joystick)
|
||||
{
|
||||
joystick_hwdata *hwdata;
|
||||
|
||||
if (!joystick) {
|
||||
return;
|
||||
}
|
||||
if (!joystick->hwdata) {
|
||||
return;
|
||||
}
|
||||
|
||||
hwdata = (joystick_hwdata *)joystick->hwdata;
|
||||
|
||||
for (int i = 0; i < hwdata->naxes; ++i) {
|
||||
SDL_PrivateJoystickAxis(joystick, i, hwdata->axes[i]);
|
||||
}
|
||||
for (int i = 0; i < hwdata->nballs; ++i) {
|
||||
SDL_PrivateJoystickBall(joystick, i, hwdata->balls[i].xrel, hwdata->balls[i].yrel);
|
||||
}
|
||||
for (int i = 0; i < hwdata->nbuttons; ++i) {
|
||||
SDL_PrivateJoystickButton(joystick, i, hwdata->buttons[i]);
|
||||
}
|
||||
for (int i = 0; i < hwdata->nhats; ++i) {
|
||||
SDL_PrivateJoystickHat(joystick, i, hwdata->hats[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
VIRTUAL_JoystickClose(SDL_Joystick * joystick)
|
||||
{
|
||||
joystick_hwdata *hwdata;
|
||||
|
||||
if (!joystick) {
|
||||
return;
|
||||
}
|
||||
if (!joystick->hwdata) {
|
||||
return;
|
||||
}
|
||||
|
||||
hwdata = (joystick_hwdata *)joystick->hwdata;
|
||||
hwdata->opened = SDL_FALSE;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
VIRTUAL_JoystickQuit(void)
|
||||
{
|
||||
while (g_VJoys) {
|
||||
VIRTUAL_FreeHWData(g_VJoys);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SDL_JoystickDriver SDL_VIRTUAL_JoystickDriver =
|
||||
{
|
||||
VIRTUAL_JoystickInit,
|
||||
VIRTUAL_JoystickGetCount,
|
||||
VIRTUAL_JoystickDetect,
|
||||
VIRTUAL_JoystickGetDeviceName,
|
||||
VIRTUAL_JoystickGetDevicePlayerIndex,
|
||||
VIRTUAL_JoystickSetDevicePlayerIndex,
|
||||
VIRTUAL_JoystickGetDeviceGUID,
|
||||
VIRTUAL_JoystickGetDeviceInstanceID,
|
||||
VIRTUAL_JoystickOpen,
|
||||
VIRTUAL_JoystickRumble,
|
||||
VIRTUAL_JoystickUpdate,
|
||||
VIRTUAL_JoystickClose,
|
||||
VIRTUAL_JoystickQuit,
|
||||
};
|
||||
|
||||
#endif /* SDL_JOYSTICK_VIRTUAL || SDL_JOYSTICK_DISABLED */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
69
src/joystick/virtual/SDL_sysjoystick_c.h
Normal file
69
src/joystick/virtual/SDL_sysjoystick_c.h
Normal file
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2020 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
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#ifndef SDL_JOYSTICK_VIRTUAL_H
|
||||
#define SDL_JOYSTICK_VIRTUAL_H
|
||||
|
||||
#if SDL_JOYSTICK_VIRTUAL
|
||||
|
||||
#include "SDL_joystick.h"
|
||||
|
||||
/**
|
||||
* Data for a virtual, software-only joystick.
|
||||
*/
|
||||
typedef struct joystick_hwdata
|
||||
{
|
||||
SDL_JoystickType type;
|
||||
SDL_bool attached;
|
||||
const char *name;
|
||||
SDL_JoystickGUID guid;
|
||||
int naxes;
|
||||
Sint16 *axes;
|
||||
int nballs;
|
||||
struct {
|
||||
Sint16 xrel;
|
||||
Sint16 yrel;
|
||||
} *balls;
|
||||
int nbuttons;
|
||||
Uint8 *buttons;
|
||||
int nhats;
|
||||
Uint8 *hats;
|
||||
SDL_JoystickID instance_id;
|
||||
SDL_bool opened;
|
||||
struct joystick_hwdata *next;
|
||||
} joystick_hwdata;
|
||||
|
||||
int SDL_JoystickAttachVirtualInner(SDL_JoystickType type,
|
||||
int naxes,
|
||||
int nballs,
|
||||
int nbuttons,
|
||||
int nhats);
|
||||
|
||||
int SDL_JoystickDetachVirtualInner(int device_index);
|
||||
|
||||
int SDL_JoystickSetVirtualAxisInner(SDL_Joystick * joystick, int axis, Sint16 value);
|
||||
int SDL_JoystickSetVirtualBallInner(SDL_Joystick * joystick, int ball, Sint16 xrel, Sint16 yrel);
|
||||
int SDL_JoystickSetVirtualButtonInner(SDL_Joystick * joystick, int button, Uint8 value);
|
||||
int SDL_JoystickSetVirtualHatInner(SDL_Joystick * joystick, int hat, Uint8 value);
|
||||
|
||||
#endif /* SDL_JOYSTICK_VIRTUAL */
|
||||
#endif /* SDL_JOYSTICK_VIRTUAL_H */
|
|
@ -310,6 +310,9 @@ main(int argc, char *argv[])
|
|||
case SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO:
|
||||
description = "Nintendo Switch Pro Controller";
|
||||
break;
|
||||
case SDL_CONTROLLER_TYPE_VIRTUAL:
|
||||
description = "Virtual Game Controller";
|
||||
break;
|
||||
default:
|
||||
description = "Game Controller";
|
||||
break;
|
||||
|
|
Loading…
Reference in a new issue