SDL 2.0
SDL_sysjoystick.m File Reference
#include "../../SDL_internal.h"
#include "SDL_sysjoystick_c.h"
#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"
#include "../../events/SDL_events_c.h"
#import <CoreMotion/CoreMotion.h>
+ Include dependency graph for SDL_sysjoystick.m:

Go to the source code of this file.

Functions

static SDL_JoystickDeviceItemGetDeviceForIndex (int device_index)
 
static void IOS_AddMFIJoystickDevice (SDL_JoystickDeviceItem *device, GCController *controller)
 
static void IOS_AddJoystickDevice (GCController *controller, SDL_bool accelerometer)
 
static SDL_JoystickDeviceItemIOS_RemoveJoystickDevice (SDL_JoystickDeviceItem *device)
 
static int IOS_JoystickInit (void)
 
static int IOS_JoystickGetCount (void)
 
static void IOS_JoystickDetect (void)
 
static const char * IOS_JoystickGetDeviceName (int device_index)
 
static int IOS_JoystickGetDevicePlayerIndex (int device_index)
 
static SDL_JoystickGUID IOS_JoystickGetDeviceGUID (int device_index)
 
static SDL_JoystickID IOS_JoystickGetDeviceInstanceID (int device_index)
 
static int IOS_JoystickOpen (SDL_Joystick *joystick, int device_index)
 
static void IOS_AccelerometerUpdate (SDL_Joystick *joystick)
 
static void IOS_MFIJoystickUpdate (SDL_Joystick *joystick)
 
static int IOS_JoystickRumble (SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
 
static void IOS_JoystickUpdate (SDL_Joystick *joystick)
 
static void IOS_JoystickClose (SDL_Joystick *joystick)
 
static void IOS_JoystickQuit (void)
 

Variables

static const char * accelerometerName = "iOS Accelerometer"
 
static CMMotionManager * motionManager = nil
 
static SDL_JoystickDeviceItemdeviceList = NULL
 
static int numjoysticks = 0
 
int SDL_AppleTVRemoteOpenedAsJoystick = 0
 
SDL_JoystickDriver SDL_IOS_JoystickDriver
 

Function Documentation

◆ GetDeviceForIndex()

static SDL_JoystickDeviceItem * GetDeviceForIndex ( int  device_index)
static

Definition at line 87 of file SDL_sysjoystick.m.

88{
90 int i = 0;
91
92 while (i < device_index) {
93 if (device == NULL) {
94 return NULL;
95 }
96 device = device->next;
97 i++;
98 }
99
100 return device;
101}
static SDL_JoystickDeviceItem * deviceList
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
#define NULL
Definition: begin_code.h:167
static SDL_AudioDeviceID device
Definition: loopwave.c:37

References device, deviceList, i, and NULL.

Referenced by IOS_JoystickGetDeviceGUID(), IOS_JoystickGetDeviceInstanceID(), IOS_JoystickGetDeviceName(), IOS_JoystickGetDevicePlayerIndex(), and IOS_JoystickOpen().

◆ IOS_AccelerometerUpdate()

static void IOS_AccelerometerUpdate ( SDL_Joystick *  joystick)
static

Definition at line 540 of file SDL_sysjoystick.m.

541{
542#if !TARGET_OS_TV
543 const float maxgforce = SDL_IPHONE_MAX_GFORCE;
544 const SInt16 maxsint16 = 0x7FFF;
545 CMAcceleration accel;
546
547 @autoreleasepool {
548 if (!motionManager.isAccelerometerActive) {
549 return;
550 }
551
552 accel = motionManager.accelerometerData.acceleration;
553 }
554
555 /*
556 Convert accelerometer data from floating point to Sint16, which is what
557 the joystick system expects.
558
559 To do the conversion, the data is first clamped onto the interval
560 [-SDL_IPHONE_MAX_G_FORCE, SDL_IPHONE_MAX_G_FORCE], then the data is multiplied
561 by MAX_SINT16 so that it is mapped to the full range of an Sint16.
562
563 You can customize the clamped range of this function by modifying the
564 SDL_IPHONE_MAX_GFORCE macro in SDL_config_iphoneos.h.
565
566 Once converted to Sint16, the accelerometer data no longer has coherent
567 units. You can convert the data back to units of g-force by multiplying
568 it in your application's code by SDL_IPHONE_MAX_GFORCE / 0x7FFF.
569 */
570
571 /* clamp the data */
572 accel.x = SDL_min(SDL_max(accel.x, -maxgforce), maxgforce);
573 accel.y = SDL_min(SDL_max(accel.y, -maxgforce), maxgforce);
574 accel.z = SDL_min(SDL_max(accel.z, -maxgforce), maxgforce);
575
576 /* pass in data mapped to range of SInt16 */
577 SDL_PrivateJoystickAxis(joystick, 0, (accel.x / maxgforce) * maxsint16);
578 SDL_PrivateJoystickAxis(joystick, 1, -(accel.y / maxgforce) * maxsint16);
579 SDL_PrivateJoystickAxis(joystick, 2, (accel.z / maxgforce) * maxsint16);
580#endif /* !TARGET_OS_TV */
581}
#define SDL_IPHONE_MAX_GFORCE
int SDL_PrivateJoystickAxis(SDL_Joystick *joystick, Uint8 axis, Sint16 value)
Definition: SDL_joystick.c:833
#define SDL_min(x, y)
Definition: SDL_stdinc.h:406
#define SDL_max(x, y)
Definition: SDL_stdinc.h:407
static CMMotionManager * motionManager

References motionManager, SDL_IPHONE_MAX_GFORCE, SDL_max, SDL_min, and SDL_PrivateJoystickAxis().

Referenced by IOS_JoystickUpdate().

◆ IOS_AddJoystickDevice()

static void IOS_AddJoystickDevice ( GCController *  controller,
SDL_bool  accelerometer 
)
static

Definition at line 259 of file SDL_sysjoystick.m.

260{
262
263#if TARGET_OS_TV
265 /* Ignore devices that aren't actually controllers (e.g. remotes), they'll be handled as keyboard input */
266 if (controller && !controller.extendedGamepad && !controller.gamepad && controller.microGamepad) {
267 return;
268 }
269 }
270#endif
271
272 while (device != NULL) {
273 if (device->controller == controller) {
274 return;
275 }
276 device = device->next;
277 }
278
280 if (device == NULL) {
281 return;
282 }
283
284 device->accelerometer = accelerometer;
285 device->instance_id = SDL_GetNextJoystickInstanceID();
286
287 if (accelerometer) {
288#if TARGET_OS_TV
290 return;
291#else
293 device->naxes = 3; /* Device acceleration in the x, y, and z axes. */
294 device->nhats = 0;
295 device->nbuttons = 0;
296
297 /* Use the accelerometer name as a GUID. */
298 SDL_memcpy(&device->guid.data, device->name, SDL_min(sizeof(SDL_JoystickGUID), SDL_strlen(device->name)));
299#endif /* TARGET_OS_TV */
300 } else if (controller) {
301 IOS_AddMFIJoystickDevice(device, controller);
302 }
303
304 if (deviceList == NULL) {
306 } else {
308 while (lastdevice->next != NULL) {
309 lastdevice = lastdevice->next;
310 }
311 lastdevice->next = device;
312 }
313
314 ++numjoysticks;
315
316 SDL_PrivateJoystickAdded(device->instance_id);
317}
#define SDL_strlen
#define SDL_free
#define SDL_strdup
#define SDL_GetHintBoolean
#define SDL_memcpy
#define SDL_calloc
#define SDL_HINT_TV_REMOTE_AS_JOYSTICK
A variable controlling whether the Android / tvOS remotes should be listed as joystick devices,...
Definition: SDL_hints.h:419
void SDL_PrivateJoystickAdded(SDL_JoystickID device_instance)
Definition: SDL_joystick.c:755
SDL_JoystickID SDL_GetNextJoystickInstanceID()
Definition: SDL_joystick.c:163
@ SDL_TRUE
Definition: SDL_stdinc.h:164
static void IOS_AddMFIJoystickDevice(SDL_JoystickDeviceItem *device, GCController *controller)
static const char * accelerometerName
static int numjoysticks
struct joystick_hwdata * next

