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.
This commit is contained in:
Steve Streeting 2021-04-29 12:28:27 +01:00
parent a466ce6a71
commit 510423abfe
2 changed files with 44 additions and 13 deletions

View File

@ -15,7 +15,8 @@ void UStevesGameSubsystem::Initialize(FSubsystemCollectionBase& Collection)
{ {
Super::Initialize(Collection); Super::Initialize(Collection);
CreateInputDetector(); CreateInputDetector();
InitTheme(); InitTheme();
InitForegroundCheck();
} }
void UStevesGameSubsystem::Deinitialize() void UStevesGameSubsystem::Deinitialize()
@ -51,6 +52,30 @@ void UStevesGameSubsystem::InitTheme()
DefaultUiTheme = LoadObject<UUiTheme>(nullptr, *DefaultUiThemePath, nullptr); DefaultUiTheme = LoadObject<UUiTheme>(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) void UStevesGameSubsystem::OnInputDetectorModeChanged(int PlayerIndex, EInputMode NewMode)
{ {
// We can't check this during Initialize because it's too early // 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 bool UStevesGameSubsystem::FInputModeDetector::ShouldProcessInputEvents() const
{ {
if (!bProcessEventsInBackground) return !bIgnoreEvents;
{
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;
} }
UStevesGameSubsystem::FInputModeDetector::FInputModeDetector() UStevesGameSubsystem::FInputModeDetector::FInputModeDetector()

View File

@ -12,6 +12,7 @@
#include "StevesGameSubsystem.generated.h" #include "StevesGameSubsystem.generated.h"
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnInputModeChanged, int, PlayerIndex, EInputMode, InputMode); DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnInputModeChanged, int, PlayerIndex, EInputMode, InputMode);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnWindowForegroundChanged, bool, bFocussed);
UCLASS(Config=Game) UCLASS(Config=Game)
class STEVESUEHELPERS_API UStevesGameSubsystem : public UGameInstanceSubsystem class STEVESUEHELPERS_API UStevesGameSubsystem : public UGameInstanceSubsystem
@ -68,8 +69,8 @@ protected:
bool ShouldProcessInputEvents() const; bool ShouldProcessInputEvents() const;
public: public:
/// Whether this detector should process events when the application is in the background /// Whether this detector should ignore events (e.g. because the application is in the background)
bool bProcessEventsInBackground = false; bool bIgnoreEvents = false;
// Single delegate caller, owner should propagate if they want (this isn't a UObject) // Single delegate caller, owner should propagate if they want (this isn't a UObject)
FInternalInputModeChanged OnInputModeChanged; FInternalInputModeChanged OnInputModeChanged;
@ -100,12 +101,20 @@ protected:
FFocusSystem FocusSystem; FFocusSystem FocusSystem;
bool bCheckedViewportClient = false; bool bCheckedViewportClient = false;
FTimerHandle ForegroundCheckHandle;
UPROPERTY(BlueprintReadOnly)
bool bIsForeground = true;
UPROPERTY(BlueprintReadWrite) UPROPERTY(BlueprintReadWrite)
UUiTheme* DefaultUiTheme; UUiTheme* DefaultUiTheme;
void CreateInputDetector(); void CreateInputDetector();
void DestroyInputDetector(); void DestroyInputDetector();
void InitTheme(); void InitTheme();
void InitForegroundCheck();
void CheckForeground();
// Called by detector // Called by detector
void OnInputDetectorModeChanged(int PlayerIndex, EInputMode NewMode); void OnInputDetectorModeChanged(int PlayerIndex, EInputMode NewMode);
@ -118,6 +127,10 @@ public:
UPROPERTY(BlueprintAssignable) UPROPERTY(BlueprintAssignable)
FOnInputModeChanged OnInputModeChanged; FOnInputModeChanged OnInputModeChanged;
/// Event raised when the game window's foreground status changes
UPROPERTY(BlueprintAssignable)
FOnWindowForegroundChanged OnWindowForegroundChanged;
UFUNCTION(BlueprintCallable) UFUNCTION(BlueprintCallable)
EInputMode GetLastInputModeUsed(int PlayerIndex = 0) const { return InputDetector->GetLastInputMode(PlayerIndex); } EInputMode GetLastInputModeUsed(int PlayerIndex = 0) const { return InputDetector->GetLastInputMode(PlayerIndex); }
@ -134,6 +147,8 @@ public:
/// Get the global focus system /// Get the global focus system
FFocusSystem* GetFocusSystem(); 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 * @brief Get an input button / key / axis image as a sprite based on any combination of action / axis binding or manual key