@novnc/novnc 1.0.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AUTHORS +13 -0
- package/LICENSE.txt +2 -1
- package/README.md +69 -3
- package/core/base64.js +35 -41
- package/core/decoders/copyrect.js +22 -0
- package/core/decoders/hextile.js +137 -0
- package/core/decoders/raw.js +56 -0
- package/core/decoders/rre.js +44 -0
- package/core/decoders/tight.js +315 -0
- package/core/decoders/tightpng.js +27 -0
- package/core/deflator.js +85 -0
- package/core/des.js +90 -95
- package/core/display.js +254 -297
- package/core/encodings.js +7 -3
- package/core/inflator.js +48 -20
- package/core/input/domkeytable.js +21 -24
- package/core/input/fixedkeys.js +3 -1
- package/core/input/gesturehandler.js +567 -0
- package/core/input/keyboard.js +194 -120
- package/core/input/keysym.js +2 -0
- package/core/input/keysymdef.js +3 -3
- package/core/input/util.js +53 -12
- package/core/input/vkeys.js +2 -1
- package/core/rfb.js +1937 -1496
- package/core/util/browser.js +80 -29
- package/core/util/cursor.js +253 -0
- package/core/util/element.js +32 -0
- package/core/util/events.js +59 -55
- package/core/util/eventtarget.js +25 -30
- package/core/util/int.js +15 -0
- package/core/util/logging.js +21 -16
- package/core/util/polyfill.js +15 -8
- package/core/util/strings.js +21 -8
- package/core/websock.js +145 -167
- package/docs/API.md +31 -10
- package/lib/base64.js +115 -0
- package/lib/decoders/copyrect.js +44 -0
- package/lib/decoders/hextile.js +173 -0
- package/lib/decoders/raw.js +78 -0
- package/lib/decoders/rre.js +65 -0
- package/lib/decoders/tight.js +350 -0
- package/lib/decoders/tightpng.js +67 -0
- package/lib/deflator.js +99 -0
- package/lib/des.js +314 -0
- package/lib/display.js +733 -0
- package/lib/encodings.js +64 -0
- package/lib/inflator.js +87 -0
- package/lib/input/domkeytable.js +282 -0
- package/lib/input/fixedkeys.js +123 -0
- package/lib/input/gesturehandler.js +642 -0
- package/lib/input/keyboard.js +429 -0
- package/lib/input/keysym.js +1135 -0
- package/lib/input/keysymdef.js +1354 -0
- package/lib/input/util.js +304 -0
- package/lib/input/vkeys.js +127 -0
- package/lib/input/xtscancodes.js +505 -0
- package/lib/rfb.js +3448 -0
- package/lib/util/browser.js +131 -0
- package/lib/util/cursor.js +314 -0
- package/lib/util/element.js +43 -0
- package/lib/util/events.js +142 -0
- package/lib/util/eventtarget.js +64 -0
- package/lib/util/int.js +22 -0
- package/lib/util/logging.js +79 -0
- package/lib/util/polyfill.js +72 -0
- package/lib/util/strings.js +38 -0
- package/lib/vendor/pako/lib/utils/common.js +67 -0
- package/lib/vendor/pako/lib/zlib/adler32.js +33 -0
- package/lib/vendor/pako/lib/zlib/constants.js +51 -0
- package/lib/vendor/pako/lib/zlib/crc32.js +42 -0
- package/lib/vendor/pako/lib/zlib/deflate.js +2159 -0
- package/lib/vendor/pako/lib/zlib/gzheader.js +53 -0
- package/lib/vendor/pako/lib/zlib/inffast.js +445 -0
- package/lib/vendor/pako/lib/zlib/inflate.js +2114 -0
- package/lib/vendor/pako/lib/zlib/inftrees.js +418 -0
- package/lib/vendor/pako/lib/zlib/messages.js +36 -0
- package/lib/vendor/pako/lib/zlib/trees.js +1499 -0
- package/lib/vendor/pako/lib/zlib/zstream.js +46 -0
- package/lib/vendor/promise.js +255 -0
- package/lib/websock.js +374 -0
- package/package.json +48 -28
- package/vendor/pako/lib/zlib/deflate.js +30 -30
- package/vendor/pako/lib/zlib/inflate.js +17 -17
- package/core/input/mouse.js +0 -280
- package/docs/API-internal.md +0 -125
- package/docs/EMBEDDING.md +0 -83
- package/docs/VERSION +0 -1
|
@@ -0,0 +1,642 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
|
|
8
|
+
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
9
|
+
|
|
10
|
+
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
|
|
11
|
+
|
|
12
|
+
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
|
|
13
|
+
|
|
14
|
+
/*
|
|
15
|
+
* noVNC: HTML5 VNC client
|
|
16
|
+
* Copyright (C) 2020 The noVNC Authors
|
|
17
|
+
* Licensed under MPL 2.0 (see LICENSE.txt)
|
|
18
|
+
*
|
|
19
|
+
* See README.md for usage and integration instructions.
|
|
20
|
+
*
|
|
21
|
+
*/
|
|
22
|
+
var GH_NOGESTURE = 0;
|
|
23
|
+
var GH_ONETAP = 1;
|
|
24
|
+
var GH_TWOTAP = 2;
|
|
25
|
+
var GH_THREETAP = 4;
|
|
26
|
+
var GH_DRAG = 8;
|
|
27
|
+
var GH_LONGPRESS = 16;
|
|
28
|
+
var GH_TWODRAG = 32;
|
|
29
|
+
var GH_PINCH = 64;
|
|
30
|
+
var GH_INITSTATE = 127;
|
|
31
|
+
var GH_MOVE_THRESHOLD = 50;
|
|
32
|
+
var GH_ANGLE_THRESHOLD = 90; // Degrees
|
|
33
|
+
// Timeout when waiting for gestures (ms)
|
|
34
|
+
|
|
35
|
+
var GH_MULTITOUCH_TIMEOUT = 250; // Maximum time between press and release for a tap (ms)
|
|
36
|
+
|
|
37
|
+
var GH_TAP_TIMEOUT = 1000; // Timeout when waiting for longpress (ms)
|
|
38
|
+
|
|
39
|
+
var GH_LONGPRESS_TIMEOUT = 1000; // Timeout when waiting to decide between PINCH and TWODRAG (ms)
|
|
40
|
+
|
|
41
|
+
var GH_TWOTOUCH_TIMEOUT = 50;
|
|
42
|
+
|
|
43
|
+
var GestureHandler = /*#__PURE__*/function () {
|
|
44
|
+
function GestureHandler() {
|
|
45
|
+
_classCallCheck(this, GestureHandler);
|
|
46
|
+
|
|
47
|
+
this._target = null;
|
|
48
|
+
this._state = GH_INITSTATE;
|
|
49
|
+
this._tracked = [];
|
|
50
|
+
this._ignored = [];
|
|
51
|
+
this._waitingRelease = false;
|
|
52
|
+
this._releaseStart = 0.0;
|
|
53
|
+
this._longpressTimeoutId = null;
|
|
54
|
+
this._twoTouchTimeoutId = null;
|
|
55
|
+
this._boundEventHandler = this._eventHandler.bind(this);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
_createClass(GestureHandler, [{
|
|
59
|
+
key: "attach",
|
|
60
|
+
value: function attach(target) {
|
|
61
|
+
this.detach();
|
|
62
|
+
this._target = target;
|
|
63
|
+
|
|
64
|
+
this._target.addEventListener('touchstart', this._boundEventHandler);
|
|
65
|
+
|
|
66
|
+
this._target.addEventListener('touchmove', this._boundEventHandler);
|
|
67
|
+
|
|
68
|
+
this._target.addEventListener('touchend', this._boundEventHandler);
|
|
69
|
+
|
|
70
|
+
this._target.addEventListener('touchcancel', this._boundEventHandler);
|
|
71
|
+
}
|
|
72
|
+
}, {
|
|
73
|
+
key: "detach",
|
|
74
|
+
value: function detach() {
|
|
75
|
+
if (!this._target) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
this._stopLongpressTimeout();
|
|
80
|
+
|
|
81
|
+
this._stopTwoTouchTimeout();
|
|
82
|
+
|
|
83
|
+
this._target.removeEventListener('touchstart', this._boundEventHandler);
|
|
84
|
+
|
|
85
|
+
this._target.removeEventListener('touchmove', this._boundEventHandler);
|
|
86
|
+
|
|
87
|
+
this._target.removeEventListener('touchend', this._boundEventHandler);
|
|
88
|
+
|
|
89
|
+
this._target.removeEventListener('touchcancel', this._boundEventHandler);
|
|
90
|
+
|
|
91
|
+
this._target = null;
|
|
92
|
+
}
|
|
93
|
+
}, {
|
|
94
|
+
key: "_eventHandler",
|
|
95
|
+
value: function _eventHandler(e) {
|
|
96
|
+
var fn;
|
|
97
|
+
e.stopPropagation();
|
|
98
|
+
e.preventDefault();
|
|
99
|
+
|
|
100
|
+
switch (e.type) {
|
|
101
|
+
case 'touchstart':
|
|
102
|
+
fn = this._touchStart;
|
|
103
|
+
break;
|
|
104
|
+
|
|
105
|
+
case 'touchmove':
|
|
106
|
+
fn = this._touchMove;
|
|
107
|
+
break;
|
|
108
|
+
|
|
109
|
+
case 'touchend':
|
|
110
|
+
case 'touchcancel':
|
|
111
|
+
fn = this._touchEnd;
|
|
112
|
+
break;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
for (var i = 0; i < e.changedTouches.length; i++) {
|
|
116
|
+
var touch = e.changedTouches[i];
|
|
117
|
+
fn.call(this, touch.identifier, touch.clientX, touch.clientY);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}, {
|
|
121
|
+
key: "_touchStart",
|
|
122
|
+
value: function _touchStart(id, x, y) {
|
|
123
|
+
// Ignore any new touches if there is already an active gesture,
|
|
124
|
+
// or we're in a cleanup state
|
|
125
|
+
if (this._hasDetectedGesture() || this._state === GH_NOGESTURE) {
|
|
126
|
+
this._ignored.push(id);
|
|
127
|
+
|
|
128
|
+
return;
|
|
129
|
+
} // Did it take too long between touches that we should no longer
|
|
130
|
+
// consider this a single gesture?
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
if (this._tracked.length > 0 && Date.now() - this._tracked[0].started > GH_MULTITOUCH_TIMEOUT) {
|
|
134
|
+
this._state = GH_NOGESTURE;
|
|
135
|
+
|
|
136
|
+
this._ignored.push(id);
|
|
137
|
+
|
|
138
|
+
return;
|
|
139
|
+
} // If we're waiting for fingers to release then we should no longer
|
|
140
|
+
// recognize new touches
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
if (this._waitingRelease) {
|
|
144
|
+
this._state = GH_NOGESTURE;
|
|
145
|
+
|
|
146
|
+
this._ignored.push(id);
|
|
147
|
+
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
this._tracked.push({
|
|
152
|
+
id: id,
|
|
153
|
+
started: Date.now(),
|
|
154
|
+
active: true,
|
|
155
|
+
firstX: x,
|
|
156
|
+
firstY: y,
|
|
157
|
+
lastX: x,
|
|
158
|
+
lastY: y,
|
|
159
|
+
angle: 0
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
switch (this._tracked.length) {
|
|
163
|
+
case 1:
|
|
164
|
+
this._startLongpressTimeout();
|
|
165
|
+
|
|
166
|
+
break;
|
|
167
|
+
|
|
168
|
+
case 2:
|
|
169
|
+
this._state &= ~(GH_ONETAP | GH_DRAG | GH_LONGPRESS);
|
|
170
|
+
|
|
171
|
+
this._stopLongpressTimeout();
|
|
172
|
+
|
|
173
|
+
break;
|
|
174
|
+
|
|
175
|
+
case 3:
|
|
176
|
+
this._state &= ~(GH_TWOTAP | GH_TWODRAG | GH_PINCH);
|
|
177
|
+
break;
|
|
178
|
+
|
|
179
|
+
default:
|
|
180
|
+
this._state = GH_NOGESTURE;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}, {
|
|
184
|
+
key: "_touchMove",
|
|
185
|
+
value: function _touchMove(id, x, y) {
|
|
186
|
+
var touch = this._tracked.find(function (t) {
|
|
187
|
+
return t.id === id;
|
|
188
|
+
}); // If this is an update for a touch we're not tracking, ignore it
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
if (touch === undefined) {
|
|
192
|
+
return;
|
|
193
|
+
} // Update the touches last position with the event coordinates
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
touch.lastX = x;
|
|
197
|
+
touch.lastY = y;
|
|
198
|
+
var deltaX = x - touch.firstX;
|
|
199
|
+
var deltaY = y - touch.firstY; // Update angle when the touch has moved
|
|
200
|
+
|
|
201
|
+
if (touch.firstX !== touch.lastX || touch.firstY !== touch.lastY) {
|
|
202
|
+
touch.angle = Math.atan2(deltaY, deltaX) * 180 / Math.PI;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
if (!this._hasDetectedGesture()) {
|
|
206
|
+
// Ignore moves smaller than the minimum threshold
|
|
207
|
+
if (Math.hypot(deltaX, deltaY) < GH_MOVE_THRESHOLD) {
|
|
208
|
+
return;
|
|
209
|
+
} // Can't be a tap or long press as we've seen movement
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
this._state &= ~(GH_ONETAP | GH_TWOTAP | GH_THREETAP | GH_LONGPRESS);
|
|
213
|
+
|
|
214
|
+
this._stopLongpressTimeout();
|
|
215
|
+
|
|
216
|
+
if (this._tracked.length !== 1) {
|
|
217
|
+
this._state &= ~GH_DRAG;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
if (this._tracked.length !== 2) {
|
|
221
|
+
this._state &= ~(GH_TWODRAG | GH_PINCH);
|
|
222
|
+
} // We need to figure out which of our different two touch gestures
|
|
223
|
+
// this might be
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
if (this._tracked.length === 2) {
|
|
227
|
+
// The other touch is the one where the id doesn't match
|
|
228
|
+
var prevTouch = this._tracked.find(function (t) {
|
|
229
|
+
return t.id !== id;
|
|
230
|
+
}); // How far the previous touch point has moved since start
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
var prevDeltaMove = Math.hypot(prevTouch.firstX - prevTouch.lastX, prevTouch.firstY - prevTouch.lastY); // We know that the current touch moved far enough,
|
|
234
|
+
// but unless both touches moved further than their
|
|
235
|
+
// threshold we don't want to disqualify any gestures
|
|
236
|
+
|
|
237
|
+
if (prevDeltaMove > GH_MOVE_THRESHOLD) {
|
|
238
|
+
// The angle difference between the direction of the touch points
|
|
239
|
+
var deltaAngle = Math.abs(touch.angle - prevTouch.angle);
|
|
240
|
+
deltaAngle = Math.abs((deltaAngle + 180) % 360 - 180); // PINCH or TWODRAG can be eliminated depending on the angle
|
|
241
|
+
|
|
242
|
+
if (deltaAngle > GH_ANGLE_THRESHOLD) {
|
|
243
|
+
this._state &= ~GH_TWODRAG;
|
|
244
|
+
} else {
|
|
245
|
+
this._state &= ~GH_PINCH;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
if (this._isTwoTouchTimeoutRunning()) {
|
|
249
|
+
this._stopTwoTouchTimeout();
|
|
250
|
+
}
|
|
251
|
+
} else if (!this._isTwoTouchTimeoutRunning()) {
|
|
252
|
+
// We can't determine the gesture right now, let's
|
|
253
|
+
// wait and see if more events are on their way
|
|
254
|
+
this._startTwoTouchTimeout();
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
if (!this._hasDetectedGesture()) {
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
this._pushEvent('gesturestart');
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
this._pushEvent('gesturemove');
|
|
266
|
+
}
|
|
267
|
+
}, {
|
|
268
|
+
key: "_touchEnd",
|
|
269
|
+
value: function _touchEnd(id, x, y) {
|
|
270
|
+
// Check if this is an ignored touch
|
|
271
|
+
if (this._ignored.indexOf(id) !== -1) {
|
|
272
|
+
// Remove this touch from ignored
|
|
273
|
+
this._ignored.splice(this._ignored.indexOf(id), 1); // And reset the state if there are no more touches
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
if (this._ignored.length === 0 && this._tracked.length === 0) {
|
|
277
|
+
this._state = GH_INITSTATE;
|
|
278
|
+
this._waitingRelease = false;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
return;
|
|
282
|
+
} // We got a touchend before the timer triggered,
|
|
283
|
+
// this cannot result in a gesture anymore.
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
if (!this._hasDetectedGesture() && this._isTwoTouchTimeoutRunning()) {
|
|
287
|
+
this._stopTwoTouchTimeout();
|
|
288
|
+
|
|
289
|
+
this._state = GH_NOGESTURE;
|
|
290
|
+
} // Some gestures don't trigger until a touch is released
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
if (!this._hasDetectedGesture()) {
|
|
294
|
+
// Can't be a gesture that relies on movement
|
|
295
|
+
this._state &= ~(GH_DRAG | GH_TWODRAG | GH_PINCH); // Or something that relies on more time
|
|
296
|
+
|
|
297
|
+
this._state &= ~GH_LONGPRESS;
|
|
298
|
+
|
|
299
|
+
this._stopLongpressTimeout();
|
|
300
|
+
|
|
301
|
+
if (!this._waitingRelease) {
|
|
302
|
+
this._releaseStart = Date.now();
|
|
303
|
+
this._waitingRelease = true; // Can't be a tap that requires more touches than we current have
|
|
304
|
+
|
|
305
|
+
switch (this._tracked.length) {
|
|
306
|
+
case 1:
|
|
307
|
+
this._state &= ~(GH_TWOTAP | GH_THREETAP);
|
|
308
|
+
break;
|
|
309
|
+
|
|
310
|
+
case 2:
|
|
311
|
+
this._state &= ~(GH_ONETAP | GH_THREETAP);
|
|
312
|
+
break;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
} // Waiting for all touches to release? (i.e. some tap)
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
if (this._waitingRelease) {
|
|
319
|
+
// Were all touches released at roughly the same time?
|
|
320
|
+
if (Date.now() - this._releaseStart > GH_MULTITOUCH_TIMEOUT) {
|
|
321
|
+
this._state = GH_NOGESTURE;
|
|
322
|
+
} // Did too long time pass between press and release?
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
if (this._tracked.some(function (t) {
|
|
326
|
+
return Date.now() - t.started > GH_TAP_TIMEOUT;
|
|
327
|
+
})) {
|
|
328
|
+
this._state = GH_NOGESTURE;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
var touch = this._tracked.find(function (t) {
|
|
332
|
+
return t.id === id;
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
touch.active = false; // Are we still waiting for more releases?
|
|
336
|
+
|
|
337
|
+
if (this._hasDetectedGesture()) {
|
|
338
|
+
this._pushEvent('gesturestart');
|
|
339
|
+
} else {
|
|
340
|
+
// Have we reached a dead end?
|
|
341
|
+
if (this._state !== GH_NOGESTURE) {
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
if (this._hasDetectedGesture()) {
|
|
348
|
+
this._pushEvent('gestureend');
|
|
349
|
+
} // Ignore any remaining touches until they are ended
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
for (var i = 0; i < this._tracked.length; i++) {
|
|
353
|
+
if (this._tracked[i].active) {
|
|
354
|
+
this._ignored.push(this._tracked[i].id);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
this._tracked = [];
|
|
359
|
+
this._state = GH_NOGESTURE; // Remove this touch from ignored if it's in there
|
|
360
|
+
|
|
361
|
+
if (this._ignored.indexOf(id) !== -1) {
|
|
362
|
+
this._ignored.splice(this._ignored.indexOf(id), 1);
|
|
363
|
+
} // We reset the state if ignored is empty
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
if (this._ignored.length === 0) {
|
|
367
|
+
this._state = GH_INITSTATE;
|
|
368
|
+
this._waitingRelease = false;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}, {
|
|
372
|
+
key: "_hasDetectedGesture",
|
|
373
|
+
value: function _hasDetectedGesture() {
|
|
374
|
+
if (this._state === GH_NOGESTURE) {
|
|
375
|
+
return false;
|
|
376
|
+
} // Check to see if the bitmask value is a power of 2
|
|
377
|
+
// (i.e. only one bit set). If it is, we have a state.
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
if (this._state & this._state - 1) {
|
|
381
|
+
return false;
|
|
382
|
+
} // For taps we also need to have all touches released
|
|
383
|
+
// before we've fully detected the gesture
|
|
384
|
+
|
|
385
|
+
|
|
386
|
+
if (this._state & (GH_ONETAP | GH_TWOTAP | GH_THREETAP)) {
|
|
387
|
+
if (this._tracked.some(function (t) {
|
|
388
|
+
return t.active;
|
|
389
|
+
})) {
|
|
390
|
+
return false;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
return true;
|
|
395
|
+
}
|
|
396
|
+
}, {
|
|
397
|
+
key: "_startLongpressTimeout",
|
|
398
|
+
value: function _startLongpressTimeout() {
|
|
399
|
+
var _this = this;
|
|
400
|
+
|
|
401
|
+
this._stopLongpressTimeout();
|
|
402
|
+
|
|
403
|
+
this._longpressTimeoutId = setTimeout(function () {
|
|
404
|
+
return _this._longpressTimeout();
|
|
405
|
+
}, GH_LONGPRESS_TIMEOUT);
|
|
406
|
+
}
|
|
407
|
+
}, {
|
|
408
|
+
key: "_stopLongpressTimeout",
|
|
409
|
+
value: function _stopLongpressTimeout() {
|
|
410
|
+
clearTimeout(this._longpressTimeoutId);
|
|
411
|
+
this._longpressTimeoutId = null;
|
|
412
|
+
}
|
|
413
|
+
}, {
|
|
414
|
+
key: "_longpressTimeout",
|
|
415
|
+
value: function _longpressTimeout() {
|
|
416
|
+
if (this._hasDetectedGesture()) {
|
|
417
|
+
throw new Error("A longpress gesture failed, conflict with a different gesture");
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
this._state = GH_LONGPRESS;
|
|
421
|
+
|
|
422
|
+
this._pushEvent('gesturestart');
|
|
423
|
+
}
|
|
424
|
+
}, {
|
|
425
|
+
key: "_startTwoTouchTimeout",
|
|
426
|
+
value: function _startTwoTouchTimeout() {
|
|
427
|
+
var _this2 = this;
|
|
428
|
+
|
|
429
|
+
this._stopTwoTouchTimeout();
|
|
430
|
+
|
|
431
|
+
this._twoTouchTimeoutId = setTimeout(function () {
|
|
432
|
+
return _this2._twoTouchTimeout();
|
|
433
|
+
}, GH_TWOTOUCH_TIMEOUT);
|
|
434
|
+
}
|
|
435
|
+
}, {
|
|
436
|
+
key: "_stopTwoTouchTimeout",
|
|
437
|
+
value: function _stopTwoTouchTimeout() {
|
|
438
|
+
clearTimeout(this._twoTouchTimeoutId);
|
|
439
|
+
this._twoTouchTimeoutId = null;
|
|
440
|
+
}
|
|
441
|
+
}, {
|
|
442
|
+
key: "_isTwoTouchTimeoutRunning",
|
|
443
|
+
value: function _isTwoTouchTimeoutRunning() {
|
|
444
|
+
return this._twoTouchTimeoutId !== null;
|
|
445
|
+
}
|
|
446
|
+
}, {
|
|
447
|
+
key: "_twoTouchTimeout",
|
|
448
|
+
value: function _twoTouchTimeout() {
|
|
449
|
+
if (this._tracked.length === 0) {
|
|
450
|
+
throw new Error("A pinch or two drag gesture failed, no tracked touches");
|
|
451
|
+
} // How far each touch point has moved since start
|
|
452
|
+
|
|
453
|
+
|
|
454
|
+
var avgM = this._getAverageMovement();
|
|
455
|
+
|
|
456
|
+
var avgMoveH = Math.abs(avgM.x);
|
|
457
|
+
var avgMoveV = Math.abs(avgM.y); // The difference in the distance between where
|
|
458
|
+
// the touch points started and where they are now
|
|
459
|
+
|
|
460
|
+
var avgD = this._getAverageDistance();
|
|
461
|
+
|
|
462
|
+
var deltaTouchDistance = Math.abs(Math.hypot(avgD.first.x, avgD.first.y) - Math.hypot(avgD.last.x, avgD.last.y));
|
|
463
|
+
|
|
464
|
+
if (avgMoveV < deltaTouchDistance && avgMoveH < deltaTouchDistance) {
|
|
465
|
+
this._state = GH_PINCH;
|
|
466
|
+
} else {
|
|
467
|
+
this._state = GH_TWODRAG;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
this._pushEvent('gesturestart');
|
|
471
|
+
|
|
472
|
+
this._pushEvent('gesturemove');
|
|
473
|
+
}
|
|
474
|
+
}, {
|
|
475
|
+
key: "_pushEvent",
|
|
476
|
+
value: function _pushEvent(type) {
|
|
477
|
+
var detail = {
|
|
478
|
+
type: this._stateToGesture(this._state)
|
|
479
|
+
}; // For most gesture events the current (average) position is the
|
|
480
|
+
// most useful
|
|
481
|
+
|
|
482
|
+
var avg = this._getPosition();
|
|
483
|
+
|
|
484
|
+
var pos = avg.last; // However we have a slight distance to detect gestures, so for the
|
|
485
|
+
// first gesture event we want to use the first positions we saw
|
|
486
|
+
|
|
487
|
+
if (type === 'gesturestart') {
|
|
488
|
+
pos = avg.first;
|
|
489
|
+
} // For these gestures, we always want the event coordinates
|
|
490
|
+
// to be where the gesture began, not the current touch location.
|
|
491
|
+
|
|
492
|
+
|
|
493
|
+
switch (this._state) {
|
|
494
|
+
case GH_TWODRAG:
|
|
495
|
+
case GH_PINCH:
|
|
496
|
+
pos = avg.first;
|
|
497
|
+
break;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
detail['clientX'] = pos.x;
|
|
501
|
+
detail['clientY'] = pos.y; // FIXME: other coordinates?
|
|
502
|
+
// Some gestures also have a magnitude
|
|
503
|
+
|
|
504
|
+
if (this._state === GH_PINCH) {
|
|
505
|
+
var distance = this._getAverageDistance();
|
|
506
|
+
|
|
507
|
+
if (type === 'gesturestart') {
|
|
508
|
+
detail['magnitudeX'] = distance.first.x;
|
|
509
|
+
detail['magnitudeY'] = distance.first.y;
|
|
510
|
+
} else {
|
|
511
|
+
detail['magnitudeX'] = distance.last.x;
|
|
512
|
+
detail['magnitudeY'] = distance.last.y;
|
|
513
|
+
}
|
|
514
|
+
} else if (this._state === GH_TWODRAG) {
|
|
515
|
+
if (type === 'gesturestart') {
|
|
516
|
+
detail['magnitudeX'] = 0.0;
|
|
517
|
+
detail['magnitudeY'] = 0.0;
|
|
518
|
+
} else {
|
|
519
|
+
var movement = this._getAverageMovement();
|
|
520
|
+
|
|
521
|
+
detail['magnitudeX'] = movement.x;
|
|
522
|
+
detail['magnitudeY'] = movement.y;
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
var gev = new CustomEvent(type, {
|
|
527
|
+
detail: detail
|
|
528
|
+
});
|
|
529
|
+
|
|
530
|
+
this._target.dispatchEvent(gev);
|
|
531
|
+
}
|
|
532
|
+
}, {
|
|
533
|
+
key: "_stateToGesture",
|
|
534
|
+
value: function _stateToGesture(state) {
|
|
535
|
+
switch (state) {
|
|
536
|
+
case GH_ONETAP:
|
|
537
|
+
return 'onetap';
|
|
538
|
+
|
|
539
|
+
case GH_TWOTAP:
|
|
540
|
+
return 'twotap';
|
|
541
|
+
|
|
542
|
+
case GH_THREETAP:
|
|
543
|
+
return 'threetap';
|
|
544
|
+
|
|
545
|
+
case GH_DRAG:
|
|
546
|
+
return 'drag';
|
|
547
|
+
|
|
548
|
+
case GH_LONGPRESS:
|
|
549
|
+
return 'longpress';
|
|
550
|
+
|
|
551
|
+
case GH_TWODRAG:
|
|
552
|
+
return 'twodrag';
|
|
553
|
+
|
|
554
|
+
case GH_PINCH:
|
|
555
|
+
return 'pinch';
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
throw new Error("Unknown gesture state: " + state);
|
|
559
|
+
}
|
|
560
|
+
}, {
|
|
561
|
+
key: "_getPosition",
|
|
562
|
+
value: function _getPosition() {
|
|
563
|
+
if (this._tracked.length === 0) {
|
|
564
|
+
throw new Error("Failed to get gesture position, no tracked touches");
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
var size = this._tracked.length;
|
|
568
|
+
var fx = 0,
|
|
569
|
+
fy = 0,
|
|
570
|
+
lx = 0,
|
|
571
|
+
ly = 0;
|
|
572
|
+
|
|
573
|
+
for (var i = 0; i < this._tracked.length; i++) {
|
|
574
|
+
fx += this._tracked[i].firstX;
|
|
575
|
+
fy += this._tracked[i].firstY;
|
|
576
|
+
lx += this._tracked[i].lastX;
|
|
577
|
+
ly += this._tracked[i].lastY;
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
return {
|
|
581
|
+
first: {
|
|
582
|
+
x: fx / size,
|
|
583
|
+
y: fy / size
|
|
584
|
+
},
|
|
585
|
+
last: {
|
|
586
|
+
x: lx / size,
|
|
587
|
+
y: ly / size
|
|
588
|
+
}
|
|
589
|
+
};
|
|
590
|
+
}
|
|
591
|
+
}, {
|
|
592
|
+
key: "_getAverageMovement",
|
|
593
|
+
value: function _getAverageMovement() {
|
|
594
|
+
if (this._tracked.length === 0) {
|
|
595
|
+
throw new Error("Failed to get gesture movement, no tracked touches");
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
var totalH, totalV;
|
|
599
|
+
totalH = totalV = 0;
|
|
600
|
+
var size = this._tracked.length;
|
|
601
|
+
|
|
602
|
+
for (var i = 0; i < this._tracked.length; i++) {
|
|
603
|
+
totalH += this._tracked[i].lastX - this._tracked[i].firstX;
|
|
604
|
+
totalV += this._tracked[i].lastY - this._tracked[i].firstY;
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
return {
|
|
608
|
+
x: totalH / size,
|
|
609
|
+
y: totalV / size
|
|
610
|
+
};
|
|
611
|
+
}
|
|
612
|
+
}, {
|
|
613
|
+
key: "_getAverageDistance",
|
|
614
|
+
value: function _getAverageDistance() {
|
|
615
|
+
if (this._tracked.length === 0) {
|
|
616
|
+
throw new Error("Failed to get gesture distance, no tracked touches");
|
|
617
|
+
} // Distance between the first and last tracked touches
|
|
618
|
+
|
|
619
|
+
|
|
620
|
+
var first = this._tracked[0];
|
|
621
|
+
var last = this._tracked[this._tracked.length - 1];
|
|
622
|
+
var fdx = Math.abs(last.firstX - first.firstX);
|
|
623
|
+
var fdy = Math.abs(last.firstY - first.firstY);
|
|
624
|
+
var ldx = Math.abs(last.lastX - first.lastX);
|
|
625
|
+
var ldy = Math.abs(last.lastY - first.lastY);
|
|
626
|
+
return {
|
|
627
|
+
first: {
|
|
628
|
+
x: fdx,
|
|
629
|
+
y: fdy
|
|
630
|
+
},
|
|
631
|
+
last: {
|
|
632
|
+
x: ldx,
|
|
633
|
+
y: ldy
|
|
634
|
+
}
|
|
635
|
+
};
|
|
636
|
+
}
|
|
637
|
+
}]);
|
|
638
|
+
|
|
639
|
+
return GestureHandler;
|
|
640
|
+
}();
|
|
641
|
+
|
|
642
|
+
exports.default = GestureHandler;
|