21 #include "../../SDL_internal.h"
34 #include "../SDL_sysjoystick.h"
35 #include "../SDL_joystick_c.h"
38 #if !SDL_EVENTS_DISABLED
39 #include "../../events/SDL_events_c.h"
43 #import <CoreMotion/CoreMotion.h>
46 #ifdef SDL_JOYSTICK_MFI
47 #import <GameController/GameController.h>
49 static id connectObserver = nil;
50 static id disconnectObserver = nil;
69 while (
i < device_index) {
83 #ifdef SDL_JOYSTICK_MFI
84 const Uint16 VENDOR_APPLE = 0x05AC;
94 device->controller = (__bridge GCController *) CFBridgingRetain(controller);
96 if (controller.vendorName) {
97 name = controller.vendorName.UTF8String;
101 name =
"MFi Gamepad";
106 if (controller.extendedGamepad) {
107 vendor = VENDOR_APPLE;
113 }
else if (controller.gamepad) {
114 vendor = VENDOR_APPLE;
122 else if (controller.microGamepad) {
123 vendor = VENDOR_APPLE;
146 device->guid.data[14] =
'm';
147 device->guid.data[15] = subtype;
151 controller.playerIndex = -1;
164 if (controller && !controller.extendedGamepad && !controller.gamepad && controller.microGamepad) {
171 if (
device->controller == controller) {
182 device->accelerometer = accelerometer;
198 }
else if (controller) {
207 lastdevice = lastdevice->
next;
230 while (item !=
NULL) {
249 #ifdef SDL_JOYSTICK_MFI
254 GCController *controller = CFBridgingRelease((__bridge CFTypeRef)(
device->controller));
255 controller.controllerPausedHandler = nil;
273 SDL_AppleTVRemoteRotationHintChanged(
void *udata,
const char *
name,
const char *oldValue,
const char *newValue)
275 BOOL allowRotation = newValue !=
NULL && *newValue !=
'0';
278 for (GCController *controller
in [GCController
controllers]) {
279 if (controller.microGamepad) {
280 controller.microGamepad.allowsRotation = allowRotation;
291 NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
300 #ifdef SDL_JOYSTICK_MFI
302 if (![GCController
class]) {
306 for (GCController *controller
in [GCController
controllers]) {
312 SDL_AppleTVRemoteRotationHintChanged,
NULL);
315 connectObserver = [center addObserverForName:GCControllerDidConnectNotification
318 usingBlock:^(NSNotification *note) {
319 GCController *controller = note.object;
320 IOS_AddJoystickDevice(controller, SDL_FALSE);
323 disconnectObserver = [center addObserverForName:GCControllerDidDisconnectNotification
326 usingBlock:^(NSNotification *note) {
327 GCController *controller = note.object;
328 SDL_JoystickDeviceItem *device = deviceList;
329 while (device != NULL) {
330 if (device->controller == controller) {
331 IOS_RemoveJoystickDevice(device);
334 device = device->next;
392 return SDL_SetError(
"Could not open Joystick: no hardware device for the specified index");
395 joystick->hwdata =
device;
396 joystick->instance_id =
device->instance_id;
398 joystick->naxes =
device->naxes;
399 joystick->nhats =
device->nhats;
400 joystick->nbuttons =
device->nbuttons;
401 joystick->nballs = 0;
403 device->joystick = joystick;
406 if (
device->accelerometer) {
414 [motionManager startAccelerometerUpdates];
417 #ifdef SDL_JOYSTICK_MFI
418 GCController *controller =
device->controller;
419 controller.controllerPausedHandler = ^(GCController *
c) {
420 if (joystick->hwdata) {
421 ++joystick->hwdata->num_pause_presses;
439 const SInt16 maxsint16 = 0x7FFF;
440 CMAcceleration accel;
478 #ifdef SDL_JOYSTICK_MFI
480 IOS_MFIJoystickHatStateForDPad(GCControllerDirectionPad *dpad)
484 if (dpad.up.isPressed) {
486 }
else if (dpad.down.isPressed) {
490 if (dpad.left.isPressed) {
492 }
else if (dpad.right.isPressed) {
509 GCController *controller = joystick->hwdata->controller;
512 int updateplayerindex = 0;
514 if (controller.extendedGamepad) {
515 GCExtendedGamepad *gamepad = controller.extendedGamepad;
519 (
Sint16) (gamepad.leftThumbstick.xAxis.value * 32767),
520 (
Sint16) (gamepad.leftThumbstick.yAxis.value * -32767),
521 (
Sint16) ((gamepad.leftTrigger.value * 65535) - 32768),
522 (
Sint16) (gamepad.rightThumbstick.xAxis.value * 32767),
523 (
Sint16) (gamepad.rightThumbstick.yAxis.value * -32767),
524 (
Sint16) ((gamepad.rightTrigger.value * 65535) - 32768),
529 gamepad.buttonA.isPressed, gamepad.buttonB.isPressed,
530 gamepad.buttonX.isPressed, gamepad.buttonY.isPressed,
531 gamepad.leftShoulder.isPressed,
532 gamepad.rightShoulder.isPressed,
535 hatstate = IOS_MFIJoystickHatStateForDPad(gamepad.dpad);
541 if ((
i != 2 &&
i != 5) || axes[i] != -32768) {
542 updateplayerindex |= (joystick->axes[i].value != axes[i]);
548 updateplayerindex |= (joystick->buttons[i] != buttons[i]);
551 }
else if (controller.gamepad) {
552 GCGamepad *gamepad = controller.gamepad;
556 gamepad.buttonA.isPressed, gamepad.buttonB.isPressed,
557 gamepad.buttonX.isPressed, gamepad.buttonY.isPressed,
558 gamepad.leftShoulder.isPressed,
559 gamepad.rightShoulder.isPressed,
562 hatstate = IOS_MFIJoystickHatStateForDPad(gamepad.dpad);
565 updateplayerindex |= (joystick->buttons[i] != buttons[i]);
570 else if (controller.microGamepad) {
571 GCMicroGamepad *gamepad = controller.microGamepad;
574 (
Sint16) (gamepad.dpad.xAxis.value * 32767),
575 (
Sint16) (gamepad.dpad.yAxis.value * -32767),
579 updateplayerindex |= (joystick->axes[i].value != axes[i]);
584 gamepad.buttonA.isPressed,
585 gamepad.buttonX.isPressed,
589 updateplayerindex |= (joystick->buttons[i] != buttons[i]);
595 if (joystick->nhats > 0) {
596 updateplayerindex |= (joystick->hats[0] != hatstate);
600 for (
i = 0;
i < joystick->hwdata->num_pause_presses;
i++) {
601 const Uint8 pausebutton = joystick->nbuttons - 1;
604 updateplayerindex = YES;
606 joystick->hwdata->num_pause_presses = 0;
608 if (updateplayerindex && controller.playerIndex == -1) {
609 BOOL usedPlayerIndexSlots[4] = {NO, NO, NO, NO};
613 if (
c != controller &&
c.playerIndex >= 0) {
622 if (!usedPlayerIndexSlots[
i]) {
623 controller.playerIndex =
i;
647 if (
device->accelerometer) {
649 }
else if (
device->controller) {
666 if (
device->accelerometer) {
668 [motionManager stopAccelerometerUpdates];
670 }
else if (
device->controller) {
671 #ifdef SDL_JOYSTICK_MFI
672 GCController *controller =
device->controller;
673 controller.controllerPausedHandler = nil;
674 controller.playerIndex = -1;
687 #ifdef SDL_JOYSTICK_MFI
688 NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
690 if (connectObserver) {
691 [center removeObserver:connectObserver name:GCControllerDidConnectNotification object:nil];
692 connectObserver = nil;
695 if (disconnectObserver) {
696 [center removeObserver:disconnectObserver name:GCControllerDidDisconnectNotification object:nil];
697 disconnectObserver = nil;
702 SDL_AppleTVRemoteRotationHintChanged,
NULL);