Only grab key events on canvas
Give the canvas proper focus handling. This avoids messy logic that needs to disable and enable event handling when we want to interact with other UI elements. It also makes sure we can properly inhibit the browser from triggering local actions on key presses.
This commit is contained in:
parent
69411b9ea3
commit
2afda54456
|
@ -870,6 +870,9 @@ select:active {
|
||||||
/* IE miscalculates width without this :( */
|
/* IE miscalculates width without this :( */
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
#noVNC_canvas:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
/*Default noVNC logo.*/
|
/*Default noVNC logo.*/
|
||||||
/* From: http://fonts.googleapis.com/css?family=Orbitron:700 */
|
/* From: http://fonts.googleapis.com/css?family=Orbitron:700 */
|
||||||
|
|
30
app/ui.js
30
app/ui.js
|
@ -292,6 +292,8 @@ var UI = {
|
||||||
|
|
||||||
document.documentElement
|
document.documentElement
|
||||||
.addEventListener('mousedown', UI.keepVirtualKeyboard, true);
|
.addEventListener('mousedown', UI.keepVirtualKeyboard, true);
|
||||||
|
document.documentElement
|
||||||
|
.addEventListener('touchstart', UI.keepVirtualKeyboard, true);
|
||||||
|
|
||||||
document.getElementById("noVNC_control_bar")
|
document.getElementById("noVNC_control_bar")
|
||||||
.addEventListener('touchstart', UI.activateControlbar);
|
.addEventListener('touchstart', UI.activateControlbar);
|
||||||
|
@ -356,10 +358,6 @@ var UI = {
|
||||||
addClipboardHandlers: function() {
|
addClipboardHandlers: function() {
|
||||||
document.getElementById("noVNC_clipboard_button")
|
document.getElementById("noVNC_clipboard_button")
|
||||||
.addEventListener('click', UI.toggleClipboardPanel);
|
.addEventListener('click', UI.toggleClipboardPanel);
|
||||||
document.getElementById("noVNC_clipboard_text")
|
|
||||||
.addEventListener('focus', UI.displayBlur);
|
|
||||||
document.getElementById("noVNC_clipboard_text")
|
|
||||||
.addEventListener('blur', UI.displayFocus);
|
|
||||||
document.getElementById("noVNC_clipboard_text")
|
document.getElementById("noVNC_clipboard_text")
|
||||||
.addEventListener('change', UI.clipboardSend);
|
.addEventListener('change', UI.clipboardSend);
|
||||||
document.getElementById("noVNC_clipboard_clear_button")
|
document.getElementById("noVNC_clipboard_clear_button")
|
||||||
|
@ -440,6 +438,7 @@ var UI = {
|
||||||
msg = _("Connected (unencrypted) to ") + UI.desktopName;
|
msg = _("Connected (unencrypted) to ") + UI.desktopName;
|
||||||
}
|
}
|
||||||
UI.showStatus(msg);
|
UI.showStatus(msg);
|
||||||
|
document.getElementById('noVNC_canvas').focus();
|
||||||
break;
|
break;
|
||||||
case 'disconnecting':
|
case 'disconnecting':
|
||||||
UI.connected = false;
|
UI.connected = false;
|
||||||
|
@ -1492,7 +1491,14 @@ var UI = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
event.preventDefault();
|
// The default action of touchstart is to generate other
|
||||||
|
// events, which other elements might depend on. So we can't
|
||||||
|
// blindly prevent that. Instead restore focus right away.
|
||||||
|
if (event.type === "touchstart") {
|
||||||
|
setTimeout(input.focus.bind(input));
|
||||||
|
} else {
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
keyboardinputReset: function() {
|
keyboardinputReset: function() {
|
||||||
|
@ -1662,20 +1668,6 @@ var UI = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
displayBlur: function() {
|
|
||||||
if (UI.rfb && !UI.rfb.get_view_only()) {
|
|
||||||
UI.rfb.get_keyboard().set_focused(false);
|
|
||||||
UI.rfb.get_mouse().set_focused(false);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
displayFocus: function() {
|
|
||||||
if (UI.rfb && !UI.rfb.get_view_only()) {
|
|
||||||
UI.rfb.get_keyboard().set_focused(true);
|
|
||||||
UI.rfb.get_mouse().set_focused(true);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
updateLocalCursor: function() {
|
updateLocalCursor: function() {
|
||||||
if (!UI.rfb) return;
|
if (!UI.rfb) return;
|
||||||
UI.rfb.set_local_cursor(UI.getSetting('cursor'));
|
UI.rfb.set_local_cursor(UI.getSetting('cursor'));
|
||||||
|
|
|
@ -24,8 +24,7 @@ export default function Keyboard(defaults) {
|
||||||
this._pendingKey = null; // Key waiting for keypress
|
this._pendingKey = null; // Key waiting for keypress
|
||||||
|
|
||||||
set_defaults(this, defaults, {
|
set_defaults(this, defaults, {
|
||||||
'target': document,
|
'target': null,
|
||||||
'focused': true
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// keep these here so we can refer to them later
|
// keep these here so we can refer to them later
|
||||||
|
@ -131,8 +130,6 @@ Keyboard.prototype = {
|
||||||
},
|
},
|
||||||
|
|
||||||
_handleKeyDown: function (e) {
|
_handleKeyDown: function (e) {
|
||||||
if (!this._focused) { return; }
|
|
||||||
|
|
||||||
var code = this._getKeyCode(e);
|
var code = this._getKeyCode(e);
|
||||||
var keysym = KeyboardUtil.getKeysym(e);
|
var keysym = KeyboardUtil.getKeysym(e);
|
||||||
|
|
||||||
|
@ -214,8 +211,6 @@ Keyboard.prototype = {
|
||||||
|
|
||||||
// Legacy event for browsers without code/key
|
// Legacy event for browsers without code/key
|
||||||
_handleKeyPress: function (e) {
|
_handleKeyPress: function (e) {
|
||||||
if (!this._focused) { return; }
|
|
||||||
|
|
||||||
stopEvent(e);
|
stopEvent(e);
|
||||||
|
|
||||||
// Are we expecting a keypress?
|
// Are we expecting a keypress?
|
||||||
|
@ -244,8 +239,6 @@ Keyboard.prototype = {
|
||||||
this._sendKeyEvent(keysym, code, true);
|
this._sendKeyEvent(keysym, code, true);
|
||||||
},
|
},
|
||||||
_handleKeyPressTimeout: function (e) {
|
_handleKeyPressTimeout: function (e) {
|
||||||
if (!this._focused) { return; }
|
|
||||||
|
|
||||||
// Did someone manage to sort out the key already?
|
// Did someone manage to sort out the key already?
|
||||||
if (this._pendingKey === null) {
|
if (this._pendingKey === null) {
|
||||||
return;
|
return;
|
||||||
|
@ -282,8 +275,6 @@ Keyboard.prototype = {
|
||||||
},
|
},
|
||||||
|
|
||||||
_handleKeyUp: function (e) {
|
_handleKeyUp: function (e) {
|
||||||
if (!this._focused) { return; }
|
|
||||||
|
|
||||||
stopEvent(e);
|
stopEvent(e);
|
||||||
|
|
||||||
var code = this._getKeyCode(e);
|
var code = this._getKeyCode(e);
|
||||||
|
@ -348,7 +339,6 @@ Keyboard.prototype = {
|
||||||
|
|
||||||
make_properties(Keyboard, [
|
make_properties(Keyboard, [
|
||||||
['target', 'wo', 'dom'], // DOM element that captures keyboard input
|
['target', 'wo', 'dom'], // DOM element that captures keyboard input
|
||||||
['focused', 'rw', 'bool'], // Capture and send key events
|
|
||||||
|
|
||||||
['onKeyEvent', 'rw', 'func'] // Handler for key press/release
|
['onKeyEvent', 'rw', 'func'] // Handler for key press/release
|
||||||
]);
|
]);
|
||||||
|
|
|
@ -31,7 +31,6 @@ export default function Mouse(defaults) {
|
||||||
// Configuration attributes
|
// Configuration attributes
|
||||||
set_defaults(this, defaults, {
|
set_defaults(this, defaults, {
|
||||||
'target': document,
|
'target': document,
|
||||||
'focused': true,
|
|
||||||
'touchButton': 1
|
'touchButton': 1
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -52,8 +51,6 @@ Mouse.prototype = {
|
||||||
},
|
},
|
||||||
|
|
||||||
_handleMouseButton: function (e, down) {
|
_handleMouseButton: function (e, down) {
|
||||||
if (!this._focused) { return; }
|
|
||||||
|
|
||||||
this._updateMousePosition(e);
|
this._updateMousePosition(e);
|
||||||
var pos = this._pos;
|
var pos = this._pos;
|
||||||
|
|
||||||
|
@ -156,7 +153,7 @@ Mouse.prototype = {
|
||||||
},
|
},
|
||||||
|
|
||||||
_handleMouseWheel: function (e) {
|
_handleMouseWheel: function (e) {
|
||||||
if (!this._focused || !this._onMouseButton) { return; }
|
if (!this._onMouseButton) { return; }
|
||||||
|
|
||||||
this._resetWheelStepTimers();
|
this._resetWheelStepTimers();
|
||||||
|
|
||||||
|
@ -201,8 +198,6 @@ Mouse.prototype = {
|
||||||
},
|
},
|
||||||
|
|
||||||
_handleMouseMove: function (e) {
|
_handleMouseMove: function (e) {
|
||||||
if (! this._focused) { return; }
|
|
||||||
|
|
||||||
this._updateMousePosition(e);
|
this._updateMousePosition(e);
|
||||||
if (this._onMouseMove) {
|
if (this._onMouseMove) {
|
||||||
this._onMouseMove(this._pos.x, this._pos.y);
|
this._onMouseMove(this._pos.x, this._pos.y);
|
||||||
|
@ -211,8 +206,6 @@ Mouse.prototype = {
|
||||||
},
|
},
|
||||||
|
|
||||||
_handleMouseDisable: function (e) {
|
_handleMouseDisable: function (e) {
|
||||||
if (!this._focused) { return; }
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Stop propagation if inside canvas area
|
* Stop propagation if inside canvas area
|
||||||
* Note: This is only needed for the 'click' event as it fails
|
* Note: This is only needed for the 'click' event as it fails
|
||||||
|
@ -292,7 +285,6 @@ Mouse.prototype = {
|
||||||
|
|
||||||
make_properties(Mouse, [
|
make_properties(Mouse, [
|
||||||
['target', 'ro', 'dom'], // DOM element that captures mouse input
|
['target', 'ro', 'dom'], // DOM element that captures mouse input
|
||||||
['focused', 'rw', 'bool'], // Capture and send mouse clicks/movement
|
|
||||||
|
|
||||||
['onMouseButton', 'rw', 'func'], // Handler for mouse button click/release
|
['onMouseButton', 'rw', 'func'], // Handler for mouse button click/release
|
||||||
['onMouseMove', 'rw', 'func'], // Handler for mouse movement
|
['onMouseMove', 'rw', 'func'], // Handler for mouse movement
|
||||||
|
|
17
core/rfb.js
17
core/rfb.js
|
@ -120,7 +120,6 @@ export default function RFB(defaults) {
|
||||||
// set the default value on user-facing properties
|
// set the default value on user-facing properties
|
||||||
set_defaults(this, defaults, {
|
set_defaults(this, defaults, {
|
||||||
'target': 'null', // VNC display rendering Canvas object
|
'target': 'null', // VNC display rendering Canvas object
|
||||||
'focusContainer': document, // DOM element that captures keyboard input
|
|
||||||
'encrypt': false, // Use TLS/SSL/wss encryption
|
'encrypt': false, // Use TLS/SSL/wss encryption
|
||||||
'local_cursor': false, // Request locally rendered cursor
|
'local_cursor': false, // Request locally rendered cursor
|
||||||
'shared': true, // Request shared mode
|
'shared': true, // Request shared mode
|
||||||
|
@ -171,7 +170,7 @@ export default function RFB(defaults) {
|
||||||
throw exc;
|
throw exc;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._keyboard = new Keyboard({target: this._focusContainer,
|
this._keyboard = new Keyboard({target: this._target,
|
||||||
onKeyEvent: this._handleKeyEvent.bind(this)});
|
onKeyEvent: this._handleKeyEvent.bind(this)});
|
||||||
|
|
||||||
this._mouse = new Mouse({target: this._target,
|
this._mouse = new Mouse({target: this._target,
|
||||||
|
@ -385,11 +384,17 @@ RFB.prototype = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Always grab focus on some kind of click event
|
||||||
|
this._target.addEventListener("mousedown", this._focusCanvas);
|
||||||
|
this._target.addEventListener("touchstart", this._focusCanvas);
|
||||||
|
|
||||||
Log.Debug("<< RFB.connect");
|
Log.Debug("<< RFB.connect");
|
||||||
},
|
},
|
||||||
|
|
||||||
_disconnect: function () {
|
_disconnect: function () {
|
||||||
Log.Debug(">> RFB.disconnect");
|
Log.Debug(">> RFB.disconnect");
|
||||||
|
this._target.removeEventListener("mousedown", this._focusCanvas);
|
||||||
|
this._target.removeEventListener("touchstart", this._focusCanvas);
|
||||||
this._cleanup();
|
this._cleanup();
|
||||||
this._sock.close();
|
this._sock.close();
|
||||||
this._print_stats();
|
this._print_stats();
|
||||||
|
@ -448,6 +453,13 @@ RFB.prototype = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Event handler for canvas so this points to the canvas element
|
||||||
|
_focusCanvas: function(event) {
|
||||||
|
// Respect earlier handlers' request to not do side-effects
|
||||||
|
if (!event.defaultPrevented)
|
||||||
|
this.focus();
|
||||||
|
},
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Connection states:
|
* Connection states:
|
||||||
* connecting
|
* connecting
|
||||||
|
@ -1457,7 +1469,6 @@ RFB.prototype = {
|
||||||
|
|
||||||
make_properties(RFB, [
|
make_properties(RFB, [
|
||||||
['target', 'wo', 'dom'], // VNC display rendering Canvas object
|
['target', 'wo', 'dom'], // VNC display rendering Canvas object
|
||||||
['focusContainer', 'wo', 'dom'], // DOM element that captures keyboard input
|
|
||||||
['encrypt', 'rw', 'bool'], // Use TLS/SSL/wss encryption
|
['encrypt', 'rw', 'bool'], // Use TLS/SSL/wss encryption
|
||||||
['local_cursor', 'rw', 'bool'], // Request locally rendered cursor
|
['local_cursor', 'rw', 'bool'], // Request locally rendered cursor
|
||||||
['shared', 'rw', 'bool'], // Request shared mode
|
['shared', 'rw', 'bool'], // Request shared mode
|
||||||
|
|
2
vnc.html
2
vnc.html
|
@ -331,7 +331,7 @@
|
||||||
autocorrect="off" autocomplete="off" spellcheck="false"
|
autocorrect="off" autocomplete="off" spellcheck="false"
|
||||||
mozactionhint="Enter"></textarea>
|
mozactionhint="Enter"></textarea>
|
||||||
|
|
||||||
<canvas id="noVNC_canvas" width="0" height="0">
|
<canvas id="noVNC_canvas" width="0" height="0" tabindex="-1">
|
||||||
Canvas not supported.
|
Canvas not supported.
|
||||||
</canvas>
|
</canvas>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in New Issue