mirror of
https://github.com/libsdl-org/SDL.git
synced 2025-10-16 06:45:59 +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:
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 */
|
Reference in New Issue
Block a user