Player lose gamepad input while playing in PIE

We have a problem with unreal editor local coop input at the moment. Player lose input when the editor changes between full screen and not full screen and they also lose input when PIE loses focus by alt tabbing out or shift + F1 they don’t get control back when returning the focus to PIE. The the thing we try to do is have multiple player on screen, watched by a single camera. First player controlled by keyboard + mouse, rest by game pads. We already have a working setup that adds a player per input device.

APlayerController* NewPlayer = UGameplayStatics::CreatePlayerFromPlatformUser(GetWorld(), UInputDeviceLibrary::GetUserForInputDevice(DeviceId));

And use common UI and have the project set to create a device per input. Project Settings -> Input -> Platform Settings -> Device Mapping -> Device Mapping Policy to Create Unique Platform User for Each Device My suspect where it breaks for now is in this part of the input handling.

bool FCommonAnalogCursor::IsGameViewportInFocusPathWithoutCapture() const

One thing we noticed is that the game pad controls the editor at that time.

same as this issue?

not fixed UE5.6.1

Hey there,

In 5.6 we introduced the concept of “Input Device Mapping Policies” (InputDeviceMappingPolicy.h) which allows you to change how the input devices are mapped on PC. For example, you could select “CreateUniquePlatformUserForEachDevice” and have a new FPlatformUserId generated for the keyboard and your first gamepad separately, allowing individual control.

If you combine this with the Game Instance callback for HandleInputDevicePairingChange, then you can call your “Create player” logic in response to an input device being connected. You may also want to enable the bFilterInputByPlatformUser setting in the the project settings to ensure that each player controller is only ever processing input events from an input device that is mapped to them.

I hope that helps,

Ben

Thanks for the hint,

the suggested solution

FReply FSceneViewport::AcquireFocusAndCapture(FIntPoint MousePosition, EFocusCause FocusCause)
{
    // ...
    // Mouse down should focus viewport for user input
//  ReplyState.SetUserFocus(ViewportWidgetRef, FocusCause);
    ReplyState.SetUserFocus(ViewportWidgetRef, FocusCause, true);
 
    // ...
}

Solves the case of alt tabbing and returning to the PIE window.

For now I added code to FLevelViewportLayout to fix the input loss on minimizing and maximizing:

Added into LevelViewportLayout.h

/**
 * Base class for level viewport layout configurations
 * Handles maximizing and restoring well as visibility of specific viewports.
 */
class LEVELEDITOR_API FLevelViewportLayout : public FAssetEditorViewportLayout
{
    ...
	struct FPL_CachedSlateUserData
	{
	public:
		int32 UserIndex { INDEX_NONE };
		TWeakPtr<SWidget> FocusWidget { nullptr };
		TWeakPtr<SWidget> CapturedWidget { nullptr };
	};
	
	TArray<FPL_CachedSlateUserData> CachedSlateUserData { };
};

Added into LevelViewportLayout.h

	void FLevelViewportLayout::MaximizeViewport( FName ViewportToMaximize, const bool bWantMaximize, const bool bWantImmersive, const bool bAllowAnimation )
	{	
		...
 
		bIsMaximized = bWantMaximize;
		bIsImmersive = bWantImmersive;
 
 
		// Start transition
		bIsTransitioning = true;	
 
		//~ Start Changes
		CachedSlateUserData.Reset();
		FSlateApplication::Get().ForEachUser(
			[&](FSlateUser& User)
			{
				FPL_CachedSlateUserData& CachedSlateUserDataEntry = CachedSlateUserData.Emplace_GetRef(FPL_CachedSlateUserData{ User.GetUserIndex() });
				CachedSlateUserDataEntry.FocusWidget = User.GetFocusedWidget();
				
				const FWeakWidgetPath& WeakCursorCapturePat = User.GetWeakCursorCapturePath();
				CachedSlateUserDataEntry.CapturedWidget = WeakCursorCapturePat.IsValid() ? WeakCursorCapturePat.GetLastWidget() : nullptr;
			});
		//~ End Changes
 
		...
	}

Replaced LevelViewportLayout.h

		// Update keyboard focus.  Focus is usually lost when we re-parent the viewport widget.
		{
			// We first need to clear keyboard focus so that Slate doesn't assume that focus won't need to change
			// simply because the viewport widget object is the same -- it has a new widget path!
			FSlateApplication::Get().ClearKeyboardFocus( EFocusCause::SetDirectly );
 
			// Set keyboard focus directly
			MaximizedViewportEntity->SetKeyboardFocus();
		}

