#include "d3d9_window.h" #include "d3d9_swapchain.h" namespace dxvk { #ifdef _WIN32 struct D3D9WindowData { bool unicode; bool filter; bool activateProcessed; WNDPROC proc; D3D9SwapChainEx* swapchain; }; static dxvk::recursive_mutex g_windowProcMapMutex; static std::unordered_map g_windowProcMap; D3D9WindowMessageFilter::D3D9WindowMessageFilter(HWND window, bool filter) : m_window(window) { std::lock_guard lock(g_windowProcMapMutex); auto it = g_windowProcMap.find(m_window); m_filter = std::exchange(it->second.filter, filter); } D3D9WindowMessageFilter::~D3D9WindowMessageFilter() { std::lock_guard lock(g_windowProcMapMutex); auto it = g_windowProcMap.find(m_window); it->second.filter = m_filter; } LRESULT CALLBACK D3D9WindowProc(HWND window, UINT message, WPARAM wparam, LPARAM lparam) { if (message == WM_NCCALCSIZE && wparam == TRUE) return 0; D3D9WindowData windowData = {}; { std::lock_guard lock(g_windowProcMapMutex); auto it = g_windowProcMap.find(window); if (it != g_windowProcMap.end()) windowData = it->second; } bool unicode = windowData.proc ? windowData.unicode : IsWindowUnicode(window); if (!windowData.proc || windowData.filter) return CallCharsetFunction( DefWindowProcW, DefWindowProcA, unicode, window, message, wparam, lparam); if (message == WM_DESTROY) ResetWindowProc(window); else if (message == WM_ACTIVATEAPP) { D3DDEVICE_CREATION_PARAMETERS create_parms; windowData.swapchain->GetDevice()->GetCreationParameters(&create_parms); if (!(create_parms.BehaviorFlags & D3DCREATE_NOWINDOWCHANGES)) { D3D9WindowMessageFilter filter(window); if (wparam && !windowData.activateProcessed) { // Heroes of Might and Magic V needs this to resume drawing after a focus loss D3DPRESENT_PARAMETERS params; RECT rect; wsi::getDesktopCoordinates(wsi::getDefaultMonitor(), &rect); windowData.swapchain->GetPresentParameters(¶ms); SetWindowPos(window, nullptr, rect.left, rect.top, params.BackBufferWidth, params.BackBufferHeight, SWP_NOACTIVATE | SWP_NOZORDER); SetActivateProcessed(window, true); } else if (!wparam) { if (IsWindowVisible(window)) ShowWindow(window, SW_MINIMIZE); SetActivateProcessed(window, false); } } } else if (message == WM_SIZE) { D3DDEVICE_CREATION_PARAMETERS create_parms; windowData.swapchain->GetDevice()->GetCreationParameters(&create_parms); if (!(create_parms.BehaviorFlags & D3DCREATE_NOWINDOWCHANGES) && !IsIconic(window)) PostMessageW(window, WM_ACTIVATEAPP, 1, GetCurrentThreadId()); } return CallCharsetFunction( CallWindowProcW, CallWindowProcA, unicode, windowData.proc, window, message, wparam, lparam); } void ResetWindowProc(HWND window) { std::lock_guard lock(g_windowProcMapMutex); auto it = g_windowProcMap.find(window); if (it == g_windowProcMap.end()) return; auto proc = reinterpret_cast( CallCharsetFunction( GetWindowLongPtrW, GetWindowLongPtrA, it->second.unicode, window, GWLP_WNDPROC)); if (proc == D3D9WindowProc) CallCharsetFunction( SetWindowLongPtrW, SetWindowLongPtrA, it->second.unicode, window, GWLP_WNDPROC, reinterpret_cast(it->second.proc)); g_windowProcMap.erase(window); } void HookWindowProc(HWND window, D3D9SwapChainEx* swapchain) { std::lock_guard lock(g_windowProcMapMutex); ResetWindowProc(window); D3D9WindowData windowData; windowData.unicode = IsWindowUnicode(window); windowData.filter = false; windowData.activateProcessed = false; windowData.proc = reinterpret_cast( CallCharsetFunction( SetWindowLongPtrW, SetWindowLongPtrA, windowData.unicode, window, GWLP_WNDPROC, reinterpret_cast(D3D9WindowProc))); windowData.swapchain = swapchain; g_windowProcMap[window] = std::move(windowData); } void SetActivateProcessed(HWND window, bool processed) { std::lock_guard lock(g_windowProcMapMutex); auto it = g_windowProcMap.find(window); if (it != g_windowProcMap.end()) it->second.activateProcessed = processed; } #else D3D9WindowMessageFilter::D3D9WindowMessageFilter(HWND window, bool filter) { } D3D9WindowMessageFilter::~D3D9WindowMessageFilter() { } void ResetWindowProc(HWND window) { } void HookWindowProc(HWND window, D3D9SwapChainEx* swapchain) { } void SetActivateProcessed(HWND window, bool processed) { } #endif }