From 510423abfe42bfe2aab812c377fbdaa6003a2d7c Mon Sep 17 00:00:00 2001 From: Steve Streeting Date: Thu, 29 Apr 2021 12:28:27 +0100 Subject: [PATCH] Improve the checking for game in foreground Instead of checking every imput event, check every 0.5s. Also expose the foregrounded boolean, and raise an event so other code can use this. --- .../Private/StevesGameSubsystem.cpp | 38 +++++++++++++------ .../Public/StevesGameSubsystem.h | 19 +++++++++- 2 files changed, 44 insertions(+), 13 deletions(-) diff --git a/Source/StevesUEHelpers/Private/StevesGameSubsystem.cpp b/Source/StevesUEHelpers/Private/StevesGameSubsystem.cpp index 5945102..b6c568f 100644 --- a/Source/StevesUEHelpers/Private/StevesGameSubsystem.cpp +++ b/Source/StevesUEHelpers/Private/StevesGameSubsystem.cpp @@ -15,7 +15,8 @@ void UStevesGameSubsystem::Initialize(FSubsystemCollectionBase& Collection) { Super::Initialize(Collection); CreateInputDetector(); - InitTheme(); + InitTheme(); + InitForegroundCheck(); } void UStevesGameSubsystem::Deinitialize() @@ -51,6 +52,30 @@ void UStevesGameSubsystem::InitTheme() DefaultUiTheme = LoadObject(nullptr, *DefaultUiThemePath, nullptr); } + +void UStevesGameSubsystem::InitForegroundCheck() +{ + // Check foreground status every 0.5 seconds + GetWorld()->GetTimerManager().SetTimer(ForegroundCheckHandle, this, &UStevesGameSubsystem::CheckForeground, 0.5); +} + +void UStevesGameSubsystem::CheckForeground() +{ + bool bNewForeground = bIsForeground; + + if (IsValid(GEngine) && IsValid(GEngine->GameViewport) && GEngine->GameViewport->Viewport) + bNewForeground = GEngine->GameViewport->Viewport->IsForegroundWindow(); + + if (bNewForeground != bIsForeground) + { + bIsForeground = bNewForeground; + InputDetector->bIgnoreEvents = !bIsForeground; + + OnWindowForegroundChanged.Broadcast(bIsForeground); + } + + +} void UStevesGameSubsystem::OnInputDetectorModeChanged(int PlayerIndex, EInputMode NewMode) { // We can't check this during Initialize because it's too early @@ -221,16 +246,7 @@ void UStevesGameSubsystem::SetBrushFromAtlas(FSlateBrush* Brush, TScriptInterfac bool UStevesGameSubsystem::FInputModeDetector::ShouldProcessInputEvents() const { - if (!bProcessEventsInBackground) - { - if (IsValid(GEngine) && IsValid(GEngine->GameViewport) && GEngine->GameViewport->Viewport) - return GEngine->GameViewport->Viewport->IsForegroundWindow(); - - // If we're not supposed to process in the background but there's no viewport, don't process - return false; - } - - return true; + return !bIgnoreEvents; } UStevesGameSubsystem::FInputModeDetector::FInputModeDetector() diff --git a/Source/StevesUEHelpers/Public/StevesGameSubsystem.h b/Source/StevesUEHelpers/Public/StevesGameSubsystem.h index 30a28be..c3a0137 100644 --- a/Source/StevesUEHelpers/Public/StevesGameSubsystem.h +++ b/Source/StevesUEHelpers/Public/StevesGameSubsystem.h @@ -12,6 +12,7 @@ #include "StevesGameSubsystem.generated.h" DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnInputModeChanged, int, PlayerIndex, EInputMode, InputMode); +DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnWindowForegroundChanged, bool, bFocussed); UCLASS(Config=Game) class STEVESUEHELPERS_API UStevesGameSubsystem : public UGameInstanceSubsystem @@ -68,8 +69,8 @@ protected: bool ShouldProcessInputEvents() const; public: - /// Whether this detector should process events when the application is in the background - bool bProcessEventsInBackground = false; + /// Whether this detector should ignore events (e.g. because the application is in the background) + bool bIgnoreEvents = false; // Single delegate caller, owner should propagate if they want (this isn't a UObject) FInternalInputModeChanged OnInputModeChanged; @@ -100,12 +101,20 @@ protected: FFocusSystem FocusSystem; bool bCheckedViewportClient = false; + FTimerHandle ForegroundCheckHandle; + + UPROPERTY(BlueprintReadOnly) + bool bIsForeground = true; + UPROPERTY(BlueprintReadWrite) UUiTheme* DefaultUiTheme; void CreateInputDetector(); void DestroyInputDetector(); void InitTheme(); + void InitForegroundCheck(); + void CheckForeground(); + // Called by detector void OnInputDetectorModeChanged(int PlayerIndex, EInputMode NewMode); @@ -118,6 +127,10 @@ public: UPROPERTY(BlueprintAssignable) FOnInputModeChanged OnInputModeChanged; + /// Event raised when the game window's foreground status changes + UPROPERTY(BlueprintAssignable) + FOnWindowForegroundChanged OnWindowForegroundChanged; + UFUNCTION(BlueprintCallable) EInputMode GetLastInputModeUsed(int PlayerIndex = 0) const { return InputDetector->GetLastInputMode(PlayerIndex); } @@ -134,6 +147,8 @@ public: /// Get the global focus system FFocusSystem* GetFocusSystem(); + /// Return whether the game is currently in the foreground + bool IsForeground() const { return bIsForeground; } /** * @brief Get an input button / key / axis image as a sprite based on any combination of action / axis binding or manual key