with

		// Update focus.  Focus is usually lost when we re-parent the viewport widget.
		{
			// We first need to clear focus so that Slate doesn't assume that focus won't need to change
			// simply because the viewport widget object is the same -- it has a new widget path!
			FSlateApplication& SlateApp = FSlateApplication::Get();
			SlateApp.ClearAllUserFocus( EFocusCause::SetDirectly );
			
			FSlateApplication::Get().ForEachUser(
				[&](FSlateUser& User)
				{
					FPL_CachedSlateUserData* CachedData = CachedSlateUserData.FindByPredicate(
						[&User](const FPL_CachedSlateUserData& SlateUserData)
						{
							return SlateUserData.UserIndex == User.GetUserIndex();
						});
					
					if (CachedData)
					{
						if (CachedData->FocusWidget.IsValid())
						{
							User.SetFocus(CachedData->FocusWidget.Pin().ToSharedRef(), EFocusCause::SetDirectly);
						}
						
						if (CachedData->CapturedWidget.IsValid())
						{
							const TSharedRef<SWidget>& CapturedWidget = CachedData->CapturedWidget.Pin().ToSharedRef();
							FWidgetPath PathToViewport;
							if (FSlateWindowHelper::FindPathToWidget(FSlateApplication::Get().GetTopLevelWindows(),
								CapturedWidget, PathToViewport, EVisibility::All))
							{
								User.SetCursorCaptor(CapturedWidget, PathToViewport);
							}
						}
					}
				}
			);
		}

this seems to work for now.

and in SlateApplication.cpp

add

#if WITH_EDITOR
#pragma region [PL] Fix gamepads losing input
			// Capture cursor for other gamepads
			if (TheReply.AffectsAllUsers())
			{
				ForEachUser([&] (FSlateUser& User) {
					if ((User.GetUserIndex() == SlateUser->GetUserIndex()) || (User.GetUserIndex() == 0))
					{
						return;
					}
					
					if (User.SetPointerCaptor(CursorPointerIndex, RequestedMouseCaptor.ToSharedRef(), CurrentEventPath))
					{
						User.RequestCursorQuery();
					}
				});
			}
#pragma endregion [PL] Fix gamepads losing input
#endif

after

		// Do not capture the mouse if we are also starting a drag and drop.
		if (RequestedMouseCaptor.IsValid() && !bStartingDragDrop)
		{

in the function

void FSlateApplication::ProcessReply( const FWidgetPath& CurrentEventPath, const FReply& TheReply, const FWidgetPath* WidgetsUnderMouse, const FPointerEvent* InMouseEvent, const uint32 UserIndex )
{

Thanks for taking the time to answer.

We are using CreateUniquePlatformUserForEachDevice which works perfectly fine to control two players from keyboard and game pad in the editor.

The problem is that the second player loses input control when minimizing/maximizing or when the user is removing and returning focus to the editor.

As far as I can see player 0 has special logic to reconnect input when minimizing / maximizing in

void FLevelViewportLayout::FinishMaximizeTransition()

which solves the problem that the slate hierarchy is changed when minimizing / maximizing

		// Update keyboard focus.  Focus is usually lost when we re-parent the viewport widget.
		{
			// We first need to clear keyboard focus so that Slate doesn't assume that focus won't need to change
			// simply because the viewport widget object is the same -- it has a new widget path!
			FSlateApplication::Get().ClearKeyboardFocus( EFocusCause::SetDirectly );
 
			// Set keyboard focus directly
			MaximizedViewportEntity->SetKeyboardFocus();
		}

which is not called for other players.

And similarly when returning focus after leaving

https://issues.unrealengine.com/issue/UE-107689

FSceneViewport::AcquireFocusAndCapture(FIntPoint MousePosition, EFocusCause FocusCause)

which does only return focus to player 0.

Thank you very much for all this detailed bug info.

I have re-assigned that issue to a more relevant team (me!) and brought it out from the backlog. I will take a deeper look soon, but by the looks of things you are right.

Unfortunately window focusing is not really a strong suite of Unreal (as you have found out!)

For future reference of input device debugging, the “showdebug devices” command may be of interest to you as well. It prints out all the currently connected devices and what platform user and Slate User ID they have. The VeryVerbose “LogPlayerInput” category will also print out all the input you receive on each player, which can be helpful to sanity check if you are receiving input or not.

I will have to dig in a bit deeper before I can give a work around, but some more info would be helpful to make sure that I am repro’ing exactly what you are doing:

What kind of controller are you using? Xbox/PlayStation?

Just to confirm, you are utilizing the Common UI and Common Input plugins and using the common analog mouse cursor, right?

Thanks

Thanks for taking a deeper look into this.

I’m using XBox controllers but other users had the same issues with generic game pads.

Platform is Windows 10.

We are using Common UI, Common Input and Enhanced Input.

Common UI Input Settings:

[Image Removed]

Great, thank you for the extra info!