style: 将部分c++代码的缩进换为tab

This commit is contained in:
Xu Liu 2021-08-01 21:13:14 +08:00
commit e37f6fa4e8
14 changed files with 1230 additions and 1162 deletions

View file

@ -215,3 +215,71 @@ dotnet_naming_style.begins_with_i.required_prefix = I
dotnet_naming_style.begins_with_i.required_suffix =
dotnet_naming_style.begins_with_i.word_separator =
dotnet_naming_style.begins_with_i.capitalization = pascal_case
# C++ 文件
[*.{c++,cc,cpp,cppm,cxx,h,h++,hh,hpp,hxx,inl,ipp,ixx,tlh,tli}]
# Visual C++ 代码样式设置
cpp_generate_documentation_comments = xml
# Visual C++ 格式设置
cpp_indent_braces = false
cpp_indent_multi_line_relative_to = innermost_parenthesis
cpp_indent_within_parentheses = indent
cpp_indent_preserve_within_parentheses = true
cpp_indent_case_contents = true
cpp_indent_case_labels = false
cpp_indent_case_contents_when_block = false
cpp_indent_lambda_braces_when_parameter = true
cpp_indent_goto_labels = one_left
cpp_indent_preprocessor = leftmost_column
cpp_indent_access_specifiers = false
cpp_indent_namespace_contents = false
cpp_indent_preserve_comments = false
cpp_new_line_before_open_brace_namespace = same_line
cpp_new_line_before_open_brace_type = same_line
cpp_new_line_before_open_brace_function = same_line
cpp_new_line_before_open_brace_block = same_line
cpp_new_line_before_open_brace_lambda = same_line
cpp_new_line_scope_braces_on_separate_lines = true
cpp_new_line_close_brace_same_line_empty_type = true
cpp_new_line_close_brace_same_line_empty_function = true
cpp_new_line_before_catch = false
cpp_new_line_before_else = false
cpp_new_line_before_while_in_do_while = false
cpp_space_before_function_open_parenthesis = remove
cpp_space_within_parameter_list_parentheses = false
cpp_space_between_empty_parameter_list_parentheses = false
cpp_space_after_keywords_in_control_flow_statements = true
cpp_space_within_control_flow_statement_parentheses = false
cpp_space_before_lambda_open_parenthesis = false
cpp_space_within_cast_parentheses = false
cpp_space_after_cast_close_parenthesis = false
cpp_space_within_expression_parentheses = false
cpp_space_before_block_open_brace = true
cpp_space_between_empty_braces = false
cpp_space_before_initializer_list_open_brace = false
cpp_space_within_initializer_list_braces = true
cpp_space_preserve_in_initializer_list = true
cpp_space_before_open_square_bracket = false
cpp_space_within_square_brackets = false
cpp_space_before_empty_square_brackets = false
cpp_space_between_empty_square_brackets = false
cpp_space_group_square_brackets = true
cpp_space_within_lambda_brackets = false
cpp_space_between_empty_lambda_brackets = false
cpp_space_before_comma = false
cpp_space_after_comma = true
cpp_space_remove_around_member_operators = true
cpp_space_before_inheritance_colon = true
cpp_space_before_constructor_colon = true
cpp_space_remove_before_semicolon = true
cpp_space_after_semicolon = true
cpp_space_remove_around_unary_operator = true
cpp_space_around_binary_operator = insert
cpp_space_around_assignment_operator = insert
cpp_space_pointer_reference_alignment = left
cpp_space_around_ternary_operator = insert
cpp_wrap_preserve_blocks = one_liners

View file

@ -90,7 +90,7 @@
<Message>Installing dependencies via Conan</Message>
<Command>.\ConanInstall.bat</Command>
<LinkObjects>false</LinkObjects>
<Outputs>$(SolutionDir).conan/$(Configuration)/Runtime/conanbuildinfo.props</Outputs>
<Outputs>$(SolutionDir).conan/$(Configuration)/Runtime/conanbuildinfo.props</Outputs>
</CustomBuild>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

View file

@ -3,7 +3,7 @@
#include "CommonDebug.h"
// 来取代简单的 DrawTransform
// 用的 DrawTransform
// 该 DrawTransform 必须满足以下条件:
// * NINPUTS 个输入
// * 输出与所有输入尺寸相同

View file

