Skip to content

Commit 8885479

Browse files
authored
fix: 修复 Win32 DWM 阴影计算 (#1272)
1 parent 7e9c7a4 commit 8885479

2 files changed

Lines changed: 23 additions & 36 deletions

File tree

source/MaaWin32ControlUnit/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ target_include_directories(MaaWin32ControlUnit
77
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${MAA_PRIVATE_INC} ${MAA_PUBLIC_INC})
88

99
target_link_libraries(MaaWin32ControlUnit PRIVATE MaaUtils ${OpenCV_LIBS} ZLIB::ZLIB Boost::system)
10-
target_link_libraries(MaaWin32ControlUnit PRIVATE d3d11 dxgi runtimeobject winmm)
10+
target_link_libraries(MaaWin32ControlUnit PRIVATE d3d11 dxgi dwmapi runtimeobject winmm)
1111

1212
target_compile_definitions(MaaWin32ControlUnit PRIVATE MAA_CONTROL_UNIT_EXPORTS)
1313

source/MaaWin32ControlUnit/Screencap/FramePoolScreencap.cpp

Lines changed: 22 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#if MAA_FRAMEPOOL_SCREENCAP_AVAILABLE
44

5+
#include <dwmapi.h>
56
#include <windows.graphics.capture.interop.h>
67
#include <windows.graphics.directx.direct3d11.interop.h>
78
#include <winrt/Windows.Foundation.Metadata.h>
@@ -110,46 +111,33 @@ std::optional<cv::Mat> FramePoolScreencap::screencap()
110111

111112
cv::Mat raw(texture_desc_.Height, texture_desc_.Width, CV_8UC4, mapped.pData, mapped.RowPitch);
112113

113-
// 先按 alpha 通道裁剪掉四周 alpha != 255 的边框
114-
cv::Mat alpha_channel;
115-
cv::extractChannel(raw, alpha_channel, 3);
116-
117-
cv::Mat alpha_bin;
118-
cv::threshold(alpha_channel, alpha_bin, UCHAR_MAX - 1, UCHAR_MAX, cv::THRESH_BINARY);
119-
120-
cv::Rect alpha_roi = cv::boundingRect(alpha_bin);
121-
if (alpha_roi.empty()) {
122-
LogError << "No opaque pixels found";
123-
return std::nullopt;
124-
}
125-
cv::Mat trimmed = raw(alpha_roi);
126-
127-
// 获取窗口客户区矩形(相对于窗口)
128114
RECT client_rect = { 0 };
129115
if (!GetClientRect(hwnd_, &client_rect)) {
130116
LogError << "GetClientRect failed";
131117
return std::nullopt;
132118
}
133119

134-
// 将客户区左上角转换为屏幕坐标
135120
POINT client_top_left = { client_rect.left, client_rect.top };
136121
if (!ClientToScreen(hwnd_, &client_top_left)) {
137122
LogError << "ClientToScreen failed";
138123
return std::nullopt;
139124
}
140125

141-
// 获取窗口矩形(屏幕坐标)
142-
RECT window_rect = { 0 };
143-
if (!GetWindowRect(hwnd_, &window_rect)) {
144-
LogError << "GetWindowRect failed";
145-
return std::nullopt;
126+
// 使用 DWM 实际可视帧边界,排除 GetWindowRect 中包含的不可见 DWM 阴影区域,
127+
// 以正确计算 WGC 捕获画面中的边框偏移
128+
RECT frame_rect = { 0 };
129+
HRESULT hr = DwmGetWindowAttribute(hwnd_, DWMWA_EXTENDED_FRAME_BOUNDS, &frame_rect, sizeof(frame_rect));
130+
if (FAILED(hr)) {
131+
LogWarn << "DwmGetWindowAttribute failed, falling back to GetWindowRect" << VAR(hr);
132+
if (!GetWindowRect(hwnd_, &frame_rect)) {
133+
LogError << "GetWindowRect failed";
134+
return std::nullopt;
135+
}
146136
}
147137

148-
// 计算边框位置,减去 alpha 裁剪的偏移
149-
int border_left = client_top_left.x - window_rect.left - alpha_roi.x;
150-
int border_top = client_top_left.y - window_rect.top - alpha_roi.y;
138+
int border_left = client_top_left.x - frame_rect.left;
139+
int border_top = client_top_left.y - frame_rect.top;
151140

152-
// 获取客户区大小
153141
int client_width = client_rect.right - client_rect.left;
154142
int client_height = client_rect.bottom - client_rect.top;
155143

@@ -159,22 +147,21 @@ std::optional<cv::Mat> FramePoolScreencap::screencap()
159147
if (border_top < 0) {
160148
border_top = 0;
161149
}
162-
if (client_width > trimmed.cols) {
163-
client_width = trimmed.cols;
150+
if (client_width > raw.cols) {
151+
client_width = raw.cols;
164152
}
165-
if (border_left + client_width > trimmed.cols) {
166-
border_left = trimmed.cols - client_width;
153+
if (border_left + client_width > raw.cols) {
154+
border_left = raw.cols - client_width;
167155
}
168-
if (client_height > trimmed.rows) {
169-
client_height = trimmed.rows;
156+
if (client_height > raw.rows) {
157+
client_height = raw.rows;
170158
}
171-
if (border_top + client_height > trimmed.rows) {
172-
border_top = trimmed.rows - client_height;
159+
if (border_top + client_height > raw.rows) {
160+
border_top = raw.rows - client_height;
173161
}
174162

175-
// 裁剪出客户区(去掉边框)
176163
cv::Rect client_roi(border_left, border_top, client_width, client_height);
177-
cv::Mat image = trimmed(client_roi);
164+
cv::Mat image = raw(client_roi);
178165

179166
cv::Mat result = bgra_to_bgr(image);
180167
cached_image_ = result.clone();

0 commit comments

Comments
 (0)