2024-11-16 21:51:11 +08:00
|
|
|
|
|
2024-11-05 15:46:45 +08:00
|
|
|
|
|
2024-04-02 15:36:52 +08:00
|
|
|
|
bool tryopenclipboard(HWND hwnd = 0)
|
|
|
|
|
{
|
2024-01-08 23:37:00 +08:00
|
|
|
|
bool success = false;
|
2024-04-02 15:36:52 +08:00
|
|
|
|
for (int i = 0; i < 50; i++)
|
|
|
|
|
{
|
|
|
|
|
if (OpenClipboard(hwnd))
|
|
|
|
|
{
|
2024-01-08 23:37:00 +08:00
|
|
|
|
success = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2024-04-02 15:36:52 +08:00
|
|
|
|
else
|
|
|
|
|
{
|
2024-01-08 23:37:00 +08:00
|
|
|
|
Sleep(10);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return success;
|
|
|
|
|
}
|
2024-07-14 15:09:37 +08:00
|
|
|
|
|
|
|
|
|
std::optional<std::wstring> clipboard_get_internal()
|
2024-04-02 15:36:52 +08:00
|
|
|
|
{
|
2024-07-14 15:09:37 +08:00
|
|
|
|
std::optional<std::wstring> data = {};
|
2024-04-02 15:36:52 +08:00
|
|
|
|
if (tryopenclipboard() == false)
|
2024-07-14 15:09:37 +08:00
|
|
|
|
return {};
|
2024-04-02 15:36:52 +08:00
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
HANDLE hData = GetClipboardData(CF_UNICODETEXT);
|
|
|
|
|
if (hData == 0)
|
|
|
|
|
break;
|
|
|
|
|
LPWSTR pszText = static_cast<LPWSTR>(GlobalLock(hData));
|
|
|
|
|
if (pszText == 0)
|
|
|
|
|
break;
|
2024-09-14 10:39:56 +08:00
|
|
|
|
data = std::move(std::wstring(pszText));
|
2024-01-08 23:37:00 +08:00
|
|
|
|
GlobalUnlock(hData);
|
|
|
|
|
} while (false);
|
|
|
|
|
CloseClipboard();
|
|
|
|
|
return data;
|
|
|
|
|
}
|
2024-07-14 15:09:37 +08:00
|
|
|
|
|
2024-11-05 15:46:45 +08:00
|
|
|
|
DECLARE_API bool clipboard_get(void (*cb)(const wchar_t *))
|
2024-07-14 15:09:37 +08:00
|
|
|
|
{
|
|
|
|
|
auto data = std::move(clipboard_get_internal());
|
|
|
|
|
if (!data)
|
|
|
|
|
return false;
|
|
|
|
|
cb(data.value().c_str());
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-05 15:46:45 +08:00
|
|
|
|
DECLARE_API bool clipboard_set(HWND hwnd, wchar_t *text)
|
2024-04-02 15:36:52 +08:00
|
|
|
|
{
|
2024-01-08 23:37:00 +08:00
|
|
|
|
bool success = false;
|
2024-04-02 15:36:52 +08:00
|
|
|
|
// static HWND hwnd=CreateWindowExA(0,"STATIC",0,0,0,0,0,0,0,0,0,0);
|
|
|
|
|
if (tryopenclipboard(hwnd) == false)
|
|
|
|
|
return false;
|
2024-01-08 23:37:00 +08:00
|
|
|
|
EmptyClipboard();
|
2024-04-02 15:36:52 +08:00
|
|
|
|
do
|
|
|
|
|
{
|
2024-01-08 23:37:00 +08:00
|
|
|
|
HGLOBAL hClipboardData;
|
|
|
|
|
size_t len = wcslen(text) + 1;
|
|
|
|
|
hClipboardData = GlobalAlloc(GMEM_MOVEABLE, len * sizeof(wchar_t));
|
2024-04-02 15:36:52 +08:00
|
|
|
|
if (hClipboardData == 0)
|
|
|
|
|
break;
|
|
|
|
|
auto pchData = (wchar_t *)GlobalLock(hClipboardData);
|
|
|
|
|
if (pchData == 0)
|
2024-10-01 22:58:41 +08:00
|
|
|
|
{
|
|
|
|
|
GlobalFree(hClipboardData);
|
2024-04-02 15:36:52 +08:00
|
|
|
|
break;
|
2024-10-01 22:58:41 +08:00
|
|
|
|
}
|
2024-04-02 15:36:52 +08:00
|
|
|
|
wcscpy_s(pchData, len, text);
|
|
|
|
|
GlobalUnlock(hClipboardData);
|
2024-10-01 22:58:41 +08:00
|
|
|
|
if (SetClipboardData(CF_UNICODETEXT, hClipboardData))
|
|
|
|
|
success = true;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
GlobalFree(hClipboardData);
|
|
|
|
|
}
|
2024-04-02 15:36:52 +08:00
|
|
|
|
|
2024-01-08 23:37:00 +08:00
|
|
|
|
} while (false);
|
|
|
|
|
CloseClipboard();
|
|
|
|
|
return success;
|
2024-06-06 20:58:53 +08:00
|
|
|
|
}
|
|
|
|
|
|
2024-07-14 15:09:37 +08:00
|
|
|
|
static void clipboard_callback_1(void (*callback)(const wchar_t *, bool), HANDLE hsema, HWND *hwnd)
|
2024-06-06 20:58:53 +08:00
|
|
|
|
{
|
|
|
|
|
const wchar_t CLASS_NAME[] = L"LunaClipboardListener";
|
|
|
|
|
|
|
|
|
|
WNDCLASS wc = {};
|
|
|
|
|
wc.lpfnWndProc = [](HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|
|
|
|
{
|
2024-11-15 07:46:53 +08:00
|
|
|
|
static auto callbackx = [](HWND hWnd)
|
2024-06-06 20:58:53 +08:00
|
|
|
|
{
|
2024-07-14 15:09:37 +08:00
|
|
|
|
auto data = clipboard_get_internal();
|
2024-06-06 20:58:53 +08:00
|
|
|
|
auto callback_ = reinterpret_cast<decltype(callback)>(GetWindowLongPtrW(hWnd, GWLP_USERDATA));
|
|
|
|
|
if (data && callback_)
|
|
|
|
|
{
|
|
|
|
|
auto ohwnd = GetClipboardOwner();
|
|
|
|
|
DWORD pid;
|
|
|
|
|
GetWindowThreadProcessId(ohwnd, &pid);
|
2024-07-14 15:09:37 +08:00
|
|
|
|
callback_(data.value().c_str(), pid == GetCurrentProcessId());
|
2024-06-06 20:58:53 +08:00
|
|
|
|
}
|
2024-11-15 07:46:53 +08:00
|
|
|
|
};
|
|
|
|
|
#ifndef WINXP
|
|
|
|
|
if (WM_CLIPBOARDUPDATE == message)
|
|
|
|
|
{
|
|
|
|
|
callbackx(hWnd);
|
2024-06-06 20:58:53 +08:00
|
|
|
|
}
|
2024-11-15 07:43:50 +08:00
|
|
|
|
#else
|
2024-11-15 09:11:45 +08:00
|
|
|
|
// 根据文档,这样做是正确的,且在win11下管用。但到xp上就读不到了。。
|
2024-11-15 07:43:50 +08:00
|
|
|
|
static HWND nextviewer;
|
|
|
|
|
switch (message)
|
|
|
|
|
{
|
|
|
|
|
case WM_CREATE:
|
|
|
|
|
{
|
|
|
|
|
nextviewer = SetClipboardViewer(hWnd);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case WM_CHANGECBCHAIN:
|
|
|
|
|
{
|
|
|
|
|
if ((HWND)wParam == nextviewer)
|
|
|
|
|
nextviewer = (HWND)lParam;
|
|
|
|
|
if (nextviewer)
|
|
|
|
|
SendMessage(nextviewer, message, wParam, lParam);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case WM_DESTROY:
|
|
|
|
|
{
|
|
|
|
|
ChangeClipboardChain(hWnd, nextviewer);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case WM_DRAWCLIPBOARD:
|
|
|
|
|
{
|
2024-11-15 07:46:53 +08:00
|
|
|
|
callbackx(hWnd);
|
2024-11-15 07:43:50 +08:00
|
|
|
|
if (nextviewer)
|
|
|
|
|
SendMessage(nextviewer, message, wParam, lParam);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2024-06-06 20:58:53 +08:00
|
|
|
|
return DefWindowProc(hWnd, message, wParam, lParam);
|
|
|
|
|
};
|
|
|
|
|
wc.hInstance = GetModuleHandle(0);
|
|
|
|
|
wc.lpszClassName = CLASS_NAME;
|
|
|
|
|
|
|
|
|
|
static auto _ = RegisterClass(&wc);
|
|
|
|
|
HWND hWnd = CreateWindowEx(
|
|
|
|
|
WS_EX_CLIENTEDGE, CLASS_NAME, CLASS_NAME, WS_OVERLAPPEDWINDOW,
|
|
|
|
|
0, 0, 0, 0,
|
|
|
|
|
NULL, NULL, GetModuleHandle(0), 0);
|
|
|
|
|
|
|
|
|
|
SetWindowLongPtrW(hWnd, GWLP_USERDATA, (LONG_PTR)callback);
|
|
|
|
|
|
|
|
|
|
*hwnd = hWnd;
|
|
|
|
|
ReleaseSemaphore(hsema, 1, 0);
|
|
|
|
|
MSG msg = {};
|
|
|
|
|
while (GetMessage(&msg, NULL, 0, 0))
|
|
|
|
|
{
|
|
|
|
|
TranslateMessage(&msg);
|
|
|
|
|
DispatchMessage(&msg);
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-11-15 09:11:45 +08:00
|
|
|
|
#ifndef WINXP
|
2024-11-04 23:10:41 +08:00
|
|
|
|
DECLARE_API HWND clipboard_callback(void (*callback)(const wchar_t *, bool))
|
2024-06-06 20:58:53 +08:00
|
|
|
|
{
|
|
|
|
|
HANDLE hsema = CreateSemaphoreW(0, 0, 10, 0);
|
|
|
|
|
HWND hwnd;
|
|
|
|
|
|
|
|
|
|
std::thread(std::bind(clipboard_callback_1, callback, hsema, &hwnd)).detach();
|
|
|
|
|
|
|
|
|
|
WaitForSingleObject(hsema, INFINITE);
|
|
|
|
|
CloseHandle(hsema);
|
|
|
|
|
if (AddClipboardFormatListener(hwnd))
|
|
|
|
|
return hwnd;
|
|
|
|
|
else
|
|
|
|
|
return NULL;
|
2024-11-15 09:11:45 +08:00
|
|
|
|
}
|
2024-11-15 07:49:38 +08:00
|
|
|
|
#else
|
2024-11-15 09:11:45 +08:00
|
|
|
|
static int running = false;
|
|
|
|
|
DECLARE_API HWND clipboard_callback(void (*callback)(const wchar_t *, bool))
|
|
|
|
|
{
|
|
|
|
|
running = true;
|
|
|
|
|
std::thread([=]()
|
|
|
|
|
{
|
|
|
|
|
std::wstring last;
|
|
|
|
|
while(running){
|
|
|
|
|
Sleep(100);
|
|
|
|
|
auto data = clipboard_get_internal();
|
|
|
|
|
if(data){
|
|
|
|
|
if(last==data.value())continue;
|
|
|
|
|
last=data.value();
|
|
|
|
|
auto ohwnd = GetClipboardOwner();
|
|
|
|
|
DWORD pid;
|
|
|
|
|
GetWindowThreadProcessId(ohwnd, &pid);
|
|
|
|
|
callback(data.value().c_str(), pid == GetCurrentProcessId());
|
|
|
|
|
}
|
|
|
|
|
} })
|
|
|
|
|
.detach();
|
|
|
|
|
return NULL;
|
2024-06-06 20:58:53 +08:00
|
|
|
|
}
|
2024-11-15 09:11:45 +08:00
|
|
|
|
#endif
|
2024-11-04 23:10:41 +08:00
|
|
|
|
DECLARE_API void clipboard_callback_stop(HWND hwnd)
|
2024-06-06 20:58:53 +08:00
|
|
|
|
{
|
2024-11-15 09:11:45 +08:00
|
|
|
|
#ifndef WINXP
|
2024-06-06 20:58:53 +08:00
|
|
|
|
if (!hwnd)
|
|
|
|
|
return;
|
|
|
|
|
RemoveClipboardFormatListener(hwnd);
|
|
|
|
|
DestroyWindow(hwnd);
|
2024-11-15 09:11:45 +08:00
|
|
|
|
#else
|
|
|
|
|
running = false;
|
|
|
|
|
#endif
|
2024-06-06 20:58:53 +08:00
|
|
|
|
}
|
2024-10-01 22:58:41 +08:00
|
|
|
|
|
2024-11-04 23:10:41 +08:00
|
|
|
|
DECLARE_API bool clipboard_set_image(HWND hwnd, void *ptr, size_t size)
|
2024-10-01 22:58:41 +08:00
|
|
|
|
{
|
|
|
|
|
size -= sizeof(BITMAPFILEHEADER);
|
|
|
|
|
HGLOBAL hDib = GlobalAlloc(GMEM_MOVEABLE, size);
|
|
|
|
|
if (!hDib)
|
|
|
|
|
return false;
|
|
|
|
|
void *pDib = GlobalLock(hDib);
|
|
|
|
|
if (!pDib)
|
|
|
|
|
{
|
|
|
|
|
GlobalFree(hDib);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
memcpy((char *)pDib, (char *)ptr + sizeof(BITMAPFILEHEADER), size);
|
|
|
|
|
if (tryopenclipboard(hwnd) == false)
|
|
|
|
|
return false;
|
|
|
|
|
EmptyClipboard();
|
|
|
|
|
if (!SetClipboardData(CF_DIB, hDib))
|
|
|
|
|
{
|
|
|
|
|
GlobalFree(hDib);
|
|
|
|
|
CloseClipboard();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
CloseClipboard();
|
|
|
|
|
return true;
|
|
|
|
|
}
|