PlayerController Input dont work when switch between Immersive Mode or not

This is a pretty weird mistake that I’m stuck with and I don’t know how to fix. In my game there are 2 different APawns each one using my custom APlayerController class and both are controlled with a different gamepad. The control of each of the APawns works well inside the editor with the viewport at normal size and also when I launch the game in Standalone mode both in full screen and normal.

The problem comes when inside the editor in runtime the Immersive Mode is activated by pressing the F11 key. When I do this the input of my second APlayerController stops working completely, then when I press again the F11 key to switch from Immersive Mode to normal mode the input of the second APlayerController works again.

I’ve been doing some research and once I press F11 the second APlayerController stops running the “Input Axis” and “Input Key” functions of the APlayerController class, I’ve put breakpoints on those two functions and they don’t activate.

I also researched the “RequestMaximizeViewport” and “MaximizeViewport” functions within the FLevelViewportLayout class which are activated when the F11 key is pressed to enable or disable the Immersive Mode, but I have not found anything that disables the input of my second APlayerController.

The only clue I got is that once I switched to the Immersive Mode, when the FSlateApplication class process the input with the **“ProcessAnalogInputEvent” **function, the first APlayer Controller who works well calls the “OnFocusReceived” function of the **SViewport **class instead of the second APlayerController who calls
the “OnFocusReceived” function but from the SWidgetClass.

I don’t understand what part of the Immersive mode change causes this and why one of the APlayerController works and the other doesn’t.
I’d like to find a workaround to this problem as it’s quite frustrating to lose input from one of the players while you’re testing things in the editor.
I tried to check if in the change of mode the connection of one of the gamepads is lost but everything works fine and I don’t know what to do anymore.

Massively appreciate any advice to solve this problem.

Thanks.

1 Like

Were you able to fix this? I’m currently having a similar situation as well.

What we concluded was that the Slate User associated to the gamepad is somehow different than what it is supposed to be but we have no idea what could be changing its value

Hello, I just had the same issue today and it took me a couple of hours but I found a workaround without modifying the engine code:

void AMyPlayerController::SetupInputComponent()
{
	Super::SetupInputComponent();

#if WITH_EDITOR
	if (IsLocalPlayerController())
	{
		TryFocusPlayInEditorSessionViewport();
		FViewport::ViewportResizedEvent.AddUObject(this, &AMyPlayerController::OnViewportResized);
	}
#endif
}

#if WITH_EDITOR
void AMyPlayerController::TryFocusPlayInEditorSessionViewport() const
{
	const TSharedPtr<IAssetViewport> Viewport = GetPlayInEditorSessionViewport();
	if (!Viewport)
	{
		return;
	}
	const ULocalPlayer* const LocalPlayer = GetLocalPlayer();
	if (!LocalPlayer)
	{
		return;
	}
	const TSharedPtr<FSlateUser> SlateUser = GetLocalPlayer()->GetSlateUser();
	if (!SlateUser)
	{
		return;
	}
	const TObjectPtr<UGameViewportClient> ViewportClient = LocalPlayer->ViewportClient;
	if (!ViewportClient)
	{
		return;
	}
	const TSharedPtr<SViewport> GameViewportWidget = ViewportClient->GetGameViewportWidget();
	if (!GameViewportWidget)
	{
		return;
	}
	SlateUser->ClearFocus(EFocusCause::SetDirectly);
	SlateUser->SetFocus(GameViewportWidget->AsShared(), EFocusCause::SetDirectly);
}

void AMyPlayerController::FocusPlayInEditorSessionViewport() const
{
	TryFocusPlayInEditorSessionViewport();
}

void AMyPlayerController::OnViewportResized(FViewport* const Viewport, const uint32 UnusedInteger)
{
	const ULocalPlayer* const LocalPlayer = GetLocalPlayer();
	if (!LocalPlayer)
	{
		return;
	}
	const TObjectPtr<UGameViewportClient> ViewportClient = LocalPlayer->ViewportClient;
	if (!ViewportClient || Viewport != ViewportClient->Viewport)
	{
		return;
	}
	TryFocusPlayInEditorSessionViewport();
	
	// We need to do it one additional time when minimizing.
	GetWorldTimerManager().SetTimerForNextTick(this, &AMyPlayerController::FocusPlayInEditorSessionViewport);
}

TSharedPtr<IAssetViewport> AMyPlayerController::GetPlayInEditorSessionViewport() const
{
	if (!GEditor)
	{
		return nullptr;
	}
	const UGameInstance* const GameInstance = GetGameInstance();
	if (!GameInstance)
	{
		return nullptr;
	}
	const FWorldContext* const WorldContext = GameInstance->GetWorldContext();
	if (!WorldContext)
	{
		return nullptr;
	}
	const FSlatePlayInEditorInfo* const SlatePlayInEditorInfo = GEditor->SlatePlayInEditorMap.Find(WorldContext->ContextHandle);
	if (!SlatePlayInEditorInfo)
	{
		return nullptr;
	}
	const TWeakPtr<IAssetViewport> DestinationSlateViewport = SlatePlayInEditorInfo->DestinationSlateViewport;
	if (!DestinationSlateViewport.IsValid())
	{
		return nullptr;
	}
	return DestinationSlateViewport.Pin();
}
#endif

It is probably easier by modifying the engine code in “FLevelViewportLayout::FinishMaximizeTransition” just below “MaximizedViewportEntity->SetKeyboardFocus();” by looping through the Slate users, clear their focus before focusing the viewport just like it’s done for the first local player with the keyboard focus.