diff --git a/app/ui.js b/app/ui.js index bbdea60d..e8f914ed 100644 --- a/app/ui.js +++ b/app/ui.js @@ -185,6 +185,8 @@ const UI = { UI.initSetting('bell', 'on'); UI.initSetting('view_only', false); UI.initSetting('show_dot', false); + UI.initSetting('show_local_cursor', false); + UI.initSetting('show_drag_cursor', false); UI.initSetting('path', 'websockify'); UI.initSetting('repeaterID', ''); UI.initSetting('reconnect', false); @@ -371,6 +373,10 @@ const UI = { UI.addSettingChangeHandler('view_only', UI.updateViewOnly); UI.addSettingChangeHandler('show_dot'); UI.addSettingChangeHandler('show_dot', UI.updateShowDotCursor); + UI.addSettingChangeHandler('show_local_cursor'); + UI.addSettingChangeHandler('show_local_cursor', UI.updateShowLocalCursor); + UI.addSettingChangeHandler('show_drag_cursor'); + UI.addSettingChangeHandler('show_drag_cursor', UI.updateShowDragCursor); UI.addSettingChangeHandler('host'); UI.addSettingChangeHandler('port'); UI.addSettingChangeHandler('path'); @@ -1101,6 +1107,8 @@ const UI = { UI.rfb.qualityLevel = parseInt(UI.getSetting('quality')); UI.rfb.compressionLevel = parseInt(UI.getSetting('compression')); UI.rfb.showDotCursor = UI.getSetting('show_dot'); + UI.rfb.showLocalCursor = UI.getSetting('show_local_cursor'); + UI.rfb.showDragCursor = UI.getSetting('show_drag_cursor'); UI.updateViewOnly(); // requires UI.rfb UI.updateClipboard(); @@ -1809,6 +1817,16 @@ const UI = { UI.rfb.showDotCursor = UI.getSetting('show_dot'); }, + updateShowLocalCursor() { + if (!UI.rfb) return; + UI.rfb.showLocalCursor = UI.getSetting('show_local_cursor'); + }, + + updateShowDragCursor() { + if (!UI.rfb) return; + UI.rfb.showDragCursor = UI.getSetting('show_drag_cursor'); + }, + updateLogging() { WebUtil.initLogging(UI.getSetting('logging')); }, diff --git a/core/rfb.js b/core/rfb.js index 1073a878..36e2e450 100644 --- a/core/rfb.js +++ b/core/rfb.js @@ -295,16 +295,18 @@ export default class RFB extends EventTargetMixin { // ===== PROPERTIES ===== - this.dragViewport = false; this.focusOnClick = true; this._viewOnly = false; this._clipViewport = false; this._clippingViewport = false; + this._dragViewport = false; this._scaleViewport = false; this._resizeSession = false; this._showDotCursor = false; + this._showLocalCursor = false; + this._showDragCursor = false; this._qualityLevel = 6; this._compressionLevel = 2; @@ -349,6 +351,12 @@ export default class RFB extends EventTargetMixin { this._updateClip(); } + get dragViewport() { return this._dragViewport; } + set dragViewport(dragViewport) { + this._dragViewport = dragViewport; + this._refreshCursor(); + } + get scaleViewport() { return this._scaleViewport; } set scaleViewport(scale) { this._scaleViewport = scale; @@ -377,6 +385,18 @@ export default class RFB extends EventTargetMixin { this._refreshCursor(); } + get showLocalCursor() { return this._showLocalCursor; } + set showLocalCursor(show) { + this._showLocalCursor = show; + this._refreshCursor(); + } + + get showDragCursor() { return this._showDragCursor; } + set showDragCursor(show) { + this._showDragCursor = show; + this._refreshCursor(); + } + get background() { return this._screen.style.background; } set background(cssValue) { this._screen.style.background = cssValue; } @@ -1118,11 +1138,16 @@ export default class RFB extends EventTargetMixin { let bmask = RFB._convertButtonMask(ev.buttons); - let down = ev.type == 'mousedown'; + let down = false; switch (ev.type) { case 'mousedown': + down = true; + // eslint-disable-next-line no-fallthrough case 'mouseup': if (this.dragViewport) { + if (this._showDragCursor) { + this._cursor.setLocalCursor(down ? 'grabbing' : 'grab'); + } if (down && !this._viewportDragging) { this._viewportDragging = true; this._viewportDragPos = {'x': pos.x, 'y': pos.y}; @@ -1341,7 +1366,7 @@ export default class RFB extends EventTargetMixin { this._handleTapEvent(ev, 0x2); break; case 'drag': - if (this.dragViewport) { + if (this._dragViewport) { this._viewportHasMoved = false; this._viewportDragging = true; this._viewportDragPos = {'x': pos.x, 'y': pos.y}; @@ -1351,7 +1376,7 @@ export default class RFB extends EventTargetMixin { } break; case 'longpress': - if (this.dragViewport) { + if (this._dragViewport) { // If dragViewport is true, we need to wait to see // if we have dragged outside the threshold before // sending any events to the server. @@ -1383,7 +1408,7 @@ export default class RFB extends EventTargetMixin { break; case 'drag': case 'longpress': - if (this.dragViewport) { + if (this._dragViewport) { this._viewportDragging = true; const deltaX = this._viewportDragPos.x - pos.x; const deltaY = this._viewportDragPos.y - pos.y; @@ -1458,7 +1483,7 @@ export default class RFB extends EventTargetMixin { case 'twodrag': break; case 'drag': - if (this.dragViewport) { + if (this._dragViewport) { this._viewportDragging = false; } else { this._fakeMouseMove(ev, pos.x, pos.y); @@ -1472,7 +1497,7 @@ export default class RFB extends EventTargetMixin { break; } - if (this.dragViewport && !this._viewportHasMoved) { + if (this._dragViewport && !this._viewportHasMoved) { this._fakeMouseMove(ev, pos.x, pos.y); // If dragViewport is true, we need to wait to see // if we have dragged outside the threshold before @@ -3047,7 +3072,7 @@ export default class RFB extends EventTargetMixin { _shouldShowDotCursor() { // Called when this._cursorImage is updated - if (!this._showDotCursor) { + if (!this._showDotCursor || (this._dragViewport && this._showDragCursor)) { // User does not want to see the dot, so... return false; } @@ -3077,6 +3102,13 @@ export default class RFB extends EventTargetMixin { image.hotx, image.hoty, image.w, image.h ); + if (this._dragViewport && this._showDragCursor) { + this._cursor.setLocalCursor(this._viewportDragging ? 'grabbing' : 'grab'); + } else if (this._showLocalCursor) { + this._cursor.setLocalCursor('default'); + } else { + this._cursor.setLocalCursor('none'); + } } static genDES(password, challenge) { diff --git a/core/util/cursor.js b/core/util/cursor.js index 6d689e7d..193372da 100644 --- a/core/util/cursor.js +++ b/core/util/cursor.js @@ -106,7 +106,7 @@ export default class Cursor { } clear() { - this._target.style.cursor = 'none'; + this.setLocalCursor('none'); this._canvas.width = 0; this._canvas.height = 0; this._position.x = this._position.x + this._hotSpot.x; @@ -115,6 +115,10 @@ export default class Cursor { this._hotSpot.y = 0; } + setLocalCursor(cursor) { + this._target.style.cursor = cursor; + } + // Mouse events might be emulated, this allows // moving the cursor in such cases move(clientX, clientY) { diff --git a/vnc.html b/vnc.html index 82cacd58..42585a71 100644 --- a/vnc.html +++ b/vnc.html @@ -296,6 +296,20 @@ Show dot when no cursor +
  • + +
  • +
  • + +

  • diff --git a/vnc_lite.html b/vnc_lite.html index 79d48146..e4a0cb39 100644 --- a/vnc_lite.html +++ b/vnc_lite.html @@ -165,6 +165,7 @@ // Set parameters that can be changed on an active connection rfb.viewOnly = readQueryVariable('view_only', false); rfb.scaleViewport = readQueryVariable('scale', false); + rfb.showLocalCursor = readQueryVariable('show_local_cursor', 0);