Merge pull request #2 from DomenGaber/display-mouse-position
Add info panel
This commit is contained in:
commit
b5b0500d4f
|
|
@ -847,7 +847,7 @@ select:active {
|
||||||
|
|
||||||
/* Main container */
|
/* Main container */
|
||||||
#noVNC_container {
|
#noVNC_container {
|
||||||
width: 100%;
|
width: 80%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background-color: #313131;
|
background-color: #313131;
|
||||||
border-bottom-right-radius: 800px 600px;
|
border-bottom-right-radius: 800px 600px;
|
||||||
|
|
@ -866,6 +866,65 @@ select:active {
|
||||||
ime-mode: disabled;
|
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.*/
|
/*Default noVNC logo.*/
|
||||||
/* From: http://fonts.googleapis.com/css?family=Orbitron:700 */
|
/* From: http://fonts.googleapis.com/css?family=Orbitron:700 */
|
||||||
@font-face {
|
@font-face {
|
||||||
|
|
|
||||||
88
app/ui.js
88
app/ui.js
|
|
@ -37,6 +37,8 @@ const UI = {
|
||||||
lastKeyboardinput: null,
|
lastKeyboardinput: null,
|
||||||
defaultKeyboardinputLen: 100,
|
defaultKeyboardinputLen: 100,
|
||||||
|
|
||||||
|
canvasInteractionEvents: Array(),
|
||||||
|
|
||||||
inhibit_reconnect: true,
|
inhibit_reconnect: true,
|
||||||
reconnect_callback: null,
|
reconnect_callback: null,
|
||||||
reconnect_password: null,
|
reconnect_password: null,
|
||||||
|
|
@ -165,6 +167,7 @@ const UI = {
|
||||||
UI.initSetting('view_only', false);
|
UI.initSetting('view_only', false);
|
||||||
UI.initSetting('img_bgrx_mode', false);
|
UI.initSetting('img_bgrx_mode', false);
|
||||||
UI.initSetting('show_dot', false);
|
UI.initSetting('show_dot', false);
|
||||||
|
UI.initSetting('show_pointer', false);
|
||||||
UI.initSetting('path', 'websockify');
|
UI.initSetting('path', 'websockify');
|
||||||
UI.initSetting('repeaterID', '');
|
UI.initSetting('repeaterID', '');
|
||||||
UI.initSetting('reconnect', false);
|
UI.initSetting('reconnect', false);
|
||||||
|
|
@ -357,6 +360,8 @@ const UI = {
|
||||||
UI.addSettingChangeHandler('img_bgrx_mode', UI.applyBGRXMode);
|
UI.addSettingChangeHandler('img_bgrx_mode', UI.applyBGRXMode);
|
||||||
UI.addSettingChangeHandler('show_dot');
|
UI.addSettingChangeHandler('show_dot');
|
||||||
UI.addSettingChangeHandler('show_dot', UI.updateShowDotCursor);
|
UI.addSettingChangeHandler('show_dot', UI.updateShowDotCursor);
|
||||||
|
UI.addSettingChangeHandler('show_pointer');
|
||||||
|
UI.addSettingChangeHandler('show_pointer', UI.updateShowPointerCursor);
|
||||||
UI.addSettingChangeHandler('host');
|
UI.addSettingChangeHandler('host');
|
||||||
UI.addSettingChangeHandler('port');
|
UI.addSettingChangeHandler('port');
|
||||||
UI.addSettingChangeHandler('path');
|
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
|
* /VISUAL
|
||||||
* ==============
|
* ==============
|
||||||
|
|
@ -1035,6 +1113,11 @@ const UI = {
|
||||||
UI.rfb.scaleViewport = UI.getSetting('resize') === 'scale';
|
UI.rfb.scaleViewport = UI.getSetting('resize') === 'scale';
|
||||||
UI.rfb.resizeSession = UI.getSetting('resize') === 'remote';
|
UI.rfb.resizeSession = UI.getSetting('resize') === 'remote';
|
||||||
UI.rfb.showDotCursor = UI.getSetting('show_dot');
|
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
|
UI.updateViewOnly(); // requires UI.rfb
|
||||||
},
|
},
|
||||||
|
|
@ -1653,6 +1736,11 @@ const UI = {
|
||||||
UI.rfb.showDotCursor = UI.getSetting('show_dot');
|
UI.rfb.showDotCursor = UI.getSetting('show_dot');
|
||||||
},
|
},
|
||||||
|
|
||||||
|
updateShowPointerCursor() {
|
||||||
|
if (!UI.rfb) return;
|
||||||
|
UI.rfb.showPointerCursor = UI.getSetting('show_pointer');
|
||||||
|
},
|
||||||
|
|
||||||
updateLogging() {
|
updateLogging() {
|
||||||
WebUtil.init_logging(UI.getSetting('logging'));
|
WebUtil.init_logging(UI.getSetting('logging'));
|
||||||
},
|
},
|
||||||
|
|
|
||||||
17
core/rfb.js
17
core/rfb.js
|
|
@ -251,6 +251,10 @@ export default class RFB extends EventTargetMixin {
|
||||||
Log.Warn("Specifying showDotCursor as a RFB constructor argument is deprecated");
|
Log.Warn("Specifying showDotCursor as a RFB constructor argument is deprecated");
|
||||||
this._showDotCursor = options.showDotCursor;
|
this._showDotCursor = options.showDotCursor;
|
||||||
}
|
}
|
||||||
|
this._showPointerCursor = false;
|
||||||
|
if (options.showPointerCursor !== undefined) {
|
||||||
|
this._showPointerCursor = options.showPointerCursor;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===== PROPERTIES =====
|
// ===== PROPERTIES =====
|
||||||
|
|
@ -271,6 +275,8 @@ export default class RFB extends EventTargetMixin {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get canvas() { return this._canvas; }
|
||||||
|
|
||||||
get capabilities() { return this._capabilities; }
|
get capabilities() { return this._capabilities; }
|
||||||
|
|
||||||
get touchButton() { return this._mouse.touchButton; }
|
get touchButton() { return this._mouse.touchButton; }
|
||||||
|
|
@ -313,6 +319,12 @@ export default class RFB extends EventTargetMixin {
|
||||||
this._refreshCursor();
|
this._refreshCursor();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get showPointerCursor() { return this._showPointerCursor; }
|
||||||
|
set showPointerCursor(show) {
|
||||||
|
this._showPointerCursor = show;
|
||||||
|
this._refreshCursor();
|
||||||
|
}
|
||||||
|
|
||||||
get background() { return this._screen.style.background; }
|
get background() { return this._screen.style.background; }
|
||||||
set background(cssValue) { this._screen.style.background = cssValue; }
|
set background(cssValue) { this._screen.style.background = cssValue; }
|
||||||
|
|
||||||
|
|
@ -1882,12 +1894,17 @@ export default class RFB extends EventTargetMixin {
|
||||||
this._rfb_connection_state !== "connected") {
|
this._rfb_connection_state !== "connected") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this._showPointerCursor) {
|
||||||
|
this._cursor.changeToDefaultCursor();
|
||||||
|
} else {
|
||||||
const image = this._shouldShowDotCursor() ? RFB.cursors.dot : this._cursorImage;
|
const image = this._shouldShowDotCursor() ? RFB.cursors.dot : this._cursorImage;
|
||||||
this._cursor.change(image.rgbaPixels,
|
this._cursor.change(image.rgbaPixels,
|
||||||
image.hotx, image.hoty,
|
image.hotx, image.hoty,
|
||||||
image.w, image.h
|
image.w, image.h
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static genDES(password, challenge) {
|
static genDES(password, challenge) {
|
||||||
const passwordChars = password.split('').map(c => c.charCodeAt(0));
|
const passwordChars = password.split('').map(c => c.charCodeAt(0));
|
||||||
|
|
|
||||||
|
|
@ -121,6 +121,10 @@ export default class Cursor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
changeToDefaultCursor() {
|
||||||
|
this._target.style.cursor = 'default';
|
||||||
|
}
|
||||||
|
|
||||||
clear() {
|
clear() {
|
||||||
this._target.style.cursor = 'none';
|
this._target.style.cursor = 'none';
|
||||||
this._canvas.width = 0;
|
this._canvas.width = 0;
|
||||||
|
|
|
||||||
23
vnc.html
23
vnc.html
|
|
@ -243,6 +243,9 @@
|
||||||
<input id="noVNC_setting_reconnect_delay" type="number">
|
<input id="noVNC_setting_reconnect_delay" type="number">
|
||||||
</li>
|
</li>
|
||||||
<li><hr></li>
|
<li><hr></li>
|
||||||
|
<li>
|
||||||
|
<label><input id="noVNC_setting_show_pointer" type="checkbox"> Show Default when No Cursor</label>
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<label><input id="noVNC_setting_show_dot" type="checkbox"> Show Dot when No Cursor</label>
|
<label><input id="noVNC_setting_show_dot" type="checkbox"> Show Dot when No Cursor</label>
|
||||||
</li>
|
</li>
|
||||||
|
|
@ -328,6 +331,26 @@
|
||||||
autocomplete="off" spellcheck="false" tabindex="-1"></textarea>
|
autocomplete="off" spellcheck="false" tabindex="-1"></textarea>
|
||||||
</div>
|
</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">
|
<audio id="noVNC_bell">
|
||||||
<source src="app/sounds/bell.oga" type="audio/ogg">
|
<source src="app/sounds/bell.oga" type="audio/ogg">
|
||||||
<source src="app/sounds/bell.mp3" type="audio/mpeg">
|
<source src="app/sounds/bell.mp3" type="audio/mpeg">
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue