@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.
Files changed (87) hide show
  1. package/AUTHORS +13 -0
  2. package/LICENSE.txt +2 -1
  3. package/README.md +69 -3
  4. package/core/base64.js +35 -41
  5. package/core/decoders/copyrect.js +22 -0
  6. package/core/decoders/hextile.js +137 -0
  7. package/core/decoders/raw.js +56 -0
  8. package/core/decoders/rre.js +44 -0
  9. package/core/decoders/tight.js +315 -0
  10. package/core/decoders/tightpng.js +27 -0
  11. package/core/deflator.js +85 -0
  12. package/core/des.js +90 -95
  13. package/core/display.js +254 -297
  14. package/core/encodings.js +7 -3
  15. package/core/inflator.js +48 -20
  16. package/core/input/domkeytable.js +21 -24
  17. package/core/input/fixedkeys.js +3 -1
  18. package/core/input/gesturehandler.js +567 -0
  19. package/core/input/keyboard.js +194 -120
  20. package/core/input/keysym.js +2 -0
  21. package/core/input/keysymdef.js +3 -3
  22. package/core/input/util.js +53 -12
  23. package/core/input/vkeys.js +2 -1
  24. package/core/rfb.js +1937 -1496
  25. package/core/util/browser.js +80 -29
  26. package/core/util/cursor.js +253 -0
  27. package/core/util/element.js +32 -0
  28. package/core/util/events.js +59 -55
  29. package/core/util/eventtarget.js +25 -30
  30. package/core/util/int.js +15 -0
  31. package/core/util/logging.js +21 -16
  32. package/core/util/polyfill.js +15 -8
  33. package/core/util/strings.js +21 -8
  34. package/core/websock.js +145 -167
  35. package/docs/API.md +31 -10
  36. package/lib/base64.js +115 -0
  37. package/lib/decoders/copyrect.js +44 -0
  38. package/lib/decoders/hextile.js +173 -0
  39. package/lib/decoders/raw.js +78 -0
  40. package/lib/decoders/rre.js +65 -0
  41. package/lib/decoders/tight.js +350 -0
  42. package/lib/decoders/tightpng.js +67 -0
  43. package/lib/deflator.js +99 -0
  44. package/lib/des.js +314 -0
  45. package/lib/display.js +733 -0
  46. package/lib/encodings.js +64 -0
  47. package/lib/inflator.js +87 -0
  48. package/lib/input/domkeytable.js +282 -0
  49. package/lib/input/fixedkeys.js +123 -0
  50. package/lib/input/gesturehandler.js +642 -0
  51. package/lib/input/keyboard.js +429 -0
  52. package/lib/input/keysym.js +1135 -0
  53. package/lib/input/keysymdef.js +1354 -0
  54. package/lib/input/util.js +304 -0
  55. package/lib/input/vkeys.js +127 -0
  56. package/lib/input/xtscancodes.js +505 -0
  57. package/lib/rfb.js +3448 -0
  58. package/lib/util/browser.js +131 -0
  59. package/lib/util/cursor.js +314 -0
  60. package/lib/util/element.js +43 -0
  61. package/lib/util/events.js +142 -0
  62. package/lib/util/eventtarget.js +64 -0
  63. package/lib/util/int.js +22 -0
  64. package/lib/util/logging.js +79 -0
  65. package/lib/util/polyfill.js +72 -0
  66. package/lib/util/strings.js +38 -0
  67. package/lib/vendor/pako/lib/utils/common.js +67 -0
  68. package/lib/vendor/pako/lib/zlib/adler32.js +33 -0
  69. package/lib/vendor/pako/lib/zlib/constants.js +51 -0
  70. package/lib/vendor/pako/lib/zlib/crc32.js +42 -0
  71. package/lib/vendor/pako/lib/zlib/deflate.js +2159 -0
  72. package/lib/vendor/pako/lib/zlib/gzheader.js +53 -0
  73. package/lib/vendor/pako/lib/zlib/inffast.js +445 -0
  74. package/lib/vendor/pako/lib/zlib/inflate.js +2114 -0
  75. package/lib/vendor/pako/lib/zlib/inftrees.js +418 -0
  76. package/lib/vendor/pako/lib/zlib/messages.js +36 -0
  77. package/lib/vendor/pako/lib/zlib/trees.js +1499 -0
  78. package/lib/vendor/pako/lib/zlib/zstream.js +46 -0
  79. package/lib/vendor/promise.js +255 -0
  80. package/lib/websock.js +374 -0
  81. package/package.json +48 -28
  82. package/vendor/pako/lib/zlib/deflate.js +30 -30
  83. package/vendor/pako/lib/zlib/inflate.js +17 -17
  84. package/core/input/mouse.js +0 -280
  85. package/docs/API-internal.md +0 -125
  86. package/docs/EMBEDDING.md +0 -83
  87. package/docs/VERSION +0 -1
