diff --git a/DDrawCompat/DDraw/RealPrimarySurface.cpp b/DDrawCompat/DDraw/RealPrimarySurface.cpp index 3fa48e3..3128aba 100644 --- a/DDrawCompat/DDraw/RealPrimarySurface.cpp +++ b/DDrawCompat/DDraw/RealPrimarySurface.cpp @@ -19,10 +19,12 @@ #include #include #include +#include #include #include #include #include +#include #include namespace @@ -160,6 +162,23 @@ namespace Gdi::VirtualScreen::update(); + Gdi::GuiThread::execute([]() + { + auto configWindow = Gdi::GuiThread::getConfigWindow(); + if (configWindow) + { + configWindow->update(); + } + + auto capture = Input::getCapture(); + if (capture) + { + capture->update(); + } + + Input::updateCursor(); + }); + if (!g_frontBuffer || !src || DDraw::RealPrimarySurface::isLost()) { Gdi::Window::present(nullptr); diff --git a/DDrawCompat/DDrawCompat.vcxproj b/DDrawCompat/DDrawCompat.vcxproj index 0884e32..b6388a8 100644 --- a/DDrawCompat/DDrawCompat.vcxproj +++ b/DDrawCompat/DDrawCompat.vcxproj @@ -94,7 +94,7 @@ $(ProjectDir);$(IntDir) - dxguid.lib;msimg32.lib;oleacc.lib;uxtheme.lib;dwmapi.lib;winmm.lib;%(AdditionalDependencies) + dwmapi.lib;dxguid.lib;imm32.lib;msimg32.lib;oleacc.lib;uxtheme.lib;winmm.lib;%(AdditionalDependencies) DebugFull true $(IntDir)$(TargetName).lib @@ -130,7 +130,7 @@ $(ProjectDir);$(IntDir) - dxguid.lib;msimg32.lib;oleacc.lib;uxtheme.lib;dwmapi.lib;winmm.lib;%(AdditionalDependencies) + dwmapi.lib;dxguid.lib;imm32.lib;msimg32.lib;oleacc.lib;uxtheme.lib;winmm.lib;%(AdditionalDependencies) DebugFull true $(IntDir)$(TargetName).lib @@ -167,7 +167,7 @@ $(ProjectDir);$(IntDir) - dxguid.lib;msimg32.lib;oleacc.lib;uxtheme.lib;dwmapi.lib;winmm.lib;%(AdditionalDependencies) + dwmapi.lib;dxguid.lib;imm32.lib;msimg32.lib;oleacc.lib;uxtheme.lib;winmm.lib;%(AdditionalDependencies) DebugFull true $(IntDir)$(TargetName).lib diff --git a/DDrawCompat/Gdi/GuiThread.cpp b/DDrawCompat/Gdi/GuiThread.cpp index 37952a9..4f8631b 100644 --- a/DDrawCompat/Gdi/GuiThread.cpp +++ b/DDrawCompat/Gdi/GuiThread.cpp @@ -57,6 +57,8 @@ namespace unsigned WINAPI messageWindowThreadProc(LPVOID /*lpParameter*/) { + ImmDisableIME(0); + WNDCLASS wc = {}; wc.lpfnWndProc = &messageWindowProc; wc.hInstance = Dll::g_currentModule; diff --git a/DDrawCompat/Input/Input.cpp b/DDrawCompat/Input/Input.cpp index 9622fcd..c211f21 100644 --- a/DDrawCompat/Input/Input.cpp +++ b/DDrawCompat/Input/Input.cpp @@ -34,7 +34,6 @@ namespace LRESULT CALLBACK lowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam); LRESULT CALLBACK lowLevelMouseProc(int nCode, WPARAM wParam, LPARAM lParam); - void setCursorPos(POINT cp); LRESULT CALLBACK cursorWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { @@ -95,11 +94,14 @@ namespace cp.y += (llHook.pt.y - origCp.y); cp.x = min(max(g_monitorRect.left, cp.x), g_monitorRect.right); cp.y = min(max(g_monitorRect.top, cp.y), g_monitorRect.bottom); - setCursorPos(cp); + g_cursorPos = cp; - RECT r = g_capture->getRect(); - cp.x -= r.left; - cp.y -= r.top; + const RECT rect = g_capture->getRect(); + const int scaleFactor = g_capture->getScaleFactor(); + cp.x /= scaleFactor; + cp.y /= scaleFactor; + cp.x -= rect.left; + cp.y -= rect.top; switch (wParam) { @@ -116,6 +118,7 @@ namespace break; } + DDraw::RealPrimarySurface::scheduleUpdate(); return 1; } return CallNextHookEx(nullptr, nCode, wParam, lParam); @@ -147,13 +150,6 @@ namespace }); } - void setCursorPos(POINT cp) - { - g_cursorPos = cp; - CALL_ORIG_FUNC(SetWindowPos)(g_cursorWindow, HWND_TOPMOST, cp.x, cp.y, g_bmpArrowSize.cx, g_bmpArrowSize.cy, - SWP_ASYNCWINDOWPOS | SWP_NOACTIVATE | SWP_NOSENDCHANGING); - } - HHOOK setWindowsHookEx(int idHook, HOOKPROC lpfn, HINSTANCE hmod, DWORD dwThreadId, decltype(&SetWindowsHookExA) origSetWindowsHookEx) { @@ -239,17 +235,17 @@ namespace Input g_capture = window; if (window) { + MONITORINFO mi = {}; + mi.cbSize = sizeof(mi); + GetMonitorInfo(MonitorFromWindow(window->getWindow(), MONITOR_DEFAULTTOPRIMARY), &mi); + g_monitorRect = mi.rcMonitor; + if (!g_mouseHook) { g_cursorWindow = Gdi::PresentationWindow::create(window->getWindow()); CALL_ORIG_FUNC(SetWindowLongA)(g_cursorWindow, GWL_WNDPROC, reinterpret_cast(&cursorWindowProc)); CALL_ORIG_FUNC(SetLayeredWindowAttributes)(g_cursorWindow, RGB(0xFF, 0xFF, 0xFF), 0, LWA_COLORKEY); - MONITORINFO mi = {}; - mi.cbSize = sizeof(mi); - GetMonitorInfo(MonitorFromWindow(window->getWindow(), MONITOR_DEFAULTTOPRIMARY), &mi); - g_monitorRect = mi.rcMonitor; - RECT r = window->getRect(); g_cursorPos = { (r.left + r.right) / 2, (r.top + r.bottom) / 2 }; CALL_ORIG_FUNC(SetWindowPos)(g_cursorWindow, HWND_TOPMOST, g_cursorPos.x, g_cursorPos.y, @@ -266,4 +262,13 @@ namespace Input g_cursorWindow = nullptr; } } + + void updateCursor() + { + Gdi::GuiThread::execute([]() + { + CALL_ORIG_FUNC(SetWindowPos)(g_cursorWindow, HWND_TOPMOST, g_cursorPos.x, g_cursorPos.y, + g_bmpArrowSize.cx, g_bmpArrowSize.cy, SWP_NOACTIVATE | SWP_NOSENDCHANGING); + }); + } } diff --git a/DDrawCompat/Input/Input.h b/DDrawCompat/Input/Input.h index 404c26b..2fc0d01 100644 --- a/DDrawCompat/Input/Input.h +++ b/DDrawCompat/Input/Input.h @@ -25,4 +25,5 @@ namespace Input void installHooks(); void registerHotKey(const HotKey& hotKey, std::function action, void* context); void setCapture(Overlay::Window* window); + void updateCursor(); } diff --git a/DDrawCompat/Overlay/ComboBoxControl.cpp b/DDrawCompat/Overlay/ComboBoxControl.cpp index 56c475a..5bd7038 100644 --- a/DDrawCompat/Overlay/ComboBoxControl.cpp +++ b/DDrawCompat/Overlay/ComboBoxControl.cpp @@ -1,18 +1,19 @@ #include +#include #include namespace Overlay { - ComboBoxControl::ComboBoxControl(Control& parent, const RECT& rect) + ComboBoxControl::ComboBoxControl(Control& parent, const RECT& rect, const std::vector& values) : Control(&parent, rect, WS_BORDER | WS_VISIBLE) - , m_dropDown(*this) + , m_dropDown(*this, values) { } void ComboBoxControl::setValue(const std::string& value) { m_value = value; - invalidate(m_rect); + invalidate(); } void ComboBoxControl::draw(HDC dc) diff --git a/DDrawCompat/Overlay/ComboBoxControl.h b/DDrawCompat/Overlay/ComboBoxControl.h index 2774699..569e1fb 100644 --- a/DDrawCompat/Overlay/ComboBoxControl.h +++ b/DDrawCompat/Overlay/ComboBoxControl.h @@ -11,7 +11,7 @@ namespace Overlay class ComboBoxControl : public Control { public: - ComboBoxControl(Control& parent, const RECT& rect); + ComboBoxControl(Control& parent, const RECT& rect, const std::vector& values); std::string getValue() const { return m_value; } std::vector getValues() const { return m_dropDown.getValues(); } diff --git a/DDrawCompat/Overlay/ComboBoxDropDown.cpp b/DDrawCompat/Overlay/ComboBoxDropDown.cpp index f3d4c07..c93e6fc 100644 --- a/DDrawCompat/Overlay/ComboBoxDropDown.cpp +++ b/DDrawCompat/Overlay/ComboBoxDropDown.cpp @@ -4,20 +4,25 @@ namespace Overlay { - ComboBoxDropDown::ComboBoxDropDown(ComboBoxControl& parent) - : Window(&static_cast(parent.getRoot()), { 0, 0, 100, 100 }) + ComboBoxDropDown::ComboBoxDropDown(ComboBoxControl& parent, const std::vector& values) + : Window(&static_cast(parent.getRoot()), calculateRect(parent, values.size())) , m_parent(parent) { + setValues(values); } - RECT ComboBoxDropDown::calculateRect(const RECT& monitorRect) const + RECT ComboBoxDropDown::calculateRect(ComboBoxControl& parent, DWORD itemCount) { - const RECT parentRect = m_parent.getRect(); - RECT r = { parentRect.left, parentRect.bottom, - parentRect.right, parentRect.bottom + static_cast(m_parent.getValues().size()) * ARROW_SIZE }; + const RECT parentRect = parent.getRect(); + return { parentRect.left, parentRect.bottom, parentRect.right, + parentRect.bottom + static_cast(itemCount) * ARROW_SIZE }; + } + RECT ComboBoxDropDown::calculateRect(const RECT& /*monitorRect*/) const + { const Window& rootWindow = static_cast(m_parent.getRoot()); - const RECT rootRect = rootWindow.calculateRect(monitorRect); + const RECT rootRect = rootWindow.getRect(); + RECT r = calculateRect(m_parent, m_values.size()); OffsetRect(&r, rootRect.left, rootRect.top); return r; } diff --git a/DDrawCompat/Overlay/ComboBoxDropDown.h b/DDrawCompat/Overlay/ComboBoxDropDown.h index 3e0b398..caad5a1 100644 --- a/DDrawCompat/Overlay/ComboBoxDropDown.h +++ b/DDrawCompat/Overlay/ComboBoxDropDown.h @@ -14,7 +14,7 @@ namespace Overlay class ComboBoxDropDown : public Window { public: - ComboBoxDropDown(ComboBoxControl& parent); + ComboBoxDropDown(ComboBoxControl& parent, const std::vector& values); virtual void onNotify(Control& control) override; @@ -22,6 +22,8 @@ namespace Overlay void setValues(const std::vector& values); private: + static RECT calculateRect(ComboBoxControl& parent, DWORD itemCount); + virtual RECT calculateRect(const RECT& monitorRect) const override; virtual void onLButtonDown(POINT pos) override; diff --git a/DDrawCompat/Overlay/ConfigWindow.cpp b/DDrawCompat/Overlay/ConfigWindow.cpp index 5496b37..cd715c8 100644 --- a/DDrawCompat/Overlay/ConfigWindow.cpp +++ b/DDrawCompat/Overlay/ConfigWindow.cpp @@ -27,12 +27,9 @@ namespace Overlay RECT ConfigWindow::calculateRect(const RECT& monitorRect) const { - const LONG width = m_rect.right - m_rect.left; - const LONG height = m_rect.bottom - m_rect.top; - - RECT r = { 0, 0, width, height }; - OffsetRect(&r, monitorRect.left, monitorRect.top); - OffsetRect(&r, (monitorRect.right - monitorRect.left - width) / 2, (monitorRect.bottom - monitorRect.top - height) / 2); + RECT r = { 0, 0, m_rect.right - m_rect.left, m_rect.bottom - m_rect.top }; + OffsetRect(&r, monitorRect.left + (monitorRect.right - monitorRect.left - r.right) / 2, + monitorRect.top + (monitorRect.bottom - monitorRect.top - r.bottom) / 2); return r; } } diff --git a/DDrawCompat/Overlay/Control.cpp b/DDrawCompat/Overlay/Control.cpp index 7cc7d3d..8a4d6ca 100644 --- a/DDrawCompat/Overlay/Control.cpp +++ b/DDrawCompat/Overlay/Control.cpp @@ -38,7 +38,7 @@ namespace Overlay RECT r = m_rect; if (!m_parent) { - OffsetRect(&r, -m_rect.left, -m_rect.top); + OffsetRect(&r, -r.left, -r.top); } CALL_ORIG_FUNC(Rectangle)(dc, r.left, r.top, r.right, r.bottom); } @@ -102,11 +102,11 @@ namespace Overlay return const_cast(std::as_const(*this).getRoot()); } - void Control::invalidate(const RECT& rect) + void Control::invalidate() { if (m_parent) { - m_parent->invalidate(rect); + m_parent->invalidate(); } } @@ -153,7 +153,7 @@ namespace Overlay if (isVisible != Control::isVisible()) { m_style ^= WS_VISIBLE; - invalidate(m_rect); + invalidate(); } } } diff --git a/DDrawCompat/Overlay/Control.h b/DDrawCompat/Overlay/Control.h index 07d4408..8782934 100644 --- a/DDrawCompat/Overlay/Control.h +++ b/DDrawCompat/Overlay/Control.h @@ -21,7 +21,7 @@ namespace Overlay Control& operator=(Control&&) = delete; virtual void draw(HDC /*dc*/) {} - virtual void invalidate(const RECT& rect); + virtual void invalidate(); virtual void onLButtonDown(POINT pos); virtual void onLButtonUp(POINT pos); virtual void onMouseMove(POINT pos); diff --git a/DDrawCompat/Overlay/SettingControl.cpp b/DDrawCompat/Overlay/SettingControl.cpp index d60eb7a..212cad7 100644 --- a/DDrawCompat/Overlay/SettingControl.cpp +++ b/DDrawCompat/Overlay/SettingControl.cpp @@ -33,9 +33,8 @@ namespace Overlay { const RECT r = { rect.left + SETTING_LABEL_WIDTH, rect.top + BORDER / 2, rect.left + SETTING_LABEL_WIDTH + SETTING_CONTROL_WIDTH, rect.bottom - BORDER / 2 }; - m_valueControl.reset(new ComboBoxControl(*this, r)); + m_valueControl.reset(new ComboBoxControl(*this, r, getValueStrings(setting))); getValueComboBox().setValue(setting.getValueStr()); - getValueComboBox().setValues(getValueStrings(setting)); onValueChanged(); updateValuesParam(); } @@ -64,7 +63,7 @@ namespace Overlay D3dDdi::Device::updateAllConfig(); } - invalidate(m_rect); + invalidate(); } void SettingControl::onParamChanged() diff --git a/DDrawCompat/Overlay/Window.cpp b/DDrawCompat/Overlay/Window.cpp index c79f74f..2a063a5 100644 --- a/DDrawCompat/Overlay/Window.cpp +++ b/DDrawCompat/Overlay/Window.cpp @@ -50,6 +50,11 @@ namespace Overlay , m_hwnd(Gdi::PresentationWindow::create(parentWindow ? parentWindow->m_hwnd : nullptr)) , m_parentWindow(parentWindow) , m_transparency(25) + , m_scaleFactor(1) + , m_dc(CreateCompatibleDC(nullptr)) + , m_bitmap(nullptr) + , m_bitmapBits(nullptr) + , m_invalid(true) { g_windows.emplace(m_hwnd, *this); CALL_ORIG_FUNC(SetWindowLongA)(m_hwnd, GWL_WNDPROC, reinterpret_cast(&staticWindowProc)); @@ -59,46 +64,44 @@ namespace Overlay { Input::registerHotKey(hotKey, &toggleWindow, this); } + + struct BITMAPINFO3 : public BITMAPINFO + { + RGBQUAD bmiRemainingColors[2]; + }; + + BITMAPINFO3 bmi = {}; + bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader); + bmi.bmiHeader.biWidth = rect.right - rect.left; + bmi.bmiHeader.biHeight = rect.top - rect.bottom; + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biBitCount = 32; + bmi.bmiHeader.biCompression = BI_BITFIELDS; + reinterpret_cast(bmi.bmiColors[0]) = 0xFF0000; + reinterpret_cast(bmi.bmiColors[1]) = 0x00FF00; + reinterpret_cast(bmi.bmiColors[2]) = 0x0000FF; + + m_bitmap = CreateDIBSection(nullptr, &bmi, DIB_RGB_COLORS, &m_bitmapBits, nullptr, 0); + SaveDC(m_dc); + SelectObject(m_dc, m_bitmap); } Window::~Window() { Gdi::GuiThread::destroyWindow(m_hwnd); g_windows.erase(m_hwnd); + RestoreDC(m_dc, -1); + DeleteDC(m_dc); + DeleteObject(m_bitmap); } void Window::draw(HDC /*dc*/) { } - void Window::invalidate(const RECT& rect) + void Window::invalidate() { - InvalidateRect(m_hwnd, &rect, TRUE); - } - - void Window::onEraseBackground(HDC dc) - { - RECT r = { 0, 0, m_rect.right - m_rect.left, m_rect.bottom - m_rect.top }; - CALL_ORIG_FUNC(FillRect)(dc, &r, static_cast(GetStockObject(BLACK_BRUSH))); - } - - void Window::onPaint() - { - static HFONT font = createDefaultFont(); - - PAINTSTRUCT ps = {}; - HDC dc = BeginPaint(m_hwnd, &ps); - SelectObject(dc, font); - SelectObject(dc, GetStockObject(DC_PEN)); - SelectObject(dc, GetStockObject(NULL_BRUSH)); - SetBkColor(dc, RGB(0, 0, 0)); - SetDCBrushColor(dc, RGB(0, 0, 0)); - SetDCPenColor(dc, RGB(0, 255, 0)); - SetTextColor(dc, RGB(0, 255, 0)); - - drawAll(dc); - - EndPaint(m_hwnd, &ps); + m_invalid = true; DDraw::RealPrimarySurface::scheduleUpdate(); } @@ -144,6 +147,35 @@ namespace Overlay return CALL_ORIG_FUNC(DefWindowProcA)(hwnd, uMsg, wParam, lParam); } + void Window::update() + { + if (!m_invalid || !isVisible()) + { + return; + } + m_invalid = false; + + static HFONT font = createDefaultFont(); + + SelectObject(m_dc, font); + SelectObject(m_dc, GetStockObject(DC_PEN)); + SelectObject(m_dc, GetStockObject(NULL_BRUSH)); + SetBkColor(m_dc, RGB(0, 0, 0)); + SetDCBrushColor(m_dc, RGB(0, 0, 0)); + SetDCPenColor(m_dc, RGB(0, 255, 0)); + SetTextColor(m_dc, RGB(0, 255, 0)); + + RECT rect = { 0, 0, m_rect.right - m_rect.left, m_rect.bottom - m_rect.top }; + CALL_ORIG_FUNC(FillRect)(m_dc, &rect, static_cast(GetStockObject(BLACK_BRUSH))); + drawAll(m_dc); + + HDC windowDc = GetWindowDC(m_hwnd); + CALL_ORIG_FUNC(StretchBlt)( + windowDc, 0, 0, (m_rect.right - m_rect.left) * m_scaleFactor, (m_rect.bottom - m_rect.top) * m_scaleFactor, + m_dc, 0, 0, rect.right - rect.left, rect.bottom - rect.top, SRCCOPY); + ReleaseDC(m_hwnd, windowDc); + } + void Window::updatePos() { auto monitorRect = Win32::DisplayMode::getEmulatedDisplayMode().rect; @@ -175,9 +207,22 @@ namespace Overlay } } - m_rect = calculateRect(monitorRect); - CALL_ORIG_FUNC(SetWindowPos)(m_hwnd, HWND_TOPMOST, m_rect.left, m_rect.top, - m_rect.right - m_rect.left, m_rect.bottom - m_rect.top, SWP_NOACTIVATE); + int scaleX = (monitorRect.right - monitorRect.left) / 640; + int scaleY = (monitorRect.bottom - monitorRect.top) / 480; + m_scaleFactor = min(scaleX, scaleY); + m_scaleFactor = 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, HWND_TOPMOST, 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); + + if (Input::getCapture() == this) + { + Input::setCapture(this); + } + + invalidate(); } LRESULT Window::windowProc(UINT uMsg, WPARAM wParam, LPARAM lParam) @@ -187,14 +232,6 @@ namespace Overlay case WM_DISPLAYCHANGE: updatePos(); break; - - case WM_ERASEBKGND: - onEraseBackground(reinterpret_cast(wParam)); - return 1; - - case WM_PAINT: - onPaint(); - return 0; } return CALL_ORIG_FUNC(DefWindowProcA)(m_hwnd, uMsg, wParam, lParam); diff --git a/DDrawCompat/Overlay/Window.h b/DDrawCompat/Overlay/Window.h index b656f01..3cabbc4 100644 --- a/DDrawCompat/Overlay/Window.h +++ b/DDrawCompat/Overlay/Window.h @@ -16,11 +16,13 @@ namespace Overlay virtual ~Window() override; virtual RECT calculateRect(const RECT& monitorRect) const = 0; - virtual void invalidate(const RECT& rect) override; + virtual void invalidate() override; virtual void setVisible(bool isVisible) override; + int getScaleFactor() const { return m_scaleFactor; } HWND getWindow() const { return m_hwnd; } void setTransparency(int transparency); + void update(); protected: HWND m_hwnd; @@ -32,10 +34,14 @@ namespace Overlay private: virtual void draw(HDC dc) override; - void onEraseBackground(HDC dc); - void onPaint(); LRESULT windowProc(UINT uMsg, WPARAM wParam, LPARAM lParam); static LRESULT CALLBACK staticWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + + int m_scaleFactor; + HDC m_dc; + HBITMAP m_bitmap; + void* m_bitmapBits; + bool m_invalid; }; }