Magpie/tools/WindowCase/KirikiriWindow.cpp
Xu d01956e3a7
源窗口位于前台时始终置顶缩放窗口 (#1259)
* feat: 模拟中途置顶的窗口

* fix: 按钮随 DPI 缩放

* fix: 始终置顶

* fix: 修复切换前台窗口

* feat: 删除置顶选项

* refactor: 检查逻辑

* refactor: 用更简单的方式将缩放窗口置于源窗口之前

* fix: 支持源窗口中途置顶

* refactor: 小优化

* fix: 修复特定操作下意外将源窗口置顶

* fix: 提高取消置顶的可靠性

* fix: 调试模式下不置顶

* chore: WindowCase 支持模拟弹窗

* fix: 不要把被禁用的窗口设为前台

* feat: WindowCase 支持模拟“模拟模态弹窗”

* chore: 避免大量错误日志

* fix: 优化 Z 顺序维护

* fix: 不再使用 SWP_NOOWNERZORDER

* fix: 修复消息弹窗可能影响窗口 Z 顺序

* refactor: 小优化

* chore: 添加注释

* chore: 添加注释

* fix: 小优化

* chore: 小优化
2025-08-21 17:49:05 +08:00

110 lines
2.5 KiB
C++

// 模拟 TVP(KIRIKIRI) 2 引擎窗口,特征是主窗口被一个零尺寸的窗口所有。模拟了大部分
// 行为,只有最小化和还原时无动画不知道如何做到的。
#include "pch.h"
#include "KirikiriWindow.h"
bool KirikiriWindow::Create(HINSTANCE hInst) noexcept {
static const wchar_t* OWNER_NAME = L"KirikiriOwnerWindow";
static const wchar_t* WINDOW_NAME = L"KirikiriWindow";
WNDCLASSEXW wcex{
.cbSize = sizeof(WNDCLASSEX),
.style = CS_HREDRAW | CS_VREDRAW,
.lpfnWndProc = _OwnerWndProc,
.hInstance = hInst,
.hCursor = LoadCursor(nullptr, IDC_ARROW),
.hbrBackground = HBRUSH(COLOR_WINDOW + 1),
.lpszClassName = OWNER_NAME
};
if (!RegisterClassEx(&wcex)) {
return false;
}
_hwndOwner = CreateWindowEx(
0,
OWNER_NAME,
OWNER_NAME,
WS_POPUP | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU,
CW_USEDEFAULT,
CW_USEDEFAULT,
0,
0,
NULL,
NULL,
hInst,
this
);
wcex.lpfnWndProc = _WndProc;
wcex.lpszClassName = WINDOW_NAME;
if (!RegisterClassEx(&wcex)) {
return false;
}
CreateWindow(
WINDOW_NAME,
WINDOW_NAME,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
_hwndOwner,
NULL,
hInst,
this
);
if (!Handle()) {
return false;
}
ShowWindow(_hwndOwner, SW_SHOWNORMAL);
const double dpiScale = _DpiScale();
SetWindowPos(Handle(), NULL, 0, 0,
std::lround(500 * dpiScale), std::lround(400 * dpiScale),
SWP_NOMOVE | SWP_SHOWWINDOW);
return true;
}
LRESULT KirikiriWindow::_MessageHandler(UINT msg, WPARAM wParam, LPARAM lParam) noexcept {
switch (msg) {
case WM_SYSCOMMAND:
{
if ((wParam & 0xFFF0) == SC_MINIMIZE) {
SendMessage(_hwndOwner, msg, wParam, lParam);
// 所有者窗口最小化后此窗口自动隐藏,无需真的最小化
return 0;
}
break;
}
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return base_type::_MessageHandler(msg, wParam, lParam);
}
LRESULT KirikiriWindow::_OwnerWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
if (msg == WM_NCCREATE) {
KirikiriWindow* that = (KirikiriWindow*)(((CREATESTRUCT*)lParam)->lpCreateParams);
assert(that && !that->_hwndOwner);
that->_hwndOwner = hWnd;
SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)that);
} else if (KirikiriWindow* that = (KirikiriWindow*)GetWindowLongPtr(hWnd, GWLP_USERDATA)) {
switch (msg) {
case WM_ACTIVATE:
{
if (LOWORD(wParam) != WA_INACTIVE) {
SetForegroundWindow(that->Handle());
}
return 0;
}
}
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}