References accelerometerName, device, deviceList, IOS_AddMFIJoystickDevice(), recDevice::next, NULL, numjoysticks, SDL_calloc, SDL_free, SDL_GetHintBoolean, SDL_GetNextJoystickInstanceID(), SDL_HINT_TV_REMOTE_AS_JOYSTICK, SDL_memcpy, SDL_min, SDL_PrivateJoystickAdded(), SDL_strdup, SDL_strlen, and SDL_TRUE.

Referenced by IOS_JoystickInit().

◆ IOS_AddMFIJoystickDevice()

static void IOS_AddMFIJoystickDevice ( SDL_JoystickDeviceItem device,
GCController *  controller 
)
static

Definition at line 104 of file SDL_sysjoystick.m.

105{
106#ifdef SDL_JOYSTICK_MFI
107 const Uint16 VENDOR_APPLE = 0x05AC;
108 const Uint16 VENDOR_MICROSOFT = 0x045e;
109 const Uint16 VENDOR_SONY = 0x054C;
110 Uint16 *guid16 = (Uint16 *)device->guid.data;
111 Uint16 vendor = 0;
112 Uint16 product = 0;
113 Uint8 subtype = 0;
114
115 const char *name = NULL;
116 /* Explicitly retain the controller because SDL_JoystickDeviceItem is a
117 * struct, and ARC doesn't work with structs. */
118 device->controller = (__bridge GCController *) CFBridgingRetain(controller);
119
120 if (controller.vendorName) {
121 name = controller.vendorName.UTF8String;
122 }
123
124 if (!name) {
125 name = "MFi Gamepad";
126 }
127
128 device->name = SDL_strdup(name);
129
130 if (controller.extendedGamepad) {
131 GCExtendedGamepad *gamepad = controller.extendedGamepad;
132 int nbuttons = 0;
133
134 /* These buttons are part of the original MFi spec */
135 device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_A);
136 device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_B);
137 device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_X);
138 device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_Y);
139 device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_LEFTSHOULDER);
140 device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_RIGHTSHOULDER);
141 nbuttons += 6;
142
143 /* These buttons are available on some newer controllers */
144#pragma clang diagnostic push
145#pragma clang diagnostic ignored "-Wunguarded-availability-new"
146 if ([gamepad respondsToSelector:@selector(leftThumbstickButton)] && gamepad.leftThumbstickButton) {
147 device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_LEFTSTICK);
148 ++nbuttons;
149 }
150 if ([gamepad respondsToSelector:@selector(rightThumbstickButton)] && gamepad.rightThumbstickButton) {
151 device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_RIGHTSTICK);
152 ++nbuttons;
153 }
154 if ([gamepad respondsToSelector:@selector(buttonOptions)] && gamepad.buttonOptions) {
155 device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_BACK);
156 ++nbuttons;
157 }
158 if ([gamepad respondsToSelector:@selector(buttonMenu)] && gamepad.buttonMenu) {
159 device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_START);
160 ++nbuttons;
161 } else {
162 device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_START);
163 ++nbuttons;
164 device->uses_pause_handler = SDL_TRUE;
165 }
166#pragma clang diagnostic pop
167
168 if ([controller.vendorName containsString: @"Xbox"]) {
169 vendor = VENDOR_MICROSOFT;
170 product = 0x02E0; /* Assume Xbox One S BLE Controller unless/until GCController flows VID/PID */
171 } else if ([controller.vendorName containsString: @"DUALSHOCK"]) {
172 vendor = VENDOR_SONY;
173 product = 0x09CC; /* Assume DS4 Slim unless/until GCController flows VID/PID */
174 } else {
175 vendor = VENDOR_APPLE;
176 product = 1;
177 subtype = 1;
178 }
179
180 device->naxes = 6; /* 2 thumbsticks and 2 triggers */
181 device->nhats = 1; /* d-pad */
182 device->nbuttons = nbuttons;
183
184 } else if (controller.gamepad) {
185 int nbuttons = 0;
186
187 /* These buttons are part of the original MFi spec */
188 device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_A);
189 device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_B);
190 device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_X);
191 device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_Y);
192 device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_LEFTSHOULDER);
193 device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_RIGHTSHOULDER);
194 device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_START);
195 nbuttons += 7;
196 device->uses_pause_handler = SDL_TRUE;
197
198 vendor = VENDOR_APPLE;
199 product = 2;
200 subtype = 2;
201 device->naxes = 0; /* no traditional analog inputs */
202 device->nhats = 1; /* d-pad */
203 device->nbuttons = nbuttons;
204 }
205#if TARGET_OS_TV
206 else if (controller.microGamepad) {
207 GCMicroGamepad *gamepad = controller.microGamepad;
208 int nbuttons = 0;
209
210 device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_A);
211 device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_B); /* Button X on microGamepad */
212 nbuttons += 2;
213
214 if ([gamepad respondsToSelector:@selector(buttonMenu)] && gamepad.buttonMenu) {
215 device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_START);
216 ++nbuttons;
217 } else {
218 device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_START);
219 ++nbuttons;
220 device->uses_pause_handler = SDL_TRUE;
221 }
222
223 vendor = VENDOR_APPLE;
224 product = 3;
225 subtype = 3;
226 device->naxes = 2; /* treat the touch surface as two axes */
227 device->nhats = 0; /* apparently the touch surface-as-dpad is buggy */
228 device->nbuttons = nbuttons;
229
230 controller.microGamepad.allowsRotation = SDL_GetHintBoolean(SDL_HINT_APPLE_TV_REMOTE_ALLOW_ROTATION, SDL_FALSE);
231 }
232#endif /* TARGET_OS_TV */
233
234 /* We only need 16 bits for each of these; space them out to fill 128. */
235 /* Byteswap so devices get same GUID on little/big endian platforms. */
237 *guid16++ = 0;
238 *guid16++ = SDL_SwapLE16(vendor);
239 *guid16++ = 0;
240 *guid16++ = SDL_SwapLE16(product);
241 *guid16++ = 0;
242
243 *guid16++ = SDL_SwapLE16(device->button_mask);
244
245 if (subtype != 0) {
246 /* Note that this is an MFI controller and what subtype it is */
247 device->guid.data[14] = 'm';
248 device->guid.data[15] = subtype;
249 }
250
251 /* This will be set when the first button press of the controller is
252 * detected. */
253 controller.playerIndex = -1;
254
255#endif /* SDL_JOYSTICK_MFI */
256}
#define SDL_SwapLE16(X)
Definition: SDL_endian.h:232
@ SDL_CONTROLLER_BUTTON_B
@ SDL_CONTROLLER_BUTTON_BACK
@ SDL_CONTROLLER_BUTTON_LEFTSTICK
@ SDL_CONTROLLER_BUTTON_START
@ SDL_CONTROLLER_BUTTON_RIGHTSHOULDER
@ SDL_CONTROLLER_BUTTON_LEFTSHOULDER
@ SDL_CONTROLLER_BUTTON_X
@ SDL_CONTROLLER_BUTTON_RIGHTSTICK
@ SDL_CONTROLLER_BUTTON_Y
@ SDL_CONTROLLER_BUTTON_A
#define SDL_HINT_APPLE_TV_REMOTE_ALLOW_ROTATION
A variable controlling whether the Apple TV remote's joystick axes will automatically match the rotat...
Definition: SDL_hints.h:388
GLuint const GLchar * name
@ SDL_FALSE
Definition: SDL_stdinc.h:163
uint16_t Uint16
Definition: SDL_stdinc.h:191
uint8_t Uint8
Definition: SDL_stdinc.h:179
#define SDL_HARDWARE_BUS_BLUETOOTH

