From 8d8251ddcb9e70d1b0282d0e4e37b9473f03db35 Mon Sep 17 00:00:00 2001 From: DomenGaber Date: Tue, 4 Feb 2020 15:39:06 +0100 Subject: [PATCH 1/6] Track mouse position on device screen --- app/styles/base.css | 15 +++++++++++++++ app/ui.js | 13 +++++++++++++ core/rfb.js | 2 ++ vnc.html | 4 ++++ 4 files changed, 34 insertions(+) diff --git a/app/styles/base.css b/app/styles/base.css index 9db83bf6..320df9f0 100644 --- a/app/styles/base.css +++ b/app/styles/base.css @@ -866,6 +866,21 @@ select:active { ime-mode: disabled; } +#noVNC_mouse_coordinates { + position: fixed; + top: 0; + right: 0; + padding: 20px; + min-width: 150px; + font-size: 20px; + font-weight: 600; + text-align: center; + background-color: #fff; + border: 2px solid #E0E0E0; + border-radius: 0 0 0 5px; + box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5); +} + /*Default noVNC logo.*/ /* From: http://fonts.googleapis.com/css?family=Orbitron:700 */ @font-face { diff --git a/app/ui.js b/app/ui.js index 9c5e922f..b4e588db 100644 --- a/app/ui.js +++ b/app/ui.js @@ -707,6 +707,17 @@ const UI = { } }, + trackMouse() { + UI.rfb.canvas.addEventListener('mousemove', function(e) { + let scaleRatioX = UI.rfb.canvas.width / UI.rfb.canvas.clientWidth; + let scaleRatioY = UI.rfb.canvas.height / UI.rfb.canvas.clientHeight; + let x = Math.floor(e.offsetX * scaleRatioX); + let y = Math.floor(e.offsetY * scaleRatioY); + document.getElementById('noVNC_mouse_coordinates').innerText = "(" + x + ", " + y + ")" + }); + }, + + /* ------^------- * /VISUAL * ============== @@ -1036,6 +1047,8 @@ const UI = { UI.rfb.resizeSession = UI.getSetting('resize') === 'remote'; UI.rfb.showDotCursor = UI.getSetting('show_dot'); + UI.trackMouse(); + UI.updateViewOnly(); // requires UI.rfb }, diff --git a/core/rfb.js b/core/rfb.js index 49a16bb6..82ed141d 100644 --- a/core/rfb.js +++ b/core/rfb.js @@ -271,6 +271,8 @@ export default class RFB extends EventTargetMixin { } } + get canvas() { return this._canvas; } + get capabilities() { return this._capabilities; } get touchButton() { return this._mouse.touchButton; } diff --git a/vnc.html b/vnc.html index d1e6c683..96746f8b 100644 --- a/vnc.html +++ b/vnc.html @@ -332,5 +332,9 @@ + +
+ (0, 0) +
From c82f683881cafdf3c3d12bb5830db7fab0fdf409 Mon Sep 17 00:00:00 2001 From: DomenGaber Date: Wed, 5 Feb 2020 09:56:16 +0100 Subject: [PATCH 2/6] Add event stack to the UI --- app/styles/base.css | 12 ++++++++++++ app/ui.js | 25 ++++++++++++++++++++++++- vnc.html | 3 +++ 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/app/styles/base.css b/app/styles/base.css index 320df9f0..dc8fe2a7 100644 --- a/app/styles/base.css +++ b/app/styles/base.css @@ -881,6 +881,18 @@ select:active { box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5); } +#noVNC_click_stack { + position: fixed; + bottom: 0; + right: 0; + width: 250px; + height: 250px; + overflow: scroll; + background-color: #fff; + border-radius: 5px 0 0 0; + box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5); +} + /*Default noVNC logo.*/ /* From: http://fonts.googleapis.com/css?family=Orbitron:700 */ @font-face { diff --git a/app/ui.js b/app/ui.js index b4e588db..4cac0341 100644 --- a/app/ui.js +++ b/app/ui.js @@ -37,6 +37,8 @@ const UI = { lastKeyboardinput: null, defaultKeyboardinputLen: 100, + canvasInteractionEvents: Array(), + inhibit_reconnect: true, reconnect_callback: null, reconnect_password: null, @@ -713,10 +715,30 @@ const UI = { let scaleRatioY = UI.rfb.canvas.height / UI.rfb.canvas.clientHeight; let x = Math.floor(e.offsetX * scaleRatioX); let y = Math.floor(e.offsetY * scaleRatioY); - document.getElementById('noVNC_mouse_coordinates').innerText = "(" + x + ", " + y + ")" + document.getElementById('noVNC_mouse_coordinates').innerHTML = "(" + x + ", " + y + ")" }); }, + trackClicks() { + UI.rfb.canvas.addEventListener('mouseup', function(e) { + let scaleRatioX = UI.rfb.canvas.width / UI.rfb.canvas.clientWidth; + let scaleRatioY = UI.rfb.canvas.height / UI.rfb.canvas.clientHeight; + let x = Math.floor(e.offsetX * scaleRatioX); + let y = Math.floor(e.offsetY * scaleRatioY); + UI.canvasInteractionEvents.push({name: e.type, x: x, y: y}) + UI.updateInteractionStackUI(); + }); + }, + + updateInteractionStackUI() { + document.getElementById('noVNC_click_stack').innerHTML = ""; + for (var i = 0; i < UI.canvasInteractionEvents.length; i++) { + let e = UI.canvasInteractionEvents[i]; + let el = document.createElement('li'); + el.innerText = e.name + " at (" + e.x + ", " + e.y + ")"; + document.getElementById('noVNC_click_stack').append(el); + } + }, /* ------^------- * /VISUAL @@ -1048,6 +1070,7 @@ const UI = { UI.rfb.showDotCursor = UI.getSetting('show_dot'); UI.trackMouse(); + UI.trackClicks(); UI.updateViewOnly(); // requires UI.rfb }, diff --git a/vnc.html b/vnc.html index 96746f8b..1ccbf52e 100644 --- a/vnc.html +++ b/vnc.html @@ -336,5 +336,8 @@
(0, 0)
+ +
    +
