X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=tests%2Ftest.keyboard.js;h=c555b4fbfb96c1b200b3d9deb7ca2751cb69f856;hb=651c23ece37c1749936d2eb97939d121887720b9;hp=7fdeb8f9d1926dfda12258851b165bb102ecc290;hpb=0aaf59c2f941477b96d84b5f1ca33c39f9f202b2;p=mirror_novnc.git diff --git a/tests/test.keyboard.js b/tests/test.keyboard.js index 7fdeb8f..c555b4f 100644 --- a/tests/test.keyboard.js +++ b/tests/test.keyboard.js @@ -1,175 +1,167 @@ -var assert = chai.assert; -var expect = chai.expect; +const expect = chai.expect; import sinon from '../vendor/sinon.js'; import Keyboard from '../core/input/keyboard.js'; +import * as browser from '../core/util/browser.js'; -function isIE() { - return navigator && !!(/trident/i).exec(navigator.userAgent); -} -function isEdge() { - return navigator && !!(/edge/i).exec(navigator.userAgent); -} - -/* jshint newcap: false, expr: true */ describe('Key Event Handling', function() { "use strict"; // The real KeyboardEvent constructor might not work everywhere we // want to run these tests function keyevent(typeArg, KeyboardEventInit) { - var e = { type: typeArg }; - for (var key in KeyboardEventInit) { + const e = { type: typeArg }; + for (let key in KeyboardEventInit) { e[key] = KeyboardEventInit[key]; } e.stopPropagation = sinon.spy(); e.preventDefault = sinon.spy(); return e; - }; + } describe('Decode Keyboard Events', function() { it('should decode keydown events', function(done) { - if (isIE() || isEdge()) this.skip(); - var kbd = new Keyboard({ - onKeyEvent: function(keysym, code, down) { + if (browser.isIE() || browser.isEdge()) this.skip(); + const kbd = new Keyboard(document); + kbd.onkeyevent = (keysym, code, down) => { expect(keysym).to.be.equal(0x61); expect(code).to.be.equal('KeyA'); expect(down).to.be.equal(true); done(); - }}); + }; kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', key: 'a'})); }); it('should decode keyup events', function(done) { - if (isIE() || isEdge()) this.skip(); - var calls = 0; - var kbd = new Keyboard({ - onKeyEvent: function(keysym, code, down) { + if (browser.isIE() || browser.isEdge()) this.skip(); + let calls = 0; + const kbd = new Keyboard(document); + kbd.onkeyevent = (keysym, code, down) => { expect(keysym).to.be.equal(0x61); expect(code).to.be.equal('KeyA'); if (calls++ === 1) { expect(down).to.be.equal(false); done(); } - }}); + }; kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', key: 'a'})); kbd._handleKeyUp(keyevent('keyup', {code: 'KeyA', key: 'a'})); }); describe('Legacy keypress Events', function() { it('should wait for keypress when needed', function() { - var callback = sinon.spy(); - var kbd = new Keyboard({onKeyEvent: callback}); + const kbd = new Keyboard(document); + kbd.onkeyevent = sinon.spy(); kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', keyCode: 0x41})); - expect(callback).to.not.have.been.called; + expect(kbd.onkeyevent).to.not.have.been.called; }); it('should decode keypress events', function(done) { - var kbd = new Keyboard({ - onKeyEvent: function(keysym, code, down) { + const kbd = new Keyboard(document); + kbd.onkeyevent = (keysym, code, down) => { expect(keysym).to.be.equal(0x61); expect(code).to.be.equal('KeyA'); expect(down).to.be.equal(true); done(); - }}); + }; kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', keyCode: 0x41})); kbd._handleKeyPress(keyevent('keypress', {code: 'KeyA', charCode: 0x61})); }); it('should ignore keypress with different code', function() { - var callback = sinon.spy(); - var kbd = new Keyboard({onKeyEvent: callback}); + const kbd = new Keyboard(document); + kbd.onkeyevent = sinon.spy(); kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', keyCode: 0x41})); kbd._handleKeyPress(keyevent('keypress', {code: 'KeyB', charCode: 0x61})); - expect(callback).to.not.have.been.called; + expect(kbd.onkeyevent).to.not.have.been.called; }); it('should handle keypress with missing code', function(done) { - var kbd = new Keyboard({ - onKeyEvent: function(keysym, code, down) { + const kbd = new Keyboard(document); + kbd.onkeyevent = (keysym, code, down) => { expect(keysym).to.be.equal(0x61); expect(code).to.be.equal('KeyA'); expect(down).to.be.equal(true); done(); - }}); + }; kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', keyCode: 0x41})); kbd._handleKeyPress(keyevent('keypress', {charCode: 0x61})); }); it('should guess key if no keypress and numeric key', function(done) { - var kbd = new Keyboard({ - onKeyEvent: function(keysym, code, down) { + const kbd = new Keyboard(document); + kbd.onkeyevent = (keysym, code, down) => { expect(keysym).to.be.equal(0x32); expect(code).to.be.equal('Digit2'); expect(down).to.be.equal(true); done(); - }}); + }; kbd._handleKeyDown(keyevent('keydown', {code: 'Digit2', keyCode: 0x32})); }); it('should guess key if no keypress and alpha key', function(done) { - var kbd = new Keyboard({ - onKeyEvent: function(keysym, code, down) { + const kbd = new Keyboard(document); + kbd.onkeyevent = (keysym, code, down) => { expect(keysym).to.be.equal(0x61); expect(code).to.be.equal('KeyA'); expect(down).to.be.equal(true); done(); - }}); + }; kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', keyCode: 0x41, shiftKey: false})); }); it('should guess key if no keypress and alpha key (with shift)', function(done) { - var kbd = new Keyboard({ - onKeyEvent: function(keysym, code, down) { + const kbd = new Keyboard(document); + kbd.onkeyevent = (keysym, code, down) => { expect(keysym).to.be.equal(0x41); expect(code).to.be.equal('KeyA'); expect(down).to.be.equal(true); done(); - }}); + }; kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', keyCode: 0x41, shiftKey: true})); }); it('should not guess key if no keypress and unknown key', function(done) { - var kbd = new Keyboard({ - onKeyEvent: function(keysym, code, down) { + const kbd = new Keyboard(document); + kbd.onkeyevent = (keysym, code, down) => { expect(keysym).to.be.equal(0); expect(code).to.be.equal('KeyA'); expect(down).to.be.equal(true); done(); - }}); + }; kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', keyCode: 0x09})); }); }); describe('suppress the right events at the right time', function() { beforeEach(function () { - if (isIE() || isEdge()) this.skip(); + if (browser.isIE() || browser.isEdge()) this.skip(); }); it('should suppress anything with a valid key', function() { - var kbd = new Keyboard({}); - var evt = keyevent('keydown', {code: 'KeyA', key: 'a'}); - kbd._handleKeyDown(evt); - expect(evt.preventDefault).to.have.been.called; - evt = keyevent('keyup', {code: 'KeyA', key: 'a'}); - kbd._handleKeyUp(evt); - expect(evt.preventDefault).to.have.been.called; + const kbd = new Keyboard(document, {}); + const evt1 = keyevent('keydown', {code: 'KeyA', key: 'a'}); + kbd._handleKeyDown(evt1); + expect(evt1.preventDefault).to.have.been.called; + const evt2 = keyevent('keyup', {code: 'KeyA', key: 'a'}); + kbd._handleKeyUp(evt2); + expect(evt2.preventDefault).to.have.been.called; }); it('should not suppress keys without key', function() { - var kbd = new Keyboard({}); - var evt = keyevent('keydown', {code: 'KeyA', keyCode: 0x41}); + const kbd = new Keyboard(document, {}); + const evt = keyevent('keydown', {code: 'KeyA', keyCode: 0x41}); kbd._handleKeyDown(evt); expect(evt.preventDefault).to.not.have.been.called; }); it('should suppress the following keypress event', function() { - var kbd = new Keyboard({}); - var evt = keyevent('keydown', {code: 'KeyA', keyCode: 0x41}); - kbd._handleKeyDown(evt); - var evt = keyevent('keypress', {code: 'KeyA', charCode: 0x41}); - kbd._handleKeyPress(evt); - expect(evt.preventDefault).to.have.been.called; + const kbd = new Keyboard(document, {}); + const evt1 = keyevent('keydown', {code: 'KeyA', keyCode: 0x41}); + kbd._handleKeyDown(evt1); + const evt2 = keyevent('keypress', {code: 'KeyA', charCode: 0x41}); + kbd._handleKeyPress(evt2); + expect(evt2.preventDefault).to.have.been.called; }); }); }); describe('Fake keyup', function() { it('should fake keyup events for virtual keyboards', function(done) { - if (isIE() || isEdge()) this.skip(); - var count = 0; - var kbd = new Keyboard({ - onKeyEvent: function(keysym, code, down) { + if (browser.isIE() || browser.isEdge()) this.skip(); + let count = 0; + const kbd = new Keyboard(document); + kbd.onkeyevent = (keysym, code, down) => { switch (count++) { case 0: expect(keysym).to.be.equal(0x61); @@ -182,12 +174,12 @@ describe('Key Event Handling', function() { expect(down).to.be.equal(false); done(); } - }}); + }; kbd._handleKeyDown(keyevent('keydown', {code: 'Unidentified', key: 'a'})); }); describe('iOS', function() { - var origNavigator; + let origNavigator; beforeEach(function () { // window.navigator is a protected read-only property in many // environments, so we need to redefine it whilst running these @@ -213,10 +205,10 @@ describe('Key Event Handling', function() { }); it('should fake keyup events on iOS', function(done) { - if (isIE() || isEdge()) this.skip(); - var count = 0; - var kbd = new Keyboard({ - onKeyEvent: function(keysym, code, down) { + if (browser.isIE() || browser.isEdge()) this.skip(); + let count = 0; + const kbd = new Keyboard(document); + kbd.onkeyevent = (keysym, code, down) => { switch (count++) { case 0: expect(keysym).to.be.equal(0x61); @@ -229,7 +221,7 @@ describe('Key Event Handling', function() { expect(down).to.be.equal(false); done(); } - }}); + }; kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', key: 'a'})); }); }); @@ -237,70 +229,70 @@ describe('Key Event Handling', function() { describe('Track Key State', function() { beforeEach(function () { - if (isIE() || isEdge()) this.skip(); + if (browser.isIE() || browser.isEdge()) this.skip(); }); it('should send release using the same keysym as the press', function(done) { - var kbd = new Keyboard({ - onKeyEvent: function(keysym, code, down) { + const kbd = new Keyboard(document); + kbd.onkeyevent = (keysym, code, down) => { expect(keysym).to.be.equal(0x61); expect(code).to.be.equal('KeyA'); if (!down) { done(); } - }}); + }; kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', key: 'a'})); kbd._handleKeyUp(keyevent('keyup', {code: 'KeyA', key: 'b'})); }); it('should send the same keysym for multiple presses', function() { - var count = 0; - var kbd = new Keyboard({ - onKeyEvent: function(keysym, code, down) { + let count = 0; + const kbd = new Keyboard(document); + kbd.onkeyevent = (keysym, code, down) => { expect(keysym).to.be.equal(0x61); expect(code).to.be.equal('KeyA'); expect(down).to.be.equal(true); count++; - }}); + }; kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', key: 'a'})); kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', key: 'b'})); expect(count).to.be.equal(2); }); it('should do nothing on keyup events if no keys are down', function() { - var callback = sinon.spy(); - var kbd = new Keyboard({onKeyEvent: callback}); + const kbd = new Keyboard(document); + kbd.onkeyevent = sinon.spy(); kbd._handleKeyUp(keyevent('keyup', {code: 'KeyA', key: 'a'})); - expect(callback).to.not.have.been.called; + expect(kbd.onkeyevent).to.not.have.been.called; }); describe('Legacy Events', function() { it('should track keys using keyCode if no code', function(done) { - var kbd = new Keyboard({ - onKeyEvent: function(keysym, code, down) { + const kbd = new Keyboard(document); + kbd.onkeyevent = (keysym, code, down) => { expect(keysym).to.be.equal(0x61); expect(code).to.be.equal('Platform65'); if (!down) { done(); } - }}); + }; kbd._handleKeyDown(keyevent('keydown', {keyCode: 65, key: 'a'})); kbd._handleKeyUp(keyevent('keyup', {keyCode: 65, key: 'b'})); }); it('should ignore compositing code', function() { - var kbd = new Keyboard({ - onKeyEvent: function(keysym, code, down) { + const kbd = new Keyboard(document); + kbd.onkeyevent = (keysym, code, down) => { expect(keysym).to.be.equal(0x61); expect(code).to.be.equal('Unidentified'); - }}); + }; kbd._handleKeyDown(keyevent('keydown', {keyCode: 229, key: 'a'})); }); it('should track keys using keyIdentifier if no code', function(done) { - var kbd = new Keyboard({ - onKeyEvent: function(keysym, code, down) { + const kbd = new Keyboard(document); + kbd.onkeyevent = (keysym, code, down) => { expect(keysym).to.be.equal(0x61); expect(code).to.be.equal('Platform65'); if (!down) { done(); } - }}); + }; kbd._handleKeyDown(keyevent('keydown', {keyIdentifier: 'U+0041', key: 'a'})); kbd._handleKeyUp(keyevent('keyup', {keyIdentifier: 'U+0041', key: 'b'})); }); @@ -308,7 +300,7 @@ describe('Key Event Handling', function() { }); describe('Shuffle modifiers on macOS', function() { - var origNavigator; + let origNavigator; beforeEach(function () { // window.navigator is a protected read-only property in many // environments, so we need to redefine it whilst running these @@ -334,9 +326,9 @@ describe('Key Event Handling', function() { }); it('should change Alt to AltGraph', function() { - var count = 0; - var kbd = new Keyboard({ - onKeyEvent: function(keysym, code, down) { + let count = 0; + const kbd = new Keyboard(document); + kbd.onkeyevent = (keysym, code, down) => { switch (count++) { case 0: expect(keysym).to.be.equal(0xFF7E); @@ -347,33 +339,33 @@ describe('Key Event Handling', function() { expect(code).to.be.equal('AltRight'); break; } - }}); + }; kbd._handleKeyDown(keyevent('keydown', {code: 'AltLeft', key: 'Alt', location: 1})); kbd._handleKeyDown(keyevent('keydown', {code: 'AltRight', key: 'Alt', location: 2})); expect(count).to.be.equal(2); }); it('should change left Super to Alt', function(done) { - var kbd = new Keyboard({ - onKeyEvent: function(keysym, code, down) { + const kbd = new Keyboard(document); + kbd.onkeyevent = (keysym, code, down) => { expect(keysym).to.be.equal(0xFFE9); expect(code).to.be.equal('MetaLeft'); done(); - }}); + }; kbd._handleKeyDown(keyevent('keydown', {code: 'MetaLeft', key: 'Meta', location: 1})); }); it('should change right Super to left Super', function(done) { - var kbd = new Keyboard({ - onKeyEvent: function(keysym, code, down) { + const kbd = new Keyboard(document); + kbd.onkeyevent = (keysym, code, down) => { expect(keysym).to.be.equal(0xFFEB); expect(code).to.be.equal('MetaRight'); done(); - }}); + }; kbd._handleKeyDown(keyevent('keydown', {code: 'MetaRight', key: 'Meta', location: 2})); }); }); describe('Escape AltGraph on Windows', function() { - var origNavigator; + let origNavigator; beforeEach(function () { // window.navigator is a protected read-only property in many // environments, so we need to redefine it whilst running these @@ -393,108 +385,128 @@ describe('Key Event Handling', function() { } window.navigator.platform = "Windows x86_64"; + + this.clock = sinon.useFakeTimers(); }); afterEach(function () { Object.defineProperty(window, "navigator", origNavigator); + this.clock.restore(); }); - it('should generate fake undo/redo events on press when AltGraph is down', function() { - var times_called = 0; - var kbd = new Keyboard({ - onKeyEvent: function(keysym, code, down) { - switch(times_called++) { - case 0: - expect(keysym).to.be.equal(0xFFE3); - expect(code).to.be.equal('ControlLeft'); - expect(down).to.be.equal(true); - break; - case 1: - expect(keysym).to.be.equal(0xFFEA); - expect(code).to.be.equal('AltRight'); - expect(down).to.be.equal(true); - break; - case 2: - expect(keysym).to.be.equal(0xFFEA); - expect(code).to.be.equal('AltRight'); - expect(down).to.be.equal(false); - break; - case 3: - expect(keysym).to.be.equal(0xFFE3); - expect(code).to.be.equal('ControlLeft'); - expect(down).to.be.equal(false); - break; - case 4: - expect(keysym).to.be.equal(0x61); - expect(code).to.be.equal('KeyA'); - expect(down).to.be.equal(true); - break; - case 5: - expect(keysym).to.be.equal(0xFFE3); - expect(code).to.be.equal('ControlLeft'); - expect(down).to.be.equal(true); - break; - case 6: - expect(keysym).to.be.equal(0xFFEA); - expect(code).to.be.equal('AltRight'); - expect(down).to.be.equal(true); - break; - } - }}); - // First the modifier combo + it('should supress ControlLeft until it knows if it is AltGr', function () { + const kbd = new Keyboard(document); + kbd.onkeyevent = sinon.spy(); kbd._handleKeyDown(keyevent('keydown', {code: 'ControlLeft', key: 'Control', location: 1})); - kbd._handleKeyDown(keyevent('keydown', {code: 'AltRight', key: 'Alt', location: 2})); - // Next a normal character - kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', key: 'a'})); - expect(times_called).to.be.equal(7); + expect(kbd.onkeyevent).to.not.have.been.called; }); - it('should no do anything on key release', function() { - var times_called = 0; - var kbd = new Keyboard({ - onKeyEvent: function(keysym, code, down) { - switch(times_called++) { - case 7: - expect(keysym).to.be.equal(0x61); - expect(code).to.be.equal('KeyA'); - expect(down).to.be.equal(false); - break; - } - }}); - // First the modifier combo + + it('should not trigger on repeating ControlLeft', function () { + const kbd = new Keyboard(document); + kbd.onkeyevent = sinon.spy(); kbd._handleKeyDown(keyevent('keydown', {code: 'ControlLeft', key: 'Control', location: 1})); - kbd._handleKeyDown(keyevent('keydown', {code: 'AltRight', key: 'Alt', location: 2})); - // Next a normal character - kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', key: 'a'})); - kbd._handleKeyUp(keyevent('keyup', {code: 'KeyA', key: 'a'})); - expect(times_called).to.be.equal(8); + kbd._handleKeyDown(keyevent('keydown', {code: 'ControlLeft', key: 'Control', location: 1})); + expect(kbd.onkeyevent).to.have.been.calledTwice; + expect(kbd.onkeyevent.firstCall).to.have.been.calledWith(0xffe3, "ControlLeft", true); + expect(kbd.onkeyevent.secondCall).to.have.been.calledWith(0xffe3, "ControlLeft", true); }); - it('should not consider a char modifier to be down on the modifier key itself', function() { - var times_called = 0; - var kbd = new Keyboard({ - onKeyEvent: function(keysym, code, down) { - switch(times_called++) { - case 0: - expect(keysym).to.be.equal(0xFFE3); - expect(code).to.be.equal('ControlLeft'); - expect(down).to.be.equal(true); - break; - case 1: - expect(keysym).to.be.equal(0xFFE9); - expect(code).to.be.equal('AltLeft'); - expect(down).to.be.equal(true); - break; - case 2: - expect(keysym).to.be.equal(0xFFE3); - expect(code).to.be.equal('ControlLeft'); - expect(down).to.be.equal(true); - break; - } - }}); - // First the modifier combo + + it('should not supress ControlRight', function () { + const kbd = new Keyboard(document); + kbd.onkeyevent = sinon.spy(); + kbd._handleKeyDown(keyevent('keydown', {code: 'ControlRight', key: 'Control', location: 2})); + expect(kbd.onkeyevent).to.have.been.calledOnce; + expect(kbd.onkeyevent).to.have.been.calledWith(0xffe4, "ControlRight", true); + }); + + it('should release ControlLeft after 100 ms', function () { + const kbd = new Keyboard(document); + kbd.onkeyevent = sinon.spy(); kbd._handleKeyDown(keyevent('keydown', {code: 'ControlLeft', key: 'Control', location: 1})); - kbd._handleKeyDown(keyevent('keydown', {code: 'AltLeft', key: 'Alt', location: 1})); - // Then one of the keys again + expect(kbd.onkeyevent).to.not.have.been.called; + this.clock.tick(100); + expect(kbd.onkeyevent).to.have.been.calledOnce; + expect(kbd.onkeyevent).to.have.been.calledWith(0xffe3, "ControlLeft", true); + }); + + it('should release ControlLeft on other key press', function () { + const kbd = new Keyboard(document); + kbd.onkeyevent = sinon.spy(); + kbd._handleKeyDown(keyevent('keydown', {code: 'ControlLeft', key: 'Control', location: 1})); + expect(kbd.onkeyevent).to.not.have.been.called; + kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', key: 'a'})); + expect(kbd.onkeyevent).to.have.been.calledTwice; + expect(kbd.onkeyevent.firstCall).to.have.been.calledWith(0xffe3, "ControlLeft", true); + expect(kbd.onkeyevent.secondCall).to.have.been.calledWith(0x61, "KeyA", true); + + // Check that the timer is properly dead + kbd.onkeyevent.reset(); + this.clock.tick(100); + expect(kbd.onkeyevent).to.not.have.been.called; + }); + + it('should release ControlLeft on other key release', function () { + const kbd = new Keyboard(document); + kbd.onkeyevent = sinon.spy(); + kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', key: 'a'})); kbd._handleKeyDown(keyevent('keydown', {code: 'ControlLeft', key: 'Control', location: 1})); - expect(times_called).to.be.equal(3); + expect(kbd.onkeyevent).to.have.been.calledOnce; + expect(kbd.onkeyevent.firstCall).to.have.been.calledWith(0x61, "KeyA", true); + kbd._handleKeyUp(keyevent('keyup', {code: 'KeyA', key: 'a'})); + expect(kbd.onkeyevent).to.have.been.calledThrice; + expect(kbd.onkeyevent.secondCall).to.have.been.calledWith(0xffe3, "ControlLeft", true); + expect(kbd.onkeyevent.thirdCall).to.have.been.calledWith(0x61, "KeyA", false); + + // Check that the timer is properly dead + kbd.onkeyevent.reset(); + this.clock.tick(100); + expect(kbd.onkeyevent).to.not.have.been.called; + }); + + it('should generate AltGraph for quick Ctrl+Alt sequence', function () { + const kbd = new Keyboard(document); + kbd.onkeyevent = sinon.spy(); + kbd._handleKeyDown(keyevent('keydown', {code: 'ControlLeft', key: 'Control', location: 1, timeStamp: Date.now()})); + this.clock.tick(20); + kbd._handleKeyDown(keyevent('keydown', {code: 'AltRight', key: 'Alt', location: 2, timeStamp: Date.now()})); + expect(kbd.onkeyevent).to.have.been.calledOnce; + expect(kbd.onkeyevent).to.have.been.calledWith(0xfe03, 'AltRight', true); + + // Check that the timer is properly dead + kbd.onkeyevent.reset(); + this.clock.tick(100); + expect(kbd.onkeyevent).to.not.have.been.called; + }); + + it('should generate Ctrl, Alt for slow Ctrl+Alt sequence', function () { + const kbd = new Keyboard(document); + kbd.onkeyevent = sinon.spy(); + kbd._handleKeyDown(keyevent('keydown', {code: 'ControlLeft', key: 'Control', location: 1, timeStamp: Date.now()})); + this.clock.tick(60); + kbd._handleKeyDown(keyevent('keydown', {code: 'AltRight', key: 'Alt', location: 2, timeStamp: Date.now()})); + expect(kbd.onkeyevent).to.have.been.calledTwice; + expect(kbd.onkeyevent.firstCall).to.have.been.calledWith(0xffe3, "ControlLeft", true); + expect(kbd.onkeyevent.secondCall).to.have.been.calledWith(0xffea, "AltRight", true); + + // Check that the timer is properly dead + kbd.onkeyevent.reset(); + this.clock.tick(100); + expect(kbd.onkeyevent).to.not.have.been.called; + }); + + it('should pass through single Alt', function () { + const kbd = new Keyboard(document); + kbd.onkeyevent = sinon.spy(); + kbd._handleKeyDown(keyevent('keydown', {code: 'AltRight', key: 'Alt', location: 2})); + expect(kbd.onkeyevent).to.have.been.calledOnce; + expect(kbd.onkeyevent).to.have.been.calledWith(0xffea, 'AltRight', true); + }); + + it('should pass through single AltGr', function () { + const kbd = new Keyboard(document); + kbd.onkeyevent = sinon.spy(); + kbd._handleKeyDown(keyevent('keydown', {code: 'AltRight', key: 'AltGraph', location: 2})); + expect(kbd.onkeyevent).to.have.been.calledOnce; + expect(kbd.onkeyevent).to.have.been.calledWith(0xfe03, 'AltRight', true); }); }); });