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

Scale config overlay with resolution

This commit is contained in:
narzoul 2022-02-06 23:56:59 +01:00
parent 229fe449ef
commit 9d7f36c45b
15 changed files with 161 additions and 87 deletions

View File

@ -19,10 +19,12 @@
#include <Gdi/Caret.h>
#include <Gdi/Cursor.h>
#include <Gdi/Gdi.h>
#include <Gdi/GuiThread.h>
#include <Gdi/Palette.h>
#include <Gdi/VirtualScreen.h>
#include <Gdi/Window.h>
#include <Gdi/WinProc.h>
#include <Overlay/ConfigWindow.h>
#include <Win32/DisplayMode.h>
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);

View File

@ -94,7 +94,7 @@
<AdditionalIncludeDirectories>$(ProjectDir);$(IntDir)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalDependencies>dxguid.lib;msimg32.lib;oleacc.lib;uxtheme.lib;dwmapi.lib;winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>dwmapi.lib;dxguid.lib;imm32.lib;msimg32.lib;oleacc.lib;uxtheme.lib;winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
<GenerateDebugInformation>DebugFull</GenerateDebugInformation>
<OptimizeReferences>true</OptimizeReferences>
<ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
@ -130,7 +130,7 @@
<AdditionalIncludeDirectories>$(ProjectDir);$(IntDir)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalDependencies>dxguid.lib;msimg32.lib;oleacc.lib;uxtheme.lib;dwmapi.lib;winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>dwmapi.lib;dxguid.lib;imm32.lib;msimg32.lib;oleacc.lib;uxtheme.lib;winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
<GenerateDebugInformation>DebugFull</GenerateDebugInformation>
<OptimizeReferences>true</OptimizeReferences>
<ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
@ -167,7 +167,7 @@
<AdditionalIncludeDirectories>$(ProjectDir);$(IntDir)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalDependencies>dxguid.lib;msimg32.lib;oleacc.lib;uxtheme.lib;dwmapi.lib;winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>dwmapi.lib;dxguid.lib;imm32.lib;msimg32.lib;oleacc.lib;uxtheme.lib;winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
<GenerateDebugInformation>DebugFull</GenerateDebugInformation>
<OptimizeReferences>true</OptimizeReferences>
<ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>

View File

@ -57,6 +57,8 @@ namespace
unsigned WINAPI messageWindowThreadProc(LPVOID /*lpParameter*/)
{
ImmDisableIME(0);
WNDCLASS wc = {};
wc.lpfnWndProc = &messageWindowProc;
wc.hInstance = Dll::g_currentModule;

View File

@ -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<LONG>(&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);
});
}
}

View File

@ -25,4 +25,5 @@ namespace Input
void installHooks();
void registerHotKey(const HotKey& hotKey, std::function<void(void*)> action, void* context);
void setCapture(Overlay::Window* window);
void updateCursor();
}

View File

@ -1,18 +1,19 @@
#include <Common/Hook.h>
#include <Input/Input.h>
#include <Overlay/ComboBoxControl.h>
namespace Overlay
{
ComboBoxControl::ComboBoxControl(Control& parent, const RECT& rect)
ComboBoxControl::ComboBoxControl(Control& parent, const RECT& rect, const std::vector<std::string>& 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)

View File

@ -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<std::string>& values);
std::string getValue() const { return m_value; }
std::vector<std::string> getValues() const { return m_dropDown.getValues(); }

View File

@ -4,20 +4,25 @@
namespace Overlay
{
ComboBoxDropDown::ComboBoxDropDown(ComboBoxControl& parent)
: Window(&static_cast<Window&>(parent.getRoot()), { 0, 0, 100, 100 })
ComboBoxDropDown::ComboBoxDropDown(ComboBoxControl& parent, const std::vector<std::string>& values)
: Window(&static_cast<Window&>(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<int>(m_parent.getValues().size()) * ARROW_SIZE };
const RECT parentRect = parent.getRect();
return { parentRect.left, parentRect.bottom, parentRect.right,
parentRect.bottom + static_cast<int>(itemCount) * ARROW_SIZE };
}
RECT ComboBoxDropDown::calculateRect(const RECT& /*monitorRect*/) const
{
const Window& rootWindow = static_cast<const Window&>(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;
}

View File

@ -14,7 +14,7 @@ namespace Overlay
class ComboBoxDropDown : public Window
{
public:
ComboBoxDropDown(ComboBoxControl& parent);
ComboBoxDropDown(ComboBoxControl& parent, const std::vector<std::string>& values);
virtual void onNotify(Control& control) override;
@ -22,6 +22,8 @@ namespace Overlay
void setValues(const std::vector<std::string>& values);
private:
static RECT calculateRect(ComboBoxControl& parent, DWORD itemCount);
virtual RECT calculateRect(const RECT& monitorRect) const override;
virtual void onLButtonDown(POINT pos) override;

View File

@ -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;
}
}

View File

@ -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<Control&>(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();
}
}
}

View File

@ -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);

View File

@ -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()

View File

@ -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<LONG>(&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<DWORD&>(bmi.bmiColors[0]) = 0xFF0000;
reinterpret_cast<DWORD&>(bmi.bmiColors[1]) = 0x00FF00;
reinterpret_cast<DWORD&>(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<HBRUSH>(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<HBRUSH>(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<HDC>(wParam));
return 1;
case WM_PAINT:
onPaint();
return 0;
}
return CALL_ORIG_FUNC(DefWindowProcA)(m_hwnd, uMsg, wParam, lParam);

View File

@ -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;
};
}