]> git.proxmox.com Git - mirror_novnc.git/blame - tests/test.keyboard.js
Use fat arrow functions `const foo = () => { ... };` for callbacks
[mirror_novnc.git] / tests / test.keyboard.js
CommitLineData
2b5f94fa 1const expect = chai.expect;
f00b6fb6 2
0aaf59c2
SM
3import sinon from '../vendor/sinon.js';
4
c1e2785f 5import Keyboard from '../core/input/keyboard.js';
59ef2916 6import * as browser from '../core/util/browser.js';
099eb856 7
f7363fd2 8describe('Key Event Handling', function() {
f00b6fb6 9 "use strict";
f00b6fb6 10
f7363fd2
PO
11 // The real KeyboardEvent constructor might not work everywhere we
12 // want to run these tests
13 function keyevent(typeArg, KeyboardEventInit) {
2b5f94fa
JD
14 const e = { type: typeArg };
15 for (let key in KeyboardEventInit) {
f7363fd2
PO
16 e[key] = KeyboardEventInit[key];
17 }
18 e.stopPropagation = sinon.spy();
19 e.preventDefault = sinon.spy();
20 return e;
8727f598 21 }
f00b6fb6 22
f7363fd2
PO
23 describe('Decode Keyboard Events', function() {
24 it('should decode keydown events', function(done) {
59ef2916 25 if (browser.isIE() || browser.isEdge()) this.skip();
2b5f94fa 26 const kbd = new Keyboard(document);
651c23ec 27 kbd.onkeyevent = (keysym, code, down) => {
f7363fd2
PO
28 expect(keysym).to.be.equal(0x61);
29 expect(code).to.be.equal('KeyA');
30 expect(down).to.be.equal(true);
31 done();
747b4623 32 };
f7363fd2
PO
33 kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', key: 'a'}));
34 });
35 it('should decode keyup events', function(done) {
59ef2916 36 if (browser.isIE() || browser.isEdge()) this.skip();
2b5f94fa
JD
37 let calls = 0;
38 const kbd = new Keyboard(document);
651c23ec 39 kbd.onkeyevent = (keysym, code, down) => {
f7363fd2
PO
40 expect(keysym).to.be.equal(0x61);
41 expect(code).to.be.equal('KeyA');
42 if (calls++ === 1) {
43 expect(down).to.be.equal(false);
44 done();
45 }
747b4623 46 };
f7363fd2
PO
47 kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', key: 'a'}));
48 kbd._handleKeyUp(keyevent('keyup', {code: 'KeyA', key: 'a'}));
49 });
50
51 describe('Legacy keypress Events', function() {
52 it('should wait for keypress when needed', function() {
2b5f94fa 53 const kbd = new Keyboard(document);
747b4623 54 kbd.onkeyevent = sinon.spy();
f7363fd2 55 kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', keyCode: 0x41}));
747b4623 56 expect(kbd.onkeyevent).to.not.have.been.called;
f7363fd2
PO
57 });
58 it('should decode keypress events', function(done) {
2b5f94fa 59 const kbd = new Keyboard(document);
651c23ec 60 kbd.onkeyevent = (keysym, code, down) => {
f7363fd2
PO
61 expect(keysym).to.be.equal(0x61);
62 expect(code).to.be.equal('KeyA');
63 expect(down).to.be.equal(true);
64 done();
747b4623 65 };
f7363fd2
PO
66 kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', keyCode: 0x41}));
67 kbd._handleKeyPress(keyevent('keypress', {code: 'KeyA', charCode: 0x61}));
f00b6fb6 68 });
9fce233d 69 it('should ignore keypress with different code', function() {
2b5f94fa 70 const kbd = new Keyboard(document);
747b4623 71 kbd.onkeyevent = sinon.spy();
9fce233d
PO
72 kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', keyCode: 0x41}));
73 kbd._handleKeyPress(keyevent('keypress', {code: 'KeyB', charCode: 0x61}));
747b4623 74 expect(kbd.onkeyevent).to.not.have.been.called;
9fce233d
PO
75 });
76 it('should handle keypress with missing code', function(done) {
2b5f94fa 77 const kbd = new Keyboard(document);
651c23ec 78 kbd.onkeyevent = (keysym, code, down) => {
9fce233d
PO
79 expect(keysym).to.be.equal(0x61);
80 expect(code).to.be.equal('KeyA');
81 expect(down).to.be.equal(true);
82 done();
747b4623 83 };
9fce233d
PO
84 kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', keyCode: 0x41}));
85 kbd._handleKeyPress(keyevent('keypress', {charCode: 0x61}));
86 });
7cac5c8e 87 it('should guess key if no keypress and numeric key', function(done) {
2b5f94fa 88 const kbd = new Keyboard(document);
651c23ec 89 kbd.onkeyevent = (keysym, code, down) => {
7cac5c8e
PO
90 expect(keysym).to.be.equal(0x32);
91 expect(code).to.be.equal('Digit2');
92 expect(down).to.be.equal(true);
93 done();
747b4623 94 };
7cac5c8e
PO
95 kbd._handleKeyDown(keyevent('keydown', {code: 'Digit2', keyCode: 0x32}));
96 });
97 it('should guess key if no keypress and alpha key', function(done) {
2b5f94fa 98 const kbd = new Keyboard(document);
651c23ec 99 kbd.onkeyevent = (keysym, code, down) => {
7cac5c8e
PO
100 expect(keysym).to.be.equal(0x61);
101 expect(code).to.be.equal('KeyA');
102 expect(down).to.be.equal(true);
103 done();
747b4623 104 };
7cac5c8e
PO
105 kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', keyCode: 0x41, shiftKey: false}));
106 });
107 it('should guess key if no keypress and alpha key (with shift)', function(done) {
2b5f94fa 108 const kbd = new Keyboard(document);
651c23ec 109 kbd.onkeyevent = (keysym, code, down) => {
7cac5c8e
PO
110 expect(keysym).to.be.equal(0x41);
111 expect(code).to.be.equal('KeyA');
112 expect(down).to.be.equal(true);
113 done();
747b4623 114 };
7cac5c8e
PO
115 kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', keyCode: 0x41, shiftKey: true}));
116 });
117 it('should not guess key if no keypress and unknown key', function(done) {
2b5f94fa 118 const kbd = new Keyboard(document);
651c23ec 119 kbd.onkeyevent = (keysym, code, down) => {
7cac5c8e
PO
120 expect(keysym).to.be.equal(0);
121 expect(code).to.be.equal('KeyA');
122 expect(down).to.be.equal(true);
123 done();
747b4623 124 };
7cac5c8e
PO
125 kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', keyCode: 0x09}));
126 });
f00b6fb6 127 });
f00b6fb6 128
f7363fd2 129 describe('suppress the right events at the right time', function() {
099eb856 130 beforeEach(function () {
59ef2916 131 if (browser.isIE() || browser.isEdge()) this.skip();
099eb856 132 });
f7363fd2 133 it('should suppress anything with a valid key', function() {
2b5f94fa
JD
134 const kbd = new Keyboard(document, {});
135 const evt1 = keyevent('keydown', {code: 'KeyA', key: 'a'});
8727f598
JD
136 kbd._handleKeyDown(evt1);
137 expect(evt1.preventDefault).to.have.been.called;
2b5f94fa 138 const evt2 = keyevent('keyup', {code: 'KeyA', key: 'a'});
8727f598
JD
139 kbd._handleKeyUp(evt2);
140 expect(evt2.preventDefault).to.have.been.called;
f7363fd2
PO
141 });
142 it('should not suppress keys without key', function() {
2b5f94fa
JD
143 const kbd = new Keyboard(document, {});
144 const evt = keyevent('keydown', {code: 'KeyA', keyCode: 0x41});
f7363fd2
PO
145 kbd._handleKeyDown(evt);
146 expect(evt.preventDefault).to.not.have.been.called;
147 });
148 it('should suppress the following keypress event', function() {
2b5f94fa
JD
149 const kbd = new Keyboard(document, {});
150 const evt1 = keyevent('keydown', {code: 'KeyA', keyCode: 0x41});
8727f598 151 kbd._handleKeyDown(evt1);
2b5f94fa 152 const evt2 = keyevent('keypress', {code: 'KeyA', charCode: 0x41});
8727f598
JD
153 kbd._handleKeyPress(evt2);
154 expect(evt2.preventDefault).to.have.been.called;
f00b6fb6 155 });
156 });
f00b6fb6 157 });
158
9e99ce12
PO
159 describe('Fake keyup', function() {
160 it('should fake keyup events for virtual keyboards', function(done) {
59ef2916 161 if (browser.isIE() || browser.isEdge()) this.skip();
2b5f94fa
JD
162 let count = 0;
163 const kbd = new Keyboard(document);
651c23ec 164 kbd.onkeyevent = (keysym, code, down) => {
9e99ce12
PO
165 switch (count++) {
166 case 0:
167 expect(keysym).to.be.equal(0x61);
168 expect(code).to.be.equal('Unidentified');
169 expect(down).to.be.equal(true);
170 break;
171 case 1:
172 expect(keysym).to.be.equal(0x61);
173 expect(code).to.be.equal('Unidentified');
174 expect(down).to.be.equal(false);
175 done();
176 }
747b4623 177 };
9e99ce12
PO
178 kbd._handleKeyDown(keyevent('keydown', {code: 'Unidentified', key: 'a'}));
179 });
180
181 describe('iOS', function() {
2b5f94fa 182 let origNavigator;
9e99ce12
PO
183 beforeEach(function () {
184 // window.navigator is a protected read-only property in many
185 // environments, so we need to redefine it whilst running these
186 // tests.
187 origNavigator = Object.getOwnPropertyDescriptor(window, "navigator");
188 if (origNavigator === undefined) {
189 // Object.getOwnPropertyDescriptor() doesn't work
190 // properly in any version of IE
191 this.skip();
192 }
193
194 Object.defineProperty(window, "navigator", {value: {}});
195 if (window.navigator.platform !== undefined) {
196 // Object.defineProperty() doesn't work properly in old
197 // versions of Chrome
198 this.skip();
199 }
200
201 window.navigator.platform = "iPhone 9.0";
202 });
203 afterEach(function () {
204 Object.defineProperty(window, "navigator", origNavigator);
205 });
206
207 it('should fake keyup events on iOS', function(done) {
59ef2916 208 if (browser.isIE() || browser.isEdge()) this.skip();
2b5f94fa
JD
209 let count = 0;
210 const kbd = new Keyboard(document);
651c23ec 211 kbd.onkeyevent = (keysym, code, down) => {
9e99ce12
PO
212 switch (count++) {
213 case 0:
214 expect(keysym).to.be.equal(0x61);
215 expect(code).to.be.equal('KeyA');
216 expect(down).to.be.equal(true);
217 break;
218 case 1:
219 expect(keysym).to.be.equal(0x61);
220 expect(code).to.be.equal('KeyA');
221 expect(down).to.be.equal(false);
222 done();
223 }
747b4623 224 };
9e99ce12
PO
225 kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', key: 'a'}));
226 });
227 });
228 });
229
f00b6fb6 230 describe('Track Key State', function() {
099eb856 231 beforeEach(function () {
59ef2916 232 if (browser.isIE() || browser.isEdge()) this.skip();
099eb856 233 });
f7363fd2 234 it('should send release using the same keysym as the press', function(done) {
2b5f94fa 235 const kbd = new Keyboard(document);
651c23ec 236 kbd.onkeyevent = (keysym, code, down) => {
f7363fd2
PO
237 expect(keysym).to.be.equal(0x61);
238 expect(code).to.be.equal('KeyA');
239 if (!down) {
240 done();
241 }
747b4623 242 };
f7363fd2
PO
243 kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', key: 'a'}));
244 kbd._handleKeyUp(keyevent('keyup', {code: 'KeyA', key: 'b'}));
f00b6fb6 245 });
ae820533 246 it('should send the same keysym for multiple presses', function() {
2b5f94fa
JD
247 let count = 0;
248 const kbd = new Keyboard(document);
651c23ec 249 kbd.onkeyevent = (keysym, code, down) => {
ae820533
PO
250 expect(keysym).to.be.equal(0x61);
251 expect(code).to.be.equal('KeyA');
252 expect(down).to.be.equal(true);
253 count++;
747b4623 254 };
ae820533
PO
255 kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', key: 'a'}));
256 kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', key: 'b'}));
257 expect(count).to.be.equal(2);
258 });
f7363fd2 259 it('should do nothing on keyup events if no keys are down', function() {
2b5f94fa 260 const kbd = new Keyboard(document);
747b4623 261 kbd.onkeyevent = sinon.spy();
f7363fd2 262 kbd._handleKeyUp(keyevent('keyup', {code: 'KeyA', key: 'a'}));
747b4623 263 expect(kbd.onkeyevent).to.not.have.been.called;
f7363fd2 264 });
7e79dfe4
PO
265
266 describe('Legacy Events', function() {
267 it('should track keys using keyCode if no code', function(done) {
2b5f94fa 268 const kbd = new Keyboard(document);
651c23ec 269 kbd.onkeyevent = (keysym, code, down) => {
7e79dfe4
PO
270 expect(keysym).to.be.equal(0x61);
271 expect(code).to.be.equal('Platform65');
272 if (!down) {
273 done();
274 }
747b4623 275 };
7e79dfe4
PO
276 kbd._handleKeyDown(keyevent('keydown', {keyCode: 65, key: 'a'}));
277 kbd._handleKeyUp(keyevent('keyup', {keyCode: 65, key: 'b'}));
278 });
4093c37f 279 it('should ignore compositing code', function() {
2b5f94fa 280 const kbd = new Keyboard(document);
651c23ec 281 kbd.onkeyevent = (keysym, code, down) => {
4093c37f
PO
282 expect(keysym).to.be.equal(0x61);
283 expect(code).to.be.equal('Unidentified');
747b4623 284 };
4093c37f
PO
285 kbd._handleKeyDown(keyevent('keydown', {keyCode: 229, key: 'a'}));
286 });
7e79dfe4 287 it('should track keys using keyIdentifier if no code', function(done) {
2b5f94fa 288 const kbd = new Keyboard(document);
651c23ec 289 kbd.onkeyevent = (keysym, code, down) => {
7e79dfe4
PO
290 expect(keysym).to.be.equal(0x61);
291 expect(code).to.be.equal('Platform65');
292 if (!down) {
293 done();
294 }
747b4623 295 };
7e79dfe4
PO
296 kbd._handleKeyDown(keyevent('keydown', {keyIdentifier: 'U+0041', key: 'a'}));
297 kbd._handleKeyUp(keyevent('keyup', {keyIdentifier: 'U+0041', key: 'b'}));
298 });
299 });
f7363fd2 300 });
f00b6fb6 301
bf43c263 302 describe('Shuffle modifiers on macOS', function() {
2b5f94fa 303 let origNavigator;
bf43c263
PO
304 beforeEach(function () {
305 // window.navigator is a protected read-only property in many
306 // environments, so we need to redefine it whilst running these
307 // tests.
308 origNavigator = Object.getOwnPropertyDescriptor(window, "navigator");
309 if (origNavigator === undefined) {
310 // Object.getOwnPropertyDescriptor() doesn't work
311 // properly in any version of IE
312 this.skip();
313 }
314
315 Object.defineProperty(window, "navigator", {value: {}});
316 if (window.navigator.platform !== undefined) {
317 // Object.defineProperty() doesn't work properly in old
318 // versions of Chrome
319 this.skip();
320 }
321
322 window.navigator.platform = "Mac x86_64";
323 });
324 afterEach(function () {
325 Object.defineProperty(window, "navigator", origNavigator);
326 });
327
328 it('should change Alt to AltGraph', function() {
2b5f94fa
JD
329 let count = 0;
330 const kbd = new Keyboard(document);
651c23ec 331 kbd.onkeyevent = (keysym, code, down) => {
bf43c263
PO
332 switch (count++) {
333 case 0:
334 expect(keysym).to.be.equal(0xFF7E);
335 expect(code).to.be.equal('AltLeft');
336 break;
337 case 1:
338 expect(keysym).to.be.equal(0xFE03);
339 expect(code).to.be.equal('AltRight');
340 break;
341 }
747b4623 342 };
9782d4a3
PO
343 kbd._handleKeyDown(keyevent('keydown', {code: 'AltLeft', key: 'Alt', location: 1}));
344 kbd._handleKeyDown(keyevent('keydown', {code: 'AltRight', key: 'Alt', location: 2}));
bf43c263
PO
345 expect(count).to.be.equal(2);
346 });
347 it('should change left Super to Alt', function(done) {
2b5f94fa 348 const kbd = new Keyboard(document);
651c23ec 349 kbd.onkeyevent = (keysym, code, down) => {
bf43c263
PO
350 expect(keysym).to.be.equal(0xFFE9);
351 expect(code).to.be.equal('MetaLeft');
352 done();
747b4623 353 };
9782d4a3 354 kbd._handleKeyDown(keyevent('keydown', {code: 'MetaLeft', key: 'Meta', location: 1}));
bf43c263
PO
355 });
356 it('should change right Super to left Super', function(done) {
2b5f94fa 357 const kbd = new Keyboard(document);
651c23ec 358 kbd.onkeyevent = (keysym, code, down) => {
bf43c263
PO
359 expect(keysym).to.be.equal(0xFFEB);
360 expect(code).to.be.equal('MetaRight');
361 done();
747b4623 362 };
9782d4a3 363 kbd._handleKeyDown(keyevent('keydown', {code: 'MetaRight', key: 'Meta', location: 2}));
bf43c263
PO
364 });
365 });
366
367 describe('Escape AltGraph on Windows', function() {
2b5f94fa 368 let origNavigator;
f7363fd2
PO
369 beforeEach(function () {
370 // window.navigator is a protected read-only property in many
371 // environments, so we need to redefine it whilst running these
372 // tests.
373 origNavigator = Object.getOwnPropertyDescriptor(window, "navigator");
374 if (origNavigator === undefined) {
375 // Object.getOwnPropertyDescriptor() doesn't work
376 // properly in any version of IE
377 this.skip();
378 }
379
380 Object.defineProperty(window, "navigator", {value: {}});
381 if (window.navigator.platform !== undefined) {
382 // Object.defineProperty() doesn't work properly in old
383 // versions of Chrome
384 this.skip();
385 }
386
387 window.navigator.platform = "Windows x86_64";
b22c9ef9
PO
388
389 this.clock = sinon.useFakeTimers();
f7363fd2
PO
390 });
391 afterEach(function () {
392 Object.defineProperty(window, "navigator", origNavigator);
b22c9ef9 393 this.clock.restore();
f7363fd2
PO
394 });
395
b22c9ef9 396 it('should supress ControlLeft until it knows if it is AltGr', function () {
2b5f94fa 397 const kbd = new Keyboard(document);
b22c9ef9 398 kbd.onkeyevent = sinon.spy();
9782d4a3 399 kbd._handleKeyDown(keyevent('keydown', {code: 'ControlLeft', key: 'Control', location: 1}));
b22c9ef9 400 expect(kbd.onkeyevent).to.not.have.been.called;
f7363fd2 401 });
b22c9ef9
PO
402
403 it('should not trigger on repeating ControlLeft', function () {
2b5f94fa 404 const kbd = new Keyboard(document);
b22c9ef9 405 kbd.onkeyevent = sinon.spy();
9782d4a3 406 kbd._handleKeyDown(keyevent('keydown', {code: 'ControlLeft', key: 'Control', location: 1}));
b22c9ef9
PO
407 kbd._handleKeyDown(keyevent('keydown', {code: 'ControlLeft', key: 'Control', location: 1}));
408 expect(kbd.onkeyevent).to.have.been.calledTwice;
409 expect(kbd.onkeyevent.firstCall).to.have.been.calledWith(0xffe3, "ControlLeft", true);
410 expect(kbd.onkeyevent.secondCall).to.have.been.calledWith(0xffe3, "ControlLeft", true);
f7363fd2 411 });
b22c9ef9
PO
412
413 it('should not supress ControlRight', function () {
2b5f94fa 414 const kbd = new Keyboard(document);
b22c9ef9
PO
415 kbd.onkeyevent = sinon.spy();
416 kbd._handleKeyDown(keyevent('keydown', {code: 'ControlRight', key: 'Control', location: 2}));
417 expect(kbd.onkeyevent).to.have.been.calledOnce;
418 expect(kbd.onkeyevent).to.have.been.calledWith(0xffe4, "ControlRight", true);
419 });
420
421 it('should release ControlLeft after 100 ms', function () {
2b5f94fa 422 const kbd = new Keyboard(document);
b22c9ef9 423 kbd.onkeyevent = sinon.spy();
9782d4a3 424 kbd._handleKeyDown(keyevent('keydown', {code: 'ControlLeft', key: 'Control', location: 1}));
b22c9ef9
PO
425 expect(kbd.onkeyevent).to.not.have.been.called;
426 this.clock.tick(100);
427 expect(kbd.onkeyevent).to.have.been.calledOnce;
428 expect(kbd.onkeyevent).to.have.been.calledWith(0xffe3, "ControlLeft", true);
429 });
430
431 it('should release ControlLeft on other key press', function () {
2b5f94fa 432 const kbd = new Keyboard(document);
b22c9ef9
PO
433 kbd.onkeyevent = sinon.spy();
434 kbd._handleKeyDown(keyevent('keydown', {code: 'ControlLeft', key: 'Control', location: 1}));
435 expect(kbd.onkeyevent).to.not.have.been.called;
436 kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', key: 'a'}));
437 expect(kbd.onkeyevent).to.have.been.calledTwice;
438 expect(kbd.onkeyevent.firstCall).to.have.been.calledWith(0xffe3, "ControlLeft", true);
439 expect(kbd.onkeyevent.secondCall).to.have.been.calledWith(0x61, "KeyA", true);
440
441 // Check that the timer is properly dead
442 kbd.onkeyevent.reset();
443 this.clock.tick(100);
444 expect(kbd.onkeyevent).to.not.have.been.called;
445 });
446
447 it('should release ControlLeft on other key release', function () {
2b5f94fa 448 const kbd = new Keyboard(document);
b22c9ef9
PO
449 kbd.onkeyevent = sinon.spy();
450 kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', key: 'a'}));
9782d4a3 451 kbd._handleKeyDown(keyevent('keydown', {code: 'ControlLeft', key: 'Control', location: 1}));
b22c9ef9
PO
452 expect(kbd.onkeyevent).to.have.been.calledOnce;
453 expect(kbd.onkeyevent.firstCall).to.have.been.calledWith(0x61, "KeyA", true);
454 kbd._handleKeyUp(keyevent('keyup', {code: 'KeyA', key: 'a'}));
455 expect(kbd.onkeyevent).to.have.been.calledThrice;
456 expect(kbd.onkeyevent.secondCall).to.have.been.calledWith(0xffe3, "ControlLeft", true);
457 expect(kbd.onkeyevent.thirdCall).to.have.been.calledWith(0x61, "KeyA", false);
458
459 // Check that the timer is properly dead
460 kbd.onkeyevent.reset();
461 this.clock.tick(100);
462 expect(kbd.onkeyevent).to.not.have.been.called;
463 });
464
465 it('should generate AltGraph for quick Ctrl+Alt sequence', function () {
2b5f94fa 466 const kbd = new Keyboard(document);
b22c9ef9
PO
467 kbd.onkeyevent = sinon.spy();
468 kbd._handleKeyDown(keyevent('keydown', {code: 'ControlLeft', key: 'Control', location: 1, timeStamp: Date.now()}));
469 this.clock.tick(20);
470 kbd._handleKeyDown(keyevent('keydown', {code: 'AltRight', key: 'Alt', location: 2, timeStamp: Date.now()}));
471 expect(kbd.onkeyevent).to.have.been.calledOnce;
472 expect(kbd.onkeyevent).to.have.been.calledWith(0xfe03, 'AltRight', true);
473
474 // Check that the timer is properly dead
475 kbd.onkeyevent.reset();
476 this.clock.tick(100);
477 expect(kbd.onkeyevent).to.not.have.been.called;
478 });
479
480 it('should generate Ctrl, Alt for slow Ctrl+Alt sequence', function () {
2b5f94fa 481 const kbd = new Keyboard(document);
b22c9ef9
PO
482 kbd.onkeyevent = sinon.spy();
483 kbd._handleKeyDown(keyevent('keydown', {code: 'ControlLeft', key: 'Control', location: 1, timeStamp: Date.now()}));
484 this.clock.tick(60);
485 kbd._handleKeyDown(keyevent('keydown', {code: 'AltRight', key: 'Alt', location: 2, timeStamp: Date.now()}));
486 expect(kbd.onkeyevent).to.have.been.calledTwice;
487 expect(kbd.onkeyevent.firstCall).to.have.been.calledWith(0xffe3, "ControlLeft", true);
488 expect(kbd.onkeyevent.secondCall).to.have.been.calledWith(0xffea, "AltRight", true);
489
490 // Check that the timer is properly dead
491 kbd.onkeyevent.reset();
492 this.clock.tick(100);
493 expect(kbd.onkeyevent).to.not.have.been.called;
494 });
495
496 it('should pass through single Alt', function () {
2b5f94fa 497 const kbd = new Keyboard(document);
b22c9ef9
PO
498 kbd.onkeyevent = sinon.spy();
499 kbd._handleKeyDown(keyevent('keydown', {code: 'AltRight', key: 'Alt', location: 2}));
500 expect(kbd.onkeyevent).to.have.been.calledOnce;
501 expect(kbd.onkeyevent).to.have.been.calledWith(0xffea, 'AltRight', true);
502 });
503
504 it('should pass through single AltGr', function () {
2b5f94fa 505 const kbd = new Keyboard(document);
b22c9ef9
PO
506 kbd.onkeyevent = sinon.spy();
507 kbd._handleKeyDown(keyevent('keydown', {code: 'AltRight', key: 'AltGraph', location: 2}));
508 expect(kbd.onkeyevent).to.have.been.calledOnce;
509 expect(kbd.onkeyevent).to.have.been.calledWith(0xfe03, 'AltRight', true);
f00b6fb6 510 });
511 });
512});