feat: 实现绘制光标 (p2)

This commit is contained in:
Xu 2026-01-12 17:28:16 +08:00
commit 514858993c
13 changed files with 332 additions and 93 deletions

View file

@ -92,7 +92,7 @@ void CursorDrawer::Draw(ID3D11Texture2D* backBuffer, POINT drawOffset) noexcept
if (isCursorActive) {
// 启用自动隐藏时光标形状或位置变化后应记录新的形状、位置和变化时间。位置由
// _lastCursorPos 记录。
// _curCursorPos 记录。
_lastRawCursorHandle = scalingWindow.CursorManager().CursorHandle();
_lastCursorActiveTime = std::chrono::steady_clock::now();
}

View file

@ -2,46 +2,71 @@
#include "CursorDrawer2.h"
#include "ScalingWindow.h"
#include "Win32Helper.h"
#include "Logger.h"
#include <ShellScalingApi.h>
#include <wil/registry.h>
namespace Magpie {
bool CursorDrawer2::Initialize(GraphicsContext& graphicsContext) noexcept {
// 系统 DPI 在程序的生命周期内不会改变,而且使用 GetIconInfo 获得的位图尺寸
// 和此值有关。
static UINT SYSTEM_DPI;
static DWORD GetCursorBaseSize() noexcept {
DWORD cursorBaseSize = 32;
HRESULT hr = wil::reg::get_value_nothrow(
HKEY_CURRENT_USER, L"Control Panel\\Cursors", L"CursorBaseSize", &cursorBaseSize);
// 键不存在不视为错误
if (FAILED(hr) && hr != HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) {
Logger::Get().ComError("wil::reg::get_value_dword_nothrow 失败", hr);
}
return cursorBaseSize;
}
bool CursorDrawer2::Initialize(GraphicsContext& graphicsContext, const RECT& destRect) noexcept {
_graphicsContext = &graphicsContext;
_destRect = destRect;
[[maybe_unused]] static Ignore _ = []() {
SYSTEM_DPI = GetDpiForSystem();
return Ignore();
}();
wil::unique_hkey key;
wil::reg::open_unique_key_nothrow(HKEY_CURRENT_USER, L"Control Panel\\Cursors", key);
_regWatcher = wil::make_registry_watcher_nothrow(std::move(key), false, [this](wil::RegistryChangeKind) {
ScalingWindow::Dispatcher().TryEnqueue(
[this, cursorBaseSize(GetCursorBaseSize()), runId(ScalingWindow::RunId())]() {
if (ScalingWindow::RunId() != runId || _cursorBaseSize == cursorBaseSize) {
return;
}
_cursorBaseSize = cursorBaseSize;
});
});
_cursorBaseSize = GetCursorBaseSize();
return true;
}
bool CursorDrawer2::NeedRedraw(HCURSOR& /*hCursor*/, POINT /*cursorPos*/) const noexcept {
/*bool isCursorActive = false;
_GetCursorState(hCursor, cursorPos, isCursorActive);
// 检查光标是否在视口内
// 光标形状或位置变化时需要重新绘制
return hCursor != _lastCursorHandle || (hCursor && cursorPos != _lastCursorPos);*/
return false;
}
void CursorDrawer2::Draw(HCURSOR /*hCursor*/, POINT /*cursorPos*/) noexcept {
}
void CursorDrawer2::_GetCursorState(HCURSOR& hCursor, POINT cursorPos, bool& isActive) const noexcept {
assert(!isActive);
using namespace std::chrono;
bool CursorDrawer2::CheckForRedraw(HCURSOR& hCursor, POINT cursorPos) noexcept {
const ScalingWindow& scalingWindow = ScalingWindow::Get();
const ScalingOptions& options = scalingWindow.Options();
// 检查自动隐藏光标
if (options.autoHideCursorDelay.has_value()) {
using namespace std::chrono;
// 光标在叠加层上或拖动窗口时禁用自动隐藏。光标处于隐藏状态视为形状不变,考虑形状
// 变化:箭头->隐藏->箭头,只要位置不变,自动隐藏功能应让光标始终隐藏;反之如果光
// 标隐藏时移动了或显示时形状变化了应正常显示。
if (_isCursorVirtualized &&
!_isMoving &&
!_isSrcMoving &&
_lastCursorPos == cursorPos &&
_curCursorPos == cursorPos &&
(_lastRawCursorHandle == hCursor || !hCursor)
) {
const duration<float> hideDelay(*options.autoHideCursorDelay);
@ -49,14 +74,168 @@ void CursorDrawer2::_GetCursorState(HCURSOR& hCursor, POINT cursorPos, bool& isA
hCursor = NULL;
}
} else {
isActive = true;
// 启用自动隐藏时光标形状或位置变化后应记录新的形状、位置和变化时间。位置由
// _curCursorPos 记录。
_lastRawCursorHandle = hCursor;
_lastCursorActiveTime = steady_clock::now();
}
}
// 截屏时暂时不渲染光标
if (!_isCursorVisible) {
hCursor = NULL;
if (hCursor) {
if (_isCursorVisible) {
// 检查光标是否在视口内
const _CursorInfo* cursorInfo = _ResolveCursor(hCursor, cursorPos);
if (cursorInfo) {
const RECT cursorRect = {
cursorPos.x,
cursorPos.y,
cursorPos.x + (LONG)cursorInfo->size.width,
cursorPos.y + (LONG)cursorInfo->size.height
};
if (!Win32Helper::IsRectOverlap(cursorRect, _destRect)) {
hCursor = NULL;
}
} else {
Logger::Get().Error("_ResolveCursor 失败");
hCursor = NULL;
}
} else {
// 截屏时暂时不渲染光标
hCursor = NULL;
}
}
// 光标形状或位置变化时需要重新绘制
if (hCursor != _hCurCursor || (hCursor && cursorPos != _curCursorPos)) {
_hCurCursor = hCursor;
_curCursorPos = cursorPos;
return true;
} else {
return false;
}
}
void CursorDrawer2::Draw() noexcept {
}
static Size CalcCursorSize(
Size cursorBmpSize,
uint32_t cursorDpi,
uint32_t monitorDpi,
uint32_t cursorBaseSize
) noexcept {
const double scale = (GetSystemMetricsForDpi(SM_CXCURSOR, monitorDpi) * cursorBaseSize) /
double(GetSystemMetricsForDpi(SM_CXCURSOR, cursorDpi) * 32);
return { (uint32_t)std::lround(cursorBmpSize.width * scale),
(uint32_t)std::lround(cursorBmpSize.height * scale) };
}
const CursorDrawer2::_CursorInfo* CursorDrawer2::_ResolveCursor(
HCURSOR hCursor,
POINT cursorPos
) noexcept {
// 检索光标所在屏幕的 DPI
const HMONITOR hCurMon = MonitorFromPoint(
{ cursorPos.x + _destRect.left, cursorPos.y + _destRect.top }, MONITOR_DEFAULTTOPRIMARY);
UINT monitorDpi = USER_DEFAULT_SCREEN_DPI;
GetDpiForMonitor(hCurMon, MDT_EFFECTIVE_DPI, &monitorDpi, &monitorDpi);
auto it = _cursorInfos.find(std::make_pair(hCursor, monitorDpi));
if (it != _cursorInfos.end()) {
return &it->second;
}
// 检查此光标是否不随 DPI 缩放
it = _cursorInfos.find(std::make_pair(hCursor, 0));
if (it != _cursorInfos.end()) {
return &it->second;
}
ICONINFOEX iconInfoEx = { .cbSize = sizeof(iconInfoEx) };
if (!GetIconInfoEx(hCursor, &iconInfoEx)) {
Logger::Get().Win32Error("GetIconInfoEx 失败");
return nullptr;
}
wil::unique_hbitmap hColorBmp(iconInfoEx.hbmColor);
wil::unique_hbitmap hMaskBmp(iconInfoEx.hbmMask);
Size bmpSize;
{
BITMAP bmp{};
if (!GetObject(hColorBmp ? hColorBmp.get() : hMaskBmp.get(), sizeof(bmp), &bmp)) {
Logger::Get().Win32Error("GetObject 失败");
return nullptr;
}
// 单色光标的掩码位图高度是光标实际高度的两倍
bmpSize = {
uint32_t(bmp.bmWidth),
uint32_t(hColorBmp ? bmp.bmHeight : bmp.bmHeight / 2)
};
}
_CursorInfo cursorInfo{};
// 如果不能确定光标是否随 DPI 缩放则假设为真,绝大多数情况下是对的
bool isCursorDpiAware = true;
// 将线程 DPI 感知设为 unaware 后 GetIconInfo 可以获得 100% DPI 缩放下的光标位图。
// 我们借助这个特性检查光标是否随 DPI 缩放,不过只在程序启动时系统 DPI 缩放不是
// 100% 时有效。
if (SYSTEM_DPI == 96) {
cursorInfo.size = CalcCursorSize(bmpSize, SYSTEM_DPI, monitorDpi, _cursorBaseSize);
} else {
ICONINFO iconInfoDpi96{};
{
DPI_AWARENESS_CONTEXT oldDpiContext =
SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_UNAWARE);
auto se = wil::scope_exit([&] {
SetThreadDpiAwarenessContext(oldDpiContext);
});
if (!GetIconInfo(hCursor, &iconInfoDpi96)) {
Logger::Get().Win32Error("GetIconInfo 失败");
return nullptr;
}
}
wil::unique_hbitmap hColorBmpDpi96(iconInfoDpi96.hbmColor);
wil::unique_hbitmap hMaskBmpDpi96(iconInfoDpi96.hbmMask);
Size bmpSizeDpi96;
{
BITMAP bmp{};
if (!GetObject(hColorBmpDpi96 ? hColorBmpDpi96.get() : hMaskBmpDpi96.get(), sizeof(bmp), &bmp)) {
Logger::Get().Win32Error("GetObject 失败");
return nullptr;
}
bmpSizeDpi96 = {
uint32_t(bmp.bmWidth),
uint32_t(hColorBmpDpi96 ? bmp.bmHeight : bmp.bmHeight / 2)
};
}
// 不同 DPI 下光标位图尺寸不变说明光标不跟随 DPI 缩放
if (bmpSize == bmpSizeDpi96) {
isCursorDpiAware = false;
cursorInfo.size = bmpSizeDpi96;
} else {
cursorInfo.size = CalcCursorSize(bmpSizeDpi96, 96, monitorDpi, _cursorBaseSize);
}
if (cursorInfo.size == bmpSizeDpi96) {
hColorBmp = std::move(hColorBmpDpi96);
hMaskBmp = std::move(hMaskBmpDpi96);
bmpSize = bmpSizeDpi96;
}
}
cursorInfo.resourceSize = bmpSize;
return &_cursorInfos.emplace(std::make_pair(hCursor, isCursorDpiAware ? monitorDpi : 0),
std::move(cursorInfo)).first->second;
}
}

View file

@ -1,4 +1,6 @@
#pragma once
#include <wil/registry.h>
#include <parallel_hashmap/phmap.h>
namespace Magpie {
@ -10,11 +12,11 @@ public:
CursorDrawer2(const CursorDrawer2&) = delete;
CursorDrawer2(CursorDrawer2&&) = delete;
bool Initialize(GraphicsContext& graphicsContext) noexcept;
bool Initialize(GraphicsContext& graphicsContext, const RECT& destRect) noexcept;
bool NeedRedraw(HCURSOR& hCursor, POINT cursorPos) const noexcept;
bool CheckForRedraw(HCURSOR& hCursor, POINT cursorPos) noexcept;
void Draw(HCURSOR hCursor, POINT cursorPos) noexcept;
void Draw() noexcept;
void OnCursorVirtualizationStarted() noexcept {
_isCursorVirtualized = true;
@ -40,17 +42,61 @@ public:
_isSrcMoving = false;
}
void OnMoved(const RECT& destRect) noexcept {
_destRect = destRect;
}
void OnDestRectChanged(const RECT& destRect) noexcept {
_destRect = destRect;
}
private:
void _GetCursorState(HCURSOR& hCursor, POINT cursorPos, bool& isActive) const noexcept;
// 所有光标纹理使用线性 RGB 空间
enum class _CursorType {
// 彩色光标
// 纹理格式: DXGI_FORMAT_R8G8B8A8_UNORM
// 计算公式: FinalColor = ScreenColor * CursorColor.a + CursorColor.rgb
// 纹理中 RGB 通道已预乘 A 通道 (premultiplied alpha)A 通道已预先取反,这是为了
// 减少着色器的计算量以及确保 (可能进行的) 双线性插值的准确性。
Color = 0,
// 单色光标
// 纹理格式: DXGI_FORMAT_R8_UNORM
// 高四位为 AND 掩码,低四位为 XOR 掩码,值只能是 0 或 0xf。
Monochrome,
// 彩色掩码光标
// 纹理格式: DXGI_FORMAT_R8G8B8A8_UNORM
// A 通道只能是 0 或 255。为 0 时用 RGB 通道取代屏幕颜色,为 255 时将 RGB 通道和
// 屏幕颜色进行异或操作。
MaskedColor
};
struct _CursorInfo {
_CursorType type;
Size size;
Point hotspot;
winrt::com_ptr<ID3D12Resource> resource;
Size resourceSize;
};
const _CursorInfo* _ResolveCursor(HCURSOR hCursor, POINT cursorPos) noexcept;
GraphicsContext* _graphicsContext = nullptr;
RECT _destRect{};
// (HCURSOR, DPI) -> _CursorInfo
// DPI 为 0 表示此光标不随 DPI 缩放
phmap::flat_hash_map<std::pair<HCURSOR, uint32_t>, _CursorInfo> _cursorInfos;
// 这两个成员用于检查自动隐藏光标
HCURSOR _lastRawCursorHandle = NULL;
std::chrono::steady_clock::time_point _lastCursorActiveTime;
// 上次绘制的光标形状和位置
HCURSOR _lastCursorHandle = NULL;
POINT _lastCursorPos{ std::numeric_limits<LONG>::max(), std::numeric_limits<LONG>::max() };
HCURSOR _hCurCursor = NULL;
POINT _curCursorPos{ std::numeric_limits<LONG>::max(), std::numeric_limits<LONG>::max() };
// 监控“指针大小”选项变化
wil::unique_registry_watcher_nothrow _regWatcher;
DWORD _cursorBaseSize = 32;
bool _isCursorVisible = true;
bool _isMoving = false;

View file

@ -1049,49 +1049,43 @@ void CursorManager::_ClipCursorOnSrcMoving() noexcept {
}
void CursorManager::_UpdateCursorPos() noexcept {
if (_shouldDrawCursor) {
CURSORINFO ci{ .cbSize = sizeof(CURSORINFO) };
if (!GetCursorInfo(&ci)) {
_hCursor = NULL;
return;
}
CURSORINFO ci = { .cbSize = sizeof(CURSORINFO) };
if (!_shouldDrawCursor || !GetCursorInfo(&ci)) {
_hCursor = NULL;
// 光标在渲染矩形外也检索光标位置,叠加层可能需要
GetCursorPos(&_cursorPos);
return;
}
if (ci.flags == CURSOR_SHOWING) {
if (ScalingWindow::Get().Options().IsWindowedMode()) {
_hCursor = ci.hCursor;
} else {
// 全屏模式缩放时我们阻止了源窗口四周可调整尺寸的区域,这使得鼠标从客户区移到边框
// 的过程中会有一瞬间的闪烁。为了解决这个问题,这里特别处理调整尺寸时的光标形状。
if (ci.hCursor == _hDiagonalSize1Cursor || ci.hCursor == _hDiagonalSize2Cursor ||
ci.hCursor == _hHorizontalSizeCursor || ci.hCursor == _hVerticalSizeCursor) {
if (_hCursor != ci.hCursor) {
using std::chrono::steady_clock;
_cursorPos = ci.ptScreenPos;
if (_sizeCursorStartTime == steady_clock::time_point{}) {
_sizeCursorStartTime = steady_clock::now();
} else {
// 延迟 50ms 更新以防止闪烁
if (steady_clock::now() - _sizeCursorStartTime > 50ms) {
_hCursor = ci.hCursor;
}
}
}
if (ci.flags != CURSOR_SHOWING) {
_hCursor = NULL;
return;
}
if (ScalingWindow::Get().Options().IsWindowedMode()) {
_hCursor = ci.hCursor;
} else {
// 全屏模式缩放时我们阻止了源窗口四周可调整尺寸的区域,这使得鼠标从客户区移到边框
// 的过程中会有一瞬间的闪烁。为了解决这个问题,这里特别处理调整尺寸时的光标形状。
if (ci.hCursor == _hDiagonalSize1Cursor || ci.hCursor == _hDiagonalSize2Cursor ||
ci.hCursor == _hHorizontalSizeCursor || ci.hCursor == _hVerticalSizeCursor) {
if (_hCursor != ci.hCursor) {
using std::chrono::steady_clock;
if (_sizeCursorStartTime == steady_clock::time_point{}) {
_sizeCursorStartTime = steady_clock::now();
} else {
_sizeCursorStartTime = {};
_hCursor = ci.hCursor;
// 延迟 50ms 更新以防止闪烁
if (steady_clock::now() - _sizeCursorStartTime > 50ms) {
_hCursor = ci.hCursor;
}
}
}
} else {
_hCursor = NULL;
}
_cursorPos = ci.ptScreenPos;
} else {
_hCursor = NULL;
// 光标在缩放窗口外也检索光标位置,叠加层可能需要
if (!GetCursorPos(&_cursorPos)) {
return;
_sizeCursorStartTime = {};
_hCursor = ci.hCursor;
}
}

View file

@ -134,7 +134,7 @@ private:
bool _isSrcFocused = false;
bool _isVirtualized = false;
// 当缩放后的光标位置在交换链窗口上且没有被其他窗口挡住时应绘制光标
// 当缩放后的光标位置在渲染矩形内且没有被其他窗口挡住时应绘制光标
bool _shouldDrawCursor = false;
bool _isCapturedOnForeground = false;

View file

@ -32,7 +32,7 @@ static void SetGpuPriority() noexcept {
ScalingError Renderer2::Initialize(
HWND hwndAttach,
HMONITOR hMonitor,
Size size,
const RECT& rendererRect,
const RECT& srcRect,
OverlayOptions& /*overlayOptions*/
) noexcept {
@ -91,18 +91,18 @@ ScalingError Renderer2::Initialize(
return ScalingError::ScalingFailedGeneral;
}
const Size rendererSize = {
uint32_t(rendererRect.right - rendererRect.left),
uint32_t(rendererRect.bottom - rendererRect.top)
};
Size outputSize;
SimpleTask<bool> task;
_frameProducer.InitializeAsync(
_graphicsContext, _colorInfo, hMonitor, srcRect, size, outputSize, task);
if (!_cursorDrawer.Initialize(_graphicsContext)) {
Logger::Get().Error("CursorDrawer2::Initialize 失败");
return ScalingError::ScalingFailedGeneral;
}
_graphicsContext, _colorInfo, hMonitor, srcRect, rendererSize, outputSize, task);
_presenter = std::make_unique<SwapChainPresenter>();
if (!_presenter->Initialize(_graphicsContext, hwndAttach, size, _colorInfo)) {
if (!_presenter->Initialize(_graphicsContext, hwndAttach, rendererSize, _colorInfo)) {
Logger::Get().Error("SwapChainPresenter::Initialize 失败");
return ScalingError::ScalingFailedGeneral;
}
@ -115,6 +115,17 @@ ScalingError Renderer2::Initialize(
_UpdateOutputRect(outputSize);
const RECT destRect = {
rendererRect.left + (LONG)_outputRect.left,
rendererRect.top + (LONG)_outputRect.top,
rendererRect.left + (LONG)_outputRect.right,
rendererRect.top + (LONG)_outputRect.bottom
};
if (!_cursorDrawer.Initialize(_graphicsContext, destRect)) {
Logger::Get().Error("CursorDrawer2::Initialize 失败");
return ScalingError::ScalingFailedGeneral;
}
return ScalingError::NoError;
}
@ -145,14 +156,14 @@ ComponentState Renderer2::Render(
}
if (latestProducerFrameNumber == _lastProducerFrameNumber &&
!_cursorDrawer.NeedRedraw(hCursor, cursorPos)) {
!_cursorDrawer.CheckForRedraw(hCursor, cursorPos)) {
return _state;
}
_lastProducerFrameNumber = latestProducerFrameNumber;
}
_CheckResult(_RenderImpl(hCursor, cursorPos, waitForGpu), "_RenderImpl 失败");
_CheckResult(_RenderImpl(waitForGpu), "_RenderImpl 失败");
return _state;
}
@ -231,6 +242,10 @@ void Renderer2::OnSrcMoveEnded() noexcept {
_cursorDrawer.OnSrcMoveEnded();
}
void Renderer2::OnDestRectChanged(const RECT& destRect) noexcept {
_cursorDrawer.OnDestRectChanged(destRect);
}
void Renderer2::OnMsgDisplayChanged() noexcept {
// winrt::DisplayInformation 可用时已通过事件监听颜色配置变化
if (_state != ComponentState::NoError || _displayInfo) {
@ -406,7 +421,7 @@ HRESULT Renderer2::_UpdateColorSpace() noexcept {
return S_OK;
}
HRESULT Renderer2::_RenderImpl(HCURSOR /*hCursor*/, POINT /*cursorPos*/, bool waitForGpu) noexcept {
HRESULT Renderer2::_RenderImpl(bool waitForGpu) noexcept {
// 处于 COPY_SOURCE 状态,使用结束后也应处于此状态
ID3D12Resource* curBuffer;
UINT64 fenceValueToSignal;

View file

@ -19,7 +19,7 @@ public:
ScalingError Initialize(
HWND hwndAttach,
HMONITOR hMonitor,
Size size,
const RECT& rendererRect,
const RECT& srcRect,
OverlayOptions& overlayOptions
) noexcept;
@ -55,6 +55,8 @@ public:
void OnSrcMoveEnded() noexcept;
void OnDestRectChanged(const RECT& destRect) noexcept;
void OnMsgDisplayChanged() noexcept;
void OnCursorVisibilityChanged(bool isVisible, bool onDestory) noexcept;
@ -66,7 +68,7 @@ private:
HRESULT _UpdateColorSpace() noexcept;
HRESULT _RenderImpl(HCURSOR hCursor, POINT cursorPos, bool waitForGpu = false) noexcept;
HRESULT _RenderImpl(bool waitForGpu = false) noexcept;
void _UpdateOutputRect(Size outputSize) noexcept;

View file

@ -318,7 +318,7 @@ ScalingError ScalingWindow::_StartImpl(HWND hwndSrc) noexcept {
ScalingError error = _renderer->Initialize(
_hwndRenderer,
_srcTracker.Monitor(),
Size{ uint32_t(_rendererRect.right - _rendererRect.left),uint32_t(_rendererRect.bottom - _rendererRect.top) },
_rendererRect,
_srcTracker.SrcRect(),
_options.overlayOptions
);
@ -407,10 +407,6 @@ void ScalingWindow::Render(bool onDeviceLost) noexcept {
// 创建 D3D 设备后(可能是 OS bug第二次是我们隐藏系统光标。
auto [hCursor, cursorPos] = _cursorManager->Update();
// 转换到渲染器本地坐标系,可能在渲染矩形外
cursorPos.x -= _rendererRect.left;
cursorPos.y -= _rendererRect.top;
bool waitingForFirstFrame = false;
ComponentState state = _renderer->Render(
hCursor, cursorPos, _shouldWaitForGpu || _isFirstFrame, &waitingForFirstFrame);
@ -429,7 +425,7 @@ void ScalingWindow::Render(bool onDeviceLost) noexcept {
ScalingError error = _renderer->Initialize(
_hwndRenderer,
_srcTracker.Monitor(),
Size{ uint32_t(_rendererRect.right - _rendererRect.left),uint32_t(_rendererRect.bottom - _rendererRect.top) },
_rendererRect,
_srcTracker.SrcRect(),
_options.overlayOptions
);
@ -1366,6 +1362,7 @@ void ScalingWindow::_HandleResize() noexcept {
_rendererRect.top + outputRect.bottom
};
_cursorManager->OnResized(destRect, _rendererRect);
_renderer->OnDestRectChanged(destRect);
Render();
}
@ -1379,6 +1376,7 @@ void ScalingWindow::_HandleMove() noexcept {
_rendererRect.top + outputRect.bottom
};
_cursorManager->OnMoved(destRect, _rendererRect);
_renderer->OnDestRectChanged(destRect);
}
bool ScalingWindow::_UpdateSrcState(bool& isSrcRepositioning) noexcept {

View file

@ -4,7 +4,7 @@
namespace Magpie {
bool ShaderEffectCompilerService::Submit(std::string_view name, ShaderEffectDesc& desc) const noexcept {
bool ShaderEffectCompilerService::Submit(std::string_view /*name*/, ShaderEffectDesc& /*desc*/) const noexcept {
return false;
}

View file

@ -3,7 +3,7 @@
namespace Magpie {
uint32_t ShaderEffectDrawer::CalcDescriptorCount(bool isFirst, bool isLast) {
uint32_t ShaderEffectDrawer::CalcDescriptorCount(bool /*isFirst*/, bool /*isLast*/) {
return 0;
}

View file

@ -50,7 +50,7 @@ private:
std::wstring _localDir;
};
bool ShaderEffectParser::ParseForInfo(std::string&& name, std::string&& source, EffectInfo& effectInfo) noexcept {
bool ShaderEffectParser::ParseForInfo(std::string&& name, std::string&& /*source*/, EffectInfo& effectInfo) noexcept {
effectInfo.name = std::move(name);
return false;
@ -58,13 +58,14 @@ bool ShaderEffectParser::ParseForInfo(std::string&& name, std::string&& source,
bool ShaderEffectParser::ParseForDesc(
std::string&& name,
std::string&& source,
std::string&& /*source*/,
std::string&& workingFolder,
const ShaderEffectParserOptions& options,
const ShaderEffectParserOptions& /*options*/,
struct ShaderEffectDesc& effectDesc,
ShaderEffectSource& effectSource
) noexcept {
effectDesc.name = std::move(name);
effectSource.workingFolder = std::move(workingFolder);
return false;
}

View file

@ -231,7 +231,7 @@ int16_t Win32Helper::AdvancedWindowHitTest(HWND hWnd, POINT ptScreen, UINT timeo
// 检查是否在窗口内
RECT windowRect;
if (!GetWindowRect(hWnd, &windowRect) || !PtInRect(&windowRect, data->ptScreen)) {
if (!GetWindowRect(hWnd, &windowRect) || !PtInRect(windowRect, data->ptScreen)) {
return TRUE;
}

View file

@ -33,6 +33,10 @@ struct Win32Helper {
return result.left < result.right && result.top < result.bottom;
}
static bool PtInRect(const RECT& rect, POINT pt) {
return pt.x >= rect.left && pt.x < rect.right && pt.y >= rect.top && pt.y < rect.bottom;
}
static std::wstring GetWindowClassName(HWND hWnd) noexcept;
static std::wstring GetWindowTitle(HWND hWnd) noexcept;