mirror of
https://github.com/kunkundi/crossdesk.git
synced 2026-11-07 23:09:21 +08:00
[feat] add acknowledged remote clipboard read and write
This commit is contained in:
@@ -59,6 +59,7 @@ void ClipboardController::Shutdown() {
|
||||
pending_remote_text_.reset();
|
||||
pending_complete_ = {};
|
||||
pending_allowed_ = {};
|
||||
pending_reads_.clear();
|
||||
}
|
||||
|
||||
bool ClipboardController::WebSessionActive(
|
||||
@@ -107,7 +108,7 @@ void ClipboardController::ReceiveWeb(const char* data, size_t size,
|
||||
if (found == web_sessions_.end() || found->second->events.lock() != events) return;
|
||||
session = found->second;
|
||||
}
|
||||
if (!hello) {
|
||||
if (!hello && kind != clip::kRead && kind != clip::kClear) {
|
||||
if (!session->ready.load(std::memory_order_acquire) ||
|
||||
kind != clip::kText || !request) return;
|
||||
message = session->assembler.Receive(std::string_view(data, size));
|
||||
@@ -121,6 +122,23 @@ void ClipboardController::ReceiveWeb(const char* data, size_t size,
|
||||
session->ready.store(true, std::memory_order_release);
|
||||
return;
|
||||
}
|
||||
if ((kind == clip::kRead || kind == clip::kClear) &&
|
||||
(!session->ready.load(std::memory_order_acquire) || !request ||
|
||||
size != clip::kHeaderBytes)) return;
|
||||
if (kind == clip::kRead) {
|
||||
const auto send = [this, remote_id, session](const std::string& frame) {
|
||||
return WebSessionActive(remote_id, session) &&
|
||||
owner_.SendControllerData(remote_id, frame.data(), frame.size(), clip::kStream) == 0;
|
||||
};
|
||||
if (!QueueRead([send, request](std::optional<std::string> text) {
|
||||
if (!text) send(clip::Frame(clip::kRejected, request));
|
||||
else if (text->empty()) send(clip::Frame(clip::kEmpty, request));
|
||||
else if (!clip::SendText(*text, request, 16 * 1024, send))
|
||||
send(clip::Frame(clip::kRejected, request));
|
||||
})) send(clip::Frame(clip::kRejected, request));
|
||||
return;
|
||||
}
|
||||
if (kind == clip::kClear) message = clip::Frame(clip::kText, request);
|
||||
if (message.empty()) return;
|
||||
const std::weak_ptr<WebSession> weak = session;
|
||||
auto allowed = [this, remote_id, weak] {
|
||||
@@ -163,7 +181,7 @@ void ClipboardController::QueueRemoteText(const char* data, size_t size,
|
||||
if (!events_enabled_.load(std::memory_order_acquire)) {
|
||||
return;
|
||||
}
|
||||
if (!data || size == 0) {
|
||||
if (!data || (size == 0 && !complete)) {
|
||||
return;
|
||||
}
|
||||
if (size > kMaxClipboardTextBytes) {
|
||||
@@ -207,11 +225,37 @@ void ClipboardController::QueueRemoteText(const char* data, size_t size,
|
||||
}
|
||||
}
|
||||
|
||||
bool ClipboardController::QueueRead(std::function<void(std::optional<std::string>)> complete) {
|
||||
{
|
||||
std::lock_guard lock(pending_mutex_);
|
||||
if (!events_enabled_.load() || pending_reads_.size() >= 32) return false;
|
||||
pending_reads_.push_back(std::move(complete));
|
||||
}
|
||||
SDL_Event event{};
|
||||
event.type = event_type_;
|
||||
if (event_type_) SDL_PushEvent(&event);
|
||||
return true;
|
||||
}
|
||||
|
||||
void ClipboardController::ApplyPendingRemoteText() {
|
||||
if (!events_enabled_.load(std::memory_order_acquire)) {
|
||||
return;
|
||||
}
|
||||
ApplyPendingWrite();
|
||||
std::deque<std::function<void(std::optional<std::string>)>> reads;
|
||||
{
|
||||
std::lock_guard lock(pending_mutex_);
|
||||
reads.swap(pending_reads_);
|
||||
}
|
||||
if (!reads.empty()) {
|
||||
char* value = SDL_GetClipboardText();
|
||||
const std::optional<std::string> text = value ? std::optional<std::string>{value} : std::nullopt;
|
||||
SDL_free(value);
|
||||
for (auto& complete : reads) complete(text);
|
||||
}
|
||||
}
|
||||
|
||||
void ClipboardController::ApplyPendingWrite() {
|
||||
std::optional<std::string> pending_text;
|
||||
std::string source_id;
|
||||
std::weak_ptr<gui_detail::RemoteSession> source_session;
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <deque>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
@@ -42,6 +43,7 @@ public:
|
||||
std::function<void(bool)> complete = {},
|
||||
std::function<bool()> allowed = {});
|
||||
void ApplyPendingRemoteText();
|
||||
bool QueueRead(std::function<void(std::optional<std::string>)> complete);
|
||||
void HandleLocalUpdate();
|
||||
void ReceiveWeb(const char* data, size_t size, const std::string& remote_id,
|
||||
PeerEventHandler* source);
|
||||
@@ -49,6 +51,7 @@ public:
|
||||
|
||||
private:
|
||||
struct WebSession;
|
||||
void ApplyPendingWrite();
|
||||
bool WebSessionActive(const std::string& remote_id,
|
||||
const std::shared_ptr<WebSession>& session);
|
||||
int SendToController(const std::string& remote_id, const std::string& text);
|
||||
@@ -59,6 +62,7 @@ private:
|
||||
uint32_t event_type_ = 0;
|
||||
std::atomic<bool> events_enabled_{false};
|
||||
std::mutex pending_mutex_;
|
||||
std::deque<std::function<void(std::optional<std::string>)>> pending_reads_;
|
||||
std::optional<std::string> pending_remote_text_;
|
||||
std::string pending_remote_id_;
|
||||
std::weak_ptr<gui_detail::RemoteSession> pending_session_;
|
||||
|
||||
@@ -21,7 +21,7 @@ void GuiRuntime::HandleAutomation(const std::string& remote_id,
|
||||
try {
|
||||
const auto method = request.value("method", std::string{});
|
||||
if (method == "capabilities") {
|
||||
reply(true, {{"input_ack", true}});
|
||||
reply(true, {{"input_ack", true}, {"clipboard", true}});
|
||||
} else if (method == "input") {
|
||||
RemoteAction action{};
|
||||
if (!request.contains("arguments") ||
|
||||
|
||||
Reference in New Issue
Block a user