diff options
author | Alexander E. Patrakov <patrakov@gmail.com> | 2018-08-12 03:17:16 +0800 |
---|---|---|
committer | Alexander E. Patrakov <patrakov@gmail.com> | 2018-09-14 20:31:59 +0500 |
commit | 4c38179d15ee5011a9144843fc655194409dd506 (patch) | |
tree | d08a3281e0c72623607ab76e652e2dbb389f2cf2 | |
parent | d1314d4b3a2dba261ba293ec90c0e3204042734b (diff) | |
download | novnc-4c38179d15ee5011a9144843fc655194409dd506.tar.gz |
Show dot when there is no visible cursor
Disabled by default.
-rw-r--r-- | app/ui.js | 9 | ||||
-rw-r--r-- | core/rfb.js | 75 | ||||
-rw-r--r-- | docs/API.md | 5 | ||||
-rw-r--r-- | docs/EMBEDDING.md | 3 | ||||
-rw-r--r-- | vnc.html | 4 |
5 files changed, 84 insertions, 12 deletions
@@ -161,6 +161,7 @@ const UI = { UI.initSetting('resize', 'off'); UI.initSetting('shared', true); UI.initSetting('view_only', false); + UI.initSetting('show_dot', false); UI.initSetting('path', 'websockify'); UI.initSetting('repeaterID', ''); UI.initSetting('reconnect', false); @@ -347,6 +348,8 @@ const UI = { UI.addSettingChangeHandler('shared'); UI.addSettingChangeHandler('view_only'); UI.addSettingChangeHandler('view_only', UI.updateViewOnly); + UI.addSettingChangeHandler('show_dot'); + UI.addSettingChangeHandler('show_dot', UI.updateShowDotCursor); UI.addSettingChangeHandler('host'); UI.addSettingChangeHandler('port'); UI.addSettingChangeHandler('path'); @@ -1015,6 +1018,7 @@ const UI = { UI.rfb = new RFB(document.getElementById('noVNC_container'), url, { shared: UI.getSetting('shared'), + showDotCursor: UI.getSetting('show_dot'), repeaterID: UI.getSetting('repeaterID'), credentials: { password: password } }); UI.rfb.addEventListener("connect", UI.connectFinished); @@ -1583,6 +1587,11 @@ const UI = { UI.setMouseButton(1); //has it's own logic for hiding/showing }, + updateShowDotCursor() { + if (!UI.rfb) return; + UI.rfb.showDotCursor = UI.getSetting('show_dot'); + }, + updateLogging() { WebUtil.init_logging(UI.getSetting('logging')); }, diff --git a/core/rfb.js b/core/rfb.js index 5d40cdd..9b59c89 100644 --- a/core/rfb.js +++ b/core/rfb.js @@ -48,6 +48,7 @@ export default class RFB extends EventTargetMixin { this._rfb_credentials = options.credentials || {}; this._shared = 'shared' in options ? !!options.shared : true; this._repeaterID = options.repeaterID || ''; + this._showDotCursor = options.showDotCursor || false; // Internal state this._rfb_connection_state = ''; @@ -168,13 +169,17 @@ export default class RFB extends EventTargetMixin { // Cursor this._cursor = new Cursor(); - this._cursorImage = { - rgbaPixels: [], - hotx: 0, - hoty: 0, - w: 0, - h: 0, - }; + + // XXX: TightVNC 2.8.11 sends no cursor at all until Windows changes + // it. Result: no cursor at all until a window border or an edit field + // is hit blindly. But there are also VNC servers that draw the cursor + // in the framebuffer and don't send the empty local cursor. There is + // no way to satisfy both sides. + // + // The spec is unclear on this "initial cursor" issue. Many other + // viewers (TigerVNC, RealVNC, Remmina) display an arrow as the + // initial cursor instead. + this._cursorImage = RFB.cursors.none; // populate encHandlers with bound versions this._encHandlers[encodings.encodingRaw] = RFB.encodingHandlers.RAW.bind(this); @@ -324,6 +329,12 @@ export default class RFB extends EventTargetMixin { } } + get showDotCursor() { return this._showDotCursor; } + set showDotCursor(show) { + this._showDotCursor = show; + this._refreshCursor(); + } + // ===== PUBLIC METHODS ===== disconnect() { @@ -426,6 +437,7 @@ export default class RFB extends EventTargetMixin { this._target.appendChild(this._screen); this._cursor.attach(this._canvas); + this._refreshCursor(); // Monitor size changes of the screen // FIXME: Use ResizeObserver, or hidden overflow @@ -1617,12 +1629,33 @@ export default class RFB extends EventTargetMixin { this._refreshCursor(); } + _shouldShowDotCursor() { + // Called when this._cursorImage is updated + if (!this._showDotCursor) { + // User does not want to see the dot, so... + return false; + } + + // The dot should not be shown if the cursor is already visible, + // i.e. contains at least one not-fully-transparent pixel. + // So iterate through all alpha bytes in rgba and stop at the + // first non-zero. + for (let i = 3; i < this._cursorImage.rgbaPixels.length; i += 4) { + if (this._cursorImage.rgbaPixels[i]) { + return false; + } + } + + // At this point, we know that the cursor is fully transparent, and + // the user wants to see the dot instead of this. + return true; + } + _refreshCursor() { - this._cursor.change(this._cursorImage.rgbaPixels, - this._cursorImage.hotx, - this._cursorImage.hoty, - this._cursorImage.w, - this._cursorImage.h + const image = this._shouldShowDotCursor() ? RFB.cursors.dot : this._cursorImage; + this._cursor.change(image.rgbaPixels, + image.hotx, image.hoty, + image.w, image.h ); } @@ -2598,3 +2631,21 @@ RFB.encodingHandlers = { } } } + +RFB.cursors = { + none: { + rgbaPixels: new Uint8Array(), + w: 0, h: 0, + hotx: 0, hoty: 0, + }, + + dot: { + rgbaPixels: new Uint8Array([ + 255, 255, 255, 255, 0, 0, 0, 255, 255, 255, 255, 255, + 0, 0, 0, 255, 0, 0, 0, 0, 0, 0, 0, 255, + 255, 255, 255, 255, 0, 0, 0, 255, 255, 255, 255, 255, + ]), + w: 3, h: 3, + hotx: 1, hoty: 1, + } +}; diff --git a/docs/API.md b/docs/API.md index a81da5c..ae7fb66 100644 --- a/docs/API.md +++ b/docs/API.md @@ -53,6 +53,11 @@ protocol stream. should be sent whenever the container changes dimensions. Disabled by default. +`showDotCursor` + - Is a `boolean` indicating whether a dot cursor should be shown + instead of a zero-sized or fully-transparent cursor if the server + sets such invisible cursor. Disabled by default. + `capabilities` *Read only* - Is an `Object` indicating which optional extensions are available on the server. Some methods may only be called if the corresponding diff --git a/docs/EMBEDDING.md b/docs/EMBEDDING.md index cad80ef..5399b48 100644 --- a/docs/EMBEDDING.md +++ b/docs/EMBEDDING.md @@ -61,6 +61,9 @@ query string. Currently the following options are available: * `resize` - How to resize the remote session if it is not the same size as the browser window. Can be one of `off`, `scale` and `remote`. +* `show_dot` - If a dot cursor should be shown when the remote server provides + no local cursor, or provides a fully-transparent (invisible) cursor. + * `logging` - The console log level. Can be one of `error`, `warn`, `info` or `debug`. @@ -250,6 +250,10 @@ <input id="noVNC_setting_reconnect_delay" type="number" /> </li> <li><hr></li> + <li> + <label><input id="noVNC_setting_show_dot" type="checkbox" /> Show Dot when No Cursor</label> + </li> + <li><hr></li> <!-- Logging selection dropdown --> <li> <label>Logging: |