References device, NULL, SDL_CONTROLLER_BUTTON_A, SDL_CONTROLLER_BUTTON_B, SDL_CONTROLLER_BUTTON_BACK, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, SDL_CONTROLLER_BUTTON_LEFTSTICK, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, SDL_CONTROLLER_BUTTON_RIGHTSTICK, SDL_CONTROLLER_BUTTON_START, SDL_CONTROLLER_BUTTON_X, SDL_CONTROLLER_BUTTON_Y, SDL_FALSE, SDL_GetHintBoolean, SDL_HARDWARE_BUS_BLUETOOTH, SDL_HINT_APPLE_TV_REMOTE_ALLOW_ROTATION, SDL_strdup, SDL_SwapLE16, and SDL_TRUE.

Referenced by IOS_AddJoystickDevice().

◆ IOS_JoystickClose()

static void IOS_JoystickClose ( SDL_Joystick *  joystick)
static

Definition at line 805 of file SDL_sysjoystick.m.

806{
807 SDL_JoystickDeviceItem *device = joystick->hwdata;
808
809 if (device == NULL) {
810 return;
811 }
812
813 device->joystick = NULL;
814
815 @autoreleasepool {
816 if (device->accelerometer) {
817#if !TARGET_OS_TV
818 [motionManager stopAccelerometerUpdates];
819#endif /* !TARGET_OS_TV */
820 } else if (device->controller) {
821#ifdef SDL_JOYSTICK_MFI
822 GCController *controller = device->controller;
823 controller.controllerPausedHandler = nil;
824 controller.playerIndex = -1;
825#endif
826 }
827 }
828 if (device->remote) {
830 }
831}
int SDL_AppleTVRemoteOpenedAsJoystick

