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:
1 parent
e6b4fe3a85
commit
0c04f7516b
10 files changed
+290
-12
No files matched your search
@@ -8,6 +8,7 @@ import (
|
||||
"github.com/yuanyuanxiang/SimpleRemoter/server/go/hub"
|
||||
"github.com/yuanyuanxiang/SimpleRemoter/server/go/protocol"
|
||||
"github.com/yuanyuanxiang/SimpleRemoter/server/go/wsauth"
|
||||
"golang.org/x/text/encoding/simplifiedchinese"
|
||||
)
|
||||
|
||||
// rotateChallenge replaces the client's nonce with a fresh one and pushes a
|
||||
@@ -64,6 +65,10 @@ func (h *wsHub) dispatch(c *wsClient, cmd string, raw []byte) {
|
||||
h.handleMouse(c, raw)
|
||||
case "key":
|
||||
h.handleKey(c, raw)
|
||||
case "clipboard_set":
|
||||
h.handleClipboardSet(c, raw)
|
||||
case "clipboard_get":
|
||||
h.handleClipboardGet(c, raw)
|
||||
case "term_open":
|
||||
h.handleTermOpen(c, raw)
|
||||
case "term_input":
|
||||
@@ -559,6 +564,59 @@ func (h *wsHub) handleKey(c *wsClient, raw []byte) {
|
||||
_ = h.devices.SendToScreen(deviceID, pkt)
|
||||
}
|
||||
|
||||
// handleClipboardSet relays the browser's local clipboard text into the remote
|
||||
// device's clipboard via COMMAND_SCREEN_SET_CLIPBOARD (25). The client's
|
||||
// UpdateClientClipboard stores the payload as CF_TEXT (ANSI/GBK), so we encode
|
||||
// the UTF-8 input to GBK here — matching the C++ WebService (explicit code
|
||||
// page 936) and the existing MCP remote_clipboard convention. Non-GBK glyphs
|
||||
// (emoji, some accented Latin) collapse to '?' — an accepted limitation.
|
||||
func (h *wsHub) handleClipboardSet(c *wsClient, raw []byte) {
|
||||
if !h.requireAuth(c, raw, "clipboard_set_result") {
|
||||
return
|
||||
}
|
||||
var in struct {
|
||||
Text string `json:"text"`
|
||||
}
|
||||
if err := json.Unmarshal(raw, &in); err != nil {
|
||||
return
|
||||
}
|
||||
if in.Text == "" {
|
||||
return
|
||||
}
|
||||
deviceID := c.watching
|
||||
if deviceID == "" {
|
||||
return
|
||||
}
|
||||
gbk, err := simplifiedchinese.GBK.NewEncoder().Bytes([]byte(in.Text))
|
||||
if err != nil {
|
||||
h.log.Warn("clipboard_set: GBK encode failed: %v", err)
|
||||
return
|
||||
}
|
||||
payload := append([]byte{protocol.CommandScreenSetClipboard}, gbk...)
|
||||
if err := h.devices.SendToScreen(deviceID, payload); err != nil {
|
||||
h.log.Warn("clipboard_set: device=%s: %v", deviceID, err)
|
||||
return
|
||||
}
|
||||
h.log.Info("clipboard_set sent: device=%s len=%d", deviceID, len(gbk))
|
||||
}
|
||||
|
||||
// handleClipboardGet asks the remote device for its clipboard text via
|
||||
// COMMAND_SCREEN_GET_CLIPBOARD (24, a single byte). The device replies with
|
||||
// TOKEN_CLIPBOARD_TEXT, which the hub relays back to the browser.
|
||||
func (h *wsHub) handleClipboardGet(c *wsClient, raw []byte) {
|
||||
if !h.requireAuth(c, raw, "clipboard_get_result") {
|
||||
return
|
||||
}
|
||||
deviceID := c.watching
|
||||
if deviceID == "" {
|
||||
return
|
||||
}
|
||||
if err := h.devices.SendToScreen(deviceID, []byte{protocol.CommandScreenGetClipboard}); err != nil {
|
||||
h.log.Warn("clipboard_get: device=%s: %v", deviceID, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// handleCreateUser provisions a new web account. Admin-only. Mirrors the
|
||||
// C++ CWebService::HandleCreateUser semantics (WebService.cpp:1009): the
|
||||
// password is hashed with a fresh salt, the user table is persisted, and
|
||||
|
||||
Reference in new issue
Block a user