Add Windows clipboard support

This commit is contained in:
Yukino Song
2024-09-28 03:31:50 +08:00
parent c72fb4544e
commit 1ae7157bba
9 changed files with 304 additions and 22 deletions

View File

@@ -35,6 +35,7 @@
#include <Shlwapi.h>
#include "misc.h"
#include "utils.h"
#include "src/entry_handler.h"
#include "src/globals.h"
@@ -95,6 +96,10 @@ namespace {
namespace bp = boost::process;
static std::string ensureCrLf(const std::string& utf8Str);
static std::wstring getClipboardData();
static int setClipboardData(const std::string& acpStr);
using namespace std::literals;
namespace platf {
using adapteraddrs_t = util::c_ptr<IP_ADAPTER_ADDRESSES>;
@@ -1941,4 +1946,103 @@ namespace platf {
create_high_precision_timer() {
return std::make_unique<win32_high_precision_timer>();
}
std::string
get_clipboard() {
std::string currentClipboard = to_utf8(getClipboardData());
return currentClipboard;
}
bool
set_clipboard(const std::string& content) {
std::string cpContent = convertUtf8ToCurrentCodepage(ensureCrLf(content));
return !setClipboardData(cpContent);
}
} // namespace platf
static std::string ensureCrLf(const std::string& utf8Str) {
std::string result;
result.reserve(utf8Str.size() + utf8Str.length() / 2); // Reserve extra space
for (size_t i = 0; i < utf8Str.size(); ++i) {
if (utf8Str[i] == '\n' && (i == 0 || utf8Str[i - 1] != '\r')) {
result += '\r'; // Add \r before \n if not present
}
result += utf8Str[i]; // Always add the current character
}
return result;
}
static std::wstring getClipboardData() {
if (!OpenClipboard(nullptr)) {
BOOST_LOG(warning) << "Failed to open clipboard.";
return L"";
}
HANDLE hData = GetClipboardData(CF_UNICODETEXT);
if (hData == nullptr) {
BOOST_LOG(warning) << "No text data in clipboard or failed to get data.";
CloseClipboard();
return L"";
}
wchar_t* pszText = static_cast<wchar_t*>(GlobalLock(hData));
if (pszText == nullptr) {
BOOST_LOG(warning) << "Failed to lock clipboard data.";
CloseClipboard();
return L"";
}
std::wstring ret = pszText;
GlobalUnlock(hData);
CloseClipboard();
return ret;
}
static int setClipboardData(const std::string& acpStr) {
if (!OpenClipboard(nullptr)) {
BOOST_LOG(warning) << "Failed to open clipboard.";
return 1;
}
if (!EmptyClipboard()) {
BOOST_LOG(warning) << "Failed to empty clipboard.";
CloseClipboard();
return 1;
}
// Allocate global memory for the clipboard text
HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, acpStr.size() + 1);
if (hGlobal == nullptr) {
BOOST_LOG(warning) << "Failed to allocate global memory.";
CloseClipboard();
return 1;
}
// Lock the global memory and copy the text
char* pGlobal = static_cast<char*>(GlobalLock(hGlobal));
if (pGlobal == nullptr) {
BOOST_LOG(warning) << "Failed to lock global memory.";
GlobalFree(hGlobal);
CloseClipboard();
return 1;
}
memcpy(pGlobal, acpStr.c_str(), acpStr.size() + 1);
GlobalUnlock(hGlobal);
// Set the clipboard data
if (SetClipboardData(CF_TEXT, hGlobal) == nullptr) {
BOOST_LOG(warning) << "Failed to set clipboard data.";
GlobalFree(hGlobal);
CloseClipboard();
return 1;
}
CloseClipboard();
return 0;
}

View File

@@ -1,28 +1,65 @@
#include "utils.h"
std::wstring acpToUtf16(const std::string& origStr) {
auto acp = GetACP();
int utf16Len = MultiByteToWideChar(acp, 0, origStr.c_str(), origStr.size(), NULL, 0);
if (utf16Len == 0) {
return L"";
}
std::wstring utf16Str(utf16Len, L'\0');
MultiByteToWideChar(acp, 0, origStr.c_str(), origStr.size(), &utf16Str[0], utf16Len);
return utf16Str;
}
std::string utf16toAcp(const std::wstring& utf16Str) {
auto acp = GetACP();
int codepageLen = WideCharToMultiByte(acp, 0, utf16Str.c_str(), utf16Str.size(), NULL, 0, NULL, NULL);
if (codepageLen == 0) {
return "";
}
std::string codepageStr(codepageLen, '\0');
WideCharToMultiByte(acp, 0, utf16Str.c_str(), utf16Str.size(), &codepageStr[0], codepageLen, NULL, NULL);
return codepageStr;
}
std::string convertUtf8ToCurrentCodepage(const std::string& utf8Str) {
if (GetACP() == CP_UTF8) {
return std::string(utf8Str);
}
// Step 1: Convert UTF-8 to UTF-16
int utf16Len = MultiByteToWideChar(CP_UTF8, 0, utf8Str.c_str(), -1, NULL, 0);
int utf16Len = MultiByteToWideChar(CP_UTF8, 0, utf8Str.c_str(), utf8Str.size(), NULL, 0);
if (utf16Len == 0) {
return std::string(utf8Str);
}
std::wstring utf16Str(utf16Len, L'\0');
MultiByteToWideChar(CP_UTF8, 0, utf8Str.c_str(), -1, &utf16Str[0], utf16Len);
MultiByteToWideChar(CP_UTF8, 0, utf8Str.c_str(), utf8Str.size(), &utf16Str[0], utf16Len);
// Step 2: Convert UTF-16 to the current Windows codepage
int codepageLen = WideCharToMultiByte(GetACP(), 0, utf16Str.c_str(), -1, NULL, 0, NULL, NULL);
if (codepageLen == 0) {
return std::string(utf8Str);
return utf16toAcp(utf16Str);
}
std::string convertCurrentCodepageToUtf8(const std::string& origStr) {
if (GetACP() == CP_UTF8) {
return std::string(origStr);
}
std::string codepageStr(codepageLen, '\0');
WideCharToMultiByte(GetACP(), 0, utf16Str.c_str(), -1, &codepageStr[0], codepageLen, NULL, NULL);
auto utf16Str = acpToUtf16(origStr);
return codepageStr;
int utf8Len = WideCharToMultiByte(CP_UTF8, 0, utf16Str.c_str(), utf16Str.size(), NULL, 0, NULL, NULL);
if (utf8Len == 0) {
return std::string(origStr);
}
std::string utf8Str(utf8Len, '\0');
WideCharToMultiByte(CP_UTF8, 0, utf16Str.c_str(), utf16Str.size(), &utf8Str[0], utf8Len, NULL, NULL);
return utf8Str;
}
// Modified from https://github.com/FrogTheFrog/Sunshine/blob/b6f8573d35eff7c55da6965dfa317dc9722bd4ef/src/platform/windows/display_device/windows_utils.cpp

View File

@@ -9,7 +9,10 @@
#include "src/utility.h"
#include "src/logging.h"
std::wstring acpToUtf16(const std::string& origStr);
std::string utf16toAcp(const std::wstring& utf16Str);
std::string convertUtf8ToCurrentCodepage(const std::string& utf8Str);
std::string convertCurrentCodepageToUtf8(const std::string& currentStr);
std::string get_error_string(LONG error_code);