Behavior When Unfocused
I use UE4 for non-game purposes at work, often alongside other applications on Windows.
A common pattern is creating the display part with UE4 and a controller-like part with WPF, then using them together.
In this pattern, the focus inevitably goes to the WPF application, leaving the UE4 window unfocused.
This caused the following problems:
- Sound cannot be heard
- GamePad input cannot be captured
I couldn’t find solutions for these for a while, but after checking the Engine source, I found countermeasures for both, so I’m writing them down as a memo.
Note that the environment where I applied these measures was 4.24, but since the implementation in that part seems unchanged in 4.25, I believe the same measures should work (though I haven’t confirmed the operation in 4.25).
Sound Playback When Unfocused
I found the following description in WindowsPlatformApplicationMisc::PumpMessages
:
// if its our window, allow sound, otherwise apply multiplier
FApp::SetVolumeMultiplier( HasFocus ? 1.0f : FApp::GetUnfocusedVolumeMultiplier() );
It seems SetVolumeMultiplier
is a function to set the sound volume. Here, it uses 1.0 if focused, and the value of GetUnfocusedVolumeMultiplier
otherwise.
Checking the value returned by GetUnfocusedVolumeMultiplier
, it was 0.
That’s why I couldn’t hear anything.
However, I found that the initial value of this is taken from the Config.
static bool GUnfocusedVolumeMultiplierInitialised = false;
float FApp::GetUnfocusedVolumeMultiplier()
{
if (!GUnfocusedVolumeMultiplierInitialised)
{
GUnfocusedVolumeMultiplierInitialised = true;
GConfig->GetFloat(TEXT("Audio"), TEXT("UnfocusedVolumeMultiplier"), UnfocusedVolumeMultiplier, GEngineIni);
}
return UnfocusedVolumeMultiplier;
So, I wrote the following setting in Config/DefaultEngine.ini
to make the value of UnfocusedVolumeMultiplier
also 1.0 and confirmed the operation.
[Audio]
UnfocusedVolumeMultiplier=1.0
Success! Sound can now be heard even when unfocused.
GamePad Input When Unfocused
In UE4, GamePad input on Windows uses an API called XInput.
Searching from there, I found a class called XInputInterface
.
Checking its contents, it calls the XInput API, so it’s highly likely that this is where GamePad input is received.
Next, searching for where XInputInterface
is used, I found it’s used in FWindowsApplication
.
Then, it seems FWindowsApplication::PollGameDeviceState
fires the XInput input events.
Furthermore, this function is called from FSlateApplication::PollGameDeviceState()
.
Looking inside FSlateApplication::PollGameDeviceState()
, it’s guarded by an if statement.
if( ActiveModalWindows.Num() == 0 && !GIntraFrameDebuggingGameThread && (!bRequireFocusForGamepadInput || IsActive()))
{
// Don't poll when a modal window open or intra frame debugging is happening
PlatformApplication->PollGameDeviceState( GetDeltaTime() );
}
There are three conditions here, and the last one, IsActive()
, feels like it means having focus.
However, there’s a variable here, bRequireFocusForGamepadInput
, which seems directly related.
Checking its definition, it looked like the value could be changed via a console command.
static bool bRequireFocusForGamepadInput = false;
FAutoConsoleVariableRef CVarRequireFocusForGamepadInput(
TEXT("Slate.RequireFocusForGamepadInput"),
bRequireFocusForGamepadInput,
TEXT("")
);
For my work purposes, I use a development build, so I tried entering the above command using Ctrl+@, and I was able to get GamePad input even when unfocused.
However, typing it every time is tedious (calling it from BluePrint is an option, but I’d rather not if possible).
Doing a bit more research, it seems console commands can also be defined in an ini file, so I decided to go with that approach.
[UE4] Special Nature of ConsoleVariables.ini - Qiita
Summary
When a UE4 application loses focus, various things become impossible, but I managed to adjust it to behave as desired.
Being able to see the engine source makes this kind of investigation easier, which is really great!