Files
XCDesktop/remote/public/index.html
2026-03-08 01:34:54 +08:00

151 lines
5.9 KiB
HTML

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>xc-remote</title>
<link rel="stylesheet" href="css/main.css">
</head>
<body>
<canvas id="video-canvas"></canvas>
<button id="file-transfer-btn">📁 文件传输</button>
<script src="js/jsmpeg.min.js"></script>
<script src="js/utils.js"></script>
<script src="js/player.js"></script>
<script src="js/input.js"></script>
<script src="js/file-panel.js"></script>
<script src="js/app.js"></script>
<script>
(function() {
const wsProtocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
const wsHost = window.location.hostname;
const wsPort = window.location.port;
const wsUrlBase = wsPort ? `${wsProtocol}//${wsHost}:${wsPort}/ws` : `${wsProtocol}//${wsHost}/ws`;
const password = getCookie('auth') || '';
const WS_URL = password ? `${wsUrlBase}?password=${encodeURIComponent(password)}` : wsUrlBase;
let clipboardWs = null;
let isClipboardSyncing = false;
function connectClipboardWs() {
if (clipboardWs && clipboardWs.readyState === WebSocket.OPEN) {
return clipboardWs;
}
clipboardWs = new WebSocket(WS_URL);
clipboardWs.onmessage = async (e) => {
if (e.data instanceof Blob) return;
try {
const msg = JSON.parse(e.data);
if (msg.type === 'clipboardData') {
if (msg.contentType === 'text' && msg.data) {
try {
await navigator.clipboard.writeText(msg.data);
console.log('Clipboard synced from remote');
} catch (err) {
console.error('Failed to write local clipboard:', err);
}
}
} else if (msg.type === 'clipboardTooLarge') {
console.warn('Remote clipboard content too large:', msg.size);
}
} catch (err) {}
};
clipboardWs.onopen = () => console.log('Clipboard sync ready');
clipboardWs.onclose = () => { clipboardWs = null; };
clipboardWs.onerror = () => { clipboardWs = null; };
return clipboardWs;
}
async function syncFromRemote() {
if (isClipboardSyncing) return;
isClipboardSyncing = true;
try {
const ws = connectClipboardWs();
const sendRequest = () => {
ws.send(JSON.stringify({ type: 'clipboardGet' }));
};
if (ws.readyState === WebSocket.OPEN) {
sendRequest();
} else {
ws.onopen = sendRequest;
}
} finally {
setTimeout(() => { isClipboardSyncing = false; }, 500);
}
}
async function syncToRemote() {
if (isClipboardSyncing) return;
isClipboardSyncing = true;
try {
let text = '';
try {
text = await navigator.clipboard.readText();
} catch (err) {
console.warn('Cannot read local clipboard');
return;
}
if (!text) return;
const ws = connectClipboardWs();
const sendRequest = () => {
ws.send(JSON.stringify({
type: 'clipboardSet',
contentType: 'text',
data: text
}));
console.log('Clipboard synced to remote');
};
if (ws.readyState === WebSocket.OPEN) {
sendRequest();
} else {
ws.onopen = sendRequest;
}
} finally {
setTimeout(() => { isClipboardSyncing = false; }, 500);
}
}
document.addEventListener('keydown', async (e) => {
if (e.ctrlKey && e.key === 'c' && !e.shiftKey && !e.altKey) {
if (document.activeElement.tagName === 'INPUT' ||
document.activeElement.tagName === 'TEXTAREA') {
return;
}
e.preventDefault();
await syncFromRemote();
}
if (e.ctrlKey && e.key === 'v' && !e.shiftKey && !e.altKey) {
if (document.activeElement.tagName === 'INPUT' ||
document.activeElement.tagName === 'TEXTAREA') {
return;
}
e.preventDefault();
await syncToRemote();
}
});
connectClipboardWs();
const filePanel = new FilePanel();
document.getElementById('file-transfer-btn').addEventListener('click', () => {
filePanel.toggle();
});
})();
</script>
</body>
</html>