diff options
author | Pierre Ossman <ossman@cendio.se> | 2020-12-10 10:23:10 +0100 |
---|---|---|
committer | Pierre Ossman <ossman@cendio.se> | 2020-12-10 10:23:10 +0100 |
commit | 67ac9f9c0d1d2990ad7ab4dd015dca6786da929c (patch) | |
tree | 0dff74d41207fa319084f1422c2a203786bd4afd | |
parent | dc9da4a042760994266260d97c78dad31dec1920 (diff) | |
parent | 4ae9d3e75a34403f44fda1bd061d9a20dd3ff76c (diff) | |
download | novnc-67ac9f9c0d1d2990ad7ab4dd015dca6786da929c.tar.gz |
Merge branch 'jp' of https://github.com/CendioOssman/noVNC
-rw-r--r-- | core/input/domkeytable.js | 4 | ||||
-rw-r--r-- | core/input/keyboard.js | 14 | ||||
-rw-r--r-- | core/input/util.js | 15 | ||||
-rw-r--r-- | tests/test.helper.js | 33 | ||||
-rw-r--r-- | tests/test.keyboard.js | 53 |
5 files changed, 109 insertions, 10 deletions
diff --git a/core/input/domkeytable.js b/core/input/domkeytable.js index b84ad45..1b6baa6 100644 --- a/core/input/domkeytable.js +++ b/core/input/domkeytable.js @@ -119,7 +119,7 @@ addStandard("WakeUp", KeyTable.XF86XK_WakeUp); // 2.8. IME and Composition Keys addStandard("AllCandidates", KeyTable.XK_MultipleCandidate); -addStandard("Alphanumeric", KeyTable.XK_Eisu_Shift); // could also be _Eisu_Toggle +addStandard("Alphanumeric", KeyTable.XK_Eisu_toggle); addStandard("CodeInput", KeyTable.XK_Codeinput); addStandard("Compose", KeyTable.XK_Multi_key); addStandard("Convert", KeyTable.XK_Henkan); @@ -147,7 +147,7 @@ addStandard("KanjiMode", KeyTable.XK_Kanji); addStandard("Katakana", KeyTable.XK_Katakana); addStandard("Romaji", KeyTable.XK_Romaji); addStandard("Zenkaku", KeyTable.XK_Zenkaku); -addStandard("ZenkakuHanaku", KeyTable.XK_Zenkaku_Hankaku); +addStandard("ZenkakuHankaku", KeyTable.XK_Zenkaku_Hankaku); // 2.9. General-Purpose Function Keys diff --git a/core/input/keyboard.js b/core/input/keyboard.js index ed3b1bf..48f65cf 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/core/input/util.js b/core/input/util.js index 182be7f..58f84e5 100644 --- a/core/input/util.js +++ b/core/input/util.js @@ -157,6 +157,21 @@ export function getKeysym(evt) { } } + // Windows sends alternating symbols for some keys when using a + // Japanese layout. We have no way of synchronising with the IM + // running on the remote system, so we send some combined keysym + // instead and hope for the best. + if (browser.isWindows()) { + switch (key) { + case 'Zenkaku': + case 'Hankaku': + return KeyTable.XK_Zenkaku_Hankaku; + case 'Romaji': + case 'KanaMode': + return KeyTable.XK_Romaji; + } + } + return DOMKeyTable[key][location]; } diff --git a/tests/test.helper.js b/tests/test.helper.js index 5552ec4..ed65770 100644 --- a/tests/test.helper.js +++ b/tests/test.helper.js @@ -186,5 +186,38 @@ describe('Helpers', function () { expect(KeyboardUtil.getKeysym({code: 'NumpadDecimal', key: ',', location: 3})).to.be.equal(0xFFAC); }); }); + + 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, + 'Romaji': 0xff24, 'KanaMode': 0xff24 }; + for (let [key, keysym] of Object.entries(keys)) { + it(`should fake combined key for ${key} on Windows`, function () { + expect(KeyboardUtil.getKeysym({code: 'FakeIM', key: key})).to.be.equal(keysym); + }); + } + }); }); }); diff --git a/tests/test.keyboard.js b/tests/test.keyboard.js index 940769e..381cd30 100644 --- a/tests/test.keyboard.js +++ b/tests/test.keyboard.js @@ -219,7 +219,7 @@ describe('Key Event Handling', function () { } }); - it('should toggle caps lock on key press on iOS', function (done) { + it('should toggle caps lock on key press on iOS', function () { window.navigator.platform = "iPad"; const kbd = new Keyboard(document); kbd.onkeyevent = sinon.spy(); @@ -228,10 +228,9 @@ describe('Key Event Handling', function () { expect(kbd.onkeyevent).to.have.been.calledTwice; expect(kbd.onkeyevent.firstCall).to.have.been.calledWith(0xFFE5, "CapsLock", true); expect(kbd.onkeyevent.secondCall).to.have.been.calledWith(0xFFE5, "CapsLock", false); - done(); }); - it('should toggle caps lock on key press on mac', function (done) { + it('should toggle caps lock on key press on mac', function () { window.navigator.platform = "Mac"; const kbd = new Keyboard(document); kbd.onkeyevent = sinon.spy(); @@ -240,10 +239,9 @@ describe('Key Event Handling', function () { expect(kbd.onkeyevent).to.have.been.calledTwice; expect(kbd.onkeyevent.firstCall).to.have.been.calledWith(0xFFE5, "CapsLock", true); expect(kbd.onkeyevent.secondCall).to.have.been.calledWith(0xFFE5, "CapsLock", false); - done(); }); - it('should toggle caps lock on key release on iOS', function (done) { + it('should toggle caps lock on key release on iOS', function () { window.navigator.platform = "iPad"; const kbd = new Keyboard(document); kbd.onkeyevent = sinon.spy(); @@ -252,10 +250,9 @@ describe('Key Event Handling', function () { expect(kbd.onkeyevent).to.have.been.calledTwice; expect(kbd.onkeyevent.firstCall).to.have.been.calledWith(0xFFE5, "CapsLock", true); expect(kbd.onkeyevent.secondCall).to.have.been.calledWith(0xFFE5, "CapsLock", false); - done(); }); - it('should toggle caps lock on key release on mac', function (done) { + it('should toggle caps lock on key release on mac', function () { window.navigator.platform = "Mac"; const kbd = new Keyboard(document); kbd.onkeyevent = sinon.spy(); @@ -264,10 +261,50 @@ describe('Key Event Handling', function () { expect(kbd.onkeyevent).to.have.been.calledTwice; expect(kbd.onkeyevent.firstCall).to.have.been.calledWith(0xFFE5, "CapsLock", true); expect(kbd.onkeyevent.secondCall).to.have.been.calledWith(0xFFE5, "CapsLock", false); - done(); }); }); + 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 () { |