Fake key release for iOS hardware keyboards

iOS sends decent key down events, but junk key up events when a
hardware keyboard is used. This confuses the key tracking as a
corresponding release is then never detected. To work around this
we'll treat the hardware keyboard like the virtual ones and send
the key release right away.
This commit is contained in:
Pierre Ossman 2017-06-21 13:50:03 +02:00
parent 637a282be5
commit 9e99ce126c
2 changed files with 82 additions and 3 deletions

View File

@ -44,6 +44,12 @@ function isMac() {
function isWindows() {
return navigator && !!(/win/i).exec(navigator.platform);
}
function isIOS() {
return navigator &&
(!!(/ipad/i).exec(navigator.platform) ||
!!(/iphone/i).exec(navigator.platform) ||
!!(/ipod/i).exec(navigator.platform));
}
Keyboard.prototype = {
// private methods
@ -106,13 +112,15 @@ Keyboard.prototype = {
// We cannot handle keys we cannot track, but we also need
// to deal with virtual keyboards which omit key info
if (code === 'Unidentified') {
// (iOS omits tracking info on keyup events, which forces us to
// special treat that platform here)
if ((code === 'Unidentified') || isIOS()) {
if (keysym) {
// If it's a virtual keyboard then it should be
// sufficient to just send press and release right
// after each other
this._sendKeyEvent(keysym, 'Unidentified', true);
this._sendKeyEvent(keysym, 'Unidentified', false);
this._sendKeyEvent(keysym, code, true);
this._sendKeyEvent(keysym, code, false);
}
stopEvent(e);

View File

@ -124,6 +124,77 @@ describe('Key Event Handling', function() {
});
});
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) {
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 (isIE() || isEdge()) this.skip();
var count = 0;
var kbd = new Keyboard({
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();