]>
git.proxmox.com Git - mirror_novnc.git/blob - tests/test.keyboard.js
1 var assert
= chai
.assert
;
2 var expect
= chai
.expect
;
4 import keysyms
from '../core/input/keysymdef.js';
5 import * as KeyboardUtil
from '../core/input/util.js';
7 /* jshint newcap: false, expr: true */
8 describe('Key Event Pipeline Stages', function() {
10 describe('Decode Keyboard Events', function() {
11 it('should pass events to the next stage', function(done
) {
12 KeyboardUtil
.KeyEventDecoder(KeyboardUtil
.ModifierSync(), function(evt
) {
13 expect(evt
).to
.be
.an
.object
;
15 }).keydown({code
: 'KeyA', key
: 'a'});
17 it('should pass the right keysym through', function(done
) {
18 KeyboardUtil
.KeyEventDecoder(KeyboardUtil
.ModifierSync(), function(evt
) {
19 expect(evt
.keysym
).to
.be
.deep
.equal(0x61);
21 }).keypress({code
: 'KeyA', key
: 'a'});
23 it('should pass the right keyid through', function(done
) {
24 KeyboardUtil
.KeyEventDecoder(KeyboardUtil
.ModifierSync(), function(evt
) {
25 expect(evt
).to
.have
.property('code', 'KeyA');
27 }).keydown({code
: 'KeyA', key
: 'a'});
29 it('should forward keydown events with the right type', function(done
) {
30 KeyboardUtil
.KeyEventDecoder(KeyboardUtil
.ModifierSync(), function(evt
) {
31 expect(evt
).to
.be
.deep
.equal({code
: 'KeyA', keysym
: 0x61, type
: 'keydown'});
33 }).keydown({code
: 'KeyA', key
: 'a'});
35 it('should forward keyup events with the right type', function(done
) {
36 KeyboardUtil
.KeyEventDecoder(KeyboardUtil
.ModifierSync(), function(evt
) {
37 expect(evt
).to
.be
.deep
.equal({code
: 'KeyA', keysym
: 0x61, type
: 'keyup'});
39 }).keyup({code
: 'KeyA', key
: 'a'});
41 it('should forward keypress events with the right type', function(done
) {
42 KeyboardUtil
.KeyEventDecoder(KeyboardUtil
.ModifierSync(), function(evt
) {
43 expect(evt
).to
.be
.deep
.equal({code
: 'KeyA', keysym
: 0x61, type
: 'keypress'});
45 }).keypress({code
: 'KeyA', key
: 'a'});
47 describe('suppress the right events at the right time', function() {
48 it('should suppress anything while a shortcut modifier is down', function() {
49 var obj
= KeyboardUtil
.KeyEventDecoder(KeyboardUtil
.ModifierSync(), function(evt
) {});
51 obj
.keydown({code
: 'ControlLeft'});
52 expect(obj
.keydown({code
: 'KeyA', key
: 'a'})).to
.be
.true;
53 expect(obj
.keydown({code
: 'Space', key
: ' '})).to
.be
.true;
54 expect(obj
.keydown({code
: 'Digit1', key
: '1'})).to
.be
.true;
55 expect(obj
.keydown({code
: 'IntlBackslash', key
: '<'})).to
.be
.true;
56 expect(obj
.keydown({code
: 'Semicolon', key
: 'ø'})).to
.be
.true;
58 it('should suppress non-character keys', function() {
59 var obj
= KeyboardUtil
.KeyEventDecoder(KeyboardUtil
.ModifierSync(), function(evt
) {});
61 expect(obj
.keydown({code
: 'Backspace'}), 'a').to
.be
.true;
62 expect(obj
.keydown({code
: 'Tab'}), 'b').to
.be
.true;
63 expect(obj
.keydown({code
: 'ControlLeft'}), 'd').to
.be
.true;
64 expect(obj
.keydown({code
: 'AltLeft'}), 'e').to
.be
.true;
66 it('should generate event for shift keydown', function() {
68 var obj
= KeyboardUtil
.KeyEventDecoder(KeyboardUtil
.ModifierSync(), function(evt
) {
69 expect(evt
).to
.have
.property('keysym');
71 }).keydown({code
: 'ShiftLeft'});
72 expect(called
).to
.be
.true;
74 it('should suppress character keys with key', function() {
75 var obj
= KeyboardUtil
.KeyEventDecoder(KeyboardUtil
.ModifierSync(), function(evt
) {});
77 expect(obj
.keydown({code
: 'KeyA', key
: 'a'})).to
.be
.true;
78 expect(obj
.keydown({code
: 'Digit1', key
: '1'})).to
.be
.true;
79 expect(obj
.keydown({code
: 'IntlBackslash', key
: '<'})).to
.be
.true;
80 expect(obj
.keydown({code
: 'Semicolon', key
: 'ø'})).to
.be
.true;
82 it('should not suppress character keys without key', function() {
83 var obj
= KeyboardUtil
.KeyEventDecoder(KeyboardUtil
.ModifierSync(), function(evt
) {});
85 expect(obj
.keydown({code
: 'KeyA'})).to
.be
.false;
86 expect(obj
.keydown({code
: 'Digit1'})).to
.be
.false;
87 expect(obj
.keydown({code
: 'IntlBackslash'})).to
.be
.false;
88 expect(obj
.keydown({code
: 'Semicolon'})).to
.be
.false;
91 describe('Keypress and keyup events', function() {
92 it('should always suppress event propagation', function() {
93 var obj
= KeyboardUtil
.KeyEventDecoder(KeyboardUtil
.ModifierSync(), function(evt
) {});
95 expect(obj
.keypress({code
: 'KeyA', key
: 'a'})).to
.be
.true;
96 expect(obj
.keypress({code
: 'IntlBackslash', key
: '<'})).to
.be
.true;
97 expect(obj
.keypress({code
: 'ControlLeft', key
: 'Control'})).to
.be
.true;
99 expect(obj
.keyup({code
: 'KeyA', key
: 'a'})).to
.be
.true;
100 expect(obj
.keyup({code
: 'IntlBackslash', key
: '<'})).to
.be
.true;
101 expect(obj
.keyup({code
: 'ControlLeft', key
: 'Control'})).to
.be
.true;
104 describe('mark events if a char modifier is down', function() {
105 it('should not mark modifiers on a keydown event', function() {
106 var times_called
= 0;
107 var obj
= KeyboardUtil
.KeyEventDecoder(KeyboardUtil
.ModifierSync([0xfe03]), function(evt
) {
108 switch (times_called
++) {
112 expect(evt
).to
.not
.have
.property('escape');
117 obj
.keydown({code
: 'AltRight', key
: 'AltGraph'})
118 obj
.keydown({code
: 'KeyA', key
: 'a'});
121 it('should indicate on events if a single-key char modifier is down', function(done
) {
122 var times_called
= 0;
123 var obj
= KeyboardUtil
.KeyEventDecoder(KeyboardUtil
.ModifierSync([0xfe03]), function(evt
) {
124 switch (times_called
++) {
128 expect(evt
).to
.be
.deep
.equal({
139 obj
.keydown({code
: 'AltRight', key
: 'AltGraph'})
140 obj
.keypress({code
: 'KeyA', key
: 'a'});
142 it('should indicate on events if a multi-key char modifier is down', function(done
) {
143 var times_called
= 0;
144 var obj
= KeyboardUtil
.KeyEventDecoder(KeyboardUtil
.ModifierSync([0xffe9, 0xffe3]), function(evt
) {
145 switch (times_called
++) {
151 expect(evt
).to
.be
.deep
.equal({
155 escape
: [0xffe9, 0xffe3]
162 obj
.keydown({code
: 'ControlLeft'});
163 obj
.keydown({code
: 'AltLeft'});
164 obj
.keypress({code
: 'KeyA', key
: 'a'});
166 it('should not consider a char modifier to be down on the modifier key itself', function() {
167 var obj
= KeyboardUtil
.KeyEventDecoder(KeyboardUtil
.ModifierSync([0xfe03]), function(evt
) {
168 expect(evt
).to
.not
.have
.property('escape');
171 obj
.keydown({code
: 'AltRight', key
: 'AltGraph'})
177 describe('Track Key State', function() {
178 it('should do nothing on keyup events if no keys are down', function() {
179 var obj
= KeyboardUtil
.TrackKeyState(function(evt
) {
180 expect(true).to
.be
.false;
182 obj({type
: 'keyup', code
: 'KeyA'});
184 it('should insert into the queue on keydown if no keys are down', function() {
185 var times_called
= 0;
187 var keysymsdown
= {};
188 var obj
= KeyboardUtil
.TrackKeyState(function(evt
) {
190 if (elem
.type
== 'keyup') {
191 expect(evt
).to
.have
.property('keysym');
192 expect (keysymsdown
[evt
.keysym
]).to
.not
.be
.undefined;
193 delete keysymsdown
[evt
.keysym
];
196 expect(evt
).to
.be
.deep
.equal(elem
);
197 expect (keysymsdown
[evt
.keysym
]).to
.not
.be
.undefined;
202 expect(elem
).to
.be
.null;
203 elem
= {type
: 'keydown', code
: 'KeyA', keysym
: 0x42};
204 keysymsdown
[0x42] = true;
206 expect(elem
).to
.be
.null;
207 elem
= {type
: 'keyup', code
: 'KeyA'};
209 expect(elem
).to
.be
.null;
210 expect(times_called
).to
.be
.equal(2);
212 it('should insert into the queue on keypress if no keys are down', function() {
213 var times_called
= 0;
215 var keysymsdown
= {};
216 var obj
= KeyboardUtil
.TrackKeyState(function(evt
) {
218 if (elem
.type
== 'keyup') {
219 expect(evt
).to
.have
.property('keysym');
220 expect (keysymsdown
[evt
.keysym
]).to
.not
.be
.undefined;
221 delete keysymsdown
[evt
.keysym
];
224 expect(evt
).to
.be
.deep
.equal(elem
);
225 expect (keysymsdown
[evt
.keysym
]).to
.not
.be
.undefined;
230 expect(elem
).to
.be
.null;
231 elem
= {type
: 'keypress', code
: 'KeyA', keysym
: 0x42};
232 keysymsdown
[0x42] = true;
234 expect(elem
).to
.be
.null;
235 elem
= {type
: 'keyup', code
: 'KeyA'};
237 expect(elem
).to
.be
.null;
238 expect(times_called
).to
.be
.equal(2);
240 it('should add keysym to last key entry if code matches', function() {
241 // this implies that a single keyup will release both keysyms
242 var times_called
= 0;
244 var keysymsdown
= {};
245 var obj
= KeyboardUtil
.TrackKeyState(function(evt
) {
247 if (elem
.type
== 'keyup') {
248 expect(evt
).to
.have
.property('keysym');
249 expect (keysymsdown
[evt
.keysym
]).to
.not
.be
.undefined;
250 delete keysymsdown
[evt
.keysym
];
253 expect(evt
).to
.be
.deep
.equal(elem
);
254 expect (keysymsdown
[evt
.keysym
]).to
.not
.be
.undefined;
259 expect(elem
).to
.be
.null;
260 elem
= {type
: 'keypress', code
: 'KeyA', keysym
: 0x42};
261 keysymsdown
[0x42] = true;
263 expect(elem
).to
.be
.null;
264 elem
= {type
: 'keypress', code
: 'KeyA', keysym
: 0x43};
265 keysymsdown
[0x43] = true;
267 expect(elem
).to
.be
.null;
268 elem
= {type
: 'keyup', code
: 'KeyA'};
270 expect(times_called
).to
.be
.equal(4);
272 it('should create new key entry if code matches and keysym does not', function() {
273 // this implies that a single keyup will release both keysyms
274 var times_called
= 0;
276 var keysymsdown
= {};
277 var obj
= KeyboardUtil
.TrackKeyState(function(evt
) {
279 if (elem
.type
== 'keyup') {
280 expect(evt
).to
.have
.property('keysym');
281 expect (keysymsdown
[evt
.keysym
]).to
.not
.be
.undefined;
282 delete keysymsdown
[evt
.keysym
];
285 expect(evt
).to
.be
.deep
.equal(elem
);
286 expect (keysymsdown
[evt
.keysym
]).to
.not
.be
.undefined;
291 expect(elem
).to
.be
.null;
292 elem
= {type
: 'keydown', code
: 'Unidentified', keysym
: 0x42};
293 keysymsdown
[0x42] = true;
295 expect(elem
).to
.be
.null;
296 elem
= {type
: 'keydown', code
: 'Unidentified', keysym
: 0x43};
297 keysymsdown
[0x43] = true;
299 expect(times_called
).to
.be
.equal(2);
300 expect(elem
).to
.be
.null;
301 elem
= {type
: 'keyup', code
: 'Unidentified'};
303 expect(times_called
).to
.be
.equal(3);
304 elem
= {type
: 'keyup', code
: 'Unidentified'};
306 expect(times_called
).to
.be
.equal(4);
308 it('should merge key entry if codes are zero and keysyms match', function() {
309 // this implies that a single keyup will release both keysyms
310 var times_called
= 0;
312 var keysymsdown
= {};
313 var obj
= KeyboardUtil
.TrackKeyState(function(evt
) {
315 if (elem
.type
== 'keyup') {
316 expect(evt
).to
.have
.property('keysym');
317 expect (keysymsdown
[evt
.keysym
]).to
.not
.be
.undefined;
318 delete keysymsdown
[evt
.keysym
];
321 expect(evt
).to
.be
.deep
.equal(elem
);
322 expect (keysymsdown
[evt
.keysym
]).to
.not
.be
.undefined;
327 expect(elem
).to
.be
.null;
328 elem
= {type
: 'keydown', code
: 'Unidentified', keysym
: 0x42};
329 keysymsdown
[0x42] = true;
331 expect(elem
).to
.be
.null;
332 elem
= {type
: 'keydown', code
: 'Unidentified', keysym
: 0x42};
333 keysymsdown
[0x42] = true;
335 expect(times_called
).to
.be
.equal(2);
336 expect(elem
).to
.be
.null;
337 elem
= {type
: 'keyup', code
: 'Unidentified'};
339 expect(times_called
).to
.be
.equal(3);
341 it('should add keysym as separate entry if code does not match last event', function() {
342 // this implies that separate keyups are required
343 var times_called
= 0;
345 var keysymsdown
= {};
346 var obj
= KeyboardUtil
.TrackKeyState(function(evt
) {
348 if (elem
.type
== 'keyup') {
349 expect(evt
).to
.have
.property('keysym');
350 expect (keysymsdown
[evt
.keysym
]).to
.not
.be
.undefined;
351 delete keysymsdown
[evt
.keysym
];
354 expect(evt
).to
.be
.deep
.equal(elem
);
355 expect (keysymsdown
[evt
.keysym
]).to
.not
.be
.undefined;
360 expect(elem
).to
.be
.null;
361 elem
= {type
: 'keypress', code
: 'KeyA', keysym
: 0x42};
362 keysymsdown
[0x42] = true;
364 expect(elem
).to
.be
.null;
365 elem
= {type
: 'keypress', code
: 'KeyB', keysym
: 0x43};
366 keysymsdown
[0x43] = true;
368 expect(elem
).to
.be
.null;
369 elem
= {type
: 'keyup', code
: 'KeyA'};
371 expect(times_called
).to
.be
.equal(4);
372 elem
= {type
: 'keyup', code
: 'KeyB'};
374 expect(times_called
).to
.be
.equal(4);
376 it('should add keysym as separate entry if code does not match last event and first is zero', function() {
377 // this implies that separate keyups are required
378 var times_called
= 0;
380 var keysymsdown
= {};
381 var obj
= KeyboardUtil
.TrackKeyState(function(evt
) {
383 if (elem
.type
== 'keyup') {
384 expect(evt
).to
.have
.property('keysym');
385 expect (keysymsdown
[evt
.keysym
]).to
.not
.be
.undefined;
386 delete keysymsdown
[evt
.keysym
];
389 expect(evt
).to
.be
.deep
.equal(elem
);
390 expect (keysymsdown
[evt
.keysym
]).to
.not
.be
.undefined;
395 expect(elem
).to
.be
.null;
396 elem
= {type
: 'keydown', code
: 'Unidentified', keysym
: 0x42};
397 keysymsdown
[0x42] = true;
399 expect(elem
).to
.be
.null;
400 elem
= {type
: 'keydown', code
: 'KeyB', keysym
: 0x43};
401 keysymsdown
[0x43] = true;
403 expect(elem
).to
.be
.null;
404 expect(times_called
).to
.be
.equal(2);
405 elem
= {type
: 'keyup', code
: 'Unidentified'};
407 expect(times_called
).to
.be
.equal(3);
408 elem
= {type
: 'keyup', code
: 'KeyB'};
410 expect(times_called
).to
.be
.equal(4);
412 it('should add keysym as separate entry if code does not match last event and second is zero', function() {
413 // this implies that a separate keyups are required
414 var times_called
= 0;
416 var keysymsdown
= {};
417 var obj
= KeyboardUtil
.TrackKeyState(function(evt
) {
419 if (elem
.type
== 'keyup') {
420 expect(evt
).to
.have
.property('keysym');
421 expect (keysymsdown
[evt
.keysym
]).to
.not
.be
.undefined;
422 delete keysymsdown
[evt
.keysym
];
425 expect(evt
).to
.be
.deep
.equal(elem
);
426 expect (keysymsdown
[evt
.keysym
]).to
.not
.be
.undefined;
431 expect(elem
).to
.be
.null;
432 elem
= {type
: 'keydown', code
: 'KeyA', keysym
: 0x42};
433 keysymsdown
[0x42] = true;
435 expect(elem
).to
.be
.null;
436 elem
= {type
: 'keydown', code
: 'Unidentified', keysym
: 0x43};
437 keysymsdown
[0x43] = true;
439 expect(elem
).to
.be
.null;
440 elem
= {type
: 'keyup', code
: 'KeyA'};
442 expect(times_called
).to
.be
.equal(3);
443 elem
= {type
: 'keyup', code
: 'Unidentified'};
445 expect(times_called
).to
.be
.equal(4);
447 it('should pop matching key event on keyup', function() {
448 var times_called
= 0;
449 var obj
= KeyboardUtil
.TrackKeyState(function(evt
) {
450 switch (times_called
++) {
454 expect(evt
.type
).to
.be
.equal('keydown');
457 expect(evt
).to
.be
.deep
.equal({type
: 'keyup', code
: 'KeyB', keysym
: 0x62});
462 obj({type
: 'keydown', code
: 'KeyA', keysym
: 0x61});
463 obj({type
: 'keydown', code
: 'KeyB', keysym
: 0x62});
464 obj({type
: 'keydown', code
: 'KeyC', keysym
: 0x63});
465 obj({type
: 'keyup', code
: 'KeyB'});
466 expect(times_called
).to
.equal(4);
468 it('should pop the first zero keyevent on keyup with zero code', function() {
469 var times_called
= 0;
470 var obj
= KeyboardUtil
.TrackKeyState(function(evt
) {
471 switch (times_called
++) {
475 expect(evt
.type
).to
.be
.equal('keydown');
478 expect(evt
).to
.be
.deep
.equal({type
: 'keyup', code
: 'Unidentified', keysym
: 0x61});
483 obj({type
: 'keydown', code
: 'Unidentified', keysym
: 0x61});
484 obj({type
: 'keydown', code
: 'Unidentified', keysym
: 0x62});
485 obj({type
: 'keydown', code
: 'KeyA', keysym
: 0x63});
486 obj({type
: 'keyup', code
: 'Unidentified'});
487 expect(times_called
).to
.equal(4);
489 it('should pop the last keyevents keysym if no match is found for code', function() {
490 var times_called
= 0;
491 var obj
= KeyboardUtil
.TrackKeyState(function(evt
) {
492 switch (times_called
++) {
496 expect(evt
.type
).to
.be
.equal('keydown');
499 expect(evt
).to
.be
.deep
.equal({type
: 'keyup', code
: 'KeyD', keysym
: 0x63});
504 obj({type
: 'keydown', code
: 'KeyA', keysym
: 0x61});
505 obj({type
: 'keydown', code
: 'KeyB', keysym
: 0x62});
506 obj({type
: 'keydown', code
: 'KeyC', keysym
: 0x63});
507 obj({type
: 'keyup', code
: 'KeyD'});
508 expect(times_called
).to
.equal(4);
510 describe('Firefox sends keypress even when keydown is suppressed', function() {
511 it('should discard the keypress', function() {
512 var times_called
= 0;
513 var obj
= KeyboardUtil
.TrackKeyState(function(evt
) {
514 expect(times_called
).to
.be
.equal(0);
518 obj({type
: 'keydown', code
: 'KeyA', keysym
: 0x42});
519 expect(times_called
).to
.be
.equal(1);
520 obj({type
: 'keypress', code
: 'KeyA', keysym
: 0x43});
523 describe('releaseAll', function() {
524 it('should do nothing if no keys have been pressed', function() {
525 var times_called
= 0;
526 var obj
= KeyboardUtil
.TrackKeyState(function(evt
) {
529 obj({type
: 'releaseall'});
530 expect(times_called
).to
.be
.equal(0);
532 it('should release the keys that have been pressed', function() {
533 var times_called
= 0;
534 var obj
= KeyboardUtil
.TrackKeyState(function(evt
) {
535 switch (times_called
++) {
537 expect(evt
).to
.be
.deep
.equal({type
: 'keyup', code
: 'Unidentified', keysym
: 0x41});
540 expect(evt
).to
.be
.deep
.equal({type
: 'keyup', code
: 'Unidentified', keysym
: 0x42});
544 obj({type
: 'keydown', code
: 'KeyA', keysym
: 0x41});
545 obj({type
: 'keydown', code
: 'KeyB', keysym
: 0x42});
546 expect(times_called
).to
.be
.equal(2);
547 obj({type
: 'releaseall'});
548 expect(times_called
).to
.be
.equal(4);
549 obj({type
: 'releaseall'});
550 expect(times_called
).to
.be
.equal(4);
556 describe('Escape Modifiers', function() {
557 describe('Keydown', function() {
558 it('should pass through when a char modifier is not down', function() {
559 var times_called
= 0;
560 KeyboardUtil
.EscapeModifiers(function(evt
) {
561 expect(times_called
).to
.be
.equal(0);
563 expect(evt
).to
.be
.deep
.equal({type
: 'keydown', code
: 'KeyA', keysym
: 0x42});
564 })({type
: 'keydown', code
: 'KeyA', keysym
: 0x42});
565 expect(times_called
).to
.be
.equal(1);
567 it('should generate fake undo/redo events when a char modifier is down', function() {
568 var times_called
= 0;
569 KeyboardUtil
.EscapeModifiers(function(evt
) {
570 switch(times_called
++) {
572 expect(evt
).to
.be
.deep
.equal({type
: 'keyup', code
: 'Unidentified', keysym
: 0xffe9});
575 expect(evt
).to
.be
.deep
.equal({type
: 'keyup', code
: 'Unidentified', keysym
: 0xffe3});
578 expect(evt
).to
.be
.deep
.equal({type
: 'keydown', code
: 'KeyA', keysym
: 0x42, escape
: [0xffe9, 0xffe3]});
581 expect(evt
).to
.be
.deep
.equal({type
: 'keydown', code
: 'Unidentified', keysym
: 0xffe9});
584 expect(evt
).to
.be
.deep
.equal({type
: 'keydown', code
: 'Unidentified', keysym
: 0xffe3});
587 })({type
: 'keydown', code
: 'KeyA', keysym
: 0x42, escape
: [0xffe9, 0xffe3]});
588 expect(times_called
).to
.be
.equal(5);
591 describe('Keyup', function() {
592 it('should pass through when a char modifier is down', function() {
593 var times_called
= 0;
594 KeyboardUtil
.EscapeModifiers(function(evt
) {
595 expect(times_called
).to
.be
.equal(0);
597 expect(evt
).to
.be
.deep
.equal({type
: 'keyup', code
: 'KeyA', keysym
: 0x42, escape
: [0xfe03]});
598 })({type
: 'keyup', code
: 'KeyA', keysym
: 0x42, escape
: [0xfe03]});
599 expect(times_called
).to
.be
.equal(1);
601 it('should pass through when a char modifier is not down', function() {
602 var times_called
= 0;
603 KeyboardUtil
.EscapeModifiers(function(evt
) {
604 expect(times_called
).to
.be
.equal(0);
606 expect(evt
).to
.be
.deep
.equal({type
: 'keyup', code
: 'KeyA', keysym
: 0x42});
607 })({type
: 'keyup', code
: 'KeyA', keysym
: 0x42});
608 expect(times_called
).to
.be
.equal(1);