From 0cdf2962c0600727dbc8bc7bc15eb0cef19f18c0 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 10 Dec 2020 10:01:04 +0100 Subject: [PATCH] Fake key releases for some Japanese IM keys Windows behaves very oddly for some Japanese IM keys in that it won't send a key release event when the key is released. In some keys it never sends the event, and in some cases it sends the release as the key is pressed the subsequent time. --- core/input/keyboard.js | 14 ++++++++++++++ tests/test.keyboard.js | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/core/input/keyboard.js b/core/input/keyboard.js index ed3b1bf1..48f65cf6 100644 --- a/core/input/keyboard.js +++ b/core/input/keyboard.js @@ -164,6 +164,20 @@ export default class Keyboard { return; } + // Windows doesn't send proper key releases for a bunch of + // Japanese IM keys so we have to fake the release right away + const jpBadKeys = [ KeyTable.XK_Zenkaku_Hankaku, + KeyTable.XK_Eisu_toggle, + KeyTable.XK_Katakana, + KeyTable.XK_Hiragana, + KeyTable.XK_Romaji ]; + if (browser.isWindows() && jpBadKeys.includes(keysym)) { + this._sendKeyEvent(keysym, code, true); + this._sendKeyEvent(keysym, code, false); + stopEvent(e); + return; + } + stopEvent(e); // Possible start of AltGr sequence? (see above) diff --git a/tests/test.keyboard.js b/tests/test.keyboard.js index 940769e6..f460eb3b 100644 --- a/tests/test.keyboard.js +++ b/tests/test.keyboard.js @@ -268,6 +268,47 @@ describe('Key Event Handling', function () { }); }); + describe('Japanese IM keys on Windows', function () { + let 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"); + + 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 = "Windows"; + }); + + afterEach(function () { + if (origNavigator !== undefined) { + Object.defineProperty(window, "navigator", origNavigator); + } + }); + + const keys = { 'Zenkaku': 0xff2a, 'Hankaku': 0xff2a, + 'Alphanumeric': 0xff30, 'Katakana': 0xff26, + 'Hiragana': 0xff25, 'Romaji': 0xff24, + 'KanaMode': 0xff24 }; + for (let [key, keysym] of Object.entries(keys)) { + it(`should fake key release for ${key} on Windows`, function () { + let kbd = new Keyboard(document); + kbd.onkeyevent = sinon.spy(); + kbd._handleKeyDown(keyevent('keydown', {code: 'FakeIM', key: key})); + + expect(kbd.onkeyevent).to.have.been.calledTwice; + expect(kbd.onkeyevent.firstCall).to.have.been.calledWith(keysym, "FakeIM", true); + expect(kbd.onkeyevent.secondCall).to.have.been.calledWith(keysym, "FakeIM", false); + }); + } + }); + describe('Escape AltGraph on Windows', function () { let origNavigator; beforeEach(function () {