From 2b738be8e672721efae06841dfd3badd4aa72a28 Mon Sep 17 00:00:00 2001 From: Rui Reis Date: Tue, 28 May 2024 14:41:15 +0200 Subject: [PATCH 1/4] Add UltraVNC touch gestures support --- app/ui.js | 7 +- core/encodings.js | 1 + core/input/touchhandlerultravnc.js | 112 ++++++++++++++++++ core/rfb.js | 184 +++++++++++++++++++++++++++-- vnc.html | 1 + 5 files changed, 297 insertions(+), 8 deletions(-) create mode 100644 core/input/touchhandlerultravnc.js diff --git a/app/ui.js b/app/ui.js index f27dfe28..8c1098e4 100644 --- a/app/ui.js +++ b/app/ui.js @@ -180,6 +180,7 @@ const UI = { UI.initSetting('shared', true); UI.initSetting('view_only', false); UI.initSetting('show_dot', false); + UI.initSetting('ultravnc_gestures', false); UI.initSetting('path', 'websockify'); UI.initSetting('repeaterID', ''); UI.initSetting('reconnect', false); @@ -368,6 +369,7 @@ const UI = { UI.addSettingChangeHandler('view_only', UI.updateViewOnly); UI.addSettingChangeHandler('show_dot'); UI.addSettingChangeHandler('show_dot', UI.updateShowDotCursor); + UI.addSettingChangeHandler('ultravnc_gestures'); UI.addSettingChangeHandler('host'); UI.addSettingChangeHandler('port'); UI.addSettingChangeHandler('path'); @@ -438,6 +440,7 @@ const UI = { UI.disableSetting('port'); UI.disableSetting('path'); UI.disableSetting('repeaterID'); + UI.disableSetting('ultravnc_gestures'); // Hide the controlbar after 2 seconds UI.closeControlbarTimeout = setTimeout(UI.closeControlbar, 2000); @@ -448,6 +451,7 @@ const UI = { UI.enableSetting('port'); UI.enableSetting('path'); UI.enableSetting('repeaterID'); + UI.enableSetting('ultravnc_gestures'); UI.updatePowerButton(); UI.keepControlbar(); } @@ -1045,7 +1049,8 @@ const UI = { UI.rfb = new RFB(document.getElementById('noVNC_container'), url, { shared: UI.getSetting('shared'), repeaterID: UI.getSetting('repeaterID'), - credentials: { password: password } }); + credentials: { password: password }, + useUltraVNCGestures: UI.getSetting('ultravnc_gestures') }); } catch (exc) { Log.Error("Failed to connect to server: " + exc); UI.updateVisualState('disconnected'); diff --git a/core/encodings.js b/core/encodings.js index 1a79989d..1e43738b 100644 --- a/core/encodings.js +++ b/core/encodings.js @@ -23,6 +23,7 @@ export const encodings = { pseudoEncodingCursor: -239, pseudoEncodingQEMUExtendedKeyEvent: -258, pseudoEncodingQEMULedEvent: -261, + pseudoEncodingGii: -305, pseudoEncodingDesktopName: -307, pseudoEncodingExtendedDesktopSize: -308, pseudoEncodingXvp: -309, diff --git a/core/input/touchhandlerultravnc.js b/core/input/touchhandlerultravnc.js new file mode 100644 index 00000000..c9ccac91 --- /dev/null +++ b/core/input/touchhandlerultravnc.js @@ -0,0 +1,112 @@ +import * as Log from '../util/logging.js'; + +export default class TouchHandlerUltraVNC { + static PF_flag = 0x80000000; // Pressed Flag : active if the touch event is pressed, inactive if it's being released. + static R1_flag = 0x40000000; // Reserved 1 + static IF_flag = 0x20000000; // Primary Flag : active if the touch event is the primary touch event. + static S1_flag = 0x10000000; // Size Flag : active if the message contains information about the size of the touch event. The events are currently all sent as symetrical ellipses. + static S2_flag = 0x8000000; // Reserved for asymetrical ellipses. Not supported yet and should be 0. + static RT_flag = 0x4000000; // Rectangle : the touch event is a rectangle instead of an ellipse. + static PR_flag = 0x2000000; // Pressure Flag : pressure of the touch. Currently unused. + static TI_flag = 0x1000000; // Timestamp : the timestamp of the touch event. + static HC_flag = 0x800000; // High Performance Counter + + static LENGTH_16_flag = 0x10; // 16 bits signed for x touch coordinate followed by 16 bits signed for y together in a 32 bits word + static IDFORMAT_32 = 0x1; // 32 bits ID + static IDFORMAT_CLEAR = 0xF; // No more touch points + + constructor() { + this._target = null; + + this._currentTouches = []; + this._sendTouchesIntervalId = -1; + this._giiDeviceOrigin = 0; + this._isUltraVNCTouchActivated = false; + + this._boundEventHandler = this._handleTouch.bind(this); + } + + attach(target) { + this.detach(); + + this._target = target; + this._target.addEventListener('touchstart', + this._boundEventHandler); + this._target.addEventListener('touchmove', + this._boundEventHandler); + this._target.addEventListener('touchend', + this._boundEventHandler); + this._target.addEventListener('touchcancel', + this._boundEventHandler); + } + + detach() { + if (!this._target) { + return; + } + + this._target.removeEventListener('touchstart', + this._boundEventHandler); + this._target.removeEventListener('touchmove', + this._boundEventHandler); + this._target.removeEventListener('touchend', + this._boundEventHandler); + this._target.removeEventListener('touchcancel', + this._boundEventHandler); + + clearInterval(this._sendTouchesIntervalId); + this._sendTouchesIntervalId = -1; + + this._target = null; + } + + _handleTouch(ev) { + Log.Debug("Gesture: " + ev.type); + + if (!this._isUltraVNCTouchActivated) { + return; + } + + if (ev.type === "touchstart") { + for (let i = 0; i < ev.changedTouches.length; i++) { + this._currentTouches.push({ event: ev.changedTouches[i], status: "POINTER_DOWN" }); + } + + if (this._sendTouchesIntervalId === -1 && this._target) { + this._dispatchTouchEvent(ev); + this._sendTouchesIntervalId = setInterval(() => { + this._dispatchTouchEvent(ev); + }, 200); + } + } else if (ev.type === "touchmove") { + for (let i = 0; i < ev.changedTouches.length; i++) { + const index = this._currentTouches.findIndex(t => t.event.identifier === ev.changedTouches[i].identifier); + if (index !== -1) { + this._currentTouches[index].event = ev.changedTouches[i]; + this._currentTouches[index].status = "POINTER_UPDATE"; + } + } + } else if (ev.type === "touchend" || ev.type === "touchcancel") { + for (let i = 0; i < ev.changedTouches.length; i++) { + const index = this._currentTouches.findIndex(t => t.event.identifier === ev.changedTouches[i].identifier); + if (index !== -1) { + this._currentTouches[index].status = "POINTER_UP"; + } + } + } + } + + _dispatchTouchEvent(ev) { + let tev = new CustomEvent('ultravnctouch', { event: ev, detail: { currentTouches: this._currentTouches, giiDeviceOrigin: this._giiDeviceOrigin } }); + this._target.dispatchEvent(tev); + } + + _removeTouch(index) { + this._currentTouches.splice(index, 1); + } + + _interruptTouches() { + clearInterval(this._sendTouchesIntervalId); + this._sendTouchesIntervalId = -1; + } +} \ No newline at end of file diff --git a/core/rfb.js b/core/rfb.js index f2deb0e7..b45b5172 100644 --- a/core/rfb.js +++ b/core/rfb.js @@ -19,6 +19,7 @@ import Inflator from "./inflator.js"; import Deflator from "./deflator.js"; import Keyboard from "./input/keyboard.js"; import GestureHandler from "./input/gesturehandler.js"; +import TouchHandlerUltraVNC from "./input/touchhandlerultravnc.js"; import Cursor from "./util/cursor.js"; import Websock from "./websock.js"; import KeyTable from "./input/keysym.js"; @@ -117,6 +118,7 @@ export default class RFB extends EventTargetMixin { this._shared = 'shared' in options ? !!options.shared : true; this._repeaterID = options.repeaterID || ''; this._wsProtocols = options.wsProtocols || []; + this._useUltraVNCGestures = options.useUltraVNCGestures || false; // Internal state this._rfbConnectionState = ''; @@ -202,6 +204,7 @@ export default class RFB extends EventTargetMixin { handleMouse: this._handleMouse.bind(this), handleWheel: this._handleWheel.bind(this), handleGesture: this._handleGesture.bind(this), + handleUltraVNCTouch: this._handleUltraVNCTouch.bind(this), handleRSAAESCredentialsRequired: this._handleRSAAESCredentialsRequired.bind(this), handleRSAAESServerVerification: this._handleRSAAESServerVerification.bind(this), }; @@ -263,7 +266,11 @@ export default class RFB extends EventTargetMixin { this._remoteCapsLock = null; // Null indicates unknown or irrelevant this._remoteNumLock = null; - this._gestures = new GestureHandler(); + if (this._useUltraVNCGestures) { + this._gestures = new TouchHandlerUltraVNC(); + } else { + this._gestures = new GestureHandler(); + } this._sock = new Websock(); this._sock.on('open', this._socketOpen.bind(this)); @@ -594,9 +601,13 @@ export default class RFB extends EventTargetMixin { this._canvas.addEventListener("wheel", this._eventHandlers.handleWheel); // Gesture events - this._canvas.addEventListener("gesturestart", this._eventHandlers.handleGesture); - this._canvas.addEventListener("gesturemove", this._eventHandlers.handleGesture); - this._canvas.addEventListener("gestureend", this._eventHandlers.handleGesture); + if (this._useUltraVNCGestures) { + this._canvas.addEventListener('ultravnctouch', this._eventHandlers.handleUltraVNCTouch); + } else { + this._canvas.addEventListener('gesturestart', this._eventHandlers.handleGesture); + this._canvas.addEventListener('gesturemove', this._eventHandlers.handleGesture); + this._canvas.addEventListener('gestureend', this._eventHandlers.handleGesture); + } Log.Debug("<< RFB.connect"); } @@ -604,9 +615,13 @@ export default class RFB extends EventTargetMixin { _disconnect() { Log.Debug(">> RFB.disconnect"); this._cursor.detach(); - this._canvas.removeEventListener("gesturestart", this._eventHandlers.handleGesture); - this._canvas.removeEventListener("gesturemove", this._eventHandlers.handleGesture); - this._canvas.removeEventListener("gestureend", this._eventHandlers.handleGesture); + if (this._useUltraVNCGestures) { + this._canvas.removeEventListener('ultravnctouch', this._eventHandlers.handleUltraVNCTouch); + } else { + this._canvas.removeEventListener('gesturestart', this._eventHandlers.handleGesture); + this._canvas.removeEventListener('gesturemove', this._eventHandlers.handleGesture); + this._canvas.removeEventListener('gestureend', this._eventHandlers.handleGesture); + } this._canvas.removeEventListener("wheel", this._eventHandlers.handleWheel); this._canvas.removeEventListener('mousedown', this._eventHandlers.handleMouse); this._canvas.removeEventListener('mouseup', this._eventHandlers.handleMouse); @@ -1374,6 +1389,87 @@ export default class RFB extends EventTargetMixin { } } + _handleUltraVNCTouch(ev) { + Log.Debug("SENDING " + ev.detail.currentTouches.length + " TOUCH(ES)"); + this._sock.sQpush8(253); // GII message type + this._sock.sQpush8(128); // GII event + this._sock.sQpush16(4 + 16 + (6 * 2 * ev.detail.currentTouches.length)); // Length + this._sock.sQpush8(4 + 16 + (6 * 2 * ev.detail.currentTouches.length)); // eventSize + this._sock.sQpush8(12); // eventType + this._sock.sQpush16(0); // padding + this._sock.sQpush32(ev.detail.giiDeviceOrigin); // deviceOrigin + this._sock.sQpush32(ev.detail.currentTouches.length); // first + this._sock.sQpush32(6 * ev.detail.currentTouches.length); // count + + let pointerUpIds = []; + + // Send all current touches + for (let i = 0; i < ev.detail.currentTouches.length; i++) { + Log.Debug("Touch Id: " + ev.detail.currentTouches[i].event.identifier); + let valuatorFlag = 0x00000000; + valuatorFlag |= TouchHandlerUltraVNC.LENGTH_16_flag; + valuatorFlag |= TouchHandlerUltraVNC.IDFORMAT_32; + if (ev.detail.currentTouches[i].status !== "POINTER_UP") valuatorFlag |= TouchHandlerUltraVNC.PF_flag; + if (ev.detail.currentTouches[i].event.identifier === 0) valuatorFlag |= TouchHandlerUltraVNC.IF_flag; // IF_flag + + this._sock.sQpush32(valuatorFlag); + this._sock.sQpush32(ev.detail.currentTouches[i].event.identifier); + + let scaledPosition = clientToElement(ev.detail.currentTouches[i].event.clientX, ev.detail.currentTouches[i].event.clientY, + this._canvas); + + if ((valuatorFlag & TouchHandlerUltraVNC.LENGTH_16_flag) !== 0) { + let scaledX16 = Math.floor(scaledPosition.x) & 0xFFFF; + let scaledY16 = Math.floor(scaledPosition.y) & 0xFFFF; + let coordinates = (Math.floor(scaledX16) << 16) | (Math.floor(scaledY16)); + this._sock.sQpush32(coordinates); + } + + // Keep track of last released touches + if (ev.detail.currentTouches[i].status === "POINTER_UP") { + pointerUpIds.push(ev.detail.currentTouches[i].event.identifier); + } + } + + this._sock.flush(); + + // Remove released touches from current touches in handler + for (let i = 0; i < pointerUpIds.length; i++) { + const index = ev.detail.currentTouches.findIndex(t => t.event.identifier === pointerUpIds[i]); + if (index !== -1) { + this._gestures._removeTouch(index); + } + } + + // Interrupt touch sending interval + if (ev.detail.currentTouches.length === 0 && this._sendTouchesIntervalId !== -1) { + Log.Debug("NO MORE TOUCHES\n"); + this._gestures._interruptTouches(); + this._sendEmptyTouch(ev.detail.giiDeviceOrigin); + return; + } + } + + _sendEmptyTouch(giiDeviceOrigin) { + let valuatorFlag = 0x00000000; + valuatorFlag |= TouchHandlerUltraVNC.LENGTH_16_flag; + valuatorFlag |= TouchHandlerUltraVNC.IDFORMAT_CLEAR; + + this._sock.sQpush8(253); // GII message type + this._sock.sQpush8(128); // GII event + this._sock.sQpush16(24); // Header length + this._sock.sQpush8(24); // Event size + this._sock.sQpush8(12); // eventType + this._sock.sQpush16(0); // padding + this._sock.sQpush32(giiDeviceOrigin); // deviceOrigin + this._sock.sQpush32(1); // first + this._sock.sQpush32(4); // Count + this._sock.sQpush32(valuatorFlag); // Flag + this._sock.sQpush32(0); // Empty Id + this._sock.sQpush32(0); // Empty coordinates + this._sock.flush(); + } + // Message Handlers _negotiateProtocolVersion() { @@ -2139,6 +2235,10 @@ export default class RFB extends EventTargetMixin { encs.push(encodings.pseudoEncodingDesktopName); encs.push(encodings.pseudoEncodingExtendedClipboard); + if (this._useUltraVNCGestures) { + encs.push(encodings.pseudoEncodingGii); + } + if (this._fbDepth == 24) { encs.push(encodings.pseudoEncodingVMwareCursor); encs.push(encodings.pseudoEncodingCursor); @@ -2434,6 +2534,25 @@ export default class RFB extends EventTargetMixin { return true; } + _handleGiiMsg() { + let giiMsgSubtype = this._sock.rQshift8(); + + switch (giiMsgSubtype) { + case 129: // GII Version Message + this._sock.rQskipBytes(34); + RFB.messages.giiVersionMessage(this._sock); + RFB.messages.giiDeviceCreation(this._sock); + break; + case 130: // GII Device Creation + this._sock.rQshiftBytes(2); + this._gestures._giiDeviceOrigin = this._sock.rQshift32(); + if (this._gestures._giiDeviceOrigin) this._gestures._isUltraVNCTouchActivated = true; + break; + } + + return true; + } + _normalMsg() { let msgType; if (this._FBU.rects > 0) { @@ -2485,6 +2604,9 @@ export default class RFB extends EventTargetMixin { case 250: // XVP return this._handleXvpMsg(); + case 253: // GII + return this._handleGiiMsg(); + default: this._fail("Unexpected server message (type " + msgType + ")"); Log.Debug("sock.rQpeekBytes(30): " + this._sock.rQpeekBytes(30)); @@ -2933,6 +3055,16 @@ export default class RFB extends EventTargetMixin { "raw", passwordChars, { name: "DES-ECB" }, false, ["encrypt"]); return legacyCrypto.encrypt({ name: "DES-ECB" }, key, challenge); } + + static stringAsByteArrayWithPadding(str, size) { + let full = new Uint8Array(size); + let utf8Encode = new TextEncoder(); + let strArray = utf8Encode.encode(str); + for (let i = 0; i < strArray.length; i++) { + full[i] = strArray[i]; + } + return full; + } } // Class Methods @@ -3224,6 +3356,44 @@ RFB.messages = { sock.sQpush8(ver); sock.sQpush8(op); + sock.flush(); + }, + + giiVersionMessage(sock) { + sock.sQpush8(253); // gii msg-type + sock.sQpush8(129); // gii version sub-msg-type + sock.sQpush16(2); // length + sock.sQpush16(1); // version + + sock.flush(); + }, + + giiDeviceCreation(sock) { + sock.sQpush8(253); // gii msg-type + sock.sQpush8(130); // gii device creation sub-msg-type + sock.sQpush16(172); // length + sock.sQpushBytes(RFB.stringAsByteArrayWithPadding("NOVNC-MT", 31)); // device name + sock.sQpush8(0); // DNTerm + sock.sQpush32(0x0908); // vendorID + sock.sQpush32(0x000b); // productID + sock.sQpush32(0x00002000); // eventMask + sock.sQpush32(0); // numRegisters + sock.sQpush32(1); // numValuators + sock.sQpush32(5); // numButtons + sock.sQpush32(0); // index + sock.sQpushBytes(RFB.stringAsByteArrayWithPadding("NOVNC Multitouch Device", 74)); // longName + sock.sQpush8(0); // LNTerm + sock.sQpushBytes(RFB.stringAsByteArrayWithPadding("NMD", 4)); // shortName + sock.sQpush8(0); // SNTerm + sock.sQpush32(0); // rangeMin + sock.sQpush32(0); // rangeCenter + sock.sQpush32(0); // rangeMax + sock.sQpush32(0); // SIUnit + sock.sQpush32(0); // SIAdd + sock.sQpush32(0); // SIMul + sock.sQpush32(0); // SIDiv + sock.sQpush32(0); // SIShift + sock.flush(); } }; diff --git a/vnc.html b/vnc.html index 24a118db..6209aa65 100644 --- a/vnc.html +++ b/vnc.html @@ -220,6 +220,7 @@

  • +

  • From c1efe1f9871d1c1f9bad342cbde1f170958e7ade Mon Sep 17 00:00:00 2001 From: Rui Reis Date: Wed, 31 Jul 2024 15:44:55 +0200 Subject: [PATCH 2/4] Fix local scaling touch position --- core/rfb.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/core/rfb.js b/core/rfb.js index b45b5172..2c58471d 100644 --- a/core/rfb.js +++ b/core/rfb.js @@ -1419,9 +1419,9 @@ export default class RFB extends EventTargetMixin { this._canvas); if ((valuatorFlag & TouchHandlerUltraVNC.LENGTH_16_flag) !== 0) { - let scaledX16 = Math.floor(scaledPosition.x) & 0xFFFF; - let scaledY16 = Math.floor(scaledPosition.y) & 0xFFFF; - let coordinates = (Math.floor(scaledX16) << 16) | (Math.floor(scaledY16)); + let scaledX16 = this._display.absX(scaledPosition.x) & 0xFFFF; + let scaledY16 = this._display.absY(scaledPosition.y) & 0xFFFF; + let coordinates = (scaledX16 << 16) | scaledY16; this._sock.sQpush32(coordinates); } @@ -2535,15 +2535,20 @@ export default class RFB extends EventTargetMixin { } _handleGiiMsg() { + if (this._sock.rQwait("GII message subtype", 1, 1)) { + return false; + } let giiMsgSubtype = this._sock.rQshift8(); switch (giiMsgSubtype) { case 129: // GII Version Message + if (this._sock.rQwait("GII version message", 34, 1)) { return false; } this._sock.rQskipBytes(34); RFB.messages.giiVersionMessage(this._sock); RFB.messages.giiDeviceCreation(this._sock); break; case 130: // GII Device Creation + if (this._sock.rQwait("GII device creation", 6, 1)) { return false; } this._sock.rQshiftBytes(2); this._gestures._giiDeviceOrigin = this._sock.rQshift32(); if (this._gestures._giiDeviceOrigin) this._gestures._isUltraVNCTouchActivated = true; From 6b770c9da26e47454416e5d49a16e2365c8d9f23 Mon Sep 17 00:00:00 2001 From: Rui Reis Date: Wed, 31 Jul 2024 15:45:33 +0200 Subject: [PATCH 3/4] Fix touches with same id not being removed properly --- core/input/touchhandlerultravnc.js | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/core/input/touchhandlerultravnc.js b/core/input/touchhandlerultravnc.js index c9ccac91..05fba0ef 100644 --- a/core/input/touchhandlerultravnc.js +++ b/core/input/touchhandlerultravnc.js @@ -88,14 +88,20 @@ export default class TouchHandlerUltraVNC { } } else if (ev.type === "touchend" || ev.type === "touchcancel") { for (let i = 0; i < ev.changedTouches.length; i++) { - const index = this._currentTouches.findIndex(t => t.event.identifier === ev.changedTouches[i].identifier); - if (index !== -1) { - this._currentTouches[index].status = "POINTER_UP"; - } + const indexes = this._getAllIndexes(this._currentTouches, (t) => t.event.identifier === ev.changedTouches[i].identifier) + indexes.forEach((index) => this._currentTouches[index].status = "POINTER_UP"); } } } + _getAllIndexes(arr, func) { + var indexes = [], i; + for (i = 0; i < arr.length; i++) + if (func(arr[i])) + indexes.push(i); + return indexes; + } + _dispatchTouchEvent(ev) { let tev = new CustomEvent('ultravnctouch', { event: ev, detail: { currentTouches: this._currentTouches, giiDeviceOrigin: this._giiDeviceOrigin } }); this._target.dispatchEvent(tev); From 43ddc6c982114dbe1299539f908aa3783b19d4a0 Mon Sep 17 00:00:00 2001 From: Rui Reis Date: Tue, 24 Sep 2024 09:23:45 +0200 Subject: [PATCH 4/4] Add preventDefault in UltraVNC touch and manage touch ids manually --- core/input/touchhandlerultravnc.js | 12 +++++++++++- core/rfb.js | 4 +--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/core/input/touchhandlerultravnc.js b/core/input/touchhandlerultravnc.js index 05fba0ef..48bb0015 100644 --- a/core/input/touchhandlerultravnc.js +++ b/core/input/touchhandlerultravnc.js @@ -61,7 +61,8 @@ export default class TouchHandlerUltraVNC { } _handleTouch(ev) { - Log.Debug("Gesture: " + ev.type); + ev.preventDefault(); + ev.stopImmediatePropagation(); if (!this._isUltraVNCTouchActivated) { return; @@ -69,6 +70,7 @@ export default class TouchHandlerUltraVNC { if (ev.type === "touchstart") { for (let i = 0; i < ev.changedTouches.length; i++) { + ev.changedTouches[i].touchIdentifier = this._getTouchIdentifier(); this._currentTouches.push({ event: ev.changedTouches[i], status: "POINTER_DOWN" }); } @@ -82,6 +84,7 @@ export default class TouchHandlerUltraVNC { for (let i = 0; i < ev.changedTouches.length; i++) { const index = this._currentTouches.findIndex(t => t.event.identifier === ev.changedTouches[i].identifier); if (index !== -1) { + ev.changedTouches[i].touchIdentifier = this._currentTouches[index].event.touchIdentifier; this._currentTouches[index].event = ev.changedTouches[i]; this._currentTouches[index].status = "POINTER_UPDATE"; } @@ -102,6 +105,13 @@ export default class TouchHandlerUltraVNC { return indexes; } + _getTouchIdentifier() { + const ids = this._currentTouches.map((ev) => ev.event.touchIdentifier); + let i = 0; + while (ids.includes(i)) { i++; } + return i; + } + _dispatchTouchEvent(ev) { let tev = new CustomEvent('ultravnctouch', { event: ev, detail: { currentTouches: this._currentTouches, giiDeviceOrigin: this._giiDeviceOrigin } }); this._target.dispatchEvent(tev); diff --git a/core/rfb.js b/core/rfb.js index 2c58471d..8129ecf6 100644 --- a/core/rfb.js +++ b/core/rfb.js @@ -1390,7 +1390,6 @@ export default class RFB extends EventTargetMixin { } _handleUltraVNCTouch(ev) { - Log.Debug("SENDING " + ev.detail.currentTouches.length + " TOUCH(ES)"); this._sock.sQpush8(253); // GII message type this._sock.sQpush8(128); // GII event this._sock.sQpush16(4 + 16 + (6 * 2 * ev.detail.currentTouches.length)); // Length @@ -1405,7 +1404,6 @@ export default class RFB extends EventTargetMixin { // Send all current touches for (let i = 0; i < ev.detail.currentTouches.length; i++) { - Log.Debug("Touch Id: " + ev.detail.currentTouches[i].event.identifier); let valuatorFlag = 0x00000000; valuatorFlag |= TouchHandlerUltraVNC.LENGTH_16_flag; valuatorFlag |= TouchHandlerUltraVNC.IDFORMAT_32; @@ -1413,7 +1411,7 @@ export default class RFB extends EventTargetMixin { if (ev.detail.currentTouches[i].event.identifier === 0) valuatorFlag |= TouchHandlerUltraVNC.IF_flag; // IF_flag this._sock.sQpush32(valuatorFlag); - this._sock.sQpush32(ev.detail.currentTouches[i].event.identifier); + this._sock.sQpush32(ev.detail.currentTouches[i].event.touchIdentifier); let scaledPosition = clientToElement(ev.detail.currentTouches[i].event.clientX, ev.detail.currentTouches[i].event.clientY, this._canvas);