Feature: Web remote desktop cursor sync with remote host

This commit is contained in:
yuanyuanxiang
2026-04-27 12:12:23 +02:00
parent b98607d24d
commit 1cc66aff56
4 changed files with 79 additions and 2 deletions

View File

@@ -1232,6 +1232,18 @@ inline std::string GetWebPageHTML() {
updateScreenStatus('connected');
initDecoder(msg.width, msg.height);
break;
case 'cursor':
// Update remote cursor style (only for desktop in control mode)
currentCursorIndex = msg.index;
if (controlEnabled && !isTouchDevice) {
const canvas = document.getElementById('screen-canvas');
// 254=custom cursor (not supported in web), 255=unsupported -> default
const cssCursor = (msg.index >= 0 && msg.index < cursorMap.length)
? cursorMap[msg.index]
: 'default';
canvas.style.cursor = cssCursor;
}
break;
case 'device_offline':
// Only handle if this is the device we're currently viewing
if (!token) break;
@@ -1748,6 +1760,28 @@ inline std::string GetWebPageHTML() {
// Control mode state (mouse/keyboard control)
let controlEnabled = false;
// Remote cursor mapping (Windows cursor index -> CSS cursor)
// Index matches CursorInfo.h: IDC_APPSTARTING(0) to IDC_WAIT(15), 254=custom, 255=unsupported
const cursorMap = [
'progress', // 0: IDC_APPSTARTING
'default', // 1: IDC_ARROW
'crosshair', // 2: IDC_CROSS
'pointer', // 3: IDC_HAND
'help', // 4: IDC_HELP
'text', // 5: IDC_IBEAM
'default', // 6: IDC_ICON (no direct CSS equivalent)
'not-allowed', // 7: IDC_NO
'default', // 8: IDC_SIZE (deprecated, use default)
'move', // 9: IDC_SIZEALL
'nesw-resize', // 10: IDC_SIZENESW
'ns-resize', // 11: IDC_SIZENS
'nwse-resize', // 12: IDC_SIZENWSE
'ew-resize', // 13: IDC_SIZEWE
'default', // 14: IDC_UPARROW (no direct CSS equivalent)
'wait' // 15: IDC_WAIT
];
let currentCursorIndex = 1; // Default: arrow
// Floating toolbar state
let toolbarVisible = false;
let toolbarHideTimer = null;
@@ -1899,8 +1933,18 @@ inline std::string GetWebPageHTML() {
const canvas = document.getElementById('screen-canvas');
const cursorOverlay = document.getElementById('cursor-overlay');
// Touch devices: hide browser cursor, show overlay (touchpad mode)
// Desktop: keep browser cursor visible, no overlay needed (remote shows cursor)
canvas.style.cursor = (controlEnabled && isTouchDevice) ? 'none' : 'default';
// Desktop: use remote cursor style when control enabled
if (controlEnabled && isTouchDevice) {
canvas.style.cursor = 'none';
} else if (controlEnabled && !isTouchDevice) {
// Apply current remote cursor
const cssCursor = (currentCursorIndex >= 0 && currentCursorIndex < cursorMap.length)
? cursorMap[currentCursorIndex]
: 'default';
canvas.style.cursor = cssCursor;
} else {
canvas.style.cursor = 'default';
}
cursorOverlay.classList.toggle('active', controlEnabled && isTouchDevice);
}
@@ -2726,6 +2770,7 @@ inline std::string GetWebPageHTML() {
if (qcMouse) qcMouse.classList.remove('active');
document.getElementById('screen-canvas').style.cursor = 'default';
document.getElementById('cursor-overlay').classList.remove('active');
currentCursorIndex = 1; // Reset to default arrow
// Reset zoom state
zoomState.scale = 1;