@ -11,379 +11,379 @@ using namespace D2D1;
// 处理光标的渲染
class CursorManager: public Renderable {
public:
CursorManager() {
_cursorSize.cx = GetSystemMetrics(SM_CXCURSOR);
_cursorSize.cy = GetSystemMetrics(SM_CYCURSOR);
CursorManager() {
_cursorSize.cx = GetSystemMetrics(SM_CXCURSOR);
_cursorSize.cy = GetSystemMetrics(SM_CYCURSOR);
HCURSOR hCursorArrow = LoadCursor(NULL, IDC_ARROW);
HCURSOR hCursorHand = LoadCursor(NULL, IDC_HAND);
HCURSOR hCursorAppStarting = LoadCursor(NULL, IDC_APPSTARTING);
HCURSOR hCursorIBeam = LoadCursor(NULL, IDC_IBEAM);
// 保存替换之前的 arrow 光标图像
// SetSystemCursor 不会改变系统光标的句柄
_ResolveCursor(hCursorArrow, hCursorArrow);
_ResolveCursor(hCursorHand, hCursorHand);
_ResolveCursor(hCursorAppStarting, hCursorAppStarting);
_ResolveCursor(hCursorIBeam, hCursorIBeam);
HCURSOR hCursorArrow = LoadCursor(NULL, IDC_ARROW);
HCURSOR hCursorHand = LoadCursor(NULL, IDC_HAND);
HCURSOR hCursorAppStarting = LoadCursor(NULL, IDC_APPSTARTING);
HCURSOR hCursorIBeam = LoadCursor(NULL, IDC_IBEAM);
// 保存替换之前的 arrow 光标图像
// SetSystemCursor 不会改变系统光标的句柄
_ResolveCursor(hCursorArrow, hCursorArrow);
_ResolveCursor(hCursorHand, hCursorHand);
_ResolveCursor(hCursorAppStarting, hCursorAppStarting);
_ResolveCursor(hCursorIBeam, hCursorIBeam);
if (Env::$instance->IsNoDisturb()) {
return;
}
Debug::ThrowIfWin32Failed(
SetSystemCursor(_CreateTransparentCursor(hCursorArrow), OCR_NORMAL),
L"设置 OCR_NORMAL 失败"
);
Debug::ThrowIfWin32Failed(
SetSystemCursor(_CreateTransparentCursor(hCursorHand), OCR_HAND),
L"设置 OCR_HAND 失败"
);
Debug::ThrowIfWin32Failed(
SetSystemCursor(_CreateTransparentCursor(hCursorAppStarting), OCR_APPSTARTING),
L"设置 OCR_APPSTARTING 失败"
);
Debug::ThrowIfWin32Failed(
SetSystemCursor(_CreateTransparentCursor(hCursorIBeam), OCR_IBEAM),
L"设置 OCR_APPSTARTING 失败"
);
if (Env::$instance->IsNoDisturb()) {
return;
}
Debug::ThrowIfWin32Failed(
SetSystemCursor(_CreateTransparentCursor(hCursorArrow), OCR_NORMAL),
L"设置 OCR_NORMAL 失败"
);
Debug::ThrowIfWin32Failed(
SetSystemCursor(_CreateTransparentCursor(hCursorHand), OCR_HAND),
L"设置 OCR_HAND 失败"
);
Debug::ThrowIfWin32Failed(
SetSystemCursor(_CreateTransparentCursor(hCursorAppStarting), OCR_APPSTARTING),
L"设置 OCR_APPSTARTING 失败"
);
Debug::ThrowIfWin32Failed(
SetSystemCursor(_CreateTransparentCursor(hCursorIBeam), OCR_IBEAM),
L"设置 OCR_APPSTARTING 失败"
);
// 限制鼠标在窗口内
Debug::ThrowIfWin32Failed(ClipCursor(&Env::$instance->GetSrcClient()), L"ClipCursor 失败");
// 限制鼠标在窗口内
Debug::ThrowIfWin32Failed(ClipCursor(&Env::$instance->GetSrcClient()), L"ClipCursor 失败");
// 设置鼠标移动速度
Debug::ThrowIfWin32Failed(
SystemParametersInfo(SPI_GETMOUSESPEED, 0, &_cursorSpeed, 0),
L"获取鼠标速度失败"
);
// 设置鼠标移动速度
Debug::ThrowIfWin32Failed(
SystemParametersInfo(SPI_GETMOUSESPEED, 0, &_cursorSpeed, 0),
L"获取鼠标速度失败"
);
const RECT& srcClient = Env::$instance->GetSrcClient();
const D2D_RECT_F& destRect = Env::$instance->GetDestRect();
float scaleX = (destRect.right - destRect.left) / (srcClient.right - srcClient.left);
float scaleY = (destRect.bottom - destRect.top) / (srcClient.bottom - srcClient.top);
const RECT& srcClient = Env::$instance->GetSrcClient();
const D2D_RECT_F& destRect = Env::$instance->GetDestRect();
float scaleX = (destRect.right - destRect.left) / (srcClient.right - srcClient.left);
float scaleY = (destRect.bottom - destRect.top) / (srcClient.bottom - srcClient.top);
long newSpeed = std::clamp(lroundf(_cursorSpeed / (scaleX + scaleY) * 2), 1L, 20L);
Debug::ThrowIfWin32Failed(
SystemParametersInfo(SPI_SETMOUSESPEED, 0, (PVOID)(intptr_t)newSpeed, 0),
L"设置鼠标速度失败"
);
}
long newSpeed = std::clamp(lroundf(_cursorSpeed / (scaleX + scaleY) * 2), 1L, 20L);
Debug::ThrowIfWin32Failed(
SystemParametersInfo(SPI_SETMOUSESPEED, 0, (PVOID)(intptr_t)newSpeed, 0),
L"设置鼠标速度失败"
);
}
CursorManager(const CursorManager&) = delete;
CursorManager(CursorManager&&) = delete;
~CursorManager() {
if (Env::$instance->IsNoDisturb()) {
return;
}
~CursorManager() {
if (Env::$instance->IsNoDisturb()) {
return;
}
ClipCursor(nullptr);
ClipCursor(nullptr);
SystemParametersInfo(SPI_SETMOUSESPEED, 0, (PVOID)(intptr_t)_cursorSpeed, 0);
SystemParametersInfo(SPI_SETMOUSESPEED, 0, (PVOID)(intptr_t)_cursorSpeed, 0);
// 还原系统光标
SystemParametersInfo(SPI_SETCURSORS, 0, NULL, 0);
}
// 还原系统光标
SystemParametersInfo(SPI_SETCURSORS, 0, NULL, 0);
}
private:
struct CursorInfo {
HCURSOR handle = NULL;
ComPtr<ID2D1Bitmap> bmp = nullptr;
int xHotSpot = 0;
int yHotSpot = 0;
int width = 0;
int height = 0;
bool isMonochrome = false;
};
struct CursorInfo {
HCURSOR handle = NULL;
ComPtr<ID2D1Bitmap> bmp = nullptr;
int xHotSpot = 0;
int yHotSpot = 0;
int width = 0;
int height = 0;
bool isMonochrome = false;
};
CursorInfo* _cursorInfo = nullptr;
D2D1_POINT_2L _targetScreenPos{};
CursorInfo* _cursorInfo = nullptr;
D2D1_POINT_2L _targetScreenPos{};
public:
ComPtr<ID2D1Image> RenderEffect(ComPtr<ID2D1Image> input) {
_CalcCursorPos();
ComPtr<ID2D1Image> RenderEffect(ComPtr<ID2D1Image> input) {
_CalcCursorPos();
if (!_cursorInfo || !_cursorInfo->isMonochrome) {
return input;
}
if (!_cursorInfo || !_cursorInfo->isMonochrome) {
return input;
}
if (!_monochromeCursorEffect) {
Debug::ThrowIfComFailed(
MonochromeCursorEffect::Register(Env::$instance->GetD2DFactory()),
L"注册MonochromeCursorEffect失败"
);
Debug::ThrowIfComFailed(
Env::$instance->GetD2DDC()->CreateEffect(CLSID_MAGPIE_MONOCHROME_CURSOR_EFFECT, &_monochromeCursorEffect),
L"创建MonochromeCursorEffect失败"
);
}
if (!_monochromeCursorEffect) {
Debug::ThrowIfComFailed(
MonochromeCursorEffect::Register(Env::$instance->GetD2DFactory()),
L"注册MonochromeCursorEffect失败"
);
Debug::ThrowIfComFailed(
Env::$instance->GetD2DDC()->CreateEffect(CLSID_MAGPIE_MONOCHROME_CURSOR_EFFECT, &_monochromeCursorEffect),
L"创建MonochromeCursorEffect失败"
);
}
_monochromeCursorEffect->SetInput(0, input.Get());
_monochromeCursorEffect->SetInput(1, _cursorInfo->bmp.Get());
_monochromeCursorEffect->SetInput(0, input.Get());
_monochromeCursorEffect->SetInput(1, _cursorInfo->bmp.Get());
auto& destRect = Env::$instance->GetDestRect();
_monochromeCursorEffect->SetValue(
MonochromeCursorEffect::PROP_CURSOR_POS,
D2D_VECTOR_2F{ FLOAT(_targetScreenPos.x) - destRect.left, FLOAT(_targetScreenPos.y) - destRect.top }
);
auto& destRect = Env::$instance->GetDestRect();
_monochromeCursorEffect->SetValue(
MonochromeCursorEffect::PROP_CURSOR_POS,
D2D_VECTOR_2F{ FLOAT(_targetScreenPos.x) - destRect.left, FLOAT(_targetScreenPos.y) - destRect.top }
);
ComPtr<ID2D1Image> output;
_monochromeCursorEffect->GetOutput(&output);
return output;
}
ComPtr<ID2D1Image> output;
_monochromeCursorEffect->GetOutput(&output);
return output;
}
void Render() override {
if (!_cursorInfo || _cursorInfo->isMonochrome) {
return;
}
void Render() override {
if (!_cursorInfo || _cursorInfo->isMonochrome) {
return;
}
D2D1_RECT_F cursorRect = {
FLOAT(_targetScreenPos.x),
FLOAT(_targetScreenPos.y),
FLOAT(_targetScreenPos.x + _cursorInfo->width),
FLOAT(_targetScreenPos.y + _cursorInfo->height)
};
D2D1_RECT_F cursorRect = {
FLOAT(_targetScreenPos.x),
FLOAT(_targetScreenPos.y),
FLOAT(_targetScreenPos.x + _cursorInfo->width),
FLOAT(_targetScreenPos.y + _cursorInfo->height)
};
Env::$instance->GetD2DDC()->DrawBitmap(_cursorInfo->bmp.Get(), &cursorRect);
}
Env::$instance->GetD2DDC()->DrawBitmap(_cursorInfo->bmp.Get(), &cursorRect);
}
std::pair<bool, LRESULT> WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
if (message == _WM_NEWCURSOR32) {
// 来自 CursorHook 的消息
// HCURSOR 似乎是共享资源,尽管来自别的进程但可以直接使用
//
// 如果消息来自 32 位进程,本程序为 64 位,必须转换为补符号位扩展,这是为了和 SetCursor 的处理方法一致
// SendMessage 为补 0 扩展SetCursor 为补符号位扩展
_AddHookCursor((HCURSOR)(INT_PTR)(INT32)wParam, (HCURSOR)(INT_PTR)(INT32)lParam);
return { true, 0 };
} else if (message == _WM_NEWCURSOR64) {
// 如果消息来自 64 位进程,本程序为 32 位HCURSOR 会被截断
// Q: 如果被截断是否能正常工作?
_AddHookCursor((HCURSOR)wParam, (HCURSOR)lParam);
return { true, 0 };
}
std::pair<bool, LRESULT> WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
if (message == _WM_NEWCURSOR32) {
// 来自 CursorHook 的消息
// HCURSOR 似乎是共享资源,尽管来自别的进程但可以直接使用
//
// 如果消息来自 32 位进程,本程序为 64 位,必须转换为补符号位扩展,这是为了和 SetCursor 的处理方法一致
// SendMessage 为补 0 扩展SetCursor 为补符号位扩展
_AddHookCursor((HCURSOR)(INT_PTR)(INT32)wParam, (HCURSOR)(INT_PTR)(INT32)lParam);
return { true, 0 };
} else if (message == _WM_NEWCURSOR64) {
// 如果消息来自 64 位进程,本程序为 32 位HCURSOR 会被截断
// Q: 如果被截断是否能正常工作?
_AddHookCursor((HCURSOR)wParam, (HCURSOR)lParam);
return { true, 0 };
}
return { false, 0 };
}
return { false, 0 };
}
private:
void _CalcCursorPos() {
CURSORINFO ci{};
ci.cbSize = sizeof(ci);
Debug::ThrowIfWin32Failed(
GetCursorInfo(&ci),
L"GetCursorInfo 失败"
);
void _CalcCursorPos() {
CURSORINFO ci{};
ci.cbSize = sizeof(ci);
Debug::ThrowIfWin32Failed(
GetCursorInfo(&ci),
L"GetCursorInfo 失败"
);
if (ci.hCursor == NULL) {
_cursorInfo = nullptr;
return;
}
if (ci.hCursor == NULL) {
_cursorInfo = nullptr;
return;
}
auto it = _cursorMap.find(ci.hCursor);
if (it != _cursorMap.end()) {
_cursorInfo = &it->second;
} else {
try {
// 未在映射中找到,创建新映射
_ResolveCursor(ci.hCursor, ci.hCursor);
auto it = _cursorMap.find(ci.hCursor);
if (it != _cursorMap.end()) {
_cursorInfo = &it->second;
} else {
try {
// 未在映射中找到,创建新映射
_ResolveCursor(ci.hCursor, ci.hCursor);
_cursorInfo = &_cursorMap[ci.hCursor];
} catch (...) {
// 如果出错,不绘制光标
_cursorInfo = nullptr;
return;
}
}
_cursorInfo = &_cursorMap[ci.hCursor];
} catch (...) {
// 如果出错,不绘制光标
_cursorInfo = nullptr;
return;
}
}
// 映射坐标
// 鼠标坐标为整数,否则会出现模糊
const RECT& srcClient = Env::$instance->GetSrcClient();
const D2D_RECT_F& destRect = Env::$instance->GetDestRect();
float scaleX = (destRect.right - destRect.left) / (srcClient.right - srcClient.left);
float scaleY = (destRect.bottom - destRect.top) / (srcClient.bottom - srcClient.top);
// 映射坐标
// 鼠标坐标为整数,否则会出现模糊
const RECT& srcClient = Env::$instance->GetSrcClient();
const D2D_RECT_F& destRect = Env::$instance->GetDestRect();
float scaleX = (destRect.right - destRect.left) / (srcClient.right - srcClient.left);
float scaleY = (destRect.bottom - destRect.top) / (srcClient.bottom - srcClient.top);
_targetScreenPos = {
lroundf((ci.ptScreenPos.x - srcClient.left) * scaleX + destRect.left) - _cursorInfo->xHotSpot,
lroundf((ci.ptScreenPos.y - srcClient.top) * scaleY + destRect.top) - _cursorInfo->yHotSpot
};
}
_targetScreenPos = {
lroundf((ci.ptScreenPos.x - srcClient.left) * scaleX + destRect.left) - _cursorInfo->xHotSpot,
lroundf((ci.ptScreenPos.y - srcClient.top) * scaleY + destRect.top) - _cursorInfo->yHotSpot
};
}
void _AddHookCursor(HCURSOR hTptCursor, HCURSOR hCursor) {
if (hTptCursor == NULL || hCursor == NULL) {
return;
}
void _AddHookCursor(HCURSOR hTptCursor, HCURSOR hCursor) {
if (hTptCursor == NULL || hCursor == NULL) {
return;
}
Debug::WriteLine(L"New Cursor Map");
_ResolveCursor(hTptCursor, hCursor);
}
Debug::WriteLine(L"New Cursor Map");
_ResolveCursor(hTptCursor, hCursor);
}
HCURSOR _CreateTransparentCursor(HCURSOR hCursorHotSpot) {
int len = _cursorSize.cx * _cursorSize.cy;
BYTE* andPlane = new BYTE[len];
memset(andPlane, 0xff, len);
BYTE* xorPlane = new BYTE[len]{};
HCURSOR _CreateTransparentCursor(HCURSOR hCursorHotSpot) {
int len = _cursorSize.cx * _cursorSize.cy;
BYTE* andPlane = new BYTE[len];
memset(andPlane, 0xff, len);
BYTE* xorPlane = new BYTE[len]{};
auto hotSpot = _GetCursorHotSpot(hCursorHotSpot);
auto hotSpot = _GetCursorHotSpot(hCursorHotSpot);
HCURSOR result = CreateCursor(
Env::$instance->GetHInstance(),
std::min(hotSpot.first, (int)_cursorSize.cx),
std::min(hotSpot.second, (int)_cursorSize.cy),
_cursorSize.cx, _cursorSize.cy,
andPlane, xorPlane
);
Debug::ThrowIfWin32Failed(result, L"创建透明鼠标失败");
HCURSOR result = CreateCursor(
Env::$instance->GetHInstance(),
std::min(hotSpot.first, (int)_cursorSize.cx),
std::min(hotSpot.second, (int)_cursorSize.cy),
_cursorSize.cx, _cursorSize.cy,
andPlane, xorPlane
);
Debug::ThrowIfWin32Failed(result, L"创建透明鼠标失败");
delete[] andPlane;
delete[] xorPlane;
return result;
}
delete[] andPlane;
delete[] xorPlane;
return result;
}
std::pair<int, int> _GetCursorHotSpot(HCURSOR hCursor) {
if (hCursor == NULL) {
return {};
}
std::pair<int, int> _GetCursorHotSpot(HCURSOR hCursor) {
if (hCursor == NULL) {
return {};
}
ICONINFO ii{};
Debug::ThrowIfWin32Failed(
GetIconInfo(hCursor, &ii),
L"GetIconInfo 失败"
);
DeleteBitmap(ii.hbmColor);
DeleteBitmap(ii.hbmMask);
ICONINFO ii{};
Debug::ThrowIfWin32Failed(
GetIconInfo(hCursor, &ii),
L"GetIconInfo 失败"
);
DeleteBitmap(ii.hbmColor);
DeleteBitmap(ii.hbmMask);
return { (int)ii.xHotspot, (int)ii.yHotspot };
}
return { (int)ii.xHotspot, (int)ii.yHotspot };
}
ComPtr<ID2D1Bitmap> _CursorToD2DBitmap(HCURSOR hCursor) {
assert(hCursor != NULL);
ComPtr<ID2D1Bitmap> _CursorToD2DBitmap(HCURSOR hCursor) {
assert(hCursor != NULL);
IWICImagingFactory2* wicImgFactory = Env::$instance->GetWICImageFactory();
IWICImagingFactory2* wicImgFactory = Env::$instance->GetWICImageFactory();
ComPtr<IWICBitmap> wicCursor = nullptr;
ComPtr<IWICFormatConverter> wicFormatConverter = nullptr;
ComPtr<ID2D1Bitmap> d2dBmpCursor = nullptr;
ComPtr<IWICBitmap> wicCursor = nullptr;
ComPtr<IWICFormatConverter> wicFormatConverter = nullptr;
ComPtr<ID2D1Bitmap> d2dBmpCursor = nullptr;
Debug::ThrowIfComFailed(
wicImgFactory->CreateBitmapFromHICON(hCursor, &wicCursor),
L"创建鼠标图像位图失败"
);
Debug::ThrowIfComFailed(
wicImgFactory->CreateFormatConverter(&wicFormatConverter),
L"CreateFormatConverter 失败"
);
Debug::ThrowIfComFailed(
wicFormatConverter->Initialize(
wicCursor.Get(),
GUID_WICPixelFormat32bppPBGRA,
WICBitmapDitherTypeNone,
NULL,
0.f,
WICBitmapPaletteTypeMedianCut
),
L"IWICFormatConverter 初始化失败"
);
Debug::ThrowIfComFailed(
Env::$instance->GetD2DDC()->CreateBitmapFromWicBitmap(wicFormatConverter.Get(), &d2dBmpCursor),
L"CreateBitmapFromWicBitmap 失败"
);
Debug::ThrowIfComFailed(
wicImgFactory->CreateBitmapFromHICON(hCursor, &wicCursor),
L"创建鼠标图像位图失败"
);
Debug::ThrowIfComFailed(
wicImgFactory->CreateFormatConverter(&wicFormatConverter),
L"CreateFormatConverter 失败"
);
Debug::ThrowIfComFailed(
wicFormatConverter->Initialize(
wicCursor.Get(),
GUID_WICPixelFormat32bppPBGRA,
WICBitmapDitherTypeNone,
NULL,
0.f,
WICBitmapPaletteTypeMedianCut
),
L"IWICFormatConverter 初始化失败"
);
Debug::ThrowIfComFailed(
Env::$instance->GetD2DDC()->CreateBitmapFromWicBitmap(wicFormatConverter.Get(), &d2dBmpCursor),
L"CreateBitmapFromWicBitmap 失败"
);
return d2dBmpCursor;
}
return d2dBmpCursor;
}
ComPtr<ID2D1Bitmap> _MonochromeToD2DBitmap(HBITMAP hbmMask) {
assert(hbmMask != NULL);
ComPtr<ID2D1Bitmap> _MonochromeToD2DBitmap(HBITMAP hbmMask) {
assert(hbmMask != NULL);
IWICImagingFactory2* wicImgFactory = Env::$instance->GetWICImageFactory();
IWICImagingFactory2* wicImgFactory = Env::$instance->GetWICImageFactory();
ComPtr<IWICBitmap> wicCursor = nullptr;
ComPtr<IWICFormatConverter> wicFormatConverter = nullptr;
ComPtr<ID2D1Bitmap> d2dBmpCursor = nullptr;
ComPtr<IWICBitmap> wicCursor = nullptr;
ComPtr<IWICFormatConverter> wicFormatConverter = nullptr;
ComPtr<ID2D1Bitmap> d2dBmpCursor = nullptr;
Debug::ThrowIfComFailed(
wicImgFactory->CreateBitmapFromHBITMAP(hbmMask, NULL, WICBitmapAlphaChannelOption::WICBitmapIgnoreAlpha, &wicCursor),
L"创建鼠标图像位图失败"
);
Debug::ThrowIfComFailed(
wicImgFactory->CreateFormatConverter(&wicFormatConverter),
L"CreateFormatConverter 失败"
);
Debug::ThrowIfComFailed(
wicFormatConverter->Initialize(
wicCursor.Get(),
GUID_WICPixelFormat32bppPBGRA,
WICBitmapDitherTypeNone,
NULL,
0.f,
WICBitmapPaletteTypeMedianCut
),
L"IWICFormatConverter 初始化失败"
);
Debug::ThrowIfComFailed(
Env::$instance->GetD2DDC()->CreateBitmapFromWicBitmap(wicFormatConverter.Get(), &d2dBmpCursor),
L"CreateBitmapFromWicBitmap 失败"
);
Debug::ThrowIfComFailed(
wicImgFactory->CreateBitmapFromHBITMAP(hbmMask, NULL, WICBitmapAlphaChannelOption::WICBitmapIgnoreAlpha, &wicCursor),
L"创建鼠标图像位图失败"
);
Debug::ThrowIfComFailed(
wicImgFactory->CreateFormatConverter(&wicFormatConverter),
L"CreateFormatConverter 失败"
);
Debug::ThrowIfComFailed(
wicFormatConverter->Initialize(
wicCursor.Get(),
GUID_WICPixelFormat32bppPBGRA,
WICBitmapDitherTypeNone,
NULL,
0.f,
WICBitmapPaletteTypeMedianCut
),
L"IWICFormatConverter 初始化失败"
);
Debug::ThrowIfComFailed(
Env::$instance->GetD2DDC()->CreateBitmapFromWicBitmap(wicFormatConverter.Get(), &d2dBmpCursor),
L"CreateBitmapFromWicBitmap 失败"
);
return d2dBmpCursor;
}
return d2dBmpCursor;
}
void _ResolveCursor(HCURSOR hTptCursor, HCURSOR hCursor) {
assert(hCursor != NULL);
void _ResolveCursor(HCURSOR hTptCursor, HCURSOR hCursor) {
assert(hCursor != NULL);
ICONINFO ii{};
Debug::ThrowIfWin32Failed(
GetIconInfo(hCursor, &ii),
L"GetIconInfo 失败"
);
ICONINFO ii{};
Debug::ThrowIfWin32Failed(
GetIconInfo(hCursor, &ii),
L"GetIconInfo 失败"
);
CursorInfo cursorInfo;
cursorInfo.handle = hCursor;
cursorInfo.xHotSpot = ii.xHotspot;
cursorInfo.yHotSpot = ii.yHotspot;
cursorInfo.isMonochrome = (ii.hbmColor == NULL);
CursorInfo cursorInfo;
cursorInfo.handle = hCursor;
cursorInfo.xHotSpot = ii.xHotspot;
cursorInfo.yHotSpot = ii.yHotspot;
cursorInfo.isMonochrome = (ii.hbmColor == NULL);
if (!cursorInfo.isMonochrome) {
SIZE size = _GetSizeOfHBmp(ii.hbmColor);
cursorInfo.width = size.cx;
cursorInfo.height = size.cy;
if (!cursorInfo.isMonochrome) {
SIZE size = _GetSizeOfHBmp(ii.hbmColor);
cursorInfo.width = size.cx;
cursorInfo.height = size.cy;
cursorInfo.bmp = _CursorToD2DBitmap(hCursor);
} else {
SIZE size = _GetSizeOfHBmp(ii.hbmMask);
cursorInfo.width = size.cx;
cursorInfo.height = size.cy / 2;
cursorInfo.bmp = _CursorToD2DBitmap(hCursor);
} else {
SIZE size = _GetSizeOfHBmp(ii.hbmMask);
cursorInfo.width = size.cx;
cursorInfo.height = size.cy / 2;
cursorInfo.bmp = _MonochromeToD2DBitmap(ii.hbmMask);
}
cursorInfo.bmp = _MonochromeToD2DBitmap(ii.hbmMask);
}
if (ii.hbmColor) {
DeleteBitmap(ii.hbmColor);
}
DeleteBitmap(ii.hbmMask);
if (ii.hbmColor) {
DeleteBitmap(ii.hbmColor);
}
DeleteBitmap(ii.hbmMask);
_cursorMap[hTptCursor] = cursorInfo;
}
_cursorMap[hTptCursor] = cursorInfo;
}
SIZE _GetSizeOfHBmp(HBITMAP hBmp) {
BITMAP bmp{};
Debug::ThrowIfWin32Failed(
GetObject(hBmp, sizeof(bmp), &bmp),
L"GetObject 失败"
);
return { bmp.bmWidth, bmp.bmHeight };
}
std::map<HCURSOR, CursorInfo> _cursorMap;
SIZE _GetSizeOfHBmp(HBITMAP hBmp) {
BITMAP bmp{};
Debug::ThrowIfWin32Failed(
GetObject(hBmp, sizeof(bmp), &bmp),
L"GetObject 失败"
);
return { bmp.bmWidth, bmp.bmHeight };
}
std::map<HCURSOR, CursorInfo> _cursorMap;
SIZE _cursorSize{};
SIZE _cursorSize{};
INT _cursorSpeed = 0;
INT _cursorSpeed = 0;
ComPtr<ID2D1Effect> _monochromeCursorEffect = nullptr;
ComPtr<ID2D1Effect> _monochromeCursorEffect = nullptr;
static UINT _WM_NEWCURSOR32;
static UINT _WM_NEWCURSOR64;
static UINT _WM_NEWCURSOR32;
static UINT _WM_NEWCURSOR64;
};