References device, NULL, and SDL_AppleTVRemoteOpenedAsJoystick.

◆ IOS_JoystickDetect()

static void IOS_JoystickDetect ( void  )
static

Definition at line 452 of file SDL_sysjoystick.m.

453{
454}

◆ IOS_JoystickGetCount()

static int IOS_JoystickGetCount ( void  )
static

Definition at line 446 of file SDL_sysjoystick.m.

447{
448 return numjoysticks;
449}

References numjoysticks.

◆ IOS_JoystickGetDeviceGUID()

static SDL_JoystickGUID IOS_JoystickGetDeviceGUID ( int  device_index)
static

Definition at line 471 of file SDL_sysjoystick.m.

472{
474 SDL_JoystickGUID guid;
475 if (device) {
476 guid = device->guid;
477 } else {
478 SDL_zero(guid);
479 }
480 return guid;
481}
#define SDL_zero(x)
Definition: SDL_stdinc.h:416
static SDL_JoystickDeviceItem * GetDeviceForIndex(int device_index)

References device, GetDeviceForIndex(), and SDL_zero.

◆ IOS_JoystickGetDeviceInstanceID()

static SDL_JoystickID IOS_JoystickGetDeviceInstanceID ( int  device_index)
static

Definition at line 484 of file SDL_sysjoystick.m.

485{
487 return device ? device->instance_id : -1;
488}

References device, and GetDeviceForIndex().

◆ IOS_JoystickGetDeviceName()

static const char * IOS_JoystickGetDeviceName ( int  device_index)
static

Definition at line 457 of file SDL_sysjoystick.m.

458{
460 return device ? device->name : "Unknown";
461}

References device, and GetDeviceForIndex().

◆ IOS_JoystickGetDevicePlayerIndex()

static int IOS_JoystickGetDevicePlayerIndex ( int  device_index)
static

Definition at line 464 of file SDL_sysjoystick.m.

465{
467 return device ? (int)device->controller.playerIndex : -1;
468}

References device, and GetDeviceForIndex().

◆ IOS_JoystickInit()

