Merge pull request #2 from DomenGaber/display-mouse-position

Add info panel
This commit is contained in:
DomenGaber 2020-02-05 13:26:51 +01:00 committed by GitHub
commit b5b0500d4f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 198 additions and 7 deletions

View File

@ -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,6 +866,65 @@ select:active {
ime-mode: disabled;
}
#noVNC_info_panel {
position: fixed;
top: 0;
right: 0;
padding: 0 20px;
width: 20%;
height: 100%;
background-color: #fff;
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;
width: 100%;
margin-bottom: 15px;
font-weight: 600;
font-size: 14px;
text-transform: uppercase;
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%;
font-weight: 600;
}
#noVNC_mouse_coordinates {
font-size: 20px;
text-align: center;
}
#noVNC_click_stack {
text-align: left;
line-height: 1.4;
margin: 0;
box-sizing: border-box;
height: 400px;
overflow-y: scroll;
}
/*Default noVNC logo.*/
/* From: http://fonts.googleapis.com/css?family=Orbitron:700 */
@font-face {

View File

@ -37,6 +37,8 @@ const UI = {
lastKeyboardinput: null,
defaultKeyboardinputLen: 100,
canvasInteractionEvents: Array(),
inhibit_reconnect: true,
reconnect_callback: null,
reconnect_password: null,
@ -165,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);
@ -357,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');
@ -707,6 +712,79 @@ 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').innerHTML = "(" + x + ", " + y + ")"
});
},
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;
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();
});
},
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 = '';
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
* ==============
@ -1035,6 +1113,11 @@ 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();
UI.attachDownloadScreenshotButton();
UI.updateViewOnly(); // requires UI.rfb
},
@ -1653,6 +1736,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'));
},

View File

@ -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 =====
@ -271,6 +275,8 @@ export default class RFB extends EventTargetMixin {
}
}
get canvas() { return this._canvas; }
get capabilities() { return this._capabilities; }
get touchButton() { return this._mouse.touchButton; }
@ -313,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; }
@ -1882,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) {

View File

@ -121,6 +121,10 @@ export default class Cursor {
}
}
changeToDefaultCursor() {
this._target.style.cursor = 'default';
}
clear() {
this._target.style.cursor = 'none';
this._canvas.width = 0;

View File

@ -16,7 +16,7 @@
<title>noVNC</title>
<meta charset="utf-8">
<!-- Always force latest IE rendering engine (even in intranet) & Chrome Frame
Remove this if you use the .htaccess -->
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
@ -243,6 +243,9 @@
<input id="noVNC_setting_reconnect_delay" type="number">
</li>
<li><hr></li>
<li>
<label><input id="noVNC_setting_show_pointer" type="checkbox"> Show Default when No Cursor</label>
</li>
<li>
<label><input id="noVNC_setting_show_dot" type="checkbox"> Show Dot when No Cursor</label>
</li>
@ -328,6 +331,26 @@
autocomplete="off" spellcheck="false" tabindex="-1"></textarea>
</div>
<div id="noVNC_info_panel">
<div class="noVNC_info_item">
<span class="noVNC_info_item_label">Mouse coordinates</span>
<div id="noVNC_mouse_coordinates">
(0, 0)
</div>
</div>
<div class="noVNC_info_item">
<span class="noVNC_info_item_label">Screenshot</span>
<button id="noVNC_download_screenshot">Download screenshot</button>
</div>
<div class="noVNC_info_item">
<span class="noVNC_info_item_label">Interaction stack</span>
<button id="noVNC_click_stack_copy">Copy stack to clipboard</button>
<button id="noVNC_click_stack_clear">Clear stack</button>
<ol id="noVNC_click_stack">
</ol>
</div>
</div>
<audio id="noVNC_bell">
<source src="app/sounds/bell.oga" type="audio/ogg">
<source src="app/sounds/bell.mp3" type="audio/mpeg">