iOS: Set the player index of MFi gamepads when the user first presses a button, rather than when it's programatically opened.
authorAlex Szpakowski
Fri, 11 Dec 2015 16:41:59 -0400
changeset 9960a20484c998da
parent 9959 182bfe0e7a60
child 9961 a66dd6fd112c
iOS: Set the player index of MFi gamepads when the user first presses a button, rather than when it's programatically opened.
src/joystick/iphoneos/SDL_sysjoystick.m
     1.1 --- a/src/joystick/iphoneos/SDL_sysjoystick.m	Thu Dec 10 22:17:22 2015 -0400
     1.2 +++ b/src/joystick/iphoneos/SDL_sysjoystick.m	Fri Dec 11 16:41:59 2015 -0400
     1.3 @@ -116,6 +116,10 @@
     1.4          device->nbuttons = 7; /* ABXY, shoulder buttons, pause button */
     1.5      }
     1.6      /* TODO: Handle micro profiles on tvOS. */
     1.7 +
     1.8 +    /* This will be set when the first button press of the controller is
     1.9 +     * detected. */
    1.10 +    controller.playerIndex = -1;
    1.11  #endif
    1.12  }
    1.13  
    1.14 @@ -361,26 +365,7 @@
    1.15          } else {
    1.16  #ifdef SDL_JOYSTICK_MFI
    1.17              GCController *controller = device->controller;
    1.18 -            BOOL usedPlayerIndexSlots[4] = {NO, NO, NO, NO};
    1.19 -
    1.20 -            /* Find the player index of all other connected controllers. */
    1.21 -            for (GCController *c in [GCController controllers]) {
    1.22 -                if (c != controller && c.playerIndex >= 0) {
    1.23 -                    usedPlayerIndexSlots[c.playerIndex] = YES;
    1.24 -                }
    1.25 -            }
    1.26 -
    1.27 -            /* Set this controller's player index to the first unused index.
    1.28 -             * FIXME: This logic isn't great... but SDL doesn't expose this
    1.29 -             * concept in its external API, so we don't have much to go on. */
    1.30 -            for (int i = 0; i < 4; i++) {
    1.31 -                if (!usedPlayerIndexSlots[i]) {
    1.32 -                    controller.playerIndex = i;
    1.33 -                    break;
    1.34 -                }
    1.35 -            }
    1.36 -
    1.37 -            controller.controllerPausedHandler = ^(GCController *controller) {
    1.38 +            controller.controllerPausedHandler = ^(GCController *c) {
    1.39                  if (joystick->hwdata) {
    1.40                      ++joystick->hwdata->num_pause_presses;
    1.41                  }
    1.42 @@ -475,53 +460,102 @@
    1.43          GCController *controller = joystick->hwdata->controller;
    1.44          Uint8 hatstate = SDL_HAT_CENTERED;
    1.45          int i;
    1.46 +        int updateplayerindex = 0;
    1.47  
    1.48          if (controller.extendedGamepad) {
    1.49              GCExtendedGamepad *gamepad = controller.extendedGamepad;
    1.50  
    1.51              /* Axis order matches the XInput Windows mappings. */
    1.52 -            SDL_PrivateJoystickAxis(joystick, 0, (Sint16) (gamepad.leftThumbstick.xAxis.value * 32767));
    1.53 -            SDL_PrivateJoystickAxis(joystick, 1, (Sint16) (gamepad.leftThumbstick.yAxis.value * -32767));
    1.54 -            SDL_PrivateJoystickAxis(joystick, 2, (Sint16) ((gamepad.leftTrigger.value * 65535) - 32768));
    1.55 -            SDL_PrivateJoystickAxis(joystick, 3, (Sint16) (gamepad.rightThumbstick.xAxis.value * 32767));
    1.56 -            SDL_PrivateJoystickAxis(joystick, 4, (Sint16) (gamepad.rightThumbstick.yAxis.value * -32767));
    1.57 -            SDL_PrivateJoystickAxis(joystick, 5, (Sint16) ((gamepad.rightTrigger.value * 65535) - 32768));
    1.58 +            Sint16 axes[] = {
    1.59 +                (Sint16) (gamepad.leftThumbstick.xAxis.value * 32767),
    1.60 +                (Sint16) (gamepad.leftThumbstick.yAxis.value * -32767),
    1.61 +                (Sint16) ((gamepad.leftTrigger.value * 65535) - 32768),
    1.62 +                (Sint16) (gamepad.rightThumbstick.xAxis.value * 32767),
    1.63 +                (Sint16) (gamepad.rightThumbstick.yAxis.value * -32767),
    1.64 +                (Sint16) ((gamepad.rightTrigger.value * 65535) - 32768),
    1.65 +            };
    1.66 +
    1.67 +            /* Button order matches the XInput Windows mappings. */
    1.68 +            Uint8 buttons[] = {
    1.69 +                gamepad.buttonA.isPressed, gamepad.buttonB.isPressed,
    1.70 +                gamepad.buttonX.isPressed, gamepad.buttonY.isPressed,
    1.71 +                gamepad.leftShoulder.isPressed,
    1.72 +                gamepad.rightShoulder.isPressed,
    1.73 +            };
    1.74  
    1.75              hatstate = SDL_SYS_MFIJoystickHatStateForDPad(gamepad.dpad);
    1.76  
    1.77 -            /* Button order matches the XInput Windows mappings. */
    1.78 -            SDL_PrivateJoystickButton(joystick, 0, gamepad.buttonA.isPressed);
    1.79 -            SDL_PrivateJoystickButton(joystick, 1, gamepad.buttonB.isPressed);
    1.80 -            SDL_PrivateJoystickButton(joystick, 2, gamepad.buttonX.isPressed);
    1.81 -            SDL_PrivateJoystickButton(joystick, 3, gamepad.buttonY.isPressed);
    1.82 -            SDL_PrivateJoystickButton(joystick, 4, gamepad.leftShoulder.isPressed);
    1.83 -            SDL_PrivateJoystickButton(joystick, 5, gamepad.rightShoulder.isPressed);
    1.84 +            for (i = 0; i < SDL_arraysize(axes); i++) {
    1.85 +                /* The triggers (axes 2 and 5) are resting at -32768 but SDL
    1.86 +                 * initializes its values to 0. We only want to make sure the
    1.87 +                 * player index is up to date if the user actually moves an axis. */
    1.88 +                if ((i != 2 && i != 5) || axes[i] != -32768) {
    1.89 +                    updateplayerindex |= (joystick->axes[i] != axes[i]);
    1.90 +                }
    1.91 +                SDL_PrivateJoystickAxis(joystick, i, axes[i]);
    1.92 +            }
    1.93 +
    1.94 +            for (i = 0; i < SDL_arraysize(buttons); i++) {
    1.95 +                updateplayerindex |= (joystick->buttons[i] != buttons[i]);
    1.96 +                SDL_PrivateJoystickButton(joystick, i, buttons[i]);
    1.97 +            }
    1.98          } else if (controller.gamepad) {
    1.99              GCGamepad *gamepad = controller.gamepad;
   1.100  
   1.101 +            /* Button order matches the XInput Windows mappings. */
   1.102 +            Uint8 buttons[] = {
   1.103 +                gamepad.buttonA.isPressed, gamepad.buttonB.isPressed,
   1.104 +                gamepad.buttonX.isPressed, gamepad.buttonY.isPressed,
   1.105 +                gamepad.leftShoulder.isPressed,
   1.106 +                gamepad.rightShoulder.isPressed,
   1.107 +            };
   1.108 +
   1.109              hatstate = SDL_SYS_MFIJoystickHatStateForDPad(gamepad.dpad);
   1.110  
   1.111 -            /* Button order matches the XInput Windows mappings. */
   1.112 -            SDL_PrivateJoystickButton(joystick, 0, gamepad.buttonA.isPressed);
   1.113 -            SDL_PrivateJoystickButton(joystick, 1, gamepad.buttonB.isPressed);
   1.114 -            SDL_PrivateJoystickButton(joystick, 2, gamepad.buttonX.isPressed);
   1.115 -            SDL_PrivateJoystickButton(joystick, 3, gamepad.buttonY.isPressed);
   1.116 -            SDL_PrivateJoystickButton(joystick, 4, gamepad.leftShoulder.isPressed);
   1.117 -            SDL_PrivateJoystickButton(joystick, 5, gamepad.rightShoulder.isPressed);
   1.118 +            for (i = 0; i < SDL_arraysize(buttons); i++) {
   1.119 +                updateplayerindex |= (joystick->buttons[i] != buttons[i]);
   1.120 +                SDL_PrivateJoystickButton(joystick, i, buttons[i]);
   1.121 +            }
   1.122          }
   1.123          /* TODO: Handle micro profiles on tvOS. */
   1.124  
   1.125 -        SDL_PrivateJoystickHat(joystick, 0, hatstate);
   1.126 +        if (joystick->nhats > 0) {
   1.127 +            updateplayerindex |= (joystick->hats[0] != hatstate);
   1.128 +            SDL_PrivateJoystickHat(joystick, 0, hatstate);
   1.129 +        }
   1.130  
   1.131          for (i = 0; i < joystick->hwdata->num_pause_presses; i++) {
   1.132              /* The pause button is always last. */
   1.133              Uint8 pausebutton = joystick->nbuttons - 1;
   1.134  
   1.135 -            SDL_PrivateJoystickButton(joystick, pausebutton, 1);
   1.136 -            SDL_PrivateJoystickButton(joystick, pausebutton, 0);
   1.137 +            SDL_PrivateJoystickButton(joystick, pausebutton, SDL_PRESSED);
   1.138 +            SDL_PrivateJoystickButton(joystick, pausebutton, SDL_RELEASED);
   1.139 +
   1.140 +            updateplayerindex = YES;
   1.141          }
   1.142  
   1.143          joystick->hwdata->num_pause_presses = 0;
   1.144 +
   1.145 +        if (updateplayerindex && controller.playerIndex == -1) {
   1.146 +            BOOL usedPlayerIndexSlots[4] = {NO, NO, NO, NO};
   1.147 +
   1.148 +            /* Find the player index of all other connected controllers. */
   1.149 +            for (GCController *c in [GCController controllers]) {
   1.150 +                if (c != controller && c.playerIndex >= 0) {
   1.151 +                    usedPlayerIndexSlots[c.playerIndex] = YES;
   1.152 +                }
   1.153 +            }
   1.154 +
   1.155 +            /* Set this controller's player index to the first unused index.
   1.156 +             * FIXME: This logic isn't great... but SDL doesn't expose this
   1.157 +             * concept in its external API, so we don't have much to go on. */
   1.158 +            for (i = 0; i < SDL_arraysize(usedPlayerIndexSlots); i++) {
   1.159 +                if (!usedPlayerIndexSlots[i]) {
   1.160 +                    controller.playerIndex = i;
   1.161 +                    break;
   1.162 +                }
   1.163 +            }
   1.164 +        }
   1.165      }
   1.166  #endif
   1.167  }
   1.168 @@ -566,6 +600,7 @@
   1.169  #ifdef SDL_JOYSTICK_MFI
   1.170              GCController *controller = device->controller;
   1.171              controller.controllerPausedHandler = nil;
   1.172 +            controller.playerIndex = -1;
   1.173  #endif
   1.174          }
   1.175      }