Separated the ability of a user widget to intercept all input into its own thing

This commit is contained in:
Steve Streeting 2020-11-18 15:12:01 +00:00
parent 983396f86a
commit 9e13cc8d53
4 changed files with 78 additions and 31 deletions

View File

@ -12,13 +12,6 @@ void UMenuStack::NativeConstruct()
{ {
Super::NativeConstruct(); Super::NativeConstruct();
if (!InputPreprocessor.IsValid())
{
InputPreprocessor = MakeShareable(new FUiInputPreprocessor());
InputPreprocessor->OnUiKeyDown.BindUObject(this, &UMenuStack::HandleKeyDownEvent);
}
FSlateApplication::Get().RegisterInputPreProcessor(InputPreprocessor);
// We could technically do input change detection in our own input processor, but since this already does it nicely... // We could technically do input change detection in our own input processor, but since this already does it nicely...
auto GS = GetStevesGameSubsystem(GetWorld()); auto GS = GetStevesGameSubsystem(GetWorld());
if (GS) if (GS)
@ -35,7 +28,6 @@ void UMenuStack::NativeConstruct()
void UMenuStack::NativeDestruct() void UMenuStack::NativeDestruct()
{ {
Super::NativeDestruct(); Super::NativeDestruct();
FSlateApplication::Get().UnregisterInputPreProcessor(InputPreprocessor);
auto GS = GetStevesGameSubsystem(GetWorld()); auto GS = GetStevesGameSubsystem(GetWorld());
if (GS) if (GS)
@ -96,6 +88,8 @@ void UMenuStack::ApplyGamePauseChange(EGamePauseChange Change) const
bool UMenuStack::HandleKeyDownEvent(const FKeyEvent& InKeyEvent) bool UMenuStack::HandleKeyDownEvent(const FKeyEvent& InKeyEvent)
{ {
Super::HandleKeyDownEvent(InKeyEvent);
// Hardcoding the Back / Exit menu navigation inputs because input mappings can't be trusted in UMG // Hardcoding the Back / Exit menu navigation inputs because input mappings can't be trusted in UMG
// This is probably OK though, no-one redefines menu controls, right? // This is probably OK though, no-one redefines menu controls, right?
FKey Key = InKeyEvent.GetKey(); FKey Key = InKeyEvent.GetKey();

View File

@ -0,0 +1,29 @@
#include "FocusableInputInterceptorUserWidget.h"
void UFocusableInputInterceptorUserWidget::NativeConstruct()
{
Super::NativeConstruct();
if (!InputPreprocessor.IsValid())
{
InputPreprocessor = MakeShareable(new FUiInputPreprocessor());
InputPreprocessor->OnUiKeyDown.BindUObject(this, &UFocusableInputInterceptorUserWidget::HandleKeyDownEvent);
}
FSlateApplication::Get().RegisterInputPreProcessor(InputPreprocessor);
}
void UFocusableInputInterceptorUserWidget::NativeDestruct()
{
Super::NativeDestruct();
FSlateApplication::Get().UnregisterInputPreProcessor(InputPreprocessor);
}
bool UFocusableInputInterceptorUserWidget::HandleKeyDownEvent(const FKeyEvent& InKeyEvent)
{
// Do nothing by default
return false;
}

View File

@ -0,0 +1,43 @@
#pragma once
#include "CoreMinimal.h"
#include "FocusableUserWidget.h"
#include "Framework/Application/IInputProcessor.h"
#include "FocusableInputInterceptorUserWidget.generated.h"
UCLASS(Blueprintable, BlueprintType)
class STEVESUEHELPERS_API UFocusableInputInterceptorUserWidget : public UFocusableUserWidget
{
GENERATED_BODY()
// Nested class which we'll use to poke into input events before anything else eats them
// Without this it seems impossible to pick up e.g. Gamepad "B" button with UMG up
// It means we hardcode the controls for menus but that's OK in practice
class FUiInputPreprocessor : public IInputProcessor, public TSharedFromThis<FUiInputPreprocessor>
{
public:
DECLARE_DELEGATE_RetVal_OneParam(bool, FOnUiKeyDown, const FKeyEvent&);
FOnUiKeyDown OnUiKeyDown;
virtual bool HandleKeyDownEvent(FSlateApplication& SlateApp, const FKeyEvent& InKeyEvent) override
{
return OnUiKeyDown.Execute(InKeyEvent);
}
// Required by IInputProcessor but we don't need
virtual void Tick(const float DeltaTime, FSlateApplication& SlateApp, TSharedRef<ICursor> Crs) override{}
};
protected:
TSharedPtr<FUiInputPreprocessor> InputPreprocessor;
public:
virtual void NativeConstruct() override;
virtual void NativeDestruct();
UFUNCTION()
virtual bool HandleKeyDownEvent(const FKeyEvent& InKeyEvent);
};

View File

@ -2,7 +2,8 @@
#include "CoreMinimal.h" #include "CoreMinimal.h"
#include "FocusableUserWidget.h"
#include "FocusableInputInterceptorUserWidget.h"
#include "Framework/Application/IInputProcessor.h" #include "Framework/Application/IInputProcessor.h"
#include "StevesHelperCommon.h" #include "StevesHelperCommon.h"
@ -20,34 +21,15 @@ DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnMenuStackClosed, class UMenuStac
/// Create a Blueprint subclass of this and make sure you include a UContentWidget with the name /// Create a Blueprint subclass of this and make sure you include a UContentWidget with the name
/// "MenuContainer" somewhere in the tree, which is where the menu contents will be placed. /// "MenuContainer" somewhere in the tree, which is where the menu contents will be placed.
UCLASS(Abstract, BlueprintType) UCLASS(Abstract, BlueprintType)
class STEVESUEHELPERS_API UMenuStack : public UFocusableUserWidget class STEVESUEHELPERS_API UMenuStack : public UFocusableInputInterceptorUserWidget
{ {
GENERATED_BODY() GENERATED_BODY()
// Nested class which we'll use to poke into input events before anything else eats them
// Without this it seems impossible to pick up e.g. Gamepad "B" button with UMG up
// It means we hardcode the controls for menus but that's OK in practice
class FUiInputPreprocessor : public IInputProcessor, public TSharedFromThis<FUiInputPreprocessor>
{
public:
DECLARE_DELEGATE_RetVal_OneParam(bool, FOnUiKeyDown, const FKeyEvent&);
FOnUiKeyDown OnUiKeyDown;
virtual bool HandleKeyDownEvent(FSlateApplication& SlateApp, const FKeyEvent& InKeyEvent) override
{
return OnUiKeyDown.Execute(InKeyEvent);
}
// Required by IInputProcessor but we don't need
virtual void Tick(const float DeltaTime, FSlateApplication& SlateApp, TSharedRef<ICursor> Crs) override{}
};
protected: protected:
EInputMode LastInputMode; EInputMode LastInputMode;
TArray<UMenuBase*> Menus; TArray<UMenuBase*> Menus;
TSharedPtr<FUiInputPreprocessor> InputPreprocessor;
virtual void LastMenuClosed(bool bWasCancel); virtual void LastMenuClosed(bool bWasCancel);
virtual void NativeConstruct() override; virtual void NativeConstruct() override;
@ -57,8 +39,7 @@ protected:
virtual void ApplyMousePointerVisibility(EMousePointerVisibilityChange Change) const; virtual void ApplyMousePointerVisibility(EMousePointerVisibilityChange Change) const;
virtual void ApplyGamePauseChange(EGamePauseChange Change) const; virtual void ApplyGamePauseChange(EGamePauseChange Change) const;
UFUNCTION() virtual bool HandleKeyDownEvent(const FKeyEvent& InKeyEvent) override;
bool HandleKeyDownEvent(const FKeyEvent& InKeyEvent);
UFUNCTION() UFUNCTION()
void InputModeChanged(int PlayerIndex, EInputMode NewMode); void InputModeChanged(int PlayerIndex, EInputMode NewMode);