First step of new focus management system

This commit is contained in:
2026-04-15 22:55:02 -04:00
parent 2f83910897
commit 8a3d200247
7 changed files with 365 additions and 5 deletions

View File

@@ -4,6 +4,24 @@
#include "TangibleManager.h"
#include "Kismet/GameplayStatics.h"
#include "Engine/GameInstance.h"
#include "Engine/GameViewportClient.h"
#include "Framework/Application/SlateApplication.h"
#include "Widgets/SViewport.h"
#include "Slate/SObjectWidget.h"
FString AlxPlayerControllerBase::GetUserWidgetName(SWidget *W)
{
while (W)
{
if (W->GetType() == FName("SObjectWidget"))
{
UUserWidget *UW = static_cast<SObjectWidget*>(W)->GetWidgetObject();
if (UW) return UW->GetClass()->GetName();
}
W = W->GetParentWidget().Get();
}
return TEXT("Unknown Widget");
}
AlxPlayerControllerBase *AlxPlayerControllerBase::FromContext(const UObject *Context)
{
@@ -53,6 +71,96 @@ FVector2D AlxPlayerControllerBase::GetLookAtPixel(const UObject *Context)
return ScreenPosition;
}
void AlxPlayerControllerBase::BeginPlay()
{
Super::BeginPlay();
CharacterModeInput = NewObject<UInputComponent>(this);
CharacterModeInput->bBlockInput = false;
PushInputComponent(CharacterModeInput);
}
void AlxPlayerControllerBase::UpdateEventDispatch()
{
EventRequests.GarbageCollect();
// If we're in GameOnly mode, check that focus is still on the viewport.
if (CurrentInputMode == InputMode::GameOnly)
{
UGameViewportClient *GVC = GetWorld() ? GetWorld()->GetGameViewport() : nullptr;
if (GVC)
{
TSharedPtr<SViewport> ViewportWidget = GVC->GetGameViewportWidget();
if (ViewportWidget.IsValid())
{
TSharedPtr<SWidget> Focused = FSlateApplication::Get().GetKeyboardFocusedWidget();
if (Focused.Get() != ViewportWidget.Get())
{
UE_LOG(LogLuprexIntegration, Error, TEXT("In GameOnly mode, keyboard focus must stay on viewport, but was stolen by: %s. Restoring."), *GetUserWidgetName(Focused.Get()));
EventRequests.SetDirty();
}
if (!ViewportWidget->HasMouseCapture())
{
UE_LOG(LogLuprexIntegration, Error, TEXT("In GameOnly mode, viewport must have mouse capture, but lost it. Restoring."));
EventRequests.SetDirty();
}
}
}
}
if (!EventRequests.IsDirty()) return;
EventRequests.ClearDirty();
CurrentInputMode = EventRequests.GetRequestedMode();
const TArray<FlxEventRequest> &Requests = EventRequests.GetRequests();
if (CurrentInputMode == InputMode::UIOnly)
{
SetInputMode(FInputModeUIOnly().SetWidgetToFocus(Requests[0].Widget->GetCachedWidget()));
}
else
{
SetInputMode(FInputModeGameOnly());
CharacterModeInput->KeyBindings.Empty();
TSet<FKey> BoundKeys;
for (const FlxEventRequest &Req : Requests)
{
for (const FKey &Key : Req.Hotkeys)
{
if (!BoundKeys.Contains(Key))
{
BoundKeys.Add(Key);
CharacterModeInput->BindKey(Key, IE_Pressed, this, &AlxPlayerControllerBase::ForwardKeyEvent);
}
}
}
}
}
void AlxPlayerControllerBase::ForwardKeyEvent(FKey Key)
{
// TODO: implement
}
void AlxPlayerControllerBase::RequestEvents(const FlxEventRequest &Request)
{
if (!FlxEventRequests::SanityCheck(Request)) return;
AlxPlayerControllerBase *PC = FromContext(Request.Widget);
PC->EventRequests.Request(Request);
}
void AlxPlayerControllerBase::UnRequestEvents(UUserWidget *Widget)
{
if (Widget == nullptr)
{
UE_LOG(LogLuprexIntegration, Error, TEXT("UnRequestEvents called with null widget."));
return;
}
AlxPlayerControllerBase *PC = FromContext(Widget);
PC->EventRequests.Remove(Widget);
}
void AlxPlayerControllerBase::UpdateLookAt()
{
UlxTangibleManager *TM = GetGameInstance()->GetSubsystem<UlxTangibleManager>();