static int IOS_JoystickInit ( void  )
static

Definition at line 390 of file SDL_sysjoystick.m.

391{
392 @autoreleasepool {
393 NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
394
395#if !TARGET_OS_TV
397 /* Default behavior, accelerometer as joystick */
399 }
400#endif /* !TARGET_OS_TV */
401
402#ifdef SDL_JOYSTICK_MFI
403 /* GameController.framework was added in iOS 7. */
404 if (![GCController class]) {
405 return 0;
406 }
407
408 for (GCController *controller in [GCController controllers]) {
409 IOS_AddJoystickDevice(controller, SDL_FALSE);
410 }
411
412#if TARGET_OS_TV
414 SDL_AppleTVRemoteRotationHintChanged, NULL);
415#endif /* TARGET_OS_TV */
416
417 connectObserver = [center addObserverForName:GCControllerDidConnectNotification
418 object:nil
419 queue:nil
420 usingBlock:^(NSNotification *note) {
421 GCController *controller = note.object;
422 IOS_AddJoystickDevice(controller, SDL_FALSE);
423 }];
424
425 disconnectObserver = [center addObserverForName:GCControllerDidDisconnectNotification
426 object:nil
427 queue:nil
428 usingBlock:^(NSNotification *note) {
429 GCController *controller = note.object;
430 SDL_JoystickDeviceItem *device = deviceList;
431 while (device != NULL) {
432 if (device->controller == controller) {
433 IOS_RemoveJoystickDevice(device);
434 break;
435 }
436 device = device->next;
437 }
438 }];
439#endif /* SDL_JOYSTICK_MFI */
440 }
441
442 return 0;
443}
#define SDL_AddHintCallback
#define SDL_HINT_ACCELEROMETER_AS_JOYSTICK
A variable controlling whether the Android / iOS built-in accelerometer should be listed as a joystic...
Definition: SDL_hints.h:409
GLuint in
static void IOS_AddJoystickDevice(GCController *controller, SDL_bool accelerometer)

References sort_controllers::controllers, IOS_AddJoystickDevice(), NULL, SDL_AddHintCallback, SDL_FALSE, SDL_GetHintBoolean, SDL_HINT_ACCELEROMETER_AS_JOYSTICK, SDL_HINT_APPLE_TV_REMOTE_ALLOW_ROTATION, and SDL_TRUE.

◆ IOS_JoystickOpen()

static int IOS_JoystickOpen ( SDL_Joystick *  joystick,
int  device_index 
)
static

Definition at line 491 of file SDL_sysjoystick.m.

492{
494 if (device == NULL) {
495 return SDL_SetError("Could not open Joystick: no hardware device for the specified index");
496 }
497
498 joystick->hwdata = device;
499 joystick->instance_id = device->instance_id;
500
501 joystick->naxes = device->naxes;
502 joystick->nhats = device->nhats;
503 joystick->nbuttons = device->nbuttons;
504 joystick->nballs = 0;
505
506 device->joystick = joystick;
507
508 @autoreleasepool {
509 if (device->accelerometer) {
510#if !TARGET_OS_TV
511 if (motionManager == nil) {
512 motionManager = [[CMMotionManager alloc] init];
513 }
514
515 /* Shorter times between updates can significantly increase CPU usage. */
516 motionManager.accelerometerUpdateInterval = 0.1;
517 [motionManager startAccelerometerUpdates];
518#endif /* !TARGET_OS_TV */
519 } else {
520#ifdef SDL_JOYSTICK_MFI
521 if (device->uses_pause_handler) {
522 GCController *controller = device->controller;
523 controller.controllerPausedHandler = ^(GCController *c) {
524 if (joystick->hwdata) {
525 ++joystick->hwdata->num_pause_presses;
526 }
527 };
528 }
529#endif /* SDL_JOYSTICK_MFI */
530 }
531 }
532 if (device->remote) {
534 }
535
536 return 0;
537}
#define SDL_SetError
const GLubyte * c

References device, GetDeviceForIndex(), motionManager, NULL, SDL_AppleTVRemoteOpenedAsJoystick, and SDL_SetError.

◆ IOS_JoystickQuit()

static void IOS_JoystickQuit ( void  )
static

Definition at line 834 of file SDL_sysjoystick.m.

835{
836 @autoreleasepool {
837#ifdef SDL_JOYSTICK_MFI
838 NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
839
840 if (connectObserver) {
841 [center removeObserver:connectObserver name:GCControllerDidConnectNotification object:nil];
842 connectObserver = nil;
843 }
844
845 if (disconnectObserver) {
846 [center removeObserver:disconnectObserver name:GCControllerDidDisconnectNotification object:nil];
847 disconnectObserver = nil;
848 }
849
850#if TARGET_OS_TV
852 SDL_AppleTVRemoteRotationHintChanged, NULL);
853#endif /* TARGET_OS_TV */
854#endif /* SDL_JOYSTICK_MFI */
855
856 while (deviceList != NULL) {
858 }
859
860#if !TARGET_OS_TV
861 motionManager = nil;
862#endif /* !TARGET_OS_TV */
863 }
864
865 numjoysticks = 0;
866}
#define SDL_DelHintCallback
static SDL_JoystickDeviceItem * IOS_RemoveJoystickDevice(SDL_JoystickDeviceItem *device)

