From 2afda54456fc45b1d343cc4b7e8edada9b71b088 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 5 Oct 2016 10:21:17 +0200 Subject: [PATCH] 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. --- app/styles/base.css | 3 +++ app/ui.js | 30 +++++++++++------------------- core/input/keyboard.js | 12 +----------- core/input/mouse.js | 10 +--------- core/rfb.js | 17 ++++++++++++++--- vnc.html | 2 +- 6 files changed, 31 insertions(+), 43 deletions(-) diff --git a/app/styles/base.css b/app/styles/base.css index 6e42d01b..b945456b 100644 --- a/app/styles/base.css +++ b/app/styles/base.css @@ -870,6 +870,9 @@ select:active { /* IE miscalculates width without this :( */ flex-shrink: 0; } +#noVNC_canvas:focus { + outline: none; +} /*Default noVNC logo.*/ /* From: http://fonts.googleapis.com/css?family=Orbitron:700 */ diff --git a/app/ui.js b/app/ui.js index 7bed04ed..02fac48a 100644 --- a/app/ui.js +++ b/app/ui.js @@ -292,6 +292,8 @@ var UI = { document.documentElement .addEventListener('mousedown', UI.keepVirtualKeyboard, true); + document.documentElement + .addEventListener('touchstart', UI.keepVirtualKeyboard, true); document.getElementById("noVNC_control_bar") .addEventListener('touchstart', UI.activateControlbar); @@ -356,10 +358,6 @@ var UI = { addClipboardHandlers: function() { document.getElementById("noVNC_clipboard_button") .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") .addEventListener('change', UI.clipboardSend); document.getElementById("noVNC_clipboard_clear_button") @@ -440,6 +438,7 @@ var UI = { msg = _("Connected (unencrypted) to ") + UI.desktopName; } UI.showStatus(msg); + document.getElementById('noVNC_canvas').focus(); break; case 'disconnecting': 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() { @@ -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() { if (!UI.rfb) return; UI.rfb.set_local_cursor(UI.getSetting('cursor')); diff --git a/core/input/keyboard.js b/core/input/keyboard.js index 7aa6288a..fa4a5ae4 100644 --- a/core/input/keyboard.js +++ b/core/input/keyboard.js @@ -24,8 +24,7 @@ export default function Keyboard(defaults) { this._pendingKey = null; // Key waiting for keypress set_defaults(this, defaults, { - 'target': document, - 'focused': true + 'target': null, }); // keep these here so we can refer to them later @@ -131,8 +130,6 @@ Keyboard.prototype = { }, _handleKeyDown: function (e) { - if (!this._focused) { return; } - var code = this._getKeyCode(e); var keysym = KeyboardUtil.getKeysym(e); @@ -214,8 +211,6 @@ Keyboard.prototype = { // Legacy event for browsers without code/key _handleKeyPress: function (e) { - if (!this._focused) { return; } - stopEvent(e); // Are we expecting a keypress? @@ -244,8 +239,6 @@ Keyboard.prototype = { this._sendKeyEvent(keysym, code, true); }, _handleKeyPressTimeout: function (e) { - if (!this._focused) { return; } - // Did someone manage to sort out the key already? if (this._pendingKey === null) { return; @@ -282,8 +275,6 @@ Keyboard.prototype = { }, _handleKeyUp: function (e) { - if (!this._focused) { return; } - stopEvent(e); var code = this._getKeyCode(e); @@ -348,7 +339,6 @@ Keyboard.prototype = { make_properties(Keyboard, [ ['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 ]); diff --git a/core/input/mouse.js b/core/input/mouse.js index 2e758074..49b5c395 100644 --- a/core/input/mouse.js +++ b/core/input/mouse.js @@ -31,7 +31,6 @@ export default function Mouse(defaults) { // Configuration attributes set_defaults(this, defaults, { 'target': document, - 'focused': true, 'touchButton': 1 }); @@ -52,8 +51,6 @@ Mouse.prototype = { }, _handleMouseButton: function (e, down) { - if (!this._focused) { return; } - this._updateMousePosition(e); var pos = this._pos; @@ -156,7 +153,7 @@ Mouse.prototype = { }, _handleMouseWheel: function (e) { - if (!this._focused || !this._onMouseButton) { return; } + if (!this._onMouseButton) { return; } this._resetWheelStepTimers(); @@ -201,8 +198,6 @@ Mouse.prototype = { }, _handleMouseMove: function (e) { - if (! this._focused) { return; } - this._updateMousePosition(e); if (this._onMouseMove) { this._onMouseMove(this._pos.x, this._pos.y); @@ -211,8 +206,6 @@ Mouse.prototype = { }, _handleMouseDisable: function (e) { - if (!this._focused) { return; } - /* * Stop propagation if inside canvas area * Note: This is only needed for the 'click' event as it fails @@ -292,7 +285,6 @@ Mouse.prototype = { make_properties(Mouse, [ ['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 ['onMouseMove', 'rw', 'func'], // Handler for mouse movement diff --git a/core/rfb.js b/core/rfb.js index 63847cf8..1ceaf8ee 100644 --- a/core/rfb.js +++ b/core/rfb.js @@ -120,7 +120,6 @@ export default function RFB(defaults) { // set the default value on user-facing properties set_defaults(this, defaults, { 'target': 'null', // VNC display rendering Canvas object - 'focusContainer': document, // DOM element that captures keyboard input 'encrypt': false, // Use TLS/SSL/wss encryption 'local_cursor': false, // Request locally rendered cursor 'shared': true, // Request shared mode @@ -171,7 +170,7 @@ export default function RFB(defaults) { throw exc; } - this._keyboard = new Keyboard({target: this._focusContainer, + this._keyboard = new Keyboard({target: this._target, onKeyEvent: this._handleKeyEvent.bind(this)}); 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"); }, _disconnect: function () { Log.Debug(">> RFB.disconnect"); + this._target.removeEventListener("mousedown", this._focusCanvas); + this._target.removeEventListener("touchstart", this._focusCanvas); this._cleanup(); this._sock.close(); 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: * connecting @@ -1457,7 +1469,6 @@ RFB.prototype = { make_properties(RFB, [ ['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 ['local_cursor', 'rw', 'bool'], // Request locally rendered cursor ['shared', 'rw', 'bool'], // Request shared mode diff --git a/vnc.html b/vnc.html index 7845fa66..67b8712e 100644 --- a/vnc.html +++ b/vnc.html @@ -331,7 +331,7 @@ autocorrect="off" autocomplete="off" spellcheck="false" mozactionhint="Enter"> - + Canvas not supported.