package/lib/rfb.js ADDED
@@ -0,0 +1,3448 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+
8
+ var _int = require("./util/int.js");
9
+
10
+ var Log = _interopRequireWildcard(require("./util/logging.js"));
11
+
12
+ var _strings = require("./util/strings.js");
13
+
14
+ var _browser = require("./util/browser.js");
15
+
16
+ var _element = require("./util/element.js");
17
+
18
+ var _events = require("./util/events.js");
19
+
20
+ var _eventtarget = _interopRequireDefault(require("./util/eventtarget.js"));
21
+
22
+ var _display = _interopRequireDefault(require("./display.js"));
23
+
24
+ var _inflator = _interopRequireDefault(require("./inflator.js"));
25
+
26
+ var _deflator = _interopRequireDefault(require("./deflator.js"));
27
+
28
+ var _keyboard = _interopRequireDefault(require("./input/keyboard.js"));
29
+
30
+ var _gesturehandler = _interopRequireDefault(require("./input/gesturehandler.js"));
31
+
32
+ var _cursor = _interopRequireDefault(require("./util/cursor.js"));
33
+
34
+ var _websock = _interopRequireDefault(require("./websock.js"));
35
+
36
+ var _des = _interopRequireDefault(require("./des.js"));
37
+
38
+ var _keysym = _interopRequireDefault(require("./input/keysym.js"));
39
+
40
+ var _xtscancodes = _interopRequireDefault(require("./input/xtscancodes.js"));
41
+
42
+ var _encodings = require("./encodings.js");
43
+
44
+ require("./util/polyfill.js");
45
+
46
+ var _raw = _interopRequireDefault(require("./decoders/raw.js"));
47
+
48
+ var _copyrect = _interopRequireDefault(require("./decoders/copyrect.js"));
49
+
50
+ var _rre = _interopRequireDefault(require("./decoders/rre.js"));
51
+
52
+ var _hextile = _interopRequireDefault(require("./decoders/hextile.js"));
53
+
54
+ var _tight = _interopRequireDefault(require("./decoders/tight.js"));
55
+
56
+ var _tightpng = _interopRequireDefault(require("./decoders/tightpng.js"));
57
+
58
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
59
+
60
+ function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function _getRequireWildcardCache() { return cache; }; return cache; }
61
+
62
+ function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
63
+
64
+ function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
65
+
66
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
67
+
68
+ 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); } }
69
+
70
+ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
71
+
72
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
73
+
74
+ function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
75
+
76
+ function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
77
+
78
+ function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
79
+
80
+ function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
81
+
82
+ function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }
83
+
84
+ function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
85
+
86
+ // How many seconds to wait for a disconnect to finish
87
+ var DISCONNECT_TIMEOUT = 3;
88
+ var DEFAULT_BACKGROUND = 'rgb(40, 40, 40)'; // Minimum wait (ms) between two mouse moves
89
+
90
+ var MOUSE_MOVE_DELAY = 17; // Wheel thresholds
91
+
92
+ var WHEEL_STEP = 50; // Pixels needed for one step
93
+
94
+ var WHEEL_LINE_HEIGHT = 19; // Assumed pixels for one line step
95
+ // Gesture thresholds
96
+
97
+ var GESTURE_ZOOMSENS = 75;
98
+ var GESTURE_SCRLSENS = 50;
99
+ var DOUBLE_TAP_TIMEOUT = 1000;
100
+ var DOUBLE_TAP_THRESHOLD = 50; // Extended clipboard pseudo-encoding formats
101
+
102
+ var extendedClipboardFormatText = 1;
103
+ /*eslint-disable no-unused-vars */
104
+
105
+ var extendedClipboardFormatRtf = 1 << 1;
106
+ var extendedClipboardFormatHtml = 1 << 2;
107
+ var extendedClipboardFormatDib = 1 << 3;
108
+ var extendedClipboardFormatFiles = 1 << 4;
109
+ /*eslint-enable */
110
+ // Extended clipboard pseudo-encoding actions
111
+
112
+ var extendedClipboardActionCaps = 1 << 24;
113
+ var extendedClipboardActionRequest = 1 << 25;
114
+ var extendedClipboardActionPeek = 1 << 26;
115
+ var extendedClipboardActionNotify = 1 << 27;
116
+ var extendedClipboardActionProvide = 1 << 28;
117
+
118
+ var RFB = /*#__PURE__*/function (_EventTargetMixin) {
119
+ _inherits(RFB, _EventTargetMixin);
120
+
121
+ var _super = _createSuper(RFB);
122
+
123
+ function RFB(target, url, options) {
124
+ var _this;
125
+
126
+ _classCallCheck(this, RFB);
127
+
128
+ if (!target) {
129
+ throw new Error("Must specify target");
130
+ }
131
+
132
+ if (!url) {
133
+ throw new Error("Must specify URL");
134
+ }
135
+
136
+ _this = _super.call(this);
137
+ _this._target = target;
138
+ _this._url = url; // Connection details
139
+
140
+ options = options || {};
141
+ _this._rfbCredentials = options.credentials || {};
142
+ _this._shared = 'shared' in options ? !!options.shared : true;
143
+ _this._repeaterID = options.repeaterID || '';
144
+ _this._wsProtocols = options.wsProtocols || []; // Internal state
145
+
146
+ _this._rfbConnectionState = '';
147
+ _this._rfbInitState = '';
148
+ _this._rfbAuthScheme = -1;
149
+ _this._rfbCleanDisconnect = true; // Server capabilities
150
+
151
+ _this._rfbVersion = 0;
152
+ _this._rfbMaxVersion = 3.8;
153
+ _this._rfbTightVNC = false;
154
+ _this._rfbVeNCryptState = 0;
155
+ _this._rfbXvpVer = 0;
156
+ _this._fbWidth = 0;
157
+ _this._fbHeight = 0;
158
+ _this._fbName = "";
159
+ _this._capabilities = {
160
+ power: false
161
+ };
162
+ _this._supportsFence = false;
163
+ _this._supportsContinuousUpdates = false;
164
+ _this._enabledContinuousUpdates = false;
165
+ _this._supportsSetDesktopSize = false;
166
+ _this._screenID = 0;
167
+ _this._screenFlags = 0;
168
+ _this._qemuExtKeyEventSupported = false;
169
+ _this._clipboardText = null;
170
+ _this._clipboardServerCapabilitiesActions = {};
171
+ _this._clipboardServerCapabilitiesFormats = {}; // Internal objects
172
+
173
+ _this._sock = null; // Websock object
174
+
175
+ _this._display = null; // Display object
176
+
177
+ _this._flushing = false; // Display flushing state
178
+
179
+ _this._keyboard = null; // Keyboard input handler object
180
+
181
+ _this._gestures = null; // Gesture input handler object
182
+ // Timers
183
+
184
+ _this._disconnTimer = null; // disconnection timer
185
+
186
+ _this._resizeTimeout = null; // resize rate limiting
187
+
188
+ _this._mouseMoveTimer = null; // Decoder states
189
+
190
+ _this._decoders = {};
191
+ _this._FBU = {
192
+ rects: 0,
193
+ x: 0,
194
+ y: 0,
195
+ width: 0,
196
+ height: 0,
197
+ encoding: null
198
+ }; // Mouse state
199
+
200
+ _this._mousePos = {};
201
+ _this._mouseButtonMask = 0;
202
+ _this._mouseLastMoveTime = 0;
203
+ _this._viewportDragging = false;
204
+ _this._viewportDragPos = {};
205
+ _this._viewportHasMoved = false;
206
+ _this._accumulatedWheelDeltaX = 0;
207
+ _this._accumulatedWheelDeltaY = 0; // Gesture state
208
+
209
+ _this._gestureLastTapTime = null;
210
+ _this._gestureFirstDoubleTapEv = null;
211
+ _this._gestureLastMagnitudeX = 0;
212
+ _this._gestureLastMagnitudeY = 0; // Bound event handlers
213
+
214
+ _this._eventHandlers = {
215
+ focusCanvas: _this._focusCanvas.bind(_assertThisInitialized(_this)),
216
+ windowResize: _this._windowResize.bind(_assertThisInitialized(_this)),
217
+ handleMouse: _this._handleMouse.bind(_assertThisInitialized(_this)),
218
+ handleWheel: _this._handleWheel.bind(_assertThisInitialized(_this)),
219
+ handleGesture: _this._handleGesture.bind(_assertThisInitialized(_this))
220
+ }; // main setup
221
+
222
+ Log.Debug(">> RFB.constructor"); // Create DOM elements
223
+
224
+ _this._screen = document.createElement('div');
225
+ _this._screen.style.display = 'flex';
226
+ _this._screen.style.width = '100%';
227
+ _this._screen.style.height = '100%';
228
+ _this._screen.style.overflow = 'auto';
229
+ _this._screen.style.background = DEFAULT_BACKGROUND;
230
+ _this._canvas = document.createElement('canvas');
231
+ _this._canvas.style.margin = 'auto'; // Some browsers add an outline on focus
232
+
233
+ _this._canvas.style.outline = 'none'; // IE miscalculates width without this :(
234
+
235
+ _this._canvas.style.flexShrink = '0';
236
+ _this._canvas.width = 0;
237
+ _this._canvas.height = 0;
238
+ _this._canvas.tabIndex = -1;
239
+
240
+ _this._screen.appendChild(_this._canvas); // Cursor
241
+
242
+
243
+ _this._cursor = new _cursor.default(); // XXX: TightVNC 2.8.11 sends no cursor at all until Windows changes
244
+ // it. Result: no cursor at all until a window border or an edit field
245
+ // is hit blindly. But there are also VNC servers that draw the cursor
246
+ // in the framebuffer and don't send the empty local cursor. There is
247
+ // no way to satisfy both sides.
248
+ //
249
+ // The spec is unclear on this "initial cursor" issue. Many other
250
+ // viewers (TigerVNC, RealVNC, Remmina) display an arrow as the
251
+ // initial cursor instead.
252
+
253
+ _this._cursorImage = RFB.cursors.none; // populate decoder array with objects
254
+
255
+ _this._decoders[_encodings.encodings.encodingRaw] = new _raw.default();
256
+ _this._decoders[_encodings.encodings.encodingCopyRect] = new _copyrect.default();
257
+ _this._decoders[_encodings.encodings.encodingRRE] = new _rre.default();
258
+ _this._decoders[_encodings.encodings.encodingHextile] = new _hextile.default();
259
+ _this._decoders[_encodings.encodings.encodingTight] = new _tight.default();
260
+ _this._decoders[_encodings.encodings.encodingTightPNG] = new _tightpng.default(); // NB: nothing that needs explicit teardown should be done
261
+ // before this point, since this can throw an exception
262
+
263
+ try {
264
+ _this._display = new _display.default(_this._canvas);
265
+ } catch (exc) {
266
+ Log.Error("Display exception: " + exc);
267
+ throw exc;
268
+ }
269
+
270
+ _this._display.onflush = _this._onFlush.bind(_assertThisInitialized(_this));
271
+ _this._keyboard = new _keyboard.default(_this._canvas);
272
+ _this._keyboard.onkeyevent = _this._handleKeyEvent.bind(_assertThisInitialized(_this));
273
+ _this._gestures = new _gesturehandler.default();
274
+ _this._sock = new _websock.default();
275
+
276
+ _this._sock.on('message', function () {
277
+ _this._handleMessage();
278
+ });
279
+
280
+ _this._sock.on('open', function () {
281
+ if (_this._rfbConnectionState === 'connecting' && _this._rfbInitState === '') {
282
+ _this._rfbInitState = 'ProtocolVersion';
283
+ Log.Debug("Starting VNC handshake");
284
+ } else {
285
+ _this._fail("Unexpected server connection while " + _this._rfbConnectionState);
286
+ }
287
+ });
288
+
289
+ _this._sock.on('close', function (e) {
290
+ Log.Debug("WebSocket on-close event");
291
+ var msg = "";
292
+
293
+ if (e.code) {
294
+ msg = "(code: " + e.code;
295
+
296
+ if (e.reason) {
297
+ msg += ", reason: " + e.reason;
298
+ }
299
+
300
+ msg += ")";
301
+ }
302
+
303
+ switch (_this._rfbConnectionState) {
304
+ case 'connecting':
305
+ _this._fail("Connection closed " + msg);
306
+
307
+ break;
308
+
309
+ case 'connected':
310
+ // Handle disconnects that were initiated server-side
311
+ _this._updateConnectionState('disconnecting');
312
+
313
+ _this._updateConnectionState('disconnected');
314
+
315
+ break;
316
+
317
+ case 'disconnecting':
318
+ // Normal disconnection path
319
+ _this._updateConnectionState('disconnected');
320
+
321
+ break;
322
+
323
+ case 'disconnected':
324
+ _this._fail("Unexpected server disconnect " + "when already disconnected " + msg);
325
+
326
+ break;
327
+
328
+ default:
329
+ _this._fail("Unexpected server disconnect before connecting " + msg);
330
+
331
+ break;
332
+ }
333
+
334
+ _this._sock.off('close');
335
+ });
336
+
337
+ _this._sock.on('error', function (e) {
338
+ return Log.Warn("WebSocket on-error event");
339
+ }); // Slight delay of the actual connection so that the caller has
340
+ // time to set up callbacks
341
+
342
+
343
+ setTimeout(_this._updateConnectionState.bind(_assertThisInitialized(_this), 'connecting'));
344
+ Log.Debug("<< RFB.constructor"); // ===== PROPERTIES =====
345
+
346
+ _this.dragViewport = false;
347
+ _this.focusOnClick = true;
348
+ _this._viewOnly = false;
349
+ _this._clipViewport = false;
350
+ _this._scaleViewport = false;
351
+ _this._resizeSession = false;
352
+ _this._showDotCursor = false;
353
+
354
+ if (options.showDotCursor !== undefined) {
355
+ Log.Warn("Specifying showDotCursor as a RFB constructor argument is deprecated");
356
+ _this._showDotCursor = options.showDotCursor;
357
+ }
358
+
359
+ _this._qualityLevel = 6;
360
+ _this._compressionLevel = 2;
361
+ return _this;
362
+ } // ===== PROPERTIES =====
363
+
364
+
365
+ _createClass(RFB, [{
366
+ key: "disconnect",
367
+ // ===== PUBLIC METHODS =====
368
+ value: function disconnect() {
369
+ this._updateConnectionState('disconnecting');
370
+
371
+ this._sock.off('error');
372
+
373
+ this._sock.off('message');
374
+
375
+ this._sock.off('open');
376
+ }
377
+ }, {
378
+ key: "sendCredentials",
379
+ value: function sendCredentials(creds) {
380
+ this._rfbCredentials = creds;
381
+ setTimeout(this._initMsg.bind(this), 0);
382
+ }
383
+ }, {
384
+ key: "sendCtrlAltDel",
385
+ value: function sendCtrlAltDel() {
386
+ if (this._rfbConnectionState !== 'connected' || this._viewOnly) {
387
+ return;
388
+ }
389
+
390
+ Log.Info("Sending Ctrl-Alt-Del");
391
+ this.sendKey(_keysym.default.XK_Control_L, "ControlLeft", true);
392
+ this.sendKey(_keysym.default.XK_Alt_L, "AltLeft", true);
393
+ this.sendKey(_keysym.default.XK_Delete, "Delete", true);
394
+ this.sendKey(_keysym.default.XK_Delete, "Delete", false);
395
+ this.sendKey(_keysym.default.XK_Alt_L, "AltLeft", false);
396
+ this.sendKey(_keysym.default.XK_Control_L, "ControlLeft", false);
397
+ }
398
+ }, {
399
+ key: "machineShutdown",
400
+ value: function machineShutdown() {
401
+ this._xvpOp(1, 2);
402
+ }
403
+ }, {
404
+ key: "machineReboot",
405
+ value: function machineReboot() {
406
+ this._xvpOp(1, 3);
407
+ }
408
+ }, {
409
+ key: "machineReset",
410
+ value: function machineReset() {
411
+ this._xvpOp(1, 4);
412
+ } // Send a key press. If 'down' is not specified then send a down key
413
+ // followed by an up key.
414
+
415
+ }, {
416
+ key: "sendKey",
417
+ value: function sendKey(keysym, code, down) {
418
+ if (this._rfbConnectionState !== 'connected' || this._viewOnly) {
419
+ return;
420
+ }
421
+
422
+ if (down === undefined) {
423
+ this.sendKey(keysym, code, true);
424
+ this.sendKey(keysym, code, false);
425
+ return;
426
+ }
427
+
428
+ var scancode = _xtscancodes.default[code];
429
+
430
+ if (this._qemuExtKeyEventSupported && scancode) {
431
+ // 0 is NoSymbol
432
+ keysym = keysym || 0;
433
+ Log.Info("Sending key (" + (down ? "down" : "up") + "): keysym " + keysym + ", scancode " + scancode);
434
+ RFB.messages.QEMUExtendedKeyEvent(this._sock, keysym, down, scancode);
435
+ } else {
436
+ if (!keysym) {
437
+ return;
438
+ }
439
+
440
+ Log.Info("Sending keysym (" + (down ? "down" : "up") + "): " + keysym);
441
+ RFB.messages.keyEvent(this._sock, keysym, down ? 1 : 0);
442
+ }
443
+ }
444
+ }, {
445
+ key: "focus",
446
+ value: function focus() {
447
+ this._canvas.focus();
448
+ }
449
+ }, {
450
+ key: "blur",
451
+ value: function blur() {
452
+ this._canvas.blur();
453
+ }
454
+ }, {
455
+ key: "clipboardPasteFrom",
456
+ value: function clipboardPasteFrom(text) {
457
+ if (this._rfbConnectionState !== 'connected' || this._viewOnly) {
458
+ return;
459
+ }
460
+
461
+ if (this._clipboardServerCapabilitiesFormats[extendedClipboardFormatText] && this._clipboardServerCapabilitiesActions[extendedClipboardActionNotify]) {
462
+ this._clipboardText = text;
463
+ RFB.messages.extendedClipboardNotify(this._sock, [extendedClipboardFormatText]);
464
+ } else {
465
+ var data = new Uint8Array(text.length);
466
+
467
+ for (var i = 0; i < text.length; i++) {
468
+ // FIXME: text can have values outside of Latin1/Uint8
469
+ data[i] = text.charCodeAt(i);
470
+ }
471
+
472
+ RFB.messages.clientCutText(this._sock, data);
473
+ }
474
+ } // ===== PRIVATE METHODS =====
475
+
476
+ }, {
477
+ key: "_connect",
478
+ value: function _connect() {
479
+ Log.Debug(">> RFB.connect");
480
+ Log.Info("connecting to " + this._url);
481
+
482
+ try {
483
+ // WebSocket.onopen transitions to the RFB init states
484
+ this._sock.open(this._url, this._wsProtocols);
485
+ } catch (e) {
486
+ if (e.name === 'SyntaxError') {
487
+ this._fail("Invalid host or port (" + e + ")");
488
+ } else {
489
+ this._fail("Error when opening socket (" + e + ")");
490
+ }
491
+ } // Make our elements part of the page
492
+
493
+
494
+ this._target.appendChild(this._screen);
495
+
496
+ this._gestures.attach(this._canvas);
497
+
498
+ this._cursor.attach(this._canvas);
499
+
500
+ this._refreshCursor(); // Monitor size changes of the screen
501
+ // FIXME: Use ResizeObserver, or hidden overflow
502
+
503
+
504
+ window.addEventListener('resize', this._eventHandlers.windowResize); // Always grab focus on some kind of click event
505
+
506
+ this._canvas.addEventListener("mousedown", this._eventHandlers.focusCanvas);
507
+
508
+ this._canvas.addEventListener("touchstart", this._eventHandlers.focusCanvas); // Mouse events
509
+
510
+
511
+ this._canvas.addEventListener('mousedown', this._eventHandlers.handleMouse);
512
+
513
+ this._canvas.addEventListener('mouseup', this._eventHandlers.handleMouse);
514
+
515
+ this._canvas.addEventListener('mousemove', this._eventHandlers.handleMouse); // Prevent middle-click pasting (see handler for why we bind to document)
516
+
517
+
518
+ this._canvas.addEventListener('click', this._eventHandlers.handleMouse); // preventDefault() on mousedown doesn't stop this event for some
519
+ // reason so we have to explicitly block it
520
+
521
+
522
+ this._canvas.addEventListener('contextmenu', this._eventHandlers.handleMouse); // Wheel events
523
+
524
+
525
+ this._canvas.addEventListener("wheel", this._eventHandlers.handleWheel); // Gesture events
526
+
527
+
528
+ this._canvas.addEventListener("gesturestart", this._eventHandlers.handleGesture);
529
+
530
+ this._canvas.addEventListener("gesturemove", this._eventHandlers.handleGesture);
531
+
532
+ this._canvas.addEventListener("gestureend", this._eventHandlers.handleGesture);
533
+
534
+ Log.Debug("<< RFB.connect");
535
+ }
536
+ }, {
537
+ key: "_disconnect",
538
+ value: function _disconnect() {
539
+ Log.Debug(">> RFB.disconnect");
540
+
541
+ this._cursor.detach();
542
+
543
+ this._canvas.removeEventListener("gesturestart", this._eventHandlers.handleGesture);
544
+
545
+ this._canvas.removeEventListener("gesturemove", this._eventHandlers.handleGesture);
546
+
547
+ this._canvas.removeEventListener("gestureend", this._eventHandlers.handleGesture);
548
+
549
+ this._canvas.removeEventListener("wheel", this._eventHandlers.handleWheel);
550
+
551
+ this._canvas.removeEventListener('mousedown', this._eventHandlers.handleMouse);
552
+
553
+ this._canvas.removeEventListener('mouseup', this._eventHandlers.handleMouse);
554
+
555
+ this._canvas.removeEventListener('mousemove', this._eventHandlers.handleMouse);
556
+
557
+ this._canvas.removeEventListener('click', this._eventHandlers.handleMouse);
558
+
559
+ this._canvas.removeEventListener('contextmenu', this._eventHandlers.handleMouse);
560
+
561
+ this._canvas.removeEventListener("mousedown", this._eventHandlers.focusCanvas);
562
+
563
+ this._canvas.removeEventListener("touchstart", this._eventHandlers.focusCanvas);
564
+
565
+ window.removeEventListener('resize', this._eventHandlers.windowResize);
566
+
567
+ this._keyboard.ungrab();
568
+
569
+ this._gestures.detach();
570
+
571
+ this._sock.close();
572
+
573
+ try {
574
+ this._target.removeChild(this._screen);
575
+ } catch (e) {
576
+ if (e.name === 'NotFoundError') {// Some cases where the initial connection fails
577
+ // can disconnect before the _screen is created
578
+ } else {
579
+ throw e;
580
+ }
581
+ }
582
+
583
+ clearTimeout(this._resizeTimeout);
584
+ clearTimeout(this._mouseMoveTimer);
585
+ Log.Debug("<< RFB.disconnect");
586
+ }
587
+ }, {
588
+ key: "_focusCanvas",
589
+ value: function _focusCanvas(event) {
590
+ if (!this.focusOnClick) {
591
+ return;
592
+ }
593
+
594
+ this.focus();
595
+ }
596
+ }, {
597
+ key: "_setDesktopName",
598
+ value: function _setDesktopName(name) {
599
+ this._fbName = name;
600
+ this.dispatchEvent(new CustomEvent("desktopname", {
601
+ detail: {
602
+ name: this._fbName
603
+ }
604
+ }));
605
+ }
606
+ }, {
607
+ key: "_windowResize",
608
+ value: function _windowResize(event) {
609
+ var _this2 = this;
610
+
611
+ // If the window resized then our screen element might have
612
+ // as well. Update the viewport dimensions.
613
+ window.requestAnimationFrame(function () {
614
+ _this2._updateClip();
615
+
616
+ _this2._updateScale();
617
+ });
618
+
619
+ if (this._resizeSession) {
620
+ // Request changing the resolution of the remote display to
621
+ // the size of the local browser viewport.
622
+ // In order to not send multiple requests before the browser-resize
623
+ // is finished we wait 0.5 seconds before sending the request.
624
+ clearTimeout(this._resizeTimeout);
625
+ this._resizeTimeout = setTimeout(this._requestRemoteResize.bind(this), 500);
626
+ }
627
+ } // Update state of clipping in Display object, and make sure the
628
+ // configured viewport matches the current screen size
629
+
630
+ }, {
631
+ key: "_updateClip",
632
+ value: function _updateClip() {
633
+ var curClip = this._display.clipViewport;
634
+ var newClip = this._clipViewport;
635
+
636
+ if (this._scaleViewport) {
637
+ // Disable viewport clipping if we are scaling
638
+ newClip = false;
639
+ }
640
+
641
+ if (curClip !== newClip) {
642
+ this._display.clipViewport = newClip;
643
+ }
644
+
645
+ if (newClip) {
646
+ // When clipping is enabled, the screen is limited to
647
+ // the size of the container.
648
+ var size = this._screenSize();
649
+
650
+ this._display.viewportChangeSize(size.w, size.h);
651
+
652
+ this._fixScrollbars();
653
+ }
654
+ }
655
+ }, {
656
+ key: "_updateScale",
657
+ value: function _updateScale() {
658
+ if (!this._scaleViewport) {
659
+ this._display.scale = 1.0;
660
+ } else {
661
+ var size = this._screenSize();
662
+
663
+ this._display.autoscale(size.w, size.h);
664
+ }
665
+
666
+ this._fixScrollbars();
667
+ } // Requests a change of remote desktop size. This message is an extension
668
+ // and may only be sent if we have received an ExtendedDesktopSize message
669
+
670
+ }, {
671
+ key: "_requestRemoteResize",
672
+ value: function _requestRemoteResize() {
673
+ clearTimeout(this._resizeTimeout);
674
+ this._resizeTimeout = null;
675
+
676
+ if (!this._resizeSession || this._viewOnly || !this._supportsSetDesktopSize) {
677
+ return;
678
+ }
679
+
680
+ var size = this._screenSize();
681
+
682
+ RFB.messages.setDesktopSize(this._sock, Math.floor(size.w), Math.floor(size.h), this._screenID, this._screenFlags);
683
+ Log.Debug('Requested new desktop size: ' + size.w + 'x' + size.h);
684
+ } // Gets the the size of the available screen
685
+
686
+ }, {
687
+ key: "_screenSize",
688
+ value: function _screenSize() {
689
+ var r = this._screen.getBoundingClientRect();
690
+
691
+ return {
692
+ w: r.width,
693
+ h: r.height
694
+ };
695
+ }
696
+ }, {
697
+ key: "_fixScrollbars",
698
+ value: function _fixScrollbars() {
699
+ // This is a hack because Chrome screws up the calculation
700
+ // for when scrollbars are needed. So to fix it we temporarily
701
+ // toggle them off and on.
702
+ var orig = this._screen.style.overflow;
703
+ this._screen.style.overflow = 'hidden'; // Force Chrome to recalculate the layout by asking for
704
+ // an element's dimensions
705
+
706
+ this._screen.getBoundingClientRect();
707
+
708
+ this._screen.style.overflow = orig;
709
+ }
710
+ /*
711
+ * Connection states:
712
+ * connecting
713
+ * connected
714
+ * disconnecting
715
+ * disconnected - permanent state
716
+ */
717
+
718
+ }, {
719
+ key: "_updateConnectionState",
720
+ value: function _updateConnectionState(state) {
721
+ var _this3 = this;
722
+
723
+ var oldstate = this._rfbConnectionState;
724
+
725
+ if (state === oldstate) {
726
+ Log.Debug("Already in state '" + state + "', ignoring");
727
+ return;
728
+ } // The 'disconnected' state is permanent for each RFB object
729
+
730
+
731
+ if (oldstate === 'disconnected') {
732
+ Log.Error("Tried changing state of a disconnected RFB object");
733
+ return;
734
+ } // Ensure proper transitions before doing anything
735
+
736
+
737
+ switch (state) {
738
+ case 'connected':
739
+ if (oldstate !== 'connecting') {
740
+ Log.Error("Bad transition to connected state, " + "previous connection state: " + oldstate);
741
+ return;
742
+ }
743
+
744
+ break;
745
+
746
+ case 'disconnected':
747
+ if (oldstate !== 'disconnecting') {
748
+ Log.Error("Bad transition to disconnected state, " + "previous connection state: " + oldstate);
749
+ return;
750
+ }
751
+
752
+ break;
753
+
754
+ case 'connecting':
755
+ if (oldstate !== '') {
756
+ Log.Error("Bad transition to connecting state, " + "previous connection state: " + oldstate);
757
+ return;
758
+ }
759
+
760
+ break;
761
+
762
+ case 'disconnecting':
763
+ if (oldstate !== 'connected' && oldstate !== 'connecting') {
764
+ Log.Error("Bad transition to disconnecting state, " + "previous connection state: " + oldstate);
765
+ return;
766
+ }
767
+
768
+ break;
769
+
770
+ default:
771
+ Log.Error("Unknown connection state: " + state);
772
+ return;
773
+ } // State change actions
774
+
775
+
776
+ this._rfbConnectionState = state;
777
+ Log.Debug("New state '" + state + "', was '" + oldstate + "'.");
778
+
779
+ if (this._disconnTimer && state !== 'disconnecting') {
780
+ Log.Debug("Clearing disconnect timer");
781
+ clearTimeout(this._disconnTimer);
782
+ this._disconnTimer = null; // make sure we don't get a double event
783
+
784
+ this._sock.off('close');
785
+ }
786
+
787
+ switch (state) {
788
+ case 'connecting':
789
+ this._connect();
790
+
791
+ break;
792
+
793
+ case 'connected':
794
+ this.dispatchEvent(new CustomEvent("connect", {
795
+ detail: {}
796
+ }));
797
+ break;
798
+
799
+ case 'disconnecting':
800
+ this._disconnect();
801
+
802
+ this._disconnTimer = setTimeout(function () {
803
+ Log.Error("Disconnection timed out.");
804
+
805
+ _this3._updateConnectionState('disconnected');
806
+ }, DISCONNECT_TIMEOUT * 1000);
807
+ break;
808
+
809
+ case 'disconnected':
810
+ this.dispatchEvent(new CustomEvent("disconnect", {
811
+ detail: {
812
+ clean: this._rfbCleanDisconnect
813
+ }
814
+ }));
815
+ break;
816
+ }
817
+ }
818
+ /* Print errors and disconnect
819
+ *
820
+ * The parameter 'details' is used for information that
821
+ * should be logged but not sent to the user interface.
822
+ */
823
+
824
+ }, {
825
+ key: "_fail",
826
+ value: function _fail(details) {
827
+ switch (this._rfbConnectionState) {
828
+ case 'disconnecting':
829
+ Log.Error("Failed when disconnecting: " + details);
830
+ break;
831
+
832
+ case 'connected':
833
+ Log.Error("Failed while connected: " + details);
834
+ break;
835
+
836
+ case 'connecting':
837
+ Log.Error("Failed when connecting: " + details);
838
+ break;
839
+
840
+ default:
841
+ Log.Error("RFB failure: " + details);
842
+ break;
843
+ }
844
+
845
+ this._rfbCleanDisconnect = false; //This is sent to the UI
846
+ // Transition to disconnected without waiting for socket to close
847
+
848
+ this._updateConnectionState('disconnecting');
849
+
850
+ this._updateConnectionState('disconnected');
851
+
852
+ return false;
853
+ }
854
+ }, {
855
+ key: "_setCapability",
856
+ value: function _setCapability(cap, val) {
857
+ this._capabilities[cap] = val;
858
+ this.dispatchEvent(new CustomEvent("capabilities", {
859
+ detail: {
860
+ capabilities: this._capabilities
861
+ }
862
+ }));
863
+ }
864
+ }, {
865
+ key: "_handleMessage",
866
+ value: function _handleMessage() {
867
+ if (this._sock.rQlen === 0) {
868
+ Log.Warn("handleMessage called on an empty receive queue");
869
+ return;
870
+ }
871
+
872
+ switch (this._rfbConnectionState) {
873
+ case 'disconnected':
874
+ Log.Error("Got data while disconnected");
875
+ break;
876
+
877
+ case 'connected':
878
+ while (true) {
879
+ if (this._flushing) {
880
+ break;
881
+ }
882
+
883
+ if (!this._normalMsg()) {
884
+ break;
885
+ }
886
+
887
+ if (this._sock.rQlen === 0) {
888
+ break;
889
+ }
890
+ }
891
+
892
+ break;
893
+
894
+ default:
895
+ this._initMsg();
896
+
897
+ break;
898
+ }
899
+ }
900
+ }, {
901
+ key: "_handleKeyEvent",
902
+ value: function _handleKeyEvent(keysym, code, down) {
903
+ this.sendKey(keysym, code, down);
904
+ }
905
+ }, {
906
+ key: "_handleMouse",
907
+ value: function _handleMouse(ev) {
908
+ /*
909
+ * We don't check connection status or viewOnly here as the
910
+ * mouse events might be used to control the viewport
911
+ */
912
+ if (ev.type === 'click') {
913
+ /*
914
+ * Note: This is only needed for the 'click' event as it fails
915
+ * to fire properly for the target element so we have
916
+ * to listen on the document element instead.
917
+ */
918
+ if (ev.target !== this._canvas) {
919
+ return;
920
+ }
921
+ } // FIXME: if we're in view-only and not dragging,
922
+ // should we stop events?
923
+
924
+
925
+ ev.stopPropagation();
926
+ ev.preventDefault();
927
+
928
+ if (ev.type === 'click' || ev.type === 'contextmenu') {
929
+ return;
930
+ }
931
+
932
+ var pos = (0, _element.clientToElement)(ev.clientX, ev.clientY, this._canvas);
933
+
934
+ switch (ev.type) {
935
+ case 'mousedown':
936
+ (0, _events.setCapture)(this._canvas);
937
+
938
+ this._handleMouseButton(pos.x, pos.y, true, 1 << ev.button);
939
+
940
+ break;
941
+
942
+ case 'mouseup':
943
+ this._handleMouseButton(pos.x, pos.y, false, 1 << ev.button);
944
+
945
+ break;
946
+
947
+ case 'mousemove':
948
+ this._handleMouseMove(pos.x, pos.y);
949
+
950
+ break;
951
+ }
952
+ }
953
+ }, {
954
+ key: "_handleMouseButton",
955
+ value: function _handleMouseButton(x, y, down, bmask) {
956
+ if (this.dragViewport) {
957
+ if (down && !this._viewportDragging) {
958
+ this._viewportDragging = true;
959
+ this._viewportDragPos = {
960
+ 'x': x,
961
+ 'y': y
962
+ };
963
+ this._viewportHasMoved = false; // Skip sending mouse events
964
+
965
+ return;
966
+ } else {
967
+ this._viewportDragging = false; // If we actually performed a drag then we are done
968
+ // here and should not send any mouse events
969
+
970
+ if (this._viewportHasMoved) {
971
+ return;
972
+ } // Otherwise we treat this as a mouse click event.
973
+ // Send the button down event here, as the button up
974
+ // event is sent at the end of this function.
975
+
976
+
977
+ this._sendMouse(x, y, bmask);
978
+ }
979
+ } // Flush waiting move event first
980
+
981
+
982
+ if (this._mouseMoveTimer !== null) {
983
+ clearTimeout(this._mouseMoveTimer);
984
+ this._mouseMoveTimer = null;
985
+
986
+ this._sendMouse(x, y, this._mouseButtonMask);
987
+ }
988
+
989
+ if (down) {
990
+ this._mouseButtonMask |= bmask;
991
+ } else {
992
+ this._mouseButtonMask &= ~bmask;
993
+ }
994
+
995
+ this._sendMouse(x, y, this._mouseButtonMask);
996
+ }
997
+ }, {
998
+ key: "_handleMouseMove",
999
+ value: function _handleMouseMove(x, y) {
1000
+ var _this4 = this;
1001
+
1002
+ if (this._viewportDragging) {
1003
+ var deltaX = this._viewportDragPos.x - x;
1004
+ var deltaY = this._viewportDragPos.y - y;
1005
+
1006
+ if (this._viewportHasMoved || Math.abs(deltaX) > _browser.dragThreshold || Math.abs(deltaY) > _browser.dragThreshold) {
1007
+ this._viewportHasMoved = true;
1008
+ this._viewportDragPos = {
1009
+ 'x': x,
1010
+ 'y': y
1011
+ };
1012
+
1013
+ this._display.viewportChangePos(deltaX, deltaY);
1014
+ } // Skip sending mouse events
1015
+
1016
+
1017
+ return;
1018
+ }
1019
+
1020
+ this._mousePos = {
1021
+ 'x': x,
1022
+ 'y': y
1023
+ }; // Limit many mouse move events to one every MOUSE_MOVE_DELAY ms
1024
+
1025
+ if (this._mouseMoveTimer == null) {
1026
+ var timeSinceLastMove = Date.now() - this._mouseLastMoveTime;
1027
+
1028
+ if (timeSinceLastMove > MOUSE_MOVE_DELAY) {
1029
+ this._sendMouse(x, y, this._mouseButtonMask);
1030
+
1031
+ this._mouseLastMoveTime = Date.now();
1032
+ } else {
1033
+ // Too soon since the latest move, wait the remaining time
1034
+ this._mouseMoveTimer = setTimeout(function () {
1035
+ _this4._handleDelayedMouseMove();
1036
+ }, MOUSE_MOVE_DELAY - timeSinceLastMove);
1037
+ }
1038
+ }
1039
+ }
1040
+ }, {
1041
+ key: "_handleDelayedMouseMove",
1042
+ value: function _handleDelayedMouseMove() {
1043
+ this._mouseMoveTimer = null;
1044
+
1045
+ this._sendMouse(this._mousePos.x, this._mousePos.y, this._mouseButtonMask);
1046
+
1047
+ this._mouseLastMoveTime = Date.now();
1048
+ }
1049
+ }, {
1050
+ key: "_sendMouse",
1051
+ value: function _sendMouse(x, y, mask) {
1052
+ if (this._rfbConnectionState !== 'connected') {
1053
+ return;
1054
+ }
1055
+
1056
+ if (this._viewOnly) {
1057
+ return;
1058
+ } // View only, skip mouse events
1059
+
1060
+
1061
+ RFB.messages.pointerEvent(this._sock, this._display.absX(x), this._display.absY(y), mask);
1062
+ }
1063
+ }, {
1064
+ key: "_handleWheel",
1065
+ value: function _handleWheel(ev) {
1066
+ if (this._rfbConnectionState !== 'connected') {
1067
+ return;
1068
+ }
1069
+
1070
+ if (this._viewOnly) {
1071
+ return;
1072
+ } // View only, skip mouse events
1073
+
1074
+
1075
+ ev.stopPropagation();
1076
+ ev.preventDefault();
1077
+ var pos = (0, _element.clientToElement)(ev.clientX, ev.clientY, this._canvas);
1078
+ var dX = ev.deltaX;
1079
+ var dY = ev.deltaY; // Pixel units unless it's non-zero.
1080
+ // Note that if deltamode is line or page won't matter since we aren't
1081
+ // sending the mouse wheel delta to the server anyway.
1082
+ // The difference between pixel and line can be important however since
1083
+ // we have a threshold that can be smaller than the line height.
1084
+
1085
+ if (ev.deltaMode !== 0) {
1086
+ dX *= WHEEL_LINE_HEIGHT;
1087
+ dY *= WHEEL_LINE_HEIGHT;
1088
+ } // Mouse wheel events are sent in steps over VNC. This means that the VNC
1089
+ // protocol can't handle a wheel event with specific distance or speed.
1090
+ // Therefor, if we get a lot of small mouse wheel events we combine them.
1091
+
1092
+
1093
+ this._accumulatedWheelDeltaX += dX;
1094
+ this._accumulatedWheelDeltaY += dY; // Generate a mouse wheel step event when the accumulated delta
1095
+ // for one of the axes is large enough.
1096
+
1097
+ if (Math.abs(this._accumulatedWheelDeltaX) >= WHEEL_STEP) {
1098
+ if (this._accumulatedWheelDeltaX < 0) {
1099
+ this._handleMouseButton(pos.x, pos.y, true, 1 << 5);
1100
+
1101
+ this._handleMouseButton(pos.x, pos.y, false, 1 << 5);
1102
+ } else if (this._accumulatedWheelDeltaX > 0) {
1103
+ this._handleMouseButton(pos.x, pos.y, true, 1 << 6);
1104
+
1105
+ this._handleMouseButton(pos.x, pos.y, false, 1 << 6);
1106
+ }
1107
+
1108
+ this._accumulatedWheelDeltaX = 0;
1109
+ }
1110
+
1111
+ if (Math.abs(this._accumulatedWheelDeltaY) >= WHEEL_STEP) {
1112
+ if (this._accumulatedWheelDeltaY < 0) {
1113
+ this._handleMouseButton(pos.x, pos.y, true, 1 << 3);
1114
+
1115
+ this._handleMouseButton(pos.x, pos.y, false, 1 << 3);
1116
+ } else if (this._accumulatedWheelDeltaY > 0) {
1117
+ this._handleMouseButton(pos.x, pos.y, true, 1 << 4);
1118
+
1119
+ this._handleMouseButton(pos.x, pos.y, false, 1 << 4);
1120
+ }
1121
+
1122
+ this._accumulatedWheelDeltaY = 0;
1123
+ }
1124
+ }
1125
+ }, {
1126
+ key: "_fakeMouseMove",
1127
+ value: function _fakeMouseMove(ev, elementX, elementY) {
1128
+ this._handleMouseMove(elementX, elementY);
1129
+
1130
+ this._cursor.move(ev.detail.clientX, ev.detail.clientY);
1131
+ }
1132
+ }, {
1133
+ key: "_handleTapEvent",
1134
+ value: function _handleTapEvent(ev, bmask) {
1135
+ var pos = (0, _element.clientToElement)(ev.detail.clientX, ev.detail.clientY, this._canvas); // If the user quickly taps multiple times we assume they meant to
1136
+ // hit the same spot, so slightly adjust coordinates
1137
+
1138
+ if (this._gestureLastTapTime !== null && Date.now() - this._gestureLastTapTime < DOUBLE_TAP_TIMEOUT && this._gestureFirstDoubleTapEv.detail.type === ev.detail.type) {
1139
+ var dx = this._gestureFirstDoubleTapEv.detail.clientX - ev.detail.clientX;
1140
+ var dy = this._gestureFirstDoubleTapEv.detail.clientY - ev.detail.clientY;
1141
+ var distance = Math.hypot(dx, dy);
1142
+
1143
+ if (distance < DOUBLE_TAP_THRESHOLD) {
1144
+ pos = (0, _element.clientToElement)(this._gestureFirstDoubleTapEv.detail.clientX, this._gestureFirstDoubleTapEv.detail.clientY, this._canvas);
1145
+ } else {
1146
+ this._gestureFirstDoubleTapEv = ev;
1147
+ }
1148
+ } else {
1149
+ this._gestureFirstDoubleTapEv = ev;
1150
+ }
1151
+
1152
+ this._gestureLastTapTime = Date.now();
1153
+
1154
+ this._fakeMouseMove(this._gestureFirstDoubleTapEv, pos.x, pos.y);
1155
+
1156
+ this._handleMouseButton(pos.x, pos.y, true, bmask);
1157
+
1158
+ this._handleMouseButton(pos.x, pos.y, false, bmask);
1159
+ }
1160
+ }, {
1161
+ key: "_handleGesture",
1162
+ value: function _handleGesture(ev) {
1163
+ var magnitude;
1164
+ var pos = (0, _element.clientToElement)(ev.detail.clientX, ev.detail.clientY, this._canvas);
1165
+
1166
+ switch (ev.type) {
1167
+ case 'gesturestart':
1168
+ switch (ev.detail.type) {
1169
+ case 'onetap':
1170
+ this._handleTapEvent(ev, 0x1);
1171
+
1172
+ break;
1173
+
1174
+ case 'twotap':
1175
+ this._handleTapEvent(ev, 0x4);
1176
+
1177
+ break;
1178
+
1179
+ case 'threetap':
1180
+ this._handleTapEvent(ev, 0x2);
1181
+
1182
+ break;
1183
+
1184
+ case 'drag':
1185
+ this._fakeMouseMove(ev, pos.x, pos.y);
1186
+
1187
+ this._handleMouseButton(pos.x, pos.y, true, 0x1);
1188
+
1189
+ break;
1190
+
1191
+ case 'longpress':
1192
+ this._fakeMouseMove(ev, pos.x, pos.y);
1193
+
1194
+ this._handleMouseButton(pos.x, pos.y, true, 0x4);
1195
+
1196
+ break;
1197
+
1198
+ case 'twodrag':
1199
+ this._gestureLastMagnitudeX = ev.detail.magnitudeX;
1200
+ this._gestureLastMagnitudeY = ev.detail.magnitudeY;
1201
+
1202
+ this._fakeMouseMove(ev, pos.x, pos.y);
1203
+
1204
+ break;
1205
+
1206
+ case 'pinch':
1207
+ this._gestureLastMagnitudeX = Math.hypot(ev.detail.magnitudeX, ev.detail.magnitudeY);
1208
+
1209
+ this._fakeMouseMove(ev, pos.x, pos.y);
1210
+
1211
+ break;
1212
+ }
1213
+
1214
+ break;
1215
+
1216
+ case 'gesturemove':
1217
+ switch (ev.detail.type) {
1218
+ case 'onetap':
1219
+ case 'twotap':
1220
+ case 'threetap':
1221
+ break;
1222
+
1223
+ case 'drag':
1224
+ case 'longpress':
1225
+ this._fakeMouseMove(ev, pos.x, pos.y);
1226
+
1227
+ break;
1228
+
1229
+ case 'twodrag':
1230
+ // Always scroll in the same position.
1231
+ // We don't know if the mouse was moved so we need to move it
1232
+ // every update.
1233
+ this._fakeMouseMove(ev, pos.x, pos.y);
1234
+
1235
+ while (ev.detail.magnitudeY - this._gestureLastMagnitudeY > GESTURE_SCRLSENS) {
1236
+ this._handleMouseButton(pos.x, pos.y, true, 0x8);
1237
+
1238
+ this._handleMouseButton(pos.x, pos.y, false, 0x8);
1239
+
1240
+ this._gestureLastMagnitudeY += GESTURE_SCRLSENS;
1241
+ }
1242
+
1243
+ while (ev.detail.magnitudeY - this._gestureLastMagnitudeY < -GESTURE_SCRLSENS) {
1244
+ this._handleMouseButton(pos.x, pos.y, true, 0x10);
1245
+
1246
+ this._handleMouseButton(pos.x, pos.y, false, 0x10);
1247
+
1248
+ this._gestureLastMagnitudeY -= GESTURE_SCRLSENS;
1249
+ }
1250
+
1251
+ while (ev.detail.magnitudeX - this._gestureLastMagnitudeX > GESTURE_SCRLSENS) {
1252
+ this._handleMouseButton(pos.x, pos.y, true, 0x20);
1253
+
1254
+ this._handleMouseButton(pos.x, pos.y, false, 0x20);
1255
+
1256
+ this._gestureLastMagnitudeX += GESTURE_SCRLSENS;
1257
+ }
1258
+
1259
+ while (ev.detail.magnitudeX - this._gestureLastMagnitudeX < -GESTURE_SCRLSENS) {
1260
+ this._handleMouseButton(pos.x, pos.y, true, 0x40);
1261
+
1262
+ this._handleMouseButton(pos.x, pos.y, false, 0x40);
1263
+
1264
+ this._gestureLastMagnitudeX -= GESTURE_SCRLSENS;
1265
+ }
1266
+
1267
+ break;
1268
+
1269
+ case 'pinch':
1270
+ // Always scroll in the same position.
1271
+ // We don't know if the mouse was moved so we need to move it
1272
+ // every update.
1273
+ this._fakeMouseMove(ev, pos.x, pos.y);
1274
+
1275
+ magnitude = Math.hypot(ev.detail.magnitudeX, ev.detail.magnitudeY);
1276
+
1277
+ if (Math.abs(magnitude - this._gestureLastMagnitudeX) > GESTURE_ZOOMSENS) {
1278
+ this._handleKeyEvent(_keysym.default.XK_Control_L, "ControlLeft", true);
1279
+
1280
+ while (magnitude - this._gestureLastMagnitudeX > GESTURE_ZOOMSENS) {
1281
+ this._handleMouseButton(pos.x, pos.y, true, 0x8);
1282
+
1283
+ this._handleMouseButton(pos.x, pos.y, false, 0x8);
1284
+
1285
+ this._gestureLastMagnitudeX += GESTURE_ZOOMSENS;
1286
+ }
1287
+
1288
+ while (magnitude - this._gestureLastMagnitudeX < -GESTURE_ZOOMSENS) {
1289
+ this._handleMouseButton(pos.x, pos.y, true, 0x10);
1290
+
1291
+ this._handleMouseButton(pos.x, pos.y, false, 0x10);
1292
+
1293
+ this._gestureLastMagnitudeX -= GESTURE_ZOOMSENS;
1294
+ }
1295
+ }
1296
+
1297
+ this._handleKeyEvent(_keysym.default.XK_Control_L, "ControlLeft", false);
1298
+
1299
+ break;
1300
+ }
1301
+
1302
+ break;
1303
+
1304
+ case 'gestureend':
1305
+ switch (ev.detail.type) {
1306
+ case 'onetap':
1307
+ case 'twotap':
1308
+ case 'threetap':
1309
+ case 'pinch':
1310
+ case 'twodrag':
1311
+ break;
1312
+
1313
+ case 'drag':
1314
+ this._fakeMouseMove(ev, pos.x, pos.y);
1315
+
1316
+ this._handleMouseButton(pos.x, pos.y, false, 0x1);
1317
+
1318
+ break;
1319
+
1320
+ case 'longpress':
1321
+ this._fakeMouseMove(ev, pos.x, pos.y);
1322
+
1323
+ this._handleMouseButton(pos.x, pos.y, false, 0x4);
1324
+
1325
+ break;
1326
+ }
1327
+
1328
+ break;
1329
+ }
1330
+ } // Message Handlers
1331
+
1332
+ }, {
1333
+ key: "_negotiateProtocolVersion",
1334
+ value: function _negotiateProtocolVersion() {
1335
+ if (this._sock.rQwait("version", 12)) {
1336
+ return false;
1337
+ }
1338
+
1339
+ var sversion = this._sock.rQshiftStr(12).substr(4, 7);
1340
+
1341
+ Log.Info("Server ProtocolVersion: " + sversion);
1342
+ var isRepeater = 0;
1343
+
1344
+ switch (sversion) {
1345
+ case "000.000":
1346
+ // UltraVNC repeater
1347
+ isRepeater = 1;
1348
+ break;
1349
+
1350
+ case "003.003":
1351
+ case "003.006": // UltraVNC
1352
+
1353
+ case "003.889":
1354
+ // Apple Remote Desktop
1355
+ this._rfbVersion = 3.3;
1356
+ break;
1357
+
1358
+ case "003.007":
1359
+ this._rfbVersion = 3.7;
1360
+ break;
1361
+
1362
+ case "003.008":
1363
+ case "004.000": // Intel AMT KVM
1364
+
1365
+ case "004.001": // RealVNC 4.6
1366
+
1367
+ case "005.000":
1368
+ // RealVNC 5.3
1369
+ this._rfbVersion = 3.8;
1370
+ break;
1371
+
1372
+ default:
1373
+ return this._fail("Invalid server version " + sversion);
1374
+ }
1375
+
1376
+ if (isRepeater) {
1377
+ var repeaterID = "ID:" + this._repeaterID;
1378
+
1379
+ while (repeaterID.length < 250) {
1380
+ repeaterID += "\0";
1381
+ }
1382
+
1383
+ this._sock.sendString(repeaterID);
1384
+
1385
+ return true;
1386
+ }
1387
+
1388
+ if (this._rfbVersion > this._rfbMaxVersion) {
1389
+ this._rfbVersion = this._rfbMaxVersion;
1390
+ }
1391
+
1392
+ var cversion = "00" + parseInt(this._rfbVersion, 10) + ".00" + this._rfbVersion * 10 % 10;
1393
+
1394
+ this._sock.sendString("RFB " + cversion + "\n");
1395
+
1396
+ Log.Debug('Sent ProtocolVersion: ' + cversion);
1397
+ this._rfbInitState = 'Security';
1398
+ }
1399
+ }, {
1400
+ key: "_negotiateSecurity",
1401
+ value: function _negotiateSecurity() {
1402
+ // Polyfill since IE and PhantomJS doesn't have
1403
+ // TypedArray.includes()
1404
+ function includes(item, array) {
1405
+ for (var i = 0; i < array.length; i++) {
1406
+ if (array[i] === item) {
1407
+ return true;
1408
+ }
1409
+ }
1410
+
1411
+ return false;
1412
+ }
1413
+
1414
+ if (this._rfbVersion >= 3.7) {
1415
+ // Server sends supported list, client decides
1416
+ var numTypes = this._sock.rQshift8();
1417
+
1418
+ if (this._sock.rQwait("security type", numTypes, 1)) {
1419
+ return false;
1420
+ }
1421
+
1422
+ if (numTypes === 0) {
1423
+ this._rfbInitState = "SecurityReason";
1424
+ this._securityContext = "no security types";
1425
+ this._securityStatus = 1;
1426
+ return this._initMsg();
1427
+ }
1428
+
1429
+ var types = this._sock.rQshiftBytes(numTypes);
1430
+
1431
+ Log.Debug("Server security types: " + types); // Look for each auth in preferred order
1432
+
1433
+ if (includes(1, types)) {
1434
+ this._rfbAuthScheme = 1; // None
1435
+ } else if (includes(22, types)) {
1436
+ this._rfbAuthScheme = 22; // XVP
1437
+ } else if (includes(16, types)) {
1438
+ this._rfbAuthScheme = 16; // Tight
1439
+ } else if (includes(2, types)) {
1440
+ this._rfbAuthScheme = 2; // VNC Auth
1441
+ } else if (includes(19, types)) {
1442
+ this._rfbAuthScheme = 19; // VeNCrypt Auth
1443
+ } else {
1444
+ return this._fail("Unsupported security types (types: " + types + ")");
1445
+ }
1446
+
1447
+ this._sock.send([this._rfbAuthScheme]);
1448
+ } else {
1449
+ // Server decides
1450
+ if (this._sock.rQwait("security scheme", 4)) {
1451
+ return false;
1452
+ }
1453
+
1454
+ this._rfbAuthScheme = this._sock.rQshift32();
1455
+
1456
+ if (this._rfbAuthScheme == 0) {
1457
+ this._rfbInitState = "SecurityReason";
1458
+ this._securityContext = "authentication scheme";
1459
+ this._securityStatus = 1;
1460
+ return this._initMsg();
1461
+ }
1462
+ }
1463
+
1464
+ this._rfbInitState = 'Authentication';
1465
+ Log.Debug('Authenticating using scheme: ' + this._rfbAuthScheme);
1466
+ return this._initMsg(); // jump to authentication
1467
+ }
1468
+ }, {
1469
+ key: "_handleSecurityReason",
1470
+ value: function _handleSecurityReason() {
1471
+ if (this._sock.rQwait("reason length", 4)) {
1472
+ return false;
1473
+ }
1474
+
1475
+ var strlen = this._sock.rQshift32();
1476
+
1477
+ var reason = "";
1478
+
1479
+ if (strlen > 0) {
1480
+ if (this._sock.rQwait("reason", strlen, 4)) {
1481
+ return false;
1482
+ }
1483
+
1484
+ reason = this._sock.rQshiftStr(strlen);
1485
+ }
1486
+
1487
+ if (reason !== "") {
1488
+ this.dispatchEvent(new CustomEvent("securityfailure", {
1489
+ detail: {
1490
+ status: this._securityStatus,
1491
+ reason: reason
1492
+ }
1493
+ }));
1494
+ return this._fail("Security negotiation failed on " + this._securityContext + " (reason: " + reason + ")");
1495
+ } else {
1496
+ this.dispatchEvent(new CustomEvent("securityfailure", {
1497
+ detail: {
1498
+ status: this._securityStatus
1499
+ }
1500
+ }));
1501
+ return this._fail("Security negotiation failed on " + this._securityContext);
1502
+ }
1503
+ } // authentication
1504
+
1505
+ }, {
1506
+ key: "_negotiateXvpAuth",
1507
+ value: function _negotiateXvpAuth() {
1508
+ if (this._rfbCredentials.username === undefined || this._rfbCredentials.password === undefined || this._rfbCredentials.target === undefined) {
1509
+ this.dispatchEvent(new CustomEvent("credentialsrequired", {
1510
+ detail: {
1511
+ types: ["username", "password", "target"]
1512
+ }
1513
+ }));
1514
+ return false;
1515
+ }
1516
+
1517
+ var xvpAuthStr = String.fromCharCode(this._rfbCredentials.username.length) + String.fromCharCode(this._rfbCredentials.target.length) + this._rfbCredentials.username + this._rfbCredentials.target;
1518
+
1519
+ this._sock.sendString(xvpAuthStr);
1520
+
1521
+ this._rfbAuthScheme = 2;
1522
+ return this._negotiateAuthentication();
1523
+ } // VeNCrypt authentication, currently only supports version 0.2 and only Plain subtype
1524
+
1525
+ }, {
1526
+ key: "_negotiateVeNCryptAuth",
1527
+ value: function _negotiateVeNCryptAuth() {
1528
+ // waiting for VeNCrypt version
1529
+ if (this._rfbVeNCryptState == 0) {
1530
+ if (this._sock.rQwait("vencrypt version", 2)) {
1531
+ return false;
1532
+ }
1533
+
1534
+ var major = this._sock.rQshift8();
1535
+
1536
+ var minor = this._sock.rQshift8();
1537
+
1538
+ if (!(major == 0 && minor == 2)) {
1539
+ return this._fail("Unsupported VeNCrypt version " + major + "." + minor);
1540
+ }
1541
+
1542
+ this._sock.send([0, 2]);
1543
+
1544
+ this._rfbVeNCryptState = 1;
1545
+ } // waiting for ACK
1546
+
1547
+
1548
+ if (this._rfbVeNCryptState == 1) {
1549
+ if (this._sock.rQwait("vencrypt ack", 1)) {
1550
+ return false;
1551
+ }
1552
+
1553
+ var res = this._sock.rQshift8();
1554
+
1555
+ if (res != 0) {
1556
+ return this._fail("VeNCrypt failure " + res);
1557
+ }
1558
+
1559
+ this._rfbVeNCryptState = 2;
1560
+ } // must fall through here (i.e. no "else if"), beacause we may have already received
1561
+ // the subtypes length and won't be called again
1562
+
1563
+
1564
+ if (this._rfbVeNCryptState == 2) {
1565
+ // waiting for subtypes length
1566
+ if (this._sock.rQwait("vencrypt subtypes length", 1)) {
1567
+ return false;
1568
+ }
1569
+
1570
+ var subtypesLength = this._sock.rQshift8();
1571
+
1572
+ if (subtypesLength < 1) {
1573
+ return this._fail("VeNCrypt subtypes empty");
1574
+ }
1575
+
1576
+ this._rfbVeNCryptSubtypesLength = subtypesLength;
1577
+ this._rfbVeNCryptState = 3;
1578
+ } // waiting for subtypes list
1579
+
1580
+
1581
+ if (this._rfbVeNCryptState == 3) {
1582
+ if (this._sock.rQwait("vencrypt subtypes", 4 * this._rfbVeNCryptSubtypesLength)) {
1583
+ return false;
1584
+ }
1585
+
1586
+ var subtypes = [];
1587
+
1588
+ for (var i = 0; i < this._rfbVeNCryptSubtypesLength; i++) {
1589
+ subtypes.push(this._sock.rQshift32());
1590
+ } // 256 = Plain subtype
1591
+
1592
+
1593
+ if (subtypes.indexOf(256) != -1) {
1594
+ // 0x100 = 256
1595
+ this._sock.send([0, 0, 1, 0]);
1596
+
1597
+ this._rfbVeNCryptState = 4;
1598
+ } else {
1599
+ return this._fail("VeNCrypt Plain subtype not offered by server");
1600
+ }
1601
+ } // negotiated Plain subtype, server waits for password
1602
+
1603
+
1604
+ if (this._rfbVeNCryptState == 4) {
1605
+ if (!this._rfbCredentials.username || !this._rfbCredentials.password) {
1606
+ this.dispatchEvent(new CustomEvent("credentialsrequired", {
1607
+ detail: {
1608
+ types: ["username", "password"]
1609
+ }
1610
+ }));
1611
+ return false;
1612
+ }
1613
+
1614
+ var user = (0, _strings.encodeUTF8)(this._rfbCredentials.username);
1615
+ var pass = (0, _strings.encodeUTF8)(this._rfbCredentials.password); // XXX we assume lengths are <= 255 (should not be an issue in the real world)
1616
+
1617
+ this._sock.send([0, 0, 0, user.length]);
1618
+
1619
+ this._sock.send([0, 0, 0, pass.length]);
1620
+
1621
+ this._sock.sendString(user);
1622
+
1623
+ this._sock.sendString(pass);
1624
+
1625
+ this._rfbInitState = "SecurityResult";
1626
+ return true;
1627
+ }
1628
+ }
1629
+ }, {
1630
+ key: "_negotiateStdVNCAuth",
1631
+ value: function _negotiateStdVNCAuth() {
1632
+ if (this._sock.rQwait("auth challenge", 16)) {
1633
+ return false;
1634
+ }
1635
+
1636
+ if (this._rfbCredentials.password === undefined) {
1637
+ this.dispatchEvent(new CustomEvent("credentialsrequired", {
1638
+ detail: {
1639
+ types: ["password"]
1640
+ }
1641
+ }));
1642
+ return false;
1643
+ } // TODO(directxman12): make genDES not require an Array
1644
+
1645
+
1646
+ var challenge = Array.prototype.slice.call(this._sock.rQshiftBytes(16));
1647
+ var response = RFB.genDES(this._rfbCredentials.password, challenge);
1648
+
1649
+ this._sock.send(response);
1650
+
1651
+ this._rfbInitState = "SecurityResult";
1652
+ return true;
1653
+ }
1654
+ }, {
1655
+ key: "_negotiateTightUnixAuth",
1656
+ value: function _negotiateTightUnixAuth() {
1657
+ if (this._rfbCredentials.username === undefined || this._rfbCredentials.password === undefined) {
1658
+ this.dispatchEvent(new CustomEvent("credentialsrequired", {
1659
+ detail: {
1660
+ types: ["username", "password"]
1661
+ }
1662
+ }));
1663
+ return false;
1664
+ }
1665
+
1666
+ this._sock.send([0, 0, 0, this._rfbCredentials.username.length]);
1667
+
1668
+ this._sock.send([0, 0, 0, this._rfbCredentials.password.length]);
1669
+
1670
+ this._sock.sendString(this._rfbCredentials.username);
1671
+
1672
+ this._sock.sendString(this._rfbCredentials.password);
1673
+
1674
+ this._rfbInitState = "SecurityResult";
1675
+ return true;
1676
+ }
1677
+ }, {
1678
+ key: "_negotiateTightTunnels",
1679
+ value: function _negotiateTightTunnels(numTunnels) {
1680
+ var clientSupportedTunnelTypes = {
1681
+ 0: {
1682
+ vendor: 'TGHT',
1683
+ signature: 'NOTUNNEL'
1684
+ }
1685
+ };
1686
+ var serverSupportedTunnelTypes = {}; // receive tunnel capabilities
1687
+
1688
+ for (var i = 0; i < numTunnels; i++) {
1689
+ var capCode = this._sock.rQshift32();
1690
+
1691
+ var capVendor = this._sock.rQshiftStr(4);
1692
+
1693
+ var capSignature = this._sock.rQshiftStr(8);
1694
+
1695
+ serverSupportedTunnelTypes[capCode] = {
1696
+ vendor: capVendor,
1697
+ signature: capSignature
1698
+ };
1699
+ }
1700
+
1701
+ Log.Debug("Server Tight tunnel types: " + serverSupportedTunnelTypes); // Siemens touch panels have a VNC server that supports NOTUNNEL,
1702
+ // but forgets to advertise it. Try to detect such servers by
1703
+ // looking for their custom tunnel type.
1704
+
1705
+ if (serverSupportedTunnelTypes[1] && serverSupportedTunnelTypes[1].vendor === "SICR" && serverSupportedTunnelTypes[1].signature === "SCHANNEL") {
1706
+ Log.Debug("Detected Siemens server. Assuming NOTUNNEL support.");
1707
+ serverSupportedTunnelTypes[0] = {
1708
+ vendor: 'TGHT',
1709
+ signature: 'NOTUNNEL'
1710
+ };
1711
+ } // choose the notunnel type
1712
+
1713
+
1714
+ if (serverSupportedTunnelTypes[0]) {
1715
+ if (serverSupportedTunnelTypes[0].vendor != clientSupportedTunnelTypes[0].vendor || serverSupportedTunnelTypes[0].signature != clientSupportedTunnelTypes[0].signature) {
1716
+ return this._fail("Client's tunnel type had the incorrect " + "vendor or signature");
1717
+ }
1718
+
1719
+ Log.Debug("Selected tunnel type: " + clientSupportedTunnelTypes[0]);
1720
+
1721
+ this._sock.send([0, 0, 0, 0]); // use NOTUNNEL
1722
+
1723
+
1724
+ return false; // wait until we receive the sub auth count to continue
1725
+ } else {
1726
+ return this._fail("Server wanted tunnels, but doesn't support " + "the notunnel type");
1727
+ }
1728
+ }
1729
+ }, {
1730
+ key: "_negotiateTightAuth",
1731
+ value: function _negotiateTightAuth() {
1732
+ if (!this._rfbTightVNC) {
1733
+ // first pass, do the tunnel negotiation
1734
+ if (this._sock.rQwait("num tunnels", 4)) {
1735
+ return false;
1736
+ }
1737
+
1738
+ var numTunnels = this._sock.rQshift32();
1739
+
1740
+ if (numTunnels > 0 && this._sock.rQwait("tunnel capabilities", 16 * numTunnels, 4)) {
1741
+ return false;
1742
+ }
1743
+
1744
+ this._rfbTightVNC = true;
1745
+
1746
+ if (numTunnels > 0) {
1747
+ this._negotiateTightTunnels(numTunnels);
1748
+
1749
+ return false; // wait until we receive the sub auth to continue
1750
+ }
1751
+ } // second pass, do the sub-auth negotiation
1752
+
1753
+
1754
+ if (this._sock.rQwait("sub auth count", 4)) {
1755
+ return false;
1756
+ }
1757
+
1758
+ var subAuthCount = this._sock.rQshift32();
1759
+
1760
+ if (subAuthCount === 0) {
1761
+ // empty sub-auth list received means 'no auth' subtype selected
1762
+ this._rfbInitState = 'SecurityResult';
1763
+ return true;
1764
+ }
1765
+
1766
+ if (this._sock.rQwait("sub auth capabilities", 16 * subAuthCount, 4)) {
1767
+ return false;
1768
+ }
1769
+
1770
+ var clientSupportedTypes = {
1771
+ 'STDVNOAUTH__': 1,
1772
+ 'STDVVNCAUTH_': 2,
1773
+ 'TGHTULGNAUTH': 129
1774
+ };
1775
+ var serverSupportedTypes = [];
1776
+
1777
+ for (var i = 0; i < subAuthCount; i++) {
1778
+ this._sock.rQshift32(); // capNum
1779
+
1780
+
1781
+ var capabilities = this._sock.rQshiftStr(12);
1782
+
1783
+ serverSupportedTypes.push(capabilities);
1784
+ }
1785
+
1786
+ Log.Debug("Server Tight authentication types: " + serverSupportedTypes);
1787
+
1788
+ for (var authType in clientSupportedTypes) {
1789
+ if (serverSupportedTypes.indexOf(authType) != -1) {
1790
+ this._sock.send([0, 0, 0, clientSupportedTypes[authType]]);
1791
+
1792
+ Log.Debug("Selected authentication type: " + authType);
1793
+
1794
+ switch (authType) {
1795
+ case 'STDVNOAUTH__':
1796
+ // no auth
1797
+ this._rfbInitState = 'SecurityResult';
1798
+ return true;
1799
+
1800
+ case 'STDVVNCAUTH_':
1801
+ // VNC auth
1802
+ this._rfbAuthScheme = 2;
1803
+ return this._initMsg();
1804
+
1805
+ case 'TGHTULGNAUTH':
1806
+ // UNIX auth
1807
+ this._rfbAuthScheme = 129;
1808
+ return this._initMsg();
1809
+
1810
+ default:
1811
+ return this._fail("Unsupported tiny auth scheme " + "(scheme: " + authType + ")");
1812
+ }
1813
+ }
1814
+ }
1815
+
1816
+ return this._fail("No supported sub-auth types!");
1817
+ }
1818
+ }, {
1819
+ key: "_negotiateAuthentication",
1820
+ value: function _negotiateAuthentication() {
1821
+ switch (this._rfbAuthScheme) {
1822
+ case 1:
1823
+ // no auth
1824
+ if (this._rfbVersion >= 3.8) {
1825
+ this._rfbInitState = 'SecurityResult';
1826
+ return true;
1827
+ }
1828
+
1829
+ this._rfbInitState = 'ClientInitialisation';
1830
+ return this._initMsg();
1831
+
1832
+ case 22:
1833
+ // XVP auth
1834
+ return this._negotiateXvpAuth();
1835
+
1836
+ case 2:
1837
+ // VNC authentication
1838
+ return this._negotiateStdVNCAuth();
1839
+
1840
+ case 16:
1841
+ // TightVNC Security Type
1842
+ return this._negotiateTightAuth();
1843
+
1844
+ case 19:
1845
+ // VeNCrypt Security Type
1846
+ return this._negotiateVeNCryptAuth();
1847
+
1848
+ case 129:
1849
+ // TightVNC UNIX Security Type
1850
+ return this._negotiateTightUnixAuth();
1851
+
1852
+ default:
1853
+ return this._fail("Unsupported auth scheme (scheme: " + this._rfbAuthScheme + ")");
1854
+ }
1855
+ }
1856
+ }, {
1857
+ key: "_handleSecurityResult",
1858
+ value: function _handleSecurityResult() {
1859
+ if (this._sock.rQwait('VNC auth response ', 4)) {
1860
+ return false;
1861
+ }
1862
+
1863
+ var status = this._sock.rQshift32();
1864
+
1865
+ if (status === 0) {
1866
+ // OK
1867
+ this._rfbInitState = 'ClientInitialisation';
1868
+ Log.Debug('Authentication OK');
1869
+ return this._initMsg();
1870
+ } else {
1871
+ if (this._rfbVersion >= 3.8) {
1872
+ this._rfbInitState = "SecurityReason";
1873
+ this._securityContext = "security result";
1874
+ this._securityStatus = status;
1875
+ return this._initMsg();
1876
+ } else {
1877
+ this.dispatchEvent(new CustomEvent("securityfailure", {
1878
+ detail: {
1879
+ status: status
1880
+ }
1881
+ }));
1882
+ return this._fail("Security handshake failed");
1883
+ }
1884
+ }
1885
+ }
1886
+ }, {
1887
+ key: "_negotiateServerInit",
1888
+ value: function _negotiateServerInit() {
1889
+ if (this._sock.rQwait("server initialization", 24)) {
1890
+ return false;
1891
+ }
1892
+ /* Screen size */
1893
+
1894
+
1895
+ var width = this._sock.rQshift16();
1896
+
1897
+ var height = this._sock.rQshift16();
1898
+ /* PIXEL_FORMAT */
1899
+
1900
+
1901
+ var bpp = this._sock.rQshift8();
1902
+
1903
+ var depth = this._sock.rQshift8();
1904
+
1905
+ var bigEndian = this._sock.rQshift8();
1906
+
1907
+ var trueColor = this._sock.rQshift8();
1908
+
1909
+ var redMax = this._sock.rQshift16();
1910
+
1911
+ var greenMax = this._sock.rQshift16();
1912
+
1913
+ var blueMax = this._sock.rQshift16();
1914
+
1915
+ var redShift = this._sock.rQshift8();
1916
+
1917
+ var greenShift = this._sock.rQshift8();
1918
+
1919
+ var blueShift = this._sock.rQshift8();
1920
+
1921
+ this._sock.rQskipBytes(3); // padding
1922
+ // NB(directxman12): we don't want to call any callbacks or print messages until
1923
+ // *after* we're past the point where we could backtrack
1924
+
1925
+ /* Connection name/title */
1926
+
1927
+
1928
+ var nameLength = this._sock.rQshift32();
1929
+
1930
+ if (this._sock.rQwait('server init name', nameLength, 24)) {
1931
+ return false;
1932
+ }
1933
+
1934
+ var name = this._sock.rQshiftStr(nameLength);
1935
+
1936
+ name = (0, _strings.decodeUTF8)(name, true);
1937
+
1938
+ if (this._rfbTightVNC) {
1939
+ if (this._sock.rQwait('TightVNC extended server init header', 8, 24 + nameLength)) {
1940
+ return false;
1941
+ } // In TightVNC mode, ServerInit message is extended
1942
+
1943
+
1944
+ var numServerMessages = this._sock.rQshift16();
1945
+
1946
+ var numClientMessages = this._sock.rQshift16();
1947
+
1948
+ var numEncodings = this._sock.rQshift16();
1949
+
1950
+ this._sock.rQskipBytes(2); // padding
1951
+
1952
+
1953
+ var totalMessagesLength = (numServerMessages + numClientMessages + numEncodings) * 16;
1954
+
1955
+ if (this._sock.rQwait('TightVNC extended server init header', totalMessagesLength, 32 + nameLength)) {
1956
+ return false;
1957
+ } // we don't actually do anything with the capability information that TIGHT sends,
1958
+ // so we just skip the all of this.
1959
+ // TIGHT server message capabilities
1960
+
1961
+
1962
+ this._sock.rQskipBytes(16 * numServerMessages); // TIGHT client message capabilities
1963
+
1964
+
1965
+ this._sock.rQskipBytes(16 * numClientMessages); // TIGHT encoding capabilities
1966
+
1967
+
1968
+ this._sock.rQskipBytes(16 * numEncodings);
1969
+ } // NB(directxman12): these are down here so that we don't run them multiple times
1970
+ // if we backtrack
1971
+
1972
+
1973
+ Log.Info("Screen: " + width + "x" + height + ", bpp: " + bpp + ", depth: " + depth + ", bigEndian: " + bigEndian + ", trueColor: " + trueColor + ", redMax: " + redMax + ", greenMax: " + greenMax + ", blueMax: " + blueMax + ", redShift: " + redShift + ", greenShift: " + greenShift + ", blueShift: " + blueShift); // we're past the point where we could backtrack, so it's safe to call this
1974
+
1975
+ this._setDesktopName(name);
1976
+
1977
+ this._resize(width, height);
1978
+
1979
+ if (!this._viewOnly) {
1980
+ this._keyboard.grab();
1981
+ }
1982
+
1983
+ this._fbDepth = 24;
1984
+
1985
+ if (this._fbName === "Intel(r) AMT KVM") {
1986
+ Log.Warn("Intel AMT KVM only supports 8/16 bit depths. Using low color mode.");
1987
+ this._fbDepth = 8;
1988
+ }
1989
+
1990
+ RFB.messages.pixelFormat(this._sock, this._fbDepth, true);
1991
+
1992
+ this._sendEncodings();
1993
+
1994
+ RFB.messages.fbUpdateRequest(this._sock, false, 0, 0, this._fbWidth, this._fbHeight);
1995
+
1996
+ this._updateConnectionState('connected');
1997
+
1998
+ return true;
1999
+ }
2000
+ }, {
2001
+ key: "_sendEncodings",
2002
+ value: function _sendEncodings() {
2003
+ var encs = []; // In preference order
2004
+
2005
+ encs.push(_encodings.encodings.encodingCopyRect); // Only supported with full depth support
2006
+
2007
+ if (this._fbDepth == 24) {
2008
+ encs.push(_encodings.encodings.encodingTight);
2009
+ encs.push(_encodings.encodings.encodingTightPNG);
2010
+ encs.push(_encodings.encodings.encodingHextile);
2011
+ encs.push(_encodings.encodings.encodingRRE);
2012
+ }
2013
+
2014
+ encs.push(_encodings.encodings.encodingRaw); // Psuedo-encoding settings
2015
+
2016
+ encs.push(_encodings.encodings.pseudoEncodingQualityLevel0 + this._qualityLevel);
2017
+ encs.push(_encodings.encodings.pseudoEncodingCompressLevel0 + this._compressionLevel);
2018
+ encs.push(_encodings.encodings.pseudoEncodingDesktopSize);
2019
+ encs.push(_encodings.encodings.pseudoEncodingLastRect);
2020
+ encs.push(_encodings.encodings.pseudoEncodingQEMUExtendedKeyEvent);
2021
+ encs.push(_encodings.encodings.pseudoEncodingExtendedDesktopSize);
2022
+ encs.push(_encodings.encodings.pseudoEncodingXvp);
2023
+ encs.push(_encodings.encodings.pseudoEncodingFence);
2024
+ encs.push(_encodings.encodings.pseudoEncodingContinuousUpdates);
2025
+ encs.push(_encodings.encodings.pseudoEncodingDesktopName);
2026
+ encs.push(_encodings.encodings.pseudoEncodingExtendedClipboard);
2027
+
2028
+ if (this._fbDepth == 24) {
2029
+ encs.push(_encodings.encodings.pseudoEncodingVMwareCursor);
2030
+ encs.push(_encodings.encodings.pseudoEncodingCursor);
2031
+ }
2032
+
2033
+ RFB.messages.clientEncodings(this._sock, encs);
2034
+ }
2035
+ /* RFB protocol initialization states:
2036
+ * ProtocolVersion
2037
+ * Security
2038
+ * Authentication
2039
+ * SecurityResult
2040
+ * ClientInitialization - not triggered by server message
2041
+ * ServerInitialization
2042
+ */
2043
+
2044
+ }, {
2045
+ key: "_initMsg",
2046
+ value: function _initMsg() {
2047
+ switch (this._rfbInitState) {
2048
+ case 'ProtocolVersion':
2049
+ return this._negotiateProtocolVersion();
2050
+
2051
+ case 'Security':
2052
+ return this._negotiateSecurity();
2053
+
2054
+ case 'Authentication':
2055
+ return this._negotiateAuthentication();
2056
+
2057
+ case 'SecurityResult':
2058
+ return this._handleSecurityResult();
2059
+
2060
+ case 'SecurityReason':
2061
+ return this._handleSecurityReason();
2062
+
2063
+ case 'ClientInitialisation':
2064
+ this._sock.send([this._shared ? 1 : 0]); // ClientInitialisation
2065
+
2066
+
2067
+ this._rfbInitState = 'ServerInitialisation';
2068
+ return true;
2069
+
2070
+ case 'ServerInitialisation':
2071
+ return this._negotiateServerInit();
2072
+
2073
+ default:
2074
+ return this._fail("Unknown init state (state: " + this._rfbInitState + ")");
2075
+ }
2076
+ }
2077
+ }, {
2078
+ key: "_handleSetColourMapMsg",
2079
+ value: function _handleSetColourMapMsg() {
2080
+ Log.Debug("SetColorMapEntries");
2081
+ return this._fail("Unexpected SetColorMapEntries message");
2082
+ }
2083
+ }, {
2084
+ key: "_handleServerCutText",
2085
+ value: function _handleServerCutText() {
2086
+ Log.Debug("ServerCutText");
2087
+
2088
+ if (this._sock.rQwait("ServerCutText header", 7, 1)) {
2089
+ return false;
2090
+ }
2091
+
2092
+ this._sock.rQskipBytes(3); // Padding
2093
+
2094
+
2095
+ var length = this._sock.rQshift32();
2096
+
2097
+ length = (0, _int.toSigned32bit)(length);
2098
+
2099
+ if (this._sock.rQwait("ServerCutText content", Math.abs(length), 8)) {
2100
+ return false;
2101
+ }
2102
+
2103
+ if (length >= 0) {
2104
+ //Standard msg
2105
+ var text = this._sock.rQshiftStr(length);
2106
+
2107
+ if (this._viewOnly) {
2108
+ return true;
2109
+ }
2110
+
2111
+ this.dispatchEvent(new CustomEvent("clipboard", {
2112
+ detail: {
2113
+ text: text
2114
+ }
2115
+ }));
2116
+ } else {
2117
+ //Extended msg.
2118
+ length = Math.abs(length);
2119
+
2120
+ var flags = this._sock.rQshift32();
2121
+
2122
+ var formats = flags & 0x0000FFFF;
2123
+ var actions = flags & 0xFF000000;
2124
+ var isCaps = !!(actions & extendedClipboardActionCaps);
2125
+
2126
+ if (isCaps) {
2127
+ this._clipboardServerCapabilitiesFormats = {};
2128
+ this._clipboardServerCapabilitiesActions = {}; // Update our server capabilities for Formats
2129
+
2130
+ for (var i = 0; i <= 15; i++) {
2131
+ var index = 1 << i; // Check if format flag is set.
2132
+
2133
+ if (formats & index) {
2134
+ this._clipboardServerCapabilitiesFormats[index] = true; // We don't send unsolicited clipboard, so we
2135
+ // ignore the size
2136
+
2137
+ this._sock.rQshift32();
2138
+ }
2139
+ } // Update our server capabilities for Actions
2140
+
2141
+
2142
+ for (var _i = 24; _i <= 31; _i++) {
2143
+ var _index = 1 << _i;
2144
+
2145
+ this._clipboardServerCapabilitiesActions[_index] = !!(actions & _index);
2146
+ }
2147
+ /* Caps handling done, send caps with the clients
2148
+ capabilities set as a response */
2149
+
2150
+
2151
+ var clientActions = [extendedClipboardActionCaps, extendedClipboardActionRequest, extendedClipboardActionPeek, extendedClipboardActionNotify, extendedClipboardActionProvide];
2152
+ RFB.messages.extendedClipboardCaps(this._sock, clientActions, {
2153
+ extendedClipboardFormatText: 0
2154
+ });
2155
+ } else if (actions === extendedClipboardActionRequest) {
2156
+ if (this._viewOnly) {
2157
+ return true;
2158
+ } // Check if server has told us it can handle Provide and there is clipboard data to send.
2159
+
2160
+
2161
+ if (this._clipboardText != null && this._clipboardServerCapabilitiesActions[extendedClipboardActionProvide]) {
2162
+ if (formats & extendedClipboardFormatText) {
2163
+ RFB.messages.extendedClipboardProvide(this._sock, [extendedClipboardFormatText], [this._clipboardText]);
2164
+ }
2165
+ }
2166
+ } else if (actions === extendedClipboardActionPeek) {
2167
+ if (this._viewOnly) {
2168
+ return true;
2169
+ }
2170
+
2171
+ if (this._clipboardServerCapabilitiesActions[extendedClipboardActionNotify]) {
2172
+ if (this._clipboardText != null) {
2173
+ RFB.messages.extendedClipboardNotify(this._sock, [extendedClipboardFormatText]);
2174
+ } else {
2175
+ RFB.messages.extendedClipboardNotify(this._sock, []);
2176
+ }
2177
+ }
2178
+ } else if (actions === extendedClipboardActionNotify) {
2179
+ if (this._viewOnly) {
2180
+ return true;
2181
+ }
2182
+
2183
+ if (this._clipboardServerCapabilitiesActions[extendedClipboardActionRequest]) {
2184
+ if (formats & extendedClipboardFormatText) {
2185
+ RFB.messages.extendedClipboardRequest(this._sock, [extendedClipboardFormatText]);
2186
+ }
2187
+ }
2188
+ } else if (actions === extendedClipboardActionProvide) {
2189
+ if (this._viewOnly) {
2190
+ return true;
2191
+ }
2192
+
2193
+ if (!(formats & extendedClipboardFormatText)) {
2194
+ return true;
2195
+ } // Ignore what we had in our clipboard client side.
2196
+
2197
+
2198
+ this._clipboardText = null; // FIXME: Should probably verify that this data was actually requested
2199
+
2200
+ var zlibStream = this._sock.rQshiftBytes(length - 4);
2201
+
2202
+ var streamInflator = new _inflator.default();
2203
+ var textData = null;
2204
+ streamInflator.setInput(zlibStream);
2205
+
2206
+ for (var _i2 = 0; _i2 <= 15; _i2++) {
2207
+ var format = 1 << _i2;
2208
+
2209
+ if (formats & format) {
2210
+ var size = 0x00;
2211
+ var sizeArray = streamInflator.inflate(4);
2212
+ size |= sizeArray[0] << 24;
2213
+ size |= sizeArray[1] << 16;
2214
+ size |= sizeArray[2] << 8;
2215
+ size |= sizeArray[3];
2216
+ var chunk = streamInflator.inflate(size);
2217
+
2218
+ if (format === extendedClipboardFormatText) {
2219
+ textData = chunk;
2220
+ }
2221
+ }
2222
+ }
2223
+
2224
+ streamInflator.setInput(null);
2225
+
2226
+ if (textData !== null) {
2227
+ var tmpText = "";
2228
+
2229
+ for (var _i3 = 0; _i3 < textData.length; _i3++) {
2230
+ tmpText += String.fromCharCode(textData[_i3]);
2231
+ }
2232
+
2233
+ textData = tmpText;
2234
+ textData = (0, _strings.decodeUTF8)(textData);
2235
+
2236
+ if (textData.length > 0 && "\0" === textData.charAt(textData.length - 1)) {
2237
+ textData = textData.slice(0, -1);
2238
+ }
2239
+
2240
+ textData = textData.replace("\r\n", "\n");
2241
+ this.dispatchEvent(new CustomEvent("clipboard", {
2242
+ detail: {
2243
+ text: textData
2244
+ }
2245
+ }));
2246
+ }
2247
+ } else {
2248
+ return this._fail("Unexpected action in extended clipboard message: " + actions);
2249
+ }
2250
+ }
2251
+
2252
+ return true;
2253
+ }
2254
+ }, {
2255
+ key: "_handleServerFenceMsg",
2256
+ value: function _handleServerFenceMsg() {
2257
+ if (this._sock.rQwait("ServerFence header", 8, 1)) {
2258
+ return false;
2259
+ }
2260
+
2261
+ this._sock.rQskipBytes(3); // Padding
2262
+
2263
+
2264
+ var flags = this._sock.rQshift32();
2265
+
2266
+ var length = this._sock.rQshift8();
2267
+
2268
+ if (this._sock.rQwait("ServerFence payload", length, 9)) {
2269
+ return false;
2270
+ }
2271
+
2272
+ if (length > 64) {
2273
+ Log.Warn("Bad payload length (" + length + ") in fence response");
2274
+ length = 64;
2275
+ }
2276
+
2277
+ var payload = this._sock.rQshiftStr(length);
2278
+
2279
+ this._supportsFence = true;
2280
+ /*
2281
+ * Fence flags
2282
+ *
2283
+ * (1<<0) - BlockBefore
2284
+ * (1<<1) - BlockAfter
2285
+ * (1<<2) - SyncNext
2286
+ * (1<<31) - Request
2287
+ */
2288
+
2289
+ if (!(flags & 1 << 31)) {
2290
+ return this._fail("Unexpected fence response");
2291
+ } // Filter out unsupported flags
2292
+ // FIXME: support syncNext
2293
+
2294
+
2295
+ flags &= 1 << 0 | 1 << 1; // BlockBefore and BlockAfter are automatically handled by
2296
+ // the fact that we process each incoming message
2297
+ // synchronuosly.
2298
+
2299
+ RFB.messages.clientFence(this._sock, flags, payload);
2300
+ return true;
2301
+ }
2302
+ }, {
2303
+ key: "_handleXvpMsg",
2304
+ value: function _handleXvpMsg() {
2305
+ if (this._sock.rQwait("XVP version and message", 3, 1)) {
2306
+ return false;
2307
+ }
2308
+
2309
+ this._sock.rQskipBytes(1); // Padding
2310
+
2311
+
2312
+ var xvpVer = this._sock.rQshift8();
2313
+
2314
+ var xvpMsg = this._sock.rQshift8();
2315
+
2316
+ switch (xvpMsg) {
2317
+ case 0:
2318
+ // XVP_FAIL
2319
+ Log.Error("XVP Operation Failed");
2320
+ break;
2321
+
2322
+ case 1:
2323
+ // XVP_INIT
2324
+ this._rfbXvpVer = xvpVer;
2325
+ Log.Info("XVP extensions enabled (version " + this._rfbXvpVer + ")");
2326
+
2327
+ this._setCapability("power", true);
2328
+
2329
+ break;
2330
+
2331
+ default:
2332
+ this._fail("Illegal server XVP message (msg: " + xvpMsg + ")");
2333
+
2334
+ break;
2335
+ }
2336
+
2337
+ return true;
2338
+ }
2339
+ }, {
2340
+ key: "_normalMsg",
2341
+ value: function _normalMsg() {
2342
+ var msgType;
2343
+
2344
+ if (this._FBU.rects > 0) {
2345
+ msgType = 0;
2346
+ } else {
2347
+ msgType = this._sock.rQshift8();
2348
+ }
2349
+
2350
+ var first, ret;
2351
+
2352
+ switch (msgType) {
2353
+ case 0:
2354
+ // FramebufferUpdate
2355
+ ret = this._framebufferUpdate();
2356
+
2357
+ if (ret && !this._enabledContinuousUpdates) {
2358
+ RFB.messages.fbUpdateRequest(this._sock, true, 0, 0, this._fbWidth, this._fbHeight);
2359
+ }
2360
+
2361
+ return ret;
2362
+
2363
+ case 1:
2364
+ // SetColorMapEntries
2365
+ return this._handleSetColourMapMsg();
2366
+
2367
+ case 2:
2368
+ // Bell
2369
+ Log.Debug("Bell");
2370
+ this.dispatchEvent(new CustomEvent("bell", {
2371
+ detail: {}
2372
+ }));
2373
+ return true;
2374
+
2375
+ case 3:
2376
+ // ServerCutText
2377
+ return this._handleServerCutText();
2378
+
2379
+ case 150:
2380
+ // EndOfContinuousUpdates
2381
+ first = !this._supportsContinuousUpdates;
2382
+ this._supportsContinuousUpdates = true;
2383
+ this._enabledContinuousUpdates = false;
2384
+
2385
+ if (first) {
2386
+ this._enabledContinuousUpdates = true;
2387
+
2388
+ this._updateContinuousUpdates();
2389
+
2390
+ Log.Info("Enabling continuous updates.");
2391
+ } else {// FIXME: We need to send a framebufferupdaterequest here
2392
+ // if we add support for turning off continuous updates
2393
+ }
2394
+
2395
+ return true;
2396
+
2397
+ case 248:
2398
+ // ServerFence
2399
+ return this._handleServerFenceMsg();
2400
+
2401
+ case 250:
2402
+ // XVP
2403
+ return this._handleXvpMsg();
2404
+
2405
+ default:
2406
+ this._fail("Unexpected server message (type " + msgType + ")");
2407
+
2408
+ Log.Debug("sock.rQslice(0, 30): " + this._sock.rQslice(0, 30));
2409
+ return true;
2410
+ }
2411
+ }
2412
+ }, {
2413
+ key: "_onFlush",
2414
+ value: function _onFlush() {
2415
+ this._flushing = false; // Resume processing
2416
+
2417
+ if (this._sock.rQlen > 0) {
2418
+ this._handleMessage();
2419
+ }
2420
+ }
2421
+ }, {
2422
+ key: "_framebufferUpdate",
2423
+ value: function _framebufferUpdate() {
2424
+ if (this._FBU.rects === 0) {
2425
+ if (this._sock.rQwait("FBU header", 3, 1)) {
2426
+ return false;
2427
+ }
2428
+
2429
+ this._sock.rQskipBytes(1); // Padding
2430
+
2431
+
2432
+ this._FBU.rects = this._sock.rQshift16(); // Make sure the previous frame is fully rendered first
2433
+ // to avoid building up an excessive queue
2434
+
2435
+ if (this._display.pending()) {
2436
+ this._flushing = true;
2437
+
2438
+ this._display.flush();
2439
+
2440
+ return false;
2441
+ }
2442
+ }
2443
+
2444
+ while (this._FBU.rects > 0) {
2445
+ if (this._FBU.encoding === null) {
2446
+ if (this._sock.rQwait("rect header", 12)) {
2447
+ return false;
2448
+ }
2449
+ /* New FramebufferUpdate */
2450
+
2451
+
2452
+ var hdr = this._sock.rQshiftBytes(12);
2453
+
2454
+ this._FBU.x = (hdr[0] << 8) + hdr[1];
2455
+ this._FBU.y = (hdr[2] << 8) + hdr[3];
2456
+ this._FBU.width = (hdr[4] << 8) + hdr[5];
2457
+ this._FBU.height = (hdr[6] << 8) + hdr[7];
2458
+ this._FBU.encoding = parseInt((hdr[8] << 24) + (hdr[9] << 16) + (hdr[10] << 8) + hdr[11], 10);
2459
+ }
2460
+
2461
+ if (!this._handleRect()) {
2462
+ return false;
2463
+ }
2464
+
2465
+ this._FBU.rects--;
2466
+ this._FBU.encoding = null;
2467
+ }
2468
+
2469
+ this._display.flip();
2470
+
2471
+ return true; // We finished this FBU
2472
+ }
2473
+ }, {
2474
+ key: "_handleRect",
2475
+ value: function _handleRect() {
2476
+ switch (this._FBU.encoding) {
2477
+ case _encodings.encodings.pseudoEncodingLastRect:
2478
+ this._FBU.rects = 1; // Will be decreased when we return
2479
+
2480
+ return true;
2481
+
2482
+ case _encodings.encodings.pseudoEncodingVMwareCursor:
2483
+ return this._handleVMwareCursor();
2484
+
2485
+ case _encodings.encodings.pseudoEncodingCursor:
2486
+ return this._handleCursor();
2487
+
2488
+ case _encodings.encodings.pseudoEncodingQEMUExtendedKeyEvent:
2489
+ // Old Safari doesn't support creating keyboard events
2490
+ try {
2491
+ var keyboardEvent = document.createEvent("keyboardEvent");
2492
+
2493
+ if (keyboardEvent.code !== undefined) {
2494
+ this._qemuExtKeyEventSupported = true;
2495
+ }
2496
+ } catch (err) {// Do nothing
2497
+ }
2498
+
2499
+ return true;
2500
+
2501
+ case _encodings.encodings.pseudoEncodingDesktopName:
2502
+ return this._handleDesktopName();
2503
+
2504
+ case _encodings.encodings.pseudoEncodingDesktopSize:
2505
+ this._resize(this._FBU.width, this._FBU.height);
2506
+
2507
+ return true;
2508
+
2509
+ case _encodings.encodings.pseudoEncodingExtendedDesktopSize:
2510
+ return this._handleExtendedDesktopSize();
2511
+
2512
+ default:
2513
+ return this._handleDataRect();
2514
+ }
2515
+ }
2516
+ }, {
2517
+ key: "_handleVMwareCursor",
2518
+ value: function _handleVMwareCursor() {
2519
+ var hotx = this._FBU.x; // hotspot-x
2520
+
2521
+ var hoty = this._FBU.y; // hotspot-y
2522
+
2523
+ var w = this._FBU.width;
2524
+ var h = this._FBU.height;
2525
+
2526
+ if (this._sock.rQwait("VMware cursor encoding", 1)) {
2527
+ return false;
2528
+ }
2529
+
2530
+ var cursorType = this._sock.rQshift8();
2531
+
2532
+ this._sock.rQshift8(); //Padding
2533
+
2534
+
2535
+ var rgba;
2536
+ var bytesPerPixel = 4; //Classic cursor
2537
+
2538
+ if (cursorType == 0) {
2539
+ //Used to filter away unimportant bits.
2540
+ //OR is used for correct conversion in js.
2541
+ var PIXEL_MASK = 0xffffff00 | 0;
2542
+ rgba = new Array(w * h * bytesPerPixel);
2543
+
2544
+ if (this._sock.rQwait("VMware cursor classic encoding", w * h * bytesPerPixel * 2, 2)) {
2545
+ return false;
2546
+ }
2547
+
2548
+ var andMask = new Array(w * h);
2549
+
2550
+ for (var pixel = 0; pixel < w * h; pixel++) {
2551
+ andMask[pixel] = this._sock.rQshift32();
2552
+ }
2553
+
2554
+ var xorMask = new Array(w * h);
2555
+
2556
+ for (var _pixel = 0; _pixel < w * h; _pixel++) {
2557
+ xorMask[_pixel] = this._sock.rQshift32();
2558
+ }
2559
+
2560
+ for (var _pixel2 = 0; _pixel2 < w * h; _pixel2++) {
2561
+ if (andMask[_pixel2] == 0) {
2562
+ //Fully opaque pixel
2563
+ var bgr = xorMask[_pixel2];
2564
+ var r = bgr >> 8 & 0xff;
2565
+ var g = bgr >> 16 & 0xff;
2566
+ var b = bgr >> 24 & 0xff;
2567
+ rgba[_pixel2 * bytesPerPixel] = r; //r
2568
+
2569
+ rgba[_pixel2 * bytesPerPixel + 1] = g; //g
2570
+
2571
+ rgba[_pixel2 * bytesPerPixel + 2] = b; //b
2572
+
2573
+ rgba[_pixel2 * bytesPerPixel + 3] = 0xff; //a
2574
+ } else if ((andMask[_pixel2] & PIXEL_MASK) == PIXEL_MASK) {
2575
+ //Only screen value matters, no mouse colouring
2576
+ if (xorMask[_pixel2] == 0) {
2577
+ //Transparent pixel
2578
+ rgba[_pixel2 * bytesPerPixel] = 0x00;
2579
+ rgba[_pixel2 * bytesPerPixel + 1] = 0x00;
2580
+ rgba[_pixel2 * bytesPerPixel + 2] = 0x00;
2581
+ rgba[_pixel2 * bytesPerPixel + 3] = 0x00;
2582
+ } else if ((xorMask[_pixel2] & PIXEL_MASK) == PIXEL_MASK) {
2583
+ //Inverted pixel, not supported in browsers.
2584
+ //Fully opaque instead.
2585
+ rgba[_pixel2 * bytesPerPixel] = 0x00;
2586
+ rgba[_pixel2 * bytesPerPixel + 1] = 0x00;
2587
+ rgba[_pixel2 * bytesPerPixel + 2] = 0x00;
2588
+ rgba[_pixel2 * bytesPerPixel + 3] = 0xff;
2589
+ } else {
2590
+ //Unhandled xorMask
2591
+ rgba[_pixel2 * bytesPerPixel] = 0x00;
2592
+ rgba[_pixel2 * bytesPerPixel + 1] = 0x00;
2593
+ rgba[_pixel2 * bytesPerPixel + 2] = 0x00;
2594
+ rgba[_pixel2 * bytesPerPixel + 3] = 0xff;
2595
+ }
2596
+ } else {
2597
+ //Unhandled andMask
2598
+ rgba[_pixel2 * bytesPerPixel] = 0x00;
2599
+ rgba[_pixel2 * bytesPerPixel + 1] = 0x00;
2600
+ rgba[_pixel2 * bytesPerPixel + 2] = 0x00;
2601
+ rgba[_pixel2 * bytesPerPixel + 3] = 0xff;
2602
+ }
2603
+ } //Alpha cursor.
2604
+
2605
+ } else if (cursorType == 1) {
2606
+ if (this._sock.rQwait("VMware cursor alpha encoding", w * h * 4, 2)) {
2607
+ return false;
2608
+ }
2609
+
2610
+ rgba = new Array(w * h * bytesPerPixel);
2611
+
2612
+ for (var _pixel3 = 0; _pixel3 < w * h; _pixel3++) {
2613
+ var data = this._sock.rQshift32();
2614
+
2615
+ rgba[_pixel3 * 4] = data >> 24 & 0xff; //r
2616
+
2617
+ rgba[_pixel3 * 4 + 1] = data >> 16 & 0xff; //g
2618
+
2619
+ rgba[_pixel3 * 4 + 2] = data >> 8 & 0xff; //b
2620
+
2621
+ rgba[_pixel3 * 4 + 3] = data & 0xff; //a
2622
+ }
2623
+ } else {
2624
+ Log.Warn("The given cursor type is not supported: " + cursorType + " given.");
2625
+ return false;
2626
+ }
2627
+
2628
+ this._updateCursor(rgba, hotx, hoty, w, h);
2629
+
2630
+ return true;
2631
+ }
2632
+ }, {
2633
+ key: "_handleCursor",
2634
+ value: function _handleCursor() {
2635
+ var hotx = this._FBU.x; // hotspot-x
2636
+
2637
+ var hoty = this._FBU.y; // hotspot-y
2638
+
2639
+ var w = this._FBU.width;
2640
+ var h = this._FBU.height;
2641
+ var pixelslength = w * h * 4;
2642
+ var masklength = Math.ceil(w / 8) * h;
2643
+ var bytes = pixelslength + masklength;
2644
+
2645
+ if (this._sock.rQwait("cursor encoding", bytes)) {
2646
+ return false;
2647
+ } // Decode from BGRX pixels + bit mask to RGBA
2648
+
2649
+
2650
+ var pixels = this._sock.rQshiftBytes(pixelslength);
2651
+
2652
+ var mask = this._sock.rQshiftBytes(masklength);
2653
+
2654
+ var rgba = new Uint8Array(w * h * 4);
2655
+ var pixIdx = 0;
2656
+
2657
+ for (var y = 0; y < h; y++) {
2658
+ for (var x = 0; x < w; x++) {
2659
+ var maskIdx = y * Math.ceil(w / 8) + Math.floor(x / 8);
2660
+ var alpha = mask[maskIdx] << x % 8 & 0x80 ? 255 : 0;
2661
+ rgba[pixIdx] = pixels[pixIdx + 2];
2662
+ rgba[pixIdx + 1] = pixels[pixIdx + 1];
2663
+ rgba[pixIdx + 2] = pixels[pixIdx];
2664
+ rgba[pixIdx + 3] = alpha;
2665
+ pixIdx += 4;
2666
+ }
2667
+ }
2668
+
2669
+ this._updateCursor(rgba, hotx, hoty, w, h);
2670
+
2671
+ return true;
2672
+ }
2673
+ }, {
2674
+ key: "_handleDesktopName",
2675
+ value: function _handleDesktopName() {
2676
+ if (this._sock.rQwait("DesktopName", 4)) {
2677
+ return false;
2678
+ }
2679
+
2680
+ var length = this._sock.rQshift32();
2681
+
2682
+ if (this._sock.rQwait("DesktopName", length, 4)) {
2683
+ return false;
2684
+ }
2685
+
2686
+ var name = this._sock.rQshiftStr(length);
2687
+
2688
+ name = (0, _strings.decodeUTF8)(name, true);
2689
+
2690
+ this._setDesktopName(name);
2691
+
2692
+ return true;
2693
+ }
2694
+ }, {
2695
+ key: "_handleExtendedDesktopSize",
2696
+ value: function _handleExtendedDesktopSize() {
2697
+ if (this._sock.rQwait("ExtendedDesktopSize", 4)) {
2698
+ return false;
2699
+ }
2700
+
2701
+ var numberOfScreens = this._sock.rQpeek8();
2702
+
2703
+ var bytes = 4 + numberOfScreens * 16;
2704
+
2705
+ if (this._sock.rQwait("ExtendedDesktopSize", bytes)) {
2706
+ return false;
2707
+ }
2708
+
2709
+ var firstUpdate = !this._supportsSetDesktopSize;
2710
+ this._supportsSetDesktopSize = true; // Normally we only apply the current resize mode after a
2711
+ // window resize event. However there is no such trigger on the
2712
+ // initial connect. And we don't know if the server supports
2713
+ // resizing until we've gotten here.
2714
+
2715
+ if (firstUpdate) {
2716
+ this._requestRemoteResize();
2717
+ }
2718
+
2719
+ this._sock.rQskipBytes(1); // number-of-screens
2720
+
2721
+
2722
+ this._sock.rQskipBytes(3); // padding
2723
+
2724
+
2725
+ for (var i = 0; i < numberOfScreens; i += 1) {
2726
+ // Save the id and flags of the first screen
2727
+ if (i === 0) {
2728
+ this._screenID = this._sock.rQshiftBytes(4); // id
2729
+
2730
+ this._sock.rQskipBytes(2); // x-position
2731
+
2732
+
2733
+ this._sock.rQskipBytes(2); // y-position
2734
+
2735
+
2736
+ this._sock.rQskipBytes(2); // width
2737
+
2738
+
2739
+ this._sock.rQskipBytes(2); // height
2740
+
2741
+
2742
+ this._screenFlags = this._sock.rQshiftBytes(4); // flags
2743
+ } else {
2744
+ this._sock.rQskipBytes(16);
2745
+ }
2746
+ }
2747
+ /*
2748
+ * The x-position indicates the reason for the change:
2749
+ *
2750
+ * 0 - server resized on its own
2751
+ * 1 - this client requested the resize
2752
+ * 2 - another client requested the resize
2753
+ */
2754
+ // We need to handle errors when we requested the resize.
2755
+
2756
+
2757
+ if (this._FBU.x === 1 && this._FBU.y !== 0) {
2758
+ var msg = ""; // The y-position indicates the status code from the server
2759
+
2760
+ switch (this._FBU.y) {
2761
+ case 1:
2762
+ msg = "Resize is administratively prohibited";
2763
+ break;
2764
+
2765
+ case 2:
2766
+ msg = "Out of resources";
2767
+ break;
2768
+
2769
+ case 3:
2770
+ msg = "Invalid screen layout";
2771
+ break;
2772
+
2773
+ default:
2774
+ msg = "Unknown reason";
2775
+ break;
2776
+ }
2777
+
2778
+ Log.Warn("Server did not accept the resize request: " + msg);
2779
+ } else {
2780
+ this._resize(this._FBU.width, this._FBU.height);
2781
+ }
2782
+
2783
+ return true;
2784
+ }
2785
+ }, {
2786
+ key: "_handleDataRect",
2787
+ value: function _handleDataRect() {
2788
+ var decoder = this._decoders[this._FBU.encoding];
2789
+
2790
+ if (!decoder) {
2791
+ this._fail("Unsupported encoding (encoding: " + this._FBU.encoding + ")");
2792
+
2793
+ return false;
2794
+ }
2795
+
2796
+ try {
2797
+ return decoder.decodeRect(this._FBU.x, this._FBU.y, this._FBU.width, this._FBU.height, this._sock, this._display, this._fbDepth);
2798
+ } catch (err) {
2799
+ this._fail("Error decoding rect: " + err);
2800
+
2801
+ return false;
2802
+ }
2803
+ }
2804
+ }, {
2805
+ key: "_updateContinuousUpdates",
2806
+ value: function _updateContinuousUpdates() {
2807
+ if (!this._enabledContinuousUpdates) {
2808
+ return;
2809
+ }
2810
+
2811
+ RFB.messages.enableContinuousUpdates(this._sock, true, 0, 0, this._fbWidth, this._fbHeight);
2812
+ }
2813
+ }, {
2814
+ key: "_resize",
2815
+ value: function _resize(width, height) {
2816
+ this._fbWidth = width;
2817
+ this._fbHeight = height;
2818
+
2819
+ this._display.resize(this._fbWidth, this._fbHeight); // Adjust the visible viewport based on the new dimensions
2820
+
2821
+
2822
+ this._updateClip();
2823
+
2824
+ this._updateScale();
2825
+
2826
+ this._updateContinuousUpdates();
2827
+ }
2828
+ }, {
2829
+ key: "_xvpOp",
2830
+ value: function _xvpOp(ver, op) {
2831
+ if (this._rfbXvpVer < ver) {
2832
+ return;
2833
+ }
2834
+
2835
+ Log.Info("Sending XVP operation " + op + " (version " + ver + ")");
2836
+ RFB.messages.xvpOp(this._sock, ver, op);
2837
+ }
2838
+ }, {
2839
+ key: "_updateCursor",
2840
+ value: function _updateCursor(rgba, hotx, hoty, w, h) {
2841
+ this._cursorImage = {
2842
+ rgbaPixels: rgba,
2843
+ hotx: hotx,
2844
+ hoty: hoty,
2845
+ w: w,
2846
+ h: h
2847
+ };
2848
+
2849
+ this._refreshCursor();
2850
+ }
2851
+ }, {
2852
+ key: "_shouldShowDotCursor",
2853
+ value: function _shouldShowDotCursor() {
2854
+ // Called when this._cursorImage is updated
2855
+ if (!this._showDotCursor) {
2856
+ // User does not want to see the dot, so...
2857
+ return false;
2858
+ } // The dot should not be shown if the cursor is already visible,
2859
+ // i.e. contains at least one not-fully-transparent pixel.
2860
+ // So iterate through all alpha bytes in rgba and stop at the
2861
+ // first non-zero.
2862
+
2863
+
2864
+ for (var i = 3; i < this._cursorImage.rgbaPixels.length; i += 4) {
2865
+ if (this._cursorImage.rgbaPixels[i]) {
2866
+ return false;
2867
+ }
2868
+ } // At this point, we know that the cursor is fully transparent, and
2869
+ // the user wants to see the dot instead of this.
2870
+
2871
+
2872
+ return true;
2873
+ }
2874
+ }, {
2875
+ key: "_refreshCursor",
2876
+ value: function _refreshCursor() {
2877
+ if (this._rfbConnectionState !== "connecting" && this._rfbConnectionState !== "connected") {
2878
+ return;
2879
+ }
2880
+
2881
+ var image = this._shouldShowDotCursor() ? RFB.cursors.dot : this._cursorImage;
2882
+
2883
+ this._cursor.change(image.rgbaPixels, image.hotx, image.hoty, image.w, image.h);
2884
+ }
2885
+ }, {
2886
+ key: "viewOnly",
2887
+ get: function get() {
2888
+ return this._viewOnly;
2889
+ },
2890
+ set: function set(viewOnly) {
2891
+ this._viewOnly = viewOnly;
2892
+
2893
+ if (this._rfbConnectionState === "connecting" || this._rfbConnectionState === "connected") {
2894
+ if (viewOnly) {
2895
+ this._keyboard.ungrab();
2896
+ } else {
2897
+ this._keyboard.grab();
2898
+ }
2899
+ }
2900
+ }
2901
+ }, {
2902
+ key: "capabilities",
2903
+ get: function get() {
2904
+ return this._capabilities;
2905
+ }
2906
+ }, {
2907
+ key: "touchButton",
2908
+ get: function get() {
2909
+ return 0;
2910
+ },
2911
+ set: function set(button) {
2912
+ Log.Warn("Using old API!");
2913
+ }
2914
+ }, {
2915
+ key: "clipViewport",
2916
+ get: function get() {
2917
+ return this._clipViewport;
2918
+ },
2919
+ set: function set(viewport) {
2920
+ this._clipViewport = viewport;
2921
+
2922
+ this._updateClip();
2923
+ }
2924
+ }, {
2925
+ key: "scaleViewport",
2926
+ get: function get() {
2927
+ return this._scaleViewport;
2928
+ },
2929
+ set: function set(scale) {
2930
+ this._scaleViewport = scale; // Scaling trumps clipping, so we may need to adjust
2931
+ // clipping when enabling or disabling scaling
2932
+
2933
+ if (scale && this._clipViewport) {
2934
+ this._updateClip();
2935
+ }
2936
+
2937
+ this._updateScale();
2938
+
2939
+ if (!scale && this._clipViewport) {
2940
+ this._updateClip();
2941
+ }
2942
+ }
2943
+ }, {
2944
+ key: "resizeSession",
2945
+ get: function get() {
2946
+ return this._resizeSession;
2947
+ },
2948
+ set: function set(resize) {
2949
+ this._resizeSession = resize;
2950
+
2951
+ if (resize) {
2952
+ this._requestRemoteResize();
2953
+ }
2954
+ }
2955
+ }, {
2956
+ key: "showDotCursor",
2957
+ get: function get() {
2958
+ return this._showDotCursor;
2959
+ },
2960
+ set: function set(show) {
2961
+ this._showDotCursor = show;
2962
+
2963
+ this._refreshCursor();
2964
+ }
2965
+ }, {
2966
+ key: "background",
2967
+ get: function get() {
2968
+ return this._screen.style.background;
2969
+ },
2970
+ set: function set(cssValue) {
2971
+ this._screen.style.background = cssValue;
2972
+ }
2973
+ }, {
2974
+ key: "qualityLevel",
2975
+ get: function get() {
2976
+ return this._qualityLevel;
2977
+ },
2978
+ set: function set(qualityLevel) {
2979
+ if (!Number.isInteger(qualityLevel) || qualityLevel < 0 || qualityLevel > 9) {
2980
+ Log.Error("qualityLevel must be an integer between 0 and 9");
2981
+ return;
2982
+ }
2983
+
2984
+ if (this._qualityLevel === qualityLevel) {
2985
+ return;
2986
+ }
2987
+
2988
+ this._qualityLevel = qualityLevel;
2989
+
2990
+ if (this._rfbConnectionState === 'connected') {
2991
+ this._sendEncodings();
2992
+ }
2993
+ }
2994
+ }, {
2995
+ key: "compressionLevel",
2996
+ get: function get() {
2997
+ return this._compressionLevel;
2998
+ },
2999
+ set: function set(compressionLevel) {
3000
+ if (!Number.isInteger(compressionLevel) || compressionLevel < 0 || compressionLevel > 9) {
3001
+ Log.Error("compressionLevel must be an integer between 0 and 9");
3002
+ return;
3003
+ }
3004
+
3005
+ if (this._compressionLevel === compressionLevel) {
3006
+ return;
3007
+ }
3008
+
3009
+ this._compressionLevel = compressionLevel;
3010
+
3011
+ if (this._rfbConnectionState === 'connected') {
3012
+ this._sendEncodings();
3013
+ }
3014
+ }
3015
+ }], [{
3016
+ key: "genDES",
3017
+ value: function genDES(password, challenge) {
3018
+ var passwordChars = password.split('').map(function (c) {
3019
+ return c.charCodeAt(0);
3020
+ });
3021
+ return new _des.default(passwordChars).encrypt(challenge);
3022
+ }
3023
+ }]);
3024
+
3025
+ return RFB;
3026
+ }(_eventtarget.default); // Class Methods
3027
+
3028
+
3029
+ exports.default = RFB;
3030
+ RFB.messages = {
3031
+ keyEvent: function keyEvent(sock, keysym, down) {
3032
+ var buff = sock._sQ;
3033
+ var offset = sock._sQlen;
3034
+ buff[offset] = 4; // msg-type
3035
+
3036
+ buff[offset + 1] = down;
3037
+ buff[offset + 2] = 0;
3038
+ buff[offset + 3] = 0;
3039
+ buff[offset + 4] = keysym >> 24;
3040
+ buff[offset + 5] = keysym >> 16;
3041
+ buff[offset + 6] = keysym >> 8;
3042
+ buff[offset + 7] = keysym;
3043
+ sock._sQlen += 8;
3044
+ sock.flush();
3045
+ },
3046
+ QEMUExtendedKeyEvent: function QEMUExtendedKeyEvent(sock, keysym, down, keycode) {
3047
+ function getRFBkeycode(xtScanCode) {
3048
+ var upperByte = keycode >> 8;
3049
+ var lowerByte = keycode & 0x00ff;
3050
+
3051
+ if (upperByte === 0xe0 && lowerByte < 0x7f) {
3052
+ return lowerByte | 0x80;
3053
+ }
3054
+
3055
+ return xtScanCode;
3056
+ }
3057
+
3058
+ var buff = sock._sQ;
3059
+ var offset = sock._sQlen;
3060
+ buff[offset] = 255; // msg-type
3061
+
3062
+ buff[offset + 1] = 0; // sub msg-type
3063
+
3064
+ buff[offset + 2] = down >> 8;
3065
+ buff[offset + 3] = down;
3066
+ buff[offset + 4] = keysym >> 24;
3067
+ buff[offset + 5] = keysym >> 16;
3068
+ buff[offset + 6] = keysym >> 8;
3069
+ buff[offset + 7] = keysym;
3070
+ var RFBkeycode = getRFBkeycode(keycode);
3071
+ buff[offset + 8] = RFBkeycode >> 24;
3072
+ buff[offset + 9] = RFBkeycode >> 16;
3073
+ buff[offset + 10] = RFBkeycode >> 8;
3074
+ buff[offset + 11] = RFBkeycode;
3075
+ sock._sQlen += 12;
3076
+ sock.flush();
3077
+ },
3078
+ pointerEvent: function pointerEvent(sock, x, y, mask) {
3079
+ var buff = sock._sQ;
3080
+ var offset = sock._sQlen;
3081
+ buff[offset] = 5; // msg-type
3082
+
3083
+ buff[offset + 1] = mask;
3084
+ buff[offset + 2] = x >> 8;
3085
+ buff[offset + 3] = x;
3086
+ buff[offset + 4] = y >> 8;
3087
+ buff[offset + 5] = y;
3088
+ sock._sQlen += 6;
3089
+ sock.flush();
3090
+ },
3091
+ // Used to build Notify and Request data.
3092
+ _buildExtendedClipboardFlags: function _buildExtendedClipboardFlags(actions, formats) {
3093
+ var data = new Uint8Array(4);
3094
+ var formatFlag = 0x00000000;
3095
+ var actionFlag = 0x00000000;
3096
+
3097
+ for (var i = 0; i < actions.length; i++) {
3098
+ actionFlag |= actions[i];
3099
+ }
3100
+
3101
+ for (var _i4 = 0; _i4 < formats.length; _i4++) {
3102
+ formatFlag |= formats[_i4];
3103
+ }
3104
+
3105
+ data[0] = actionFlag >> 24; // Actions
3106
+
3107
+ data[1] = 0x00; // Reserved
3108
+
3109
+ data[2] = 0x00; // Reserved
3110
+
3111
+ data[3] = formatFlag; // Formats
3112
+
3113
+ return data;
3114
+ },
3115
+ extendedClipboardProvide: function extendedClipboardProvide(sock, formats, inData) {
3116
+ // Deflate incomming data and their sizes
3117
+ var deflator = new _deflator.default();
3118
+ var dataToDeflate = [];
3119
+
3120
+ for (var i = 0; i < formats.length; i++) {
3121
+ // We only support the format Text at this time
3122
+ if (formats[i] != extendedClipboardFormatText) {
3123
+ throw new Error("Unsupported extended clipboard format for Provide message.");
3124
+ } // Change lone \r or \n into \r\n as defined in rfbproto
3125
+
3126
+
3127
+ inData[i] = inData[i].replace(/\r\n|\r|\n/gm, "\r\n"); // Check if it already has \0
3128
+
3129
+ var text = (0, _strings.encodeUTF8)(inData[i] + "\0");
3130
+ dataToDeflate.push(text.length >> 24 & 0xFF, text.length >> 16 & 0xFF, text.length >> 8 & 0xFF, text.length & 0xFF);
3131
+
3132
+ for (var j = 0; j < text.length; j++) {
3133
+ dataToDeflate.push(text.charCodeAt(j));
3134
+ }
3135
+ }
3136
+
3137
+ var deflatedData = deflator.deflate(new Uint8Array(dataToDeflate)); // Build data to send
3138
+
3139
+ var data = new Uint8Array(4 + deflatedData.length);
3140
+ data.set(RFB.messages._buildExtendedClipboardFlags([extendedClipboardActionProvide], formats));
3141
+ data.set(deflatedData, 4);
3142
+ RFB.messages.clientCutText(sock, data, true);
3143
+ },
3144
+ extendedClipboardNotify: function extendedClipboardNotify(sock, formats) {
3145
+ var flags = RFB.messages._buildExtendedClipboardFlags([extendedClipboardActionNotify], formats);
3146
+
3147
+ RFB.messages.clientCutText(sock, flags, true);
3148
+ },
3149
+ extendedClipboardRequest: function extendedClipboardRequest(sock, formats) {
3150
+ var flags = RFB.messages._buildExtendedClipboardFlags([extendedClipboardActionRequest], formats);
3151
+
3152
+ RFB.messages.clientCutText(sock, flags, true);
3153
+ },
3154
+ extendedClipboardCaps: function extendedClipboardCaps(sock, actions, formats) {
3155
+ var formatKeys = Object.keys(formats);
3156
+ var data = new Uint8Array(4 + 4 * formatKeys.length);
3157
+ formatKeys.map(function (x) {
3158
+ return parseInt(x);
3159
+ });
3160
+ formatKeys.sort(function (a, b) {
3161
+ return a - b;
3162
+ });
3163
+ data.set(RFB.messages._buildExtendedClipboardFlags(actions, []));
3164
+ var loopOffset = 4;
3165
+
3166
+ for (var i = 0; i < formatKeys.length; i++) {
3167
+ data[loopOffset] = formats[formatKeys[i]] >> 24;
3168
+ data[loopOffset + 1] = formats[formatKeys[i]] >> 16;
3169
+ data[loopOffset + 2] = formats[formatKeys[i]] >> 8;
3170
+ data[loopOffset + 3] = formats[formatKeys[i]] >> 0;
3171
+ loopOffset += 4;
3172
+ data[3] |= 1 << formatKeys[i]; // Update our format flags
3173
+ }
3174
+
3175
+ RFB.messages.clientCutText(sock, data, true);
3176
+ },
3177
+ clientCutText: function clientCutText(sock, data) {
3178
+ var extended = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
3179
+ var buff = sock._sQ;
3180
+ var offset = sock._sQlen;
3181
+ buff[offset] = 6; // msg-type
3182
+
3183
+ buff[offset + 1] = 0; // padding
3184
+
3185
+ buff[offset + 2] = 0; // padding
3186
+
3187
+ buff[offset + 3] = 0; // padding
3188
+
3189
+ var length;
3190
+
3191
+ if (extended) {
3192
+ length = (0, _int.toUnsigned32bit)(-data.length);
3193
+ } else {
3194
+ length = data.length;
3195
+ }
3196
+
3197
+ buff[offset + 4] = length >> 24;
3198
+ buff[offset + 5] = length >> 16;
3199
+ buff[offset + 6] = length >> 8;
3200
+ buff[offset + 7] = length;
3201
+ sock._sQlen += 8; // We have to keep track of from where in the data we begin creating the
3202
+ // buffer for the flush in the next iteration.
3203
+
3204
+ var dataOffset = 0;
3205
+ var remaining = data.length;
3206
+
3207
+ while (remaining > 0) {
3208
+ var flushSize = Math.min(remaining, sock._sQbufferSize - sock._sQlen);
3209
+
3210
+ for (var i = 0; i < flushSize; i++) {
3211
+ buff[sock._sQlen + i] = data[dataOffset + i];
3212
+ }
3213
+
3214
+ sock._sQlen += flushSize;
3215
+ sock.flush();
3216
+ remaining -= flushSize;
3217
+ dataOffset += flushSize;
3218
+ }
3219
+ },
3220
+ setDesktopSize: function setDesktopSize(sock, width, height, id, flags) {
3221
+ var buff = sock._sQ;
3222
+ var offset = sock._sQlen;
3223
+ buff[offset] = 251; // msg-type
3224
+
3225
+ buff[offset + 1] = 0; // padding
3226
+
3227
+ buff[offset + 2] = width >> 8; // width
3228
+
3229
+ buff[offset + 3] = width;
3230
+ buff[offset + 4] = height >> 8; // height
3231
+
3232
+ buff[offset + 5] = height;
3233
+ buff[offset + 6] = 1; // number-of-screens
3234
+
3235
+ buff[offset + 7] = 0; // padding
3236
+ // screen array
3237
+
3238
+ buff[offset + 8] = id >> 24; // id
3239
+
3240
+ buff[offset + 9] = id >> 16;
3241
+ buff[offset + 10] = id >> 8;
3242
+ buff[offset + 11] = id;
3243
+ buff[offset + 12] = 0; // x-position
3244
+
3245
+ buff[offset + 13] = 0;
3246
+ buff[offset + 14] = 0; // y-position
3247
+
3248
+ buff[offset + 15] = 0;
3249
+ buff[offset + 16] = width >> 8; // width
3250
+
3251
+ buff[offset + 17] = width;
3252
+ buff[offset + 18] = height >> 8; // height
3253
+
3254
+ buff[offset + 19] = height;
3255
+ buff[offset + 20] = flags >> 24; // flags
3256
+
3257
+ buff[offset + 21] = flags >> 16;
3258
+ buff[offset + 22] = flags >> 8;
3259
+ buff[offset + 23] = flags;
3260
+ sock._sQlen += 24;
3261
+ sock.flush();
3262
+ },
3263
+ clientFence: function clientFence(sock, flags, payload) {
3264
+ var buff = sock._sQ;
3265
+ var offset = sock._sQlen;
3266
+ buff[offset] = 248; // msg-type
3267
+
3268
+ buff[offset + 1] = 0; // padding
3269
+
3270
+ buff[offset + 2] = 0; // padding
3271
+
3272
+ buff[offset + 3] = 0; // padding
3273
+
3274
+ buff[offset + 4] = flags >> 24; // flags
3275
+
3276
+ buff[offset + 5] = flags >> 16;
3277
+ buff[offset + 6] = flags >> 8;
3278
+ buff[offset + 7] = flags;
3279
+ var n = payload.length;
3280
+ buff[offset + 8] = n; // length
3281
+
3282
+ for (var i = 0; i < n; i++) {
3283
+ buff[offset + 9 + i] = payload.charCodeAt(i);
3284
+ }
3285
+
3286
+ sock._sQlen += 9 + n;
3287
+ sock.flush();
3288
+ },
3289
+ enableContinuousUpdates: function enableContinuousUpdates(sock, enable, x, y, width, height) {
3290
+ var buff = sock._sQ;
3291
+ var offset = sock._sQlen;
3292
+ buff[offset] = 150; // msg-type
3293
+
3294
+ buff[offset + 1] = enable; // enable-flag
3295
+
3296
+ buff[offset + 2] = x >> 8; // x
3297
+
3298
+ buff[offset + 3] = x;
3299
+ buff[offset + 4] = y >> 8; // y
3300
+
3301
+ buff[offset + 5] = y;
3302
+ buff[offset + 6] = width >> 8; // width
3303
+
3304
+ buff[offset + 7] = width;
3305
+ buff[offset + 8] = height >> 8; // height
3306
+
3307
+ buff[offset + 9] = height;
3308
+ sock._sQlen += 10;
3309
+ sock.flush();
3310
+ },
3311
+ pixelFormat: function pixelFormat(sock, depth, trueColor) {
3312
+ var buff = sock._sQ;
3313
+ var offset = sock._sQlen;
3314
+ var bpp;
3315
+
3316
+ if (depth > 16) {
3317
+ bpp = 32;
3318
+ } else if (depth > 8) {
3319
+ bpp = 16;
3320
+ } else {
3321
+ bpp = 8;
3322
+ }
3323
+
3324
+ var bits = Math.floor(depth / 3);
3325
+ buff[offset] = 0; // msg-type
3326
+
3327
+ buff[offset + 1] = 0; // padding
3328
+
3329
+ buff[offset + 2] = 0; // padding
3330
+
3331
+ buff[offset + 3] = 0; // padding
3332
+
3333
+ buff[offset + 4] = bpp; // bits-per-pixel
3334
+
3335
+ buff[offset + 5] = depth; // depth
3336
+
3337
+ buff[offset + 6] = 0; // little-endian
3338
+
3339
+ buff[offset + 7] = trueColor ? 1 : 0; // true-color
3340
+
3341
+ buff[offset + 8] = 0; // red-max
3342
+
3343
+ buff[offset + 9] = (1 << bits) - 1; // red-max
3344
+
3345
+ buff[offset + 10] = 0; // green-max
3346
+
3347
+ buff[offset + 11] = (1 << bits) - 1; // green-max
3348
+
3349
+ buff[offset + 12] = 0; // blue-max
3350
+
3351
+ buff[offset + 13] = (1 << bits) - 1; // blue-max
3352
+
3353
+ buff[offset + 14] = bits * 2; // red-shift
3354
+
3355
+ buff[offset + 15] = bits * 1; // green-shift
3356
+
3357
+ buff[offset + 16] = bits * 0; // blue-shift
3358
+
3359
+ buff[offset + 17] = 0; // padding
3360
+
3361
+ buff[offset + 18] = 0; // padding
3362
+
3363
+ buff[offset + 19] = 0; // padding
3364
+
3365
+ sock._sQlen += 20;
3366
+ sock.flush();
3367
+ },
3368
+ clientEncodings: function clientEncodings(sock, encodings) {
3369
+ var buff = sock._sQ;
3370
+ var offset = sock._sQlen;
3371
+ buff[offset] = 2; // msg-type
3372
+
3373
+ buff[offset + 1] = 0; // padding
3374
+
3375
+ buff[offset + 2] = encodings.length >> 8;
3376
+ buff[offset + 3] = encodings.length;
3377
+ var j = offset + 4;
3378
+
3379
+ for (var i = 0; i < encodings.length; i++) {
3380
+ var enc = encodings[i];
3381
+ buff[j] = enc >> 24;
3382
+ buff[j + 1] = enc >> 16;
3383
+ buff[j + 2] = enc >> 8;
3384
+ buff[j + 3] = enc;
3385
+ j += 4;
3386
+ }
3387
+
3388
+ sock._sQlen += j - offset;
3389
+ sock.flush();
3390
+ },
3391
+ fbUpdateRequest: function fbUpdateRequest(sock, incremental, x, y, w, h) {
3392
+ var buff = sock._sQ;
3393
+ var offset = sock._sQlen;
3394
+
3395
+ if (typeof x === "undefined") {
3396
+ x = 0;
3397
+ }
3398
+
3399
+ if (typeof y === "undefined") {
3400
+ y = 0;
3401
+ }
3402
+
3403
+ buff[offset] = 3; // msg-type
3404
+
3405
+ buff[offset + 1] = incremental ? 1 : 0;
3406
+ buff[offset + 2] = x >> 8 & 0xFF;
3407
+ buff[offset + 3] = x & 0xFF;
3408
+ buff[offset + 4] = y >> 8 & 0xFF;
3409
+ buff[offset + 5] = y & 0xFF;
3410
+ buff[offset + 6] = w >> 8 & 0xFF;
3411
+ buff[offset + 7] = w & 0xFF;
3412
+ buff[offset + 8] = h >> 8 & 0xFF;
3413
+ buff[offset + 9] = h & 0xFF;
3414
+ sock._sQlen += 10;
3415
+ sock.flush();
3416
+ },
3417
+ xvpOp: function xvpOp(sock, ver, op) {
3418
+ var buff = sock._sQ;
3419
+ var offset = sock._sQlen;
3420
+ buff[offset] = 250; // msg-type
3421
+
3422
+ buff[offset + 1] = 0; // padding
3423
+
3424
+ buff[offset + 2] = ver;
3425
+ buff[offset + 3] = op;
3426
+ sock._sQlen += 4;
3427
+ sock.flush();
3428
+ }
3429
+ };
3430
+ RFB.cursors = {
3431
+ none: {
3432
+ rgbaPixels: new Uint8Array(),
3433
+ w: 0,
3434
+ h: 0,
3435
+ hotx: 0,
3436
+ hoty: 0
3437
+ },
3438
+ dot: {
3439
+ /* eslint-disable indent */
3440
+ rgbaPixels: new Uint8Array([255, 255, 255, 255, 0, 0, 0, 255, 255, 255, 255, 255, 0, 0, 0, 255, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 0, 0, 0, 255, 255, 255, 255, 255]),
3441
+
3442
+ /* eslint-enable indent */
3443
+ w: 3,
3444
+ h: 3,
3445
+ hotx: 1,
3446
+ hoty: 1
3447
+ }
3448
+ };