References deviceList, IOS_RemoveJoystickDevice(), motionManager, NULL, numjoysticks, SDL_DelHintCallback, and SDL_HINT_APPLE_TV_REMOTE_ALLOW_ROTATION.

◆ IOS_JoystickRumble()

static int IOS_JoystickRumble ( SDL_Joystick *  joystick,
Uint16  low_frequency_rumble,
Uint16  high_frequency_rumble,
Uint32  duration_ms 
)
static

Definition at line 783 of file SDL_sysjoystick.m.

784{
785 return SDL_Unsupported();
786}
#define SDL_Unsupported()
Definition: SDL_error.h:53

References SDL_Unsupported.

◆ IOS_JoystickUpdate()

static void IOS_JoystickUpdate ( SDL_Joystick *  joystick)
static

Definition at line 789 of file SDL_sysjoystick.m.

790{
791 SDL_JoystickDeviceItem *device = joystick->hwdata;
792
793 if (device == NULL) {
794 return;
795 }
796
797 if (device->accelerometer) {
798 IOS_AccelerometerUpdate(joystick);
799 } else if (device->controller) {
800 IOS_MFIJoystickUpdate(joystick);
801 }
802}
static void IOS_AccelerometerUpdate(SDL_Joystick *joystick)
static void IOS_MFIJoystickUpdate(SDL_Joystick *joystick)

References device, IOS_AccelerometerUpdate(), IOS_MFIJoystickUpdate(), and NULL.

◆ IOS_MFIJoystickUpdate()

static void IOS_MFIJoystickUpdate ( SDL_Joystick *  joystick)
static

Definition at line 610 of file SDL_sysjoystick.m.

