diff --git a/app/ui.js b/app/ui.js index 2542e0591..2fee29e2b 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 }, @@ -1759,6 +1767,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 80011e4a1..997592ba3 100644 --- a/core/rfb.js +++ b/core/rfb.js @@ -290,16 +290,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; @@ -342,6 +344,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; @@ -370,6 +378,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; } @@ -1111,11 +1131,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}; @@ -1334,7 +1359,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}; @@ -1344,7 +1369,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. @@ -1376,7 +1401,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; @@ -1451,7 +1476,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); @@ -1465,7 +1490,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 @@ -3032,7 +3057,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; } @@ -3062,6 +3087,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 6d689e7d5..193372daa 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 82cacd580..42585a714 100644 --- a/vnc.html +++ b/vnc.html @@ -296,6 +296,20 @@