View file

@ -10,215 +10,215 @@ using namespace D2D1;
class D2DContext {
public:
D2DContext() {
_InitD2D();
_InitD2D();
}
// 不可复制,不可移动
D2DContext(const D2DContext&) = delete;
D2DContext(D2DContext&&) = delete;
// 不可复制,不可移动
D2DContext(const D2DContext&) = delete;
D2DContext(D2DContext&&) = delete;
~D2DContext() {
if (Env::$instance->GetCaptureMode() != 1) {
CloseHandle(_frameLatencyWaitableObject);
}
}
~D2DContext() {
if (Env::$instance->GetCaptureMode() != 1) {
CloseHandle(_frameLatencyWaitableObject);
}
}
void Render(std::function<bool(ID2D1DeviceContext*)> renderFunc) {
if (!_waitingForFrame) {
// 在任何渲染发生之前等待以减少输入延迟
if (Env::$instance->GetCaptureMode() == 1) {
// GDI 捕获要求必须等待下一次垂直同步
Debug::ThrowIfComFailed(
_dxgiOutput->WaitForVBlank(),
L"WaitForVBlank失败"
);
} else {
WaitForSingleObject(_frameLatencyWaitableObject, 1000);
}
}
void Render(std::function<bool(ID2D1DeviceContext*)> renderFunc) {
if (!_waitingForFrame) {
// 在任何渲染发生之前等待以减少输入延迟
if (Env::$instance->GetCaptureMode() == 1) {
// GDI 捕获要求必须等待下一次垂直同步
Debug::ThrowIfComFailed(
_dxgiOutput->WaitForVBlank(),
L"WaitForVBlank失败"
);
} else {
WaitForSingleObject(_frameLatencyWaitableObject, 1000);
}
}
_d2dDC->BeginDraw();
_waitingForFrame = !renderFunc(_d2dDC.Get());
Debug::ThrowIfComFailed(
_d2dDC->EndDraw(),
L"EndDraw 失败"
);
_d2dDC->BeginDraw();
_waitingForFrame = !renderFunc(_d2dDC.Get());
Debug::ThrowIfComFailed(
_d2dDC->EndDraw(),
L"EndDraw 失败"
);
if (!_waitingForFrame) {
Debug::ThrowIfComFailed(
_dxgiSwapChain->Present(0, 0),
L"Present 失败"
);
}
}
if (!_waitingForFrame) {
Debug::ThrowIfComFailed(
_dxgiSwapChain->Present(0, 0),
L"Present 失败"
);
}
}
private:
void _InitD2D() {
ComPtr<ID3D11Device> d3dDevice = nullptr;
ComPtr<ID2D1Factory1> d2dFactory = nullptr;
ComPtr<ID2D1Device> d2dDevice = nullptr;
void _InitD2D() {
ComPtr<ID3D11Device> d3dDevice = nullptr;
ComPtr<ID2D1Factory1> d2dFactory = nullptr;
ComPtr<ID2D1Device> d2dDevice = nullptr;
// This array defines the set of DirectX hardware feature levels this app supports.
// The ordering is important and you should preserve it.
// Don't forget to declare your app's minimum required feature level in its
// description. All apps are assumed to support 9.1 unless otherwise stated.
D3D_FEATURE_LEVEL featureLevels[] =
{
D3D_FEATURE_LEVEL_11_1,
D3D_FEATURE_LEVEL_11_0,
D3D_FEATURE_LEVEL_10_1,
D3D_FEATURE_LEVEL_10_0,
};
// This array defines the set of DirectX hardware feature levels this app supports.
// The ordering is important and you should preserve it.
// Don't forget to declare your app's minimum required feature level in its
// description. All apps are assumed to support 9.1 unless otherwise stated.
D3D_FEATURE_LEVEL featureLevels[] =
{
D3D_FEATURE_LEVEL_11_1,
D3D_FEATURE_LEVEL_11_0,
D3D_FEATURE_LEVEL_10_1,
D3D_FEATURE_LEVEL_10_0,
};
// Create the DX11 API device object, and get a corresponding context.
ComPtr<ID3D11DeviceContext> d3dDC = nullptr;
Debug::ThrowIfComFailed(
D3D11CreateDevice(
nullptr, // specify null to use the default adapter
D3D_DRIVER_TYPE_HARDWARE,
NULL,
D3D11_CREATE_DEVICE_BGRA_SUPPORT,
featureLevels, // list of feature levels this app can support
ARRAYSIZE(featureLevels), // number of possible feature levels
D3D11_SDK_VERSION,
&d3dDevice, // returns the Direct3D device created
nullptr, // returns feature level of device created
&d3dDC // returns the device immediate context
),
L"创建 D3D Device 失败"
);
// Create the DX11 API device object, and get a corresponding context.
ComPtr<ID3D11DeviceContext> d3dDC = nullptr;
Debug::ThrowIfComFailed(
D3D11CreateDevice(
nullptr, // specify null to use the default adapter
D3D_DRIVER_TYPE_HARDWARE,
NULL,
D3D11_CREATE_DEVICE_BGRA_SUPPORT,
featureLevels, // list of feature levels this app can support
ARRAYSIZE(featureLevels), // number of possible feature levels
D3D11_SDK_VERSION,
&d3dDevice, // returns the Direct3D device created
nullptr, // returns feature level of device created
&d3dDC // returns the device immediate context
),
L"创建 D3D Device 失败"
);
// Obtain the underlying DXGI device of the Direct3D11 device.
ComPtr<IDXGIDevice1> dxgiDevice;
Debug::ThrowIfComFailed(
d3dDevice.As(&dxgiDevice),
L"获取 DXGI Device 失败"
);
// Obtain the underlying DXGI device of the Direct3D11 device.
ComPtr<IDXGIDevice1> dxgiDevice;
Debug::ThrowIfComFailed(
d3dDevice.As(&dxgiDevice),
L"获取 DXGI Device 失败"
);
Debug::ThrowIfComFailed(
D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, IID_PPV_ARGS(&d2dFactory)),
L"创建 D2D Factory 失败"
);
Debug::ThrowIfComFailed(
D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, IID_PPV_ARGS(&d2dFactory)),
L"创建 D2D Factory 失败"
);
// Obtain the Direct2D device for 2-D rendering.
Debug::ThrowIfComFailed(
d2dFactory->CreateDevice(dxgiDevice.Get(), &d2dDevice),
L"创建 D2D Device 失败"
);
// Get Direct2D device's corresponding device context object.
Debug::ThrowIfComFailed(
d2dDevice->CreateDeviceContext(D2D1_DEVICE_CONTEXT_OPTIONS_NONE, &_d2dDC),
L"创建 D2D DC 失败"
);
// Obtain the Direct2D device for 2-D rendering.
Debug::ThrowIfComFailed(
d2dFactory->CreateDevice(dxgiDevice.Get(), &d2dDevice),
L"创建 D2D Device 失败"
);
// Get Direct2D device's corresponding device context object.
Debug::ThrowIfComFailed(
d2dDevice->CreateDeviceContext(D2D1_DEVICE_CONTEXT_OPTIONS_NONE, &_d2dDC),
L"创建 D2D DC 失败"
);
// Identify the physical adapter (GPU or card) this device is runs on.
ComPtr<IDXGIAdapter> dxgiAdapter;
Debug::ThrowIfComFailed(
dxgiDevice->GetAdapter(&dxgiAdapter),
L"获取 DXGI Adapter 失败"
);
// Identify the physical adapter (GPU or card) this device is runs on.
ComPtr<IDXGIAdapter> dxgiAdapter;
Debug::ThrowIfComFailed(
dxgiDevice->GetAdapter(&dxgiAdapter),
L"获取 DXGI Adapter 失败"
);
// Get the factory object that created the DXGI device.
ComPtr<IDXGIFactory2> dxgiFactory = nullptr;
Debug::ThrowIfComFailed(
dxgiAdapter->GetParent(IID_PPV_ARGS(&dxgiFactory)),
L"获取 DXGI Factory 失败"
);
// Allocate a descriptor.
DXGI_SWAP_CHAIN_DESC1 swapChainDesc{};
swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;
// Get the factory object that created the DXGI device.
ComPtr<IDXGIFactory2> dxgiFactory = nullptr;
Debug::ThrowIfComFailed(
dxgiAdapter->GetParent(IID_PPV_ARGS(&dxgiFactory)),
L"获取 DXGI Factory 失败"
);
// Allocate a descriptor.
DXGI_SWAP_CHAIN_DESC1 swapChainDesc{};
swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;
const RECT& hostClient = Env::$instance->GetHostClient();
swapChainDesc.Width = hostClient.right - hostClient.left,
swapChainDesc.Height = hostClient.bottom - hostClient.top,
swapChainDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; // this is the most common swapchain format
swapChainDesc.Stereo = FALSE;
swapChainDesc.SampleDesc.Count = 1; // don't use multi-sampling
swapChainDesc.SampleDesc.Quality = 0;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.BufferCount = 2; // use double buffering to enable flip
swapChainDesc.Scaling = DXGI_SCALING_NONE;
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_IGNORE;
const RECT& hostClient = Env::$instance->GetHostClient();
swapChainDesc.Width = hostClient.right - hostClient.left,
swapChainDesc.Height = hostClient.bottom - hostClient.top,
swapChainDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; // this is the most common swapchain format
swapChainDesc.Stereo = FALSE;
swapChainDesc.SampleDesc.Count = 1; // don't use multi-sampling
swapChainDesc.SampleDesc.Quality = 0;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.BufferCount = 2; // use double buffering to enable flip
swapChainDesc.Scaling = DXGI_SCALING_NONE;
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_IGNORE;
// Get the final swap chain for this window from the DXGI factory.
ComPtr<IDXGISwapChain1> dxgiSwapChain1;
Debug::ThrowIfComFailed(
dxgiFactory->CreateSwapChainForHwnd(
d3dDevice.Get(),
Env::$instance->GetHwndHost(),
&swapChainDesc,
nullptr,
nullptr,
&dxgiSwapChain1
),
L"创建 Swap Chain 失败"
);
// 转换成 IDXGISwapChain2 以使用 DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT
// 见 https://docs.microsoft.com/en-us/windows/win32/api/dxgi/ne-dxgi-dxgi_swap_chain_flag
Debug::ThrowIfComFailed(
dxgiSwapChain1.As(&_dxgiSwapChain),
L"获取 IDXGISwapChain2 失败"
);
Debug::ThrowIfComFailed(
_dxgiSwapChain->SetMaximumFrameLatency(1),
L"SetMaximumFrameLatency 失败"
);
// Get the final swap chain for this window from the DXGI factory.
ComPtr<IDXGISwapChain1> dxgiSwapChain1;
Debug::ThrowIfComFailed(
dxgiFactory->CreateSwapChainForHwnd(
d3dDevice.Get(),
Env::$instance->GetHwndHost(),
&swapChainDesc,
nullptr,
nullptr,
&dxgiSwapChain1
),
L"创建 Swap Chain 失败"
);
// 转换成 IDXGISwapChain2 以使用 DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT
// 见 https://docs.microsoft.com/en-us/windows/win32/api/dxgi/ne-dxgi-dxgi_swap_chain_flag
Debug::ThrowIfComFailed(
dxgiSwapChain1.As(&_dxgiSwapChain),
L"获取 IDXGISwapChain2 失败"
);
Debug::ThrowIfComFailed(
_dxgiSwapChain->SetMaximumFrameLatency(1),
L"SetMaximumFrameLatency 失败"
);
if (Env::$instance->GetCaptureMode() == 1) {
Debug::ThrowIfComFailed(
_dxgiSwapChain->GetContainingOutput(&_dxgiOutput),
L"获取DXGIOutput失败"
);
} else {
_frameLatencyWaitableObject = _dxgiSwapChain->GetFrameLatencyWaitableObject();
}
if (Env::$instance->GetCaptureMode() == 1) {
Debug::ThrowIfComFailed(
_dxgiSwapChain->GetContainingOutput(&_dxgiOutput),
L"获取DXGIOutput失败"
);
} else {
_frameLatencyWaitableObject = _dxgiSwapChain->GetFrameLatencyWaitableObject();
}
// Direct2D needs the dxgi version of the backbuffer surface pointer.
ComPtr<IDXGISurface> dxgiBackBuffer = nullptr;
Debug::ThrowIfComFailed(
_dxgiSwapChain->GetBuffer(0, IID_PPV_ARGS(&dxgiBackBuffer)),
L"获取 DXGI Backbuffer 失败"
);
// Direct2D needs the dxgi version of the backbuffer surface pointer.
ComPtr<IDXGISurface> dxgiBackBuffer = nullptr;
Debug::ThrowIfComFailed(
_dxgiSwapChain->GetBuffer(0, IID_PPV_ARGS(&dxgiBackBuffer)),
L"获取 DXGI Backbuffer 失败"
);
// Now we set up the Direct2D render target bitmap linked to the swapchain.
// Whenever we render to this bitmap, it is directly rendered to the
// swap chain associated with the window.
D2D1_BITMAP_PROPERTIES1 bitmapProperties = BitmapProperties1(
D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW,
PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE)
);
// Now we set up the Direct2D render target bitmap linked to the swapchain.
// Whenever we render to this bitmap, it is directly rendered to the
// swap chain associated with the window.
D2D1_BITMAP_PROPERTIES1 bitmapProperties = BitmapProperties1(
D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW,
PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE)
);
// Get a D2D surface from the DXGI back buffer to use as the D2D render target.
ComPtr<ID2D1Bitmap1> d2dTargetBitmap = nullptr;
Debug::ThrowIfComFailed(
_d2dDC->CreateBitmapFromDxgiSurface(
dxgiBackBuffer.Get(),
&bitmapProperties,
&d2dTargetBitmap
),
L"CreateBitmapFromDxgiSurface 失败"
);
// Get a D2D surface from the DXGI back buffer to use as the D2D render target.
ComPtr<ID2D1Bitmap1> d2dTargetBitmap = nullptr;
Debug::ThrowIfComFailed(
_d2dDC->CreateBitmapFromDxgiSurface(
dxgiBackBuffer.Get(),
&bitmapProperties,
&d2dTargetBitmap
),
L"CreateBitmapFromDxgiSurface 失败"
);
// Now we can set the Direct2D render target.
_d2dDC->SetTarget(d2dTargetBitmap.Get());
_d2dDC->SetUnitMode(D2D1_UNIT_MODE_PIXELS);
// Now we can set the Direct2D render target.
_d2dDC->SetTarget(d2dTargetBitmap.Get());
_d2dDC->SetUnitMode(D2D1_UNIT_MODE_PIXELS);
Env::$instance->SetD2DContext(d3dDevice, d2dFactory, d2dDevice, _d2dDC);
}
Env::$instance->SetD2DContext(d3dDevice, d2dFactory, d2dDevice, _d2dDC);
}
ComPtr<ID2D1DeviceContext> _d2dDC = nullptr;
ComPtr<IDXGISwapChain2> _dxgiSwapChain = nullptr;
ComPtr<ID2D1DeviceContext> _d2dDC = nullptr;
ComPtr<IDXGISwapChain2> _dxgiSwapChain = nullptr;
// 用于 GDI 捕获
ComPtr<IDXGIOutput> _dxgiOutput = nullptr;
// 用于 WinRT 捕获
HANDLE _frameLatencyWaitableObject;
// 用于 GDI 捕获
ComPtr<IDXGIOutput> _dxgiOutput = nullptr;
// 用于 WinRT 捕获
HANDLE _frameLatencyWaitableObject;
// 未接收到帧时确保不渲染
bool _waitingForFrame = false;
// 未接收到帧时确保不渲染
bool _waitingForFrame = false;
};

