123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841 |
- var assert = chai.assert;
- var expect = chai.expect;
- describe('Key Event Pipeline Stages', function() {
- "use strict";
- describe('Decode Keyboard Events', function() {
- it('should pass events to the next stage', function(done) {
- KeyEventDecoder(kbdUtil.ModifierSync(), function(evt) {
- expect(evt).to.be.an.object;
- done();
- }).keydown({keyCode: 0x41});
- });
- it('should pass the right keysym through', function(done) {
- KeyEventDecoder(kbdUtil.ModifierSync(), function(evt) {
- expect(evt.keysym).to.be.deep.equal(keysyms.lookup(0x61));
- done();
- }).keypress({keyCode: 0x41});
- });
- it('should pass the right keyid through', function(done) {
- KeyEventDecoder(kbdUtil.ModifierSync(), function(evt) {
- expect(evt).to.have.property('keyId', 0x41);
- done();
- }).keydown({keyCode: 0x41});
- });
- it('should not sync modifiers on a keypress', function() {
- // Firefox provides unreliable modifier state on keypress events
- var count = 0;
- KeyEventDecoder(kbdUtil.ModifierSync(), function(evt) {
- ++count;
- }).keypress({keyCode: 0x41, ctrlKey: true});
- expect(count).to.be.equal(1);
- });
- it('should sync modifiers if necessary', function(done) {
- var count = 0;
- KeyEventDecoder(kbdUtil.ModifierSync(), function(evt) {
- switch (count) {
- case 0: // fake a ctrl keydown
- expect(evt).to.be.deep.equal({keysym: keysyms.lookup(0xffe3), type: 'keydown'});
- ++count;
- break;
- case 1:
- expect(evt).to.be.deep.equal({keyId: 0x41, type: 'keydown', keysym: keysyms.lookup(0x61)});
- done();
- break;
- }
- }).keydown({keyCode: 0x41, ctrlKey: true});
- });
- it('should forward keydown events with the right type', function(done) {
- KeyEventDecoder(kbdUtil.ModifierSync(), function(evt) {
- expect(evt).to.be.deep.equal({keyId: 0x41, type: 'keydown'});
- done();
- }).keydown({keyCode: 0x41})
- });
- it('should forward keyup events with the right type', function(done) {
- KeyEventDecoder(kbdUtil.ModifierSync(), function(evt) {
- expect(evt).to.be.deep.equal({keyId: 0x41, keysym: keysyms.lookup(0x61), type: 'keyup'});
- done();
- }).keyup({keyCode: 0x41});
- });
- it('should forward keypress events with the right type', function(done) {
- KeyEventDecoder(kbdUtil.ModifierSync(), function(evt) {
- expect(evt).to.be.deep.equal({keyId: 0x41, keysym: keysyms.lookup(0x61), type: 'keypress'});
- done();
- }).keypress({keyCode: 0x41});
- });
- it('should generate stalls if a char modifier is down while a key is pressed', function(done) {
- var count = 0;
- KeyEventDecoder(kbdUtil.ModifierSync([0xfe03]), function(evt) {
- switch (count) {
- case 0: // fake altgr
- expect(evt).to.be.deep.equal({keysym: keysyms.lookup(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',
- keyId: 0x41,
- keysym: keysyms.lookup(0x61)
- });
- done();
- break;
- }
- }).keydown({keyCode: 0x41, altGraphKey: true});
- });
- describe('suppress the right events at the right time', function() {
- it('should suppress anything while a shortcut modifier is down', function() {
- var obj = KeyEventDecoder(kbdUtil.ModifierSync(), function(evt) {});
- obj.keydown({keyCode: 0x11}); // press ctrl
- expect(obj.keydown({keyCode: 'A'.charCodeAt()})).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
- });
- it('should suppress non-character keys', function() {
- var obj = KeyEventDecoder(kbdUtil.ModifierSync(), function(evt) {});
- expect(obj.keydown({keyCode: 0x08}), 'a').to.be.true;
- expect(obj.keydown({keyCode: 0x09}), 'b').to.be.true;
- expect(obj.keydown({keyCode: 0x11}), 'd').to.be.true;
- expect(obj.keydown({keyCode: 0x12}), 'e').to.be.true;
- });
- it('should not suppress shift', function() {
- var obj = KeyEventDecoder(kbdUtil.ModifierSync(), function(evt) {});
- expect(obj.keydown({keyCode: 0x10}), 'd').to.be.false;
- });
- it('should generate event for shift keydown', function() {
- var called = false;
- var obj = KeyEventDecoder(kbdUtil.ModifierSync(), function(evt) {
- expect(evt).to.have.property('keysym');
- called = true;
- }).keydown({keyCode: 0x10});
- expect(called).to.be.true;
- });
- it('should not suppress character keys', function() {
- var obj = KeyEventDecoder(kbdUtil.ModifierSync(), function(evt) {});
- expect(obj.keydown({keyCode: 'A'.charCodeAt()})).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
- });
- it('should not suppress if a char modifier is down', function() {
- var obj = KeyEventDecoder(kbdUtil.ModifierSync([0xfe03]), function(evt) {});
- obj.keydown({keyCode: 0xe1}); // press altgr
- expect(obj.keydown({keyCode: 'A'.charCodeAt()})).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
- });
- });
- describe('Keypress and keyup events', function() {
- it('should always suppress event propagation', function() {
- var obj = KeyEventDecoder(kbdUtil.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({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({keyCode: 0x11})).to.be.true;
- });
- it('should never generate stalls', function() {
- var obj = KeyEventDecoder(kbdUtil.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() {
- var times_called = 0;
- var obj = KeyEventDecoder(kbdUtil.ModifierSync([0xfe03]), function(evt) {
- switch (times_called++) {
- case 0: //altgr
- break;
- case 1: // 'a'
- expect(evt).to.not.have.property('escape');
- break;
- }
- });
- obj.keydown({keyCode: 0xe1}); // press altgr
- obj.keydown({keyCode: 'A'.charCodeAt()});
- });
- it('should indicate on events if a single-key char modifier is down', function(done) {
- var times_called = 0;
- var obj = KeyEventDecoder(kbdUtil.ModifierSync([0xfe03]), function(evt) {
- switch (times_called++) {
- case 0: //altgr
- break;
- case 1: // 'a'
- expect(evt).to.be.deep.equal({
- type: 'keypress',
- keyId: 'A'.charCodeAt(),
- keysym: keysyms.lookup('a'.charCodeAt()),
- escape: [0xfe03]
- });
- done();
- return;
- }
- });
- obj.keydown({keyCode: 0xe1}); // press altgr
- obj.keypress({keyCode: 'A'.charCodeAt()});
- });
- it('should indicate on events if a multi-key char modifier is down', function(done) {
- var times_called = 0;
- var obj = KeyEventDecoder(kbdUtil.ModifierSync([0xffe9, 0xffe3]), function(evt) {
- switch (times_called++) {
- case 0: //ctrl
- break;
- case 1: //alt
- break;
- case 2: // 'a'
- expect(evt).to.be.deep.equal({
- type: 'keypress',
- keyId: 'A'.charCodeAt(),
- keysym: keysyms.lookup('a'.charCodeAt()),
- escape: [0xffe9, 0xffe3]
- });
- done();
- return;
- }
- });
- obj.keydown({keyCode: 0x11}); // press ctrl
- obj.keydown({keyCode: 0x12}); // press alt
- obj.keypress({keyCode: 'A'.charCodeAt()});
- });
- it('should not consider a char modifier to be down on the modifier key itself', function() {
- var obj = KeyEventDecoder(kbdUtil.ModifierSync([0xfe03]), function(evt) {
- expect(evt).to.not.have.property('escape');
- });
- obj.keydown({keyCode: 0xe1}); // press altgr
- });
- });
- describe('add/remove keysym', function() {
- it('should remove keysym from keydown if a char key and no modifier', function() {
- KeyEventDecoder(kbdUtil.ModifierSync(), function(evt) {
- expect(evt).to.be.deep.equal({keyId: 0x41, type: 'keydown'});
- }).keydown({keyCode: 0x41});
- });
- it('should not remove keysym from keydown if a shortcut modifier is down', function() {
- var times_called = 0;
- KeyEventDecoder(kbdUtil.ModifierSync(), function(evt) {
- switch (times_called++) {
- case 1:
- expect(evt).to.be.deep.equal({keyId: 0x41, keysym: keysyms.lookup(0x61), type: 'keydown'});
- break;
- }
- }).keydown({keyCode: 0x41, 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;
- KeyEventDecoder(kbdUtil.ModifierSync([0xfe03]), function(evt) {
- switch (times_called++) {
- case 2:
- expect(evt).to.be.deep.equal({keyId: 0x41, keysym: keysyms.lookup(0x61), type: 'keydown'});
- break;
- }
- }).keydown({keyCode: 0x41, altGraphKey: true});
- expect(times_called).to.be.equal(3);
- });
- it('should not remove keysym from keydown if key is noncharacter', function() {
- KeyEventDecoder(kbdUtil.ModifierSync(), function(evt) {
- expect(evt, 'bacobjpace').to.be.deep.equal({keyId: 0x09, keysym: keysyms.lookup(0xff09), type: 'keydown'});
- }).keydown({keyCode: 0x09});
- KeyEventDecoder(kbdUtil.ModifierSync(), function(evt) {
- expect(evt, 'ctrl').to.be.deep.equal({keyId: 0x11, keysym: keysyms.lookup(0xffe3), type: 'keydown'});
- }).keydown({keyCode: 0x11});
- });
- it('should never remove keysym from keypress', function() {
- KeyEventDecoder(kbdUtil.ModifierSync(), function(evt) {
- expect(evt).to.be.deep.equal({keyId: 0x41, keysym: keysyms.lookup(0x61), type: 'keypress'});
- }).keypress({keyCode: 0x41});
- });
- it('should never remove keysym from keyup', function() {
- KeyEventDecoder(kbdUtil.ModifierSync(), function(evt) {
- expect(evt).to.be.deep.equal({keyId: 0x41, keysym: keysyms.lookup(0x61), type: 'keyup'});
- }).keyup({keyCode: 0x41});
- });
- });
- // 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 = VerifyCharModifier(function(evt){
- expect(evt).to.deep.equal({type: 'keydown', keyId: 0x41, keysym: keysyms.lookup(0x41)});
- done();
- })({type: 'keydown', keyId: 0x41, keysym: keysyms.lookup(0x41)});
- });
- it('should pass keyup events through if there is no stall', function(done) {
- var obj = VerifyCharModifier(function(evt){
- expect(evt).to.deep.equal({type: 'keyup', keyId: 0x41, keysym: keysyms.lookup(0x41)});
- done();
- })({type: 'keyup', keyId: 0x41, keysym: keysyms.lookup(0x41)});
- });
- it('should pass keypress events through if there is no stall', function(done) {
- var obj = VerifyCharModifier(function(evt){
- expect(evt).to.deep.equal({type: 'keypress', keyId: 0x41, keysym: keysyms.lookup(0x41)});
- done();
- })({type: 'keypress', keyId: 0x41, keysym: keysyms.lookup(0x41)});
- });
- it('should not pass stall events through', function(done){
- var obj = VerifyCharModifier(function(evt){
- // should only be called once, for the keydown
- expect(evt).to.deep.equal({type: 'keydown', keyId: 0x41, keysym: keysyms.lookup(0x41)});
- done();
- });
- obj({type: 'stall'});
- obj({type: 'keydown', keyId: 0x41, keysym: keysyms.lookup(0x41)});
- });
- it('should merge keydown and keypress events if they come after a stall', function(done) {
- var next_called = false;
- var obj = 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', keyId: 0x41, keysym: keysyms.lookup(0x44)});
- done();
- });
- obj({type: 'stall'});
- obj({type: 'keydown', keyId: 0x41, keysym: keysyms.lookup(0x42)});
- obj({type: 'keypress', keyId: 0x43, keysym: keysyms.lookup(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 = 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', keyId: 0x41, keysym: keysyms.lookup(0x44), escape: [0xffe3]});
- done();
- });
- obj({type: 'stall'});
- obj({type: 'keydown', keyId: 0x41, keysym: keysyms.lookup(0x42)});
- obj({type: 'keypress', keyId: 0x43, keysym: keysyms.lookup(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 = VerifyCharModifier(function(evt){
- expect(evt).to.not.have.property('escape');
- });
- obj({type: 'stall'});
- obj({type: 'keydown', keyId: 0x41, keysym: keysyms.lookup(0x42)});
- obj({type: 'keypress', keyId: 0x43, keysym: keysyms.lookup(0x42), escape: [0xffe3]});
- });
- it('should not merge keydown and keypress events if there is no stall', function(done) {
- var times_called = 0;
- var obj = VerifyCharModifier(function(evt){
- switch(times_called) {
- case 0:
- expect(evt).to.deep.equal({type: 'keydown', keyId: 0x41, keysym: keysyms.lookup(0x42)});
- break;
- case 1:
- expect(evt).to.deep.equal({type: 'keypress', keyId: 0x43, keysym: keysyms.lookup(0x44)});
- done();
- break;
- }
- ++times_called;
- });
- obj({type: 'keydown', keyId: 0x41, keysym: keysyms.lookup(0x42)});
- obj({type: 'keypress', keyId: 0x43, keysym: keysyms.lookup(0x44)});
- });
- it('should not merge keydown and keypress events if separated by another event', function(done) {
- var times_called = 0;
- var obj = VerifyCharModifier(function(evt){
- switch(times_called) {
- case 0:
- expect(evt,1).to.deep.equal({type: 'keydown', keyId: 0x41, keysym: keysyms.lookup(0x42)});
- break;
- case 1:
- expect(evt,2).to.deep.equal({type: 'keyup', keyId: 0x43, keysym: keysyms.lookup(0x44)});
- break;
- case 2:
- expect(evt,3).to.deep.equal({type: 'keypress', keyId: 0x45, keysym: keysyms.lookup(0x46)});
- done();
- break;
- }
- ++times_called;
- });
- obj({type: 'stall'});
- obj({type: 'keydown', keyId: 0x41, keysym: keysyms.lookup(0x42)});
- obj({type: 'keyup', keyId: 0x43, keysym: keysyms.lookup(0x44)});
- obj({type: 'keypress', keyId: 0x45, keysym: keysyms.lookup(0x46)});
- });
- });
- describe('Track Key State', function() {
- it('should do nothing on keyup events if no keys are down', function() {
- var obj = TrackKeyState(function(evt) {
- expect(true).to.be.false;
- });
- obj({type: 'keyup', keyId: 0x41});
- });
- it('should insert into the queue on keydown if no keys are down', function() {
- var times_called = 0;
- var elem = null;
- var keysymsdown = {};
- var obj = TrackKeyState(function(evt) {
- ++times_called;
- if (elem.type == 'keyup') {
- expect(evt).to.have.property('keysym');
- expect (keysymsdown[evt.keysym.keysym]).to.not.be.undefined;
- delete keysymsdown[evt.keysym.keysym];
- }
- else {
- expect(evt).to.be.deep.equal(elem);
- expect (keysymsdown[evt.keysym.keysym]).to.not.be.undefined;
- }
- elem = null;
- });
- expect(elem).to.be.null;
- elem = {type: 'keydown', keyId: 0x41, keysym: keysyms.lookup(0x42)};
- keysymsdown[keysyms.lookup(0x42).keysym] = true;
- obj(elem);
- expect(elem).to.be.null;
- elem = {type: 'keyup', keyId: 0x41};
- obj(elem);
- expect(elem).to.be.null;
- expect(times_called).to.be.equal(2);
- });
- it('should insert into the queue on keypress if no keys are down', function() {
- var times_called = 0;
- var elem = null;
- var keysymsdown = {};
- var obj = TrackKeyState(function(evt) {
- ++times_called;
- if (elem.type == 'keyup') {
- expect(evt).to.have.property('keysym');
- expect (keysymsdown[evt.keysym.keysym]).to.not.be.undefined;
- delete keysymsdown[evt.keysym.keysym];
- }
- else {
- expect(evt).to.be.deep.equal(elem);
- expect (keysymsdown[evt.keysym.keysym]).to.not.be.undefined;
- }
- elem = null;
- });
- expect(elem).to.be.null;
- elem = {type: 'keypress', keyId: 0x41, keysym: keysyms.lookup(0x42)};
- keysymsdown[keysyms.lookup(0x42).keysym] = true;
- obj(elem);
- expect(elem).to.be.null;
- elem = {type: 'keyup', keyId: 0x41};
- obj(elem);
- expect(elem).to.be.null;
- expect(times_called).to.be.equal(2);
- });
- it('should add keysym to last key entry if keyId matches', function() {
- // this implies that a single keyup will release both keysyms
- var times_called = 0;
- var elem = null;
- var keysymsdown = {};
- var obj = TrackKeyState(function(evt) {
- ++times_called;
- if (elem.type == 'keyup') {
- expect(evt).to.have.property('keysym');
- expect (keysymsdown[evt.keysym.keysym]).to.not.be.undefined;
- delete keysymsdown[evt.keysym.keysym];
- }
- else {
- expect(evt).to.be.deep.equal(elem);
- expect (keysymsdown[evt.keysym.keysym]).to.not.be.undefined;
- elem = null;
- }
- });
- expect(elem).to.be.null;
- elem = {type: 'keypress', keyId: 0x41, keysym: keysyms.lookup(0x42)};
- keysymsdown[keysyms.lookup(0x42).keysym] = true;
- obj(elem);
- expect(elem).to.be.null;
- elem = {type: 'keypress', keyId: 0x41, keysym: keysyms.lookup(0x43)};
- keysymsdown[keysyms.lookup(0x43).keysym] = true;
- obj(elem);
- expect(elem).to.be.null;
- elem = {type: 'keyup', keyId: 0x41};
- obj(elem);
- expect(times_called).to.be.equal(4);
- });
- it('should create new key entry if keyId matches and keysym does not', function() {
- // this implies that a single keyup will release both keysyms
- var times_called = 0;
- var elem = null;
- var keysymsdown = {};
- var obj = TrackKeyState(function(evt) {
- ++times_called;
- if (elem.type == 'keyup') {
- expect(evt).to.have.property('keysym');
- expect (keysymsdown[evt.keysym.keysym]).to.not.be.undefined;
- delete keysymsdown[evt.keysym.keysym];
- }
- else {
- expect(evt).to.be.deep.equal(elem);
- expect (keysymsdown[evt.keysym.keysym]).to.not.be.undefined;
- elem = null;
- }
- });
- expect(elem).to.be.null;
- elem = {type: 'keydown', keyId: 0, keysym: keysyms.lookup(0x42)};
- keysymsdown[keysyms.lookup(0x42).keysym] = true;
- obj(elem);
- expect(elem).to.be.null;
- elem = {type: 'keydown', keyId: 0, keysym: keysyms.lookup(0x43)};
- keysymsdown[keysyms.lookup(0x43).keysym] = true;
- obj(elem);
- expect(times_called).to.be.equal(2);
- expect(elem).to.be.null;
- elem = {type: 'keyup', keyId: 0};
- obj(elem);
- expect(times_called).to.be.equal(3);
- elem = {type: 'keyup', keyId: 0};
- obj(elem);
- expect(times_called).to.be.equal(4);
- });
- it('should merge key entry if keyIds are zero and keysyms match', function() {
- // this implies that a single keyup will release both keysyms
- var times_called = 0;
- var elem = null;
- var keysymsdown = {};
- var obj = TrackKeyState(function(evt) {
- ++times_called;
- if (elem.type == 'keyup') {
- expect(evt).to.have.property('keysym');
- expect (keysymsdown[evt.keysym.keysym]).to.not.be.undefined;
- delete keysymsdown[evt.keysym.keysym];
- }
- else {
- expect(evt).to.be.deep.equal(elem);
- expect (keysymsdown[evt.keysym.keysym]).to.not.be.undefined;
- elem = null;
- }
- });
- expect(elem).to.be.null;
- elem = {type: 'keydown', keyId: 0, keysym: keysyms.lookup(0x42)};
- keysymsdown[keysyms.lookup(0x42).keysym] = true;
- obj(elem);
- expect(elem).to.be.null;
- elem = {type: 'keydown', keyId: 0, keysym: keysyms.lookup(0x42)};
- keysymsdown[keysyms.lookup(0x42).keysym] = true;
- obj(elem);
- expect(times_called).to.be.equal(2);
- expect(elem).to.be.null;
- elem = {type: 'keyup', keyId: 0};
- obj(elem);
- expect(times_called).to.be.equal(3);
- });
- it('should add keysym as separate entry if keyId does not match last event', function() {
- // this implies that separate keyups are required
- var times_called = 0;
- var elem = null;
- var keysymsdown = {};
- var obj = TrackKeyState(function(evt) {
- ++times_called;
- if (elem.type == 'keyup') {
- expect(evt).to.have.property('keysym');
- expect (keysymsdown[evt.keysym.keysym]).to.not.be.undefined;
- delete keysymsdown[evt.keysym.keysym];
- }
- else {
- expect(evt).to.be.deep.equal(elem);
- expect (keysymsdown[evt.keysym.keysym]).to.not.be.undefined;
- elem = null;
- }
- });
- expect(elem).to.be.null;
- elem = {type: 'keypress', keyId: 0x41, keysym: keysyms.lookup(0x42)};
- keysymsdown[keysyms.lookup(0x42).keysym] = true;
- obj(elem);
- expect(elem).to.be.null;
- elem = {type: 'keypress', keyId: 0x42, keysym: keysyms.lookup(0x43)};
- keysymsdown[keysyms.lookup(0x43).keysym] = true;
- obj(elem);
- expect(elem).to.be.null;
- elem = {type: 'keyup', keyId: 0x41};
- obj(elem);
- expect(times_called).to.be.equal(4);
- elem = {type: 'keyup', keyId: 0x42};
- obj(elem);
- expect(times_called).to.be.equal(4);
- });
- it('should add keysym as separate entry if keyId does not match last event and first is zero', function() {
- // this implies that separate keyups are required
- var times_called = 0;
- var elem = null;
- var keysymsdown = {};
- var obj = TrackKeyState(function(evt) {
- ++times_called;
- if (elem.type == 'keyup') {
- expect(evt).to.have.property('keysym');
- expect (keysymsdown[evt.keysym.keysym]).to.not.be.undefined;
- delete keysymsdown[evt.keysym.keysym];
- }
- else {
- expect(evt).to.be.deep.equal(elem);
- expect (keysymsdown[evt.keysym.keysym]).to.not.be.undefined;
- elem = null;
- }
- });
- expect(elem).to.be.null;
- elem = {type: 'keydown', keyId: 0, keysym: keysyms.lookup(0x42)};
- keysymsdown[keysyms.lookup(0x42).keysym] = true;
- obj(elem);
- expect(elem).to.be.null;
- elem = {type: 'keydown', keyId: 0x42, keysym: keysyms.lookup(0x43)};
- keysymsdown[keysyms.lookup(0x43).keysym] = true;
- obj(elem);
- expect(elem).to.be.null;
- expect(times_called).to.be.equal(2);
- elem = {type: 'keyup', keyId: 0};
- obj(elem);
- expect(times_called).to.be.equal(3);
- elem = {type: 'keyup', keyId: 0x42};
- obj(elem);
- expect(times_called).to.be.equal(4);
- });
- it('should add keysym as separate entry if keyId does not match last event and second is zero', function() {
- // this implies that a separate keyups are required
- var times_called = 0;
- var elem = null;
- var keysymsdown = {};
- var obj = TrackKeyState(function(evt) {
- ++times_called;
- if (elem.type == 'keyup') {
- expect(evt).to.have.property('keysym');
- expect (keysymsdown[evt.keysym.keysym]).to.not.be.undefined;
- delete keysymsdown[evt.keysym.keysym];
- }
- else {
- expect(evt).to.be.deep.equal(elem);
- expect (keysymsdown[evt.keysym.keysym]).to.not.be.undefined;
- elem = null;
- }
- });
- expect(elem).to.be.null;
- elem = {type: 'keydown', keyId: 0x41, keysym: keysyms.lookup(0x42)};
- keysymsdown[keysyms.lookup(0x42).keysym] = true;
- obj(elem);
- expect(elem).to.be.null;
- elem = {type: 'keydown', keyId: 0, keysym: keysyms.lookup(0x43)};
- keysymsdown[keysyms.lookup(0x43).keysym] = true;
- obj(elem);
- expect(elem).to.be.null;
- elem = {type: 'keyup', keyId: 0x41};
- obj(elem);
- expect(times_called).to.be.equal(3);
- elem = {type: 'keyup', keyId: 0};
- obj(elem);
- expect(times_called).to.be.equal(4);
- });
- it('should pop matching key event on keyup', function() {
- var times_called = 0;
- var obj = TrackKeyState(function(evt) {
- switch (times_called++) {
- case 0:
- case 1:
- case 2:
- expect(evt.type).to.be.equal('keydown');
- break;
- case 3:
- expect(evt).to.be.deep.equal({type: 'keyup', keyId: 0x42, keysym: keysyms.lookup(0x62)});
- break;
- }
- });
- obj({type: 'keydown', keyId: 0x41, keysym: keysyms.lookup(0x61)});
- obj({type: 'keydown', keyId: 0x42, keysym: keysyms.lookup(0x62)});
- obj({type: 'keydown', keyId: 0x43, keysym: keysyms.lookup(0x63)});
- obj({type: 'keyup', keyId: 0x42});
- expect(times_called).to.equal(4);
- });
- it('should pop the first zero keyevent on keyup with zero keyId', function() {
- var times_called = 0;
- var obj = TrackKeyState(function(evt) {
- switch (times_called++) {
- case 0:
- case 1:
- case 2:
- expect(evt.type).to.be.equal('keydown');
- break;
- case 3:
- expect(evt).to.be.deep.equal({type: 'keyup', keyId: 0, keysym: keysyms.lookup(0x61)});
- break;
- }
- });
- obj({type: 'keydown', keyId: 0, keysym: keysyms.lookup(0x61)});
- obj({type: 'keydown', keyId: 0, keysym: keysyms.lookup(0x62)});
- obj({type: 'keydown', keyId: 0x41, keysym: keysyms.lookup(0x63)});
- obj({type: 'keyup', keyId: 0x0});
- expect(times_called).to.equal(4);
- });
- it('should pop the last keyevents keysym if no match is found for keyId', function() {
- var times_called = 0;
- var obj = TrackKeyState(function(evt) {
- switch (times_called++) {
- case 0:
- case 1:
- case 2:
- expect(evt.type).to.be.equal('keydown');
- break;
- case 3:
- expect(evt).to.be.deep.equal({type: 'keyup', keyId: 0x44, keysym: keysyms.lookup(0x63)});
- break;
- }
- });
- obj({type: 'keydown', keyId: 0x41, keysym: keysyms.lookup(0x61)});
- obj({type: 'keydown', keyId: 0x42, keysym: keysyms.lookup(0x62)});
- obj({type: 'keydown', keyId: 0x43, keysym: keysyms.lookup(0x63)});
- obj({type: 'keyup', keyId: 0x44});
- expect(times_called).to.equal(4);
- });
- describe('Firefox sends keypress even when keydown is suppressed', function() {
- it('should discard the keypress', function() {
- var times_called = 0;
- var obj = TrackKeyState(function(evt) {
- expect(times_called).to.be.equal(0);
- ++times_called;
- });
- obj({type: 'keydown', keyId: 0x41, keysym: keysyms.lookup(0x42)});
- expect(times_called).to.be.equal(1);
- obj({type: 'keypress', keyId: 0x41, keysym: keysyms.lookup(0x43)});
- });
- });
- describe('releaseAll', function() {
- it('should do nothing if no keys have been pressed', function() {
- var times_called = 0;
- var obj = TrackKeyState(function(evt) {
- ++times_called;
- });
- obj({type: 'releaseall'});
- expect(times_called).to.be.equal(0);
- });
- it('should release the keys that have been pressed', function() {
- var times_called = 0;
- var obj = TrackKeyState(function(evt) {
- switch (times_called++) {
- case 2:
- expect(evt).to.be.deep.equal({type: 'keyup', keyId: 0, keysym: keysyms.lookup(0x41)});
- break;
- case 3:
- expect(evt).to.be.deep.equal({type: 'keyup', keyId: 0, keysym: keysyms.lookup(0x42)});
- break;
- }
- });
- obj({type: 'keydown', keyId: 0x41, keysym: keysyms.lookup(0x41)});
- obj({type: 'keydown', keyId: 0x42, keysym: keysyms.lookup(0x42)});
- expect(times_called).to.be.equal(2);
- obj({type: 'releaseall'});
- expect(times_called).to.be.equal(4);
- obj({type: 'releaseall'});
- expect(times_called).to.be.equal(4);
- });
- });
- });
- describe('Escape Modifiers', function() {
- describe('Keydown', function() {
- it('should pass through when a char modifier is not down', function() {
- var times_called = 0;
- EscapeModifiers(function(evt) {
- expect(times_called).to.be.equal(0);
- ++times_called;
- expect(evt).to.be.deep.equal({type: 'keydown', keyId: 0x41, keysym: keysyms.lookup(0x42)});
- })({type: 'keydown', keyId: 0x41, keysym: keysyms.lookup(0x42)});
- expect(times_called).to.be.equal(1);
- });
- it('should generate fake undo/redo events when a char modifier is down', function() {
- var times_called = 0;
- EscapeModifiers(function(evt) {
- switch(times_called++) {
- case 0:
- expect(evt).to.be.deep.equal({type: 'keyup', keyId: 0, keysym: keysyms.lookup(0xffe9)});
- break;
- case 1:
- expect(evt).to.be.deep.equal({type: 'keyup', keyId: 0, keysym: keysyms.lookup(0xffe3)});
- break;
- case 2:
- expect(evt).to.be.deep.equal({type: 'keydown', keyId: 0x41, keysym: keysyms.lookup(0x42), escape: [0xffe9, 0xffe3]});
- break;
- case 3:
- expect(evt).to.be.deep.equal({type: 'keydown', keyId: 0, keysym: keysyms.lookup(0xffe9)});
- break;
- case 4:
- expect(evt).to.be.deep.equal({type: 'keydown', keyId: 0, keysym: keysyms.lookup(0xffe3)});
- break;
- }
- })({type: 'keydown', keyId: 0x41, keysym: keysyms.lookup(0x42), escape: [0xffe9, 0xffe3]});
- expect(times_called).to.be.equal(5);
- });
- });
- describe('Keyup', function() {
- it('should pass through when a char modifier is down', function() {
- var times_called = 0;
- EscapeModifiers(function(evt) {
- expect(times_called).to.be.equal(0);
- ++times_called;
- expect(evt).to.be.deep.equal({type: 'keyup', keyId: 0x41, keysym: keysyms.lookup(0x42), escape: [0xfe03]});
- })({type: 'keyup', keyId: 0x41, keysym: keysyms.lookup(0x42), escape: [0xfe03]});
- expect(times_called).to.be.equal(1);
- });
- it('should pass through when a char modifier is not down', function() {
- var times_called = 0;
- EscapeModifiers(function(evt) {
- expect(times_called).to.be.equal(0);
- ++times_called;
- expect(evt).to.be.deep.equal({type: 'keyup', keyId: 0x41, keysym: keysyms.lookup(0x42)});
- })({type: 'keyup', keyId: 0x41, keysym: keysyms.lookup(0x42)});
- expect(times_called).to.be.equal(1);
- });
- });
- });
- });
|