summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPierre Ossman <ossman@cendio.se>2017-01-25 11:29:08 +0100
committerPierre Ossman <ossman@cendio.se>2017-05-04 12:13:47 +0200
commitbfa1b237b9caec28380f3bb3e03f409eadc7f2b0 (patch)
treea86aa494a08856f48d28a3f34da0f857d318cc9b
parent80cb8ffddd49d828fe3b9c94b556ad154381b225 (diff)
downloadnovnc-bfa1b237b9caec28380f3bb3e03f409eadc7f2b0.tar.gz
Improve character keysym lookup
Use the more modern 'key' field, and remove some legacy fallbacks that are no longer required. This also removes the "stall" mechanism as it is not needed with current browsers.
-rw-r--r--core/input/devices.js8
-rw-r--r--core/input/util.js88
-rw-r--r--tests/test.helper.js24
-rw-r--r--tests/test.keyboard.js219
4 files changed, 53 insertions, 286 deletions
diff --git a/core/input/devices.js b/core/input/devices.js
index 8aaabbd..c68966b 100644
--- a/core/input/devices.js
+++ b/core/input/devices.js
@@ -29,12 +29,10 @@ const Keyboard = function (defaults) {
// create the keyboard handler
this._handler = new KeyboardUtil.KeyEventDecoder(KeyboardUtil.ModifierSync(),
- KeyboardUtil.VerifyCharModifier( /* jshint newcap: false */
- KeyboardUtil.TrackKeyState(
- KeyboardUtil.EscapeModifiers(this._handleRfbEvent.bind(this))
- )
+ KeyboardUtil.TrackKeyState(
+ KeyboardUtil.EscapeModifiers(this._handleRfbEvent.bind(this))
)
- ); /* jshint newcap: true */
+ );
// keep these here so we can refer to them later
this._eventHandlers = {
diff --git a/core/input/util.js b/core/input/util.js
index 508193e..18867af 100644
--- a/core/input/util.js
+++ b/core/input/util.js
@@ -196,23 +196,20 @@ export function getKeycode(evt){
// if char/charCode is available, prefer those, otherwise fall back to key/keyCode/which
export function getKeysym(evt){
var codepoint;
- if (evt.char && evt.char.length === 1) {
- codepoint = evt.char.charCodeAt();
- }
- else if (evt.charCode) {
+
+ if ('key' in evt) {
+ // Ignore special keys
+ if (evt.key.length === 1) {
+ codepoint = evt.key.charCodeAt();
+ }
+ } else if ('charCode' in evt) {
codepoint = evt.charCode;
}
- else if (evt.keyCode && evt.type === 'keypress') {
- // IE10 stores the char code as keyCode, and has no other useful properties
- codepoint = evt.keyCode;
- }
+
if (codepoint) {
return keysyms.lookup(codepoint);
}
- // we could check evt.key here.
- // Legal values are defined in http://www.w3.org/TR/DOM-Level-3-Events/#key-values-list,
- // so we "just" need to map them to keysym, but AFAIK this is only available in IE10, which also provides evt.key
- // so we don't *need* it yet
+
if (evt.keyCode) {
return keysymFromKeyCode(evt.keyCode, evt.shiftKey);
}
@@ -437,7 +434,6 @@ export function TrackQEMUKeyState (next) {
// - determines a code identifying the key that was pressed (corresponding to the code/keyCode properties on the DOM event)
// - synthesizes events to synchronize modifier key state between which modifiers are actually down, and which we thought were down
// - marks each event with an 'escape' property if a modifier was down which should be "escaped"
-// - generates a "stall" event in cases where it might be necessary to wait and see if a keypress event follows a keydown
// This information is collected into an object which is passed to the next() function. (one call per event)
export function KeyEventDecoder (modifierState, next) {
"use strict";
@@ -476,10 +472,6 @@ export function KeyEventDecoder (modifierState, next) {
// so only do that if we have to.
var suppress = !isShift && (type !== 'keydown' || modifierState.hasShortcutModifier() || !!nonCharacterKey(evt));
- // If a char modifier is down on a keydown, we need to insert a stall,
- // so VerifyCharModifier knows to wait and see if a keypress is comnig
- var stall = type === 'keydown' && modifierState.activeCharModifier() && !nonCharacterKey(evt);
-
// if a char modifier is pressed, get the keys it consists of (on Windows, AltGr is equivalent to Ctrl+Alt)
var active = modifierState.activeCharModifier();
@@ -498,10 +490,6 @@ export function KeyEventDecoder (modifierState, next) {
}
}
- if (stall) {
- // insert a fake "stall" event
- next({type: 'stall'});
- }
next(result);
return suppress;
@@ -526,64 +514,6 @@ export function KeyEventDecoder (modifierState, next) {
};
};
-// Combines keydown and keypress events where necessary to handle char modifiers.
-// On some OS'es, a char modifier is sometimes used as a shortcut modifier.
-// For example, on Windows, AltGr is synonymous with Ctrl-Alt. On a Danish keyboard layout, AltGr-2 yields a @, but Ctrl-Alt-D does nothing
-// so when used with the '2' key, Ctrl-Alt counts as a char modifier (and should be escaped), but when used with 'D', it does not.
-// The only way we can distinguish these cases is to wait and see if a keypress event arrives
-// When we receive a "stall" event, wait a few ms before processing the next keydown. If a keypress has also arrived, merge the two
-export function VerifyCharModifier (next) {
- "use strict";
- var queue = [];
- var timer = null;
- function process() {
- if (timer) {
- return;
- }
-
- var delayProcess = function () {
- clearTimeout(timer);
- timer = null;
- process();
- };
-
- while (queue.length !== 0) {
- var cur = queue[0];
- queue = queue.splice(1);
- switch (cur.type) {
- case 'stall':
- // insert a delay before processing available events.
- /* jshint loopfunc: true */
- timer = setTimeout(delayProcess, 5);
- /* jshint loopfunc: false */
- return;
- case 'keydown':
- // is the next element a keypress? Then we should merge the two
- if (queue.length !== 0 && queue[0].type === 'keypress') {
- // Firefox sends keypress even when no char is generated.
- // so, if keypress keysym is the same as we'd have guessed from keydown,
- // the modifier didn't have any effect, and should not be escaped
- if (queue[0].escape && (!cur.keysym || cur.keysym !== queue[0].keysym)) {
- cur.escape = queue[0].escape;
- }
- cur.keysym = queue[0].keysym;
- queue = queue.splice(1);
- }
- break;
- }
-
- // swallow stall events, and pass all others to the next stage
- if (cur.type !== 'stall') {
- next(cur);
- }
- }
- }
- return function(evt) {
- queue.push(evt);
- process();
- };
-};
-
// Keeps track of which keys we (and the server) believe are down
// When a keyup is received, match it against this list, to determine the corresponding keysym(s)
// in some cases, a single key may produce multiple keysyms, so the corresponding keyup event must release all of these chars
diff --git a/tests/test.helper.js b/tests/test.helper.js
index 3d0afb5..b66c5e5 100644
--- a/tests/test.helper.js
+++ b/tests/test.helper.js
@@ -99,25 +99,11 @@ describe('Helpers', function() {
});
describe('getKeysym', function() {
- it('should prefer char', function() {
- expect(KeyboardUtil.getKeysym({char : 'a', charCode: 'Š'.charCodeAt(), keyCode: 0x42, which: 0x43})).to.be.equal(0x61);
+ it('should prefer key', function() {
+ expect(KeyboardUtil.getKeysym({key: 'a', charCode: 'Š'.charCodeAt(), keyCode: 0x42, which: 0x43})).to.be.equal(0x61);
});
- it('should use charCode if no char', function() {
- expect(KeyboardUtil.getKeysym({char : '', charCode: 'Š'.charCodeAt(), keyCode: 0x42, which: 0x43})).to.be.equal(0x01a9);
+ it('should use charCode if no key', function() {
expect(KeyboardUtil.getKeysym({charCode: 'Š'.charCodeAt(), keyCode: 0x42, which: 0x43})).to.be.equal(0x01a9);
- expect(KeyboardUtil.getKeysym({char : 'hello', charCode: 'Š'.charCodeAt(), keyCode: 0x42, which: 0x43})).to.be.equal(0x01a9);
- });
- it('should use keyCode if no charCode', function() {
- expect(KeyboardUtil.getKeysym({keyCode: 0x42, which: 0x43, shiftKey: false})).to.be.equal(0x62);
- expect(KeyboardUtil.getKeysym({keyCode: 0x42, which: 0x43, shiftKey: true})).to.be.equal(0x42);
- });
- it('should return null for unknown keycodes', function() {
- expect(KeyboardUtil.getKeysym({keyCode: 0xc0, which: 0xc1, shiftKey:false})).to.be.null;
- expect(KeyboardUtil.getKeysym({keyCode: 0xde, which: 0xdf, shiftKey:false})).to.be.null;
- });
- it('should use which if no keyCode', function() {
- expect(KeyboardUtil.getKeysym({which: 0x43, shiftKey: false})).to.be.equal(0x63);
- expect(KeyboardUtil.getKeysym({which: 0x43, shiftKey: true})).to.be.equal(0x43);
});
describe('Non-character keys', function() {
@@ -133,6 +119,10 @@ describe('Helpers', function() {
expect(KeyboardUtil.getKeysym({keyCode: 0x1b})).to.be.equal(0xFF1B);
expect(KeyboardUtil.getKeysym({keyCode: 0x26})).to.be.equal(0xFF52);
});
+ it('should return null for unknown keycodes', function() {
+ expect(KeyboardUtil.getKeysym({keyCode: 0xc0})).to.be.null;
+ expect(KeyboardUtil.getKeysym({keyCode: 0xde})).to.be.null;
+ });
it('should not recognize character keys', function() {
expect(KeyboardUtil.getKeysym({keyCode: 'A'})).to.be.null;
expect(KeyboardUtil.getKeysym({keyCode: '1'})).to.be.null;
diff --git a/tests/test.keyboard.js b/tests/test.keyboard.js
index aa96142..f29a339 100644
--- a/tests/test.keyboard.js
+++ b/tests/test.keyboard.js
@@ -12,26 +12,26 @@ describe('Key Event Pipeline Stages', function() {
KeyboardUtil.KeyEventDecoder(KeyboardUtil.ModifierSync(), function(evt) {
expect(evt).to.be.an.object;
done();
- }).keydown({code: 'KeyA', keyCode: 0x41});
+ }).keydown({code: 'KeyA', key: 'a'});
});
it('should pass the right keysym through', function(done) {
KeyboardUtil.KeyEventDecoder(KeyboardUtil.ModifierSync(), function(evt) {
expect(evt.keysym).to.be.deep.equal(0x61);
done();
- }).keypress({code: 'KeyA', keyCode: 0x41});
+ }).keypress({code: 'KeyA', key: 'a'});
});
it('should pass the right keyid through', function(done) {
KeyboardUtil.KeyEventDecoder(KeyboardUtil.ModifierSync(), function(evt) {
expect(evt).to.have.property('code', 'KeyA');
done();
- }).keydown({code: 'KeyA', keyCode: 0x41});
+ }).keydown({code: 'KeyA', key: 'a'});
});
it('should not sync modifiers on a keypress', function() {
// Firefox provides unreliable modifier state on keypress events
var count = 0;
KeyboardUtil.KeyEventDecoder(KeyboardUtil.ModifierSync(), function(evt) {
++count;
- }).keypress({code: 'KeyA', keyCode: 0x41, ctrlKey: true});
+ }).keypress({code: 'KeyA', key: 'a', ctrlKey: true});
expect(count).to.be.equal(1);
});
it('should sync modifiers if necessary', function(done) {
@@ -47,61 +47,36 @@ describe('Key Event Pipeline Stages', function() {
done();
break;
}
- }).keydown({code: 'KeyA', keyCode: 0x41, ctrlKey: true});
+ }).keydown({code: 'KeyA', key: 'a', ctrlKey: true});
});
it('should forward keydown events with the right type', function(done) {
KeyboardUtil.KeyEventDecoder(KeyboardUtil.ModifierSync(), function(evt) {
expect(evt).to.be.deep.equal({code: 'KeyA', type: 'keydown'});
done();
- }).keydown({code: 'KeyA', keyCode: 0x41});
+ }).keydown({code: 'KeyA', key: 'a'});
});
it('should forward keyup events with the right type', function(done) {
KeyboardUtil.KeyEventDecoder(KeyboardUtil.ModifierSync(), function(evt) {
expect(evt).to.be.deep.equal({code: 'KeyA', keysym: 0x61, type: 'keyup'});
done();
- }).keyup({code: 'KeyA', keyCode: 0x41});
+ }).keyup({code: 'KeyA', key: 'a'});
});
it('should forward keypress events with the right type', function(done) {
KeyboardUtil.KeyEventDecoder(KeyboardUtil.ModifierSync(), function(evt) {
expect(evt).to.be.deep.equal({code: 'KeyA', keysym: 0x61, type: 'keypress'});
done();
- }).keypress({code: 'KeyA', keyCode: 0x41});
- });
- it('should generate stalls if a char modifier is down while a key is pressed', function(done) {
- var count = 0;
- KeyboardUtil.KeyEventDecoder(KeyboardUtil.ModifierSync([0xfe03]), function(evt) {
- switch (count) {
- case 0: // fake altgr
- expect(evt).to.be.deep.equal({keysym: 0xfe03, type: 'keydown'});
- ++count;
- break;
- case 1: // stall before processing the 'a' keydown
- expect(evt).to.be.deep.equal({type: 'stall'});
- ++count;
- break;
- case 2: // 'a'
- expect(evt).to.be.deep.equal({
- type: 'keydown',
- code: 'KeyA',
- keysym: 0x61
- });
-
- done();
- break;
- }
- }).keydown({code: 'KeyA', keyCode: 0x41, altGraphKey: true});
-
+ }).keypress({code: 'KeyA', key: 'a'});
});
describe('suppress the right events at the right time', function() {
it('should suppress anything while a shortcut modifier is down', function() {
var obj = KeyboardUtil.KeyEventDecoder(KeyboardUtil.ModifierSync(), function(evt) {});
obj.keydown({keyCode: 0x11}); // press ctrl
- expect(obj.keydown({keyCode: 'A'.charCodeAt()})).to.be.true;
+ expect(obj.keydown({key: 'A'})).to.be.true;
expect(obj.keydown({keyCode: ' '.charCodeAt()})).to.be.true;
- expect(obj.keydown({keyCode: '1'.charCodeAt()})).to.be.true;
- expect(obj.keydown({keyCode: 0x3c})).to.be.true; // < key on DK Windows
- expect(obj.keydown({keyCode: 0xde})).to.be.true; // Ø key on DK
+ expect(obj.keydown({key: '1'})).to.be.true;
+ expect(obj.keydown({key: '<'})).to.be.true;
+ expect(obj.keydown({key: 'ø'})).to.be.true;
});
it('should suppress non-character keys', function() {
var obj = KeyboardUtil.KeyEventDecoder(KeyboardUtil.ModifierSync(), function(evt) {});
@@ -127,48 +102,35 @@ describe('Key Event Pipeline Stages', function() {
it('should not suppress character keys', function() {
var obj = KeyboardUtil.KeyEventDecoder(KeyboardUtil.ModifierSync(), function(evt) {});
- expect(obj.keydown({keyCode: 'A'.charCodeAt()})).to.be.false;
+ expect(obj.keydown({key: 'A'})).to.be.false;
expect(obj.keydown({keyCode: ' '.charCodeAt()})).to.be.false;
- expect(obj.keydown({keyCode: '1'.charCodeAt()})).to.be.false;
- expect(obj.keydown({keyCode: 0x3c})).to.be.false; // < key on DK Windows
- expect(obj.keydown({keyCode: 0xde})).to.be.false; // Ø key on DK
+ expect(obj.keydown({key: '1'})).to.be.false;
+ expect(obj.keydown({key: '<'})).to.be.false; // < key on DK Windows
+ expect(obj.keydown({key: 'ø'})).to.be.false; // Ø key on DK
});
it('should not suppress if a char modifier is down', function() {
var obj = KeyboardUtil.KeyEventDecoder(KeyboardUtil.ModifierSync([0xfe03]), function(evt) {});
obj.keydown({keyCode: 0xe1}); // press altgr
- expect(obj.keydown({keyCode: 'A'.charCodeAt()})).to.be.false;
+ expect(obj.keydown({key: 'A'})).to.be.false;
expect(obj.keydown({keyCode: ' '.charCodeAt()})).to.be.false;
- expect(obj.keydown({keyCode: '1'.charCodeAt()})).to.be.false;
- expect(obj.keydown({keyCode: 0x3c})).to.be.false; // < key on DK Windows
- expect(obj.keydown({keyCode: 0xde})).to.be.false; // Ø key on DK
+ expect(obj.keydown({key: '1'})).to.be.false;
+ expect(obj.keydown({key: '<'})).to.be.false;
+ expect(obj.keydown({key: 'ø'})).to.be.false;
});
});
describe('Keypress and keyup events', function() {
it('should always suppress event propagation', function() {
var obj = KeyboardUtil.KeyEventDecoder(KeyboardUtil.ModifierSync(), function(evt) {});
- expect(obj.keypress({keyCode: 'A'.charCodeAt()})).to.be.true;
- expect(obj.keypress({keyCode: 0x3c})).to.be.true; // < key on DK Windows
+ expect(obj.keypress({key: 'A'})).to.be.true;
+ expect(obj.keypress({key: '<'})).to.be.true;
expect(obj.keypress({keyCode: 0x11})).to.be.true;
- expect(obj.keyup({keyCode: 'A'.charCodeAt()})).to.be.true;
- expect(obj.keyup({keyCode: 0x3c})).to.be.true; // < key on DK Windows
+ expect(obj.keyup({key: 'A'})).to.be.true;
+ expect(obj.keyup({key: '<'})).to.be.true;
expect(obj.keyup({keyCode: 0x11})).to.be.true;
});
- it('should never generate stalls', function() {
- var obj = KeyboardUtil.KeyEventDecoder(KeyboardUtil.ModifierSync(), function(evt) {
- expect(evt.type).to.not.be.equal('stall');
- });
-
- obj.keypress({keyCode: 'A'.charCodeAt()});
- obj.keypress({keyCode: 0x3c});
- obj.keypress({keyCode: 0x11});
-
- obj.keyup({keyCode: 'A'.charCodeAt()});
- obj.keyup({keyCode: 0x3c});
- obj.keyup({keyCode: 0x11});
- });
});
describe('mark events if a char modifier is down', function() {
it('should not mark modifiers on a keydown event', function() {
@@ -184,7 +146,7 @@ describe('Key Event Pipeline Stages', function() {
});
obj.keydown({keyCode: 0xe1}); // press altgr
- obj.keydown({code: 'KeyA', keyCode: 0x41});
+ obj.keydown({code: 'KeyA', key: 'a'});
});
it('should indicate on events if a single-key char modifier is down', function(done) {
@@ -206,7 +168,7 @@ describe('Key Event Pipeline Stages', function() {
});
obj.keydown({keyCode: 0xe1}); // press altgr
- obj.keypress({code: 'KeyA', keyCode: 0x41});
+ obj.keypress({code: 'KeyA', key: 'a'});
});
it('should indicate on events if a multi-key char modifier is down', function(done) {
var times_called = 0;
@@ -230,7 +192,7 @@ describe('Key Event Pipeline Stages', function() {
obj.keydown({keyCode: 0x11}); // press ctrl
obj.keydown({keyCode: 0x12}); // press alt
- obj.keypress({code: 'KeyA', keyCode: 0x41});
+ obj.keypress({code: 'KeyA', key: 'a'});
});
it('should not consider a char modifier to be down on the modifier key itself', function() {
var obj = KeyboardUtil.KeyEventDecoder(KeyboardUtil.ModifierSync([0xfe03]), function(evt) {
@@ -245,7 +207,7 @@ describe('Key Event Pipeline Stages', function() {
it('should remove keysym from keydown if a char key and no modifier', function() {
KeyboardUtil.KeyEventDecoder(KeyboardUtil.ModifierSync(), function(evt) {
expect(evt).to.be.deep.equal({code: 'KeyA', type: 'keydown'});
- }).keydown({code: 'KeyA', keyCode: 0x41});
+ }).keydown({code: 'KeyA', key: 'a'});
});
it('should not remove keysym from keydown if a shortcut modifier is down', function() {
var times_called = 0;
@@ -255,19 +217,19 @@ describe('Key Event Pipeline Stages', function() {
expect(evt).to.be.deep.equal({code: 'KeyA', keysym: 0x61, type: 'keydown'});
break;
}
- }).keydown({code: 'KeyA', keyCode: 0x41, ctrlKey: true});
+ }).keydown({code: 'KeyA', key: 'a', ctrlKey: true});
expect(times_called).to.be.equal(2);
});
it('should not remove keysym from keydown if a char modifier is down', function() {
var times_called = 0;
KeyboardUtil.KeyEventDecoder(KeyboardUtil.ModifierSync([0xfe03]), function(evt) {
switch (times_called++) {
- case 2:
+ case 1:
expect(evt).to.be.deep.equal({code: 'KeyA', keysym: 0x61, type: 'keydown'});
break;
}
- }).keydown({code: 'KeyA', keyCode: 0x41, altGraphKey: true});
- expect(times_called).to.be.equal(3);
+ }).keydown({code: 'KeyA', key: 'a', altGraphKey: true});
+ expect(times_called).to.be.equal(2);
});
it('should not remove keysym from keydown if key is noncharacter', function() {
KeyboardUtil.KeyEventDecoder(KeyboardUtil.ModifierSync(), function(evt) {
@@ -281,131 +243,18 @@ describe('Key Event Pipeline Stages', function() {
it('should never remove keysym from keypress', function() {
KeyboardUtil.KeyEventDecoder(KeyboardUtil.ModifierSync(), function(evt) {
expect(evt).to.be.deep.equal({code: 'KeyA', keysym: 0x61, type: 'keypress'});
- }).keypress({code: 'KeyA', keyCode: 0x41});
+ }).keypress({code: 'KeyA', key: 'a'});
});
it('should never remove keysym from keyup', function() {
KeyboardUtil.KeyEventDecoder(KeyboardUtil.ModifierSync(), function(evt) {
expect(evt).to.be.deep.equal({code: 'KeyA', keysym: 0x61, type: 'keyup'});
- }).keyup({code: 'KeyA', keyCode: 0x41});
+ }).keyup({code: 'KeyA', key: 'a'});
});
});
// on keypress, keyup(?), always set keysym
// on keydown, only do it if we don't expect a keypress: if noncharacter OR modifier is down
});
- describe('Verify that char modifiers are active', function() {
- it('should pass keydown events through if there is no stall', function(done) {
- var obj = KeyboardUtil.VerifyCharModifier(function(evt){
- expect(evt).to.deep.equal({type: 'keydown', code: 'KeyA', keysym: 0x41});
- done();
- })({type: 'keydown', code: 'KeyA', keysym: 0x41});
- });
- it('should pass keyup events through if there is no stall', function(done) {
- var obj = KeyboardUtil.VerifyCharModifier(function(evt){
- expect(evt).to.deep.equal({type: 'keyup', code: 'KeyA', keysym: 0x41});
- done();
- })({type: 'keyup', code: 'KeyA', keysym: 0x41});
- });
- it('should pass keypress events through if there is no stall', function(done) {
- var obj = KeyboardUtil.VerifyCharModifier(function(evt){
- expect(evt).to.deep.equal({type: 'keypress', code: 'KeyA', keysym: 0x41});
- done();
- })({type: 'keypress', code: 'KeyA', keysym: 0x41});
- });
- it('should not pass stall events through', function(done){
- var obj = KeyboardUtil.VerifyCharModifier(function(evt){
- // should only be called once, for the keydown
- expect(evt).to.deep.equal({type: 'keydown', code: 'KeyA', keysym: 0x41});
- done();
- });
-
- obj({type: 'stall'});
- obj({type: 'keydown', code: 'KeyA', keysym: 0x41});
- });
- it('should merge keydown and keypress events if they come after a stall', function(done) {
- var next_called = false;
- var obj = KeyboardUtil.VerifyCharModifier(function(evt){
- // should only be called once, for the keydown
- expect(next_called).to.be.false;
- next_called = true;
- expect(evt).to.deep.equal({type: 'keydown', code: 'KeyA', keysym: 0x44});
- done();
- });
-
- obj({type: 'stall'});
- obj({type: 'keydown', code: 'KeyA', keysym: 0x42});
- obj({type: 'keypress', code: 'KeyC', keysym: 0x44});
- expect(next_called).to.be.false;
- });
- it('should preserve modifier attribute when merging if keysyms differ', function(done) {
- var next_called = false;
- var obj = KeyboardUtil.VerifyCharModifier(function(evt){
- // should only be called once, for the keydown
- expect(next_called).to.be.false;
- next_called = true;
- expect(evt).to.deep.equal({type: 'keydown', code: 'KeyA', keysym: 0x44, escape: [0xffe3]});
- done();
- });
-
- obj({type: 'stall'});
- obj({type: 'keydown', code: 'KeyA', keysym: 0x42});
- obj({type: 'keypress', code: 'KeyC', keysym: 0x44, escape: [0xffe3]});
- expect(next_called).to.be.false;
- });
- it('should not preserve modifier attribute when merging if keysyms are the same', function() {
- var obj = KeyboardUtil.VerifyCharModifier(function(evt){
- expect(evt).to.not.have.property('escape');
- });
-
- obj({type: 'stall'});
- obj({type: 'keydown', code: 'KeyA', keysym: 0x42});
- obj({type: 'keypress', code: 'KeyC', keysym: 0x42, escape: [0xffe3]});
- });
- it('should not merge keydown and keypress events if there is no stall', function(done) {
- var times_called = 0;
- var obj = KeyboardUtil.VerifyCharModifier(function(evt){
- switch(times_called) {
- case 0:
- expect(evt).to.deep.equal({type: 'keydown', code: 'KeyA', keysym: 0x42});
- break;
- case 1:
- expect(evt).to.deep.equal({type: 'keypress', code: 'KeyC', keysym: 0x44});
- done();
- break;
- }
-
- ++times_called;
- });
-
- obj({type: 'keydown', code: 'KeyA', keysym: 0x42});
- obj({type: 'keypress', code: 'KeyC', keysym: 0x44});
- });
- it('should not merge keydown and keypress events if separated by another event', function(done) {
- var times_called = 0;
- var obj = KeyboardUtil.VerifyCharModifier(function(evt){
- switch(times_called) {
- case 0:
- expect(evt,1).to.deep.equal({type: 'keydown', code: 'KeyA', keysym: 0x42});
- break;
- case 1:
- expect(evt,2).to.deep.equal({type: 'keyup', code: 'KeyC', keysym: 0x44});
- break;
- case 2:
- expect(evt,3).to.deep.equal({type: 'keypress', code: 'KeyE', keysym: 0x46});
- done();
- break;
- }
-
- ++times_called;
- });
-
- obj({type: 'stall'});
- obj({type: 'keydown', code: 'KeyA', keysym: 0x42});
- obj({type: 'keyup', code: 'KeyC', keysym: 0x44});
- obj({type: 'keypress', code: 'KeyE', keysym: 0x46});
- });
- });
-
describe('Track Key State', function() {
it('should do nothing on keyup events if no keys are down', function() {
var obj = KeyboardUtil.TrackKeyState(function(evt) {