View file

@ -10,106 +10,106 @@
// c++ 原生 exception 不支持宽字符串
class magpie_exception {
public:
magpie_exception() noexcept {}
magpie_exception() noexcept {}
magpie_exception(const std::wstring_view& msg) noexcept: _msg(msg) {
}
magpie_exception(const std::wstring_view& msg) noexcept: _msg(msg) {
}
virtual const std::wstring& what() const {
return _msg;
}
virtual const std::wstring& what() const {
return _msg;
}
virtual ~magpie_exception() {}
virtual ~magpie_exception() {}
private:
std::wstring _msg;
std::wstring _msg;
};
// COM 出错时产生的异常
class com_exception : public magpie_exception {
public:
com_exception(HRESULT hr) noexcept: _result(hr) {
_whatMsg = std::move(L"HRESULT=" + std::to_wstring(_result));
}
com_exception(HRESULT hr) noexcept: _result(hr) {
_whatMsg = std::move(L"HRESULT=" + std::to_wstring(_result));
}
com_exception(HRESULT hr, const std::wstring_view& msg) noexcept
: magpie_exception(msg), _result(hr) {
_whatMsg = fmt::format(L"{} (HRESULT={#x})", magpie_exception::what(), _result);
}
com_exception(HRESULT hr, const std::wstring_view& msg) noexcept
: magpie_exception(msg), _result(hr) {
_whatMsg = fmt::format(L"{} (HRESULT={#x})", magpie_exception::what(), _result);
}
const std::wstring& what() const override {
return _whatMsg;
}
const std::wstring& what() const override {
return _whatMsg;
}
private:
HRESULT _result;
std::wstring _whatMsg;
HRESULT _result;
std::wstring _whatMsg;
};
// 调用 WIN32 API 出错时产生的异常
class win32_exception : public magpie_exception {
public:
win32_exception() noexcept : magpie_exception() {};
win32_exception() noexcept : magpie_exception() {};
win32_exception(const std::wstring_view& msg) noexcept : magpie_exception(msg) {};
win32_exception(const std::wstring_view& msg) noexcept : magpie_exception(msg) {};
};
class Debug : public CommonDebug {
public:
static SIZE GetSize(const RECT& rect) {
return { rect.right - rect.left, rect.bottom - rect.top };
}
static SIZE GetSize(const RECT& rect) {
return { rect.right - rect.left, rect.bottom - rect.top };
}
static D2D1_SIZE_F GetSize(const D2D1_RECT_F& rect) {
return { rect.right - rect.left,rect.bottom - rect.top };
}
static D2D1_SIZE_F GetSize(const D2D1_RECT_F& rect) {
return { rect.right - rect.left,rect.bottom - rect.top };
}
// 将 COM 的错误转换为异常
static void ThrowIfComFailed(HRESULT hr, const std::wstring_view& failMsg) {
if (SUCCEEDED(hr)) {
return;
}
// 将 COM 的错误转换为异常
static void ThrowIfComFailed(HRESULT hr, const std::wstring_view& failMsg) {
if (SUCCEEDED(hr)) {
return;
}
com_exception e(hr, failMsg);
WriteLine(L"com_exception: " + e.what());
com_exception e(hr, failMsg);
WriteLine(L"com_exception: " + e.what());
throw e;
}
throw e;
}
// 将 Win32 错误转换成异常
template <typename T>
static void ThrowIfWin32Failed(T result, const std::wstring_view& failMsg) {
if (result) {
return;
}
// 将 Win32 错误转换成异常
template <typename T>
static void ThrowIfWin32Failed(T result, const std::wstring_view& failMsg) {
if (result) {
return;
}
win32_exception e(failMsg);
WriteLine(L"win32_exception: " + e.what());
win32_exception e(failMsg);
WriteLine(L"win32_exception: " + e.what());
throw e;
}
throw e;
}
template <typename T>
static void Assert(T result, const std::wstring_view& failMsg) {
if (result) {
return;
}
template <typename T>
static void Assert(T result, const std::wstring_view& failMsg) {
if (result) {
return;
}
magpie_exception e(failMsg);
WriteLine(L"magpie_exception: " + e.what());
magpie_exception e(failMsg);
WriteLine(L"magpie_exception: " + e.what());
throw e;
}
throw e;
}
static int Measure(std::function<void()> func) {
using namespace std::chrono;
static int Measure(std::function<void()> func) {
using namespace std::chrono;
auto t = steady_clock::now();
func();
auto dura = duration_cast<milliseconds>(steady_clock::now() - t);
auto t = steady_clock::now();
func();
auto dura = duration_cast<milliseconds>(steady_clock::now() - t);
return int(dura.count());
}
return int(dura.count());
}
};

