summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPierre Ossman <ossman@cendio.se>2019-11-04 10:17:45 +0100
committerPierre Ossman <ossman@cendio.se>2019-11-04 10:17:45 +0100
commitccb511a527a693d0de0ad58b430f73aa2fb74344 (patch)
tree9c2e0eeb457e40ba4e6aa49fd86f278aece8c03f
parent3388c92c7f55b4e77527d1481a52c27459345f46 (diff)
downloadnovnc-ccb511a527a693d0de0ad58b430f73aa2fb74344.tar.gz
Handle missing Shift events on Windows
This is a bug in the OS that leaks through to the browsers. We need to fake a Shift release here to avoid Shift getting stuck in the remote session.
-rw-r--r--core/input/keyboard.js15
-rw-r--r--tests/test.keyboard.js70
2 files changed, 85 insertions, 0 deletions
diff --git a/core/input/keyboard.js b/core/input/keyboard.js
index 764288a..ab62378 100644
--- a/core/input/keyboard.js
+++ b/core/input/keyboard.js
@@ -281,6 +281,21 @@ export default class Keyboard {
}
this._sendKeyEvent(this._keyDownList[code], code, false);
+
+ // Windows has a rather nasty bug where it won't send key
+ // release events for a Shift button if the other Shift is still
+ // pressed
+ if (browser.isWindows() && ((code === 'ShiftLeft') ||
+ (code === 'ShiftRight'))) {
+ if ('ShiftRight' in this._keyDownList) {
+ this._sendKeyEvent(this._keyDownList['ShiftRight'],
+ 'ShiftRight', false);
+ }
+ if ('ShiftLeft' in this._keyDownList) {
+ this._sendKeyEvent(this._keyDownList['ShiftLeft'],
+ 'ShiftLeft', false);
+ }
+ }
}
_handleAltGrTimeout() {
diff --git a/tests/test.keyboard.js b/tests/test.keyboard.js
index 170149f..f5807e9 100644
--- a/tests/test.keyboard.js
+++ b/tests/test.keyboard.js
@@ -459,4 +459,74 @@ describe('Key Event Handling', function () {
expect(kbd.onkeyevent).to.have.been.calledWith(0xfe03, 'AltRight', true);
});
});
+
+ describe('Missing Shift keyup 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");
+ 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 = "Windows x86_64";
+
+ this.clock = sinon.useFakeTimers();
+ });
+ afterEach(function () {
+ Object.defineProperty(window, "navigator", origNavigator);
+ this.clock.restore();
+ });
+
+ it('should fake a left Shift keyup', function () {
+ const kbd = new Keyboard(document);
+ kbd.onkeyevent = sinon.spy();
+
+ kbd._handleKeyDown(keyevent('keydown', {code: 'ShiftLeft', key: 'Shift', location: 1}));
+ expect(kbd.onkeyevent).to.have.been.calledOnce;
+ expect(kbd.onkeyevent).to.have.been.calledWith(0xffe1, 'ShiftLeft', true);
+ kbd.onkeyevent.resetHistory();
+
+ kbd._handleKeyDown(keyevent('keydown', {code: 'ShiftRight', key: 'Shift', location: 2}));
+ expect(kbd.onkeyevent).to.have.been.calledOnce;
+ expect(kbd.onkeyevent).to.have.been.calledWith(0xffe2, 'ShiftRight', true);
+ kbd.onkeyevent.resetHistory();
+
+ kbd._handleKeyUp(keyevent('keyup', {code: 'ShiftLeft', key: 'Shift', location: 1}));
+ expect(kbd.onkeyevent).to.have.been.calledTwice;
+ expect(kbd.onkeyevent).to.have.been.calledWith(0xffe2, 'ShiftRight', false);
+ expect(kbd.onkeyevent).to.have.been.calledWith(0xffe1, 'ShiftLeft', false);
+ });
+
+ it('should fake a right Shift keyup', function () {
+ const kbd = new Keyboard(document);
+ kbd.onkeyevent = sinon.spy();
+
+ kbd._handleKeyDown(keyevent('keydown', {code: 'ShiftLeft', key: 'Shift', location: 1}));
+ expect(kbd.onkeyevent).to.have.been.calledOnce;
+ expect(kbd.onkeyevent).to.have.been.calledWith(0xffe1, 'ShiftLeft', true);
+ kbd.onkeyevent.resetHistory();
+
+ kbd._handleKeyDown(keyevent('keydown', {code: 'ShiftRight', key: 'Shift', location: 2}));
+ expect(kbd.onkeyevent).to.have.been.calledOnce;
+ expect(kbd.onkeyevent).to.have.been.calledWith(0xffe2, 'ShiftRight', true);
+ kbd.onkeyevent.resetHistory();
+
+ kbd._handleKeyUp(keyevent('keyup', {code: 'ShiftRight', key: 'Shift', location: 2}));
+ expect(kbd.onkeyevent).to.have.been.calledTwice;
+ expect(kbd.onkeyevent).to.have.been.calledWith(0xffe2, 'ShiftRight', false);
+ expect(kbd.onkeyevent).to.have.been.calledWith(0xffe1, 'ShiftLeft', false);
+ });
+ });
});