1
0
mirror of https://github.com/narzoul/DDrawCompat synced 2024-12-30 08:55:36 +01:00

Improved support for DPI unaware apps

This commit is contained in:
narzoul 2023-10-15 16:01:44 +02:00
parent a9ec2bbe7c
commit 97805b17b6
37 changed files with 775 additions and 511 deletions

View File

@ -12,6 +12,11 @@ struct RectF
namespace Rect
{
inline SIZE getSize(const RECT& rect)
{
return { rect.right - rect.left, rect.bottom - rect.top };
}
RectF toRectF(const RECT& rect);
bool isEqualSize(const RECT& rect1, const RECT& rect2);
void transform(RECT& rect, const RECT& srcView, const RECT& dstView);

View File

@ -4,6 +4,7 @@
#include <Common/Comparison.h>
#include <Common/CompatVtable.h>
#include <Common/Rect.h>
#include <Config/Settings/Antialiasing.h>
#include <Config/Settings/DisplayAspectRatio.h>
#include <Config/Settings/PalettizedTextures.h>
@ -63,23 +64,23 @@ namespace D3dDdi
{
}
Int2 Adapter::getAspectRatio(Win32::DisplayMode::Resolution res) const
Int2 Adapter::getAspectRatio(SIZE appRes, SIZE displayRes) const
{
SIZE ar = Config::displayAspectRatio.get();
if (Config::Settings::DisplayAspectRatio::APP == ar)
{
return 0 != res.app.cx ? res.app : Win32::DisplayMode::getAppResolution(m_deviceName);
return 0 != appRes.cx ? appRes : Rect::getSize(Win32::DisplayMode::getMonitorInfo(m_deviceName).rcEmulated);
}
else if (Config::Settings::DisplayAspectRatio::DISPLAY == ar)
{
return 0 != res.display.cx ? res.display : Win32::DisplayMode::getDisplayResolution(m_deviceName);
return 0 != displayRes.cx ? displayRes : Rect::getSize(Win32::DisplayMode::getMonitorInfo(m_deviceName).rcReal);
}
return ar;
}
Int2 Adapter::getAspectRatio() const
{
return getAspectRatio({});
return getAspectRatio({}, {});
}
const Adapter::AdapterInfo& Adapter::findInfo() const
@ -253,20 +254,23 @@ namespace D3dDdi
return 1;
}
const auto res = Win32::DisplayMode::getResolution(m_deviceName);
const auto& mi = Win32::DisplayMode::getMonitorInfo(m_deviceName);
auto displayRes = Rect::getSize(mi.rcReal);
auto appRes = Rect::getSize(mi.isEmulated ? mi.rcEmulated : mi.rcReal);
Int2 targetResolution = resolutionScale;
if (Config::Settings::ResolutionScale::APP == resolutionScale)
{
targetResolution = res.app;
targetResolution = appRes;
}
else if (Config::Settings::ResolutionScale::DISPLAY == resolutionScale)
{
targetResolution = res.display;
targetResolution = displayRes;
}
targetResolution *= abs(multiplier);
const Int2 ar = getAspectRatio(res);
const Int2 ar = getAspectRatio(appRes, displayRes);
if (targetResolution.y * ar.x / ar.y <= targetResolution.x)
{
targetResolution.x = targetResolution.y * ar.x / ar.y;
@ -276,7 +280,7 @@ namespace D3dDdi
targetResolution.y = targetResolution.x * ar.y / ar.x;
}
const auto scaleFactor = Float2(targetResolution) / Float2(res.app);
const auto scaleFactor = Float2(targetResolution) / Float2(appRes);
return multiplier < 0 ? scaleFactor : ceil(scaleFactor);
}

View File

@ -38,6 +38,7 @@ namespace D3dDdi
Int2 getAspectRatio() const;
const AdapterInfo& getInfo() const { return m_info; }
LUID getLuid() const { return m_luid; }
const auto& getMonitorInfo() const { return Win32::DisplayMode::getMonitorInfo(m_deviceName); }
std::pair<D3DDDIMULTISAMPLE_TYPE, UINT> getMultisampleConfig(D3DDDIFORMAT format) const;
const D3DDDI_ADAPTERFUNCS& getOrigVtable() const { return m_origVtable; }
CompatWeakPtr<IDirectDraw7> getRepository() const { return m_repository; }
@ -58,7 +59,7 @@ namespace D3dDdi
template <typename Data>
HRESULT getCaps(D3DDDICAPS_TYPE type, Data& data, UINT size = sizeof(Data)) const;
Int2 getAspectRatio(Win32::DisplayMode::Resolution res) const;
Int2 getAspectRatio(SIZE appRes, SIZE displayRes) const;
std::map<D3DDDIFORMAT, FORMATOP> getFixedFormatOps(const AdapterInfo& info) const;
std::map<D3DDDIFORMAT, FORMATOP> getFormatOps() const;
Float2 getScaleFactor() const;

View File

@ -19,6 +19,7 @@
#include <Gdi/Palette.h>
#include <Gdi/Window.h>
#include <Win32/DisplayMode.h>
#include <Win32/DpiAwareness.h>
namespace
{
@ -310,7 +311,7 @@ namespace
MONITORINFOEX mi = {};
mi.cbSize = sizeof(mi);
GetMonitorInfo(MonitorFromPoint({}, MONITOR_DEFAULTTOPRIMARY), &mi);
CALL_ORIG_FUNC(GetMonitorInfoA)(MonitorFromPoint({}, MONITOR_DEFAULTTOPRIMARY), &mi);
D3DKMT_OPENADAPTERFROMHDC data = {};
data.hDc = CreateDC(mi.szDevice, mi.szDevice, nullptr, nullptr);
@ -374,11 +375,11 @@ namespace D3dDdi
HWND presentationWindow = DDraw::RealPrimarySurface::getPresentationWindow();
if (presentationWindow && presentationWindow == data.hWindow)
{
rect = DDraw::RealPrimarySurface::getMonitorRect();
Win32::ScopedDpiAwareness dpiAwareness;
GetWindowRect(presentationWindow, &rect);
OffsetRect(&rect, -rect.left, -rect.top);
data.SrcRect = rect;
data.DstRect.right = data.DstRect.left + rect.right;
data.DstRect.bottom = data.DstRect.top + rect.bottom;
data.DstRect = rect;
if (1 == data.SubRectCnt)
{
data.pSrcSubRects = &rect;

View File

@ -1270,10 +1270,8 @@ namespace D3dDdi
if (!IsRectEmpty(&g_presentationRect))
{
auto dstRect = DDraw::RealPrimarySurface::getMonitorRect();
OffsetRect(&dstRect, -dstRect.left, -dstRect.top);
presentLayeredWindows(*this, data.DstSubResourceIndex, dstRect,
Gdi::Window::getVisibleOverlayWindows(), dstRect);
presentLayeredWindows(*this, data.DstSubResourceIndex, getRect(data.DstSubResourceIndex),
Gdi::Window::getVisibleOverlayWindows(), m_device.getAdapter().getMonitorInfo().rcMonitor);
}
return LOG_RESULT(S_OK);
@ -1294,7 +1292,7 @@ namespace D3dDdi
continue;
}
RECT srcRect = { 0, 0, visibleRect.right - visibleRect.left, visibleRect.bottom - visibleRect.top };
RECT srcRect = { 0, 0, visibleRect.right - visibleRect.left + 1, visibleRect.bottom - visibleRect.top + 1 };
auto& windowSurface = repo.getTempSysMemSurface(srcRect.right, srcRect.bottom);
auto& texture = repo.getTempTexture(srcRect.right, srcRect.bottom, D3DDDIFMT_A8R8G8B8);
if (!windowSurface.resource || !texture.resource)
@ -1304,9 +1302,16 @@ namespace D3dDdi
HDC srcDc = GetWindowDC(layeredWindow.hwnd);
HDC dstDc = nullptr;
POINT srcOrig = { visibleRect.left - layeredWindow.rect.left, visibleRect.top - layeredWindow.rect.top };
windowSurface.surface->GetDC(windowSurface.surface, &dstDc);
CALL_ORIG_FUNC(BitBlt)(dstDc, 0, 0, srcRect.right, srcRect.bottom, srcDc,
visibleRect.left - layeredWindow.rect.left, visibleRect.top - layeredWindow.rect.top, SRCCOPY);
CALL_ORIG_FUNC(BitBlt)(dstDc, 0, 0, srcRect.right - 1, srcRect.bottom - 1,
srcDc, srcOrig.x, srcOrig.y, SRCCOPY);
CALL_ORIG_FUNC(BitBlt)(dstDc, srcRect.right - 1, 0, 1, srcRect.bottom - 1,
srcDc, srcOrig.x + srcRect.right - 2, srcOrig.y, SRCCOPY);
CALL_ORIG_FUNC(BitBlt)(dstDc, 0, srcRect.bottom - 1, srcRect.right - 1, 1,
srcDc, srcOrig.x, srcOrig.y + srcRect.bottom - 2, SRCCOPY);
CALL_ORIG_FUNC(BitBlt)(dstDc, srcRect.right - 1, srcRect.bottom - 1, 1, 1,
srcDc, srcOrig.x + srcRect.right - 2, srcOrig.y + srcRect.bottom - 2, SRCCOPY);
windowSurface.surface->ReleaseDC(windowSurface.surface, dstDc);
ReleaseDC(layeredWindow.hwnd, srcDc);
@ -1327,8 +1332,10 @@ namespace D3dDdi
}
Rect::transform(visibleRect, monitorRect, dstRect);
blitter.textureBlt(dst, dstSubResourceIndex, visibleRect, *texture.resource, 0, srcRect, D3DTEXF_POINT,
ck, (flags & ULW_ALPHA) ? &alpha : nullptr,
srcRect.right--;
srcRect.bottom--;
blitter.textureBlt(dst, dstSubResourceIndex, visibleRect, *texture.resource, 0, srcRect,
D3DTEXF_LINEAR | D3DTEXF_SRGB, ck, (flags & ULW_ALPHA) ? &alpha : nullptr,
layeredWindow.region);
}
}
@ -1398,14 +1405,16 @@ namespace D3dDdi
const Int2 ar = m_device.getAdapter().getAspectRatio();
g_presentationRect = calculateScaledRect({ 0, 0, ar.x, ar.y }, DDraw::RealPrimarySurface::getMonitorRect());
auto& si = m_origData.pSurfList[0];
RECT primaryRect = { 0, 0, static_cast<LONG>(si.Width), static_cast<LONG>(si.Height) };
Gdi::Cursor::setMonitorClipRect(DDraw::PrimarySurface::getMonitorRect());
if (!EqualRect(&g_presentationRect, &primaryRect))
const auto& mi = m_device.getAdapter().getMonitorInfo();
auto clipRect = mi.rcEmulated;
if (!EqualRect(&mi.rcMonitor, &mi.rcReal))
{
Gdi::Cursor::setEmulated(true);
InflateRect(&clipRect, -1, -1);
}
Gdi::Cursor::setMonitorClipRect(clipRect);
Gdi::Cursor::setEmulated(mi.isEmulated);
Gdi::VirtualScreen::setFullscreenMode(m_origData.Flags.MatchGdiPrimary);
}
else

View File

