Improve web-side remote desktop control user experience
This commit is contained in:
@@ -649,6 +649,7 @@ inline std::string GetWebPageHTML() {
|
||||
</div>
|
||||
<div class="toolbar-right">
|
||||
<span id="screen-status" class="screen-status connecting">Connecting...</span>
|
||||
<button class="toolbar-btn-bar" id="btn-rdp-reset-bar" onclick="sendRdpReset()" title="RDP Reset">↻</button>
|
||||
<button class="toolbar-btn-bar" id="btn-mouse-bar" onclick="toggleControl()" title="Mouse Control">🖱</button>
|
||||
<button class="toolbar-btn-bar" id="btn-keyboard-bar" onclick="toggleKeyboard()" title="Keyboard" disabled>⌨</button>
|
||||
<button class="fullscreen-btn" onclick="toggleFullscreen()" title="Fullscreen (F11)">⛶</button>
|
||||
@@ -747,14 +748,35 @@ inline std::string GetWebPageHTML() {
|
||||
return viewMode === 'grid' ? 12 : 50;
|
||||
}
|
||||
|
||||
// Page visibility state for background detection (iOS PWA)
|
||||
let isPageVisible = !document.hidden;
|
||||
let reconnectTimer = null;
|
||||
|
||||
function scheduleReconnect() {
|
||||
if (reconnectTimer) return; // Already scheduled
|
||||
if (!isPageVisible) return; // Don't reconnect in background
|
||||
reconnectTimer = setTimeout(() => {
|
||||
reconnectTimer = null;
|
||||
if (isPageVisible) connectWebSocket();
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
function cancelReconnect() {
|
||||
if (reconnectTimer) {
|
||||
clearTimeout(reconnectTimer);
|
||||
reconnectTimer = null;
|
||||
}
|
||||
}
|
||||
|
||||
function connectWebSocket() {
|
||||
if (!isPageVisible) return; // Don't connect in background
|
||||
const protocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
|
||||
updateWsStatus('connecting');
|
||||
try {
|
||||
ws = new WebSocket(protocol + '//' + location.host + '/ws');
|
||||
} catch (e) {
|
||||
updateWsStatus('disconnected');
|
||||
setTimeout(connectWebSocket, 3000);
|
||||
scheduleReconnect();
|
||||
return;
|
||||
}
|
||||
ws.binaryType = 'arraybuffer';
|
||||
@@ -767,7 +789,7 @@ inline std::string GetWebPageHTML() {
|
||||
getDevices();
|
||||
}
|
||||
};
|
||||
ws.onclose = () => { stopPingInterval(); updateWsStatus('disconnected'); setTimeout(connectWebSocket, 3000); };
|
||||
ws.onclose = () => { stopPingInterval(); updateWsStatus('disconnected'); scheduleReconnect(); };
|
||||
ws.onerror = (e) => console.error('WS error:', e);
|
||||
ws.onmessage = (event) => {
|
||||
if (typeof event.data === 'string') handleSignaling(JSON.parse(event.data));
|
||||
@@ -1631,6 +1653,10 @@ inline std::string GetWebPageHTML() {
|
||||
showZoomIndicator();
|
||||
}
|
||||
applyZoomTransform();
|
||||
// Update cursor overlay to follow canvas transform
|
||||
if (cursorState.initialized) {
|
||||
updateCursorOverlay(cursorState.x, cursorState.y);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1715,10 +1741,14 @@ inline std::string GetWebPageHTML() {
|
||||
if (zoomState.isPinching) {
|
||||
if (e.touches.length < 2) {
|
||||
zoomState.isPinching = false;
|
||||
// Update pan center for smooth transition to pan mode
|
||||
// Update pan center and lastX/lastY for smooth transition
|
||||
if (e.touches.length === 1) {
|
||||
zoomState.pinchCenterX = e.touches[0].clientX;
|
||||
zoomState.pinchCenterY = e.touches[0].clientY;
|
||||
const touch = e.touches[0];
|
||||
zoomState.pinchCenterX = touch.clientX;
|
||||
zoomState.pinchCenterY = touch.clientY;
|
||||
// Reset lastX/lastY to prevent delta jump on next move
|
||||
touchState.lastX = touch.clientX;
|
||||
touchState.lastY = touch.clientY;
|
||||
}
|
||||
}
|
||||
touchState.touchCount = e.touches.length;
|
||||
@@ -1930,6 +1960,27 @@ inline std::string GetWebPageHTML() {
|
||||
if (e.key === 'Enter' && document.querySelector('.page.active').id === 'login-page') login();
|
||||
});
|
||||
|
||||
// Handle page visibility change (iOS PWA background/foreground)
|
||||
document.addEventListener('visibilitychange', () => {
|
||||
isPageVisible = !document.hidden;
|
||||
if (document.hidden) {
|
||||
// Page going to background - close connection and cancel reconnect
|
||||
cancelReconnect();
|
||||
stopPingInterval();
|
||||
if (ws) {
|
||||
ws.onclose = null; // Prevent triggering reconnect
|
||||
ws.close();
|
||||
ws = null;
|
||||
}
|
||||
updateWsStatus('disconnected');
|
||||
} else {
|
||||
// Page coming to foreground - reconnect
|
||||
if (!ws || ws.readyState !== WebSocket.OPEN) {
|
||||
connectWebSocket();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
window.onload = function() {
|
||||
const compat = checkWebCodecs();
|
||||
if (!compat.supported) {
|
||||
|
||||
Reference in New Issue
Block a user