GCController's sfSymbolsName returns incorrect values when customization is disabled

Summary

GCController's sfSymbolsName API returns the customized symbol names after customization is disabled until the app is restarted. It should be returning the uncustomized symbol names (to match the current button inputs).

Detailed Repro

I've connected a Horipad to my iPad (OS 14.3).
When I start the app, it starts printing the correct symbol names:
Controller HORIPAD ULTIMATE
buttonA: a.circle
buttonB: b.circle
buttonX: x.circle
buttonY: y.circle

I turn on customization (Settings > General > Game Controller > Customizations > Enable Customizations) and swap two face buttons with shoulders (using the global customization) and the symbol names change as expected:
Controller HORIPAD ULTIMATE
buttonA: l1.rectangle.roundedbottom
buttonB: r1.rectangle.roundedbottom
buttonX: x.circle
buttonY: y.circle

I swap buttonX and buttonY and the symbol names update:
Controller HORIPAD ULTIMATE
buttonA: l1.rectangle.roundedbottom
buttonB: r1.rectangle.roundedbottom
buttonX: y.circle
buttonY: x.circle

I turn off customization and the symbol names fail to update:
Controller HORIPAD ULTIMATE
buttonA: l1.rectangle.roundedbottom
buttonB: r1.rectangle.roundedbottom
buttonX: y.circle
buttonY: x.circle

I'd expect it to go back to the first set of names (a.circle, etc).

Launching the app with customization enabled and switching to settings to turn it off also continues to produce the customized sfSymbolsName values instead of the correct uncustomized values.

I'm testing from a Unity game (Unity 2019.4.7f1). Here's my minimal repro:

Code Block cs
// Assets/Scripts/GamepadTest.cs
using System;
using System.Runtime.InteropServices;
using UnityEngine;
namespace Game {
public class GamepadTest : MonoBehaviour {
#if UNITY_IOS || UNITY_TVOS
[DllImport("__Internal")]
private static extern void GCControllerInit();
[DllImport("__Internal")]
private static extern void GCControllerUpdate();
void Start() {
GCControllerInit();
}
void Update() {
GCControllerUpdate();
}
#endif // UNITY_IOS || UNITY_TVOS
}
}


Code Block objc
// Assets/Plugins/InputTest/iOS/gccontroller.m
#import <stdint.h>
#import <Foundation/Foundation.h>
#import <GameController/GameController.h>
static bool g_initialized = false;
static GCController* g_controller;
void GCControllerUpdate()
{
if(g_controller == NULL) {
return;
}
// BUG: First print is correct. First change to button mapping
// correctly transitions. Second change to button mapping doesn't
// transition.
NSLog(@"Controller %@\n", g_controller.vendorName);
NSLog(@"buttonA: %@\n", g_controller.extendedGamepad.buttonA.sfSymbolsName);
NSLog(@"buttonB: %@\n", g_controller.extendedGamepad.buttonB.sfSymbolsName);
NSLog(@"buttonX: %@\n", g_controller.extendedGamepad.buttonX.sfSymbolsName);
NSLog(@"buttonY: %@\n", g_controller.extendedGamepad.buttonY.sfSymbolsName);
}
static void onConnected(GCController* gcController)
{
NSLog(@"[Gamepad] CONNECTED: %@\n", gcController.vendorName);
if(g_controller) {
NSLog(@"[Gamepad] Already had connected: %@\n", g_controller.vendorName);
}
g_controller = gcController;
}
static void onDisconnected(GCController* gcController)
{
if(g_controller == gcController) {
NSLog(@"[Gamepad] Wasn't connected: %@\n", g_controller.vendorName);
return;
}
g_controller = NULL;
NSLog(@"[Gamepad] DISCONNECTED: %@\n", gcController.vendorName);
}
void GCControllerInit()
{
if(g_initialized) {
NSLog(@"[Gamepad] Warning! Already initialized!\n");
return;
}
g_controller = NULL;
for(GCController *gcController in [GCController controllers]) {
onConnected(gcController);
}
NSNotificationCenter * center = [NSNotificationCenter defaultCenter];
[center addObserverForName:
GCControllerDidConnectNotification
object: nil
queue: nil
usingBlock: ^(NSNotification *note) { onConnected(note.object); } ];
[center addObserverForName:
GCControllerDidDisconnectNotification
object: nil
queue: nil
usingBlock: ^(NSNotification *note) { onDisconnected(note.object); } ];
g_initialized = true;
GCControllerUpdate();
}


I tried to make a native app to demonstrate the problem, but it disconnects when it loses focus so the app restarts and gets valid values. I assume if I figured out how to make it run like a game and stay alive after losing focus it would have the same problem?
GCController's sfSymbolsName returns incorrect values when customization is disabled
 
 
Q