summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPierre Ossman <ossman@cendio.se>2017-01-27 12:26:55 +0100
committerPierre Ossman <ossman@cendio.se>2017-05-04 12:13:47 +0200
commitae82053366bdf91c6cbcb459f92101ec4e693f0a (patch)
tree4ab30159efdce081473bc7fcb13854fbfb01cc2c
parent9fce233d51c803b08b6779bc8e906334de6916cf (diff)
downloadnovnc-ae82053366bdf91c6cbcb459f92101ec4e693f0a.tar.gz
Simplify pressed key handling
Prefer avoid having the server simulate multiple key presses by refusing to use multiple keysyms for the same physical key.
-rw-r--r--core/input/devices.js84
-rw-r--r--tests/test.keyboard.js21
2 files changed, 45 insertions, 60 deletions
diff --git a/core/input/devices.js b/core/input/devices.js
index d1c0649..f7d9052 100644
--- a/core/input/devices.js
+++ b/core/input/devices.js
@@ -19,7 +19,7 @@ import * as KeyboardUtil from "./util.js";
//
const Keyboard = function (defaults) {
- this._keyDownList = []; // List of depressed keys
+ this._keyDownList = {}; // List of depressed keys
// (even if they are happy)
this._pendingKey = null; // Key waiting for keypress
@@ -75,6 +75,27 @@ Keyboard.prototype = {
var code = this._getKeyCode(e);
var keysym = KeyboardUtil.getKeysym(e);
+ // We cannot handle keys we cannot track, but we also need
+ // to deal with virtual keyboards which omit key info
+ if (code === 'Unidentified') {
+ if (keysym) {
+ // If it's a virtual keyboard then it should be
+ // sufficient to just send press and release right
+ // after each other
+ this._sendKeyEvent(keysym, 'Unidentified', true);
+ this._sendKeyEvent(keysym, 'Unidentified', false);
+ }
+
+ stopEvent(e);
+ return;
+ }
+
+ // Is this key already pressed? If so, then we must use the
+ // same keysym or we'll confuse the server
+ if (code in this._keyDownList) {
+ keysym = this._keyDownList[code];
+ }
+
// If this is a legacy browser then we'll need to wait for
// a keypress event as well
if (!keysym) {
@@ -106,22 +127,7 @@ Keyboard.prototype = {
}
}
- var last;
- if (this._keyDownList.length === 0) {
- last = null;
- } else {
- last = this._keyDownList[this._keyDownList.length-1];
- }
-
- // insert a new entry if last seen key was different.
- if (!last || code === 'Unidentified' || last.code !== code) {
- last = {code: code, keysyms: {}};
- this._keyDownList.push(last);
- }
-
- // make sure last event contains this keysym (a single "logical" keyevent
- // can cause multiple key events to be sent to the VNC server)
- last.keysyms[keysym] = keysym;
+ this._keyDownList[code] = keysym;
// undo modifiers
if (escape) {
@@ -184,23 +190,12 @@ Keyboard.prototype = {
}
}
- var last;
- if (this._keyDownList.length === 0) {
- last = null;
- } else {
- last = this._keyDownList[this._keyDownList.length-1];
- }
-
- if (!last) {
- last = {code: code, keysyms: {}};
- this._keyDownList.push(last);
- }
if (!keysym) {
console.log('keypress with no keysym:', e);
return;
}
- last.keysyms[keysym] = keysym;
+ this._keyDownList[code] = keysym;
// undo modifiers
if (escape) {
@@ -229,37 +224,22 @@ Keyboard.prototype = {
var code = this._getKeyCode(e);
- if (this._keyDownList.length === 0) {
+ // Do we really think this key is down?
+ if (!(code in this._keyDownList)) {
return;
}
- var idx = null;
- // do we have a matching key tracked as being down?
- for (var i = 0; i !== this._keyDownList.length; ++i) {
- if (this._keyDownList[i].code === code) {
- idx = i;
- break;
- }
- }
- // if we couldn't find a match (it happens), assume it was the last key pressed
- if (idx === null) {
- idx = this._keyDownList.length - 1;
- }
- var item = this._keyDownList.splice(idx, 1)[0];
- for (var key in item.keysyms) {
- this._sendKeyEvent(item.keysyms[key], code, false);
- }
+ this._sendKeyEvent(this._keyDownList[code], code, false);
+
+ delete this._keyDownList[code];
},
_allKeysUp: function () {
Log.Debug(">> Keyboard.allKeysUp");
- for (var i = 0; i < this._keyDownList.length; i++) {
- var item = this._keyDownList[i];
- for (var key in item.keysyms) {
- this._sendKeyEvent(item.keysyms[key], 'Unidentified', false);
- }
+ for (var code in this._keyDownList) {
+ this._sendKeyEvent(this._keyDownList[code], code, false);
};
- this._keyDownList = [];
+ this._keyDownList = {};
Log.Debug("<< Keyboard.allKeysUp");
},
diff --git a/tests/test.keyboard.js b/tests/test.keyboard.js
index 51c6b8f..f9d5ff1 100644
--- a/tests/test.keyboard.js
+++ b/tests/test.keyboard.js
@@ -125,20 +125,25 @@ describe('Key Event Handling', function() {
kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', key: 'a'}));
kbd._handleKeyUp(keyevent('keyup', {code: 'KeyA', key: 'b'}));
});
+ it('should send the same keysym for multiple presses', function() {
+ var count = 0;
+ var kbd = new Keyboard({
+ onKeyEvent: function(keysym, code, down) {
+ expect(keysym).to.be.equal(0x61);
+ expect(code).to.be.equal('KeyA');
+ expect(down).to.be.equal(true);
+ count++;
+ }});
+ kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', key: 'a'}));
+ kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', key: 'b'}));
+ expect(count).to.be.equal(2);
+ });
it('should do nothing on keyup events if no keys are down', function() {
var callback = sinon.spy();
var kbd = new Keyboard({onKeyEvent: callback});
kbd._handleKeyUp(keyevent('keyup', {code: 'KeyA', key: 'a'}));
expect(callback).to.not.have.been.called;
});
- it('should send a key release for each key press with the same code', function() {
- var callback = sinon.spy();
- var kbd = new Keyboard({onKeyEvent: callback});
- kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', key: 'a'}));
- kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', key: 'b'}));
- kbd._handleKeyUp(keyevent('keyup', {code: 'KeyA'}));
- expect(callback.callCount).to.be.equal(4);
- });
});
describe('Escape Modifiers', function() {