diff --git a/app/ui.js b/app/ui.js index a447ad91..bdc91797 100644 --- a/app/ui.js +++ b/app/ui.js @@ -427,6 +427,8 @@ const UI = { addTouchSpecificHandlers() { document.getElementById("noVNC_keyboard_button") .addEventListener('click', UI.toggleVirtualKeyboard); + document.getElementById("noVNC_keyboard_button") + .addEventListener('touch', UI.toggleVirtualKeyboard); document.getElementById("noVNC_keyboardinput") .addEventListener('focus', UI.onfocusVirtualKeyboard); document.getElementById("noVNC_keyboardinput") diff --git a/core/input/util.js b/core/input/util.js index 58f84e55..36b69817 100644 --- a/core/input/util.js +++ b/core/input/util.js @@ -67,7 +67,7 @@ export function getKeycode(evt) { // Get 'KeyboardEvent.key', handling legacy browsers export function getKey(evt) { // Are we getting a proper key value? - if (evt.key !== undefined) { + if ((evt.key !== undefined) && (evt.key !== 'Unidentified')) { // Mozilla isn't fully in sync with the spec yet switch (evt.key) { case 'OS': return 'Meta'; diff --git a/core/rfb.js b/core/rfb.js index 3d962662..2a95b2ea 100644 --- a/core/rfb.js +++ b/core/rfb.js @@ -12,7 +12,7 @@ import { toUnsigned32bit, toSigned32bit } from './util/int.js'; import * as Log from './util/logging.js'; import { encodeUTF8, decodeUTF8, uuidv4 } from './util/strings.js'; import { hashUInt8Array } from './util/int.js'; -import { dragThreshold, supportsCursorURIs, isTouchDevice, isWindows, isMac, isIOS } from './util/browser.js'; +import { dragThreshold, supportsCursorURIs, isTouchDevice, isWindows, isMac, isIOS, isDesktop } from './util/browser.js'; import { clientToElement } from './util/element.js'; import { setCapture } from './util/events.js'; import EventTargetMixin from './util/eventtarget.js'; @@ -2224,7 +2224,7 @@ export default class RFB extends EventTargetMixin { // With multiple displays, it is possible to end up in a state where we lost the mouseup event // If a mouse move indicates no buttons are down but the current state shows something down, lets clear the plate - if (this._mouseButtonMask !== 0 && !down && !simulated) { + if (this._display.screens.length > 1 && this._mouseButtonMask !== 0 && !down && !simulated && isDesktop()) { this._mouseButtonMask = 0; Log.Debug('Mouse event button down mismatch with current mask, resetting mask to 0.') } @@ -2375,8 +2375,14 @@ export default class RFB extends EventTargetMixin { } _fakeMouseMove(ev, elementX, elementY) { - this._handleMouseMove(elementX, elementY, false, true); - this._cursor.move(ev.detail.clientX, ev.detail.clientY); + if (this._isPrimaryDisplay) { + this._handleMouseMove(elementX, elementY, false, true); + this._cursor.move(ev.detail.clientX, ev.detail.clientY); + } else { + this._proxyRFBMessage('mousemove', [ elementX, elementY, true, false ]); + this._cursor.move(ev.detail.clientX, ev.detail.clientY); + + } } _handleTapEvent(ev, bmask) { @@ -2406,8 +2412,20 @@ export default class RFB extends EventTargetMixin { this._gestureLastTapTime = Date.now(); this._fakeMouseMove(this._gestureFirstDoubleTapEv, pos.x, pos.y); - this._handleMouseButton(pos.x, pos.y, true, bmask); - this._handleMouseButton(pos.x, pos.y, false, bmask); + this._fakeMouseButton(pos.x, pos.y, true, bmask); + this._fakeMouseButton(pos.x, pos.y, false, bmask); + } + + _fakeMouseButton(x, y, down, mask) { + if (this._isPrimaryDisplay) { + this._handleMouseButton(x, y, down, mask); + } else { + if (down) { + this._proxyRFBMessage('mousedown', [ x, y, mask ]); + } else { + this._proxyRFBMessage('mouseup', [ x, y, mask ]); + } + } } _handleGesture(ev) { @@ -2429,11 +2447,12 @@ export default class RFB extends EventTargetMixin { break; case 'drag': this._fakeMouseMove(ev, pos.x, pos.y); - this._handleMouseButton(pos.x, pos.y, true, 0x1); + + this._fakeMouseButton(pos.x, pos.y, true, 0x1); break; case 'longpress': this._fakeMouseMove(ev, pos.x, pos.y); - this._handleMouseButton(pos.x, pos.y, true, 0x4); + this._fakeMouseButton(pos.x, pos.y, true, 0x4); break; case 'twodrag': @@ -2465,23 +2484,23 @@ export default class RFB extends EventTargetMixin { // every update. this._fakeMouseMove(ev, pos.x, pos.y); while ((ev.detail.magnitudeY - this._gestureLastMagnitudeY) > GESTURE_SCRLSENS) { - this._handleMouseButton(pos.x, pos.y, true, 0x8); - this._handleMouseButton(pos.x, pos.y, false, 0x8); + this._fakeMouseButton(pos.x, pos.y, true, 0x8); + this._fakeMouseButton(pos.x, pos.y, false, 0x8); this._gestureLastMagnitudeY += GESTURE_SCRLSENS; } while ((ev.detail.magnitudeY - this._gestureLastMagnitudeY) < -GESTURE_SCRLSENS) { - this._handleMouseButton(pos.x, pos.y, true, 0x10); - this._handleMouseButton(pos.x, pos.y, false, 0x10); + this._fakeMouseButton(pos.x, pos.y, true, 0x10); + this._fakeMouseButton(pos.x, pos.y, false, 0x10); this._gestureLastMagnitudeY -= GESTURE_SCRLSENS; } while ((ev.detail.magnitudeX - this._gestureLastMagnitudeX) > GESTURE_SCRLSENS) { - this._handleMouseButton(pos.x, pos.y, true, 0x20); - this._handleMouseButton(pos.x, pos.y, false, 0x20); + this._fakeMouseButton(pos.x, pos.y, true, 0x20); + this._fakeMouseButton(pos.x, pos.y, false, 0x20); this._gestureLastMagnitudeX += GESTURE_SCRLSENS; } while ((ev.detail.magnitudeX - this._gestureLastMagnitudeX) < -GESTURE_SCRLSENS) { - this._handleMouseButton(pos.x, pos.y, true, 0x40); - this._handleMouseButton(pos.x, pos.y, false, 0x40); + this._fakeMouseButton(pos.x, pos.y, true, 0x40); + this._fakeMouseButton(pos.x, pos.y, false, 0x40); this._gestureLastMagnitudeX -= GESTURE_SCRLSENS; } break; @@ -2494,13 +2513,13 @@ export default class RFB extends EventTargetMixin { if (Math.abs(magnitude - this._gestureLastMagnitudeX) > GESTURE_ZOOMSENS) { this._handleKeyEvent(KeyTable.XK_Control_L, "ControlLeft", true); while ((magnitude - this._gestureLastMagnitudeX) > GESTURE_ZOOMSENS) { - this._handleMouseButton(pos.x, pos.y, true, 0x8); - this._handleMouseButton(pos.x, pos.y, false, 0x8); + this._fakeMouseButton(pos.x, pos.y, true, 0x8); + this._fakeMouseButton(pos.x, pos.y, false, 0x8); this._gestureLastMagnitudeX += GESTURE_ZOOMSENS; } while ((magnitude - this._gestureLastMagnitudeX) < -GESTURE_ZOOMSENS) { - this._handleMouseButton(pos.x, pos.y, true, 0x10); - this._handleMouseButton(pos.x, pos.y, false, 0x10); + this._fakeMouseButton(pos.x, pos.y, true, 0x10); + this._fakeMouseButton(pos.x, pos.y, false, 0x10); this._gestureLastMagnitudeX -= GESTURE_ZOOMSENS; } } @@ -2519,11 +2538,11 @@ export default class RFB extends EventTargetMixin { break; case 'drag': this._fakeMouseMove(ev, pos.x, pos.y); - this._handleMouseButton(pos.x, pos.y, false, 0x1); + this._fakeMouseButton(pos.x, pos.y, false, 0x1); break; case 'longpress': this._fakeMouseMove(ev, pos.x, pos.y); - this._handleMouseButton(pos.x, pos.y, false, 0x4); + this._fakeMouseButton(pos.x, pos.y, false, 0x4); break; } break; diff --git a/core/util/browser.js b/core/util/browser.js index 23bf6cb5..937fbd1e 100644 --- a/core/util/browser.js +++ b/core/util/browser.js @@ -85,6 +85,10 @@ export function isWindows() { return navigator && !!(/win/i).exec(navigator.platform); } +export function isLinux() { + return navigator && !!(/linux/i).exec(navigator.platform) +} + export function isIOS() { return navigator && (!!(/ipad/i).exec(navigator.platform) || @@ -97,6 +101,18 @@ export function isSafari() { navigator.userAgent.indexOf('Chrome') === -1); } +//is the client a desktop like operating system +export function isDesktop() { + var userAgent = navigator.userAgent; + if (isIOS() || userAgent.indexOf("OculusBrowser") != -1 || userAgent.indexOf("SamsungBrowser") != -1) { + return false + } else if (userAgent.indexOf("Windows") != -1 || userAgent.indexOf("Mac") != -1 || userAgent.indexOf("X11") != -1 || userAgent.indexOf("Linux") != -1) { + return true; + } else { + return false; + } + } + // Returns IE version number if IE or older Edge browser export function isIE() { var ua = window.navigator.userAgent; diff --git a/tests/test.helper.js b/tests/test.helper.js index ed65770e..601a137e 100644 --- a/tests/test.helper.js +++ b/tests/test.helper.js @@ -116,6 +116,8 @@ describe('Helpers', function () { }); it('should use charCode if no key', function () { expect(KeyboardUtil.getKey({charCode: 'Š'.charCodeAt(), keyCode: 0x42, which: 0x43})).to.be.equal('Š'); + // Broken Oculus browser + expect(KeyboardUtil.getKey({charCode: 'Š'.charCodeAt(), keyCode: 0x42, which: 0x43, key: 'Unidentified'})).to.be.equal('Š'); }); it('should return Unidentified when it cannot map the key', function () { expect(KeyboardUtil.getKey({keycode: 0x42})).to.be.equal('Unidentified');