View file

@ -12,64 +12,64 @@ HINSTANCE hInst = NULL;
// DLL 入口
BOOL APIENTRY DllMain(
HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
) {
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH:
hInst = hModule;
break;
case DLL_PROCESS_DETACH:
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
}
return TRUE;
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH:
hInst = hModule;
break;
case DLL_PROCESS_DETACH:
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
}
return TRUE;
}
API_DECLSPEC void WINAPI RunMagWindow(
void reportStatus(int status, const wchar_t* errorMsg),
HWND hwndSrc,
const char* scaleModel,
int captureMode,
bool showFPS,
bool noDisturb
void reportStatus(int status, const wchar_t* errorMsg),
HWND hwndSrc,
const char* scaleModel,
int captureMode,
bool showFPS,
bool noDisturb
) {
Debug::ThrowIfComFailed(
CoInitializeEx(NULL, COINIT_MULTITHREADED),
L"初始化 COM 出错"
);
Debug::ThrowIfComFailed(
CoInitializeEx(NULL, COINIT_MULTITHREADED),
L"初始化 COM 出错"
);
try {
Debug::Assert(
IsWindow(hwndSrc) && IsWindowVisible(hwndSrc) && Utils::GetWindowShowCmd(hwndSrc) == SW_NORMAL,
L"不合法的源窗口"
);
Debug::Assert(
captureMode >= 0 && captureMode <= 1,
L"非法的抓取模式"
);
try {
Debug::Assert(
IsWindow(hwndSrc) && IsWindowVisible(hwndSrc) && Utils::GetWindowShowCmd(hwndSrc) == SW_NORMAL,
L"不合法的源窗口"
);
Debug::Assert(
captureMode >= 0 && captureMode <= 1,
L"非法的抓取模式"
);
Env::CreateInstance(hInst, hwndSrc, scaleModel, captureMode, showFPS, noDisturb);
MagWindow::CreateInstance();
} catch(const magpie_exception& e) {
reportStatus(0, (L"创建全屏窗口出错:" + e.what()).c_str());
return;
} catch (...) {
Debug::WriteErrorMessage(L"创建全屏窗口发生未知错误");
reportStatus(0, L"未知错误");
return;
}
reportStatus(2, nullptr);
Env::CreateInstance(hInst, hwndSrc, scaleModel, captureMode, showFPS, noDisturb);
MagWindow::CreateInstance();
} catch(const magpie_exception& e) {
reportStatus(0, (L"创建全屏窗口出错:" + e.what()).c_str());
return;
} catch (...) {
Debug::WriteErrorMessage(L"创建全屏窗口发生未知错误");
reportStatus(0, L"未知错误");
return;
}
reportStatus(2, nullptr);
// 主消息循环
std::wstring errMsg = MagWindow::RunMsgLoop();
// 主消息循环
std::wstring errMsg = MagWindow::RunMsgLoop();
Env::$instance = nullptr;
reportStatus(0, errMsg.empty() ? nullptr : errMsg.c_str());
Env::$instance = nullptr;
reportStatus(0, errMsg.empty() ? nullptr : errMsg.c_str());
}

View file

