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
@@ -1365,6 +1365,7 @@
|
||||
<script>
|
||||
let ws = null, token = null, decoder = null, devices = [], currentDevice = null;
|
||||
let frameCount = 0, lastFrameTime = 0, fps = 0, pingInterval = null;
|
||||
let skipNextCtrlVKeyup = false; // 剪贴板桥:抑制 pasteToRemote 合成的 Ctrl+V 物理 keyup
|
||||
// FPS 计数:原始风格——decoder.onOutput 里 ++,每经过 1 秒采样一次。
|
||||
// 简单直接,与本次会话改动前一致。
|
||||
// 网络流量统计:handleBinaryFrame 累加,每 1 秒钟 renderStats 读出
|
||||
@@ -1863,6 +1864,12 @@
|
||||
applyRemoteCursor(msg.index);
|
||||
}
|
||||
break;
|
||||
case 'clipboard_text':
|
||||
// 远程剪贴板文本回传:写回浏览器(即本机)剪贴板
|
||||
if (msg.text) {
|
||||
try { navigator.clipboard.writeText(msg.text); } catch (e) {}
|
||||
}
|
||||
break;
|
||||
case 'device_offline':
|
||||
// Only handle if this is the device we're currently viewing
|
||||
if (!token) break;
|
||||
@@ -3714,6 +3721,28 @@
|
||||
}
|
||||
}
|
||||
|
||||
// 本地剪贴板 → 远程:读浏览器剪贴板,先 clipboard_set 到远程,再合成一次完整 Ctrl+V。
|
||||
// 合成按键放在 readText 的 then 里,保证 clipboard_set 先于 Ctrl+V 到达(同一条 WS 有序)。
|
||||
function pasteToRemote() {
|
||||
const press = () => { sendKey(86, true, false); sendKey(86, false, false); };
|
||||
navigator.clipboard.readText().then(function(text) {
|
||||
if (text && ws && ws.readyState === WebSocket.OPEN && token) {
|
||||
ws.send(JSON.stringify({ cmd: 'clipboard_set', token, text }));
|
||||
}
|
||||
press();
|
||||
}).catch(function() { press(); }); // 读剪贴板被拒/为空:仍执行一次普通远程粘贴
|
||||
}
|
||||
|
||||
// 远程剪贴板 → 本地:等远程完成拷贝(启发式延时)后请求远程剪贴板,回包写回浏览器剪贴板。
|
||||
// 不保证 100% 命中,失败用户二次 Ctrl+C 即可。
|
||||
function scheduleCopyFromRemote() {
|
||||
setTimeout(function() {
|
||||
if (ws && ws.readyState === WebSocket.OPEN && token) {
|
||||
ws.send(JSON.stringify({ cmd: 'clipboard_get', token }));
|
||||
}
|
||||
}, 250);
|
||||
}
|
||||
|
||||
function showTouchIndicator(x, y) {
|
||||
touchIndicator.style.left = x + 'px';
|
||||
touchIndicator.style.top = y + 'px';
|
||||
@@ -4198,14 +4227,38 @@
|
||||
// controlling the remote — see the F11 handler above. Skip here
|
||||
// to let that one handle it.
|
||||
if (e.key === 'F11' && !controlEnabled) return;
|
||||
|
||||
// 文本剪贴板桥(secure context 下 navigator.clipboard 可用)。
|
||||
// Ctrl/Cmd+V:把本地剪贴板文本先灌到远程剪贴板,再合成一次 Ctrl+V 粘贴。
|
||||
// Ctrl/Cmd+C / Ctrl/Cmd+X:照常转发给远程(远程完成拷贝/剪切),随后延迟拉取远程剪贴板回本地。
|
||||
if (controlEnabled && (e.ctrlKey || e.metaKey) && !e.shiftKey && !e.altKey) {
|
||||
if (e.keyCode === 86) { // Ctrl/Cmd+V
|
||||
e.preventDefault();
|
||||
skipNextCtrlVKeyup = true;
|
||||
pasteToRemote();
|
||||
return;
|
||||
}
|
||||
// e.keyCode === 67(C)/88(X) 时落到下面的 sendKey 原样转发,转发后再延迟拉取
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
sendKey(e.keyCode, true, e.altKey);
|
||||
|
||||
if (controlEnabled && (e.ctrlKey || e.metaKey) && !e.shiftKey && !e.altKey && (e.keyCode === 67 || e.keyCode === 88)) {
|
||||
scheduleCopyFromRemote();
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener('keyup', function(e) {
|
||||
if (!document.getElementById('screen-page').classList.contains('active')) return;
|
||||
if (e.target.tagName === 'INPUT') return;
|
||||
if (e.key === 'F11' && !controlEnabled) return;
|
||||
// 由 pasteToRemote 合成的完整 Ctrl+V 按下:物理 keyup 不再转发,避免 down/up 乱序
|
||||
if (e.keyCode === 86 && skipNextCtrlVKeyup) {
|
||||
skipNextCtrlVKeyup = false;
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
sendKey(e.keyCode, false, e.altKey);
|
||||
});
|
||||
|
||||
Reference in new issue
Block a user