Feature: Web remote desktop bidirectional text clipboard sync

Add keyboard-shortcut (Ctrl+C / Ctrl+X / Ctrl+V) text clipboard transfer
between the browser and the remote desktop, reusing the clipboard protocol
that already exists in the native viewer (COMMAND_SCREEN_GET_CLIPBOARD=24,
COMMAND_SCREEN_SET_CLIPBOARD=25, TOKEN_CLIPBOARD_TEXT=118) so the client
needs no change.

Local -> remote: pressing Ctrl+V reads the browser clipboard, pushes it to
the remote clipboard (UTF-8 -> GBK, matching the client's CF_TEXT/ANSI
handling) and then synthesizes a remote Ctrl+V so the pasted text is the
newly delivered one.

Remote -> local: Ctrl+C or Ctrl+X is forwarded to the remote as usual and,
after a short delay, the remote clipboard is pulled back and written to the
browser clipboard for a later local Ctrl+V.

Both the MFC and Go servers get the same three clipboard signaling paths
(clipboard_set, clipboard_get, clipboard_text) so the shared single-page
frontend behaves identically on either backend.

Co-Authored-By: deepseek-v4-pro
This commit is contained in:
yuanyuanxianganddeepseek-v4-pro committed 2026-10-17 19:52:38 +02:00
1 parent e6b4fe3a85
commit 0c04f7516b
10 files changed
+290 -12

No files matched your search

+11
View File
@@ -187,6 +187,9 @@ type EventHandler interface {
// Duplicates (same index as the previous frame) are filtered out by the
// hub before reaching subscribers.
OnCursorChange(deviceID string, index byte)
// OnClipboardText delivers the device's clipboard text (already UTF-8),
// captured in response to a browser "clipboard_get" request.
OnClipboardText(deviceID string, text string)
// OnTerminalReady fires once the device's shell sub-conn is bound and
// the server has sent COMMAND_NEXT to start its output read loop.
// isPTY=true means PTY mode (Linux/macOS or ConPTY); false means the
@@ -606,6 +609,14 @@ func (h *Hub) PublishScreenFrame(deviceID string, packet []byte, isKeyframe bool
}
}
// PublishClipboardText relays a device's clipboard text (UTF-8) to all
// subscribers, e.g. in response to a browser "clipboard_get" request.
func (h *Hub) PublishClipboardText(deviceID string, text string) {
for _, s := range h.snapshotSubscribers() {
s.OnClipboardText(deviceID, text)
}
}
// UpdateLive applies a heartbeat-derived RTT and active-window title to the
// device's live fields, then notifies subscribers. No-op if the device is
// not registered (e.g. heartbeat arriving for a connection that never sent
+2
View File
@@ -84,6 +84,8 @@ func (c *captureHandler) OnResolutionChange(_ string, _, _ int) {}
func (c *captureHandler) OnCursorChange(_ string, _ byte) {}
func (c *captureHandler) OnClipboardText(_ string, _ string) {}
func (c *captureHandler) OnTerminalReady(_ string, _ bool) {}
func (c *captureHandler) OnTerminalData(_ string, _ []byte) {}