@ -4,11 +4,11 @@
// {A9DF8B5B-B5C5-478F-B5B3-BC5C48E96EF5}
DEFINE_GUID(GUID_MAGPIE_MONOCHROME_CURSOR_SHADER,
0xa9df8b5b, 0xb5c5, 0x478f, 0xb5, 0xb3, 0xbc, 0x5c, 0x48, 0xe9, 0x6e, 0xf5);
0xa9df8b5b, 0xb5c5, 0x478f, 0xb5, 0xb3, 0xbc, 0x5c, 0x48, 0xe9, 0x6e, 0xf5);
// {BF2F648B-CE26-4177-ACE1-CC0FB3DA9F52}
DEFINE_GUID(CLSID_MAGPIE_MONOCHROME_CURSOR_EFFECT,
0xbf2f648b, 0xce26, 0x4177, 0xac, 0xe1, 0xcc, 0xf, 0xb3, 0xda, 0x9f, 0x52);
0xbf2f648b, 0xce26, 0x4177, 0xac, 0xe1, 0xcc, 0xf, 0xb3, 0xda, 0x9f, 0x52);
constexpr auto MAGPIE_MONOCHROME_CURSOR_SHADER = L"shaders/MonochromeCursorShader.cso";

View file

@ -11,92 +11,92 @@
class MagCallbackWindowCapturer : public WindowCapturerBase {
public:
MagCallbackWindowCapturer() {
if (_instance) {
Debug::Assert(false, L"已存在 MagCallbackWindowCapturer 实例");
}
if (_instance) {
Debug::Assert(false, L"已存在 MagCallbackWindowCapturer 实例");
}
Debug::ThrowIfWin32Failed(
MagInitialize(),
L"MagInitialize 失败"
);
// 创建不可见的放大镜控件
// 大小为目标窗口客户区
SIZE srcClientSize = Utils::GetSize(Env::$instance->GetSrcClient());
// 创建不可见的放大镜控件
// 大小为目标窗口客户区
SIZE srcClientSize = Utils::GetSize(Env::$instance->GetSrcClient());
_hwndMag = CreateWindow(
WC_MAGNIFIER,
L"MagnifierWindow",
WS_CHILD,
0, 0,
srcClientSize.cx, srcClientSize.cy,
Env::$instance->GetHwndHost(),
NULL,
Env::$instance->GetHInstance(),
NULL
);
Debug::ThrowIfWin32Failed(_hwndMag, L"创建放大镜控件失败");
_hwndMag = CreateWindow(
WC_MAGNIFIER,
L"MagnifierWindow",
WS_CHILD,
0, 0,
srcClientSize.cx, srcClientSize.cy,
Env::$instance->GetHwndHost(),
NULL,
Env::$instance->GetHInstance(),
NULL
);
Debug::ThrowIfWin32Failed(_hwndMag, L"创建放大镜控件失败");
Debug::ThrowIfWin32Failed(
MagSetImageScalingCallback(_hwndMag, &_ImageScalingCallback),
L"设置放大镜回调失败"
);
Debug::ThrowIfWin32Failed(
MagSetImageScalingCallback(_hwndMag, &_ImageScalingCallback),
L"设置放大镜回调失败"
);
_instance = this;
_instance = this;
}
~MagCallbackWindowCapturer() {
MagUninitialize();
_instance = nullptr;
_instance = nullptr;
}
ComPtr<IUnknown> GetFrame() override {
// MagSetWindowSource 是同步执行的
if (!MagSetWindowSource(_hwndMag, Env::$instance->GetSrcClient())) {
Debug::WriteErrorMessage(L"MagSetWindowSource 失败");
}
ComPtr<IUnknown> GetFrame() override {
// MagSetWindowSource 是同步执行的
if (!MagSetWindowSource(_hwndMag, Env::$instance->GetSrcClient())) {
Debug::WriteErrorMessage(L"MagSetWindowSource 失败");
}
return _bmp;
return _bmp;
}
CaptureredFrameType GetFrameType() override {
return CaptureredFrameType::D2DImage;
}
CaptureredFrameType GetFrameType() override {
return CaptureredFrameType::D2DImage;
}
private:
static BOOL CALLBACK _ImageScalingCallback(
HWND hWnd,
void* srcdata,
MAGIMAGEHEADER srcheader,
void* destdata,
MAGIMAGEHEADER destheader,
RECT unclipped,
RECT clipped,
HRGN dirty
) {
if (!_instance) {
return FALSE;
}
static BOOL CALLBACK _ImageScalingCallback(
HWND hWnd,
void* srcdata,
MAGIMAGEHEADER srcheader,
void* destdata,
MAGIMAGEHEADER destheader,
RECT unclipped,
RECT clipped,
HRGN dirty
) {
if (!_instance) {
return FALSE;
}
if (srcheader.cbSize / srcheader.width / srcheader.height != 4) {
Debug::WriteErrorMessage(L"srcdata 不是BGRA格式");
return FALSE;
}
Env::$instance->GetD2DDC()->CreateBitmap(
{ srcheader.width, srcheader.height },
BitmapProperties(PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE)),
& _instance->_bmp
);
D2D1_RECT_U destRect = { 0, 0, srcheader.width, srcheader.height };
_instance->_bmp->CopyFromMemory(&destRect, srcdata, srcheader.stride);
if (srcheader.cbSize / srcheader.width / srcheader.height != 4) {
Debug::WriteErrorMessage(L"srcdata 不是BGRA格式");
return FALSE;
}
Env::$instance->GetD2DDC()->CreateBitmap(
{ srcheader.width, srcheader.height },
BitmapProperties(PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE)),
& _instance->_bmp
);
D2D1_RECT_U destRect = { 0, 0, srcheader.width, srcheader.height };
_instance->_bmp->CopyFromMemory(&destRect, srcdata, srcheader.stride);
return TRUE;
}
return TRUE;
}
HWND _hwndMag = NULL;
HWND _hwndMag = NULL;
ComPtr<ID2D1Bitmap> _bmp = nullptr;
ComPtr<ID2D1Bitmap> _bmp = nullptr;
static MagCallbackWindowCapturer* _instance;
static MagCallbackWindowCapturer* _instance;
};

View file

