mirror of
https://github.com/Blinue/Magpie.git
synced 2026-06-24 02:04:10 +00:00
parent
dd458ff447
commit
06ffbf76f7
5 changed files with 103 additions and 53 deletions
|
|
@ -347,18 +347,18 @@ void ScalingWindow::SwitchToolbarState() noexcept {
|
|||
}
|
||||
|
||||
void ScalingWindow::Render() noexcept {
|
||||
const bool originIsSrcFocused = _srcTracker.IsFocused();
|
||||
|
||||
bool isSrcRepositioning = false;
|
||||
if (!_UpdateSrcState(isSrcRepositioning)) {
|
||||
bool srcFocusedChanged = false;
|
||||
bool srcOwnedWindowFocusedChanged = false;
|
||||
if (!_UpdateSrcState(isSrcRepositioning, srcFocusedChanged, srcOwnedWindowFocusedChanged)) {
|
||||
Logger::Get().Info("源窗口状态改变");
|
||||
_DelayedStop(false, isSrcRepositioning);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_srcTracker.IsFocused() != originIsSrcFocused) {
|
||||
_UpdateFocusStateAsync();
|
||||
}
|
||||
if (srcFocusedChanged || srcOwnedWindowFocusedChanged) {
|
||||
_UpdateFocusStateAsync(!srcFocusedChanged && srcOwnedWindowFocusedChanged, false);
|
||||
}
|
||||
|
||||
// 虽然可以在第一帧渲染完成后再隐藏系统光标,但某些设备上显示窗口时光标状态会变成忙,
|
||||
// 提前隐藏光标可以提高观感。缩放窗口显示后再隐藏光标还可能造成光标闪烁两次,第一次是
|
||||
|
|
@ -1174,7 +1174,7 @@ void ScalingWindow::_Show() noexcept {
|
|||
|
||||
// 如果源窗口位于前台则将缩放窗口置顶
|
||||
if (_srcTracker.IsFocused()) {
|
||||
_UpdateFocusStateAsync(true);
|
||||
_UpdateFocusStateAsync(false, true);
|
||||
}
|
||||
|
||||
if (_options.IsTouchSupportEnabled()) {
|
||||
|
|
@ -1228,7 +1228,11 @@ void ScalingWindow::_MoveRenderer() noexcept {
|
|||
}
|
||||
}
|
||||
|
||||
bool ScalingWindow::_UpdateSrcState(bool& isSrcRepositioning) noexcept {
|
||||
bool ScalingWindow::_UpdateSrcState(
|
||||
bool& isSrcRepositioning,
|
||||
bool& srcFocusedChanged,
|
||||
bool& srcOwnedWindowFocusedChanged
|
||||
) noexcept {
|
||||
HWND hwndFore = GetForegroundWindow();
|
||||
|
||||
if (hwndFore == Handle()) {
|
||||
|
|
@ -1247,8 +1251,9 @@ bool ScalingWindow::_UpdateSrcState(bool& isSrcRepositioning) noexcept {
|
|||
bool srcRectChanged = false;
|
||||
bool srcSizeChanged = false;
|
||||
bool srcMovingChanged = false;
|
||||
if (!_srcTracker.UpdateState(hwndFore, _options.IsWindowedMode(),
|
||||
_isResizingOrMoving, srcRectChanged, srcSizeChanged, srcMovingChanged)) {
|
||||
if (!_srcTracker.UpdateState(hwndFore, _options.IsWindowedMode(), _isResizingOrMoving,
|
||||
srcFocusedChanged, srcOwnedWindowFocusedChanged,
|
||||
srcRectChanged, srcSizeChanged, srcMovingChanged)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -1803,14 +1808,19 @@ void ScalingWindow::_UpdateFrameMargins() const noexcept {
|
|||
DwmExtendFrameIntoClientArea(Handle(), &margins);
|
||||
}
|
||||
|
||||
winrt::fire_and_forget ScalingWindow::_UpdateFocusStateAsync(bool onShow) const noexcept {
|
||||
if (_options.IsWindowedMode()) {
|
||||
winrt::fire_and_forget ScalingWindow::_UpdateFocusStateAsync(
|
||||
bool onSrcOwnedWindowFocusedChanged,
|
||||
bool onShow
|
||||
) const noexcept {
|
||||
if (!onSrcOwnedWindowFocusedChanged && _options.IsWindowedMode()) {
|
||||
// 根据源窗口状态绘制非客户区,我们必须自己控制非客户区是绘制成焦点状态还是非焦点
|
||||
// 状态,因为缩放窗口实际上永远不会得到焦点。
|
||||
DefWindowProc(Handle(), WM_NCACTIVATE, _srcTracker.IsFocused(), 0);
|
||||
}
|
||||
|
||||
if (!_options.IsDebugMode() && (_srcTracker.IsOwnedWindowFocused() || !_options.IsWindowedMode())) {
|
||||
if (_srcTracker.IsOwnedWindowFocused() ||
|
||||
(!onSrcOwnedWindowFocusedChanged && !_options.IsWindowedMode()))
|
||||
{
|
||||
if (!onShow) {
|
||||
const uint32_t runId = RunId();
|
||||
|
||||
|
|
@ -1834,12 +1844,14 @@ winrt::fire_and_forget ScalingWindow::_UpdateFocusStateAsync(bool onShow) const
|
|||
const HWND hwndPrev = GetWindow(_srcTracker.Handle(), GW_HWNDPREV);
|
||||
SetWindowPos(Handle(), hwndPrev,
|
||||
0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
|
||||
} else if (!_options.IsWindowedMode()) {
|
||||
} else if (!onSrcOwnedWindowFocusedChanged && !_options.IsWindowedMode()) {
|
||||
// 源窗口位于前台时将缩放窗口置顶,这使不支持 MPO 的显卡更容易激活 DirectFlip
|
||||
if (_srcTracker.IsFocused()) {
|
||||
SetWindowPos(Handle(), HWND_TOPMOST,
|
||||
0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
|
||||
// 再次调用 SetWindowPos 确保缩放窗口在所有置顶窗口之上
|
||||
if (!_options.IsDebugMode()) {
|
||||
SetWindowPos(Handle(), HWND_TOPMOST,
|
||||
0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
|
||||
}
|
||||
// 非调试模式时再次调用 SetWindowPos 确保缩放窗口在所有置顶窗口之上
|
||||
SetWindowPos(Handle(), HWND_TOP,
|
||||
0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
|
||||
} else {
|
||||
|
|
@ -1849,11 +1861,13 @@ winrt::fire_and_forget ScalingWindow::_UpdateFocusStateAsync(bool onShow) const
|
|||
}
|
||||
}
|
||||
|
||||
if (_srcTracker.IsFocused()) {
|
||||
PostMessage(HWND_BROADCAST, WM_MAGPIE_SCALINGCHANGED, 1, (LPARAM)Handle());
|
||||
} else {
|
||||
// lParam 传 1 表示转到后台而非结束缩放
|
||||
PostMessage(HWND_BROADCAST, WM_MAGPIE_SCALINGCHANGED, 0, 1);
|
||||
if (!onSrcOwnedWindowFocusedChanged) {
|
||||
if (_srcTracker.IsFocused()) {
|
||||
PostMessage(HWND_BROADCAST, WM_MAGPIE_SCALINGCHANGED, 1, (LPARAM)Handle());
|
||||
} else {
|
||||
// lParam 传 1 表示转到后台而非结束缩放
|
||||
PostMessage(HWND_BROADCAST, WM_MAGPIE_SCALINGCHANGED, 0, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -106,7 +106,11 @@ private:
|
|||
|
||||
void _Show() noexcept;
|
||||
|
||||
bool _UpdateSrcState(bool& isSrcRepositioning) noexcept;
|
||||
bool _UpdateSrcState(
|
||||
bool& isSrcRepositioning,
|
||||
bool& srcFocusedChanged,
|
||||
bool& srcOwnedWindowFocusedChanged
|
||||
) noexcept;
|
||||
|
||||
bool _CheckForegroundFor3DGameMode(HWND hwndFore) const noexcept;
|
||||
|
||||
|
|
@ -136,7 +140,10 @@ private:
|
|||
|
||||
void _UpdateFrameMargins() const noexcept;
|
||||
|
||||
winrt::fire_and_forget _UpdateFocusStateAsync(bool onShow = false) const noexcept;
|
||||
winrt::fire_and_forget _UpdateFocusStateAsync(
|
||||
bool onSrcOwnedWindowFocusedChanged,
|
||||
bool onShow
|
||||
) const noexcept;
|
||||
|
||||
bool _IsBorderless() const noexcept;
|
||||
|
||||
|
|
|
|||
|
|
@ -77,7 +77,9 @@ ScalingError SrcTracker::Set(HWND hWnd, const ScalingOptions& options) noexcept
|
|||
return ScalingError::InvalidSourceWindow;
|
||||
}
|
||||
|
||||
_isFocused = GetForegroundWindow() == hWnd;
|
||||
const HWND hwndFore = GetForegroundWindow();
|
||||
_isFocused = hwndFore == hWnd;
|
||||
_UpdateIsOwnedWindowFocused(hwndFore);
|
||||
|
||||
if (!GetWindowRect(hWnd, &_windowRect)) {
|
||||
Logger::Get().Win32Error("GetWindowRect 失败");
|
||||
|
|
@ -159,16 +161,6 @@ ScalingError SrcTracker::Set(HWND hWnd, const ScalingOptions& options) noexcept
|
|||
return _CalcSrcRect(options, borderThicknessInFrame);
|
||||
}
|
||||
|
||||
static bool IsOwnedWindow(HWND hwndOwner, HWND hwndTest) noexcept {
|
||||
HWND hwndCur = hwndTest;
|
||||
while (bool(hwndCur = GetWindowOwner(hwndCur))) {
|
||||
if (hwndCur == hwndOwner) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool IsPrimaryMouseButtonDown() noexcept {
|
||||
const bool isSwapped = GetSystemMetrics(SM_SWAPBUTTON);
|
||||
const int vkPrimary = isSwapped ? VK_RBUTTON : VK_LBUTTON;
|
||||
|
|
@ -179,11 +171,13 @@ bool SrcTracker::UpdateState(
|
|||
HWND hwndFore,
|
||||
bool isWindowedMode,
|
||||
bool isResizingOrMoving,
|
||||
bool& srcRectChanged,
|
||||
bool& srcSizeChanged,
|
||||
bool& srcMovingChanged
|
||||
bool& focusedChanged,
|
||||
bool& ownedWindowFocusedChanged,
|
||||
bool& rectChanged,
|
||||
bool& sizeChanged,
|
||||
bool& movingChanged
|
||||
) noexcept {
|
||||
assert(!srcRectChanged && !srcSizeChanged && !srcMovingChanged);
|
||||
assert(!focusedChanged && !ownedWindowFocusedChanged && !rectChanged && !sizeChanged && !movingChanged);
|
||||
|
||||
if (!IsWindow(_hWnd)) {
|
||||
Logger::Get().Error("源窗口已销毁");
|
||||
|
|
@ -204,8 +198,12 @@ bool SrcTracker::UpdateState(
|
|||
return false;
|
||||
}
|
||||
|
||||
_isFocused = hwndFore == _hWnd;
|
||||
_isOwnedWindowFocused = !_isFocused && IsOwnedWindow(_hWnd, hwndFore);
|
||||
if (_isFocused != (hwndFore == _hWnd)) {
|
||||
_isFocused = !_isFocused;
|
||||
focusedChanged = true;
|
||||
}
|
||||
|
||||
ownedWindowFocusedChanged = _UpdateIsOwnedWindowFocused(hwndFore);
|
||||
|
||||
const bool oldMaximized = _isMaximized;
|
||||
UINT showCmd = Win32Helper::GetWindowShowCmd(_hWnd);
|
||||
|
|
@ -221,19 +219,19 @@ bool SrcTracker::UpdateState(
|
|||
return false;
|
||||
}
|
||||
|
||||
srcSizeChanged = oldMaximized != _isMaximized ||
|
||||
sizeChanged = oldMaximized != _isMaximized ||
|
||||
Win32Helper::GetSizeOfRect(curWindowRect) != Win32Helper::GetSizeOfRect(_windowRect);
|
||||
|
||||
// 缩放窗口正在调整大小或被拖动时源窗口的移动是异步的,暂时不检查源窗口是否移动
|
||||
if (isResizingOrMoving) {
|
||||
srcRectChanged = oldMaximized != _isMaximized;
|
||||
rectChanged = oldMaximized != _isMaximized;
|
||||
return true;
|
||||
}
|
||||
|
||||
// 最大化状态改变视为尺寸发生变化
|
||||
srcRectChanged = oldMaximized != _isMaximized || curWindowRect != _windowRect;
|
||||
rectChanged = oldMaximized != _isMaximized || curWindowRect != _windowRect;
|
||||
|
||||
if (isWindowedMode && !srcSizeChanged) {
|
||||
if (isWindowedMode && !sizeChanged) {
|
||||
bool isMoving = false;
|
||||
GUITHREADINFO guiThreadInfo{ .cbSize = sizeof(GUITHREADINFO) };
|
||||
if (GetGUIThreadInfo(GetWindowThreadProcessId(_hWnd, nullptr), &guiThreadInfo)) {
|
||||
|
|
@ -244,11 +242,11 @@ bool SrcTracker::UpdateState(
|
|||
|
||||
// 处理自己实现拖拽逻辑的窗口:将鼠标左键按下视为开始拖拽,释放视为拖拽结束。
|
||||
// 可能会有误判,但幸好后果不太严重。
|
||||
if (_isMoving || (!_isMoving && srcRectChanged)) {
|
||||
if (_isMoving || (!_isMoving && rectChanged)) {
|
||||
isMoving = isMoving || IsPrimaryMouseButtonDown();
|
||||
}
|
||||
|
||||
if (srcRectChanged) {
|
||||
if (rectChanged) {
|
||||
const LONG offsetX = curWindowRect.left - _windowRect.left;
|
||||
const LONG offsetY = curWindowRect.top - _windowRect.top;
|
||||
Win32Helper::OffsetRect(_windowFrameRect, offsetX, offsetY);
|
||||
|
|
@ -256,12 +254,12 @@ bool SrcTracker::UpdateState(
|
|||
}
|
||||
|
||||
if (_isMoving != isMoving) {
|
||||
srcMovingChanged = true;
|
||||
movingChanged = true;
|
||||
_isMoving = isMoving;
|
||||
}
|
||||
}
|
||||
|
||||
if (srcRectChanged) {
|
||||
if (rectChanged) {
|
||||
_windowRect = curWindowRect;
|
||||
}
|
||||
|
||||
|
|
@ -422,6 +420,10 @@ static bool GetClientRectOfUWP(HWND hWnd, RECT& rect) noexcept {
|
|||
}
|
||||
|
||||
bool SrcTracker::SetFocus() const noexcept {
|
||||
if (_isOwnedWindowFocused) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 如果源窗口存在弹窗(即被源窗口所有的窗口),应把弹窗设为前台窗口
|
||||
const HWND hwndPopup = GetWindow(_hWnd, GW_ENABLEDPOPUP);
|
||||
return SetForegroundWindow(hwndPopup ? hwndPopup : _hWnd);
|
||||
|
|
@ -488,4 +490,27 @@ ScalingError SrcTracker::_CalcSrcRect(const ScalingOptions& options, LONG border
|
|||
return ScalingError::NoError;
|
||||
}
|
||||
|
||||
static bool IsOwnedWindow(HWND hwndOwner, HWND hwndTest) noexcept {
|
||||
HWND hwndCur = hwndTest;
|
||||
while (bool(hwndCur = GetWindowOwner(hwndCur))) {
|
||||
if (hwndCur == hwndOwner) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SrcTracker::_UpdateIsOwnedWindowFocused(HWND hwndFore) noexcept {
|
||||
// 支持两种形式的弹窗
|
||||
// 1. 弹窗被源窗口所有
|
||||
// 2. 弹窗没有被源窗口所有,但弹出时源窗口被禁用
|
||||
bool newValue = !_isFocused && (IsOwnedWindow(_hWnd, hwndFore) || !IsWindowEnabled(_hWnd));
|
||||
if (_isOwnedWindowFocused == newValue) {
|
||||
return false;
|
||||
} else {
|
||||
_isOwnedWindowFocused = newValue;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,9 +33,11 @@ public:
|
|||
HWND hwndFore,
|
||||
bool isWindowedMode,
|
||||
bool isResizingOrMoving,
|
||||
bool& srcRectChanged,
|
||||
bool& srcSizeChanged,
|
||||
bool& srcMovingChanged
|
||||
bool& focusedChanged,
|
||||
bool& ownedWindowFocusedChanged,
|
||||
bool& rectChanged,
|
||||
bool& sizeChanged,
|
||||
bool& movingChanged
|
||||
) noexcept;
|
||||
|
||||
bool Move(int offsetX, int offsetY, bool async) noexcept;
|
||||
|
|
@ -85,6 +87,8 @@ public:
|
|||
private:
|
||||
ScalingError _CalcSrcRect(const ScalingOptions& options, LONG borderThicknessInFrame) noexcept;
|
||||
|
||||
bool _UpdateIsOwnedWindowFocused(HWND hwndFore) noexcept;
|
||||
|
||||
HWND _hWnd = NULL;
|
||||
RECT _windowRect{};
|
||||
RECT _windowFrameRect{};
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
#include "CommonSharedConstants.h"
|
||||
#include "JsonHelper.h"
|
||||
#include "Logger.h"
|
||||
#include "MainWindow.h"
|
||||
#include "StrHelper.h"
|
||||
#include "UpdateService.h"
|
||||
#include "Version.h"
|
||||
|
|
@ -11,7 +12,6 @@
|
|||
#include <bcrypt.h>
|
||||
#include <wil/resource.h> // 再次包含以激活 CNG 相关包装器
|
||||
#include <rapidjson/document.h>
|
||||
#include <shellapi.h>
|
||||
#include <winrt/Windows.Storage.Streams.h>
|
||||
#include <winrt/Windows.Web.Http.h>
|
||||
#include <zip/zip.h>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue