-
Notifications
You must be signed in to change notification settings - Fork 32
Open
Labels
enhancementNew feature or requestNew feature or request
Description
考虑开启一个窗口捕获文件复制到剪贴板的操作,可以尝试解析多个文件的路径,Windows提供了此功能。
API 还可以分辨出是否是 Cut 操作。
然后,复用右键菜单的 Paste 等功能。
下面是一个快速原型验证:
// ClipboardCopyFileTest.cpp
//
#include <iostream>
#include <vector>
#include <functional>
#include <windows.h>
#include <shellapi.h>
#include <Shlobj.h>
#include <assert.h>
class ClipboardListener
{
public:
struct FileClipboardEventArg
{
std::vector<std::wstring> files;
bool isMove = false;
};
using Handler = std::function<void(FileClipboardEventArg const &)>;
void OnFileClipboard(std::function<void(FileClipboardEventArg const &)> func)
{
m_handlers.push_back(std::move(func));
createWindowIfNotCreated();
}
static ClipboardListener& GetInstance()
{
static ClipboardListener s;
return s;
}
private:
constexpr static auto MessageWindowClassName = L"FastCopyClipboardMessageWindowClass";
HWND m_hwnd{};
std::vector<Handler> m_handlers;
void createWindowIfNotCreated()
{
if (!m_hwnd) createWindow();
}
void createWindow()
{
WNDCLASSW wc{};
wc.lpszClassName = MessageWindowClassName;
wc.lpfnWndProc = +[](HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) -> LRESULT
{
auto& self = ClipboardListener::GetInstance();
switch (msg)
{
case WM_CREATE:
AddClipboardFormatListener(hwnd);
break;
case WM_CLIPBOARDUPDATE:
self.handleClipboardUpdate();
break;
case WM_DESTROY:
RemoveClipboardFormatListener(hwnd);
break;
}
return DefWindowProcW(hwnd, msg, wParam, lParam);
};
RegisterClassW(&wc);
m_hwnd = CreateWindowW(
MessageWindowClassName, L"", 0,
0, 0, 0, 0,
HWND_MESSAGE, nullptr, nullptr, nullptr
);
assert(m_hwnd);
}
void handleClipboardUpdate()
{
FileClipboardEventArg arg;
if (!readFileClipboard(arg))
return;
for (auto& h : m_handlers)
h(arg);
}
static bool readFileClipboard(FileClipboardEventArg& out);
};
bool ClipboardListener::readFileClipboard(FileClipboardEventArg& out)
{
if (!IsClipboardFormatAvailable(CF_HDROP))
return false;
if (!OpenClipboard(nullptr))
return false;
HDROP hDrop = (HDROP)GetClipboardData(CF_HDROP);
if (!hDrop) {
CloseClipboard();
return false;
}
UINT count = DragQueryFileW(hDrop, 0xFFFFFFFF, nullptr, 0);
if (!count) {
CloseClipboard();
return false;
}
out.files.clear();
out.files.reserve(count);
for (UINT i = 0; i < count; ++i)
{
UINT len = DragQueryFileW(hDrop, i, nullptr, 0);
std::wstring path(len, L'\0');
DragQueryFileW(hDrop, i, path.data(), len + 1);
out.files.push_back(std::move(path));
}
// 判定 Copy / Move
UINT cfDropEffect = RegisterClipboardFormatW(CFSTR_PREFERREDDROPEFFECT);
bool isMove = false;
if (IsClipboardFormatAvailable(cfDropEffect))
{
if (HGLOBAL hEffect = (HGLOBAL)GetClipboardData(cfDropEffect))
{
DWORD* p = (DWORD*)GlobalLock(hEffect);
if (p)
{
isMove = (*p & DROPEFFECT_MOVE) != 0;
GlobalUnlock(hEffect);
}
}
}
out.isMove = isMove;
CloseClipboard();
return !out.files.empty();
}
int main()
{
// Test
ClipboardListener::GetInstance().OnFileClipboard([](ClipboardListener::FileClipboardEventArg const & arg)
{
std::wcout << L"Got " << arg.files.size() << L" files, isMove=" << arg.isMove << std::endl;
for (auto& f : arg.files)
std::wcout << f << std::endl;
std::wcout << std::endl;
}
);
MSG msg{};
while (GetMessageW(&msg, nullptr, 0, 0))
{
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
return 0;
}实际效果如图所示:
参考官方的文档了解更多有关剪贴板数据类型的信息:
https://learn.microsoft.com/zh-cn/windows/win32/shell/clipboard
MuLin4396
Metadata
Metadata
Assignees
Labels
enhancementNew feature or requestNew feature or request