@ -8,138 +8,138 @@
// 管理全屏窗口的创建和销毁
class MagWindow {
public:
// 确保只能同时存在一个全屏窗口
static std::unique_ptr<MagWindow> $instance;
// 确保只能同时存在一个全屏窗口
static std::unique_ptr<MagWindow> $instance;
static void CreateInstance() {
$instance.reset(new MagWindow());
}
// 不可复制,不可移动
MagWindow(const MagWindow&) = delete;
MagWindow(MagWindow&&) = delete;
static void CreateInstance() {
$instance.reset(new MagWindow());
}
// 不可复制,不可移动
MagWindow(const MagWindow&) = delete;
MagWindow(MagWindow&&) = delete;
~MagWindow() {
UnregisterClass(_HOST_WINDOW_CLASS_NAME, Env::$instance->GetHInstance());
}
~MagWindow() {
UnregisterClass(_HOST_WINDOW_CLASS_NAME, Env::$instance->GetHInstance());
}
public:
static std::wstring RunMsgLoop() {
std::wstring errMsg;
static std::wstring RunMsgLoop() {
std::wstring errMsg;
while (true) {
MSG msg;
while (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT) {
return std::move(errMsg);
}
while (true) {
MSG msg;
while (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT) {
return std::move(errMsg);
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
try {
if ($instance) {
$instance->_renderManager->Render();
}
} catch (const magpie_exception& e) {
errMsg = L"渲染出错:" + e.what();
DestroyWindow(Env::$instance->GetHwndHost());
} catch (...) {
errMsg = L"渲染出现未知错误";
DestroyWindow(Env::$instance->GetHwndHost());
}
}
}
try {
if ($instance) {
$instance->_renderManager->Render();
}
} catch (const magpie_exception& e) {
errMsg = L"渲染出错:" + e.what();
DestroyWindow(Env::$instance->GetHwndHost());
} catch (...) {
errMsg = L"渲染出现未知错误";
DestroyWindow(Env::$instance->GetHwndHost());
}
}
}
private:
MagWindow() {
if ($instance) {
Debug::Assert(false, L"已存在全屏窗口");
}
MagWindow() {
if ($instance) {
Debug::Assert(false, L"已存在全屏窗口");
}
_RegisterHostWndClass();
_CreateHostWnd();
_RegisterHostWndClass();
_CreateHostWnd();
_renderManager.reset(new RenderManager());
_renderManager.reset(new RenderManager());
Debug::ThrowIfWin32Failed(
ShowWindow(Env::$instance->GetHwndHost(), SW_NORMAL),
L"ShowWindow失败"
);
}
Debug::ThrowIfWin32Failed(
ShowWindow(Env::$instance->GetHwndHost(), SW_NORMAL),
L"ShowWindow失败"
);
}
LRESULT _HostWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
if (message == _WM_DESTORYMAG) {
DestroyWindow(Env::$instance->GetHwndHost());
return 0;
}
if (message == WM_DESTROY) {
// 有两个退出路径:
// 1. 前台窗口发生改变
// 2. 收到_WM_DESTORYMAG 消息
$instance = nullptr;
PostQuitMessage(0);
return 0;
} else {
auto [resolved, rt] = _renderManager->WndProc(hWnd, message, wParam, lParam);
LRESULT _HostWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
if (message == _WM_DESTORYMAG) {
DestroyWindow(Env::$instance->GetHwndHost());
return 0;
}
if (message == WM_DESTROY) {
// 有两个退出路径:
// 1. 前台窗口发生改变
// 2. 收到_WM_DESTORYMAG 消息
$instance = nullptr;
PostQuitMessage(0);
return 0;
} else {
auto [resolved, rt] = _renderManager->WndProc(hWnd, message, wParam, lParam);
if (resolved) {
return rt;
} else {
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
if (resolved) {
return rt;
} else {
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
return 0;
}
return 0;
}
static LRESULT CALLBACK _HostWndProcStatic(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
if (!$instance) {
return DefWindowProc(hWnd, message, wParam, lParam);
} else {
return $instance->_HostWndProc(hWnd, message, wParam, lParam);
}
}
static LRESULT CALLBACK _HostWndProcStatic(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
if (!$instance) {
return DefWindowProc(hWnd, message, wParam, lParam);
} else {
return $instance->_HostWndProc(hWnd, message, wParam, lParam);
}
}
// 注册全屏窗口类
void _RegisterHostWndClass() const {
WNDCLASSEX wcex = {};
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.lpfnWndProc = _HostWndProcStatic;
wcex.hInstance = Env::$instance->GetHInstance();
wcex.lpszClassName = _HOST_WINDOW_CLASS_NAME;
// 注册全屏窗口类
void _RegisterHostWndClass() const {
WNDCLASSEX wcex = {};
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.lpfnWndProc = _HostWndProcStatic;
wcex.hInstance = Env::$instance->GetHInstance();
wcex.lpszClassName = _HOST_WINDOW_CLASS_NAME;
// 忽略重复注册造成的错误
RegisterClassEx(&wcex);
}
// 忽略重复注册造成的错误
RegisterClassEx(&wcex);
}
void _CreateHostWnd() {
// 创建全屏窗口
SIZE screenSize = Utils::GetScreenSize(Env::$instance->GetHwndSrc());
HWND hwndHost = CreateWindowEx(
(Env::$instance->IsNoDisturb() ? 0 : WS_EX_TOPMOST) | WS_EX_NOACTIVATE | WS_EX_LAYERED | WS_EX_TRANSPARENT,
_HOST_WINDOW_CLASS_NAME, NULL, WS_CLIPCHILDREN | WS_POPUP | WS_VISIBLE,
0, 0, screenSize.cx, screenSize.cy,
NULL, NULL, Env::$instance->GetHInstance(), NULL);
Debug::ThrowIfWin32Failed(hwndHost, L"创建全屏窗口失败");
void _CreateHostWnd() {
// 创建全屏窗口
SIZE screenSize = Utils::GetScreenSize(Env::$instance->GetHwndSrc());
HWND hwndHost = CreateWindowEx(
(Env::$instance->IsNoDisturb() ? 0 : WS_EX_TOPMOST) | WS_EX_NOACTIVATE | WS_EX_LAYERED | WS_EX_TRANSPARENT,
_HOST_WINDOW_CLASS_NAME, NULL, WS_CLIPCHILDREN | WS_POPUP | WS_VISIBLE,
0, 0, screenSize.cx, screenSize.cy,
NULL, NULL, Env::$instance->GetHInstance(), NULL);
Debug::ThrowIfWin32Failed(hwndHost, L"创建全屏窗口失败");
// 设置窗口不透明
Debug::ThrowIfWin32Failed(
SetLayeredWindowAttributes(hwndHost, 0, 255, LWA_ALPHA),
L"SetLayeredWindowAttributes 失败"
);
// 设置窗口不透明
Debug::ThrowIfWin32Failed(
SetLayeredWindowAttributes(hwndHost, 0, 255, LWA_ALPHA),
L"SetLayeredWindowAttributes 失败"
);
Env::$instance->SetHwndHost(hwndHost);
}
Env::$instance->SetHwndHost(hwndHost);
}
// 全屏窗口类名
static constexpr const wchar_t* _HOST_WINDOW_CLASS_NAME = L"Window_Magpie_967EB565-6F73-4E94-AE53-00CC42592A22";
// 全屏窗口类名
static constexpr const wchar_t* _HOST_WINDOW_CLASS_NAME = L"Window_Magpie_967EB565-6F73-4E94-AE53-00CC42592A22";
static UINT _WM_DESTORYMAG;
std::unique_ptr<RenderManager> _renderManager = nullptr;
static UINT _WM_DESTORYMAG;
std::unique_ptr<RenderManager> _renderManager = nullptr;
};

View file

@ -7,89 +7,89 @@
class MonochromeCursorEffect : public EffectBase {
public:
IFACEMETHODIMP Initialize(
_In_ ID2D1EffectContext* pEffectContext,
_In_ ID2D1TransformGraph* pTransformGraph
) {
HRESULT hr = MonochromeCursorTransform::Create(pEffectContext, &_transform);
if (FAILED(hr)) {
return hr;
}
IFACEMETHODIMP Initialize(
_In_ ID2D1EffectContext* pEffectContext,
_In_ ID2D1TransformGraph* pTransformGraph
) {
HRESULT hr = MonochromeCursorTransform::Create(pEffectContext, &_transform);
if (FAILED(hr)) {
return hr;
}
hr = pTransformGraph->AddNode(_transform.Get());
if (FAILED(hr)) {
return hr;
}
hr = pTransformGraph->ConnectToEffectInput(0, _transform.Get(), 0);
if (FAILED(hr)) {
return hr;
}
hr = pTransformGraph->ConnectToEffectInput(1, _transform.Get(), 1);
if (FAILED(hr)) {
return hr;
}
hr = pTransformGraph->SetOutputNode(_transform.Get());
if (FAILED(hr)) {
return hr;
}
hr = pTransformGraph->AddNode(_transform.Get());
if (FAILED(hr)) {
return hr;
}
hr = pTransformGraph->ConnectToEffectInput(0, _transform.Get(), 0);
if (FAILED(hr)) {
return hr;
}
hr = pTransformGraph->ConnectToEffectInput(1, _transform.Get(), 1);
if (FAILED(hr)) {
return hr;
}
hr = pTransformGraph->SetOutputNode(_transform.Get());
if (FAILED(hr)) {
return hr;
}
return S_OK;
}
return S_OK;
}
HRESULT SetCursorPos(D2D_VECTOR_2F value) {
_transform->SetCursorPos({ lroundf(value.x), lroundf(value.y) });
return S_OK;
}
HRESULT SetCursorPos(D2D_VECTOR_2F value) {
_transform->SetCursorPos({ lroundf(value.x), lroundf(value.y) });
return S_OK;
}
D2D_VECTOR_2F GetCursorPos() const {
POINT pos = _transform->GetCursorPos();
return { float(pos.x), float(pos.y) };
}
D2D_VECTOR_2F GetCursorPos() const {
POINT pos = _transform->GetCursorPos();
return { float(pos.x), float(pos.y) };
}
enum PROPS {
PROP_CURSOR_POS = 0
};
enum PROPS {
PROP_CURSOR_POS = 0
};
static HRESULT Register(_In_ ID2D1Factory1* pFactory) {
const D2D1_PROPERTY_BINDING bindings[] =
{
D2D1_VALUE_TYPE_BINDING(L"CursorPos", &SetCursorPos, &GetCursorPos),
};
static HRESULT Register(_In_ ID2D1Factory1* pFactory) {
const D2D1_PROPERTY_BINDING bindings[] =
{
D2D1_VALUE_TYPE_BINDING(L"CursorPos", &SetCursorPos, &GetCursorPos),
};
HRESULT hr = pFactory->RegisterEffectFromString(CLSID_MAGPIE_MONOCHROME_CURSOR_EFFECT, XML(
<?xml version='1.0'?>
<Effect>
<!--System Properties-->
<Property name='DisplayName' type='string' value='Monochrome cursor'/>
<Property name='Author' type='string' value='Blinue'/>
<Property name='Category' type='string' value='Cursor'/>
<Property name='Description' type='string' value='Monochrome cursor'/>
<Inputs>
<Input name='Source'/>
<Input name='Cursor'/>
</Inputs>
<Property name='CursorPos' type='vector2'>
<Property name='DisplayName' type='string' value='Cursor Pos'/>
<Property name='Default' type='vector2' value='(0,0)'/>
</Property>
</Effect>
), bindings, ARRAYSIZE(bindings), CreateEffect);
HRESULT hr = pFactory->RegisterEffectFromString(CLSID_MAGPIE_MONOCHROME_CURSOR_EFFECT, XML(
<?xml version='1.0'?>
<Effect>
<!--System Properties-->
<Property name='DisplayName' type='string' value='Monochrome cursor'/>
<Property name='Author' type='string' value='Blinue'/>
<Property name='Category' type='string' value='Cursor'/>
<Property name='Description' type='string' value='Monochrome cursor'/>
<Inputs>
<Input name='Source'/>
<Input name='Cursor'/>
</Inputs>
<Property name='CursorPos' type='vector2'>
<Property name='DisplayName' type='string' value='Cursor Pos'/>
<Property name='Default' type='vector2' value='(0,0)'/>
</Property>
</Effect>
), bindings, ARRAYSIZE(bindings), CreateEffect);
return hr;
}
return hr;
}
static HRESULT CALLBACK CreateEffect(_Outptr_ IUnknown** ppEffectImpl) {
*ppEffectImpl = static_cast<ID2D1EffectImpl*>(new MonochromeCursorEffect());
static HRESULT CALLBACK CreateEffect(_Outptr_ IUnknown** ppEffectImpl) {
*ppEffectImpl = static_cast<ID2D1EffectImpl*>(new MonochromeCursorEffect());
if (*ppEffectImpl == nullptr) {
return E_OUTOFMEMORY;
}
if (*ppEffectImpl == nullptr) {
return E_OUTOFMEMORY;
}
return S_OK;
}
return S_OK;
}
private:
MonochromeCursorEffect() {}
MonochromeCursorEffect() {}
ComPtr<MonochromeCursorTransform> _transform = nullptr;
ComPtr<MonochromeCursorTransform> _transform = nullptr;
};

View file

@ -6,66 +6,66 @@
class MonochromeCursorTransform : public SimpleDrawTransform<2> {
private:
MonochromeCursorTransform() : SimpleDrawTransform<2>(GUID_MAGPIE_MONOCHROME_CURSOR_SHADER) {}
MonochromeCursorTransform() : SimpleDrawTransform<2>(GUID_MAGPIE_MONOCHROME_CURSOR_SHADER) {}
public:
static HRESULT Create(
_In_ ID2D1EffectContext* d2dEC,
_Outptr_ MonochromeCursorTransform** ppOutput
) {
*ppOutput = nullptr;
static HRESULT Create(
_In_ ID2D1EffectContext* d2dEC,
_Outptr_ MonochromeCursorTransform** ppOutput
) {
*ppOutput = nullptr;
HRESULT hr = LoadShader(
d2dEC,
MAGPIE_MONOCHROME_CURSOR_SHADER,
GUID_MAGPIE_MONOCHROME_CURSOR_SHADER
);
if (FAILED(hr)) {
return hr;
}
HRESULT hr = LoadShader(
d2dEC,
MAGPIE_MONOCHROME_CURSOR_SHADER,
GUID_MAGPIE_MONOCHROME_CURSOR_SHADER
);
if (FAILED(hr)) {
return hr;
}
*ppOutput = new MonochromeCursorTransform();
*ppOutput = new MonochromeCursorTransform();
return S_OK;
}
return S_OK;
}
IFACEMETHODIMP MapInputRectsToOutputRect(
_In_reads_(inputRectCount) const D2D1_RECT_L* pInputRects,
_In_reads_(inputRectCount) const D2D1_RECT_L* pInputOpaqueSubRects,
UINT32 inputRectCount,
_Out_ D2D1_RECT_L* pOutputRect,
_Out_ D2D1_RECT_L* pOutputOpaqueSubRect
) override {
if (inputRectCount != 2) {
return E_INVALIDARG;
}
IFACEMETHODIMP MapInputRectsToOutputRect(
_In_reads_(inputRectCount) const D2D1_RECT_L* pInputRects,
_In_reads_(inputRectCount) const D2D1_RECT_L* pInputOpaqueSubRects,
UINT32 inputRectCount,
_Out_ D2D1_RECT_L* pOutputRect,
_Out_ D2D1_RECT_L* pOutputOpaqueSubRect
) override {
if (inputRectCount != 2) {
return E_INVALIDARG;
}
*pOutputRect = pInputRects[0];
_inputRects[0] = pInputRects[0];
_inputRects[1] = pInputRects[1];
*pOutputRect = pInputRects[0];
_inputRects[0] = pInputRects[0];
_inputRects[1] = pInputRects[1];
*pOutputOpaqueSubRect = { 0,0,0,0 };
*pOutputOpaqueSubRect = { 0,0,0,0 };
RECT shaderConstants{
_cursorPos.x,
_cursorPos.y,
_cursorPos.x + pInputRects[1].right - pInputRects[1].left,
_cursorPos.y + (pInputRects[1].bottom - pInputRects[1].top) / 2
};
RECT shaderConstants{
_cursorPos.x,
_cursorPos.y,
_cursorPos.x + pInputRects[1].right - pInputRects[1].left,
_cursorPos.y + (pInputRects[1].bottom - pInputRects[1].top) / 2
};
_drawInfo->SetPixelShaderConstantBuffer((BYTE*)&shaderConstants, sizeof(shaderConstants));
_drawInfo->SetPixelShaderConstantBuffer((BYTE*)&shaderConstants, sizeof(shaderConstants));
return S_OK;
}
return S_OK;
}
const POINT& GetCursorPos() const {
return _cursorPos;
}
const POINT& GetCursorPos() const {
return _cursorPos;
}
void SetCursorPos(const POINT& value) {
_cursorPos = value;
}
void SetCursorPos(const POINT& value) {
_cursorPos = value;
}
private:
POINT _cursorPos{};
POINT _cursorPos{};
};

View file

@ -9,164 +9,164 @@ using namespace Microsoft::WRL;
class Utils {
public:
static UINT GetWindowShowCmd(HWND hwnd) {
assert(hwnd != NULL);
static UINT GetWindowShowCmd(HWND hwnd) {
assert(hwnd != NULL);
WINDOWPLACEMENT wp{};
wp.length = sizeof(wp);
Debug::ThrowIfWin32Failed(
GetWindowPlacement(hwnd, &wp),
L"GetWindowPlacement失败"
);
WINDOWPLACEMENT wp{};
wp.length = sizeof(wp);
Debug::ThrowIfWin32Failed(
GetWindowPlacement(hwnd, &wp),
L"GetWindowPlacement失败"
);
return wp.showCmd;
}
return wp.showCmd;
}
static void GetClientScreenRect(HWND hWnd, RECT& rect) {
RECT r;
Debug::ThrowIfWin32Failed(
GetClientRect(hWnd, &r),
L"GetClientRect 失败"
);
static void GetClientScreenRect(HWND hWnd, RECT& rect) {
RECT r;
Debug::ThrowIfWin32Failed(
GetClientRect(hWnd, &r),
L"GetClientRect 失败"
);
POINT p{};
Debug::ThrowIfWin32Failed(
ClientToScreen(hWnd, &p),
L"ClientToScreen 失败"
);
POINT p{};
Debug::ThrowIfWin32Failed(
ClientToScreen(hWnd, &p),
L"ClientToScreen 失败"
);
rect.bottom = r.bottom + p.y;
rect.left = r.left + p.x;
rect.right = r.right + p.x;
rect.top = r.top + p.y;
}
rect.bottom = r.bottom + p.y;
rect.left = r.left + p.x;
rect.right = r.right + p.x;
rect.top = r.top + p.y;
}
static SIZE GetScreenSize(HWND hWnd) {
HMONITOR hMonitor = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST);
static SIZE GetScreenSize(HWND hWnd) {
HMONITOR hMonitor = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST);
MONITORINFO mi{};
mi.cbSize = sizeof(mi);
Debug::ThrowIfWin32Failed(
GetMonitorInfo(hMonitor, &mi),
L"获取显示器信息失败"
);
return GetSize(mi.rcMonitor);
}
MONITORINFO mi{};
mi.cbSize = sizeof(mi);
Debug::ThrowIfWin32Failed(
GetMonitorInfo(hMonitor, &mi),
L"获取显示器信息失败"
);
return GetSize(mi.rcMonitor);
}
static SIZE GetSize(const RECT& rect) {
return { rect.right - rect.left, rect.bottom - rect.top };
}
static SIZE GetSize(const RECT& rect) {
return { rect.right - rect.left, rect.bottom - rect.top };
}
static D2D1_SIZE_F GetSize(const D2D1_RECT_F& rect) {
return { rect.right - rect.left,rect.bottom - rect.top };
}
static D2D1_SIZE_F GetSize(const D2D1_RECT_F& rect) {
return { rect.right - rect.left,rect.bottom - rect.top };
}
static BOOL Str2GUID(const std::wstring_view &szGUID, GUID& guid) {
if (szGUID.size() != 36) {
return FALSE;
}
static BOOL Str2GUID(const std::wstring_view &szGUID, GUID& guid) {
if (szGUID.size() != 36) {
return FALSE;
}
return swscanf_s(szGUID.data(),
L"%08lx-%04hx-%04hx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx",
&guid.Data1,
&guid.Data2,
&guid.Data3,
&guid.Data4[0], &guid.Data4[1],
&guid.Data4[2], &guid.Data4[3], &guid.Data4[4], &guid.Data4[5], &guid.Data4[6], &guid.Data4[7]
) == 11;
}
return swscanf_s(szGUID.data(),
L"%08lx-%04hx-%04hx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx",
&guid.Data1,
&guid.Data2,
&guid.Data3,
&guid.Data4[0], &guid.Data4[1],
&guid.Data4[2], &guid.Data4[3], &guid.Data4[4], &guid.Data4[5], &guid.Data4[6], &guid.Data4[7]
) == 11;
}
static std::string GUID2Str(GUID guid) {
char buf[65]{};
static std::string GUID2Str(GUID guid) {
char buf[65]{};
sprintf_s(buf, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
guid.Data1,
guid.Data2,
guid.Data3,
guid.Data4[0], guid.Data4[1],
guid.Data4[2], guid.Data4[3], guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]
);
return { buf };
}
sprintf_s(buf, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
guid.Data1,
guid.Data2,
guid.Data3,
guid.Data4[0], guid.Data4[1],
guid.Data4[2], guid.Data4[3], guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]
);
return { buf };
}
static void SaveD2DImage(
ComPtr<ID2D1Device> d2dDevice,
ComPtr<ID2D1Image> img,
const std::wstring_view& fileName
) {
ComPtr<IWICImagingFactory2> wicImgFactory;
static void SaveD2DImage(
ComPtr<ID2D1Device> d2dDevice,
ComPtr<ID2D1Image> img,
const std::wstring_view& fileName
) {
ComPtr<IWICImagingFactory2> wicImgFactory;
Debug::ThrowIfComFailed(
CoCreateInstance(
CLSID_WICImagingFactory,
nullptr,
CLSCTX_INPROC_SERVER,
IID_PPV_ARGS(&wicImgFactory)
),
L"创建 IWICImagingFactory2 失败"
);
Debug::ThrowIfComFailed(
CoCreateInstance(
CLSID_WICImagingFactory,
nullptr,
CLSCTX_INPROC_SERVER,
IID_PPV_ARGS(&wicImgFactory)
),
L"创建 IWICImagingFactory2 失败"
);
ComPtr<IStream> stream;
Debug::ThrowIfComFailed(
SHCreateStreamOnFileEx(fileName.data(), STGM_WRITE | STGM_CREATE, 0, TRUE, nullptr, &stream),
L"SHCreateStreamOnFileEx 失败"
);
ComPtr<IStream> stream;
Debug::ThrowIfComFailed(
SHCreateStreamOnFileEx(fileName.data(), STGM_WRITE | STGM_CREATE, 0, TRUE, nullptr, &stream),
L"SHCreateStreamOnFileEx 失败"
);
ComPtr<IWICBitmapEncoder> bmpEncoder;
Debug::ThrowIfComFailed(
wicImgFactory->CreateEncoder(GUID_ContainerFormatPng, nullptr, &bmpEncoder),
L"创建 IWICBitmapEncoder 失败"
);
Debug::ThrowIfComFailed(
bmpEncoder->Initialize(stream.Get(), WICBitmapEncoderNoCache),
L"IWICBitmapEncoder 初始化失败"
);
ComPtr<IWICBitmapEncoder> bmpEncoder;
Debug::ThrowIfComFailed(
wicImgFactory->CreateEncoder(GUID_ContainerFormatPng, nullptr, &bmpEncoder),
L"创建 IWICBitmapEncoder 失败"
);
Debug::ThrowIfComFailed(
bmpEncoder->Initialize(stream.Get(), WICBitmapEncoderNoCache),
L"IWICBitmapEncoder 初始化失败"
);
ComPtr<IWICBitmapFrameEncode> frameEncoder;
Debug::ThrowIfComFailed(
bmpEncoder->CreateNewFrame(&frameEncoder, nullptr),
L"创建 IWICBitmapFrameEncode 失败"
);
Debug::ThrowIfComFailed(
frameEncoder->Initialize(nullptr),
L"IWICBitmapFrameEncode 初始化失败"
);
ComPtr<IWICBitmapFrameEncode> frameEncoder;
Debug::ThrowIfComFailed(
bmpEncoder->CreateNewFrame(&frameEncoder, nullptr),
L"创建 IWICBitmapFrameEncode 失败"
);
Debug::ThrowIfComFailed(
frameEncoder->Initialize(nullptr),
L"IWICBitmapFrameEncode 初始化失败"
);
ComPtr<IWICImageEncoder> d2dImgEncoder;
Debug::ThrowIfComFailed(
wicImgFactory->CreateImageEncoder(d2dDevice.Get(), &d2dImgEncoder),
L"创建 IWICImageEncoder 失败"
);
Debug::ThrowIfComFailed(
d2dImgEncoder->WriteFrame(img.Get(), frameEncoder.Get(), nullptr),
L"IWICImageEncoder.WriteFrame失败"
);
Debug::ThrowIfComFailed(frameEncoder->Commit(), L"IWICBitmapFrameEncode.Commit 失败");
Debug::ThrowIfComFailed(bmpEncoder->Commit(), L"IWICBitmapEncoder.Commit 失败");
Debug::ThrowIfComFailed(stream->Commit(STGC_DEFAULT), L"IStream.Commit 失败");
}
ComPtr<IWICImageEncoder> d2dImgEncoder;
Debug::ThrowIfComFailed(
wicImgFactory->CreateImageEncoder(d2dDevice.Get(), &d2dImgEncoder),
L"创建 IWICImageEncoder 失败"
);
Debug::ThrowIfComFailed(
d2dImgEncoder->WriteFrame(img.Get(), frameEncoder.Get(), nullptr),
L"IWICImageEncoder.WriteFrame失败"
);
Debug::ThrowIfComFailed(frameEncoder->Commit(), L"IWICBitmapFrameEncode.Commit 失败");
Debug::ThrowIfComFailed(bmpEncoder->Commit(), L"IWICBitmapEncoder.Commit 失败");
Debug::ThrowIfComFailed(stream->Commit(STGC_DEFAULT), L"IStream.Commit 失败");
}
static HRESULT UTF8ToUTF16(std::string_view str, std::wstring& result) {
return EffectUtils::UTF8ToUTF16(str, result);
}
static HRESULT UTF8ToUTF16(std::string_view str, std::wstring& result) {
return EffectUtils::UTF8ToUTF16(str, result);
}
};
namespace std {
// std::hash 的 GUID 特化
template<>
struct hash<GUID> {
size_t operator()(const GUID& value) const {
size_t result = hash<unsigned long>()(value.Data1);
result ^= hash<unsigned short>()(value.Data2) << 1;
result ^= hash<unsigned short>()(value.Data3) << 2;
for (int i = 0; i < 8; ++i) {
result ^= hash<unsigned short>()(value.Data4[i]) << i;
}
// std::hash 的 GUID 特化
template<>
struct hash<GUID> {
size_t operator()(const GUID& value) const {
size_t result = hash<unsigned long>()(value.Data1);
result ^= hash<unsigned short>()(value.Data2) << 1;
result ^= hash<unsigned short>()(value.Data3) << 2;
for (int i = 0; i < 8; ++i) {
result ^= hash<unsigned short>()(value.Data4[i]) << i;
}
return result;
}
};
return result;
}
};
}

View file

@ -1,9 +1,9 @@
with open('../EffectCommon/conanfile.py') as f:
exec(f.read())
exec(f.read())
class RuntimeConan(EffectCommonConan):
pass
pass
del EffectCommonConan