From 75381cb03bb2639ae4a996d17a13b4f875557e75 Mon Sep 17 00:00:00 2001 From: DomenGaber Date: Wed, 5 Feb 2020 11:13:59 +0100 Subject: [PATCH 3/6] Decrease vnc container size and add info panel --- app/styles/base.css | 60 +++++++++++++++++++++++++++++++-------------- vnc.html | 21 ++++++++++------ 2 files changed, 55 insertions(+), 26 deletions(-) diff --git a/app/styles/base.css b/app/styles/base.css index dc8fe2a7..49d8c09b 100644 --- a/app/styles/base.css +++ b/app/styles/base.css @@ -847,7 +847,7 @@ select:active { /* Main container */ #noVNC_container { - width: 100%; + width: 80%; height: 100%; background-color: #313131; border-bottom-right-radius: 800px 600px; @@ -866,31 +866,53 @@ select:active { ime-mode: disabled; } -#noVNC_mouse_coordinates { +#noVNC_info_panel { position: fixed; top: 0; right: 0; - padding: 20px; - min-width: 150px; - font-size: 20px; - font-weight: 600; - text-align: center; + padding: 0 20px; + width: 20%; + height: 100%; background-color: #fff; - border: 2px solid #E0E0E0; - border-radius: 0 0 0 5px; - box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5); + box-sizing: border-box; + overflow: hidden; +} + +.noVNC_info_item { + width: 100%; + padding: 20px 0; + box-sizing: border-box; + border-bottom: 1px solid rgba(0, 0, 0, .15); + text-align: center; +} + +.noVNC_info_item_label { + display: inline-block; + margin-bottom: 15px; + font-weight: 600; + font-size: 14px; + text-transform: uppercase; + color: rgba(0, 0, 0, .5); +} + +#noVNC_mouse_coordinates, +#noVNC_click_stack { + width: 100%; + font-weight: 600; +} + +#noVNC_mouse_coordinates { + font-size: 20px; + text-align: center; } #noVNC_click_stack { - position: fixed; - bottom: 0; - right: 0; - width: 250px; - height: 250px; - overflow: scroll; - background-color: #fff; - border-radius: 5px 0 0 0; - box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5); + text-align: left; + line-height: 1.4; + margin: 0; + box-sizing: border-box; + height: 400px; + overflow-y: scroll; } /*Default noVNC logo.*/ diff --git a/vnc.html b/vnc.html index 1ccbf52e..8101661b 100644 --- a/vnc.html +++ b/vnc.html @@ -328,16 +328,23 @@ autocomplete="off" spellcheck="false" tabindex="-1"> +
+
+ Mouse coordinates +
+ (0, 0) +
+
+
+ Interaction stack +
    +
+
+
+ - -
- (0, 0) -
- -
    -
From 0d74223888a9ec3956ed4fa839332d4365da3cd3 Mon Sep 17 00:00:00 2001 From: DomenGaber Date: Wed, 5 Feb 2020 11:35:54 +0100 Subject: [PATCH 4/6] Add buttons to copy and clear interaction stack --- app/styles/base.css | 10 ++++++++++ app/ui.js | 33 +++++++++++++++++++++++++++++++++ vnc.html | 4 +++- 3 files changed, 46 insertions(+), 1 deletion(-) diff --git a/app/styles/base.css b/app/styles/base.css index 49d8c09b..1dc1e0cf 100644 --- a/app/styles/base.css +++ b/app/styles/base.css @@ -888,6 +888,7 @@ select:active { .noVNC_info_item_label { display: inline-block; + width: 100%; margin-bottom: 15px; font-weight: 600; font-size: 14px; @@ -895,6 +896,15 @@ select:active { color: rgba(0, 0, 0, .5); } +.noVNC_info_item button { + display: inline-block; + padding: 4px 4px; + margin: 10px 5px 20px 0; + vertical-align: middle; + border: 1px solid rgba(0, 0, 0, 0.2); + border-radius: 6px; +} + #noVNC_mouse_coordinates, #noVNC_click_stack { width: 100%; diff --git a/app/ui.js b/app/ui.js index 4cac0341..0a0f3923 100644 --- a/app/ui.js +++ b/app/ui.js @@ -720,6 +720,39 @@ const UI = { }, trackClicks() { + document.getElementById('noVNC_click_stack_copy').addEventListener('click', function() { + let text = JSON.stringify(UI.canvasInteractionEvents); + if (!navigator.clipboard) { + var textArea = document.createElement("textarea"); + textArea.value = text; + textArea.style.position="fixed"; //avoid scrolling to bottom + document.body.appendChild(textArea); + textArea.focus(); + textArea.select(); + + try { + var successful = document.execCommand('copy'); + var msg = successful ? 'successful' : 'unsuccessful'; + console.log('Fallback: Copying text command was ' + msg); + } catch (err) { + console.error('Fallback: Oops, unable to copy', err); + } + + document.body.removeChild(textArea); + return; + } + navigator.clipboard.writeText(text).then(function() { + console.log('Async: Copying to clipboard was successful!'); + }, function(err) { + console.error('Async: Could not copy text: ', err); + }); + }); + + document.getElementById('noVNC_click_stack_clear').addEventListener('click', function() { + UI.canvasInteractionEvents = Array(); + UI.updateInteractionStackUI(); + }); + UI.rfb.canvas.addEventListener('mouseup', function(e) { let scaleRatioX = UI.rfb.canvas.width / UI.rfb.canvas.clientWidth; let scaleRatioY = UI.rfb.canvas.height / UI.rfb.canvas.clientHeight; diff --git a/vnc.html b/vnc.html index 8101661b..841b48c8 100644 --- a/vnc.html +++ b/vnc.html @@ -335,8 +335,10 @@ (0, 0) -
+
Interaction stack + +
From 65bd696326d1f76aed518a9b68e3336889105494 Mon Sep 17 00:00:00 2001 From: DomenGaber Date: Wed, 5 Feb 2020 12:01:56 +0100 Subject: [PATCH 5/6] Add option to select default cursor --- app/ui.js | 9 +++++++++ core/rfb.js | 25 ++++++++++++++++++++----- core/util/cursor.js | 4 ++++ vnc.html | 3 +++ 4 files changed, 36 insertions(+), 5 deletions(-) diff --git a/app/ui.js b/app/ui.js index 0a0f3923..ffbb64f1 100644 --- a/app/ui.js +++ b/app/ui.js @@ -167,6 +167,7 @@ const UI = { UI.initSetting('view_only', false); UI.initSetting('img_bgrx_mode', false); UI.initSetting('show_dot', false); + UI.initSetting('show_pointer', false); UI.initSetting('path', 'websockify'); UI.initSetting('repeaterID', ''); UI.initSetting('reconnect', false); @@ -359,6 +360,8 @@ const UI = { UI.addSettingChangeHandler('img_bgrx_mode', UI.applyBGRXMode); UI.addSettingChangeHandler('show_dot'); UI.addSettingChangeHandler('show_dot', UI.updateShowDotCursor); + UI.addSettingChangeHandler('show_pointer'); + UI.addSettingChangeHandler('show_pointer', UI.updateShowPointerCursor); UI.addSettingChangeHandler('host'); UI.addSettingChangeHandler('port'); UI.addSettingChangeHandler('path'); @@ -1101,6 +1104,7 @@ const UI = { UI.rfb.scaleViewport = UI.getSetting('resize') === 'scale'; UI.rfb.resizeSession = UI.getSetting('resize') === 'remote'; UI.rfb.showDotCursor = UI.getSetting('show_dot'); + UI.rfb.showPointerCursor = UI.getSetting('show_pointer'); UI.trackMouse(); UI.trackClicks(); @@ -1722,6 +1726,11 @@ const UI = { UI.rfb.showDotCursor = UI.getSetting('show_dot'); }, + updateShowPointerCursor() { + if (!UI.rfb) return; + UI.rfb.showPointerCursor = UI.getSetting('show_pointer'); + }, + updateLogging() { WebUtil.init_logging(UI.getSetting('logging')); }, diff --git a/core/rfb.js b/core/rfb.js index 82ed141d..3fa940e1 100644 --- a/core/rfb.js +++ b/core/rfb.js @@ -251,6 +251,10 @@ export default class RFB extends EventTargetMixin { Log.Warn("Specifying showDotCursor as a RFB constructor argument is deprecated"); this._showDotCursor = options.showDotCursor; } + this._showPointerCursor = false; + if (options.showPointerCursor !== undefined) { + this._showPointerCursor = options.showPointerCursor; + } } // ===== PROPERTIES ===== @@ -315,6 +319,12 @@ export default class RFB extends EventTargetMixin { this._refreshCursor(); } + get showPointerCursor() { return this._showPointerCursor; } + set showPointerCursor(show) { + this._showPointerCursor = show; + this._refreshCursor(); + } + get background() { return this._screen.style.background; } set background(cssValue) { this._screen.style.background = cssValue; } @@ -1884,11 +1894,16 @@ export default class RFB extends EventTargetMixin { this._rfb_connection_state !== "connected") { return; } - const image = this._shouldShowDotCursor() ? RFB.cursors.dot : this._cursorImage; - this._cursor.change(image.rgbaPixels, - image.hotx, image.hoty, - image.w, image.h - ); + + if (this._showPointerCursor) { + this._cursor.changeToDefaultCursor(); + } else { + const image = this._shouldShowDotCursor() ? RFB.cursors.dot : this._cursorImage; + this._cursor.change(image.rgbaPixels, + image.hotx, image.hoty, + image.w, image.h + ); + } } static genDES(password, challenge) { diff --git a/core/util/cursor.js b/core/util/cursor.js index c7a084f0..b5c8b8cd 100644 --- a/core/util/cursor.js +++ b/core/util/cursor.js @@ -121,6 +121,10 @@ export default class Cursor { } } + changeToDefaultCursor() { + this._target.style.cursor = 'default'; + } + clear() { this._target.style.cursor = 'none'; this._canvas.width = 0; diff --git a/vnc.html b/vnc.html index 841b48c8..578e8647 100644 --- a/vnc.html +++ b/vnc.html @@ -243,6 +243,9 @@

  • +
  • + +
  • From 7090db605bdee20e9478e9bdf1b4d598d9076078 Mon Sep 17 00:00:00 2001 From: DomenGaber Date: Wed, 5 Feb 2020 13:16:10 +0100 Subject: [PATCH 6/6] Add download screenshot button --- app/ui.js | 14 ++++++++++++-- vnc.html | 6 +++++- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/app/ui.js b/app/ui.js index ffbb64f1..8b056170 100644 --- a/app/ui.js +++ b/app/ui.js @@ -766,12 +766,21 @@ const UI = { }); }, + attachDownloadScreenshotButton() { + document.getElementById('noVNC_download_screenshot').addEventListener('click', function() { + let link = document.createElement('a'); + link.download = 'screenshot.png'; + link.href = UI.rfb.canvas.toDataURL("image/png"); + link.click(); + }); + }, + updateInteractionStackUI() { - document.getElementById('noVNC_click_stack').innerHTML = ""; + document.getElementById('noVNC_click_stack').innerHTML = ''; for (var i = 0; i < UI.canvasInteractionEvents.length; i++) { let e = UI.canvasInteractionEvents[i]; let el = document.createElement('li'); - el.innerText = e.name + " at (" + e.x + ", " + e.y + ")"; + el.innerText = e.name + ' at (' + e.x + ', ' + e.y + ')'; document.getElementById('noVNC_click_stack').append(el); } }, @@ -1108,6 +1117,7 @@ const UI = { UI.trackMouse(); UI.trackClicks(); + UI.attachDownloadScreenshotButton(); UI.updateViewOnly(); // requires UI.rfb }, diff --git a/vnc.html b/vnc.html index 578e8647..05977e35 100644 --- a/vnc.html +++ b/vnc.html @@ -16,7 +16,7 @@ noVNC - + @@ -338,6 +338,10 @@ (0, 0)
    +
    + Screenshot + +
    Interaction stack