var assert = chai.assert;
var expect = chai.expect;
-import { Keyboard } from '../core/input/devices.js';
-import keysyms from '../core/input/keysymdef.js';
-import * as KeyboardUtil from '../core/input/util.js';
-
-function isIE() {
- return navigator && !!(/trident/i).exec(navigator.userAgent);
-}
-function isEdge() {
- return navigator && !!(/edge/i).exec(navigator.userAgent);
-}
-
-/* jshint newcap: false, expr: true */
+import sinon from '../vendor/sinon.js';
+
+import Keyboard from '../core/input/keyboard.js';
+import * as browser from '../core/util/browser.js';
+
describe('Key Event Handling', function() {
"use strict";
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();
+ var kbd = new Keyboard(document);
+ kbd.onkeyevent = function(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();
+ if (browser.isIE() || browser.isEdge()) this.skip();
var calls = 0;
- var kbd = new Keyboard({
- onKeyEvent: function(keysym, code, down) {
+ var kbd = new Keyboard(document);
+ kbd.onkeyevent = function(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});
+ var 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) {
+ var kbd = new Keyboard(document);
+ kbd.onkeyevent = function(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});
+ var 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) {
+ var kbd = new Keyboard(document);
+ kbd.onkeyevent = function(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(document);
+ kbd.onkeyevent = function(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(document);
+ kbd.onkeyevent = function(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(document);
+ kbd.onkeyevent = function(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(document);
+ kbd.onkeyevent = function(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 kbd = new Keyboard(document, {});
var evt = keyevent('keydown', {code: 'KeyA', key: 'a'});
kbd._handleKeyDown(evt);
expect(evt.preventDefault).to.have.been.called;
expect(evt.preventDefault).to.have.been.called;
});
it('should not suppress keys without key', function() {
- var kbd = new Keyboard({});
+ var kbd = new Keyboard(document, {});
var 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 kbd = new Keyboard(document, {});
var evt = keyevent('keydown', {code: 'KeyA', keyCode: 0x41});
kbd._handleKeyDown(evt);
var evt = keyevent('keypress', {code: 'KeyA', charCode: 0x41});
});
});
+ describe('Fake keyup', function() {
+ it('should fake keyup events for virtual keyboards', function(done) {
+ if (browser.isIE() || browser.isEdge()) this.skip();
+ var count = 0;
+ var kbd = new Keyboard(document);
+ kbd.onkeyevent = function(keysym, code, down) {
+ switch (count++) {
+ case 0:
+ expect(keysym).to.be.equal(0x61);
+ expect(code).to.be.equal('Unidentified');
+ expect(down).to.be.equal(true);
+ break;
+ case 1:
+ expect(keysym).to.be.equal(0x61);
+ expect(code).to.be.equal('Unidentified');
+ expect(down).to.be.equal(false);
+ done();
+ }
+ };
+ kbd._handleKeyDown(keyevent('keydown', {code: 'Unidentified', key: 'a'}));
+ });
+
+ describe('iOS', function() {
+ var origNavigator;
+ beforeEach(function () {
+ // window.navigator is a protected read-only property in many
+ // environments, so we need to redefine it whilst running these
+ // tests.
+ origNavigator = Object.getOwnPropertyDescriptor(window, "navigator");
+ if (origNavigator === undefined) {
+ // Object.getOwnPropertyDescriptor() doesn't work
+ // properly in any version of IE
+ this.skip();
+ }
+
+ Object.defineProperty(window, "navigator", {value: {}});
+ if (window.navigator.platform !== undefined) {
+ // Object.defineProperty() doesn't work properly in old
+ // versions of Chrome
+ this.skip();
+ }
+
+ window.navigator.platform = "iPhone 9.0";
+ });
+ afterEach(function () {
+ Object.defineProperty(window, "navigator", origNavigator);
+ });
+
+ it('should fake keyup events on iOS', function(done) {
+ if (browser.isIE() || browser.isEdge()) this.skip();
+ var count = 0;
+ var kbd = new Keyboard(document);
+ kbd.onkeyevent = function(keysym, code, down) {
+ switch (count++) {
+ case 0:
+ expect(keysym).to.be.equal(0x61);
+ expect(code).to.be.equal('KeyA');
+ expect(down).to.be.equal(true);
+ break;
+ case 1:
+ expect(keysym).to.be.equal(0x61);
+ expect(code).to.be.equal('KeyA');
+ expect(down).to.be.equal(false);
+ done();
+ }
+ };
+ kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', key: 'a'}));
+ });
+ });
+ });
+
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) {
+ var kbd = new Keyboard(document);
+ kbd.onkeyevent = function(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) {
+ var kbd = new Keyboard(document);
+ kbd.onkeyevent = function(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});
+ var 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) {
+ var kbd = new Keyboard(document);
+ kbd.onkeyevent = function(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(document);
+ kbd.onkeyevent = function(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) {
+ var kbd = new Keyboard(document);
+ kbd.onkeyevent = function(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'}));
});
it('should change Alt to AltGraph', function() {
var count = 0;
- var kbd = new Keyboard({
- onKeyEvent: function(keysym, code, down) {
+ var kbd = new Keyboard(document);
+ kbd.onkeyevent = function(keysym, code, down) {
switch (count++) {
case 0:
expect(keysym).to.be.equal(0xFF7E);
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) {
+ var kbd = new Keyboard(document);
+ kbd.onkeyevent = function(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) {
+ var kbd = new Keyboard(document);
+ kbd.onkeyevent = function(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}));
});
});
}
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 () {
+ var 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 () {
+ var 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 () {
+ var 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 () {
+ var 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 () {
+ var 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 () {
+ var 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 () {
+ var 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 () {
+ var 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 () {
+ var 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 () {
+ var 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);
});
});
});