611{
612#if SDL_JOYSTICK_MFI
613 @autoreleasepool {
614 GCController *controller = joystick->hwdata->controller;
615 Uint8 hatstate = SDL_HAT_CENTERED;
616 int i;
617 int updateplayerindex = 0;
618 int pause_button_index = 0;
619
620 if (controller.extendedGamepad) {
621 GCExtendedGamepad *gamepad = controller.extendedGamepad;
622
623 /* Axis order matches the XInput Windows mappings. */
624 Sint16 axes[] = {
625 (Sint16) (gamepad.leftThumbstick.xAxis.value * 32767),
626 (Sint16) (gamepad.leftThumbstick.yAxis.value * -32767),
627 (Sint16) ((gamepad.leftTrigger.value * 65535) - 32768),
628 (Sint16) (gamepad.rightThumbstick.xAxis.value * 32767),
629 (Sint16) (gamepad.rightThumbstick.yAxis.value * -32767),
630 (Sint16) ((gamepad.rightTrigger.value * 65535) - 32768),
631 };
632
633 /* Button order matches the XInput Windows mappings. */
634 Uint8 buttons[joystick->nbuttons];
635 int button_count = 0;
636
637 /* These buttons are part of the original MFi spec */
638 buttons[button_count++] = gamepad.buttonA.isPressed;
639 buttons[button_count++] = gamepad.buttonB.isPressed;
640 buttons[button_count++] = gamepad.buttonX.isPressed;
641 buttons[button_count++] = gamepad.buttonY.isPressed;
642 buttons[button_count++] = gamepad.leftShoulder.isPressed;
643 buttons[button_count++] = gamepad.rightShoulder.isPressed;
644
645 /* These buttons are available on some newer controllers */
646#pragma clang diagnostic push
647#pragma clang diagnostic ignored "-Wunguarded-availability-new"
648 if (joystick->hwdata->button_mask & (1 << SDL_CONTROLLER_BUTTON_LEFTSTICK)) {
649 buttons[button_count++] = gamepad.leftThumbstickButton.isPressed;
650 }
651 if (joystick->hwdata->button_mask & (1 << SDL_CONTROLLER_BUTTON_RIGHTSTICK)) {
652 buttons[button_count++] = gamepad.rightThumbstickButton.isPressed;
653 }
654 if (joystick->hwdata->button_mask & (1 << SDL_CONTROLLER_BUTTON_BACK)) {
655 buttons[button_count++] = gamepad.buttonOptions.isPressed;
656 }
657 /* This must be the last button, so we can optionally handle it with pause_button_index below */
658 if (joystick->hwdata->button_mask & (1 << SDL_CONTROLLER_BUTTON_START)) {
659 if (joystick->hwdata->uses_pause_handler) {
660 pause_button_index = button_count;
661 buttons[button_count++] = joystick->delayed_guide_button;
662 } else {
663 buttons[button_count++] = gamepad.buttonMenu.isPressed;
664 }
665 }
666#pragma clang diagnostic pop
667
668 hatstate = IOS_MFIJoystickHatStateForDPad(gamepad.dpad);
669
670 for (i = 0; i < SDL_arraysize(axes); i++) {
671 /* The triggers (axes 2 and 5) are resting at -32768 but SDL
672 * initializes its values to 0. We only want to make sure the
673 * player index is up to date if the user actually moves an axis. */
674 if ((i != 2 && i != 5) || axes[i] != -32768) {
675 updateplayerindex |= (joystick->axes[i].value != axes[i]);
676 }
677 SDL_PrivateJoystickAxis(joystick, i, axes[i]);
678 }
679
680 for (i = 0; i < button_count; i++) {
681 updateplayerindex |= (joystick->buttons[i] != buttons[i]);
682 SDL_PrivateJoystickButton(joystick, i, buttons[i]);
683 }
684 } else if (controller.gamepad) {
685 GCGamepad *gamepad = controller.gamepad;
686
687 /* Button order matches the XInput Windows mappings. */
688 Uint8 buttons[joystick->nbuttons];
689 int button_count = 0;
690 buttons[button_count++] = gamepad.buttonA.isPressed;
691 buttons[button_count++] = gamepad.buttonB.isPressed;
692 buttons[button_count++] = gamepad.buttonX.isPressed;
693 buttons[button_count++] = gamepad.buttonY.isPressed;
694 buttons[button_count++] = gamepad.leftShoulder.isPressed;
695 buttons[button_count++] = gamepad.rightShoulder.isPressed;
696 pause_button_index = button_count;
697 buttons[button_count++] = joystick->delayed_guide_button;
698
699 hatstate = IOS_MFIJoystickHatStateForDPad(gamepad.dpad);
700
701 for (i = 0; i < button_count; i++) {
702 updateplayerindex |= (joystick->buttons[i] != buttons[i]);
703 SDL_PrivateJoystickButton(joystick, i, buttons[i]);
704 }
705 }
706#if TARGET_OS_TV
707 else if (controller.microGamepad) {
708 GCMicroGamepad *gamepad = controller.microGamepad;
709
710 Sint16 axes[] = {
711 (Sint16) (gamepad.dpad.xAxis.value * 32767),
712 (Sint16) (gamepad.dpad.yAxis.value * -32767),
713 };
714
715 for (i = 0; i < SDL_arraysize(axes); i++) {
716 updateplayerindex |= (joystick->axes[i].value != axes[i]);
717 SDL_PrivateJoystickAxis(joystick, i, axes[i]);
718 }
719
720 Uint8 buttons[joystick->nbuttons];
721 int button_count = 0;
722 buttons[button_count++] = gamepad.buttonA.isPressed;
723 buttons[button_count++] = gamepad.buttonX.isPressed;
724#pragma clang diagnostic push
725#pragma clang diagnostic ignored "-Wunguarded-availability-new"
726 /* This must be the last button, so we can optionally handle it with pause_button_index below */
727 if (joystick->hwdata->button_mask & (1 << SDL_CONTROLLER_BUTTON_START)) {
728 if (joystick->hwdata->uses_pause_handler) {
729 pause_button_index = button_count;
730 buttons[button_count++] = joystick->delayed_guide_button;
731 } else {
732 buttons[button_count++] = gamepad.buttonMenu.isPressed;
733 }
734 }
735#pragma clang diagnostic pop
736
737 for (i = 0; i < button_count; i++) {
738 updateplayerindex |= (joystick->buttons[i] != buttons[i]);
739 SDL_PrivateJoystickButton(joystick, i, buttons[i]);
740 }
741 }
742#endif /* TARGET_OS_TV */
743
744 if (joystick->nhats > 0) {
745 updateplayerindex |= (joystick->hats[0] != hatstate);
746 SDL_PrivateJoystickHat(joystick, 0, hatstate);
747 }
748
749 if (joystick->hwdata->uses_pause_handler) {
750 for (i = 0; i < joystick->hwdata->num_pause_presses; i++) {
751 SDL_PrivateJoystickButton(joystick, pause_button_index, SDL_PRESSED);
752 SDL_PrivateJoystickButton(joystick, pause_button_index, SDL_RELEASED);
753 updateplayerindex = YES;
754 }
755 joystick->hwdata->num_pause_presses = 0;
756 }
757
758 if (updateplayerindex && controller.playerIndex == -1) {
759 BOOL usedPlayerIndexSlots[4] = {NO, NO, NO, NO};
760
761 /* Find the player index of all other connected controllers. */
762 for (GCController *c in [GCController controllers]) {
763 if (c != controller && c.playerIndex >= 0) {
764 usedPlayerIndexSlots[c.playerIndex] = YES;
765 }
766 }
767
768 /* Set this controller's player index to the first unused index.
769 * FIXME: This logic isn't great... but SDL doesn't expose this
770 * concept in its external API, so we don't have much to go on. */
771 for (i = 0; i < SDL_arraysize(usedPlayerIndexSlots); i++) {
772 if (!usedPlayerIndexSlots[i]) {
773 controller.playerIndex = i;
774 break;
775 }
776 }
777 }
778 }
779#endif /* SDL_JOYSTICK_MFI */
780}
#define SDL_RELEASED
Definition: SDL_events.h:49
#define SDL_PRESSED
Definition: SDL_events.h:50
int SDL_PrivateJoystickHat(SDL_Joystick *joystick, Uint8 hat, Uint8 value)
Definition: SDL_joystick.c:890
int SDL_PrivateJoystickButton(SDL_Joystick *joystick, Uint8 button, Uint8 state)
Definition: SDL_joystick.c:966
#define SDL_HAT_CENTERED
Definition: SDL_joystick.h:329
GLsizei const GLfloat * value
#define SDL_arraysize(array)
Definition: SDL_stdinc.h:115
int16_t Sint16
Definition: SDL_stdinc.h:185

