Is it possible to choose the default screen in a multi monitor configuration?

Hi all!

I’m working on a project that requires a fullscreen window to appear in a specific monitor.

My question is: Is it possible (via C++ or Blueprint) to detect how many monitors are being used and set a default monitor in which the program will appear when launched?

An example of what is pretended is, while using a triple-monitor configuration, making the application launch in fullscreen mode in the right monitor.

Thanks in advance for all the help :slight_smile:

In C++ you got this:

https://docs.unrealengine.com/latest/INT/API/Runtime/Core/GenericPlatform/FDisplayMetrics/index.html

First you call this to get the metrics:

FDisplayMetrics Display;
FDisplayMetrics::GetDisplayMetrics(Display);

And then you check how many moniters there is by checking MonitorInfo array size with Display.MonitorInfo.Num()

2 Likes

As far as I can tell Unreal does not support this natively, but it would be platform specific.

On windows you should be able to use the info here:

https://www.microsoft.com/msj/0697/monitor/monitor.aspx

Essentially what you do is you enumerate all your monitors, find the one you want, and then move your application to there and maximize it.

edit:

Looking in WindowsWindow.cpp, you probably want to write a function very similar to GetFullScreenInfo that just enumerates the windows instead of using a rectangle and then gets the corresponding data from it, then use MoveWindowTo to move the window to there and MAximize to biggify it.

UE4 got huge set of platfrom specific function wrappers, specially made so it’s easy to make your game portable (well technily it was made to make engine portable :p):

I was looking for something like that, but couldn’t figure out where EnumDisplayDevices was hooked up to something generic. The spot in your answer looks like that spot. :stuck_out_tongue:

Thanks for all the help. I found a really simple solution for this problem. Here’s the source code if anyone comes across the same situation :wink:

// Move window to the corresponding monitor
if (GEngine && GEngine->GameViewport) {
	
	int MonitorNumber = 1;
	FParse::Value(FCommandLine::Get(), L"monitor=", MonitorNumber);
	
	FDisplayMetrics Display;
	FDisplayMetrics::GetDisplayMetrics(Display);

	int8 MonitorIndex = MonitorNumber - 1;
	int32 CurrentMonitorWidth = Display.MonitorInfo[MonitorIndex].NativeWidth;
	
	float WidthPosition = (MonitorIndex)*Display.PrimaryDisplayWidth - CurrentMonitorWidth;

	float HeightPosition = 0.0f;

	FVector2D WindowPosition = FVector2D(WidthPosition, 0.f);
	GEngine->GameViewport->GetWindow()->MoveWindowTo(WindowPosition);
}
2 Likes

As you are creating your game to run on 3 monitors You are using a Multiplayer scheme ???
Or this opening the windows as viewports

You could specify the schema that vc this using to open the windows?

Is there any way you can communicate this functionality to a blueprint user? I’m trying my best to understand this, and I get it for the most part - but I’ve only been able to teach myself blueprint and don’t know where to put this code, how to call it, or anything like that when it comes to building my came to run on a non-primary monitor.

Hello, I’m trying to use this code, but since unreal made some changes in c++, i getting this error when I compile:

error LNK2019: unresolved external symbol “__declspec(dllimport) public: static void __cdecl FDisplayMetrics::GetDisplayMetrics(struct FDisplayMetrics &)” (_imp?GetDisplayMetrics@FDisplayMetrics@@SAXAEAU1@@Z) referenced in function “protected: virtual void __cdecl UDisplaySettings::BeginPlay(void)” (?Beg
inPlay@UDisplaySettings@@MEAAXXZ)

I’ve already Include the “Engine.h” and “GenericApplication.h”, but still no success.
Can you help me? I can’t find a solution anywhere.

1 Like

I think all the answers here are incomplete as they assume the following:

  • user has all monitors with the same resolution
  • monitors are aligned from left to right
  • runs only on windows (on linux apparently it does not work properly only in windowed mode)
  • destination monitor also has a native resolution larger or equal to the game resolution

The only information you need is from FMonitorInfo.WorkArea Left/Top.

FDisplayMetrics Display;
FDisplayMetrics::GetDisplayMetrics(Display);
    
// Start on the main display by default
int32 MonitorNumber = 0;
FParse::Value(FCommandLine::Get(), TEXT("monitor="), MonitorNumber);

// Get the correct monitor index
int32 MonitorIndex = INDEX_NONE;
if (MonitorNumber == 0)
{
    // Start monitor on the main screen
    for (int32 Index = 0; Index < DisplayMetrics.MonitorInfo.Num(); Index++)
    {
        if (DisplayMetrics.MonitorInfo[Index].bIsPrimary)
        {
            MonitorIndex = Index;
            break;
        }
    }
}
else
{
    // Normalize
    MonitorIndex = MonitorNumber - 1;
}
 
