1. Background
Unreal Engine Source Build doesn’t work with the multiple gamepads on Mac.
2. Implementation
1. Engine/Source/Runtime/ApplicationCore/Private/Apple/AppleControllerInterface.h
...
enum PlayerIndex
{
PlayerOne,
PlayerTwo,
PlayerThree,
PlayerFour,
+ LastPlayerIndex = PlayerFour,
+ MaxPlayerCount = LastPlayerIndex + 1,
PlayerUnset = -1
};
...
class FAppleControllerInterface : public IInputInterface
{
...
void SetCurrentController(GCController* Controller);
+ PlayerIndex GetPlayerIndex(GCController* Controller) const;
+ PlayerIndex GetAvailablePlayerIndex() const;
+ bool ReplacePlayerOne(PlayerIndex NewPlayerIndex);
+ bool SetPlayerIndex(GCController* Controller, PlayerIndex NewPlayerIndex);
...
};
2. Engine/Source/Runtime/ApplicationCore/Private/Apple/AppleControllerInterface.cpp
...
void FAppleControllerInterface::SetCurrentController(GCController* Controller)
{
+ const PlayerIndex CurPlayerIndex = GetPlayerIndex(Controller);
+
+ // The controller is already PlayerOne, the current controller.
+ if (CurPlayerIndex == PlayerIndex::PlayerOne)
+ {
+ return;
+ }
+
+ // Error: Invalid Controller.
+ if(CurPlayerIndex == PlayerIndex::PlayerUnset)
+ {
+ UE_LOG(LogAppleController, Warning, TEXT("Controller is not connected."));
+ return;
+ }
+
+ // Replace existing PlayerOne with the Controller's PlayerIndex.
+ if(!ReplacePlayerOne(CurPlayerIndex))
+ {
+ UE_LOG(LogAppleController, Warning, TEXT("Failed to replace PlayerOne to PlayerIndex %d."), static_cast<int32>(CurPlayerIndex));
+ return;
+ }
+
+ // Set the controller to PlayerOne
+ if (!SetPlayerIndex(Controller, PlayerIndex::PlayerOne))
+ {
+ UE_LOG(LogAppleController, Warning, TEXT("Failed to set PlayerOne to Controller %s."));
+ return;
+ }
}
+PlayerIndex FAppleControllerInterface::GetPlayerIndex(GCController* Controller) const
+{
+ for (int32 ControllerIndex = 0; ControllerIndex < UE_ARRAY_COUNT(Controllers); ControllerIndex++)
+ {
+ if (Controllers[ControllerIndex].Controller == Controller)
+ {
+ return Controllers[ControllerIndex].PlayerIndex;
+ }
+ }
+
+ UE_LOG(LogAppleController, Warning, TEXT("Controller %@ is not connected"), Controller.productCategory);
+ return PlayerIndex::PlayerUnset;
+}
+PlayerIndex +FAppleControllerInterface::GetAvailablePlayerIndex() const
+{
+ bool UsedPlayerIndices[MaxPlayerCount] = { false };
+ for (int32 ControllerIndex = 0; ControllerIndex < UE_ARRAY_COUNT(Controllers); ControllerIndex++)
+ {
+ if (Controllers[ControllerIndex].PlayerIndex != PlayerIndex::PlayerUnset)
+ {
+ UsedPlayerIndices[Controllers[ControllerIndex].PlayerIndex] = true;
+ }
+ }
+
+ // Return the first available player index.
+ for (int32 CandidatePlayerIndex = 0; CandidatePlayerIndex <= LastPlayerIndex; CandidatePlayerIndex++)
+ {
+ if (UsedPlayerIndices[CandidatePlayerIndex] == false)
+ {
+ return static_cast<PlayerIndex>(CandidatePlayerIndex);
+ }
+ }
+
+ // No available player index found;
+ return PlayerIndex::PlayerUnset;
+}
+bool FAppleControllerInterface::ReplacePlayerOne(PlayerIndex NewPlayerIndex)
+{
+ for (int32 ControllerIndex = 0; ControllerIndex < UE_ARRAY_COUNT(Controllers); ControllerIndex++)
+ {
+ if (Controllers[ControllerIndex].PlayerIndex == PlayerIndex::PlayerOne)
+ {
+ Controllers[ControllerIndex].PlayerIndex = NewPlayerIndex;
+ return true;
+ }
+ }
+
+ return false;
+}
+bool FAppleControllerInterface::SetPlayerIndex(GCController* Controller, PlayerIndex NewPlayerIndex)
+{
+ for (int32 ControllerIndex = 0; ControllerIndex < UE_ARRAY_COUNT(Controllers); ControllerIndex++)
+ {
+ if (Controllers[ControllerIndex].Controller == Controller)
+ {
+ Controllers[ControllerIndex].PlayerIndex = NewPlayerIndex;
+ return true;
+ }
+ }
+
+ return false;
+}
void FAppleControllerInterface::HandleConnection(GCController* Controller)
{
...
+ const PlayerIndex NewPlayerIndex = GetAvailablePlayerIndex();
+ if (NewPlayerIndex == PlayerIndex::PlayerUnset)
+ {
+ UE_LOG(LogAppleController, Log, TEXT("Maximum player count %d reached."), MaxPlayerCount);
+ return;
+ }
...
for (int32 ControllerIndex = 0; ControllerIndex < UE_ARRAY_COUNT(Controllers); ControllerIndex++)
{
...
+ Controllers[ControllerIndex].PlayerIndex = NewPlayerIndex;
...
+ UE_LOG(LogAppleController, Log, TEXT("New %s controller inserted, assigned to playerIndex %d"),
Controllers[ControllerIndex].ControllerType == ControllerType::SiriRemote
? TEXT("Remote") : TEXT("Gamepad"), Controllers[ControllerIndex].PlayerIndex);
break;
}
...
}
...