]>
git.proxmox.com Git - mirror_novnc.git/blob - tests/test.keyboard.js
1 // requires local modules: input, keyboard, keysymdef
2 var assert
= chai
.assert
;
3 var expect
= chai
.expect
;
5 /* jshint newcap: false, expr: true */
6 describe('Key Event Pipeline Stages', function() {
8 describe('Decode Keyboard Events', function() {
9 it('should pass events to the next stage', function(done
) {
10 KeyEventDecoder(kbdUtil
.ModifierSync(), function(evt
) {
11 expect(evt
).to
.be
.an
.object
;
13 }).keydown({keyCode
: 0x41});
15 it('should pass the right keysym through', function(done
) {
16 KeyEventDecoder(kbdUtil
.ModifierSync(), function(evt
) {
17 expect(evt
.keysym
).to
.be
.deep
.equal(keysyms
.lookup(0x61));
19 }).keypress({keyCode
: 0x41});
21 it('should pass the right keyid through', function(done
) {
22 KeyEventDecoder(kbdUtil
.ModifierSync(), function(evt
) {
23 expect(evt
).to
.have
.property('keyId', 0x41);
25 }).keydown({keyCode
: 0x41});
27 it('should not sync modifiers on a keypress', function() {
28 // Firefox provides unreliable modifier state on keypress events
30 KeyEventDecoder(kbdUtil
.ModifierSync(), function(evt
) {
32 }).keypress({keyCode
: 0x41, ctrlKey
: true});
33 expect(count
).to
.be
.equal(1);
35 it('should sync modifiers if necessary', function(done
) {
37 KeyEventDecoder(kbdUtil
.ModifierSync(), function(evt
) {
39 case 0: // fake a ctrl keydown
40 expect(evt
).to
.be
.deep
.equal({keysym
: keysyms
.lookup(0xffe3), type
: 'keydown'});
44 expect(evt
).to
.be
.deep
.equal({keyId
: 0x41, type
: 'keydown', keysym
: keysyms
.lookup(0x61)});
48 }).keydown({keyCode
: 0x41, ctrlKey
: true});
50 it('should forward keydown events with the right type', function(done
) {
51 KeyEventDecoder(kbdUtil
.ModifierSync(), function(evt
) {
52 expect(evt
).to
.be
.deep
.equal({keyId
: 0x41, type
: 'keydown'});
54 }).keydown({keyCode
: 0x41});
56 it('should forward keyup events with the right type', function(done
) {
57 KeyEventDecoder(kbdUtil
.ModifierSync(), function(evt
) {
58 expect(evt
).to
.be
.deep
.equal({keyId
: 0x41, keysym
: keysyms
.lookup(0x61), type
: 'keyup'});
60 }).keyup({keyCode
: 0x41});
62 it('should forward keypress events with the right type', function(done
) {
63 KeyEventDecoder(kbdUtil
.ModifierSync(), function(evt
) {
64 expect(evt
).to
.be
.deep
.equal({keyId
: 0x41, keysym
: keysyms
.lookup(0x61), type
: 'keypress'});
66 }).keypress({keyCode
: 0x41});
68 it('should generate stalls if a char modifier is down while a key is pressed', function(done
) {
70 KeyEventDecoder(kbdUtil
.ModifierSync([0xfe03]), function(evt
) {
73 expect(evt
).to
.be
.deep
.equal({keysym
: keysyms
.lookup(0xfe03), type
: 'keydown'});
76 case 1: // stall before processing the 'a' keydown
77 expect(evt
).to
.be
.deep
.equal({type
: 'stall'});
81 expect(evt
).to
.be
.deep
.equal({
84 keysym
: keysyms
.lookup(0x61)
90 }).keydown({keyCode
: 0x41, altGraphKey
: true});
93 describe('suppress the right events at the right time', function() {
94 it('should suppress anything while a shortcut modifier is down', function() {
95 var obj
= KeyEventDecoder(kbdUtil
.ModifierSync(), function(evt
) {});
97 obj
.keydown({keyCode
: 0x11}); // press ctrl
98 expect(obj
.keydown({keyCode
: 'A'.charCodeAt()})).to
.be
.true;
99 expect(obj
.keydown({keyCode
: ' '.charCodeAt()})).to
.be
.true;
100 expect(obj
.keydown({keyCode
: '1'.charCodeAt()})).to
.be
.true;
101 expect(obj
.keydown({keyCode
: 0x3c})).to
.be
.true; // < key on DK Windows
102 expect(obj
.keydown({keyCode
: 0xde})).to
.be
.true; // Ø key on DK
104 it('should suppress non-character keys', function() {
105 var obj
= KeyEventDecoder(kbdUtil
.ModifierSync(), function(evt
) {});
107 expect(obj
.keydown({keyCode
: 0x08}), 'a').to
.be
.true;
108 expect(obj
.keydown({keyCode
: 0x09}), 'b').to
.be
.true;
109 expect(obj
.keydown({keyCode
: 0x11}), 'd').to
.be
.true;
110 expect(obj
.keydown({keyCode
: 0x12}), 'e').to
.be
.true;
112 it('should not suppress shift', function() {
113 var obj
= KeyEventDecoder(kbdUtil
.ModifierSync(), function(evt
) {});
115 expect(obj
.keydown({keyCode
: 0x10}), 'd').to
.be
.false;
117 it('should generate event for shift keydown', function() {
119 var obj
= KeyEventDecoder(kbdUtil
.ModifierSync(), function(evt
) {
120 expect(evt
).to
.have
.property('keysym');
122 }).keydown({keyCode
: 0x10});
123 expect(called
).to
.be
.true;
125 it('should not suppress character keys', function() {
126 var obj
= KeyEventDecoder(kbdUtil
.ModifierSync(), function(evt
) {});
128 expect(obj
.keydown({keyCode
: 'A'.charCodeAt()})).to
.be
.false;
129 expect(obj
.keydown({keyCode
: ' '.charCodeAt()})).to
.be
.false;
130 expect(obj
.keydown({keyCode
: '1'.charCodeAt()})).to
.be
.false;
131 expect(obj
.keydown({keyCode
: 0x3c})).to
.be
.false; // < key on DK Windows
132 expect(obj
.keydown({keyCode
: 0xde})).to
.be
.false; // Ø key on DK
134 it('should not suppress if a char modifier is down', function() {
135 var obj
= KeyEventDecoder(kbdUtil
.ModifierSync([0xfe03]), function(evt
) {});
137 obj
.keydown({keyCode
: 0xe1}); // press altgr
138 expect(obj
.keydown({keyCode
: 'A'.charCodeAt()})).to
.be
.false;
139 expect(obj
.keydown({keyCode
: ' '.charCodeAt()})).to
.be
.false;
140 expect(obj
.keydown({keyCode
: '1'.charCodeAt()})).to
.be
.false;
141 expect(obj
.keydown({keyCode
: 0x3c})).to
.be
.false; // < key on DK Windows
142 expect(obj
.keydown({keyCode
: 0xde})).to
.be
.false; // Ø key on DK
145 describe('Keypress and keyup events', function() {
146 it('should always suppress event propagation', function() {
147 var obj
= KeyEventDecoder(kbdUtil
.ModifierSync(), function(evt
) {});
149 expect(obj
.keypress({keyCode
: 'A'.charCodeAt()})).to
.be
.true;
150 expect(obj
.keypress({keyCode
: 0x3c})).to
.be
.true; // < key on DK Windows
151 expect(obj
.keypress({keyCode
: 0x11})).to
.be
.true;
153 expect(obj
.keyup({keyCode
: 'A'.charCodeAt()})).to
.be
.true;
154 expect(obj
.keyup({keyCode
: 0x3c})).to
.be
.true; // < key on DK Windows
155 expect(obj
.keyup({keyCode
: 0x11})).to
.be
.true;
157 it('should never generate stalls', function() {
158 var obj
= KeyEventDecoder(kbdUtil
.ModifierSync(), function(evt
) {
159 expect(evt
.type
).to
.not
.be
.equal('stall');
162 obj
.keypress({keyCode
: 'A'.charCodeAt()});
163 obj
.keypress({keyCode
: 0x3c});
164 obj
.keypress({keyCode
: 0x11});
166 obj
.keyup({keyCode
: 'A'.charCodeAt()});
167 obj
.keyup({keyCode
: 0x3c});
168 obj
.keyup({keyCode
: 0x11});
171 describe('mark events if a char modifier is down', function() {
172 it('should not mark modifiers on a keydown event', function() {
173 var times_called
= 0;
174 var obj
= KeyEventDecoder(kbdUtil
.ModifierSync([0xfe03]), function(evt
) {
175 switch (times_called
++) {
179 expect(evt
).to
.not
.have
.property('escape');
184 obj
.keydown({keyCode
: 0xe1}); // press altgr
185 obj
.keydown({keyCode
: 'A'.charCodeAt()});
188 it('should indicate on events if a single-key char modifier is down', function(done
) {
189 var times_called
= 0;
190 var obj
= KeyEventDecoder(kbdUtil
.ModifierSync([0xfe03]), function(evt
) {
191 switch (times_called
++) {
195 expect(evt
).to
.be
.deep
.equal({
197 keyId
: 'A'.charCodeAt(),
198 keysym
: keysyms
.lookup('a'.charCodeAt()),
206 obj
.keydown({keyCode
: 0xe1}); // press altgr
207 obj
.keypress({keyCode
: 'A'.charCodeAt()});
209 it('should indicate on events if a multi-key char modifier is down', function(done
) {
210 var times_called
= 0;
211 var obj
= KeyEventDecoder(kbdUtil
.ModifierSync([0xffe9, 0xffe3]), function(evt
) {
212 switch (times_called
++) {
218 expect(evt
).to
.be
.deep
.equal({
220 keyId
: 'A'.charCodeAt(),
221 keysym
: keysyms
.lookup('a'.charCodeAt()),
222 escape
: [0xffe9, 0xffe3]
229 obj
.keydown({keyCode
: 0x11}); // press ctrl
230 obj
.keydown({keyCode
: 0x12}); // press alt
231 obj
.keypress({keyCode
: 'A'.charCodeAt()});
233 it('should not consider a char modifier to be down on the modifier key itself', function() {
234 var obj
= KeyEventDecoder(kbdUtil
.ModifierSync([0xfe03]), function(evt
) {
235 expect(evt
).to
.not
.have
.property('escape');
238 obj
.keydown({keyCode
: 0xe1}); // press altgr
242 describe('add/remove keysym', function() {
243 it('should remove keysym from keydown if a char key and no modifier', function() {
244 KeyEventDecoder(kbdUtil
.ModifierSync(), function(evt
) {
245 expect(evt
).to
.be
.deep
.equal({keyId
: 0x41, type
: 'keydown'});
246 }).keydown({keyCode
: 0x41});
248 it('should not remove keysym from keydown if a shortcut modifier is down', function() {
249 var times_called
= 0;
250 KeyEventDecoder(kbdUtil
.ModifierSync(), function(evt
) {
251 switch (times_called
++) {
253 expect(evt
).to
.be
.deep
.equal({keyId
: 0x41, keysym
: keysyms
.lookup(0x61), type
: 'keydown'});
256 }).keydown({keyCode
: 0x41, ctrlKey
: true});
257 expect(times_called
).to
.be
.equal(2);
259 it('should not remove keysym from keydown if a char modifier is down', function() {
260 var times_called
= 0;
261 KeyEventDecoder(kbdUtil
.ModifierSync([0xfe03]), function(evt
) {
262 switch (times_called
++) {
264 expect(evt
).to
.be
.deep
.equal({keyId
: 0x41, keysym
: keysyms
.lookup(0x61), type
: 'keydown'});
267 }).keydown({keyCode
: 0x41, altGraphKey
: true});
268 expect(times_called
).to
.be
.equal(3);
270 it('should not remove keysym from keydown if key is noncharacter', function() {
271 KeyEventDecoder(kbdUtil
.ModifierSync(), function(evt
) {
272 expect(evt
, 'bacobjpace').to
.be
.deep
.equal({keyId
: 0x09, keysym
: keysyms
.lookup(0xff09), type
: 'keydown'});
273 }).keydown({keyCode
: 0x09});
275 KeyEventDecoder(kbdUtil
.ModifierSync(), function(evt
) {
276 expect(evt
, 'ctrl').to
.be
.deep
.equal({keyId
: 0x11, keysym
: keysyms
.lookup(0xffe3), type
: 'keydown'});
277 }).keydown({keyCode
: 0x11});
279 it('should never remove keysym from keypress', function() {
280 KeyEventDecoder(kbdUtil
.ModifierSync(), function(evt
) {
281 expect(evt
).to
.be
.deep
.equal({keyId
: 0x41, keysym
: keysyms
.lookup(0x61), type
: 'keypress'});
282 }).keypress({keyCode
: 0x41});
284 it('should never remove keysym from keyup', function() {
285 KeyEventDecoder(kbdUtil
.ModifierSync(), function(evt
) {
286 expect(evt
).to
.be
.deep
.equal({keyId
: 0x41, keysym
: keysyms
.lookup(0x61), type
: 'keyup'});
287 }).keyup({keyCode
: 0x41});
290 // on keypress, keyup(?), always set keysym
291 // on keydown, only do it if we don't expect a keypress: if noncharacter OR modifier is down
294 describe('Verify that char modifiers are active', function() {
295 it('should pass keydown events through if there is no stall', function(done
) {
296 var obj
= VerifyCharModifier(function(evt
){
297 expect(evt
).to
.deep
.equal({type
: 'keydown', keyId
: 0x41, keysym
: keysyms
.lookup(0x41)});
299 })({type
: 'keydown', keyId
: 0x41, keysym
: keysyms
.lookup(0x41)});
301 it('should pass keyup events through if there is no stall', function(done
) {
302 var obj
= VerifyCharModifier(function(evt
){
303 expect(evt
).to
.deep
.equal({type
: 'keyup', keyId
: 0x41, keysym
: keysyms
.lookup(0x41)});
305 })({type
: 'keyup', keyId
: 0x41, keysym
: keysyms
.lookup(0x41)});
307 it('should pass keypress events through if there is no stall', function(done
) {
308 var obj
= VerifyCharModifier(function(evt
){
309 expect(evt
).to
.deep
.equal({type
: 'keypress', keyId
: 0x41, keysym
: keysyms
.lookup(0x41)});
311 })({type
: 'keypress', keyId
: 0x41, keysym
: keysyms
.lookup(0x41)});
313 it('should not pass stall events through', function(done
){
314 var obj
= VerifyCharModifier(function(evt
){
315 // should only be called once, for the keydown
316 expect(evt
).to
.deep
.equal({type
: 'keydown', keyId
: 0x41, keysym
: keysyms
.lookup(0x41)});
320 obj({type
: 'stall'});
321 obj({type
: 'keydown', keyId
: 0x41, keysym
: keysyms
.lookup(0x41)});
323 it('should merge keydown and keypress events if they come after a stall', function(done
) {
324 var next_called
= false;
325 var obj
= VerifyCharModifier(function(evt
){
326 // should only be called once, for the keydown
327 expect(next_called
).to
.be
.false;
329 expect(evt
).to
.deep
.equal({type
: 'keydown', keyId
: 0x41, keysym
: keysyms
.lookup(0x44)});
333 obj({type
: 'stall'});
334 obj({type
: 'keydown', keyId
: 0x41, keysym
: keysyms
.lookup(0x42)});
335 obj({type
: 'keypress', keyId
: 0x43, keysym
: keysyms
.lookup(0x44)});
336 expect(next_called
).to
.be
.false;
338 it('should preserve modifier attribute when merging if keysyms differ', function(done
) {
339 var next_called
= false;
340 var obj
= VerifyCharModifier(function(evt
){
341 // should only be called once, for the keydown
342 expect(next_called
).to
.be
.false;
344 expect(evt
).to
.deep
.equal({type
: 'keydown', keyId
: 0x41, keysym
: keysyms
.lookup(0x44), escape
: [0xffe3]});
348 obj({type
: 'stall'});
349 obj({type
: 'keydown', keyId
: 0x41, keysym
: keysyms
.lookup(0x42)});
350 obj({type
: 'keypress', keyId
: 0x43, keysym
: keysyms
.lookup(0x44), escape
: [0xffe3]});
351 expect(next_called
).to
.be
.false;
353 it('should not preserve modifier attribute when merging if keysyms are the same', function() {
354 var obj
= VerifyCharModifier(function(evt
){
355 expect(evt
).to
.not
.have
.property('escape');
358 obj({type
: 'stall'});
359 obj({type
: 'keydown', keyId
: 0x41, keysym
: keysyms
.lookup(0x42)});
360 obj({type
: 'keypress', keyId
: 0x43, keysym
: keysyms
.lookup(0x42), escape
: [0xffe3]});
362 it('should not merge keydown and keypress events if there is no stall', function(done
) {
363 var times_called
= 0;
364 var obj
= VerifyCharModifier(function(evt
){
365 switch(times_called
) {
367 expect(evt
).to
.deep
.equal({type
: 'keydown', keyId
: 0x41, keysym
: keysyms
.lookup(0x42)});
370 expect(evt
).to
.deep
.equal({type
: 'keypress', keyId
: 0x43, keysym
: keysyms
.lookup(0x44)});
378 obj({type
: 'keydown', keyId
: 0x41, keysym
: keysyms
.lookup(0x42)});
379 obj({type
: 'keypress', keyId
: 0x43, keysym
: keysyms
.lookup(0x44)});
381 it('should not merge keydown and keypress events if separated by another event', function(done
) {
382 var times_called
= 0;
383 var obj
= VerifyCharModifier(function(evt
){
384 switch(times_called
) {
386 expect(evt
,1).to
.deep
.equal({type
: 'keydown', keyId
: 0x41, keysym
: keysyms
.lookup(0x42)});
389 expect(evt
,2).to
.deep
.equal({type
: 'keyup', keyId
: 0x43, keysym
: keysyms
.lookup(0x44)});
392 expect(evt
,3).to
.deep
.equal({type
: 'keypress', keyId
: 0x45, keysym
: keysyms
.lookup(0x46)});
400 obj({type
: 'stall'});
401 obj({type
: 'keydown', keyId
: 0x41, keysym
: keysyms
.lookup(0x42)});
402 obj({type
: 'keyup', keyId
: 0x43, keysym
: keysyms
.lookup(0x44)});
403 obj({type
: 'keypress', keyId
: 0x45, keysym
: keysyms
.lookup(0x46)});
407 describe('Track Key State', function() {
408 it('should do nothing on keyup events if no keys are down', function() {
409 var obj
= TrackKeyState(function(evt
) {
410 expect(true).to
.be
.false;
412 obj({type
: 'keyup', keyId
: 0x41});
414 it('should insert into the queue on keydown if no keys are down', function() {
415 var times_called
= 0;
417 var keysymsdown
= {};
418 var obj
= TrackKeyState(function(evt
) {
420 if (elem
.type
== 'keyup') {
421 expect(evt
).to
.have
.property('keysym');
422 expect (keysymsdown
[evt
.keysym
.keysym
]).to
.not
.be
.undefined;
423 delete keysymsdown
[evt
.keysym
.keysym
];
426 expect(evt
).to
.be
.deep
.equal(elem
);
427 expect (keysymsdown
[evt
.keysym
.keysym
]).to
.not
.be
.undefined;
432 expect(elem
).to
.be
.null;
433 elem
= {type
: 'keydown', keyId
: 0x41, keysym
: keysyms
.lookup(0x42)};
434 keysymsdown
[keysyms
.lookup(0x42).keysym
] = true;
436 expect(elem
).to
.be
.null;
437 elem
= {type
: 'keyup', keyId
: 0x41};
439 expect(elem
).to
.be
.null;
440 expect(times_called
).to
.be
.equal(2);
442 it('should insert into the queue on keypress if no keys are down', function() {
443 var times_called
= 0;
445 var keysymsdown
= {};
446 var obj
= TrackKeyState(function(evt
) {
448 if (elem
.type
== 'keyup') {
449 expect(evt
).to
.have
.property('keysym');
450 expect (keysymsdown
[evt
.keysym
.keysym
]).to
.not
.be
.undefined;
451 delete keysymsdown
[evt
.keysym
.keysym
];
454 expect(evt
).to
.be
.deep
.equal(elem
);
455 expect (keysymsdown
[evt
.keysym
.keysym
]).to
.not
.be
.undefined;
460 expect(elem
).to
.be
.null;
461 elem
= {type
: 'keypress', keyId
: 0x41, keysym
: keysyms
.lookup(0x42)};
462 keysymsdown
[keysyms
.lookup(0x42).keysym
] = true;
464 expect(elem
).to
.be
.null;
465 elem
= {type
: 'keyup', keyId
: 0x41};
467 expect(elem
).to
.be
.null;
468 expect(times_called
).to
.be
.equal(2);
470 it('should add keysym to last key entry if keyId matches', function() {
471 // this implies that a single keyup will release both keysyms
472 var times_called
= 0;
474 var keysymsdown
= {};
475 var obj
= TrackKeyState(function(evt
) {
477 if (elem
.type
== 'keyup') {
478 expect(evt
).to
.have
.property('keysym');
479 expect (keysymsdown
[evt
.keysym
.keysym
]).to
.not
.be
.undefined;
480 delete keysymsdown
[evt
.keysym
.keysym
];
483 expect(evt
).to
.be
.deep
.equal(elem
);
484 expect (keysymsdown
[evt
.keysym
.keysym
]).to
.not
.be
.undefined;
489 expect(elem
).to
.be
.null;
490 elem
= {type
: 'keypress', keyId
: 0x41, keysym
: keysyms
.lookup(0x42)};
491 keysymsdown
[keysyms
.lookup(0x42).keysym
] = true;
493 expect(elem
).to
.be
.null;
494 elem
= {type
: 'keypress', keyId
: 0x41, keysym
: keysyms
.lookup(0x43)};
495 keysymsdown
[keysyms
.lookup(0x43).keysym
] = true;
497 expect(elem
).to
.be
.null;
498 elem
= {type
: 'keyup', keyId
: 0x41};
500 expect(times_called
).to
.be
.equal(4);
502 it('should create new key entry if keyId matches and keysym does not', function() {
503 // this implies that a single keyup will release both keysyms
504 var times_called
= 0;
506 var keysymsdown
= {};
507 var obj
= TrackKeyState(function(evt
) {
509 if (elem
.type
== 'keyup') {
510 expect(evt
).to
.have
.property('keysym');
511 expect (keysymsdown
[evt
.keysym
.keysym
]).to
.not
.be
.undefined;
512 delete keysymsdown
[evt
.keysym
.keysym
];
515 expect(evt
).to
.be
.deep
.equal(elem
);
516 expect (keysymsdown
[evt
.keysym
.keysym
]).to
.not
.be
.undefined;
521 expect(elem
).to
.be
.null;
522 elem
= {type
: 'keydown', keyId
: 0, keysym
: keysyms
.lookup(0x42)};
523 keysymsdown
[keysyms
.lookup(0x42).keysym
] = true;
525 expect(elem
).to
.be
.null;
526 elem
= {type
: 'keydown', keyId
: 0, keysym
: keysyms
.lookup(0x43)};
527 keysymsdown
[keysyms
.lookup(0x43).keysym
] = true;
529 expect(times_called
).to
.be
.equal(2);
530 expect(elem
).to
.be
.null;
531 elem
= {type
: 'keyup', keyId
: 0};
533 expect(times_called
).to
.be
.equal(3);
534 elem
= {type
: 'keyup', keyId
: 0};
536 expect(times_called
).to
.be
.equal(4);
538 it('should merge key entry if keyIds are zero and keysyms match', function() {
539 // this implies that a single keyup will release both keysyms
540 var times_called
= 0;
542 var keysymsdown
= {};
543 var obj
= TrackKeyState(function(evt
) {
545 if (elem
.type
== 'keyup') {
546 expect(evt
).to
.have
.property('keysym');
547 expect (keysymsdown
[evt
.keysym
.keysym
]).to
.not
.be
.undefined;
548 delete keysymsdown
[evt
.keysym
.keysym
];
551 expect(evt
).to
.be
.deep
.equal(elem
);
552 expect (keysymsdown
[evt
.keysym
.keysym
]).to
.not
.be
.undefined;
557 expect(elem
).to
.be
.null;
558 elem
= {type
: 'keydown', keyId
: 0, keysym
: keysyms
.lookup(0x42)};
559 keysymsdown
[keysyms
.lookup(0x42).keysym
] = true;
561 expect(elem
).to
.be
.null;
562 elem
= {type
: 'keydown', keyId
: 0, keysym
: keysyms
.lookup(0x42)};
563 keysymsdown
[keysyms
.lookup(0x42).keysym
] = true;
565 expect(times_called
).to
.be
.equal(2);
566 expect(elem
).to
.be
.null;
567 elem
= {type
: 'keyup', keyId
: 0};
569 expect(times_called
).to
.be
.equal(3);
571 it('should add keysym as separate entry if keyId does not match last event', function() {
572 // this implies that separate keyups are required
573 var times_called
= 0;
575 var keysymsdown
= {};
576 var obj
= TrackKeyState(function(evt
) {
578 if (elem
.type
== 'keyup') {
579 expect(evt
).to
.have
.property('keysym');
580 expect (keysymsdown
[evt
.keysym
.keysym
]).to
.not
.be
.undefined;
581 delete keysymsdown
[evt
.keysym
.keysym
];
584 expect(evt
).to
.be
.deep
.equal(elem
);
585 expect (keysymsdown
[evt
.keysym
.keysym
]).to
.not
.be
.undefined;
590 expect(elem
).to
.be
.null;
591 elem
= {type
: 'keypress', keyId
: 0x41, keysym
: keysyms
.lookup(0x42)};
592 keysymsdown
[keysyms
.lookup(0x42).keysym
] = true;
594 expect(elem
).to
.be
.null;
595 elem
= {type
: 'keypress', keyId
: 0x42, keysym
: keysyms
.lookup(0x43)};
596 keysymsdown
[keysyms
.lookup(0x43).keysym
] = true;
598 expect(elem
).to
.be
.null;
599 elem
= {type
: 'keyup', keyId
: 0x41};
601 expect(times_called
).to
.be
.equal(4);
602 elem
= {type
: 'keyup', keyId
: 0x42};
604 expect(times_called
).to
.be
.equal(4);
606 it('should add keysym as separate entry if keyId does not match last event and first is zero', function() {
607 // this implies that separate keyups are required
608 var times_called
= 0;
610 var keysymsdown
= {};
611 var obj
= TrackKeyState(function(evt
) {
613 if (elem
.type
== 'keyup') {
614 expect(evt
).to
.have
.property('keysym');
615 expect (keysymsdown
[evt
.keysym
.keysym
]).to
.not
.be
.undefined;
616 delete keysymsdown
[evt
.keysym
.keysym
];
619 expect(evt
).to
.be
.deep
.equal(elem
);
620 expect (keysymsdown
[evt
.keysym
.keysym
]).to
.not
.be
.undefined;
625 expect(elem
).to
.be
.null;
626 elem
= {type
: 'keydown', keyId
: 0, keysym
: keysyms
.lookup(0x42)};
627 keysymsdown
[keysyms
.lookup(0x42).keysym
] = true;
629 expect(elem
).to
.be
.null;
630 elem
= {type
: 'keydown', keyId
: 0x42, keysym
: keysyms
.lookup(0x43)};
631 keysymsdown
[keysyms
.lookup(0x43).keysym
] = true;
633 expect(elem
).to
.be
.null;
634 expect(times_called
).to
.be
.equal(2);
635 elem
= {type
: 'keyup', keyId
: 0};
637 expect(times_called
).to
.be
.equal(3);
638 elem
= {type
: 'keyup', keyId
: 0x42};
640 expect(times_called
).to
.be
.equal(4);
642 it('should add keysym as separate entry if keyId does not match last event and second is zero', function() {
643 // this implies that a separate keyups are required
644 var times_called
= 0;
646 var keysymsdown
= {};
647 var obj
= TrackKeyState(function(evt
) {
649 if (elem
.type
== 'keyup') {
650 expect(evt
).to
.have
.property('keysym');
651 expect (keysymsdown
[evt
.keysym
.keysym
]).to
.not
.be
.undefined;
652 delete keysymsdown
[evt
.keysym
.keysym
];
655 expect(evt
).to
.be
.deep
.equal(elem
);
656 expect (keysymsdown
[evt
.keysym
.keysym
]).to
.not
.be
.undefined;
661 expect(elem
).to
.be
.null;
662 elem
= {type
: 'keydown', keyId
: 0x41, keysym
: keysyms
.lookup(0x42)};
663 keysymsdown
[keysyms
.lookup(0x42).keysym
] = true;
665 expect(elem
).to
.be
.null;
666 elem
= {type
: 'keydown', keyId
: 0, keysym
: keysyms
.lookup(0x43)};
667 keysymsdown
[keysyms
.lookup(0x43).keysym
] = true;
669 expect(elem
).to
.be
.null;
670 elem
= {type
: 'keyup', keyId
: 0x41};
672 expect(times_called
).to
.be
.equal(3);
673 elem
= {type
: 'keyup', keyId
: 0};
675 expect(times_called
).to
.be
.equal(4);
677 it('should pop matching key event on keyup', function() {
678 var times_called
= 0;
679 var obj
= TrackKeyState(function(evt
) {
680 switch (times_called
++) {
684 expect(evt
.type
).to
.be
.equal('keydown');
687 expect(evt
).to
.be
.deep
.equal({type
: 'keyup', keyId
: 0x42, keysym
: keysyms
.lookup(0x62)});
692 obj({type
: 'keydown', keyId
: 0x41, keysym
: keysyms
.lookup(0x61)});
693 obj({type
: 'keydown', keyId
: 0x42, keysym
: keysyms
.lookup(0x62)});
694 obj({type
: 'keydown', keyId
: 0x43, keysym
: keysyms
.lookup(0x63)});
695 obj({type
: 'keyup', keyId
: 0x42});
696 expect(times_called
).to
.equal(4);
698 it('should pop the first zero keyevent on keyup with zero keyId', function() {
699 var times_called
= 0;
700 var obj
= TrackKeyState(function(evt
) {
701 switch (times_called
++) {
705 expect(evt
.type
).to
.be
.equal('keydown');
708 expect(evt
).to
.be
.deep
.equal({type
: 'keyup', keyId
: 0, keysym
: keysyms
.lookup(0x61)});
713 obj({type
: 'keydown', keyId
: 0, keysym
: keysyms
.lookup(0x61)});
714 obj({type
: 'keydown', keyId
: 0, keysym
: keysyms
.lookup(0x62)});
715 obj({type
: 'keydown', keyId
: 0x41, keysym
: keysyms
.lookup(0x63)});
716 obj({type
: 'keyup', keyId
: 0x0});
717 expect(times_called
).to
.equal(4);
719 it('should pop the last keyevents keysym if no match is found for keyId', function() {
720 var times_called
= 0;
721 var obj
= TrackKeyState(function(evt
) {
722 switch (times_called
++) {
726 expect(evt
.type
).to
.be
.equal('keydown');
729 expect(evt
).to
.be
.deep
.equal({type
: 'keyup', keyId
: 0x44, keysym
: keysyms
.lookup(0x63)});
734 obj({type
: 'keydown', keyId
: 0x41, keysym
: keysyms
.lookup(0x61)});
735 obj({type
: 'keydown', keyId
: 0x42, keysym
: keysyms
.lookup(0x62)});
736 obj({type
: 'keydown', keyId
: 0x43, keysym
: keysyms
.lookup(0x63)});
737 obj({type
: 'keyup', keyId
: 0x44});
738 expect(times_called
).to
.equal(4);
740 describe('Firefox sends keypress even when keydown is suppressed', function() {
741 it('should discard the keypress', function() {
742 var times_called
= 0;
743 var obj
= TrackKeyState(function(evt
) {
744 expect(times_called
).to
.be
.equal(0);
748 obj({type
: 'keydown', keyId
: 0x41, keysym
: keysyms
.lookup(0x42)});
749 expect(times_called
).to
.be
.equal(1);
750 obj({type
: 'keypress', keyId
: 0x41, keysym
: keysyms
.lookup(0x43)});
753 describe('releaseAll', function() {
754 it('should do nothing if no keys have been pressed', function() {
755 var times_called
= 0;
756 var obj
= TrackKeyState(function(evt
) {
759 obj({type
: 'releaseall'});
760 expect(times_called
).to
.be
.equal(0);
762 it('should release the keys that have been pressed', function() {
763 var times_called
= 0;
764 var obj
= TrackKeyState(function(evt
) {
765 switch (times_called
++) {
767 expect(evt
).to
.be
.deep
.equal({type
: 'keyup', keyId
: 0, keysym
: keysyms
.lookup(0x41)});
770 expect(evt
).to
.be
.deep
.equal({type
: 'keyup', keyId
: 0, keysym
: keysyms
.lookup(0x42)});
774 obj({type
: 'keydown', keyId
: 0x41, keysym
: keysyms
.lookup(0x41)});
775 obj({type
: 'keydown', keyId
: 0x42, keysym
: keysyms
.lookup(0x42)});
776 expect(times_called
).to
.be
.equal(2);
777 obj({type
: 'releaseall'});
778 expect(times_called
).to
.be
.equal(4);
779 obj({type
: 'releaseall'});
780 expect(times_called
).to
.be
.equal(4);
786 describe('Escape Modifiers', function() {
787 describe('Keydown', function() {
788 it('should pass through when a char modifier is not down', function() {
789 var times_called
= 0;
790 EscapeModifiers(function(evt
) {
791 expect(times_called
).to
.be
.equal(0);
793 expect(evt
).to
.be
.deep
.equal({type
: 'keydown', keyId
: 0x41, keysym
: keysyms
.lookup(0x42)});
794 })({type
: 'keydown', keyId
: 0x41, keysym
: keysyms
.lookup(0x42)});
795 expect(times_called
).to
.be
.equal(1);
797 it('should generate fake undo/redo events when a char modifier is down', function() {
798 var times_called
= 0;
799 EscapeModifiers(function(evt
) {
800 switch(times_called
++) {
802 expect(evt
).to
.be
.deep
.equal({type
: 'keyup', keyId
: 0, keysym
: keysyms
.lookup(0xffe9)});
805 expect(evt
).to
.be
.deep
.equal({type
: 'keyup', keyId
: 0, keysym
: keysyms
.lookup(0xffe3)});
808 expect(evt
).to
.be
.deep
.equal({type
: 'keydown', keyId
: 0x41, keysym
: keysyms
.lookup(0x42), escape
: [0xffe9, 0xffe3]});
811 expect(evt
).to
.be
.deep
.equal({type
: 'keydown', keyId
: 0, keysym
: keysyms
.lookup(0xffe9)});
814 expect(evt
).to
.be
.deep
.equal({type
: 'keydown', keyId
: 0, keysym
: keysyms
.lookup(0xffe3)});
817 })({type
: 'keydown', keyId
: 0x41, keysym
: keysyms
.lookup(0x42), escape
: [0xffe9, 0xffe3]});
818 expect(times_called
).to
.be
.equal(5);
821 describe('Keyup', function() {
822 it('should pass through when a char modifier is down', function() {
823 var times_called
= 0;
824 EscapeModifiers(function(evt
) {
825 expect(times_called
).to
.be
.equal(0);
827 expect(evt
).to
.be
.deep
.equal({type
: 'keyup', keyId
: 0x41, keysym
: keysyms
.lookup(0x42), escape
: [0xfe03]});
828 })({type
: 'keyup', keyId
: 0x41, keysym
: keysyms
.lookup(0x42), escape
: [0xfe03]});
829 expect(times_called
).to
.be
.equal(1);
831 it('should pass through when a char modifier is not down', function() {
832 var times_called
= 0;
833 EscapeModifiers(function(evt
) {
834 expect(times_called
).to
.be
.equal(0);
836 expect(evt
).to
.be
.deep
.equal({type
: 'keyup', keyId
: 0x41, keysym
: keysyms
.lookup(0x42)});
837 })({type
: 'keyup', keyId
: 0x41, keysym
: keysyms
.lookup(0x42)});
838 expect(times_called
).to
.be
.equal(1);