How to set up GCController valueChangeHandler Properly in Xcode?

1.8k Views Asked by At

I have successfully connected a steel series Nimbus dual analog controller to use for testing in both my iOS and tvOS apps. But I am unsure about how to properly set up the valueChangeHandler portion of my GCController property.

I understand so far that there are microGamepad, gamepad and extendedGamepad classes of controllers and the differences between them. I also understand that you can check to see if the respective controller class is available on the controller connected to your device.

But now I am having trouble setting up valueChangeHandler because if I set the three valueChangeHandler portions like so, then only the valueChangeHandler that works is the last one that was loaded in this sequence:

self.gameController = GCController.controllers()[0]

self.gameController.extendedGamepad?.valueChangedHandler = { (gamepad, element) -> Void in
    if element == self.gameController.extendedGamepad?.leftThumbstick {
        //Never gets called
    }
}

self.gameController.gamepad?.valueChangedHandler = { (gamepad, element) -> Void in
    if element == self.gameController.gamepad?.dpad {
        //Never gets called   
    }
}

self.gameController.microGamepad?.valueChangedHandler = { (gamepad, element) -> Void in
    if element == self.gameController.microGamepad?.dpad {
        //Gets called
    }
}

If I switch them around and call self.gameController.extendedGamepad.valueChangeHandler... last, then those methods will work and the gamepad and microGamepad methods will not.

Anyone know how to fix this?

1

There are 1 best solutions below

1
On

You test which profile is available and depending on the profile, you set the valueChangedHandler.

It's important to realise that the extendedGamepad contains most functionality and the microGamepad least (I think the microGamepad is only used for the AppleTV remote). Therefore the checks should be ordered differently. An extendedGamepad has all functionality of the microGamepad + additional controls so in your code the method would always enter the microGamepad profile.

Apple uses the following code in the DemoBots example project:

private func registerMovementEvents() {
    /// An analog movement handler for D-pads and movement thumbsticks.
    let movementHandler: GCControllerDirectionPadValueChangedHandler = { [unowned self] _, xValue, yValue in
        // Code to handle movement here ...
    }

    #if os(tvOS)
    // `GCMicroGamepad` D-pad handler.
    if let microGamepad = gameController.microGamepad {
        // Allow the gamepad to handle transposing D-pad values when rotating the controller.
        microGamepad.allowsRotation = true
        microGamepad.dpad.valueChangedHandler = movementHandler
    }
    #endif

    // `GCGamepad` D-pad handler.
    // Will never enter here in case of AppleTV remote as the AppleTV remote is a microGamepad
    if let gamepad = gameController.gamepad {
        gamepad.dpad.valueChangedHandler = movementHandler 
    }

    // `GCExtendedGamepad` left thumbstick.
    if let extendedGamepad = gameController.extendedGamepad {
        extendedGamepad.leftThumbstick.valueChangedHandler = movementHandler
    }
}