Skip to content

Commit

Permalink
fix: 修复部分游戏缩放后 Alt+Tab 列表中出现两个窗口的情况
Browse files Browse the repository at this point in the history
  • Loading branch information
Blinue committed Mar 3, 2023
1 parent 9aae602 commit dbedf20
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 10 deletions.
68 changes: 59 additions & 9 deletions src/Magpie.Core/GraphicsCaptureFrameSource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -153,14 +153,15 @@ bool GraphicsCaptureFrameSource::_CaptureWindow(IGraphicsCaptureItemInterop* int
}

// 尝试设置源窗口样式,因为 WGC 只能捕获位于 Alt+Tab 列表中的窗口
LONG_PTR srcWndExStyle = GetWindowLongPtr(hwndSrc, GWL_EXSTYLE);
if ((srcWndExStyle & WS_EX_APPWINDOW) == 0) {
LONG_PTR srcExStyle = GetWindowLongPtr(hwndSrc, GWL_EXSTYLE);
if ((srcExStyle & WS_EX_APPWINDOW) == 0) {
// 添加 WS_EX_APPWINDOW 样式,确保源窗口可被 Alt+Tab 选中
if (SetWindowLongPtr(hwndSrc, GWL_EXSTYLE, srcWndExStyle | WS_EX_APPWINDOW)) {
if (SetWindowLongPtr(hwndSrc, GWL_EXSTYLE, srcExStyle | WS_EX_APPWINDOW)) {
Logger::Get().Info("已改变源窗口样式");
_originalSrcWndExStyle = srcWndExStyle;
_originalSrcExStyle = srcExStyle;

if (_TryCreateGraphicsCaptureItem(interop, hwndSrc)) {
_RemoveOwnerFromAltTabList(hwndSrc);
return true;
}
} else {
Expand All @@ -176,6 +177,7 @@ bool GraphicsCaptureFrameSource::_CaptureWindow(IGraphicsCaptureItemInterop* int
Logger::Get().Info("已添加任务栏图标");

if (_TryCreateGraphicsCaptureItem(interop, hwndSrc)) {
_RemoveOwnerFromAltTabList(hwndSrc);
return true;
}
} else {
Expand All @@ -192,9 +194,15 @@ bool GraphicsCaptureFrameSource::_CaptureWindow(IGraphicsCaptureItemInterop* int
_taskbarList->DeleteTab(hwndSrc);
_taskbarList = nullptr;
}
if (_originalSrcWndExStyle) {
SetWindowLongPtr(hwndSrc, GWL_EXSTYLE, _originalSrcWndExStyle);
_originalSrcWndExStyle = 0;
if (_originalSrcExStyle) {
// 首先还原所有者窗口的样式以压制任务栏的动画
if (_originalOwnerExStyle) {
SetWindowLongPtr(GetWindowOwner(hwndSrc), GWL_EXSTYLE, _originalOwnerExStyle);
_originalOwnerExStyle = 0;
}

SetWindowLongPtr(hwndSrc, GWL_EXSTYLE, _originalSrcExStyle);
_originalSrcExStyle = 0;
}

return false;
Expand All @@ -219,6 +227,43 @@ bool GraphicsCaptureFrameSource::_TryCreateGraphicsCaptureItem(IGraphicsCaptureI
return true;
}

// 部分使用 Kirikiri 引擎的游戏有着这样的架构:游戏窗口并非根窗口,它被一个尺寸为 0 的窗口
// 所有。此时 Alt+Tab 列表中的窗口和任务栏图标实际上是所有者窗口,这会导致 WGC 捕获游戏窗
// 口时失败。_CaptureWindow 在初次捕获失败后会将 WS_EX_APPWINDOW 样式添加到游戏窗口,这
// 可以工作,但也导致所有者窗口和游戏窗口同时出现 Alt+Tab 列表中,引起用户的困惑。
//
// 此函数检测这种情况并改变所有者窗口的样式使它不会出现在 Alt+Tab 列表中。
void GraphicsCaptureFrameSource::_RemoveOwnerFromAltTabList(HWND hwndSrc) noexcept {
HWND hwndOwner = GetWindowOwner(hwndSrc);
if (!hwndOwner) {
return;
}

RECT ownerRect{};
if (!GetWindowRect(hwndOwner, &ownerRect)) {
Logger::Get().Win32Error("GetWindowRect 失败");
return;
}

// 检查所有者窗口尺寸
if (ownerRect.right != ownerRect.left || ownerRect.bottom != ownerRect.top) {
return;
}

LONG_PTR ownerExStyle = GetWindowLongPtr(hwndOwner, GWL_EXSTYLE);
if (ownerExStyle == 0) {
Logger::Get().Win32Error("GetWindowLongPtr 失败");
return;
}

if (!SetWindowLongPtr(hwndOwner, GWL_EXSTYLE, ownerExStyle | WS_EX_TOOLWINDOW)) {
Logger::Get().Win32Error("SetWindowLongPtr 失败");
return;
}

_originalOwnerExStyle = ownerExStyle;
}

bool GraphicsCaptureFrameSource::_CaptureMonitor(IGraphicsCaptureItemInterop* interop) {
// WDA_EXCLUDEFROMCAPTURE 只在 Win10 20H1 及更新版本中可用
if (!Win32Utils::GetOSVersion().Is20H1OrNewer()) {
Expand Down Expand Up @@ -354,8 +399,13 @@ GraphicsCaptureFrameSource::~GraphicsCaptureFrameSource() {
}

// 还原源窗口样式
if (_originalSrcWndExStyle) {
SetWindowLongPtr(hwndSrc, GWL_EXSTYLE, _originalSrcWndExStyle);
if (_originalSrcExStyle) {
// 首先还原所有者窗口的样式以压制任务栏的动画
if (_originalOwnerExStyle) {
SetWindowLongPtr(GetWindowOwner(hwndSrc), GWL_EXSTYLE, _originalOwnerExStyle);
}

SetWindowLongPtr(hwndSrc, GWL_EXSTYLE, _originalSrcExStyle);
}
}

Expand Down
5 changes: 4 additions & 1 deletion src/Magpie.Core/GraphicsCaptureFrameSource.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,10 @@ class GraphicsCaptureFrameSource : public FrameSourceBase {

bool _TryCreateGraphicsCaptureItem(IGraphicsCaptureItemInterop* interop, HWND hwndSrc) noexcept;

LONG_PTR _originalSrcWndExStyle = 0;
void _RemoveOwnerFromAltTabList(HWND hwndSrc) noexcept;

LONG_PTR _originalSrcExStyle = 0;
LONG_PTR _originalOwnerExStyle = 0;
winrt::com_ptr<ITaskbarList> _taskbarList;

D3D11_BOX _frameBox{};
Expand Down

0 comments on commit dbedf20

Please sign in to comment.