I have not heard back from my bug report either.
A programmer that was working on our team put together a fix for us (5.1) by creating a custom GameViewport class - I mentioned he could post it here but it looks like he hasn’t got around to it, so here it is. This is not my code.
BoozeGameViewportClient.h:
#pragma once
#include "CoreMinimal.h"
#include "Engine/GameViewportClient.h"
#include "BoozeGameViewportClient.generated.h"
DECLARE_MULTICAST_DELEGATE_OneParam(FOnInputKeySignature, const FInputKeyEventArgs& /*EventArgs*/);
DECLARE_DELEGATE_RetVal_FourParams(bool, FOverrideInputAxisHandler, FInputKeyEventArgs& /*EventArgs*/, float& /*Delta*/, float& /*DeltaTime*/, int32& /*NumSamples*/);
/**
*
*/
UCLASS()
class BOOZEGAME_API UBoozeGameViewportClient : public UGameViewportClient
{
GENERATED_BODY()
public:
virtual bool InputKey(const FInputKeyEventArgs& EventArgs) override;
virtual void RemapControllerInput(FInputKeyEventArgs& InOutKeyEvent) override;
virtual bool InputAxis(FViewport* InViewport, FInputDeviceId InputDevice, FKey Key, float Delta, float DeltaTime, int32 NumSamples = 1, bool bGamepad = false) override;
private:
ULocalPlayer* GetLocalPlayerFromControllerId(int32 ControllerId) const;
/** A broadcast delegate broadcasting from UGameViewportClient::InputKey */
FOnInputKeySignature OnInputKeyEvent;
/** Delegate for overriding input key behavior */
FOverrideInputKeyHandler OnOverrideInputKeyEvent;
/** A broadcast delegate broadcasting from UGameViewportClient::InputAxis */
FOnInputAxisSignature OnInputAxisEvent;
/** Delegate for overriding input axis behavior */
FOverrideInputAxisHandler OnOverrideInputAxisEvent;
#if WITH_EDITOR
/** Delegate called when game viewport client received input key */
FOnGameViewportInputKey GameViewportInputKeyDelegate;
#endif
};
BoozeGameViewportClient.cpp:
#include "BoozeGameViewportClient.h"
#include "GameMapsSettings.h"
#include "Engine/Console.h"
#include "Framework/Application/SlateApplication.h"
#include "GameMapsSettings.h"
bool UBoozeGameViewportClient::InputKey(const FInputKeyEventArgs& InEventArgs)
{
FInputKeyEventArgs EventArgs = InEventArgs;
if (TryToggleFullscreenOnInputKey(EventArgs.Key, EventArgs.Event))
{
return true;
}
if (EventArgs.Key == EKeys::LeftMouseButton && EventArgs.Event == EInputEvent::IE_Pressed)
{
GEngine->SetFlashIndicatorLatencyMarker(GFrameCounter);
}
//if turn on skip setting and using gamepad, increment controllerId
RemapControllerInput(EventArgs);
if (IgnoreInput())
{
return ViewportConsole ? ViewportConsole->InputKey(EventArgs.InputDevice, EventArgs.Key, EventArgs.Event, EventArgs.AmountDepressed, EventArgs.IsGamepad()) : false;
}
OnInputKeyEvent.Broadcast(EventArgs);
#if WITH_EDITOR
// Give debugger commands a chance to process key binding
if (GameViewportInputKeyDelegate.IsBound())
{
if ( GameViewportInputKeyDelegate.Execute(EventArgs.Key, FSlateApplication::Get().GetModifierKeys(), EventArgs.Event) )
{
return true;
}
}
#endif
// route to subsystems that care
bool bResult = ( ViewportConsole ? ViewportConsole->InputKey(EventArgs.InputDevice, EventArgs.Key, EventArgs.Event, EventArgs.AmountDepressed, EventArgs.IsGamepad()) : false );
// Try the override callback, this may modify event args
if (!bResult && OnOverrideInputKeyEvent.IsBound())
{
bResult = OnOverrideInputKeyEvent.Execute(EventArgs);
}
if (!bResult)
{
ULocalPlayer* TargetLocalPlayer = GetLocalPlayerFromControllerId(EventArgs.ControllerId);
if(TargetLocalPlayer && TargetLocalPlayer->PlayerController)
{
bResult = TargetLocalPlayer->PlayerController->InputKey(FInputKeyParams(EventArgs.Key, EventArgs.Event, static_cast<double>(EventArgs.AmountDepressed), EventArgs.IsGamepad(), EventArgs.InputDevice));
}
// A gameviewport is always considered to have responded to a mouse buttons to avoid throttling
if (!bResult && EventArgs.Key.IsMouseButton())
{
bResult = true;
}
}
return bResult;
}
bool UBoozeGameViewportClient::InputAxis(FViewport* InViewport, FInputDeviceId InputDevice, FKey Key, float Delta,
float DeltaTime, int32 NumSamples, bool bGamepad)
{
if (IgnoreInput())
{
return false;
}
// Handle mapping controller id and key if needed
FInputKeyEventArgs EventArgs(InViewport, InputDevice, Key, IE_Axis);
//if turn on skip setting and using gamepad, increment controllerId
RemapControllerInput(EventArgs);
OnInputAxisEvent.Broadcast(InViewport, EventArgs.ControllerId, EventArgs.Key, Delta, DeltaTime, NumSamples, EventArgs.IsGamepad());
bool bResult = false;
// Don't allow mouse/joystick input axes while in PIE and the console has forced the cursor to be visible. It's
// just distracting when moving the mouse causes mouse look while you are trying to move the cursor over a button
// in the editor!
if( !( InViewport->IsSlateViewport() && InViewport->IsPlayInEditorViewport() ) || ViewportConsole == nullptr || !ViewportConsole->ConsoleActive() )
{
// route to subsystems that care
if (ViewportConsole != nullptr)
{
bResult = ViewportConsole->InputAxis(EventArgs.InputDevice, EventArgs.Key, Delta, DeltaTime, NumSamples, EventArgs.IsGamepad());
}
// Try the override callback, this may modify event args
if (!bResult && OnOverrideInputAxisEvent.IsBound())
{
bResult = OnOverrideInputAxisEvent.Execute(EventArgs, Delta, DeltaTime, NumSamples);
}
if (!bResult)
{
ULocalPlayer* const TargetLocalPlayer = GetLocalPlayerFromControllerId(EventArgs.ControllerId);
if (TargetLocalPlayer && TargetLocalPlayer->PlayerController)
{
bResult = TargetLocalPlayer->PlayerController->InputKey(FInputKeyParams(EventArgs.Key, (double)Delta, DeltaTime, NumSamples, EventArgs.IsGamepad(), EventArgs.InputDevice));
}
}
if( InViewport->IsSlateViewport() && InViewport->IsPlayInEditorViewport() )
{
// Absorb all keys so game input events are not routed to the Slate editor frame
bResult = true;
}
}
return bResult;
}
void UBoozeGameViewportClient::RemapControllerInput(FInputKeyEventArgs& InOutEventArgs)
{
const int32 NumLocalPlayers = World ? World->GetGameInstance()->GetNumLocalPlayers() : 0;
if (NumLocalPlayers > 1 && InOutEventArgs.Key.IsGamepadKey() && GetDefault<UGameMapsSettings>()->bOffsetPlayerGamepadIds)
{
InOutEventArgs.ControllerId++;
}
else if (InOutEventArgs.Viewport->IsPlayInEditorViewport() && InOutEventArgs.Key.IsGamepadKey())
{
GEngine->RemapGamepadControllerIdForPIE(this, InOutEventArgs.ControllerId);
}
}
ULocalPlayer* UBoozeGameViewportClient::GetLocalPlayerFromControllerId(int32 ControllerId) const
{
if (UGameInstance* BoozeGameInstance = GetWorld()->GetGameInstance())
{
const TArray<ULocalPlayer*>& BoozeLocalPlayerArray = BoozeGameInstance->GetLocalPlayers();
for(ULocalPlayer* const BoozeLocalPlayer : BoozeLocalPlayerArray)
{
if(BoozeLocalPlayer && BoozeLocalPlayer->GetControllerId() == ControllerId)
{
return BoozeLocalPlayer;
}
}
}
return nullptr;
}