summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPierre Ossman <ossman@cendio.se>2020-12-10 10:23:10 +0100
committerPierre Ossman <ossman@cendio.se>2020-12-10 10:23:10 +0100
commit67ac9f9c0d1d2990ad7ab4dd015dca6786da929c (patch)
tree0dff74d41207fa319084f1422c2a203786bd4afd
parentdc9da4a042760994266260d97c78dad31dec1920 (diff)
parent4ae9d3e75a34403f44fda1bd061d9a20dd3ff76c (diff)
downloadnovnc-67ac9f9c0d1d2990ad7ab4dd015dca6786da929c.tar.gz
Merge branch 'jp' of https://github.com/CendioOssman/noVNC
-rw-r--r--core/input/domkeytable.js4
-rw-r--r--core/input/keyboard.js14
-rw-r--r--core/input/util.js15
-rw-r--r--tests/test.helper.js33
-rw-r--r--tests/test.keyboard.js53
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 () {