diff --git a/DDrawCompat/Config/Config.cpp b/DDrawCompat/Config/Config.cpp index 049fb3e..1b33cc4 100644 --- a/DDrawCompat/Config/Config.cpp +++ b/DDrawCompat/Config/Config.cpp @@ -5,5 +5,6 @@ namespace Config Settings::CpuAffinity cpuAffinity; Settings::DesktopColorDepth desktopColorDepth; Settings::DisplayResolution displayResolution; + Settings::SupportedResolutions supportedResolutions; Settings::ThreadPriorityBoost threadPriorityBoost; } diff --git a/DDrawCompat/Config/Config.h b/DDrawCompat/Config/Config.h index 89649c6..84ef048 100644 --- a/DDrawCompat/Config/Config.h +++ b/DDrawCompat/Config/Config.h @@ -3,6 +3,7 @@ #include #include #include +#include #include namespace Config @@ -14,5 +15,6 @@ namespace Config extern Settings::CpuAffinity cpuAffinity; extern Settings::DesktopColorDepth desktopColorDepth; extern Settings::DisplayResolution displayResolution; + extern Settings::SupportedResolutions supportedResolutions; extern Settings::ThreadPriorityBoost threadPriorityBoost; } diff --git a/DDrawCompat/Config/EnumSetting.cpp b/DDrawCompat/Config/EnumSetting.cpp index 2546cf9..4e0f010 100644 --- a/DDrawCompat/Config/EnumSetting.cpp +++ b/DDrawCompat/Config/EnumSetting.cpp @@ -21,7 +21,7 @@ namespace namespace Config { - EnumSetting::EnumSetting(const std::string& name, unsigned default, const std::vector& enumNames) + EnumSetting::EnumSetting(const std::string& name, const std::string& default, const std::vector& enumNames) : MappedSetting(name, default, createMapping(enumNames)) { } diff --git a/DDrawCompat/Config/EnumSetting.h b/DDrawCompat/Config/EnumSetting.h index 525146a..7ec5896 100644 --- a/DDrawCompat/Config/EnumSetting.h +++ b/DDrawCompat/Config/EnumSetting.h @@ -9,6 +9,6 @@ namespace Config class EnumSetting : public MappedSetting { protected: - EnumSetting(const std::string& name, unsigned default, const std::vector& enumNames); + EnumSetting(const std::string& name, const std::string& default, const std::vector& enumNames); }; } diff --git a/DDrawCompat/Config/ListSetting.cpp b/DDrawCompat/Config/ListSetting.cpp index dd7dad1..0b3b8ac 100644 --- a/DDrawCompat/Config/ListSetting.cpp +++ b/DDrawCompat/Config/ListSetting.cpp @@ -4,16 +4,10 @@ namespace Config { ListSetting::ListSetting(const std::string& name, const std::string& default) - : Setting(name) - , m_default(default) + : Setting(name, default) { } - void ListSetting::resetValue() - { - setValue(m_default); - } - void ListSetting::setValue(const std::string& value) { std::vector values; diff --git a/DDrawCompat/Config/ListSetting.h b/DDrawCompat/Config/ListSetting.h index 8036b2c..57be3bb 100644 --- a/DDrawCompat/Config/ListSetting.h +++ b/DDrawCompat/Config/ListSetting.h @@ -11,11 +11,7 @@ namespace Config protected: ListSetting(const std::string& name, const std::string& default); - void resetValue() override; void setValue(const std::string& value) override; virtual void setValues(const std::vector& values) = 0; - - private: - std::string m_default; }; } diff --git a/DDrawCompat/Config/MappedSetting.h b/DDrawCompat/Config/MappedSetting.h index 651430e..43c1cb0 100644 --- a/DDrawCompat/Config/MappedSetting.h +++ b/DDrawCompat/Config/MappedSetting.h @@ -14,10 +14,9 @@ namespace Config Value get() const { return m_value; } protected: - MappedSetting(const std::string& name, Value default, const std::map& valueMapping) - : Setting(name) - , m_default(default) - , m_value(default) + MappedSetting(const std::string& name, const std::string& default, const std::map& valueMapping) + : Setting(name, default) + , m_value{} , m_valueMapping(valueMapping) { } @@ -34,11 +33,6 @@ namespace Config throw ParsingError("MappedSetting::getValueStr(): value not found in mapping"); } - void resetValue() override - { - m_value = m_default; - } - void setValue(const std::string& value) override { auto it = m_valueMapping.find(value); @@ -49,7 +43,6 @@ namespace Config m_value = it->second; } - Value m_default; Value m_value; const std::map m_valueMapping; }; diff --git a/DDrawCompat/Config/Setting.cpp b/DDrawCompat/Config/Setting.cpp index 4ac3ee4..7fc2fd0 100644 --- a/DDrawCompat/Config/Setting.cpp +++ b/DDrawCompat/Config/Setting.cpp @@ -3,28 +3,21 @@ namespace Config { - Setting::Setting(const std::string& name) + Setting::Setting(const std::string& name, const std::string& default) : m_name(name) + , m_default(default) { Parser::registerSetting(*this); } void Setting::reset() { - resetValue(); - m_source = "default"; + set("default", "default"); } void Setting::set(const std::string& value, const std::string& source) { - if ("default" == value) - { - resetValue(); - } - else - { - setValue(value); - } + setValue("default" == value ? m_default : value); m_source = source; } } diff --git a/DDrawCompat/Config/Setting.h b/DDrawCompat/Config/Setting.h index 4551a94..266835a 100644 --- a/DDrawCompat/Config/Setting.h +++ b/DDrawCompat/Config/Setting.h @@ -7,7 +7,7 @@ namespace Config class Setting { public: - Setting(const std::string& name); + Setting(const std::string& name, const std::string& default); Setting(const Setting&) = delete; Setting(Setting&&) = delete; @@ -23,11 +23,11 @@ namespace Config protected: virtual std::string getValueStr() const = 0; - virtual void resetValue() = 0; virtual void setValue(const std::string& value) = 0; private: std::string m_name; + std::string m_default; std::string m_source; }; } diff --git a/DDrawCompat/Config/Settings/DesktopColorDepth.h b/DDrawCompat/Config/Settings/DesktopColorDepth.h index f03d958..6182fbd 100644 --- a/DDrawCompat/Config/Settings/DesktopColorDepth.h +++ b/DDrawCompat/Config/Settings/DesktopColorDepth.h @@ -12,7 +12,7 @@ namespace Config static const UINT INITIAL = 0; DesktopColorDepth() - : MappedSetting("DesktopColorDepth", INITIAL, { {"initial", INITIAL}, {"8", 8}, {"16", 16}, {"32", 32} }) + : MappedSetting("DesktopColorDepth", "initial", { {"initial", INITIAL}, {"8", 8}, {"16", 16}, {"32", 32} }) { } }; diff --git a/DDrawCompat/Config/Settings/DisplayResolution.cpp b/DDrawCompat/Config/Settings/DisplayResolution.cpp index f71b4b6..d54d6bc 100644 --- a/DDrawCompat/Config/Settings/DisplayResolution.cpp +++ b/DDrawCompat/Config/Settings/DisplayResolution.cpp @@ -5,7 +5,7 @@ namespace Config namespace Settings { DisplayResolution::DisplayResolution() - : MappedSetting("DisplayResolution", DESKTOP, { {"app", APP}, {"desktop", DESKTOP} }) + : MappedSetting("DisplayResolution", "desktop", { {"app", APP}, {"desktop", DESKTOP} }) { } diff --git a/DDrawCompat/Config/Settings/SupportedResolutions.cpp b/DDrawCompat/Config/Settings/SupportedResolutions.cpp new file mode 100644 index 0000000..e98b37b --- /dev/null +++ b/DDrawCompat/Config/Settings/SupportedResolutions.cpp @@ -0,0 +1,37 @@ +#include +#include +#include + +namespace Config +{ + namespace Settings + { + SupportedResolutions::SupportedResolutions() + : ListSetting("SupportedResolutions", "native, 640x480, 800x600, 1024x768") + { + } + + std::string SupportedResolutions::getValueStr() const + { + std::string result; + for (const auto& res : m_resolutions) + { + result += ", "; + result += NATIVE == res ? "native" : std::to_string(res.cx) + 'x' + std::to_string(res.cy); + } + return result.substr(2); + } + + void SupportedResolutions::setValues(const std::vector& values) + { + std::set result; + for (const auto& v : values) + { + result.insert("native" == v ? NATIVE : Parser::parseResolution(v)); + } + m_resolutions = result; + } + + const SIZE SupportedResolutions::NATIVE = { 0, 0 }; + } +} diff --git a/DDrawCompat/Config/Settings/SupportedResolutions.h b/DDrawCompat/Config/Settings/SupportedResolutions.h new file mode 100644 index 0000000..59ebea2 --- /dev/null +++ b/DDrawCompat/Config/Settings/SupportedResolutions.h @@ -0,0 +1,29 @@ +#pragma once + +#include + +#include + +#include + +namespace Config +{ + namespace Settings + { + class SupportedResolutions : public ListSetting + { + public: + static const SIZE NATIVE; + + SupportedResolutions(); + + std::set get() const { return m_resolutions; } + + private: + std::string getValueStr() const override; + void setValues(const std::vector& values) override; + + std::set m_resolutions; + }; + } +} diff --git a/DDrawCompat/Config/Settings/ThreadPriorityBoost.h b/DDrawCompat/Config/Settings/ThreadPriorityBoost.h index a19e6ff..2276ba1 100644 --- a/DDrawCompat/Config/Settings/ThreadPriorityBoost.h +++ b/DDrawCompat/Config/Settings/ThreadPriorityBoost.h @@ -12,7 +12,7 @@ namespace Config enum Value { OFF, ON, MAIN, APP }; ThreadPriorityBoost() - : EnumSetting("ThreadPriorityBoost", OFF, { "off", "on", "main", "app" }) + : EnumSetting("ThreadPriorityBoost", "off", { "off", "on", "main", "app" }) { } }; diff --git a/DDrawCompat/DDrawCompat.vcxproj b/DDrawCompat/DDrawCompat.vcxproj index 9f0a31f..7cb5ea9 100644 --- a/DDrawCompat/DDrawCompat.vcxproj +++ b/DDrawCompat/DDrawCompat.vcxproj @@ -216,6 +216,7 @@ + @@ -320,6 +321,7 @@ + diff --git a/DDrawCompat/DDrawCompat.vcxproj.filters b/DDrawCompat/DDrawCompat.vcxproj.filters index ce3048c..8981b59 100644 --- a/DDrawCompat/DDrawCompat.vcxproj.filters +++ b/DDrawCompat/DDrawCompat.vcxproj.filters @@ -441,6 +441,9 @@ Header Files\Config\Settings + + Header Files\Config\Settings + @@ -692,6 +695,9 @@ Source Files\Gdi + + Source Files\Config\Settings + diff --git a/DDrawCompat/Win32/DisplayMode.cpp b/DDrawCompat/Win32/DisplayMode.cpp index d2f2796..cfca5d9 100644 --- a/DDrawCompat/Win32/DisplayMode.cpp +++ b/DDrawCompat/Win32/DisplayMode.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -22,6 +23,11 @@ namespace using Win32::DisplayMode::DisplayMode; using Win32::DisplayMode::EmulatedDisplayMode; + template struct DevModeType; + template <> struct DevModeType { typedef DEVMODEA Type; }; + template <> struct DevModeType { typedef DEVMODEW Type; }; + template using DevMode = typename DevModeType::Type; + template struct EnumParams { @@ -53,8 +59,8 @@ namespace BOOL WINAPI dwm8And16BitIsShimAppliedCallOut(); BOOL WINAPI seComHookInterface(CLSID* clsid, GUID* iid, DWORD unk1, DWORD unk2); - template - SIZE getConfiguredResolution(EnumDisplaySettingsExFunc origEnumDisplaySettingsEx, const Char* deviceName); + template + SIZE getConfiguredResolution(const Char* deviceName); template std::wstring getDeviceName(const Char* deviceName); @@ -62,9 +68,19 @@ namespace HMONITOR getMonitorFromDc(HDC dc); MONITORINFO getMonitorInfo(const std::wstring& deviceName); - template - std::vector getSupportedDisplayModes( - EnumDisplaySettingsExFunc origEnumDisplaySettingsEx, const Char* deviceName, DWORD flags); + template + std::map> getSupportedDisplayModeMap(const Char* deviceName, DWORD flags); + template + std::vector getSupportedDisplayModes(const Char* deviceName, DWORD flags); + + SIZE makeSize(DWORD width, DWORD height); + + LONG origChangeDisplaySettingsEx(LPCSTR lpszDeviceName, DEVMODEA* lpDevMode, HWND hwnd, DWORD dwflags, LPVOID lParam); + LONG origChangeDisplaySettingsEx(LPCWSTR lpszDeviceName, DEVMODEW* lpDevMode, HWND hwnd, DWORD dwflags, LPVOID lParam); + BOOL origEnumDisplaySettingsEx(LPCSTR lpszDeviceName, DWORD iModeNum, DEVMODEA* lpDevMode, DWORD dwFlags); + BOOL origEnumDisplaySettingsEx(LPCWSTR lpszDeviceName, DWORD iModeNum, DEVMODEW* lpDevMode, DWORD dwFlags); + + void setDwmDxFullscreenTransitionEvent(); void adjustMonitorInfo(MONITORINFO& mi) { @@ -80,27 +96,65 @@ namespace } } - template - LONG changeDisplaySettingsEx( - ChangeDisplaySettingsExFunc origChangeDisplaySettingsEx, - EnumDisplaySettingsExFunc origEnumDisplaySettingsEx, - CStr lpszDeviceName, DevMode* lpDevMode, HWND hwnd, DWORD dwflags, LPVOID lParam) + template + LONG changeDisplaySettingsEx(const Char* lpszDeviceName, typename DevMode* lpDevMode, HWND hwnd, DWORD dwflags, LPVOID lParam) { DDraw::ScopedThreadLock lock; - DevMode targetDevMode = {}; + DevMode targetDevMode = {}; + SIZE emulatedResolution = {}; if (lpDevMode) { + DevMode currDevMode = {}; + currDevMode.dmSize = sizeof(currDevMode); + enumDisplaySettingsEx(lpszDeviceName, ENUM_CURRENT_SETTINGS, &currDevMode, 0); + targetDevMode = *lpDevMode; + targetDevMode.dmFields |= DM_BITSPERPEL; targetDevMode.dmBitsPerPel = 32; - SIZE resolutionOverride = getConfiguredResolution(origEnumDisplaySettingsEx, lpszDeviceName); + if (!(targetDevMode.dmFields & DM_PELSWIDTH)) + { + targetDevMode.dmFields |= DM_PELSWIDTH; + targetDevMode.dmPelsWidth = currDevMode.dmPelsWidth; + } + if (!(targetDevMode.dmFields & DM_PELSHEIGHT)) + { + targetDevMode.dmFields |= DM_PELSHEIGHT; + targetDevMode.dmPelsHeight = currDevMode.dmPelsHeight; + } + + emulatedResolution = makeSize(targetDevMode.dmPelsWidth, targetDevMode.dmPelsHeight); + auto supportedDisplayModeMap(getSupportedDisplayModeMap(lpszDeviceName, 0)); + if (supportedDisplayModeMap.find(emulatedResolution) == supportedDisplayModeMap.end()) + { + if (!(dwflags & CDS_TEST)) + { + setDwmDxFullscreenTransitionEvent(); + } + return DISP_CHANGE_BADMODE; + } + + SIZE resolutionOverride = getConfiguredResolution(lpszDeviceName); if (0 != resolutionOverride.cx) { - targetDevMode.dmPelsWidth = resolutionOverride.cx; - targetDevMode.dmPelsHeight = resolutionOverride.cy; + DevMode dm = {}; + dm.dmSize = sizeof(dm); + dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT; + dm.dmPelsWidth = resolutionOverride.cx; + dm.dmPelsHeight = resolutionOverride.cy; + LONG result = origChangeDisplaySettingsEx(lpszDeviceName, &dm, nullptr, CDS_TEST, nullptr); + if (DISP_CHANGE_SUCCESSFUL == result) + { + targetDevMode.dmPelsWidth = resolutionOverride.cx; + targetDevMode.dmPelsHeight = resolutionOverride.cy; + } + else + { + LOG_ONCE("Failed to apply setting: DisplayResolution = " << dm.dmPelsWidth << 'x' << dm.dmPelsHeight); + } } } - DevMode prevDevMode = {}; + DevMode prevDevMode = {}; if (!(dwflags & CDS_TEST)) { prevDevMode.dmSize = sizeof(prevDevMode); @@ -111,14 +165,6 @@ namespace if (lpDevMode) { result = origChangeDisplaySettingsEx(lpszDeviceName, &targetDevMode, hwnd, dwflags, lParam); - if (DISP_CHANGE_SUCCESSFUL != result && - (lpDevMode->dmPelsWidth != targetDevMode.dmPelsWidth || lpDevMode->dmPelsHeight != targetDevMode.dmPelsHeight)) - { - LOG_ONCE("Failed to apply setting: DisplayResolution = " << targetDevMode.dmPelsWidth << 'x' << targetDevMode.dmPelsHeight); - targetDevMode.dmPelsWidth = lpDevMode->dmPelsWidth; - targetDevMode.dmPelsHeight = lpDevMode->dmPelsHeight; - result = origChangeDisplaySettingsEx(lpszDeviceName, &targetDevMode, hwnd, dwflags, lParam); - } } else { @@ -130,16 +176,13 @@ namespace return result; } - DevMode currDevMode = {}; + DevMode currDevMode = {}; currDevMode.dmSize = sizeof(currDevMode); origEnumDisplaySettingsEx(lpszDeviceName, ENUM_CURRENT_SETTINGS, &currDevMode, 0); if (0 == memcmp(&currDevMode, &prevDevMode, sizeof(currDevMode))) { - HANDLE dwmDxFullScreenTransitionEvent = OpenEventW( - EVENT_MODIFY_STATE, FALSE, L"DWM_DX_FULLSCREEN_TRANSITION_EVENT"); - SetEvent(dwmDxFullScreenTransitionEvent); - CloseHandle(dwmDxFullScreenTransitionEvent); + setDwmDxFullscreenTransitionEvent(); } if (DISP_CHANGE_SUCCESSFUL != result) @@ -152,9 +195,12 @@ namespace ++g_displaySettingsUniquenessBias; if (lpDevMode) { - g_emulatedDisplayMode.width = lpDevMode->dmPelsWidth; - g_emulatedDisplayMode.height = lpDevMode->dmPelsHeight; - g_emulatedDisplayMode.bpp = lpDevMode->dmBitsPerPel; + g_emulatedDisplayMode.width = emulatedResolution.cx; + g_emulatedDisplayMode.height = emulatedResolution.cy; + if (lpDevMode->dmFields & DM_BITSPERPEL) + { + g_emulatedDisplayMode.bpp = lpDevMode->dmBitsPerPel; + } g_emulatedDisplayMode.refreshRate = currDevMode.dmDisplayFrequency; g_emulatedDisplayMode.deviceName = getDeviceName(lpszDeviceName); @@ -171,11 +217,10 @@ namespace } } - auto& dm = lpDevMode ? *lpDevMode : currDevMode; - LPARAM resolution = (dm.dmPelsHeight << 16) | dm.dmPelsWidth; - EnumWindows(sendDisplayChange, resolution); + SIZE res = lpDevMode ? emulatedResolution : makeSize(currDevMode.dmPelsWidth, currDevMode.dmPelsHeight); + EnumWindows(sendDisplayChange, (res.cy << 16) | res.cx); - SetCursorPos(currDevMode.dmPosition.x + dm.dmPelsWidth / 2, currDevMode.dmPosition.y + dm.dmPelsHeight / 2); + SetCursorPos(currDevMode.dmPosition.x + res.cx / 2, currDevMode.dmPosition.y + res.cy / 2); Gdi::VirtualScreen::update(); return result; @@ -185,20 +230,14 @@ namespace LPCSTR lpszDeviceName, DEVMODEA* lpDevMode, HWND hwnd, DWORD dwflags, LPVOID lParam) { LOG_FUNC("ChangeDisplaySettingsExA", lpszDeviceName, lpDevMode, hwnd, dwflags, lParam); - return LOG_RESULT(changeDisplaySettingsEx( - CALL_ORIG_FUNC(ChangeDisplaySettingsExA), - CALL_ORIG_FUNC(EnumDisplaySettingsExA), - lpszDeviceName, lpDevMode, hwnd, dwflags, lParam)); + return LOG_RESULT(changeDisplaySettingsEx(lpszDeviceName, lpDevMode, hwnd, dwflags, lParam)); } LONG WINAPI changeDisplaySettingsExW( LPCWSTR lpszDeviceName, DEVMODEW* lpDevMode, HWND hwnd, DWORD dwflags, LPVOID lParam) { LOG_FUNC("ChangeDisplaySettingsExW", lpszDeviceName, lpDevMode, hwnd, dwflags, lParam); - return LOG_RESULT(changeDisplaySettingsEx( - CALL_ORIG_FUNC(ChangeDisplaySettingsExW), - CALL_ORIG_FUNC(EnumDisplaySettingsExW), - lpszDeviceName, lpDevMode, hwnd, dwflags, lParam)); + return LOG_RESULT(changeDisplaySettingsEx(lpszDeviceName, lpDevMode, hwnd, dwflags, lParam)); } void disableDwm8And16BitMitigation() @@ -223,9 +262,8 @@ namespace return LOG_RESULT(FALSE); } - template - BOOL enumDisplaySettingsEx(EnumDisplaySettingsExFunc origEnumDisplaySettingsEx, - const Char* lpszDeviceName, DWORD iModeNum, DevMode* lpDevMode, DWORD dwFlags) + template + BOOL enumDisplaySettingsEx(const Char* lpszDeviceName, DWORD iModeNum, DevMode* lpDevMode, DWORD dwFlags) { if (ENUM_REGISTRY_SETTINGS == iModeNum || !lpDevMode) { @@ -259,7 +297,7 @@ namespace if (0 == iModeNum || displayModes.empty() || currentEnumParams != lastEnumParams) { - displayModes = getSupportedDisplayModes(origEnumDisplaySettingsEx, lpszDeviceName, dwFlags); + displayModes = getSupportedDisplayModes(lpszDeviceName, dwFlags); lastEnumParams = currentEnumParams; } @@ -291,16 +329,14 @@ namespace LPCSTR lpszDeviceName, DWORD iModeNum, DEVMODEA* lpDevMode, DWORD dwFlags) { LOG_FUNC("EnumDisplaySettingsExA", lpszDeviceName, iModeNum, lpDevMode, dwFlags); - return LOG_RESULT(enumDisplaySettingsEx(CALL_ORIG_FUNC(EnumDisplaySettingsExA), - lpszDeviceName, iModeNum, lpDevMode, dwFlags)); + return LOG_RESULT(enumDisplaySettingsEx(lpszDeviceName, iModeNum, lpDevMode, dwFlags)); } BOOL WINAPI enumDisplaySettingsExW( LPCWSTR lpszDeviceName, DWORD iModeNum, DEVMODEW* lpDevMode, DWORD dwFlags) { LOG_FUNC("EnumDisplaySettingsExW", lpszDeviceName, iModeNum, lpDevMode, dwFlags); - return LOG_RESULT(enumDisplaySettingsEx(CALL_ORIG_FUNC(EnumDisplaySettingsExW), - lpszDeviceName, iModeNum, lpDevMode, dwFlags)); + return LOG_RESULT(enumDisplaySettingsEx(lpszDeviceName, iModeNum, lpDevMode, dwFlags)); } ULONG WINAPI gdiEntry13() @@ -309,13 +345,13 @@ namespace return CALL_ORIG_FUNC(GdiEntry13)() + g_displaySettingsUniquenessBias; } - template - SIZE getConfiguredResolution(EnumDisplaySettingsExFunc origEnumDisplaySettingsEx, const Char* deviceName) + template + SIZE getConfiguredResolution(const Char* deviceName) { auto resolution = Config::displayResolution.get(); if (Config::Settings::DisplayResolution::DESKTOP == resolution) { - DevMode dm = {}; + DevMode dm = {}; dm.dmSize = sizeof(dm); if (origEnumDisplaySettingsEx(deviceName, ENUM_REGISTRY_SETTINGS, &dm, 0)) { @@ -497,61 +533,75 @@ namespace return LOG_RESULT(result); } - template - std::vector getSupportedDisplayModes( - EnumDisplaySettingsExFunc origEnumDisplaySettingsEx, const Char* deviceName, DWORD flags) + template + std::map> getSupportedDisplayModeMap(const Char* deviceName, DWORD flags) { - std::set displayModes; - DWORD modeNum = 0; - DevMode dm = {}; - dm.dmSize = sizeof(dm); + std::map> nativeDisplayModeMap; + DWORD modeNum = 0; + DevMode dm = {}; + dm.dmSize = sizeof(dm); while (origEnumDisplaySettingsEx(deviceName, modeNum, &dm, flags)) { if (32 == dm.dmBitsPerPel) { - displayModes.insert({ dm.dmPelsWidth, dm.dmPelsHeight, dm.dmBitsPerPel, dm.dmDisplayFrequency }); + nativeDisplayModeMap[makeSize(dm.dmPelsWidth, dm.dmPelsHeight)].insert(dm.dmDisplayFrequency); } ++modeNum; } - auto resolutionOverride = getConfiguredResolution(origEnumDisplaySettingsEx, deviceName); - if (0 == resolutionOverride.cx) + const auto& supportedResolutions = Config::supportedResolutions.get(); + std::map> displayModeMap; + if (supportedResolutions.find(Config::Settings::SupportedResolutions::NATIVE) != supportedResolutions.end()) { - return { displayModes.begin(), displayModes.end() }; + displayModeMap = nativeDisplayModeMap; } - std::set supportedRefreshRates; - for (const auto& mode : displayModes) + const auto resolutionOverride = getConfiguredResolution(deviceName); + const auto it = nativeDisplayModeMap.find({ resolutionOverride.cx, resolutionOverride.cy }); + if (it != nativeDisplayModeMap.end()) { - if (static_cast(mode.width) == resolutionOverride.cx && - static_cast(mode.height) == resolutionOverride.cy) + for (auto& v : displayModeMap) { - supportedRefreshRates.insert(mode.refreshRate); + v.second = it->second; } } - if (supportedRefreshRates.empty()) + for (auto& v : supportedResolutions) { - return { displayModes.begin(), displayModes.end() }; - } - - std::vector customDisplayModes; - DWORD prevWidth = 0; - DWORD prevHeight = 0; - for (const auto& mode : displayModes) - { - if (mode.width != prevWidth || mode.height != prevHeight) + if (v != Config::Settings::SupportedResolutions::NATIVE) { - for (auto refreshRate : supportedRefreshRates) + if (it != nativeDisplayModeMap.end()) { - customDisplayModes.push_back({ mode.width, mode.height, mode.bpp, refreshRate }); + displayModeMap[{ v.cx, v.cy }] = it->second; + } + else + { + auto iter = nativeDisplayModeMap.find({ v.cx, v.cy }); + if (iter != nativeDisplayModeMap.end()) + { + displayModeMap.insert(*iter); + } } - prevWidth = mode.width; - prevHeight = mode.height; } } - return customDisplayModes; + + return displayModeMap; + } + + template + std::vector getSupportedDisplayModes(const Char* deviceName, DWORD flags) + { + auto displayModeMap(getSupportedDisplayModeMap(deviceName, flags)); + std::vector displayModeVector; + for (const auto& v : displayModeMap) + { + for (const auto& r : v.second) + { + displayModeVector.push_back({ static_cast(v.first.cx), static_cast(v.first.cy), 32, r }); + } + } + return displayModeVector; } BOOL CALLBACK initMonitor(HMONITOR hMonitor, HDC /*hdcMonitor*/, LPRECT /*lprcMonitor*/, LPARAM /*dwData*/) @@ -577,6 +627,31 @@ namespace return TRUE; } + SIZE makeSize(DWORD width, DWORD height) + { + return { static_cast(width), static_cast(height) }; + } + + LONG origChangeDisplaySettingsEx(LPCSTR lpszDeviceName, DEVMODEA* lpDevMode, HWND hwnd, DWORD dwflags, LPVOID lParam) + { + return CALL_ORIG_FUNC(ChangeDisplaySettingsExA)(lpszDeviceName, lpDevMode, hwnd, dwflags, lParam); + } + + LONG origChangeDisplaySettingsEx(LPCWSTR lpszDeviceName, DEVMODEW* lpDevMode, HWND hwnd, DWORD dwflags, LPVOID lParam) + { + return CALL_ORIG_FUNC(ChangeDisplaySettingsExW)(lpszDeviceName, lpDevMode, hwnd, dwflags, lParam); + } + + BOOL origEnumDisplaySettingsEx(LPCSTR lpszDeviceName, DWORD iModeNum, DEVMODEA* lpDevMode, DWORD dwFlags) + { + return CALL_ORIG_FUNC(EnumDisplaySettingsExA)(lpszDeviceName, iModeNum, lpDevMode, dwFlags); + } + + BOOL origEnumDisplaySettingsEx(LPCWSTR lpszDeviceName, DWORD iModeNum, DEVMODEW* lpDevMode, DWORD dwFlags) + { + return CALL_ORIG_FUNC(EnumDisplaySettingsExW)(lpszDeviceName, iModeNum, lpDevMode, dwFlags); + } + BOOL WINAPI seComHookInterface(CLSID* clsid, GUID* iid, DWORD unk1, DWORD unk2) { LOG_FUNC("SE_COM_HookInterface", clsid, iid, unk1, unk2); @@ -597,6 +672,17 @@ namespace } return TRUE; } + + void setDwmDxFullscreenTransitionEvent() + { + HANDLE dwmDxFullscreenTransitionEvent = OpenEventW( + EVENT_MODIFY_STATE, FALSE, L"DWM_DX_FULLSCREEN_TRANSITION_EVENT"); + if (dwmDxFullscreenTransitionEvent) + { + SetEvent(dwmDxFullscreenTransitionEvent); + CloseHandle(dwmDxFullscreenTransitionEvent); + } + } } namespace Win32