// Preferred monitor (request of 2026-10-25): a setting in the graphics options // picks the monitor the game starts on; with none set, or the preferred one // not connected, the system's main monitor. // // The game window and its render size are decided when the display mode is // set at startup (borderless.cpp, widescreen.cpp ApplyRenderSize): both ask // GameMonitorRect. A change applies at the next start. // // Monitors are told apart by their device path (DisplayConfigGetDeviceInfo, // target name: "\\?\DISPLAY#GSM5B7F#..."), which survives restarts, monitor // order changes and other ports' changes, unlike the GDI names \\.\DISPLAYn. // // sacredK.ini: // [display] // Monitor= ; empty: the main monitor #include "mods/monitor.h" #include #include "re/config.h" #include "re/log.h" namespace mods::monitor { namespace { constexpr const char* kSection = "display"; constexpr const char* kKey = "Monitor"; std::string Utf8(const wchar_t* text) { const int size = WideCharToMultiByte(CP_UTF8, 0, text, -1, nullptr, 0, nullptr, nullptr); if (size <= 1) { return {}; } std::string result(static_cast(size - 1), '\0'); WideCharToMultiByte(CP_UTF8, 0, text, -1, result.data(), size, nullptr, nullptr); return result; } struct Target { std::wstring gdiName; // \\.\DISPLAYn of the source showing it std::string id; std::wstring name; }; // The active display paths: which monitor shows which GDI display. std::vector Targets() { UINT32 pathCount = 0; UINT32 modeCount = 0; std::vector paths; std::vector modes; LONG result; do { if (GetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &pathCount, &modeCount) != ERROR_SUCCESS) { return {}; } paths.resize(pathCount); modes.resize(modeCount); result = QueryDisplayConfig(QDC_ONLY_ACTIVE_PATHS, &pathCount, paths.data(), &modeCount, modes.data(), nullptr); } while (result == ERROR_INSUFFICIENT_BUFFER); if (result != ERROR_SUCCESS) { return {}; } paths.resize(pathCount); std::vector targets; for (const DISPLAYCONFIG_PATH_INFO& path : paths) { DISPLAYCONFIG_SOURCE_DEVICE_NAME source = {}; source.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME; source.header.size = sizeof(source); source.header.adapterId = path.sourceInfo.adapterId; source.header.id = path.sourceInfo.id; DISPLAYCONFIG_TARGET_DEVICE_NAME target = {}; target.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME; target.header.size = sizeof(target); target.header.adapterId = path.targetInfo.adapterId; target.header.id = path.targetInfo.id; if (DisplayConfigGetDeviceInfo(&source.header) != ERROR_SUCCESS || DisplayConfigGetDeviceInfo(&target.header) != ERROR_SUCCESS) { continue; } targets.push_back({source.viewGdiDeviceName, Utf8(target.monitorDevicePath), target.monitorFriendlyDeviceName}); } return targets; } BOOL CALLBACK AddMonitor(HMONITOR handle, HDC, LPRECT, LPARAM data) { auto* gdi = reinterpret_cast*>(data); MONITORINFOEXW info = {}; info.cbSize = sizeof(info); if (GetMonitorInfoW(handle, &info)) { gdi->push_back(info); } return TRUE; } } // namespace std::vector List() { std::vector gdi; EnumDisplayMonitors(nullptr, nullptr, &AddMonitor, reinterpret_cast(&gdi)); const std::vector targets = Targets(); std::vector monitors; for (const MONITORINFOEXW& info : gdi) { Monitor monitor{"", L"", info.rcMonitor, (info.dwFlags & MONITORINFOF_PRIMARY) != 0}; for (const Target& target : targets) { if (target.gdiName == info.szDevice) { // mirrored displays: the first monitor monitor.id = target.id; monitor.name = target.name; break; } } if (monitor.id.empty()) { monitor.id = Utf8(info.szDevice); // no display config (remote desktop, ...) } if (monitor.name.empty()) { monitor.name = L"Monitor " + std::to_wstring(monitors.size() + 1); } monitors.push_back(monitor); } std::stable_sort(monitors.begin(), monitors.end(), [](const Monitor& a, const Monitor& b) { return a.primary && !b.primary; }); return monitors; } std::string PreferredId() { return re::ConfigString(kSection, kKey, ""); } void SetPreferredId(const std::string& id) { re::SetConfigString(kSection, kKey, id.c_str()); } RECT GameMonitorRect() { const std::vector monitors = List(); const std::string preferred = PreferredId(); const Monitor* chosen = nullptr; for (const Monitor& monitor : monitors) { if ((!preferred.empty() && monitor.id == preferred) || (!chosen && monitor.primary)) { chosen = &monitor; } } if (!chosen) { // No monitor reported: the main monitor's rectangle as Windows has it. MONITORINFO info = {sizeof(info)}; GetMonitorInfoW(MonitorFromPoint({0, 0}, MONITOR_DEFAULTTOPRIMARY), &info); return info.rcMonitor; } const bool found = !preferred.empty() && chosen->id == preferred; static bool logged = false; if (!logged) { logged = true; re::Log("monitor: %ls %ldx%ld at (%ld,%ld)%s", chosen->name.c_str(), chosen->rect.right - chosen->rect.left, chosen->rect.bottom - chosen->rect.top, chosen->rect.left, chosen->rect.top, found ? "" : preferred.empty() ? ", main monitor" : ", preferred monitor not connected: main monitor"); } return chosen->rect; } } // namespace mods::monitor