mirror of
https://github.com/Blinue/Magpie.git
synced 2026-06-24 02:04:10 +00:00
style: 将部分c++代码的缩进换为tab
This commit is contained in:
parent
c2295198d0
commit
e37f6fa4e8
14 changed files with 1230 additions and 1162 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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" />
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
#include "CommonDebug.h"
|
||||
|
||||
|
||||
// 用来取代简单的 DrawTransform
|
||||
// 通用的 DrawTransform
|
||||
// 该 DrawTransform 必须满足以下条件:
|
||||
// * NINPUTS 个输入
|
||||
// * 输出与所有输入尺寸相同
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
126
Runtime/Debug.h
126
Runtime/Debug.h
|
|
@ -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());
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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{};
|
||||
};
|
||||
|
|
|
|||
270
Runtime/Utils.h
270
Runtime/Utils.h
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
with open('../EffectCommon/conanfile.py') as f:
|
||||
exec(f.read())
|
||||
exec(f.read())
|
||||
|
||||
|
||||
class RuntimeConan(EffectCommonConan):
|
||||
pass
|
||||
pass
|
||||
|
||||
|
||||
del EffectCommonConan
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue