]>
Commit | Line | Data |
---|---|---|
2b5f94fa | 1 | const expect = chai.expect; |
f00b6fb6 | 2 | |
0aaf59c2 SM |
3 | import sinon from '../vendor/sinon.js'; |
4 | ||
c1e2785f | 5 | import Keyboard from '../core/input/keyboard.js'; |
59ef2916 | 6 | import * as browser from '../core/util/browser.js'; |
099eb856 | 7 | |
f7363fd2 | 8 | describe('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 | }); |