References sort_controllers::controllers, i, SDL_arraysize, SDL_CONTROLLER_BUTTON_BACK, SDL_CONTROLLER_BUTTON_LEFTSTICK, SDL_CONTROLLER_BUTTON_RIGHTSTICK, SDL_CONTROLLER_BUTTON_START, SDL_HAT_CENTERED, SDL_PRESSED, SDL_PrivateJoystickAxis(), SDL_PrivateJoystickButton(), SDL_PrivateJoystickHat(), and SDL_RELEASED.

Referenced by IOS_JoystickUpdate().

◆ IOS_RemoveJoystickDevice()

static SDL_JoystickDeviceItem * IOS_RemoveJoystickDevice ( SDL_JoystickDeviceItem device)
static

Definition at line 320 of file SDL_sysjoystick.m.

321{
325
326 if (device == NULL) {
327 return NULL;
328 }
329
330 next = device->next;
331
332 while (item != NULL) {
333 if (item == device) {
334 break;
335 }
336 prev = item;
337 item = item->next;
338 }
339
340 /* Unlink the device item from the device list. */
341 if (prev) {
342 prev->next = device->next;
343 } else if (device == deviceList) {
344 deviceList = device->next;
345 }
346
347 if (device->joystick) {
348 device->joystick->hwdata = NULL;
349 }
350
351#ifdef SDL_JOYSTICK_MFI
352 @autoreleasepool {
353 if (device->controller) {
354 /* The controller was explicitly retained in the struct, so it
355 * should be explicitly released before freeing the struct. */
356 GCController *controller = CFBridgingRelease((__bridge CFTypeRef)(device->controller));
357 controller.controllerPausedHandler = nil;
358 device->controller = nil;
359 }
360 }
361#endif /* SDL_JOYSTICK_MFI */
362
363 --numjoysticks;
364
366
367 SDL_free(device->name);
369
370 return next;
371}
void SDL_PrivateJoystickRemoved(SDL_JoystickID device_instance)
Definition: SDL_joystick.c:805

References device, deviceList, recDevice::next, NULL, numjoysticks, SDL_free, and SDL_PrivateJoystickRemoved().

Referenced by IOS_JoystickQuit().

Variable Documentation

◆ accelerometerName

const char* accelerometerName = "iOS Accelerometer"
static

Definition at line 77 of file SDL_sysjoystick.m.

Referenced by IOS_AddJoystickDevice().

◆ deviceList

◆ motionManager

CMMotionManager* motionManager = nil
static

Definition at line 78 of file SDL_sysjoystick.m.

Referenced by IOS_AccelerometerUpdate(), IOS_JoystickOpen(), and IOS_JoystickQuit().

◆ numjoysticks

int numjoysticks = 0
static

◆ SDL_AppleTVRemoteOpenedAsJoystick

int SDL_AppleTVRemoteOpenedAsJoystick = 0

Definition at line 84 of file SDL_sysjoystick.m.

Referenced by IOS_JoystickClose(), and IOS_JoystickOpen().

◆ SDL_IOS_JoystickDriver

SDL_JoystickDriver SDL_IOS_JoystickDriver
Initial value:
=
{
}
static int IOS_JoystickGetDevicePlayerIndex(int device_index)
static void IOS_JoystickDetect(void)
static void IOS_JoystickClose(SDL_Joystick *joystick)
static SDL_JoystickGUID IOS_JoystickGetDeviceGUID(int device_index)
static void IOS_JoystickUpdate(SDL_Joystick *joystick)
static int IOS_JoystickOpen(SDL_Joystick *joystick, int device_index)
static const char * IOS_JoystickGetDeviceName(int device_index)
static int IOS_JoystickGetCount(void)
static void IOS_JoystickQuit(void)
static int IOS_JoystickInit(void)
static int IOS_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
static SDL_JoystickID IOS_JoystickGetDeviceInstanceID(int device_index)

Definition at line 868 of file SDL_sysjoystick.m.