if (DisplayMetrics.MonitorInfo.IsValidIndex(MonitorIndex))
{
	const FMonitorInfo Monitor = DisplayMetrics.MonitorInfo[MonitorIndex];
    // check if UserSettings.ResolutionSizeX > Monitor.NativeWidth || UserSettings.ResolutionSizeY > Monitor.NativeHeight
    // if true then change your game resolution to Monitor.NativeWidth, Monitor.NativeHeight

    const int32 WindowPosX = Monitor.WorkArea.Left;
	const int32 WindowPosY = Monitor.WorkArea.Top;
    const FVector2D Position(static_cast<float>(WindowPosX), static_cast<float>(WindowPosY));

    if (GEngine && GEngine->GameViewport)
    {
        TSharedPtr<SWindow> Window = GEngine->GameViewport->GetWindow();

        // Hack for linux
#if PLATFORM_LINUX
       const EWindowMode::Type CurrentWindowMode = Window->GetWindowMode();
       Window->SetWindowMode(EWindowMode::Windowed);
#endif

        Window->MoveWindowTo(Position);

#if PLATFORM_LINUX
        // Set back to original
        Window->SetWindowMode(CurrentWindowMode);
#endif
    }
}
3 Likes

I too am stuck with the “unresolved external symbol” error in the 4.19.2 version.

EDIT: I needed to include the following headers:

  • include “GenericApplication.h”
  • include “SWindow.h”

And add the following modules in my project’s Build.cs file:

  • ApplicationCore
  • SlateCore
1 Like

Perfect, thank you. This is the complete answer!

How would I get the current (active) Display Index ?

It is explained in the answer
// Start monitor on the main screen

@henriquebach ,FDisplayMetrics is in module “ ApplicationCore“ with link:(ApplicationCore | Unreal Engine Documentation),you should add “ ApplicationCore“ to your xxx.build.cs

Hey, I noticed a lot of people have this problem.
Let’s brake it down to a simple digestible bits:

  1. How to call c++ code (function) in blueprint:
    I assume you can learn c++ class structure on your own.
    Function in *.h file can be prefixed with UFUNCTION() macro with certain parameters in prentices. It looks like this:

UCLASS(Blueprintable)
class MODULE_API UMyObject : public UObject
{
GENERATED_BODY()
public:

UFUNCTION(BlueprintCallable, Category = "my functions")
void MyCppFunctionWithExecutionFlow();

   UFUNCTION(BlueprintPure, Category = "my functions")
void MyCppFunctionWithoutExecutionFlow();

};
now it blueprint our object UMyObject instance will have both MyCppFunctionWithExecutionFlow and MyCppFunctionWithoutExecutionFlow.

2 where to put the code. I recommend to create plugin as BlueprintFunctionLibrary and store all such code there
Plugin is very easy to create from UEeditor->edit-> plugins ->Add. you’ll get something like this
UCLASS()
class UBFLTestBPLibrary : public UBlueprintFunctionLibrary
{
GENERATED_UCLASS_BODY()

UFUNCTION(BlueprintCallable, meta = (DisplayName = "Execute Sample function", Keywords = "BFLTest sample test testing"), Category = "BFLTestTesting")
static float BFLTestSampleFunction(float Param);

};

noticed that in *.h file return value of functions prefixed with keyword “static” this mean that in order to call this function you do not need instance of object it is implemented in.

you can create any function this way as long as these functions does not need to store data between calls (this is very simplistic).

3 Modules. Functionality in UE divided into modules and in order to asscess it you need to include module you need in *.Build.cs with located in plugin source folder. Module name can be found in ue documentation.

public class BFLTest : ModuleRules
{
public BFLTest(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;

	PublicIncludePaths.AddRange(
		new string[] {
			// ... add public include paths required here ...
		}
		);
			
	
	PrivateIncludePaths.AddRange(
		new string[] {
			// ... add other private include paths required here ...
		}
		);
		
	
	PublicDependencyModuleNames.AddRange(
		new string[]
		{
			"Core",
			// ... add other public dependencies that you statically link with here ...
		}
		);
		
	
	PrivateDependencyModuleNames.AddRange(
		new string[]
		{
			"CoreUObject",
			"Engine",
			"Slate",
			"SlateCore",
			// ... add private dependencies that you statically link with here ...	
		}
		);
	
	
	DynamicallyLoadedModuleNames.AddRange(
		new string[]
		{
			// ... add any modules that your module loads dynamically here ...
		}
		);
}

}

after adding module and relevant includes better to clean derivative data and regenerate vs/xcode project and recompile it.

Of course it is much more to this and it might not work from first attempt but this is better than nothing.

you can help me with this problem, please.