Remove old files from SDL external

They were already removed in SDL upstream but the update mechanism did
not remove them in this repository.

They were causing build failures when the SDL external was used.
This commit is contained in:
Simon Bruder
2022-01-22 11:15:39 +01:00
parent 0c49a90d80
commit 9867c12dc0
86 changed files with 0 additions and 18934 deletions

View File

@@ -1,784 +0,0 @@
/*
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"
#ifdef SDL_JOYSTICK_USBHID
/*
* Joystick driver for the uhid(4) interface found in OpenBSD,
* NetBSD and FreeBSD.
*
* Maintainer: <vedge at csoft.org>
*/
#include <sys/param.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#ifndef __FreeBSD_kernel_version
#define __FreeBSD_kernel_version __FreeBSD_version
#endif
#if defined(HAVE_USB_H)
#include <usb.h>
#endif
#ifdef __DragonFly__
#include <bus/usb/usb.h>
#include <bus/usb/usbhid.h>
#else
#include <dev/usb/usb.h>
#include <dev/usb/usbhid.h>
#endif
#if defined(HAVE_USBHID_H)
#include <usbhid.h>
#elif defined(HAVE_LIBUSB_H)
#include <libusb.h>
#elif defined(HAVE_LIBUSBHID_H)
#include <libusbhid.h>
#endif
#if defined(__FREEBSD__) || defined(__FreeBSD_kernel__)
#ifndef __DragonFly__
#include <osreldate.h>
#endif
#if __FreeBSD_kernel_version > 800063
#include <dev/usb/usb_ioctl.h>
#endif
#include <sys/joystick.h>
#endif
#if SDL_JOYSTICK_USBHID_MACHINE_JOYSTICK_H
#include <machine/joystick.h>
#endif
#include "SDL_joystick.h"
#include "../SDL_sysjoystick.h"
#include "../SDL_joystick_c.h"
#define MAX_UHID_JOYS 64
#define MAX_JOY_JOYS 2
#define MAX_JOYS (MAX_UHID_JOYS + MAX_JOY_JOYS)
#ifdef __OpenBSD__
#define HUG_DPAD_UP 0x90
#define HUG_DPAD_DOWN 0x91
#define HUG_DPAD_RIGHT 0x92
#define HUG_DPAD_LEFT 0x93
#define HAT_CENTERED 0x00
#define HAT_UP 0x01
#define HAT_RIGHT 0x02
#define HAT_DOWN 0x04
#define HAT_LEFT 0x08
#define HAT_RIGHTUP (HAT_RIGHT|HAT_UP)
#define HAT_RIGHTDOWN (HAT_RIGHT|HAT_DOWN)
#define HAT_LEFTUP (HAT_LEFT|HAT_UP)
#define HAT_LEFTDOWN (HAT_LEFT|HAT_DOWN)
/* calculate the value from the state of the dpad */
int
dpad_to_sdl(Sint32 *dpad)
{
if (dpad[2]) {
if (dpad[0])
return HAT_RIGHTUP;
else if (dpad[1])
return HAT_RIGHTDOWN;
else
return HAT_RIGHT;
} else if (dpad[3]) {
if (dpad[0])
return HAT_LEFTUP;
else if (dpad[1])
return HAT_LEFTDOWN;
else
return HAT_LEFT;
} else if (dpad[0]) {
return HAT_UP;
} else if (dpad[1]) {
return HAT_DOWN;
}
return HAT_CENTERED;
}
#endif
struct report
{
#if defined(__FREEBSD__) && (__FreeBSD_kernel_version > 900000)
void *buf; /* Buffer */
#elif defined(__FREEBSD__) && (__FreeBSD_kernel_version > 800063)
struct usb_gen_descriptor *buf; /* Buffer */
#else
struct usb_ctl_report *buf; /* Buffer */
#endif
size_t size; /* Buffer size */
int rid; /* Report ID */
enum
{
SREPORT_UNINIT,
SREPORT_CLEAN,
SREPORT_DIRTY
} status;
};
static struct
{
int uhid_report;
hid_kind_t kind;
const char *name;
} const repinfo[] = {
{UHID_INPUT_REPORT, hid_input, "input"},
{UHID_OUTPUT_REPORT, hid_output, "output"},
{UHID_FEATURE_REPORT, hid_feature, "feature"}
};
enum
{
REPORT_INPUT = 0,
REPORT_OUTPUT = 1,
REPORT_FEATURE = 2
};
enum
{
JOYAXE_X,
JOYAXE_Y,
JOYAXE_Z,
JOYAXE_SLIDER,
JOYAXE_WHEEL,
JOYAXE_RX,
JOYAXE_RY,
JOYAXE_RZ,
JOYAXE_count
};
struct joystick_hwdata
{
int fd;
char *path;
enum
{
BSDJOY_UHID, /* uhid(4) */
BSDJOY_JOY /* joy(4) */
} type;
struct report_desc *repdesc;
struct report inreport;
int axis_map[JOYAXE_count]; /* map present JOYAXE_* to 0,1,.. */
};
static char *joynames[MAX_JOYS];
static char *joydevnames[MAX_JOYS];
static int report_alloc(struct report *, struct report_desc *, int);
static void report_free(struct report *);
#if defined(USBHID_UCR_DATA) || (defined(__FreeBSD_kernel__) && __FreeBSD_kernel_version <= 800063)
#define REP_BUF_DATA(rep) ((rep)->buf->ucr_data)
#elif (defined(__FREEBSD__) && (__FreeBSD_kernel_version > 900000))
#define REP_BUF_DATA(rep) ((rep)->buf)
#elif (defined(__FREEBSD__) && (__FreeBSD_kernel_version > 800063))
#define REP_BUF_DATA(rep) ((rep)->buf->ugd_data)
#else
#define REP_BUF_DATA(rep) ((rep)->buf->data)
#endif
static int numjoysticks = 0;
static int BSD_JoystickOpen(SDL_Joystick * joy, int device_index);
static void BSD_JoystickClose(SDL_Joystick * joy);
static int
BSD_JoystickInit(void)
{
char s[16];
int i, fd;
numjoysticks = 0;
SDL_memset(joynames, 0, sizeof(joynames));
SDL_memset(joydevnames, 0, sizeof(joydevnames));
for (i = 0; i < MAX_UHID_JOYS; i++) {
SDL_Joystick nj;
SDL_snprintf(s, SDL_arraysize(s), "/dev/uhid%d", i);
joynames[numjoysticks] = SDL_strdup(s);
if (BSD_JoystickOpen(&nj, numjoysticks) == 0) {
BSD_JoystickClose(&nj);
numjoysticks++;
} else {
SDL_free(joynames[numjoysticks]);
joynames[numjoysticks] = NULL;
}
}
for (i = 0; i < MAX_JOY_JOYS; i++) {
SDL_snprintf(s, SDL_arraysize(s), "/dev/joy%d", i);
fd = open(s, O_RDONLY);
if (fd != -1) {
joynames[numjoysticks++] = SDL_strdup(s);
close(fd);
}
}
/* Read the default USB HID usage table. */
hid_init(NULL);
return (numjoysticks);
}
static int
BSD_JoystickGetCount(void)
{
return numjoysticks;
}
static void
BSD_JoystickDetect(void)
{
}
static const char *
BSD_JoystickGetDeviceName(int device_index)
{
if (joydevnames[device_index] != NULL) {
return (joydevnames[device_index]);
}
return (joynames[device_index]);
}
static int
BSD_JoystickGetDevicePlayerIndex(int device_index)
{
return -1;
}
static void
BSD_JoystickSetDevicePlayerIndex(int device_index, int player_index)
{
}
/* Function to perform the mapping from device index to the instance id for this index */
static SDL_JoystickID
BSD_JoystickGetDeviceInstanceID(int device_index)
{
return device_index;
}
static int
usage_to_joyaxe(unsigned usage)
{
int joyaxe;
switch (usage) {
case HUG_X:
joyaxe = JOYAXE_X;
break;
case HUG_Y:
joyaxe = JOYAXE_Y;
break;
case HUG_Z:
joyaxe = JOYAXE_Z;
break;
case HUG_SLIDER:
joyaxe = JOYAXE_SLIDER;
break;
case HUG_WHEEL:
joyaxe = JOYAXE_WHEEL;
break;
case HUG_RX:
joyaxe = JOYAXE_RX;
break;
case HUG_RY:
joyaxe = JOYAXE_RY;
break;
case HUG_RZ:
joyaxe = JOYAXE_RZ;
break;
default:
joyaxe = -1;
}
return joyaxe;
}
static unsigned
hatval_to_sdl(Sint32 hatval)
{
static const unsigned hat_dir_map[8] = {
SDL_HAT_UP, SDL_HAT_RIGHTUP, SDL_HAT_RIGHT, SDL_HAT_RIGHTDOWN,
SDL_HAT_DOWN, SDL_HAT_LEFTDOWN, SDL_HAT_LEFT, SDL_HAT_LEFTUP
};
unsigned result;
if ((hatval & 7) == hatval)
result = hat_dir_map[hatval];
else
result = SDL_HAT_CENTERED;
return result;
}
static int
BSD_JoystickOpen(SDL_Joystick * joy, int device_index)
{
char *path = joynames[device_index];
struct joystick_hwdata *hw;
struct hid_item hitem;
struct hid_data *hdata;
struct report *rep = NULL;
#if defined(__NetBSD__)
usb_device_descriptor_t udd;
struct usb_string_desc usd;
#endif
int fd;
int i;
fd = open(path, O_RDONLY);
if (fd == -1) {
return SDL_SetError("%s: %s", path, strerror(errno));
}
joy->instance_id = device_index;
hw = (struct joystick_hwdata *)
SDL_malloc(sizeof(struct joystick_hwdata));
if (hw == NULL) {
close(fd);
return SDL_OutOfMemory();
}
joy->hwdata = hw;
hw->fd = fd;
hw->path = SDL_strdup(path);
if (!SDL_strncmp(path, "/dev/joy", 8)) {
hw->type = BSDJOY_JOY;
joy->naxes = 2;
joy->nbuttons = 2;
joy->nhats = 0;
joy->nballs = 0;
joydevnames[device_index] = SDL_strdup("Gameport joystick");
goto usbend;
} else {
hw->type = BSDJOY_UHID;
}
{
int ax;
for (ax = 0; ax < JOYAXE_count; ax++)
hw->axis_map[ax] = -1;
}
hw->repdesc = hid_get_report_desc(fd);
if (hw->repdesc == NULL) {
SDL_SetError("%s: USB_GET_REPORT_DESC: %s", hw->path,
strerror(errno));
goto usberr;
}
rep = &hw->inreport;
#if defined(__FREEBSD__) && (__FreeBSD_kernel_version > 800063) || defined(__FreeBSD_kernel__)
rep->rid = hid_get_report_id(fd);
if (rep->rid < 0) {
#else
if (ioctl(fd, USB_GET_REPORT_ID, &rep->rid) < 0) {
#endif
rep->rid = -1; /* XXX */
}
#if defined(__NetBSD__)
if (ioctl(fd, USB_GET_DEVICE_DESC, &udd) == -1)
goto desc_failed;
/* Get default language */
usd.usd_string_index = USB_LANGUAGE_TABLE;
usd.usd_language_id = 0;
if (ioctl(fd, USB_GET_STRING_DESC, &usd) == -1 || usd.usd_desc.bLength < 4) {
usd.usd_language_id = 0;
} else {
usd.usd_language_id = UGETW(usd.usd_desc.bString[0]);
}
usd.usd_string_index = udd.iProduct;
if (ioctl(fd, USB_GET_STRING_DESC, &usd) == 0) {
char str[128];
char *new_name = NULL;
int i;
for (i = 0; i < (usd.usd_desc.bLength >> 1) - 1 && i < sizeof(str) - 1; i++) {
str[i] = UGETW(usd.usd_desc.bString[i]);
}
str[i] = '\0';
asprintf(&new_name, "%s @ %s", str, path);
if (new_name != NULL) {
SDL_free(joydevnames[numjoysticks]);
joydevnames[numjoysticks] = new_name;
}
}
desc_failed:
#endif
if (report_alloc(rep, hw->repdesc, REPORT_INPUT) < 0) {
goto usberr;
}
if (rep->size <= 0) {
SDL_SetError("%s: Input report descriptor has invalid length",
hw->path);
goto usberr;
}
#if defined(USBHID_NEW) || (defined(__FREEBSD__) && __FreeBSD_kernel_version >= 500111) || defined(__FreeBSD_kernel__)
hdata = hid_start_parse(hw->repdesc, 1 << hid_input, rep->rid);
#else
hdata = hid_start_parse(hw->repdesc, 1 << hid_input);
#endif
if (hdata == NULL) {
SDL_SetError("%s: Cannot start HID parser", hw->path);
goto usberr;
}
joy->naxes = 0;
joy->nbuttons = 0;
joy->nhats = 0;
joy->nballs = 0;
for (i = 0; i < JOYAXE_count; i++)
hw->axis_map[i] = -1;
while (hid_get_item(hdata, &hitem) > 0) {
char *sp;
const char *s;
switch (hitem.kind) {
case hid_collection:
switch (HID_PAGE(hitem.usage)) {
case HUP_GENERIC_DESKTOP:
switch (HID_USAGE(hitem.usage)) {
case HUG_JOYSTICK:
case HUG_GAME_PAD:
s = hid_usage_in_page(hitem.usage);
sp = SDL_malloc(SDL_strlen(s) + 5);
SDL_snprintf(sp, SDL_strlen(s) + 5, "%s (%d)",
s, device_index);
joydevnames[device_index] = sp;
}
}
break;
case hid_input:
switch (HID_PAGE(hitem.usage)) {
case HUP_GENERIC_DESKTOP:
{
unsigned usage = HID_USAGE(hitem.usage);
int joyaxe = usage_to_joyaxe(usage);
if (joyaxe >= 0) {
hw->axis_map[joyaxe] = 1;
} else if (usage == HUG_HAT_SWITCH
#ifdef __OpenBSD__
|| usage == HUG_DPAD_UP
#endif
) {
joy->nhats++;
}
break;
}
case HUP_BUTTON:
joy->nbuttons++;
break;
default:
break;
}
break;
default:
break;
}
}
hid_end_parse(hdata);
for (i = 0; i < JOYAXE_count; i++)
if (hw->axis_map[i] > 0)
hw->axis_map[i] = joy->naxes++;
if (joy->naxes == 0 && joy->nbuttons == 0 && joy->nhats == 0 && joy->nballs == 0) {
SDL_SetError("%s: Not a joystick, ignoring", hw->path);
goto usberr;
}
usbend:
/* The poll blocks the event thread. */
fcntl(fd, F_SETFL, O_NONBLOCK);
#ifdef __NetBSD__
/* Flush pending events */
if (rep) {
while (read(joy->hwdata->fd, REP_BUF_DATA(rep), rep->size) == rep->size)
;
}
#endif
return (0);
usberr:
close(hw->fd);
SDL_free(hw->path);
SDL_free(hw);
return (-1);
}
static void
BSD_JoystickUpdate(SDL_Joystick * joy)
{
struct hid_item hitem;
struct hid_data *hdata;
struct report *rep;
int nbutton, naxe = -1;
Sint32 v;
#ifdef __OpenBSD__
Sint32 dpad[4] = {0, 0, 0, 0};
#endif
#if defined(__FREEBSD__) || SDL_JOYSTICK_USBHID_MACHINE_JOYSTICK_H || defined(__FreeBSD_kernel__)
struct joystick gameport;
static int x, y, xmin = 0xffff, ymin = 0xffff, xmax = 0, ymax = 0;
if (joy->hwdata->type == BSDJOY_JOY) {
while (read(joy->hwdata->fd, &gameport, sizeof gameport) == sizeof gameport) {
if (abs(x - gameport.x) > 8) {
x = gameport.x;
if (x < xmin) {
xmin = x;
}
if (x > xmax) {
xmax = x;
}
if (xmin == xmax) {
xmin--;
xmax++;
}
v = (Sint32) x;
v -= (xmax + xmin + 1) / 2;
v *= 32768 / ((xmax - xmin + 1) / 2);
SDL_PrivateJoystickAxis(joy, 0, v);
}
if (abs(y - gameport.y) > 8) {
y = gameport.y;
if (y < ymin) {
ymin = y;
}
if (y > ymax) {
ymax = y;
}
if (ymin == ymax) {
ymin--;
ymax++;
}
v = (Sint32) y;
v -= (ymax + ymin + 1) / 2;
v *= 32768 / ((ymax - ymin + 1) / 2);
SDL_PrivateJoystickAxis(joy, 1, v);
}
SDL_PrivateJoystickButton(joy, 0, gameport.b1);
SDL_PrivateJoystickButton(joy, 1, gameport.b2);
}
return;
}
#endif /* defined(__FREEBSD__) || SDL_JOYSTICK_USBHID_MACHINE_JOYSTICK_H */
rep = &joy->hwdata->inreport;
while (read(joy->hwdata->fd, REP_BUF_DATA(rep), rep->size) == rep->size) {
#if defined(USBHID_NEW) || (defined(__FREEBSD__) && __FreeBSD_kernel_version >= 500111) || defined(__FreeBSD_kernel__)
hdata = hid_start_parse(joy->hwdata->repdesc, 1 << hid_input, rep->rid);
#else
hdata = hid_start_parse(joy->hwdata->repdesc, 1 << hid_input);
#endif
if (hdata == NULL) {
/*fprintf(stderr, "%s: Cannot start HID parser\n", joy->hwdata->path);*/
continue;
}
for (nbutton = 0; hid_get_item(hdata, &hitem) > 0;) {
switch (hitem.kind) {
case hid_input:
switch (HID_PAGE(hitem.usage)) {
case HUP_GENERIC_DESKTOP:
{
unsigned usage = HID_USAGE(hitem.usage);
int joyaxe = usage_to_joyaxe(usage);
if (joyaxe >= 0) {
naxe = joy->hwdata->axis_map[joyaxe];
/* scaleaxe */
v = (Sint32) hid_get_data(REP_BUF_DATA(rep), &hitem);
v -= (hitem.logical_maximum +
hitem.logical_minimum + 1) / 2;
v *= 32768 /
((hitem.logical_maximum -
hitem.logical_minimum + 1) / 2);
SDL_PrivateJoystickAxis(joy, naxe, v);
} else if (usage == HUG_HAT_SWITCH) {
v = (Sint32) hid_get_data(REP_BUF_DATA(rep), &hitem);
SDL_PrivateJoystickHat(joy, 0,
hatval_to_sdl(v) -
hitem.logical_minimum);
}
#ifdef __OpenBSD__
else if (usage == HUG_DPAD_UP) {
dpad[0] = (Sint32) hid_get_data(REP_BUF_DATA(rep), &hitem);
SDL_PrivateJoystickHat(joy, 0, dpad_to_sdl(dpad));
}
else if (usage == HUG_DPAD_DOWN) {
dpad[1] = (Sint32) hid_get_data(REP_BUF_DATA(rep), &hitem);
SDL_PrivateJoystickHat(joy, 0, dpad_to_sdl(dpad));
}
else if (usage == HUG_DPAD_RIGHT) {
dpad[2] = (Sint32) hid_get_data(REP_BUF_DATA(rep), &hitem);
SDL_PrivateJoystickHat(joy, 0, dpad_to_sdl(dpad));
}
else if (usage == HUG_DPAD_LEFT) {
dpad[3] = (Sint32) hid_get_data(REP_BUF_DATA(rep), &hitem);
SDL_PrivateJoystickHat(joy, 0, dpad_to_sdl(dpad));
}
#endif
break;
}
case HUP_BUTTON:
v = (Sint32) hid_get_data(REP_BUF_DATA(rep), &hitem);
SDL_PrivateJoystickButton(joy, nbutton, v);
nbutton++;
break;
default:
continue;
}
break;
default:
break;
}
}
hid_end_parse(hdata);
}
}
/* Function to close a joystick after use */
static void
BSD_JoystickClose(SDL_Joystick * joy)
{
if (SDL_strncmp(joy->hwdata->path, "/dev/joy", 8)) {
report_free(&joy->hwdata->inreport);
hid_dispose_report_desc(joy->hwdata->repdesc);
}
close(joy->hwdata->fd);
SDL_free(joy->hwdata->path);
SDL_free(joy->hwdata);
}
static void
BSD_JoystickQuit(void)
{
int i;
for (i = 0; i < MAX_JOYS; i++) {
SDL_free(joynames[i]);
SDL_free(joydevnames[i]);
}
return;
}
static SDL_JoystickGUID
BSD_JoystickGetDeviceGUID( int device_index )
{
SDL_JoystickGUID guid;
/* the GUID is just the first 16 chars of the name for now */
const char *name = BSD_JoystickGetDeviceName( device_index );
SDL_zero( guid );
SDL_memcpy( &guid, name, SDL_min( sizeof(guid), SDL_strlen( name ) ) );
return guid;
}
static int
report_alloc(struct report *r, struct report_desc *rd, int repind)
{
int len;
#ifdef __DragonFly__
len = hid_report_size(rd, r->rid, repinfo[repind].kind);
#elif __FREEBSD__
# if (__FreeBSD_kernel_version >= 460000) || defined(__FreeBSD_kernel__)
# if (__FreeBSD_kernel_version <= 500111)
len = hid_report_size(rd, r->rid, repinfo[repind].kind);
# else
len = hid_report_size(rd, repinfo[repind].kind, r->rid);
# endif
# else
len = hid_report_size(rd, repinfo[repind].kind, &r->rid);
# endif
#else
# ifdef USBHID_NEW
len = hid_report_size(rd, repinfo[repind].kind, r->rid);
# else
len = hid_report_size(rd, repinfo[repind].kind, &r->rid);
# endif
#endif
if (len < 0) {
return SDL_SetError("Negative HID report size");
}
r->size = len;
if (r->size > 0) {
#if defined(__FREEBSD__) && (__FreeBSD_kernel_version > 900000)
r->buf = SDL_malloc(r->size);
#else
r->buf = SDL_malloc(sizeof(*r->buf) - sizeof(REP_BUF_DATA(r)) +
r->size);
#endif
if (r->buf == NULL) {
return SDL_OutOfMemory();
}
} else {
r->buf = NULL;
}
r->status = SREPORT_CLEAN;
return 0;
}
static void
report_free(struct report *r)
{
SDL_free(r->buf);
r->status = SREPORT_UNINIT;
}
static int
BSD_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
{
return SDL_Unsupported();
}
SDL_JoystickDriver SDL_BSD_JoystickDriver =
{
BSD_JoystickInit,
BSD_JoystickGetCount,
BSD_JoystickDetect,
BSD_JoystickGetDeviceName,
BSD_JoystickGetDevicePlayerIndex,
BSD_JoystickSetDevicePlayerIndex,
BSD_JoystickGetDeviceGUID,
BSD_JoystickGetDeviceInstanceID,
BSD_JoystickOpen,
BSD_JoystickRumble,
BSD_JoystickUpdate,
BSD_JoystickClose,
BSD_JoystickQuit,
};
#endif /* SDL_JOYSTICK_USBHID */
/* vi: set ts=4 sw=4 expandtab: */

File diff suppressed because it is too large Load Diff

View File

@@ -1,79 +0,0 @@
/*
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_IOKIT_H
#define SDL_JOYSTICK_IOKIT_H
#include <IOKit/hid/IOHIDLib.h>
#include <ForceFeedback/ForceFeedback.h>
#include <ForceFeedback/ForceFeedbackConstants.h>
struct recElement
{
IOHIDElementRef elementRef;
IOHIDElementCookie cookie;
uint32_t usagePage, usage; /* HID usage */
SInt32 min; /* reported min value possible */
SInt32 max; /* reported max value possible */
/* runtime variables used for auto-calibration */
SInt32 minReport; /* min returned value */
SInt32 maxReport; /* max returned value */
struct recElement *pNext; /* next element in list */
};
typedef struct recElement recElement;
struct joystick_hwdata
{
IOHIDDeviceRef deviceRef; /* HIDManager device handle */
io_service_t ffservice; /* Interface for force feedback, 0 = no ff */
FFDeviceObjectReference ffdevice;
FFEFFECT *ffeffect;
FFEffectObjectReference ffeffect_ref;
SDL_bool ff_initialized;
char product[256]; /* name of product */
uint32_t usage; /* usage page from IOUSBHID Parser.h which defines general usage */
uint32_t usagePage; /* usage within above page from IOUSBHID Parser.h which defines specific usage */
int axes; /* number of axis (calculated, not reported by device) */
int buttons; /* number of buttons (calculated, not reported by device) */
int hats; /* number of hat switches (calculated, not reported by device) */
int elements; /* number of total elements (should be total of above) (calculated, not reported by device) */
recElement *firstAxis;
recElement *firstButton;
recElement *firstHat;
SDL_bool removed;
int instance_id;
SDL_JoystickGUID guid;
struct joystick_hwdata *pNext; /* next device */
};
typedef struct joystick_hwdata recDevice;
#endif /* SDL_JOYSTICK_IOKIT_H */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -1,863 +0,0 @@
/*
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"
/* This is the iOS implementation of the SDL joystick API */
#include "SDL_sysjoystick_c.h"
/* needed for SDL_IPHONE_MAX_GFORCE macro */
#include "../../../include/SDL_config_iphoneos.h"
#include "SDL_assert.h"
#include "SDL_events.h"
#include "SDL_joystick.h"
#include "SDL_hints.h"
#include "SDL_stdinc.h"
#include "../SDL_sysjoystick.h"
#include "../SDL_joystick_c.h"
#if !SDL_EVENTS_DISABLED
#include "../../events/SDL_events_c.h"
#endif
#if !TARGET_OS_TV
#import <CoreMotion/CoreMotion.h>
#endif
#ifdef SDL_JOYSTICK_MFI
#import <GameController/GameController.h>
static id connectObserver = nil;
static id disconnectObserver = nil;
#include <Availability.h>
#include <objc/message.h>
/* remove compilation warnings for strict builds by defining these selectors, even though
* they are only ever used indirectly through objc_msgSend
*/
@interface GCExtendedGamepad (SDL)
#if (__IPHONE_OS_VERSION_MAX_ALLOWED < 121000) || (__APPLETV_OS_VERSION_MAX_ALLOWED < 121000) || (__MAC_OS_VERSION_MAX_ALLOWED < 1401000)
@property (nonatomic, readonly, nullable) GCControllerButtonInput *leftThumbstickButton;
@property (nonatomic, readonly, nullable) GCControllerButtonInput *rightThumbstickButton;
#endif
#if (__IPHONE_OS_VERSION_MAX_ALLOWED < 130000) || (__APPLETV_OS_VERSION_MAX_ALLOWED < 130000) || (__MAC_OS_VERSION_MAX_ALLOWED < 1500000)
@property (nonatomic, readonly) GCControllerButtonInput *buttonMenu;
@property (nonatomic, readonly, nullable) GCControllerButtonInput *buttonOptions;
#endif
@end
@interface GCMicroGamepad (SDL)
#if (__IPHONE_OS_VERSION_MAX_ALLOWED < 130000) || (__APPLETV_OS_VERSION_MAX_ALLOWED < 130000) || (__MAC_OS_VERSION_MAX_ALLOWED < 1500000)
@property (nonatomic, readonly) GCControllerButtonInput *buttonMenu;
#endif
@end
#endif /* SDL_JOYSTICK_MFI */
#if !TARGET_OS_TV
static const char *accelerometerName = "iOS Accelerometer";
static CMMotionManager *motionManager = nil;
#endif /* !TARGET_OS_TV */
static SDL_JoystickDeviceItem *deviceList = NULL;
static int numjoysticks = 0;
int SDL_AppleTVRemoteOpenedAsJoystick = 0;
static SDL_JoystickDeviceItem *
GetDeviceForIndex(int device_index)
{
SDL_JoystickDeviceItem *device = deviceList;
int i = 0;
while (i < device_index) {
if (device == NULL) {
return NULL;
}
device = device->next;
i++;
}
return device;
}
static void
IOS_AddMFIJoystickDevice(SDL_JoystickDeviceItem *device, GCController *controller)
{
#ifdef SDL_JOYSTICK_MFI
const Uint16 VENDOR_APPLE = 0x05AC;
const Uint16 VENDOR_MICROSOFT = 0x045e;
const Uint16 VENDOR_SONY = 0x054C;
Uint16 *guid16 = (Uint16 *)device->guid.data;
Uint16 vendor = 0;
Uint16 product = 0;
Uint8 subtype = 0;
const char *name = NULL;
/* Explicitly retain the controller because SDL_JoystickDeviceItem is a
* struct, and ARC doesn't work with structs. */
device->controller = (__bridge GCController *) CFBridgingRetain(controller);
if (controller.vendorName) {
name = controller.vendorName.UTF8String;
}
if (!name) {
name = "MFi Gamepad";
}
device->name = SDL_strdup(name);
if (controller.extendedGamepad) {
GCExtendedGamepad *gamepad = controller.extendedGamepad;
BOOL is_xbox = [controller.vendorName containsString: @"Xbox"];
BOOL is_ps4 = [controller.vendorName containsString: @"DUALSHOCK"];
#if TARGET_OS_TV
BOOL is_MFi = (!is_xbox && !is_ps4);
#endif
int nbuttons = 0;
/* These buttons are part of the original MFi spec */
device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_A);
device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_B);
device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_X);
device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_Y);
device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_LEFTSHOULDER);
device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_RIGHTSHOULDER);
nbuttons += 6;
/* These buttons are available on some newer controllers */
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunguarded-availability-new"
if ([gamepad respondsToSelector:@selector(leftThumbstickButton)] && gamepad.leftThumbstickButton) {
device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_LEFTSTICK);
++nbuttons;
}
if ([gamepad respondsToSelector:@selector(rightThumbstickButton)] && gamepad.rightThumbstickButton) {
device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_RIGHTSTICK);
++nbuttons;
}
if ([gamepad respondsToSelector:@selector(buttonOptions)] && gamepad.buttonOptions) {
device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_BACK);
++nbuttons;
}
BOOL has_direct_menu = [gamepad respondsToSelector:@selector(buttonMenu)] && gamepad.buttonMenu;
#if TARGET_OS_TV
/* On tvOS MFi controller menu button brings you to the home screen */
if (is_MFi) {
has_direct_menu = FALSE;
}
#endif
device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_START);
++nbuttons;
if (!has_direct_menu) {
device->uses_pause_handler = SDL_TRUE;
}
#pragma clang diagnostic pop
if (is_xbox) {
vendor = VENDOR_MICROSOFT;
product = 0x02E0; /* Assume Xbox One S BLE Controller unless/until GCController flows VID/PID */
} else if (is_ps4) {
vendor = VENDOR_SONY;
product = 0x09CC; /* Assume DS4 Slim unless/until GCController flows VID/PID */
} else {
vendor = VENDOR_APPLE;
product = 1;
subtype = 1;
}
device->naxes = 6; /* 2 thumbsticks and 2 triggers */
device->nhats = 1; /* d-pad */
device->nbuttons = nbuttons;
} else if (controller.gamepad) {
int nbuttons = 0;
/* These buttons are part of the original MFi spec */
device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_A);
device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_B);
device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_X);
device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_Y);
device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_LEFTSHOULDER);
device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_RIGHTSHOULDER);
device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_START);
nbuttons += 7;
device->uses_pause_handler = SDL_TRUE;
vendor = VENDOR_APPLE;
product = 2;
subtype = 2;
device->naxes = 0; /* no traditional analog inputs */
device->nhats = 1; /* d-pad */
device->nbuttons = nbuttons;
}
#if TARGET_OS_TV
else if (controller.microGamepad) {
int nbuttons = 0;
device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_A);
device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_B); /* Button X on microGamepad */
nbuttons += 2;
device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_START);
++nbuttons;
device->uses_pause_handler = SDL_TRUE;
vendor = VENDOR_APPLE;
product = 3;
subtype = 3;
device->naxes = 2; /* treat the touch surface as two axes */
device->nhats = 0; /* apparently the touch surface-as-dpad is buggy */
device->nbuttons = nbuttons;
controller.microGamepad.allowsRotation = SDL_GetHintBoolean(SDL_HINT_APPLE_TV_REMOTE_ALLOW_ROTATION, SDL_FALSE);
}
#endif /* TARGET_OS_TV */
/* We only need 16 bits for each of these; space them out to fill 128. */
/* Byteswap so devices get same GUID on little/big endian platforms. */
*guid16++ = SDL_SwapLE16(SDL_HARDWARE_BUS_BLUETOOTH);
*guid16++ = 0;
*guid16++ = SDL_SwapLE16(vendor);
*guid16++ = 0;
*guid16++ = SDL_SwapLE16(product);
*guid16++ = 0;
*guid16++ = SDL_SwapLE16(device->button_mask);
if (subtype != 0) {
/* Note that this is an MFI controller and what subtype it is */
device->guid.data[14] = 'm';
device->guid.data[15] = subtype;
}
/* This will be set when the first button press of the controller is
* detected. */
controller.playerIndex = -1;
#endif /* SDL_JOYSTICK_MFI */
}
static void
IOS_AddJoystickDevice(GCController *controller, SDL_bool accelerometer)
{
SDL_JoystickDeviceItem *device = deviceList;
#if TARGET_OS_TV
if (!SDL_GetHintBoolean(SDL_HINT_TV_REMOTE_AS_JOYSTICK, SDL_TRUE)) {
/* Ignore devices that aren't actually controllers (e.g. remotes), they'll be handled as keyboard input */
if (controller && !controller.extendedGamepad && !controller.gamepad && controller.microGamepad) {
return;
}
}
#endif
while (device != NULL) {
if (device->controller == controller) {
return;
}
device = device->next;
}
device = (SDL_JoystickDeviceItem *) SDL_calloc(1, sizeof(SDL_JoystickDeviceItem));
if (device == NULL) {
return;
}
device->accelerometer = accelerometer;
device->instance_id = SDL_GetNextJoystickInstanceID();
if (accelerometer) {
#if TARGET_OS_TV
SDL_free(device);
return;
#else
device->name = SDL_strdup(accelerometerName);
device->naxes = 3; /* Device acceleration in the x, y, and z axes. */
device->nhats = 0;
device->nbuttons = 0;
/* Use the accelerometer name as a GUID. */
SDL_memcpy(&device->guid.data, device->name, SDL_min(sizeof(SDL_JoystickGUID), SDL_strlen(device->name)));
#endif /* TARGET_OS_TV */
} else if (controller) {
IOS_AddMFIJoystickDevice(device, controller);
}
if (deviceList == NULL) {
deviceList = device;
} else {
SDL_JoystickDeviceItem *lastdevice = deviceList;
while (lastdevice->next != NULL) {
lastdevice = lastdevice->next;
}
lastdevice->next = device;
}
++numjoysticks;
SDL_PrivateJoystickAdded(device->instance_id);
}
static SDL_JoystickDeviceItem *
IOS_RemoveJoystickDevice(SDL_JoystickDeviceItem *device)
{
SDL_JoystickDeviceItem *prev = NULL;
SDL_JoystickDeviceItem *next = NULL;
SDL_JoystickDeviceItem *item = deviceList;
if (device == NULL) {
return NULL;
}
next = device->next;
while (item != NULL) {
if (item == device) {
break;
}
prev = item;
item = item->next;
}
/* Unlink the device item from the device list. */
if (prev) {
prev->next = device->next;
} else if (device == deviceList) {
deviceList = device->next;
}
if (device->joystick) {
device->joystick->hwdata = NULL;
}
#ifdef SDL_JOYSTICK_MFI
@autoreleasepool {
if (device->controller) {
/* The controller was explicitly retained in the struct, so it
* should be explicitly released before freeing the struct. */
GCController *controller = CFBridgingRelease((__bridge CFTypeRef)(device->controller));
controller.controllerPausedHandler = nil;
device->controller = nil;
}
}
#endif /* SDL_JOYSTICK_MFI */
--numjoysticks;
SDL_PrivateJoystickRemoved(device->instance_id);
SDL_free(device->name);
SDL_free(device);
return next;
}
#if TARGET_OS_TV
static void SDLCALL
SDL_AppleTVRemoteRotationHintChanged(void *udata, const char *name, const char *oldValue, const char *newValue)
{
BOOL allowRotation = newValue != NULL && *newValue != '0';
@autoreleasepool {
for (GCController *controller in [GCController controllers]) {
if (controller.microGamepad) {
controller.microGamepad.allowsRotation = allowRotation;
}
}
}
}
#endif /* TARGET_OS_TV */
static int
IOS_JoystickInit(void)
{
@autoreleasepool {
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
#if !TARGET_OS_TV
if (SDL_GetHintBoolean(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, SDL_TRUE)) {
/* Default behavior, accelerometer as joystick */
IOS_AddJoystickDevice(nil, SDL_TRUE);
}
#endif /* !TARGET_OS_TV */
#ifdef SDL_JOYSTICK_MFI
/* GameController.framework was added in iOS 7. */
if (![GCController class]) {
return 0;
}
for (GCController *controller in [GCController controllers]) {
IOS_AddJoystickDevice(controller, SDL_FALSE);
}
#if TARGET_OS_TV
SDL_AddHintCallback(SDL_HINT_APPLE_TV_REMOTE_ALLOW_ROTATION,
SDL_AppleTVRemoteRotationHintChanged, NULL);
#endif /* TARGET_OS_TV */
connectObserver = [center addObserverForName:GCControllerDidConnectNotification
object:nil
queue:nil
usingBlock:^(NSNotification *note) {
GCController *controller = note.object;
IOS_AddJoystickDevice(controller, SDL_FALSE);
}];
disconnectObserver = [center addObserverForName:GCControllerDidDisconnectNotification
object:nil
queue:nil
usingBlock:^(NSNotification *note) {
GCController *controller = note.object;
SDL_JoystickDeviceItem *device = deviceList;
while (device != NULL) {
if (device->controller == controller) {
IOS_RemoveJoystickDevice(device);
break;
}
device = device->next;
}
}];
#endif /* SDL_JOYSTICK_MFI */
}
return 0;
}
static int
IOS_JoystickGetCount(void)
{
return numjoysticks;
}
static void
IOS_JoystickDetect(void)
{
}
static const char *
IOS_JoystickGetDeviceName(int device_index)
{
SDL_JoystickDeviceItem *device = GetDeviceForIndex(device_index);
return device ? device->name : "Unknown";
}
static int
IOS_JoystickGetDevicePlayerIndex(int device_index)
{
SDL_JoystickDeviceItem *device = GetDeviceForIndex(device_index);
return device ? (int)device->controller.playerIndex : -1;
}
static void
IOS_JoystickSetDevicePlayerIndex(int device_index, int player_index)
{
SDL_JoystickDeviceItem *device = GetDeviceForIndex(device_index);
if (device) {
device->controller.playerIndex = player_index;
}
}
static SDL_JoystickGUID
IOS_JoystickGetDeviceGUID( int device_index )
{
SDL_JoystickDeviceItem *device = GetDeviceForIndex(device_index);
SDL_JoystickGUID guid;
if (device) {
guid = device->guid;
} else {
SDL_zero(guid);
}
return guid;
}
static SDL_JoystickID
IOS_JoystickGetDeviceInstanceID(int device_index)
{
SDL_JoystickDeviceItem *device = GetDeviceForIndex(device_index);
return device ? device->instance_id : -1;
}
static int
IOS_JoystickOpen(SDL_Joystick * joystick, int device_index)
{
SDL_JoystickDeviceItem *device = GetDeviceForIndex(device_index);
if (device == NULL) {
return SDL_SetError("Could not open Joystick: no hardware device for the specified index");
}
joystick->hwdata = device;
joystick->instance_id = device->instance_id;
joystick->naxes = device->naxes;
joystick->nhats = device->nhats;
joystick->nbuttons = device->nbuttons;
joystick->nballs = 0;
device->joystick = joystick;
@autoreleasepool {
if (device->accelerometer) {
#if !TARGET_OS_TV
if (motionManager == nil) {
motionManager = [[CMMotionManager alloc] init];
}
/* Shorter times between updates can significantly increase CPU usage. */
motionManager.accelerometerUpdateInterval = 0.1;
[motionManager startAccelerometerUpdates];
#endif /* !TARGET_OS_TV */
} else {
#ifdef SDL_JOYSTICK_MFI
if (device->uses_pause_handler) {
GCController *controller = device->controller;
controller.controllerPausedHandler = ^(GCController *c) {
if (joystick->hwdata) {
++joystick->hwdata->num_pause_presses;
}
};
}
#endif /* SDL_JOYSTICK_MFI */
}
}
if (device->remote) {
++SDL_AppleTVRemoteOpenedAsJoystick;
}
return 0;
}
static void
IOS_AccelerometerUpdate(SDL_Joystick * joystick)
{
#if !TARGET_OS_TV
const float maxgforce = SDL_IPHONE_MAX_GFORCE;
const SInt16 maxsint16 = 0x7FFF;
CMAcceleration accel;
@autoreleasepool {
if (!motionManager.isAccelerometerActive) {
return;
}
accel = motionManager.accelerometerData.acceleration;
}
/*
Convert accelerometer data from floating point to Sint16, which is what
the joystick system expects.
To do the conversion, the data is first clamped onto the interval
[-SDL_IPHONE_MAX_G_FORCE, SDL_IPHONE_MAX_G_FORCE], then the data is multiplied
by MAX_SINT16 so that it is mapped to the full range of an Sint16.
You can customize the clamped range of this function by modifying the
SDL_IPHONE_MAX_GFORCE macro in SDL_config_iphoneos.h.
Once converted to Sint16, the accelerometer data no longer has coherent
units. You can convert the data back to units of g-force by multiplying
it in your application's code by SDL_IPHONE_MAX_GFORCE / 0x7FFF.
*/
/* clamp the data */
accel.x = SDL_min(SDL_max(accel.x, -maxgforce), maxgforce);
accel.y = SDL_min(SDL_max(accel.y, -maxgforce), maxgforce);
accel.z = SDL_min(SDL_max(accel.z, -maxgforce), maxgforce);
/* pass in data mapped to range of SInt16 */
SDL_PrivateJoystickAxis(joystick, 0, (accel.x / maxgforce) * maxsint16);
SDL_PrivateJoystickAxis(joystick, 1, -(accel.y / maxgforce) * maxsint16);
SDL_PrivateJoystickAxis(joystick, 2, (accel.z / maxgforce) * maxsint16);
#endif /* !TARGET_OS_TV */
}
#ifdef SDL_JOYSTICK_MFI
static Uint8
IOS_MFIJoystickHatStateForDPad(GCControllerDirectionPad *dpad)
{
Uint8 hat = 0;
if (dpad.up.isPressed) {
hat |= SDL_HAT_UP;
} else if (dpad.down.isPressed) {
hat |= SDL_HAT_DOWN;
}
if (dpad.left.isPressed) {
hat |= SDL_HAT_LEFT;
} else if (dpad.right.isPressed) {
hat |= SDL_HAT_RIGHT;
}
if (hat == 0) {
return SDL_HAT_CENTERED;
}
return hat;
}
#endif
static void
IOS_MFIJoystickUpdate(SDL_Joystick * joystick)
{
#if SDL_JOYSTICK_MFI
@autoreleasepool {
GCController *controller = joystick->hwdata->controller;
Uint8 hatstate = SDL_HAT_CENTERED;
int i;
int pause_button_index = 0;
if (controller.extendedGamepad) {
GCExtendedGamepad *gamepad = controller.extendedGamepad;
/* Axis order matches the XInput Windows mappings. */
Sint16 axes[] = {
(Sint16) (gamepad.leftThumbstick.xAxis.value * 32767),
(Sint16) (gamepad.leftThumbstick.yAxis.value * -32767),
(Sint16) ((gamepad.leftTrigger.value * 65535) - 32768),
(Sint16) (gamepad.rightThumbstick.xAxis.value * 32767),
(Sint16) (gamepad.rightThumbstick.yAxis.value * -32767),
(Sint16) ((gamepad.rightTrigger.value * 65535) - 32768),
};
/* Button order matches the XInput Windows mappings. */
Uint8 buttons[joystick->nbuttons];
int button_count = 0;
/* These buttons are part of the original MFi spec */
buttons[button_count++] = gamepad.buttonA.isPressed;
buttons[button_count++] = gamepad.buttonB.isPressed;
buttons[button_count++] = gamepad.buttonX.isPressed;
buttons[button_count++] = gamepad.buttonY.isPressed;
buttons[button_count++] = gamepad.leftShoulder.isPressed;
buttons[button_count++] = gamepad.rightShoulder.isPressed;
/* These buttons are available on some newer controllers */
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunguarded-availability-new"
if (joystick->hwdata->button_mask & (1 << SDL_CONTROLLER_BUTTON_LEFTSTICK)) {
buttons[button_count++] = gamepad.leftThumbstickButton.isPressed;
}
if (joystick->hwdata->button_mask & (1 << SDL_CONTROLLER_BUTTON_RIGHTSTICK)) {
buttons[button_count++] = gamepad.rightThumbstickButton.isPressed;
}
if (joystick->hwdata->button_mask & (1 << SDL_CONTROLLER_BUTTON_BACK)) {
buttons[button_count++] = gamepad.buttonOptions.isPressed;
}
/* This must be the last button, so we can optionally handle it with pause_button_index below */
if (joystick->hwdata->button_mask & (1 << SDL_CONTROLLER_BUTTON_START)) {
if (joystick->hwdata->uses_pause_handler) {
pause_button_index = button_count;
buttons[button_count++] = joystick->delayed_guide_button;
} else {
buttons[button_count++] = gamepad.buttonMenu.isPressed;
}
}
#pragma clang diagnostic pop
hatstate = IOS_MFIJoystickHatStateForDPad(gamepad.dpad);
for (i = 0; i < SDL_arraysize(axes); i++) {
SDL_PrivateJoystickAxis(joystick, i, axes[i]);
}
for (i = 0; i < button_count; i++) {
SDL_PrivateJoystickButton(joystick, i, buttons[i]);
}
} else if (controller.gamepad) {
GCGamepad *gamepad = controller.gamepad;
/* Button order matches the XInput Windows mappings. */
Uint8 buttons[joystick->nbuttons];
int button_count = 0;
buttons[button_count++] = gamepad.buttonA.isPressed;
buttons[button_count++] = gamepad.buttonB.isPressed;
buttons[button_count++] = gamepad.buttonX.isPressed;
buttons[button_count++] = gamepad.buttonY.isPressed;
buttons[button_count++] = gamepad.leftShoulder.isPressed;
buttons[button_count++] = gamepad.rightShoulder.isPressed;
pause_button_index = button_count;
buttons[button_count++] = joystick->delayed_guide_button;
hatstate = IOS_MFIJoystickHatStateForDPad(gamepad.dpad);
for (i = 0; i < button_count; i++) {
SDL_PrivateJoystickButton(joystick, i, buttons[i]);
}
}
#if TARGET_OS_TV
else if (controller.microGamepad) {
GCMicroGamepad *gamepad = controller.microGamepad;
Sint16 axes[] = {
(Sint16) (gamepad.dpad.xAxis.value * 32767),
(Sint16) (gamepad.dpad.yAxis.value * -32767),
};
for (i = 0; i < SDL_arraysize(axes); i++) {
SDL_PrivateJoystickAxis(joystick, i, axes[i]);
}
Uint8 buttons[joystick->nbuttons];
int button_count = 0;
buttons[button_count++] = gamepad.buttonA.isPressed;
buttons[button_count++] = gamepad.buttonX.isPressed;
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunguarded-availability-new"
/* This must be the last button, so we can optionally handle it with pause_button_index below */
if (joystick->hwdata->button_mask & (1 << SDL_CONTROLLER_BUTTON_START)) {
if (joystick->hwdata->uses_pause_handler) {
pause_button_index = button_count;
buttons[button_count++] = joystick->delayed_guide_button;
} else {
buttons[button_count++] = gamepad.buttonMenu.isPressed;
}
}
#pragma clang diagnostic pop
for (i = 0; i < button_count; i++) {
SDL_PrivateJoystickButton(joystick, i, buttons[i]);
}
}
#endif /* TARGET_OS_TV */
if (joystick->nhats > 0) {
SDL_PrivateJoystickHat(joystick, 0, hatstate);
}
if (joystick->hwdata->uses_pause_handler) {
for (i = 0; i < joystick->hwdata->num_pause_presses; i++) {
SDL_PrivateJoystickButton(joystick, pause_button_index, SDL_PRESSED);
SDL_PrivateJoystickButton(joystick, pause_button_index, SDL_RELEASED);
}
joystick->hwdata->num_pause_presses = 0;
}
}
#endif /* SDL_JOYSTICK_MFI */
}
static int
IOS_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
{
return SDL_Unsupported();
}
static void
IOS_JoystickUpdate(SDL_Joystick * joystick)
{
SDL_JoystickDeviceItem *device = joystick->hwdata;
if (device == NULL) {
return;
}
if (device->accelerometer) {
IOS_AccelerometerUpdate(joystick);
} else if (device->controller) {
IOS_MFIJoystickUpdate(joystick);
}
}
static void
IOS_JoystickClose(SDL_Joystick * joystick)
{
SDL_JoystickDeviceItem *device = joystick->hwdata;
if (device == NULL) {
return;
}
device->joystick = NULL;
@autoreleasepool {
if (device->accelerometer) {
#if !TARGET_OS_TV
[motionManager stopAccelerometerUpdates];
#endif /* !TARGET_OS_TV */
} else if (device->controller) {
#ifdef SDL_JOYSTICK_MFI
GCController *controller = device->controller;
controller.controllerPausedHandler = nil;
controller.playerIndex = -1;
#endif
}
}
if (device->remote) {
--SDL_AppleTVRemoteOpenedAsJoystick;
}
}
static void
IOS_JoystickQuit(void)
{
@autoreleasepool {
#ifdef SDL_JOYSTICK_MFI
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
if (connectObserver) {
[center removeObserver:connectObserver name:GCControllerDidConnectNotification object:nil];
connectObserver = nil;
}
if (disconnectObserver) {
[center removeObserver:disconnectObserver name:GCControllerDidDisconnectNotification object:nil];
disconnectObserver = nil;
}
#if TARGET_OS_TV
SDL_DelHintCallback(SDL_HINT_APPLE_TV_REMOTE_ALLOW_ROTATION,
SDL_AppleTVRemoteRotationHintChanged, NULL);
#endif /* TARGET_OS_TV */
#endif /* SDL_JOYSTICK_MFI */
while (deviceList != NULL) {
IOS_RemoveJoystickDevice(deviceList);
}
#if !TARGET_OS_TV
motionManager = nil;
#endif /* !TARGET_OS_TV */
}
numjoysticks = 0;
}
SDL_JoystickDriver SDL_IOS_JoystickDriver =
{
IOS_JoystickInit,
IOS_JoystickGetCount,
IOS_JoystickDetect,
IOS_JoystickGetDeviceName,
IOS_JoystickGetDevicePlayerIndex,
IOS_JoystickSetDevicePlayerIndex,
IOS_JoystickGetDeviceGUID,
IOS_JoystickGetDeviceInstanceID,
IOS_JoystickOpen,
IOS_JoystickRumble,
IOS_JoystickUpdate,
IOS_JoystickClose,
IOS_JoystickQuit,
};
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -1,59 +0,0 @@
/*
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_IOS_H
#define SDL_JOYSTICK_IOS_H
#include "SDL_stdinc.h"
#include "../SDL_sysjoystick.h"
@class GCController;
typedef struct joystick_hwdata
{
SDL_bool accelerometer;
SDL_bool remote;
GCController __unsafe_unretained *controller;
SDL_bool uses_pause_handler;
int num_pause_presses;
Uint32 pause_button_down_time;
char *name;
SDL_Joystick *joystick;
SDL_JoystickID instance_id;
SDL_JoystickGUID guid;
int naxes;
int nbuttons;
int nhats;
Uint16 button_mask;
struct joystick_hwdata *next;
} joystick_hwdata;
typedef joystick_hwdata SDL_JoystickDeviceItem;
#endif /* SDL_JOYSTICK_IOS_H */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -1,515 +0,0 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2021 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"
#ifdef SDL_JOYSTICK_WINMM
/* Win32 MultiMedia Joystick driver, contributed by Andrei de A. Formiga */
#include "../../core/windows/SDL_windows.h"
#include <mmsystem.h>
#include <regstr.h>
#include "SDL_events.h"
#include "SDL_joystick.h"
#include "../SDL_sysjoystick.h"
#include "../SDL_joystick_c.h"
#ifdef REGSTR_VAL_JOYOEMNAME
#undef REGSTR_VAL_JOYOEMNAME
#endif
#define REGSTR_VAL_JOYOEMNAME "OEMName"
#define MAX_JOYSTICKS 16
#define MAX_AXES 6 /* each joystick can have up to 6 axes */
#define MAX_BUTTONS 32 /* and 32 buttons */
#define JOY_BUTTON_FLAG(n) (1<<n)
/* array to hold joystick ID values */
static UINT SYS_JoystickID[MAX_JOYSTICKS];
static JOYCAPSA SYS_Joystick[MAX_JOYSTICKS];
static char *SYS_JoystickName[MAX_JOYSTICKS];
/* The private structure used to keep track of a joystick */
struct joystick_hwdata
{
/* joystick ID */
UINT id;
/* values used to translate device-specific coordinates into
SDL-standard ranges */
struct _transaxis
{
int offset;
float scale;
} transaxis[6];
};
/* Convert a Windows Multimedia API return code to a text message */
static void SetMMerror(char *function, int code);
static char *
GetJoystickName(int index, const char *szRegKey)
{
/* added 7/24/2004 by Eckhard Stolberg */
/*
see if there is a joystick for the current
index (1-16) listed in the registry
*/
char *name = NULL;
HKEY hTopKey;
HKEY hKey;
DWORD regsize;
LONG regresult;
char regkey[256];
char regvalue[256];
char regname[256];
SDL_snprintf(regkey, SDL_arraysize(regkey),
#ifdef UNICODE
"%S\\%s\\%S",
#else
"%s\\%s\\%s",
#endif
REGSTR_PATH_JOYCONFIG, szRegKey, REGSTR_KEY_JOYCURR);
hTopKey = HKEY_LOCAL_MACHINE;
regresult = RegOpenKeyExA(hTopKey, regkey, 0, KEY_READ, &hKey);
if (regresult != ERROR_SUCCESS) {
hTopKey = HKEY_CURRENT_USER;
regresult = RegOpenKeyExA(hTopKey, regkey, 0, KEY_READ, &hKey);
}
if (regresult != ERROR_SUCCESS) {
return NULL;
}
/* find the registry key name for the joystick's properties */
regsize = sizeof(regname);
SDL_snprintf(regvalue, SDL_arraysize(regvalue), "Joystick%d%s", index + 1,
REGSTR_VAL_JOYOEMNAME);
regresult =
RegQueryValueExA(hKey, regvalue, 0, 0, (LPBYTE) regname, &regsize);
RegCloseKey(hKey);
if (regresult != ERROR_SUCCESS) {
return NULL;
}
/* open that registry key */
SDL_snprintf(regkey, SDL_arraysize(regkey),
#ifdef UNICODE
"%S\\%s",
#else
"%s\\%s",
#endif
REGSTR_PATH_JOYOEM, regname);
regresult = RegOpenKeyExA(hTopKey, regkey, 0, KEY_READ, &hKey);
if (regresult != ERROR_SUCCESS) {
return NULL;
}
/* find the size for the OEM name text */
regsize = sizeof(regvalue);
regresult =
RegQueryValueExA(hKey, REGSTR_VAL_JOYOEMNAME, 0, 0, NULL, &regsize);
if (regresult == ERROR_SUCCESS) {
/* allocate enough memory for the OEM name text ... */
name = (char *) SDL_malloc(regsize);
if (name) {
/* ... and read it from the registry */
regresult = RegQueryValueExA(hKey,
REGSTR_VAL_JOYOEMNAME, 0, 0,
(LPBYTE) name, &regsize);
}
}
RegCloseKey(hKey);
return (name);
}
static int numjoysticks = 0;
/* Function to scan the system for joysticks.
* Joystick 0 should be the system default joystick.
* It should return 0, or -1 on an unrecoverable fatal error.
*/
static int
WINMM_JoystickInit(void)
{
int i;
int maxdevs;
JOYINFOEX joyinfo;
JOYCAPSA joycaps;
MMRESULT result;
/* Reset the joystick ID & name mapping tables */
for (i = 0; i < MAX_JOYSTICKS; ++i) {
SYS_JoystickID[i] = 0;
SYS_JoystickName[i] = NULL;
}
/* Loop over all potential joystick devices */
numjoysticks = 0;
maxdevs = joyGetNumDevs();
for (i = JOYSTICKID1; i < maxdevs && numjoysticks < MAX_JOYSTICKS; ++i) {
joyinfo.dwSize = sizeof(joyinfo);
joyinfo.dwFlags = JOY_RETURNALL;
result = joyGetPosEx(i, &joyinfo);
if (result == JOYERR_NOERROR) {
result = joyGetDevCapsA(i, &joycaps, sizeof(joycaps));
if (result == JOYERR_NOERROR) {
SYS_JoystickID[numjoysticks] = i;
SYS_Joystick[numjoysticks] = joycaps;
SYS_JoystickName[numjoysticks] =
GetJoystickName(i, joycaps.szRegKey);
numjoysticks++;
}
}
}
return numjoysticks;
}
static int
WINMM_NumJoysticks(void)
{
return numjoysticks;
}
static void
WINMM_JoystickDetect(void)
{
}
/* Function to get the device-dependent name of a joystick */
static const char *
WINMM_JoystickGetDeviceName(int device_index)
{
if (SYS_JoystickName[device_index] != NULL) {
return (SYS_JoystickName[device_index]);
} else {
return (SYS_Joystick[device_index].szPname);
}
}
static int
WINMM_JoystickGetDevicePlayerIndex(int device_index)
{
return -1;
}
static void
WINMM_JoystickSetDevicePlayerIndex(int device_index, int player_index)
{
}
static SDL_JoystickGUID WINMM_JoystickGetDeviceGUID(int device_index)
{
SDL_JoystickGUID guid;
/* the GUID is just the first 16 chars of the name for now */
const char *name = WINMM_JoystickGetDeviceName(device_index);
SDL_zero(guid);
SDL_memcpy(&guid, name, SDL_min(sizeof(guid), SDL_strlen(name)));
return guid;
}
/* Function to perform the mapping from device index to the instance id for this index */
static SDL_JoystickID WINMM_JoystickGetDeviceInstanceID(int device_index)
{
return device_index;
}
/* Function to open a joystick for use.
The joystick to open is specified by the device index.
This should fill the nbuttons and naxes fields of the joystick structure.
It returns 0, or -1 if there is an error.
*/
static int
WINMM_JoystickOpen(SDL_Joystick *joystick, int device_index)
{
int index, i;
int caps_flags[MAX_AXES - 2] =
{ JOYCAPS_HASZ, JOYCAPS_HASR, JOYCAPS_HASU, JOYCAPS_HASV };
int axis_min[MAX_AXES], axis_max[MAX_AXES];
/* shortcut */
index = device_index;
axis_min[0] = SYS_Joystick[index].wXmin;
axis_max[0] = SYS_Joystick[index].wXmax;
axis_min[1] = SYS_Joystick[index].wYmin;
axis_max[1] = SYS_Joystick[index].wYmax;
axis_min[2] = SYS_Joystick[index].wZmin;
axis_max[2] = SYS_Joystick[index].wZmax;
axis_min[3] = SYS_Joystick[index].wRmin;
axis_max[3] = SYS_Joystick[index].wRmax;
axis_min[4] = SYS_Joystick[index].wUmin;
axis_max[4] = SYS_Joystick[index].wUmax;
axis_min[5] = SYS_Joystick[index].wVmin;
axis_max[5] = SYS_Joystick[index].wVmax;
/* allocate memory for system specific hardware data */
joystick->instance_id = device_index;
joystick->hwdata =
(struct joystick_hwdata *) SDL_malloc(sizeof(*joystick->hwdata));
if (joystick->hwdata == NULL) {
return SDL_OutOfMemory();
}
SDL_memset(joystick->hwdata, 0, sizeof(*joystick->hwdata));
/* set hardware data */
joystick->hwdata->id = SYS_JoystickID[index];
for (i = 0; i < MAX_AXES; ++i) {
if ((i < 2) || (SYS_Joystick[index].wCaps & caps_flags[i - 2])) {
joystick->hwdata->transaxis[i].offset = SDL_JOYSTICK_AXIS_MIN - axis_min[i];
joystick->hwdata->transaxis[i].scale =
(float) (SDL_JOYSTICK_AXIS_MAX - SDL_JOYSTICK_AXIS_MIN) / (axis_max[i] - axis_min[i]);
} else {
joystick->hwdata->transaxis[i].offset = 0;
joystick->hwdata->transaxis[i].scale = 1.0; /* Just in case */
}
}
/* fill nbuttons, naxes, and nhats fields */
joystick->nbuttons = SYS_Joystick[index].wNumButtons;
joystick->naxes = SYS_Joystick[index].wNumAxes;
if (SYS_Joystick[index].wCaps & JOYCAPS_HASPOV) {
joystick->nhats = 1;
} else {
joystick->nhats = 0;
}
return (0);
}
static Uint8
TranslatePOV(DWORD value)
{
Uint8 pos;
pos = SDL_HAT_CENTERED;
if (value != JOY_POVCENTERED) {
if ((value > JOY_POVLEFT) || (value < JOY_POVRIGHT)) {
pos |= SDL_HAT_UP;
}
if ((value > JOY_POVFORWARD) && (value < JOY_POVBACKWARD)) {
pos |= SDL_HAT_RIGHT;
}
if ((value > JOY_POVRIGHT) && (value < JOY_POVLEFT)) {
pos |= SDL_HAT_DOWN;
}
if (value > JOY_POVBACKWARD) {
pos |= SDL_HAT_LEFT;
}
}
return (pos);
}
static int
WINMM_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
{
return SDL_Unsupported();
}
static int
WINMM_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)
{
return SDL_Unsupported();
}
static SDL_bool WINMM_JoystickHasLED(SDL_Joystick *joystick)
{
return SDL_FALSE;
}
static int
WINMM_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
{
return SDL_Unsupported();
}
static int
WINMM_JoystickSendEffect(SDL_Joystick *joystick, const void *data, int size)
{
return SDL_Unsupported();
}
static int WINMM_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool enabled)
{
return SDL_Unsupported();
}
/* Function to update the state of a joystick - called as a device poll.
* This function shouldn't update the joystick structure directly,
* but instead should call SDL_PrivateJoystick*() to deliver events
* and update joystick device state.
*/
static void
WINMM_JoystickUpdate(SDL_Joystick *joystick)
{
MMRESULT result;
int i;
DWORD flags[MAX_AXES] = { JOY_RETURNX, JOY_RETURNY, JOY_RETURNZ,
JOY_RETURNR, JOY_RETURNU, JOY_RETURNV
};
DWORD pos[MAX_AXES];
struct _transaxis *transaxis;
int value;
JOYINFOEX joyinfo;
joyinfo.dwSize = sizeof(joyinfo);
joyinfo.dwFlags = JOY_RETURNALL | JOY_RETURNPOVCTS;
if (!joystick->hats) {
joyinfo.dwFlags &= ~(JOY_RETURNPOV | JOY_RETURNPOVCTS);
}
result = joyGetPosEx(joystick->hwdata->id, &joyinfo);
if (result != JOYERR_NOERROR) {
SetMMerror("joyGetPosEx", result);
return;
}
/* joystick motion events */
pos[0] = joyinfo.dwXpos;
pos[1] = joyinfo.dwYpos;
pos[2] = joyinfo.dwZpos;
pos[3] = joyinfo.dwRpos;
pos[4] = joyinfo.dwUpos;
pos[5] = joyinfo.dwVpos;
transaxis = joystick->hwdata->transaxis;
for (i = 0; i < joystick->naxes; i++) {
if (joyinfo.dwFlags & flags[i]) {
value = (int) (((float) pos[i] + transaxis[i].offset) * transaxis[i].scale);
SDL_PrivateJoystickAxis(joystick, (Uint8) i, (Sint16) value);
}
}
/* joystick button events */
if (joyinfo.dwFlags & JOY_RETURNBUTTONS) {
for (i = 0; i < joystick->nbuttons; ++i) {
if (joyinfo.dwButtons & JOY_BUTTON_FLAG(i)) {
SDL_PrivateJoystickButton(joystick, (Uint8) i, SDL_PRESSED);
} else {
SDL_PrivateJoystickButton(joystick, (Uint8) i, SDL_RELEASED);
}
}
}
/* joystick hat events */
if (joyinfo.dwFlags & JOY_RETURNPOV) {
SDL_PrivateJoystickHat(joystick, 0, TranslatePOV(joyinfo.dwPOV));
}
}
/* Function to close a joystick after use */
static void
WINMM_JoystickClose(SDL_Joystick *joystick)
{
SDL_free(joystick->hwdata);
}
/* Function to perform any system-specific joystick related cleanup */
static void
WINMM_JoystickQuit(void)
{
int i;
for (i = 0; i < MAX_JOYSTICKS; i++) {
SDL_free(SYS_JoystickName[i]);
SYS_JoystickName[i] = NULL;
}
}
static SDL_bool
WINMM_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out)
{
return SDL_FALSE;
}
/* implementation functions */
void
SetMMerror(char *function, int code)
{
static char *error;
static char errbuf[1024];
errbuf[0] = 0;
switch (code) {
case MMSYSERR_NODRIVER:
error = "Joystick driver not present";
break;
case MMSYSERR_INVALPARAM:
case JOYERR_PARMS:
error = "Invalid parameter(s)";
break;
case MMSYSERR_BADDEVICEID:
error = "Bad device ID";
break;
case JOYERR_UNPLUGGED:
error = "Joystick not attached";
break;
case JOYERR_NOCANDO:
error = "Can't capture joystick input";
break;
default:
SDL_snprintf(errbuf, SDL_arraysize(errbuf),
"%s: Unknown Multimedia system error: 0x%x",
function, code);
break;
}
if (!errbuf[0]) {
SDL_snprintf(errbuf, SDL_arraysize(errbuf), "%s: %s", function,
error);
}
SDL_SetError("%s", errbuf);
}
SDL_JoystickDriver SDL_WINMM_JoystickDriver =
{
WINMM_JoystickInit,
WINMM_NumJoysticks,
WINMM_JoystickDetect,
WINMM_JoystickGetDeviceName,
WINMM_JoystickGetDevicePlayerIndex,
WINMM_JoystickSetDevicePlayerIndex,
WINMM_JoystickGetDeviceGUID,
WINMM_JoystickGetDeviceInstanceID,
WINMM_JoystickOpen,
WINMM_JoystickRumble,
WINMM_JoystickRumbleTriggers,
WINMM_JoystickHasLED,
WINMM_JoystickSetLED,
WINMM_JoystickSendEffect,
WINMM_JoystickSetSensorsEnabled,
WINMM_JoystickUpdate,
WINMM_JoystickClose,
WINMM_JoystickQuit,
WINMM_JoystickGetGamepadMapping
};
#endif /* SDL_JOYSTICK_WINMM */
/* vi: set ts=4 sw=4 expandtab: */