@ -180,14 +180,6 @@ namespace DDraw
{
namespace DirectDraw
{
DDSURFACEDESC2 getDisplayMode(CompatRef<IDirectDraw7> dd)
{
DDSURFACEDESC2 dm = {};
dm.dwSize = sizeof(dm);
dd->GetDisplayMode(&dd, &dm);
return dm;
}
DDPIXELFORMAT getRgbPixelFormat(DWORD bpp)
{
DDPIXELFORMAT pf = {};

View File

@ -12,7 +12,6 @@ namespace DDraw
{
namespace DirectDraw
{
DDSURFACEDESC2 getDisplayMode(CompatRef<IDirectDraw7> dd);
DDPIXELFORMAT getRgbPixelFormat(DWORD bpp);
LRESULT handleActivateApp(bool isActivated, std::function<LRESULT()> callOrigWndProc);
void onCreate(GUID* guid, CompatRef<IDirectDraw7> dd);

View File

@ -5,8 +5,8 @@
#include <Common/CompatVtable.h>
#include <D3dDdi/KernelModeThunks.h>
#include <DDraw/DirectDrawClipper.h>
#include <DDraw/RealPrimarySurface.h>
#include <DDraw/ScopedThreadLock.h>
#include <DDraw/Surfaces/PrimarySurface.h>
#include <DDraw/Surfaces/Surface.h>
#include <DDraw/Visitors/DirectDrawClipperVtblVisitor.h>
#include <Gdi/Gdi.h>
@ -46,7 +46,7 @@ namespace
GetRandomRgn(dc, rgn, SYSRGN);
CALL_ORIG_FUNC(ReleaseDC)(data.hwnd, dc);
RECT primaryRect = DDraw::RealPrimarySurface::getMonitorRect();
RECT primaryRect = DDraw::PrimarySurface::getMonitorRect();
if (0 != primaryRect.left || 0 != primaryRect.top)
{
rgn.offset(-primaryRect.left, -primaryRect.top);

View File

@ -1,6 +1,9 @@
#include <memory>
#include <vector>
#include <Windows.h>
#include <VersionHelpers.h>
#include <Common/Comparison.h>
#include <Common/CompatPtr.h>
#include <Common/Hook.h>
@ -8,6 +11,7 @@
#include <Common/ScopedThreadPriority.h>
#include <Common/Time.h>
#include <Config/Settings/FpsLimiter.h>
#include <Config/Settings/FullscreenMode.h>
#include <Config/Settings/VSync.h>
#include <D3dDdi/Device.h>
#include <D3dDdi/KernelModeThunks.h>
@ -35,6 +39,7 @@
#include <Overlay/ConfigWindow.h>
#include <Overlay/StatsWindow.h>
#include <Win32/DisplayMode.h>
#include <Win32/DpiAwareness.h>
#include <Win32/Thread.h>
namespace
@ -54,6 +59,7 @@ namespace
DDraw::IReleaseNotifier g_releaseNotifier(onRelease);
bool g_isFullscreen = false;
bool g_isExclusiveFullscreen = false;
DDraw::Surface* g_lastFlipSurface = nullptr;
DDraw::TagSurface* g_tagSurface = nullptr;
@ -82,6 +88,9 @@ namespace
{
if (!g_isFullscreen)
{
updatePresentationWindow();
if (g_presentationWindow)
{
D3dDdi::ScopedCriticalSection lock;
auto srcResource = D3dDdi::Device::findResource(
@ -99,8 +108,7 @@ namespace
bbResource->presentationBlt(blt, srcResource);
}
updatePresentationWindow();
Gdi::Window::present(*g_frontBuffer, *g_windowedBackBuffer, *g_clipper);
Gdi::Window::present(*g_frontBuffer, g_presentationWindow ? *g_windowedBackBuffer : src, *g_clipper);
return;
}
@ -172,7 +180,7 @@ namespace
DDraw::RealPrimarySurface::destroyDefaultPrimary();
auto dm = Win32::DisplayMode::getEmulatedDisplayMode();
if (0 == dm.diff.cx && 0 == dm.diff.cy)
if (dm.deviceName.empty())
{
return;
}
@ -373,7 +381,7 @@ namespace
Input::updateCursor();
});
if (!g_frontBuffer || !src || DDraw::RealPrimarySurface::isLost() || FAILED(src->IsLost(src)))
if (!g_frontBuffer || !src || DDraw::RealPrimarySurface::isLost())
{
Gdi::Window::present(nullptr);
return;
@ -409,49 +417,67 @@ namespace
{
LOG_FUNC("RealPrimarySurface::updatePresentationWindow");
const bool isActive = isProcessActive();
HWND fullscreenWindow = nullptr;
if (g_isFullscreen && IsWindowVisible(g_deviceWindow) && !IsIconic(g_deviceWindow))
if (isProcessActive())
{
fullscreenWindow = g_deviceWindow;
if (g_isFullscreen && IsWindowVisible(g_deviceWindow) && !IsIconic(g_deviceWindow))
{
if (g_isExclusiveFullscreen)
{
return;
}
fullscreenWindow = g_deviceWindow;
}
else if (g_frontBuffer && DDraw::PrimarySurface::getPrimary() && SUCCEEDED(g_frontBuffer->IsLost(g_frontBuffer)))
{
fullscreenWindow = Gdi::Window::getFullscreenWindow();
}
}
else if (g_frontBuffer && DDraw::PrimarySurface::getPrimary() && SUCCEEDED(g_frontBuffer->IsLost(g_frontBuffer)))
else if (g_isFullscreen)
{
fullscreenWindow = Gdi::Window::getFullscreenWindow();
return;
}
fullscreenWindow = fullscreenWindow ? Gdi::Window::getPresentationWindow(fullscreenWindow) : nullptr;
HWND fullscreenPresentationWindow = nullptr;
if (fullscreenWindow)
{
Gdi::Window::setDpiAwareness(fullscreenWindow, true);
fullscreenPresentationWindow = Gdi::Window::getPresentationWindow(fullscreenWindow);
}
if (g_windowedBackBuffer)
{
auto resource = D3dDdi::Device::findResource(
DDraw::DirectDrawSurface::getDriverResourceHandle(*g_windowedBackBuffer));
resource->setFullscreenMode(isActive && fullscreenWindow);
resource->setFullscreenMode(fullscreenPresentationWindow);
}
if (!isActive)
{
return;
}
g_presentationWindow = fullscreenWindow;
g_presentationWindow = fullscreenPresentationWindow;
if (g_presentationWindow)
{
Gdi::GuiThread::execute([&]()
{
CALL_ORIG_FUNC(SetWindowPos)(g_presentationWindow, HWND_TOPMOST, g_monitorRect.left, g_monitorRect.top,
Win32::ScopedDpiAwareness dpiAwareness;
CALL_ORIG_FUNC(SetWindowPos)(g_presentationWindow, HWND_TOPMOST, g_monitorRect.left, g_monitorRect.top, 0, 0,
SWP_NOACTIVATE | SWP_NOSENDCHANGING | SWP_NOREDRAW | SWP_NOOWNERZORDER | SWP_SHOWWINDOW | SWP_NOSIZE);
CALL_ORIG_FUNC(SetWindowPos)(g_presentationWindow, nullptr, 0, 0,
g_monitorRect.right - g_monitorRect.left, g_monitorRect.bottom - g_monitorRect.top,
SWP_NOACTIVATE | SWP_NOSENDCHANGING | SWP_NOREDRAW | SWP_NOOWNERZORDER | SWP_SHOWWINDOW);
SWP_NOACTIVATE | SWP_NOSENDCHANGING | SWP_NOREDRAW | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOMOVE);
});
}
static HWND prevPresentationWindow = nullptr;
if (prevPresentationWindow && prevPresentationWindow != g_presentationWindow)
static HWND prevFullscreenWindow = nullptr;
if (prevFullscreenWindow && prevFullscreenWindow != fullscreenWindow)
{
Gdi::Window::updatePresentationWindowPos(prevPresentationWindow, GetParent(prevPresentationWindow));
Gdi::Window::setDpiAwareness(prevFullscreenWindow, false);
HWND prevFullscreenPresentationWindow = Gdi::Window::getPresentationWindow(prevFullscreenWindow);
if (prevFullscreenPresentationWindow)
{
Gdi::Window::updatePresentationWindowPos(prevFullscreenPresentationWindow, prevFullscreenWindow);
}
}
prevPresentationWindow = g_presentationWindow;
prevFullscreenWindow = fullscreenWindow;
}
unsigned WINAPI updateThreadProc(LPVOID /*lpParameter*/)
@ -481,9 +507,10 @@ namespace DDraw
{
LOG_FUNC("RealPrimarySurface::create", &dd);
DDraw::ScopedThreadLock lock;
const auto& mi = Win32::DisplayMode::getMonitorInfo(
D3dDdi::KernelModeThunks::getAdapterInfo(*CompatPtr<IDirectDraw7>::from(&dd)).deviceName);
auto prevMonitorRect = g_monitorRect;
g_monitorRect = Win32::DisplayMode::getMonitorInfo(
D3dDdi::KernelModeThunks::getAdapterInfo(*CompatPtr<IDirectDraw7>::from(&dd)).deviceName).rcMonitor;
g_monitorRect = g_isExclusiveFullscreen ? mi.rcReal : mi.rcDpiAware;
DDSURFACEDESC desc = {};
desc.dwSize = sizeof(desc);
@ -499,6 +526,7 @@ namespace DDraw
if (DDERR_NOEXCLUSIVEMODE == result)
{
g_isFullscreen = false;
g_monitorRect = mi.rcDpiAware;
desc.dwFlags = DDSD_CAPS;
desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
desc.dwBackBufferCount = 0;
@ -603,6 +631,7 @@ namespace DDraw
static UINT lastOverlayCheckVsyncCount = 0;
if (vsyncCount != lastOverlayCheckVsyncCount)
{
setPresentationWindowTopmost();
Gdi::Cursor::update();
Gdi::Caret::blink();
auto statsWindow = Gdi::GuiThread::getStatsWindow();
@ -676,13 +705,9 @@ namespace DDraw
auto primary(DDraw::PrimarySurface::getPrimary());
CompatWeakPtr<IDirectDrawSurface7> src;
if (g_isDelayedFlipPending)
if (primary && SUCCEEDED(primary->IsLost(primary)))
{
src = g_lastFlipSurface->getDDS();
}
else if (primary && SUCCEEDED(primary->IsLost(primary)))
{
src = primary;
src = g_isDelayedFlipPending ? g_lastFlipSurface->getDDS() : primary;
}
else
{
@ -734,6 +759,8 @@ namespace DDraw
void RealPrimarySurface::init()
{
g_isExclusiveFullscreen = Config::Settings::FullscreenMode::EXCLUSIVE == Config::fullscreenMode.get() ||
!IsWindows8OrGreater();
Dll::createThread(&updateThreadProc, nullptr, THREAD_PRIORITY_TIME_CRITICAL);
}

View File

@ -92,12 +92,10 @@ namespace DDraw
LOG_FUNC("PrimarySurface::create", &dd, desc, surface);
DDraw::RealPrimarySurface::destroyDefaultPrimary();
const auto& dm = DDraw::DirectDraw::getDisplayMode(*CompatPtr<IDirectDraw7>::from(&dd));
auto deviceName = D3dDdi::KernelModeThunks::getAdapterInfo(*CompatPtr<IDirectDraw7>::from(&dd)).deviceName;
const auto& mi = Win32::DisplayMode::getMonitorInfo(deviceName);
auto prevMonitorRect = g_monitorRect;
g_monitorRect = Win32::DisplayMode::getMonitorInfo(deviceName).rcMonitor;
g_monitorRect.right = g_monitorRect.left + dm.dwWidth;
g_monitorRect.bottom = g_monitorRect.top + dm.dwHeight;
g_monitorRect = mi.rcEmulated;
HRESULT result = RealPrimarySurface::create(*CompatPtr<IDirectDraw>::from(&dd));
if (FAILED(result))
@ -111,12 +109,12 @@ namespace DDraw
auto data = privateData.get();
desc.dwFlags |= DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
desc.dwWidth = dm.dwWidth;
desc.dwHeight = dm.dwHeight;
desc.dwWidth = g_monitorRect.right - g_monitorRect.left;
desc.dwHeight = g_monitorRect.bottom - g_monitorRect.top;
desc.ddsCaps.dwCaps &= ~(DDSCAPS_PRIMARYSURFACE | DDSCAPS_SYSTEMMEMORY |
DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM | DDSCAPS_NONLOCALVIDMEM);
desc.ddsCaps.dwCaps |= DDSCAPS_OFFSCREENPLAIN;
desc.ddpfPixelFormat = dm.ddpfPixelFormat;
desc.ddpfPixelFormat = DirectDraw::getRgbPixelFormat(mi.bpp);
result = Surface::create(dd, desc, surface, std::move(privateData));
if (FAILED(result))

View File

@ -35,7 +35,7 @@ namespace
D3dDdi::ScopedCriticalSection lock;
Gdi::Region clipRgn(DDraw::DirectDrawClipper::getClipRgn(*clipper));
RECT monitorRect = DDraw::RealPrimarySurface::getMonitorRect();
RECT monitorRect = DDraw::PrimarySurface::getMonitorRect();
RECT virtualScreenBounds = Gdi::VirtualScreen::getBounds();
clipRgn.offset(monitorRect.left, monitorRect.top);
clipRgn &= virtualScreenBounds;

View File

@ -327,6 +327,7 @@
<ClInclude Include="Overlay\StatsWindow.h" />
<ClInclude Include="Overlay\Window.h" />
<ClInclude Include="Win32\DisplayMode.h" />
<ClInclude Include="Win32\DpiAwareness.h" />
<ClInclude Include="Win32\Log.h" />
<ClInclude Include="Win32\MemoryManagement.h" />
<ClInclude Include="Win32\Registry.h" />
@ -460,6 +461,7 @@
<ClCompile Include="Overlay\StatsWindow.cpp" />
<ClCompile Include="Overlay\Window.cpp" />
<ClCompile Include="Win32\DisplayMode.cpp" />
<ClCompile Include="Win32\DpiAwareness.cpp" />
<ClCompile Include="Win32\Log.cpp" />
<ClCompile Include="Win32\MemoryManagement.cpp" />
<ClCompile Include="Win32\Registry.cpp" />

View File

@ -705,6 +705,9 @@
<ClInclude Include="Config\Settings\CrashDump.h">
<Filter>Header Files\Config\Settings</Filter>
</ClInclude>
<ClInclude Include="Win32\DpiAwareness.h">
<Filter>Header Files\Win32</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Gdi\Gdi.cpp">
@ -1100,6 +1103,9 @@
<ClCompile Include="Config\Settings\ConfigRows.cpp">
<Filter>Source Files\Config\Settings</Filter>
</ClCompile>
<ClCompile Include="Win32\DpiAwareness.cpp">
<Filter>Source Files\Win32</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="DDrawCompat.rc">

View File

@ -28,6 +28,7 @@
#include <Gdi/VirtualScreen.h>
#include <Input/Input.h>
#include <Win32/DisplayMode.h>
#include <Win32/DpiAwareness.h>
#include <Win32/MemoryManagement.h>
#include <Win32/Registry.h>
#include <Win32/Thread.h>
@ -149,12 +150,6 @@ namespace
(!Compat::isEqual(currentDllPath, dciman32DllPath) && GetModuleHandleW(dciman32DllPath.c_str()));
}
void logDpiAwareness(bool isSuccessful, DPI_AWARENESS_CONTEXT dpiAwareness, const char* funcName)
{
LOG_INFO << (isSuccessful ? "DPI awareness was successfully changed" : "Failed to change process DPI awareness")
<< " to \"" << Config::dpiAwareness.convertToString(dpiAwareness) << "\" via " << funcName;
}
void onDirectDrawCreate(GUID* lpGUID, LPDIRECTDRAW* lplpDD, IUnknown* /*pUnkOuter*/)
{
return DDraw::DirectDraw::onCreate(lpGUID, *CompatPtr<IDirectDraw7>::from(*lplpDD));
@ -180,71 +175,6 @@ namespace
return LOG_RESULT(CALL_ORIG_PROC(SetAppCompatData)(param1, param2));
}
void setDpiAwareness()
{
auto dpiAwareness = Config::dpiAwareness.get();
if (!dpiAwareness)
{
return;
}
HMODULE user32 = LoadLibrary("user32");
auto isValidDpiAwarenessContext = reinterpret_cast<decltype(&IsValidDpiAwarenessContext)>(
Compat::getProcAddress(user32, "IsValidDpiAwarenessContext"));
auto setProcessDpiAwarenessContext = reinterpret_cast<decltype(&SetProcessDpiAwarenessContext)>(
Compat::getProcAddress(user32, "SetProcessDpiAwarenessContext"));
if (isValidDpiAwarenessContext && setProcessDpiAwarenessContext)
{
if (DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 == dpiAwareness &&
!isValidDpiAwarenessContext(dpiAwareness))
{
dpiAwareness = DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE;
}
if (DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED == dpiAwareness &&
!isValidDpiAwarenessContext(dpiAwareness))
{
dpiAwareness = DPI_AWARENESS_CONTEXT_UNAWARE;
}
logDpiAwareness(setProcessDpiAwarenessContext(dpiAwareness), dpiAwareness, "SetProcessDpiAwarenessContext");
return;
}
auto setProcessDpiAwareness = reinterpret_cast<decltype(&SetProcessDpiAwareness)>(
Compat::getProcAddress(LoadLibrary("shcore"), "SetProcessDpiAwareness"));
if (setProcessDpiAwareness)
{
HRESULT result = S_OK;
if (DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE == dpiAwareness ||
DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 == dpiAwareness)
{
dpiAwareness = DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE;
result = setProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE);
}
else if (DPI_AWARENESS_CONTEXT_SYSTEM_AWARE == dpiAwareness)
{
result = setProcessDpiAwareness(PROCESS_SYSTEM_DPI_AWARE);
}
else
{
dpiAwareness = DPI_AWARENESS_CONTEXT_UNAWARE;
result = setProcessDpiAwareness(PROCESS_DPI_UNAWARE);
}
logDpiAwareness(SUCCEEDED(result), dpiAwareness, "SetProcessDpiAwareness");
return;
}
if (DPI_AWARENESS_CONTEXT_UNAWARE == dpiAwareness ||
DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED == dpiAwareness)
{
LOG_INFO << "DPI awareness was not changed";
}
logDpiAwareness(SetProcessDPIAware(), DPI_AWARENESS_CONTEXT_SYSTEM_AWARE, "SetProcessDPIAware");
}
LPTOP_LEVEL_EXCEPTION_FILTER WINAPI setUnhandledExceptionFilter(LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter)
{
LOG_FUNC("SetUnhandledExceptionFilter", Compat::funcPtrToStr(lpTopLevelExceptionFilter));
@ -407,7 +337,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
Compat::closeDbgEng();
CALL_ORIG_FUNC(timeBeginPeriod)(1);
setDpiAwareness();
Win32::DpiAwareness::init();
SetThemeAppProperties(0);
Time::init();
Win32::Thread::applyConfig();

View File

@ -192,7 +192,7 @@ namespace Gdi
POINT pos = {};
CALL_ORIG_FUNC(GetCursorPos)(&pos);
SetCursorPos(pos.x, pos.y);
CALL_ORIG_FUNC(SetCursorPos)(pos.x, pos.y);
}
void setMonitorClipRect(const RECT& rect)

View File

@ -12,6 +12,7 @@
#include <Overlay/ConfigWindow.h>
#include <Overlay/StatsWindow.h>
#include <Win32/DisplayMode.h>
#include <Win32/DpiAwareness.h>
namespace
{
@ -105,8 +106,8 @@ namespace Gdi
{
namespace GuiThread
{
HWND createWindow(DWORD dwExStyle, LPCWSTR lpClassName, LPCWSTR lpWindowName, DWORD dwStyle,
int X, int Y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam)
HWND createWindow(DWORD dwExStyle, LPCWSTR lpClassName, LPCWSTR lpWindowName, DWORD dwStyle, int X, int Y,
int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam, bool dpiAware)
{
// Workaround for ForceSimpleWindow shim
static auto createWindowExW = reinterpret_cast<decltype(&CreateWindowExW)>(
@ -115,6 +116,7 @@ namespace Gdi
HWND hwnd = nullptr;
execute([&]()
{
Win32::ScopedDpiAwareness dpiAwareness(dpiAware);
hwnd = createWindowExW(dwExStyle, lpClassName, lpWindowName, dwStyle, X, Y, nWidth, nHeight,
hWndParent, hMenu, hInstance, lpParam);
});

View File

@ -16,8 +16,8 @@ namespace Gdi
{
namespace GuiThread
{
HWND createWindow(DWORD dwExStyle, LPCWSTR lpClassName, LPCWSTR lpWindowName, DWORD dwStyle,
int X, int Y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam);
HWND createWindow(DWORD dwExStyle, LPCWSTR lpClassName, LPCWSTR lpWindowName, DWORD dwStyle, int X, int Y,
int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam, bool dpiAware);
void deleteTaskbarTab(HWND hwnd);
void destroyWindow(HWND hwnd);
void setWindowRgn(HWND hwnd, Gdi::Region rgn);

View File

@ -12,11 +12,10 @@ namespace
int getAdjustedDisplayMetrics(int nIndex, int cxIndex)
{
int result = CALL_ORIG_FUNC(GetSystemMetrics)(nIndex);
auto dm = Win32::DisplayMode::getEmulatedDisplayMode();
if (0 == dm.rect.left && 0 == dm.rect.top)
{
result += (nIndex == cxIndex) ? dm.diff.cx : dm.diff.cy;
}
auto mi = Win32::DisplayMode::getMonitorInfo();
result += (nIndex == cxIndex)
? (mi.rcEmulated.right - mi.rcMonitor.right)
: (mi.rcEmulated.bottom - mi.rcMonitor.bottom);
return result;
}

View File

@ -19,9 +19,9 @@ namespace Gdi
{
namespace PresentationWindow
{
HWND create(HWND owner)
HWND create(HWND owner, bool dpiAware)
{
LOG_FUNC("PresentationWindow::create", owner);
LOG_FUNC("PresentationWindow::create", owner, dpiAware);
HWND presentationWindow = nullptr;
GuiThread::execute([&]()
{
@ -34,7 +34,8 @@ namespace Gdi
owner,
nullptr,
nullptr,
nullptr);
nullptr,
dpiAware);
if (presentationWindow)
{

View File

@ -6,7 +6,7 @@ namespace Gdi
{
namespace PresentationWindow
{
HWND create(HWND owner);
HWND create(HWND owner, bool dpiAware = false);
void installHooks();
}

View File

@ -11,7 +11,6 @@
#include <DDraw/ScopedThreadLock.h>
#include <DDraw/Surfaces/PrimarySurface.h>
#include <Gdi/Gdi.h>
#include <Gdi/Region.h>
#include <Gdi/VirtualScreen.h>
#include <Gdi/Window.h>
#include <Win32/DisplayMode.h>
@ -24,7 +23,6 @@ namespace
};
Compat::CriticalSection g_cs;
Gdi::Region g_region;
RECT g_bounds = {};
DWORD g_bpp = 0;
LONG g_width = 0;
@ -39,27 +37,6 @@ namespace
RGBQUAD g_systemPalette[256] = {};
std::map<HDC, VirtualScreenDc> g_dcs;
BOOL CALLBACK addMonitorRectToRegion(
HMONITOR hMonitor, HDC /*hdcMonitor*/, LPRECT lprcMonitor, LPARAM dwData)
{
MONITORINFOEXW mi = {};
mi.cbSize = sizeof(mi);
CALL_ORIG_FUNC(GetMonitorInfoW)(hMonitor, &mi);
auto res = Win32::DisplayMode::getDisplayResolution(mi.szDevice);
RECT rect = *lprcMonitor;
if (0 != res.cx && 0 != res.cy)
{
rect.right = rect.left + res.cx;
rect.bottom = rect.top + res.cy;
}
Gdi::Region& virtualScreenRegion = *reinterpret_cast<Gdi::Region*>(dwData);
Gdi::Region monitorRegion(rect);
virtualScreenRegion |= monitorRegion;
return TRUE;
}
RGBQUAD convertToRgbQuad(PALETTEENTRY entry)
{
RGBQUAD quad = {};
@ -199,12 +176,6 @@ namespace Gdi
return g_bounds;
}
Region getRegion()
{
Compat::ScopedCriticalSection lock(g_cs);
return g_region;
}
DDSURFACEDESC2 getSurfaceDesc(const RECT& rect)
{
Compat::ScopedCriticalSection lock(g_cs);
@ -278,13 +249,14 @@ namespace Gdi
if (g_isFullscreen)
{
g_bounds = DDraw::PrimarySurface::getMonitorRect();
g_region = g_bounds;
}
else
{
g_region.clear();
EnumDisplayMonitors(nullptr, nullptr, addMonitorRectToRegion, reinterpret_cast<LPARAM>(&g_region));
GetRgnBox(g_region, &g_bounds);
g_bounds = {};
for (const auto& mi : Win32::DisplayMode::getAllMonitorInfo())
{
UnionRect(&g_bounds, &g_bounds, &mi.second.rcMonitor);
}
}
g_bpp = Win32::DisplayMode::getBpp();

View File

@ -17,7 +17,6 @@ namespace Gdi
void deleteDc(HDC dc);
RECT getBounds();
Region getRegion();
DDSURFACEDESC2 getSurfaceDesc(const RECT& rect);
void init();

View File

@ -31,6 +31,7 @@
#include <Overlay/ConfigWindow.h>
#include <Overlay/StatsWindow.h>
#include <Win32/DisplayMode.h>
#include <Win32/DpiAwareness.h>
namespace
{
@ -51,7 +52,6 @@ namespace
};
decltype(&DwmSetIconicThumbnail) g_dwmSetIconicThumbnail = nullptr;
decltype(&SetThreadDpiAwarenessContext) g_setThreadDpiAwarenessContext = nullptr;
wchar_t g_dummyWindowText;
std::map<HMENU, UINT> g_menuMaxHeight;
@ -327,19 +327,8 @@ namespace
DeleteDC(dstDc);
ReleaseDC(presentationWindow, srcDc);
DPI_AWARENESS_CONTEXT prevContext = nullptr;
if (g_setThreadDpiAwarenessContext)
{
prevContext = g_setThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE);
}
Win32::ScopedDpiAwareness dpiAwareness;
g_dwmSetIconicThumbnail(hwnd, bmp, 0);
if (prevContext)
{
g_setThreadDpiAwarenessContext(prevContext);
}
DeleteObject(bmp);
}
@ -370,6 +359,11 @@ namespace
return getMessage(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax, CALL_ORIG_FUNC(GetMessageW));
}
int WINAPI getRandomRgn(HDC hdc, HRGN hrgn, INT i)
{
return Gdi::Window::getRandomRgn(hdc, hrgn, i);
}
LONG getWindowLong(HWND hWnd, int nIndex,
decltype(&GetWindowLongA) origGetWindowLong, WNDPROC(WindowProc::* wndProc))
{
@ -441,24 +435,22 @@ namespace
return;
}
HMONITOR monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY);
auto mi = Win32::DisplayMode::getMonitorInfo(hwnd);
MONITORINFO origMi = {};
origMi.cbSize = sizeof(origMi);
CALL_ORIG_FUNC(GetMonitorInfoA)(monitor, &origMi);
MONITORINFO mi = {};
mi.cbSize = sizeof(mi);
GetMonitorInfoA(monitor, &mi);
if (!EqualRect(&origMi.rcMonitor, &mi.rcMonitor))
if (!EqualRect(&mi.rcEmulated, &mi.rcMonitor))
{
RECT wr = {};
GetWindowRect(hwnd, &wr);
const LONG width = wr.right - wr.left;
const LONG height = wr.bottom - wr.top;
const RECT& mr = 0 == g_inMessageBox ? mi.rcWork : mi.rcMonitor;
if (0 == g_inMessageBox)
{
mi.rcWork.right = mi.rcWork.left + mi.rcEmulated.right - mi.rcEmulated.left;
mi.rcWork.bottom = mi.rcWork.top + mi.rcEmulated.bottom - mi.rcEmulated.top;
}
const RECT& mr = 0 == g_inMessageBox ? mi.rcWork : mi.rcEmulated;
const LONG left = (mr.left + mr.right - width) / 2;
const LONG top = (mr.top + mr.bottom - height) / 2;
@ -506,11 +498,9 @@ namespace
void onGetMinMaxInfo(MINMAXINFO& mmi)
{
MONITORINFOEXA mi = {};
mi.cbSize = sizeof(mi);
GetMonitorInfoA(MonitorFromPoint({}, MONITOR_DEFAULTTOPRIMARY), &mi);
mmi.ptMaxSize.x = mi.rcMonitor.right - 2 * mmi.ptMaxPosition.x;
mmi.ptMaxSize.y = mi.rcMonitor.bottom - 2 * mmi.ptMaxPosition.y;
const auto& mi = Win32::DisplayMode::getMonitorInfo();
mmi.ptMaxSize.x = mi.rcEmulated.right - 2 * mmi.ptMaxPosition.x;
mmi.ptMaxSize.y = mi.rcEmulated.bottom - 2 * mmi.ptMaxPosition.y;
}
void onInitMenuPopup(HMENU menu)
@ -861,6 +851,7 @@ namespace Gdi
HOOK_FUNCTION(user32, GetCursorPos, getCursorPos);
HOOK_FUNCTION(user32, GetMessageA, getMessageA);
HOOK_FUNCTION(user32, GetMessageW, getMessageW);
HOOK_FUNCTION(gdi32, GetRandomRgn, getRandomRgn);
HOOK_FUNCTION(user32, GetWindowLongA, getWindowLongA);
HOOK_FUNCTION(user32, GetWindowLongW, getWindowLongW);
HOOK_FUNCTION(user32, MessageBoxA, messageBox<MessageBoxA>);
@ -878,8 +869,6 @@ namespace Gdi
g_dwmSetIconicThumbnail = reinterpret_cast<decltype(&DwmSetIconicThumbnail)>(
GetProcAddress(GetModuleHandle("dwmapi"), "DwmSetIconicThumbnail"));
g_setThreadDpiAwarenessContext = reinterpret_cast<decltype(&SetThreadDpiAwarenessContext)>(
GetProcAddress(GetModuleHandle("user32"), "SetThreadDpiAwarenessContext"));
Compat::hookIatFunction(Dll::g_origDDrawModule, "SetWindowLongA", ddrawSetWindowLongA);

View File

@ -18,6 +18,8 @@
#include <Input/Input.h>
#include <Overlay/ConfigWindow.h>
#include <Overlay/StatsWindow.h>
#include <Win32/DisplayMode.h>
#include <Win32/DpiAwareness.h>
namespace
{
@ -35,28 +37,24 @@ namespace
HWND presentationWindow;
RECT windowRect;
RECT clientRect;
Gdi::Region windowRegion;
Gdi::Region visibleRegion;
Gdi::Region invalidatedRegion;
bool isMenu;
bool isLayered;
bool isVisibleRegionChanged;
bool isDpiAware;
Window(HWND hwnd)
: hwnd(hwnd)
, presentationWindow(nullptr)
, windowRect{}
, clientRect{}
, windowRegion(nullptr)
, isMenu(Gdi::MENU_ATOM == GetClassLong(hwnd, GCW_ATOM))
, isLayered(true)
, isVisibleRegionChanged(false)
, isDpiAware(false)
{
}
};
const RECT REGION_OVERRIDE_MARKER_RECT = { 32000, 32000, 32001, 32001 };
std::map<HWND, Window> g_windows;
std::vector<Window*> g_windowZOrder;
@ -92,16 +90,6 @@ namespace
return true;
}
Gdi::Region getWindowRegion(HWND hwnd)
{
Gdi::Region rgn;
if (ERROR == CALL_ORIG_FUNC(GetWindowRgn)(hwnd, rgn))
{
return nullptr;
}
return rgn;
}
void presentLayeredWindow(CompatWeakPtr<IDirectDrawSurface7> dst,
HWND hwnd, RECT wr, const RECT& monitorRect, HDC& dstDc, Gdi::Region* rgn = nullptr, bool isMenu = false)
{
@ -261,17 +249,14 @@ namespace
const LONG exStyle = CALL_ORIG_FUNC(GetWindowLongA)(hwnd, GWL_EXSTYLE);
const bool isLayered = it->second.isMenu || (exStyle & WS_EX_LAYERED);
const bool isVisible = IsWindowVisible(hwnd) && !IsIconic(hwnd);
bool setPresentationWindowRgn = false;
if (isLayered != it->second.isLayered)
{
it->second.isLayered = isLayered;
it->second.isVisibleRegionChanged = isVisible;
if (!isLayered)
{
it->second.presentationWindow = Gdi::PresentationWindow::create(hwnd);
Gdi::WinProc::updatePresentationWindowText(hwnd);
setPresentationWindowRgn = true;
}
else if (it->second.presentationWindow)
{
@ -280,14 +265,6 @@ namespace
}
}
Gdi::Region windowRegion(getWindowRegion(hwnd));
if (windowRegion && !PtInRegion(windowRegion, REGION_OVERRIDE_MARKER_RECT.left, REGION_OVERRIDE_MARKER_RECT.top) ||
!windowRegion && it->second.windowRegion)
{
swap(it->second.windowRegion, windowRegion);
setPresentationWindowRgn = true;
}
WINDOWINFO wi = {};
Gdi::Region visibleRegion;
@ -297,15 +274,24 @@ namespace
GetWindowInfo(hwnd, &wi);
if (!IsRectEmpty(&wi.rcWindow))
{
if (it->second.windowRegion)
if (isLayered)
{
visibleRegion = it->second.windowRegion;
visibleRegion.offset(wi.rcWindow.left, wi.rcWindow.top);
if (ERROR != GetWindowRgn(hwnd, visibleRegion))
{
visibleRegion.offset(wi.rcWindow.left, wi.rcWindow.top);
}
else
{
visibleRegion = wi.rcWindow;
}
}
else
{
visibleRegion = wi.rcWindow;
HDC windowDc = GetWindowDC(hwnd);
CALL_ORIG_FUNC(GetRandomRgn)(windowDc, visibleRegion, SYSRGN);
ReleaseDC(hwnd, windowDc);
}
visibleRegion &= context.virtualScreenRegion;
if (!it->second.isMenu)
{
@ -335,27 +321,11 @@ namespace
context.invalidatedRegion |= visibleRegion - it->second.visibleRegion;
}
if (isVisible && !it->second.isVisibleRegionChanged)
if (it->second.presentationWindow &&
(!isVisible || it->second.presentationWindow != DDraw::RealPrimarySurface::getPresentationWindow()))
{
visibleRegion.offset(it->second.windowRect.left - wi.rcWindow.left, it->second.windowRect.top - wi.rcWindow.top);
if (it->second.visibleRegion != visibleRegion)
{
it->second.isVisibleRegionChanged = true;
}
}
if (it->second.presentationWindow)
{
if (setPresentationWindowRgn)
{
Gdi::GuiThread::setWindowRgn(it->second.presentationWindow, it->second.windowRegion);
}
if (it->second.presentationWindow != DDraw::RealPrimarySurface::getPresentationWindow())
{
Gdi::Window::updatePresentationWindowPos(it->second.presentationWindow, hwnd);
}
Gdi::GuiThread::setWindowRgn(it->second.presentationWindow, Gdi::Window::getWindowRgn(hwnd));
Gdi::Window::updatePresentationWindowPos(it->second.presentationWindow, hwnd);
}
}
return TRUE;
@ -395,7 +365,7 @@ namespace Gdi
if (statsWindow && statsWindow->isVisible())
{
GetWindowRect(statsWindow->getWindow(), &wr);
auto visibleRegion(getWindowRegion(statsWindow->getWindow()));
auto visibleRegion(getWindowRgn(statsWindow->getWindow()));
visibleRegion.offset(wr.left, wr.top);
layeredWindows.push_back({ statsWindow->getWindow(), wr, visibleRegion });
}
@ -404,7 +374,7 @@ namespace Gdi
if (configWindow && configWindow->isVisible())
{
GetWindowRect(configWindow->getWindow(), &wr);
auto visibleRegion(getWindowRegion(configWindow->getWindow()));
auto visibleRegion(getWindowRgn(configWindow->getWindow()));
visibleRegion.offset(wr.left, wr.top);
layeredWindows.push_back({ configWindow->getWindow(), wr, visibleRegion });
auto capture = Input::getCaptureWindow();
@ -445,6 +415,47 @@ namespace Gdi
return nullptr;
}
int getRandomRgn(HDC hdc, HRGN hrgn, INT i)
{
auto result = CALL_ORIG_FUNC(GetRandomRgn)(hdc, hrgn, i);
if (1 != result || SYSRGN != i)
{
return result;
}
HWND hwnd = WindowFromDC(hdc);
if (!hwnd)
{
return result;
}
HWND root = GetAncestor(hwnd, GA_ROOT);
if (!root)
{
return result;
}
D3dDdi::ScopedCriticalSection lock;
auto it = g_windows.find(root);
if (it == g_windows.end())
{
return result;
}
CombineRgn(hrgn, hrgn, it->second.visibleRegion, RGN_AND);
return result;
}
Gdi::Region getWindowRgn(HWND hwnd)
{
Gdi::Region rgn;
if (ERROR == CALL_ORIG_FUNC(GetWindowRgn)(hwnd, rgn))
{
return nullptr;
}
return rgn;
}
bool isTopLevelWindow(HWND hwnd)
{
return GetDesktopWindow() == GetAncestor(hwnd, GA_PARENT);
@ -470,7 +481,6 @@ namespace Gdi
void onSyncPaint(HWND hwnd)
{
LOG_FUNC("Window::onSyncPaint", hwnd);
bool isInvalidated = false;
{
D3dDdi::ScopedCriticalSection lock;
@ -480,38 +490,13 @@ namespace Gdi
return;
}
if (it->second.isVisibleRegionChanged)
{
it->second.isVisibleRegionChanged = false;
const LONG origWndProc = CALL_ORIG_FUNC(GetWindowLongA)(hwnd, GWL_WNDPROC);
CALL_ORIG_FUNC(SetWindowLongA)(hwnd, GWL_WNDPROC, reinterpret_cast<LONG>(CALL_ORIG_FUNC(DefWindowProcA)));
Gdi::Region rgn(it->second.isLayered ? it->second.windowRegion : it->second.visibleRegion);
if (!it->second.isLayered)
{
rgn.offset(-it->second.windowRect.left, -it->second.windowRect.top);
rgn |= REGION_OVERRIDE_MARKER_RECT;
}
if (SetWindowRgn(hwnd, rgn, FALSE))
{
rgn.release();
}
CALL_ORIG_FUNC(SetWindowLongA)(hwnd, GWL_WNDPROC, origWndProc);
}
isInvalidated = !it->second.invalidatedRegion.isEmpty();
if (isInvalidated)
{
RedrawWindow(hwnd, nullptr, it->second.invalidatedRegion,
RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN);
it->second.invalidatedRegion.clear();
}
RedrawWindow(hwnd, nullptr, it->second.invalidatedRegion,
RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN);
it->second.invalidatedRegion.clear();
}
if (isInvalidated)
{
RECT emptyRect = {};
RedrawWindow(hwnd, &emptyRect, nullptr, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ERASENOW);
}
RECT emptyRect = {};
RedrawWindow(hwnd, &emptyRect, nullptr, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ERASENOW);
}
void present(CompatRef<IDirectDrawSurface7> dst, CompatRef<IDirectDrawSurface7> src,
@ -526,12 +511,13 @@ namespace Gdi
return;
}
auto mr = DDraw::PrimarySurface::getMonitorRect();
for (auto window : g_windowZOrder)
{
if (window->presentationWindow && !window->visibleRegion.isEmpty())
{
clipper->SetHWnd(&clipper, 0, window->presentationWindow);
dst->Blt(&dst, nullptr, &src, nullptr, DDBLT_WAIT, nullptr);
dst->Blt(&dst, &mr, &src, nullptr, DDBLT_WAIT, nullptr);
}
}
}
@ -589,7 +575,7 @@ namespace Gdi
UpdateWindowContext context;
context.processId = GetCurrentProcessId();
context.virtualScreenRegion = VirtualScreen::getRegion();
context.virtualScreenRegion = VirtualScreen::getBounds();
std::vector<HWND> invalidatedWindows;
{
@ -616,7 +602,7 @@ namespace Gdi
for (auto it = g_windowZOrder.rbegin(); it != g_windowZOrder.rend(); ++it)
{
auto& window = **it;
if (window.isVisibleRegionChanged || !window.invalidatedRegion.isEmpty())
if (!window.invalidatedRegion.isEmpty())
{
invalidatedWindows.push_back(window.hwnd);
}
@ -629,6 +615,31 @@ namespace Gdi
}
}
void setDpiAwareness(HWND hwnd, bool dpiAware)
{
if (!Win32::DpiAwareness::isMixedModeSupported())
{
return;
}
D3dDdi::ScopedCriticalSection lock;
auto it = g_windows.find(hwnd);
if (it != g_windows.end() && it->second.isDpiAware != dpiAware)
{
it->second.isDpiAware = dpiAware;
auto prevPresentationWindow = it->second.presentationWindow;
it->second.presentationWindow = Gdi::PresentationWindow::create(hwnd, dpiAware);
if (it->second.presentationWindow)
{
Gdi::WinProc::updatePresentationWindowText(hwnd);
Gdi::GuiThread::setWindowRgn(it->second.presentationWindow, getWindowRgn(hwnd));
}
Gdi::GuiThread::destroyWindow(prevPresentationWindow);
}
}
void updatePresentationWindowPos(HWND presentationWindow, HWND owner)
{
if (IsIconic(owner))
@ -667,7 +678,9 @@ namespace Gdi
Gdi::GuiThread::execute([&]()
{
CALL_ORIG_FUNC(SetWindowPos)(presentationWindow,
wp.hwndInsertAfter, wp.x, wp.y, wp.cx, wp.cy, wp.flags);
wp.hwndInsertAfter, wp.x, wp.y, wp.cx, wp.cy, wp.flags | SWP_NOMOVE);
CALL_ORIG_FUNC(SetWindowPos)(presentationWindow,
wp.hwndInsertAfter, wp.x, wp.y, wp.cx, wp.cy, wp.flags | SWP_NOSIZE);
});
}
}

View File

@ -21,12 +21,15 @@ namespace Gdi
std::vector<LayeredWindow> getVisibleLayeredWindows();
std::vector<LayeredWindow> getVisibleOverlayWindows();
HWND getFullscreenWindow();
int getRandomRgn(HDC hdc, HRGN hrgn, INT i);
Gdi::Region getWindowRgn(HWND hwnd);
bool isTopLevelWindow(HWND hwnd);
void onStyleChanged(HWND hwnd, WPARAM wParam);
void onSyncPaint(HWND hwnd);
void present(CompatRef<IDirectDrawSurface7> dst, CompatRef<IDirectDrawSurface7> src,
CompatRef<IDirectDrawClipper> clipper);
void present(Gdi::Region excludeRegion);
void setDpiAwareness(HWND hwnd, bool dpiAware);
void updateAll();
void updatePresentationWindowPos(HWND presentationWindow, HWND owner);
}

View File

@ -3,10 +3,12 @@
#include <tuple>
#include <Windows.h>
#include <hidusage.h>
#include <winternl.h>
#include <Common/Hook.h>
#include <Common/Log.h>
#include <Common/Path.h>
#include <Common/Rect.h>
#include <Config/Settings/TerminateHotKey.h>
#include <Dll/Dll.h>
#include <DDraw/RealPrimarySurface.h>
@ -15,9 +17,18 @@
#include <Input/Input.h>
#include <Overlay/ConfigWindow.h>
#include <Overlay/Window.h>
#include <Win32/DisplayMode.h>
namespace
{
struct DInputMouseHookData
{
HOOKPROC origHookProc;
LPARAM origHookStruct;
MSLLHOOKSTRUCT hookStruct;
DWORD dpiScale;
};
struct HotKeyData
{
std::function<void(void*)> action;
@ -29,14 +40,19 @@ namespace
SIZE g_bmpArrowSize = {};
Overlay::Control* g_capture = nullptr;
POINT g_cursorPos = {};
POINT g_origCursorPos = { MAXLONG, MAXLONG };
HWND g_cursorWindow = nullptr;
std::map<Input::HotKey, HotKeyData> g_hotKeys;
RECT g_monitorRect = {};
HHOOK g_keyboardHook = nullptr;
HHOOK g_mouseHook = nullptr;
DInputMouseHookData g_dinputMouseHookData = {};
decltype(&PhysicalToLogicalPointForPerMonitorDPI) g_physicalToLogicalPointForPerMonitorDPI = nullptr;
LRESULT CALLBACK lowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK lowLevelMouseProc(int nCode, WPARAM wParam, LPARAM lParam);
POINT physicalToLogicalPoint(POINT pt, DWORD dpiScale);
LRESULT CALLBACK cursorWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
@ -67,6 +83,44 @@ namespace
return CALL_ORIG_FUNC(DefWindowProcA)(hwnd, uMsg, wParam, lParam);
}
LRESULT WINAPI dinputCallNextHookEx(HHOOK hhk, int nCode, WPARAM wParam, LPARAM lParam)
{
if (lParam == reinterpret_cast<LPARAM>(&g_dinputMouseHookData.hookStruct))
{
lParam = g_dinputMouseHookData.origHookStruct;
}
return CallNextHookEx(hhk, nCode, wParam, lParam);
}
LRESULT CALLBACK dinputLowLevelMouseProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (HC_ACTION == nCode)
{
auto& data = g_dinputMouseHookData;
data.origHookStruct = lParam;
data.hookStruct = *reinterpret_cast<MSLLHOOKSTRUCT*>(lParam);
if (WM_MOUSEMOVE == wParam)
{
data.hookStruct.pt = physicalToLogicalPoint(data.hookStruct.pt, data.dpiScale);
}
else
{
CALL_ORIG_FUNC(GetCursorPos)(&data.hookStruct.pt);
}
lParam = reinterpret_cast<LPARAM>(&g_dinputMouseHookData.hookStruct);
}
return g_dinputMouseHookData.origHookProc(nCode, wParam, lParam);
}
DWORD getDpiScaleForCursorPos()
{
POINT cp = {};
CALL_ORIG_FUNC(GetCursorPos)(&cp);
return Win32::DisplayMode::getMonitorInfo(cp).dpiScale;
}
LRESULT CALLBACK lowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (HC_ACTION == nCode &&
@ -101,12 +155,25 @@ namespace
if (WM_MOUSEMOVE == wParam)
{
POINT cp = g_cursorPos;
POINT origCp = {};
CALL_ORIG_FUNC(GetCursorPos)(&origCp);
if (MAXLONG == g_origCursorPos.y)
{
if (llHook.flags & LLMHF_INJECTED)
{
if (MAXLONG == g_origCursorPos.x)
{
g_origCursorPos.x = llHook.pt.x;
}
else
{
g_origCursorPos.y = llHook.pt.y;
}
}
return 1;
}
cp.x += (llHook.pt.x - origCp.x);
cp.y += (llHook.pt.y - origCp.y);
POINT cp = g_cursorPos;
cp.x += llHook.pt.x - g_origCursorPos.x;
cp.y += llHook.pt.y - g_origCursorPos.y;
cp.x = std::min(std::max(g_monitorRect.left, cp.x), g_monitorRect.right);
cp.y = std::min(std::max(g_monitorRect.top, cp.y), g_monitorRect.bottom);
g_cursorPos = cp;
@ -150,6 +217,16 @@ namespace
TerminateProcess(GetCurrentProcess(), 0);
}
POINT physicalToLogicalPoint(POINT pt, DWORD dpiScale)
{
if (g_physicalToLogicalPointForPerMonitorDPI)
{
g_physicalToLogicalPointForPerMonitorDPI(nullptr, &pt);
return pt;
}
return { MulDiv(pt.x, 100, dpiScale), MulDiv(pt.y, 100, dpiScale) };
}
void resetKeyboardHook()
{
Gdi::GuiThread::execute([]()
@ -171,18 +248,54 @@ namespace
{
UnhookWindowsHookEx(g_mouseHook);
}
g_origCursorPos = { MAXLONG, MAXLONG };
g_mouseHook = CALL_ORIG_FUNC(SetWindowsHookExA)(
WH_MOUSE_LL, &lowLevelMouseProc, Dll::g_currentModule, 0);
INPUT inputs[2] = {};
inputs[0].mi.dy = 1;
inputs[0].mi.dwFlags = MOUSEEVENTF_MOVE;
inputs[1].mi.dx = 1;
inputs[1].mi.dwFlags = MOUSEEVENTF_MOVE;
SendInput(2, inputs, sizeof(INPUT));
});
}
BOOL WINAPI setCursorPos(int X, int Y)
{
LOG_FUNC("SetCursorPos", X, Y);
auto result = CALL_ORIG_FUNC(SetCursorPos)(X, Y);
if (result && g_mouseHook)
{
resetMouseHook();
}
return LOG_RESULT(result);
}
HHOOK setWindowsHookEx(int idHook, HOOKPROC lpfn, HINSTANCE hmod, DWORD dwThreadId,
decltype(&SetWindowsHookExA) origSetWindowsHookEx)
{
if (WH_KEYBOARD_LL == idHook && hmod && GetModuleHandle("AcGenral") == hmod)
if (hmod && (WH_KEYBOARD_LL == idHook || WH_MOUSE_LL == idHook))
{
// Disable the IgnoreAltTab shim
return nullptr;
auto moduleName = Compat::getModulePath(hmod).stem().string();
if (WH_KEYBOARD_LL == idHook && 0 == _stricmp(moduleName.c_str(), "acgenral"))
{
// Disable the IgnoreAltTab shim
return nullptr;
}
else if (WH_MOUSE_LL == idHook &&
(0 == _stricmp(moduleName.c_str(), "dinput") || 0 == _stricmp(moduleName.c_str(), "dinput8")))
{
g_dinputMouseHookData.origHookProc = lpfn;
if (!g_physicalToLogicalPointForPerMonitorDPI)
{
g_dinputMouseHookData.dpiScale = getDpiScaleForCursorPos();
}
lpfn = dinputLowLevelMouseProc;
Compat::hookIatFunction(hmod, "CallNextHookEx", dinputCallNextHookEx);
}
}
HHOOK result = origSetWindowsHookEx(idHook, lpfn, hmod, dwThreadId);
@ -235,11 +348,6 @@ namespace Input
return g_capture ? static_cast<Overlay::Window*>(&g_capture->getRoot()) : nullptr;
}
POINT getCursorPos()
{
return g_cursorPos;
}
HWND getCursorWindow()
{
return g_cursorWindow;
@ -272,6 +380,10 @@ namespace Input
GetObject(g_bmpArrow, sizeof(bm), &bm);
g_bmpArrowSize = { bm.bmWidth, bm.bmHeight };
g_physicalToLogicalPointForPerMonitorDPI = reinterpret_cast<decltype(&PhysicalToLogicalPointForPerMonitorDPI)>(
GetProcAddress(GetModuleHandle("user32"), "PhysicalToLogicalPointForPerMonitorDPI"));
HOOK_FUNCTION(user32, SetCursorPos, setCursorPos);
HOOK_FUNCTION(user32, SetWindowsHookExA, setWindowsHookExA);
HOOK_FUNCTION(user32, SetWindowsHookExW, setWindowsHookExW);
@ -301,11 +413,7 @@ namespace Input
if (control)
{
auto window = getCaptureWindow();
MONITORINFO mi = {};
mi.cbSize = sizeof(mi);
CALL_ORIG_FUNC(GetMonitorInfoA)(MonitorFromWindow(window->getWindow(), MONITOR_DEFAULTTOPRIMARY), &mi);
g_monitorRect = mi.rcMonitor;
g_monitorRect = Win32::DisplayMode::getMonitorInfo(window->getWindow()).rcMonitor;
if (!g_mouseHook)
{

View File

@ -18,7 +18,6 @@ namespace Input
Overlay::Control* getCapture();
Overlay::Window* getCaptureWindow();
POINT getCursorPos();
HWND getCursorWindow();
POINT getRelativeCursorPos();
void installHooks();

View File

@ -72,7 +72,8 @@ namespace
namespace Overlay
{
ConfigWindow::ConfigWindow()
: Window(nullptr, { 0, 0, 640, 480 }, WS_BORDER, Config::configTransparency.get(), Config::configHotKey.get())
: Window(nullptr, { 0, 0, VIRTUAL_SCREEN_WIDTH, VIRTUAL_SCREEN_HEIGHT },
WS_BORDER, Config::configTransparency.get(), Config::configHotKey.get())
, m_buttonCount(0)
, m_focus(nullptr)
{

View File

@ -7,12 +7,12 @@
#include <Common/Log.h>
#include <Dll/Dll.h>
#include <DDraw/RealPrimarySurface.h>
#include <DDraw/Surfaces/PrimarySurface.h>
#include <Gdi/GuiThread.h>
#include <Gdi/PresentationWindow.h>
#include <Input/Input.h>
#include <Overlay/Control.h>
#include <Overlay/Window.h>
#include <Win32/DisplayMode.h>
namespace
{
@ -179,42 +179,20 @@ namespace Overlay
void Window::updatePos()
{
RECT monitorRect = DDraw::RealPrimarySurface::getMonitorRect();
if (IsRectEmpty(&monitorRect))
{
HMONITOR monitor = nullptr;
HWND foregroundWindow = GetForegroundWindow();
if (foregroundWindow)
{
monitor = MonitorFromWindow(foregroundWindow, MONITOR_DEFAULTTONEAREST);
}
else
{
monitor = MonitorFromPoint({ 0, 0 }, MONITOR_DEFAULTTOPRIMARY);
}
MONITORINFO mi = {};
mi.cbSize = sizeof(mi);
CALL_ORIG_FUNC(GetMonitorInfoA)(monitor, &mi);
monitorRect = mi.rcMonitor;
if (IsRectEmpty(&monitorRect))
{
monitorRect = { 0, 0, m_rect.right - m_rect.left, m_rect.bottom - m_rect.top };
}
}
int scaleX = (monitorRect.right - monitorRect.left) / 640;
int scaleY = (monitorRect.bottom - monitorRect.top) / 480;
const RECT monitorRect = Win32::DisplayMode::getMonitorInfo(GetForegroundWindow()).rcMonitor;
int scaleX = (monitorRect.right - monitorRect.left) / VIRTUAL_SCREEN_WIDTH;
int scaleY = (monitorRect.bottom - monitorRect.top) / VIRTUAL_SCREEN_HEIGHT;
m_scaleFactor = std::min(scaleX, scaleY);
m_scaleFactor = std::max(1, m_scaleFactor);
m_rect = calculateRect({ monitorRect.left / m_scaleFactor, monitorRect.top / m_scaleFactor,
monitorRect.right / m_scaleFactor, monitorRect.bottom / m_scaleFactor });
CALL_ORIG_FUNC(SetWindowPos)(m_hwnd, getTopmost(),
m_rect.left * m_scaleFactor, m_rect.top * m_scaleFactor,
(m_rect.right - m_rect.left) * m_scaleFactor, (m_rect.bottom - m_rect.top) * m_scaleFactor,
SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOREDRAW | SWP_NOSENDCHANGING | SWP_SHOWWINDOW);
{
CALL_ORIG_FUNC(SetWindowPos)(m_hwnd, getTopmost(),
m_rect.left * m_scaleFactor, m_rect.top * m_scaleFactor,
(m_rect.right - m_rect.left) * m_scaleFactor, (m_rect.bottom - m_rect.top) * m_scaleFactor,
SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOREDRAW | SWP_NOSENDCHANGING | SWP_SHOWWINDOW);
}
if (Input::getCaptureWindow() == this)
{

View File

@ -13,6 +13,9 @@ namespace Overlay
class Window : public Control
{
public:
static const LONG VIRTUAL_SCREEN_WIDTH = 640;
static const LONG VIRTUAL_SCREEN_HEIGHT = 480;
Window(Window* parentWindow, const RECT& rect, DWORD style, int alpha, const Input::HotKey& hotKey = {});
virtual ~Window() override;

View File

@ -9,7 +9,9 @@
#include <Common/Comparison.h>
#include <Common/CompatPtr.h>
#include <Common/Hook.h>
#include <Common/ScopedSrwLock.h>
#include <Common/Log.h>
#include <Common/Rect.h>
#include <Common/ScopedCriticalSection.h>
#include <Config/Settings/DesktopColorDepth.h>
#include <Config/Settings/DesktopResolution.h>
#include <Config/Settings/DisplayRefreshRate.h>
@ -21,6 +23,7 @@
#include <Gdi/GuiThread.h>
#include <Gdi/VirtualScreen.h>
#include <Win32/DisplayMode.h>
#include <Win32/DpiAwareness.h>
BOOL WINAPI DWM8And16Bit_IsShimApplied_CallOut() { return FALSE; }
ULONG WINAPI GdiEntry13() { return 0; }
@ -62,7 +65,10 @@ namespace
DWORD g_desktopBpp = 0;
ULONG g_displaySettingsUniquenessBias = 0;
EmulatedDisplayMode g_emulatedDisplayMode = {};
Compat::SrwLock g_srwLock;
ULONG g_monitorInfoUniqueness = 0;
std::map<HMONITOR, Win32::DisplayMode::MonitorInfo> g_monitorInfo;
Win32::DisplayMode::MonitorInfo g_emptyMonitorInfo = {};
Compat::CriticalSection g_cs;
BOOL WINAPI dwm8And16BitIsShimAppliedCallOut();
BOOL WINAPI seComHookInterface(CLSID* clsid, GUID* iid, DWORD unk1, DWORD unk2);
@ -92,24 +98,10 @@ namespace
void setDwmDxFullscreenTransitionEvent();
void adjustMonitorInfo(MONITORINFO& mi)
{
Compat::ScopedSrwLockShared srwLock(g_srwLock);
if (!g_emulatedDisplayMode.deviceName.empty() &&
g_emulatedDisplayMode.rect.left == mi.rcMonitor.left &&
g_emulatedDisplayMode.rect.top == mi.rcMonitor.top)
{
mi.rcMonitor.right += g_emulatedDisplayMode.diff.cx;
mi.rcMonitor.bottom += g_emulatedDisplayMode.diff.cy;
mi.rcWork.right += g_emulatedDisplayMode.diff.cx;
mi.rcWork.bottom += g_emulatedDisplayMode.diff.cy;
}
}
template <typename Char>
LONG changeDisplaySettingsEx(const Char* lpszDeviceName, typename DevMode<Char>* lpDevMode, HWND hwnd, DWORD dwflags, LPVOID lParam)
{
DDraw::ScopedThreadLock lock;
DDraw::ScopedThreadLock ddLock;
auto desktopResolution = Config::desktopResolution.get();
if (!lpDevMode && 0 == dwflags && Config::Settings::DesktopResolution::DESKTOP != desktopResolution)
{
@ -235,7 +227,7 @@ namespace
}
{
Compat::ScopedSrwLockExclusive srwLock(g_srwLock);
Compat::ScopedCriticalSection lock(g_cs);
++g_displaySettingsUniquenessBias;
if (lpDevMode)
{
@ -246,13 +238,7 @@ namespace
g_emulatedDisplayMode.bpp = lpDevMode->dmBitsPerPel;
}
g_emulatedDisplayMode.refreshRate = currDevMode.dmDisplayFrequency;
g_emulatedDisplayMode.deviceName = getDeviceName(lpszDeviceName);
g_emulatedDisplayMode.rect = Win32::DisplayMode::getMonitorInfo(g_emulatedDisplayMode.deviceName).rcMonitor;
g_emulatedDisplayMode.rect.right = g_emulatedDisplayMode.rect.left + emulatedResolution.cx;
g_emulatedDisplayMode.rect.bottom = g_emulatedDisplayMode.rect.top + emulatedResolution.cy;
g_emulatedDisplayMode.diff.cx = emulatedResolution.cx - currDevMode.dmPelsWidth;
g_emulatedDisplayMode.diff.cy = emulatedResolution.cy - currDevMode.dmPelsHeight;
}
else
{
@ -322,7 +308,7 @@ namespace
BOOL result = origEnumDisplaySettingsEx(lpszDeviceName, iModeNum, lpDevMode, dwFlags);
if (result)
{
Compat::ScopedSrwLockShared srwLock(g_srwLock);
Compat::ScopedCriticalSection lock(g_cs);
if (getDeviceName(lpszDeviceName) == g_emulatedDisplayMode.deviceName)
{
lpDevMode->dmBitsPerPel = g_emulatedDisplayMode.bpp;
@ -388,22 +374,10 @@ namespace
ULONG WINAPI gdiEntry13()
{
Compat::ScopedSrwLockShared lock(g_srwLock);
Compat::ScopedCriticalSection lock(g_cs);
return CALL_ORIG_FUNC(GdiEntry13)() + g_displaySettingsUniquenessBias;
}
SIZE getAppResolution(const std::wstring& deviceName, SIZE displayResolution = {})
{
{
Compat::ScopedSrwLockShared srwLock(g_srwLock);
if (deviceName == g_emulatedDisplayMode.deviceName)
{
return { static_cast<LONG>(g_emulatedDisplayMode.width), static_cast<LONG>(g_emulatedDisplayMode.height) };
}
}
return 0 != displayResolution.cx ? displayResolution : Win32::DisplayMode::getDisplayResolution(deviceName);
}
template <typename Char>
DWORD getConfiguredRefreshRate(const Char* deviceName)
{
@ -464,17 +438,8 @@ namespace
case VERTRES:
if (Gdi::isDisplayDc(hdc))
{
MONITORINFO mi = {};
mi.cbSize = sizeof(mi);
GetMonitorInfo(getMonitorFromDc(hdc), &mi);
if (HORZRES == nIndex)
{
return LOG_RESULT(mi.rcMonitor.right - mi.rcMonitor.left);
}
else
{
return LOG_RESULT(mi.rcMonitor.bottom - mi.rcMonitor.top);
}
const auto& r = Win32::DisplayMode::getMonitorInfo().rcEmulated;
return HORZRES == nIndex ? (r.right - r.left) : (r.bottom - r.top);
}
break;
@ -527,64 +492,13 @@ namespace
return mi.szDevice;
}
BOOL CALLBACK getMonitorFromDcEnum(HMONITOR hMonitor, HDC /*hdcMonitor*/, LPRECT /*lprcMonitor*/, LPARAM dwData)
{
auto& args = *reinterpret_cast<GetMonitorFromDcEnumArgs*>(dwData);
MONITORINFOEX mi = {};
mi.cbSize = sizeof(mi);
CALL_ORIG_FUNC(GetMonitorInfoA)(hMonitor, &mi);
HDC dc = CreateDC(mi.szDevice, nullptr, nullptr, nullptr);
if (dc)
{
POINT org = {};
GetDCOrgEx(dc, &org);
DeleteDC(dc);
if (org == args.org)
{
args.hmonitor = hMonitor;
return FALSE;
}
}
return TRUE;
}
HMONITOR getMonitorFromDc(HDC dc)
{
HWND hwnd = CALL_ORIG_FUNC(WindowFromDC)(dc);
if (hwnd)
{
return MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY);
}
GetMonitorFromDcEnumArgs args = {};
GetDCOrgEx(dc, &args.org);
EnumDisplayMonitors(nullptr, nullptr, getMonitorFromDcEnum, reinterpret_cast<LPARAM>(&args));
return args.hmonitor ? args.hmonitor : MonitorFromPoint({}, MONITOR_DEFAULTTOPRIMARY);
}
BOOL CALLBACK getMonitorInfoEnum(HMONITOR hMonitor, HDC /*hdcMonitor*/, LPRECT /*lprcMonitor*/, LPARAM dwData)
{
MONITORINFOEXW mi = {};
mi.cbSize = sizeof(mi);
CALL_ORIG_FUNC(GetMonitorInfoW)(hMonitor, &mi);
auto& dest = *reinterpret_cast<MONITORINFOEXW*>(dwData);
if (0 == wcscmp(mi.szDevice, dest.szDevice))
{
dest = mi;
return FALSE;
}
return TRUE;
}
BOOL WINAPI getMonitorInfoA(HMONITOR hMonitor, LPMONITORINFO lpmi)
{
LOG_FUNC("GetMonitorInfoA", hMonitor, lpmi);
BOOL result = CALL_ORIG_FUNC(GetMonitorInfoA)(hMonitor, lpmi);
if (result)
{
adjustMonitorInfo(*lpmi);
lpmi->rcMonitor = Win32::DisplayMode::getMonitorInfo(hMonitor).rcEmulated;
}
return LOG_RESULT(result);
}
@ -595,7 +509,7 @@ namespace
BOOL result = CALL_ORIG_FUNC(GetMonitorInfoW)(hMonitor, lpmi);
if (result)
{
adjustMonitorInfo(*lpmi);
lpmi->rcMonitor = Win32::DisplayMode::getMonitorInfo(hMonitor).rcEmulated;
}
return LOG_RESULT(result);
}
@ -750,50 +664,129 @@ namespace
CloseHandle(dwmDxFullscreenTransitionEvent);
}
}
BOOL CALLBACK updateMonitorInfoEnum(HMONITOR hMonitor, HDC /*hdcMonitor*/, LPRECT /*lprcMonitor*/, LPARAM /*dwData*/)
{
auto& mi = g_monitorInfo[hMonitor];
mi.cbSize = sizeof(MONITORINFOEXW);
CALL_ORIG_FUNC(GetMonitorInfoW)(hMonitor, &mi);
DEVMODEW dm = {};
dm.dmSize = sizeof(dm);
CALL_ORIG_FUNC(EnumDisplaySettingsExW)(mi.szDevice, ENUM_CURRENT_SETTINGS, &dm, 0);
mi.rcReal.left = dm.dmPosition.x;
mi.rcReal.top = dm.dmPosition.y;
mi.rcReal.right = dm.dmPosition.x + dm.dmPelsWidth;
mi.rcReal.bottom = dm.dmPosition.y + dm.dmPelsHeight;
mi.rcDpiAware = Win32::DpiAwareness::isMixedModeSupported() ? mi.rcReal : mi.rcMonitor;
mi.rcEmulated = mi.rcMonitor;
if (g_emulatedDisplayMode.deviceName == mi.szDevice)
{
mi.rcEmulated.right = mi.rcEmulated.left + g_emulatedDisplayMode.width;
mi.rcEmulated.bottom = mi.rcEmulated.top + g_emulatedDisplayMode.height;
mi.bpp = g_emulatedDisplayMode.bpp;
mi.isEmulated = true;
}
else
{
mi.bpp = g_desktopBpp;
}
mi.dpiScale = MulDiv(100, mi.rcReal.right - mi.rcReal.left, mi.rcMonitor.right - mi.rcMonitor.left);
if (0 == mi.rcMonitor.left && 0 == mi.rcMonitor.top)
{
g_monitorInfo[nullptr] = mi;
}
LOG_DEBUG << "updateMonitorInfoEnum: " << hMonitor << " " << mi;
return TRUE;
}
void updateMonitorInfo()
{
const auto uniqueness = gdiEntry13();
if (uniqueness != g_monitorInfoUniqueness || g_monitorInfo.empty())
{
g_monitorInfo.clear();
g_monitorInfoUniqueness = uniqueness;
EnumDisplayMonitors(nullptr, nullptr, &updateMonitorInfoEnum, 0);
}
}
}
namespace Win32
{
namespace DisplayMode
{
SIZE getAppResolution(const std::wstring& deviceName)
std::ostream& operator<<(std::ostream& os, const MonitorInfo& mi)
{
return ::getAppResolution(deviceName);
return Compat::LogStruct(os)
<< mi.rcMonitor
<< mi.rcWork
<< Compat::hex(mi.dwFlags)
<< mi.szDevice
<< mi.rcReal
<< mi.rcDpiAware
<< mi.rcEmulated
<< mi.bpp
<< mi.dpiScale
<< mi.isEmulated;
}
std::map<HMONITOR, MonitorInfo> getAllMonitorInfo()
{
Compat::ScopedCriticalSection lock(g_cs);
updateMonitorInfo();
auto mi = g_monitorInfo;
mi.erase(nullptr);
return mi;
}
DWORD getBpp()
{
return getEmulatedDisplayMode().bpp;
}
SIZE getDisplayResolution(const std::wstring& deviceName)
{
DEVMODEW dm = {};
dm.dmSize = sizeof(dm);
CALL_ORIG_FUNC(EnumDisplaySettingsExW)(deviceName.c_str(), ENUM_CURRENT_SETTINGS, &dm, 0);
return { static_cast<LONG>(dm.dmPelsWidth), static_cast<LONG>(dm.dmPelsHeight) };
Compat::ScopedCriticalSection lock(g_cs);
return g_emulatedDisplayMode.bpp;
}
EmulatedDisplayMode getEmulatedDisplayMode()
{
Compat::ScopedSrwLockShared lock(g_srwLock);
Compat::ScopedCriticalSection lock(g_cs);
return g_emulatedDisplayMode;
}
MONITORINFOEXW getMonitorInfo(const std::wstring& deviceName)
const MonitorInfo& getMonitorInfo(HMONITOR monitor)
{
MONITORINFOEXW mi = {};
wcscpy_s(mi.szDevice, deviceName.c_str());
EnumDisplayMonitors(nullptr, nullptr, &getMonitorInfoEnum, reinterpret_cast<LPARAM>(&mi));
return mi;
Compat::ScopedCriticalSection lock(g_cs);
updateMonitorInfo();
auto it = g_monitorInfo.find(monitor);
return it != g_monitorInfo.end() ? it->second : g_emptyMonitorInfo;
}
Resolution getResolution(const std::wstring& deviceName)
const MonitorInfo& getMonitorInfo(HWND hwnd)
{
Resolution res = {};
res.display = getDisplayResolution(deviceName);
res.app = ::getAppResolution(deviceName, res.display);
return res;
return getMonitorInfo(hwnd ? MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST) : nullptr);
}
const MonitorInfo& getMonitorInfo(POINT pt)
{
return getMonitorInfo(MonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST));
}
const MonitorInfo& getMonitorInfo(const std::wstring& deviceName)
{
Compat::ScopedCriticalSection lock(g_cs);
updateMonitorInfo();
for (const auto& mi : g_monitorInfo)
{
if (deviceName == mi.second.szDevice)
{
return mi.second;
}
}
return g_emptyMonitorInfo;
}
ULONG queryDisplaySettingsUniqueness()

View File

@ -1,10 +1,11 @@
#pragma once
#include <tuple>
#include <map>
#include <Windows.h>
#include <Common/Comparison.h>
#include <Gdi/Region.h>
namespace Win32
{
@ -21,31 +22,29 @@ namespace Win32
struct EmulatedDisplayMode : DisplayMode
{
std::wstring deviceName;
RECT rect;
SIZE diff;
};
struct Resolution
struct MonitorInfo : MONITORINFOEXW
{
SIZE app;
SIZE display;
RECT rcReal;
RECT rcDpiAware;
RECT rcEmulated;
DWORD bpp;
DWORD dpiScale;
bool isEmulated;
};
SIZE getAppResolution(const std::wstring& deviceName);
std::ostream& operator<<(std::ostream& os, const MonitorInfo& mi);
std::map<HMONITOR, MonitorInfo> getAllMonitorInfo();
DWORD getBpp();
SIZE getDisplayResolution(const std::wstring& deviceName);
EmulatedDisplayMode getEmulatedDisplayMode();
MONITORINFOEXW getMonitorInfo(const std::wstring& deviceName);
Resolution getResolution(const std::wstring& deviceName);
const MonitorInfo& getMonitorInfo(HMONITOR monitor = nullptr);
const MonitorInfo& getMonitorInfo(HWND hwnd);
const MonitorInfo& getMonitorInfo(POINT pt);
const MonitorInfo& getMonitorInfo(const std::wstring& deviceName);
ULONG queryDisplaySettingsUniqueness();
void installHooks();
using ::operator<;
inline auto toTuple(const DisplayMode& dm)
{
return std::make_tuple(dm.width, dm.height, dm.bpp, dm.refreshRate);
}
}
}

View File

@ -0,0 +1,179 @@
#include <ShellScalingApi.h>
#include <Common/Log.h>
#include <Config/Settings/DpiAwareness.h>
#include <Win32/DpiAwareness.h>
namespace
{
decltype(&AreDpiAwarenessContextsEqual) g_areDpiAwarenessContextsEqual = nullptr;
decltype(&GetProcessDpiAwareness) g_getProcessDpiAwareness = nullptr;
decltype(&GetThreadDpiAwarenessContext) g_getThreadDpiAwarenessContext = nullptr;
decltype(&IsValidDpiAwarenessContext) g_isValidDpiAwarenessContext = nullptr;
decltype(&SetProcessDpiAwareness) g_setProcessDpiAwareness = nullptr;
decltype(&SetProcessDpiAwarenessContext) g_setProcessDpiAwarenessContext = nullptr;
decltype(&SetThreadDpiAwarenessContext) g_setThreadDpiAwarenessContext = nullptr;
void logDpiAwareness(bool isSuccessful, DPI_AWARENESS_CONTEXT dpiAwareness, const char* funcName)
{
LOG_INFO << (isSuccessful ? "DPI awareness was successfully changed" : "Failed to change DPI awareness")
<< " to \"" << Config::dpiAwareness.convertToString(dpiAwareness) << "\" via " << funcName;
}
}
namespace Win32
{
ScopedDpiAwareness::ScopedDpiAwareness(bool dpiAware)
: m_prevContext(dpiAware ? DpiAwareness::setThreadContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2) : nullptr)
{
}
ScopedDpiAwareness::~ScopedDpiAwareness()
{
if (m_prevContext)
{
DpiAwareness::setThreadContext(m_prevContext);
}
}
namespace DpiAwareness
{
DPI_AWARENESS_CONTEXT getThreadContext()
{
if (g_getThreadDpiAwarenessContext && g_areDpiAwarenessContextsEqual)
{
auto context = g_getThreadDpiAwarenessContext();
if (g_areDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_UNAWARE))
{
return DPI_AWARENESS_CONTEXT_UNAWARE;
}
else if (g_areDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_SYSTEM_AWARE))
{
return DPI_AWARENESS_CONTEXT_SYSTEM_AWARE;
}
else if (g_areDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE))
{
return DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE;
}
else if (g_areDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2))
{
return DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2;
}
else if (g_areDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED))
{
return DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED;
}
}
if (g_getProcessDpiAwareness)
{
PROCESS_DPI_AWARENESS awareness = PROCESS_DPI_UNAWARE;
if (SUCCEEDED(g_getProcessDpiAwareness(nullptr, &awareness)))
{
switch (awareness)
{
case PROCESS_DPI_UNAWARE:
return DPI_AWARENESS_CONTEXT_UNAWARE;
case PROCESS_SYSTEM_DPI_AWARE:
return DPI_AWARENESS_CONTEXT_SYSTEM_AWARE;
case PROCESS_PER_MONITOR_DPI_AWARE:
return DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE;
}
}
}
return IsProcessDPIAware() ? DPI_AWARENESS_CONTEXT_SYSTEM_AWARE : DPI_AWARENESS_CONTEXT_UNAWARE;
}
void init()
{
auto user32 = GetModuleHandle("user32");
auto shcore = LoadLibrary("shcore");
g_areDpiAwarenessContextsEqual = reinterpret_cast<decltype(&AreDpiAwarenessContextsEqual)>(
GetProcAddress(user32, "AreDpiAwarenessContextsEqual"));
g_getProcessDpiAwareness = reinterpret_cast<decltype(&GetProcessDpiAwareness)>(
GetProcAddress(shcore, "GetProcessDpiAwareness"));
g_getThreadDpiAwarenessContext = reinterpret_cast<decltype(&GetThreadDpiAwarenessContext)>(
GetProcAddress(user32, "GetThreadDpiAwarenessContext"));
g_isValidDpiAwarenessContext = reinterpret_cast<decltype(&IsValidDpiAwarenessContext)>(
GetProcAddress(user32, "IsValidDpiAwarenessContext"));
g_setProcessDpiAwareness = reinterpret_cast<decltype(&SetProcessDpiAwareness)>(
GetProcAddress(shcore, "SetProcessDpiAwareness"));
g_setProcessDpiAwarenessContext = reinterpret_cast<decltype(&SetProcessDpiAwarenessContext)>(
GetProcAddress(user32, "SetProcessDpiAwarenessContext"));
g_setThreadDpiAwarenessContext = reinterpret_cast<decltype(&SetThreadDpiAwarenessContext)>(
GetProcAddress(user32, "SetThreadDpiAwarenessContext"));
LOG_INFO << "Initial DPI awareness: " << Config::dpiAwareness.convertToString(getThreadContext());
auto dpiAwareness = Config::dpiAwareness.get();
if (!dpiAwareness)
{
return;
}
if (g_isValidDpiAwarenessContext && g_setProcessDpiAwarenessContext)
{
if (DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 == dpiAwareness &&
!g_isValidDpiAwarenessContext(dpiAwareness))
{
dpiAwareness = DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE;
}
if (DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED == dpiAwareness &&
!g_isValidDpiAwarenessContext(dpiAwareness))
{
dpiAwareness = DPI_AWARENESS_CONTEXT_UNAWARE;
}
logDpiAwareness(g_setProcessDpiAwarenessContext(dpiAwareness), dpiAwareness, "SetProcessDpiAwarenessContext");
return;
}
if (g_setProcessDpiAwareness)
{
HRESULT result = S_OK;
if (DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE == dpiAwareness ||
DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 == dpiAwareness)
{
dpiAwareness = DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE;
result = g_setProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE);
}
else if (DPI_AWARENESS_CONTEXT_SYSTEM_AWARE == dpiAwareness)
{
result = g_setProcessDpiAwareness(PROCESS_SYSTEM_DPI_AWARE);
}
else
{
dpiAwareness = DPI_AWARENESS_CONTEXT_UNAWARE;
result = g_setProcessDpiAwareness(PROCESS_DPI_UNAWARE);
}
logDpiAwareness(SUCCEEDED(result), dpiAwareness, "SetProcessDpiAwareness");
return;
}
if (DPI_AWARENESS_CONTEXT_UNAWARE == dpiAwareness ||
DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED == dpiAwareness)
{
LOG_INFO << "DPI awareness was not changed";
}
else
{
logDpiAwareness(SetProcessDPIAware(), DPI_AWARENESS_CONTEXT_SYSTEM_AWARE, "SetProcessDPIAware");
}
}
bool isMixedModeSupported()
{
return g_setThreadDpiAwarenessContext;
}
DPI_AWARENESS_CONTEXT setThreadContext(DPI_AWARENESS_CONTEXT context)
{
return g_setThreadDpiAwarenessContext ? g_setThreadDpiAwarenessContext(context) : nullptr;
}
}
}

View File

@ -0,0 +1,26 @@
#pragma once
#include <Windows.h>
namespace Win32
{
class ScopedDpiAwareness
{
public:
ScopedDpiAwareness(bool dpiAware = true);
~ScopedDpiAwareness();
private:
DPI_AWARENESS_CONTEXT m_prevContext;
};
namespace DpiAwareness
{
void init();
bool isMixedModeSupported();
DPI_AWARENESS_CONTEXT getThreadContext();
DPI_AWARENESS_CONTEXT setThreadContext(DPI_AWARENESS_CONTEXT context);
}
}

View File

@ -2,6 +2,7 @@
#include <Common/Hook.h>
#include <Common/Log.h>
#include <Common/Path.h>
#include <Win32/Log.h>
namespace
@ -261,6 +262,14 @@ std::ostream& operator<<(std::ostream& os, const HFONT__& font)
<< lf;
}
std::ostream& operator<<(std::ostream& os, const HINSTANCE__& inst)
{
os << "MOD";
return Compat::LogStruct(os)
<< static_cast<const void*>(&inst)
<< Compat::getModulePath(const_cast<HINSTANCE>(&inst));
}
std::ostream& operator<<(std::ostream& os, const HRGN__& rgn)
{
os << "RGN";

View File

@ -21,6 +21,7 @@ std::ostream& operator<<(std::ostream& os, const GESTURENOTIFYSTRUCT& gns);
std::ostream& operator<<(std::ostream& os, const HDC__& dc);
std::ostream& operator<<(std::ostream& os, const HELPINFO& hi);
std::ostream& operator<<(std::ostream& os, const HFONT__& font);
std::ostream& operator<<(std::ostream& os, const HINSTANCE__& inst);
std::ostream& operator<<(std::ostream& os, const HRGN__& rgn);
std::ostream& operator<<(std::ostream& os, const HWND__& wnd);
std::ostream& operator<<(std::ostream& os, const LOGFONT& lf);

View File

@ -6,6 +6,7 @@
#include <Common/Hook.h>
#include <Common/Log.h>
#include <Dll/Dll.h>
#include <Win32/Registry.h>
typedef long NTSTATUS;
@ -66,6 +67,19 @@ namespace
#undef HKLM_SOFTWARE_KEY
LSTATUS WINAPI ddrawRegCreateKeyExA(HKEY hKey, LPCSTR lpSubKey, DWORD Reserved, LPSTR lpClass, DWORD dwOptions,
REGSAM samDesired, const LPSECURITY_ATTRIBUTES lpSecurityAttributes, PHKEY phkResult, LPDWORD lpdwDisposition)
{
LOG_FUNC("ddrawRegCreateKeyExA", hKey, lpSubKey, Reserved, lpClass, dwOptions, samDesired,
lpSecurityAttributes, phkResult, lpdwDisposition);
if (0 == lstrcmpi(lpSubKey, "Software\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Layers"))
{
return LOG_RESULT(E_ABORT);
}
return LOG_RESULT(RegCreateKeyExA(hKey, lpSubKey, Reserved, lpClass, dwOptions, samDesired,
lpSecurityAttributes, phkResult, lpdwDisposition));
}
bool filterType(DWORD type, const DWORD* flags)
{
if (!flags)
@ -424,6 +438,8 @@ namespace Win32
HOOK_REGISTRY_FUNCTION(RegGetValueW, regGetValueW);
HOOK_REGISTRY_FUNCTION(RegQueryValueExA, regQueryValueExA);
HOOK_REGISTRY_FUNCTION(RegQueryValueExW, regQueryValueExW);
Compat::hookIatFunction(Dll::g_origDDrawModule, "RegCreateKeyExA", ddrawRegCreateKeyExA);
}
}
}