前言
在运行打包后的UE程序时,有时我们的电脑配置了多个显示器,想要在指定的显示器上运行我们的程序,当然可以在运行的时候通过鼠标拖拽窗口的方式到其他显示器上。也可以在程序初始化的时候通过设置运行窗口的起点位置的方式指定显示器,但是每次都需要我们自己计算每个显示器的起点位置。如果能直接指定其在某一个ID的显示器上运行就更方便了。于是可以通过枚举出某一个ID显示器的起点位置,再将其设置我们的UE窗口起点就行了。
虽然UE本身没有内置的方法来获取连接的显示器,但是可以通过不同平台的API来获取显示器的信息
一、Windows平台
1、在 Windows 上,可以使用 EnumDisplayMonitors 函数来枚举所有连接的显示器
添加必要的头文件(如果报错把2行和4行的也加上)
#include "Windows/AllowWindowsPlatformTypes.h"
//#include "Windows/PreWindowsApi.h"
#include <Windows.h>
//#include "Windows/PostWindowsApi.h"
#include "Windows/HideWindowsPlatformTypes.h"
枚举显示器并获取目标显示器的起点位置
FVector2D GetTargetMonitorPosition(int targetIndex)
{
HMONITOR targetMonitor = nullptr;
MONITORINFOEX monitorInfo;
monitorInfo.cbSize = sizeof(MONITORINFOEX);
auto MonitorEnumProc = [](HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor,
LPARAM dwData) -> BOOL
{
static int monitorIndex = 0;
if (monitorIndex == targetIndex)
{
MONITORINFOEX* pMonitorInfo = reinterpret_cast<MONITORINFOEX*>(dwData);
if (GetMonitorInfo(hMonitor, pMonitorInfo))
{
return FALSE; // 终止枚举
}
}
monitorIndex++;
return TRUE; // 继续枚举
};
EnumDisplayMonitors(nullptr, nullptr, MonitorEnumProc,
reinterpret_cast<LPARAM>(&monitorInfo));
return FVector2D(monitorInfo.rcMonitor.left, monitorInfo.rcMonitor.top);
}
2、在程序初始化的时候设置窗口运行的起点位置(包括全屏和非全屏时)
UGameUserSetting* gameSetting = GEngine->GetGameUserSettings();
//可以在电脑设置->系统->屏幕那里点击识别查看显示器的ID
int targetIndex = 3;//假设需要在第三个显示器上运行
//窗口化时窗口的分辨率
int windowWidth = 1280;
int windowHeight = 960;
if(FullScreen)//自己定义是否需要全屏
{
GEngine->GameViewport->GetWindow()->MoveWindowTo(GetTargetMonitorPosition(targetIndex));
gameSetting->SetFullScreenMode(EWindowMode::WindowedFullScreen);
gameSetting->ApplySettings(true);
}
else
{
gameSetting->SetFullScreenMode(EWindowMode::Windowed);
gameSetting->SetScreenResolution(FIntPoint(windowWidth, windowHeight));
GEngine->GameViewport->GetWindow()->MoveWindowTo(GetTargetMonitorPosition(targetIndex));
gameSetting->ApplySettings(true);
}
二 、Mac平台
1、在 Mac 上,可以使用 CoreGraphics 框架来获取连接的显示器信息
添加必要的头文件
#include <CoreGraphics/CoreGraphics.h>
枚举显示器
FVector2D GetTargetMonitorPosition(int targetIndex)
{
uint32_t displayCount;
CGGetActiveDisplayList(0, nullptr, &displayCount);
CGDirectDisplayID displays[displayCount];
CGGetActiveDisplayList(displayCount, displays, &displayCount);
if (targetIndex < displayCount)
{
CGRect displayBounds = CGDisplayBounds(displays[targetIndex]);
return FVector2D(displayBounds.origin.x, displayBounds.origin.y);
}
return FVector2D(0, 0); // 默认位置
}
2、设置窗口起点位置同上
三、Linux平台
1、在 Linux 上,可以使用 X11 库来获取显示器信息
安装libX11库
首先更新软件包列表
sudo apt update
安装X11库和X11扩展库
sudo apt install libx11-dev
sudo apt install libxrandr-dev
查询X11库的头文件位置
dpkg-query -L libx11-dev
dpkg-query -L libxrandr-dev
查询X11库文件的位置
sudo find / -name libX11.so
sudo find / -name libXrandr.so
并在你的项目配置文件projectname.Build.cs文件中链接该库
public projectname(ReadOnlyTargetRules Target): base(Target)
{
//配置文件里有这个函数,只需在这个函数里添加对库文件和头文件的包含路径
if(Target.Platform == UnrealTargetPlatform.Linux)
{
//通过之前的命令找到库文件和头文件的位置
PublicAdditionalLibraries.Add("/usr/lib/x86_64-linux-gnu/X11");//库文件
PublicAdditionalLibraries.Add("/usr/lib/x86_64-linux-gnu/Xrandr");
PublicIncludePaths.Add("/usr/include");//头文件
PublicIncludePaths.Add("/usr/include/X11");
}
}
添加必要的头文件
#paragma push_macro("None")//使用宏定义避免与UE源码产生冲突
#undef None
#include <X11/Xlib.h>
#include <X11/extensions/Xrandr.h>
#pargma pop_macro("None")
枚举显示器
FVector2D GetTargetMonitorPosition(int targetIndex)
{
Display* display = XOpenDisplay(nullptr);
if (display)
{
Window root = DefaultRootWindow(display);
XRRScreenResources* screenResources = XRRGetScreenResources(display, root);
if (screenResources)
{
if (targetIndex < screenResources->noutput)
{
XRROutputInfo* outputInfo = XRRGetOutputInfo(display,
screenResources, screenResources->outputs[targetIndex]);
if (outputInfo && outputInfo->connection == RR_Connected)
{
XRRCrtcInfo* crtcInfo = XRRGetCrtcInfo(display, screenResources,
outputInfo->crtc);
if (crtcInfo)
{
FVector2D TargetPosition(crtcInfo->x, crtcInfo->y);
XRRFreeCrtcInfo(crtcInfo);
XRRFreeOutputInfo(outputInfo);
XRRFreeScreenResources(screenResources);
XCloseDisplay(display);
return TargetPosition;
}
}
XRRFreeOutputInfo(outputInfo);
}
XRRFreeScreenResources(screenResources);
}
XCloseDisplay(display);
}
return FVector2D(0, 0); // 默认位置
}
2、设置窗口起点位置同上