mirror of
https://github.com/novnc/noVNC.git
synced 2026-06-06 20:39:39 +00:00
Use Typed Arrays for the send queue
This commit converts the send queue to use typed arrays, and converts message creation functions in 'rfb.js' to create messages directly into the socket's send queue. This commit also removes the separate mouse array, which is no longer needed.
This commit is contained in:
256
include/rfb.js
256
include/rfb.js
@@ -259,14 +259,14 @@ var RFB;
|
||||
if (this._rfb_state !== 'normal' || this._view_only) { return false; }
|
||||
Util.Info("Sending Ctrl-Alt-Del");
|
||||
|
||||
var arr = [];
|
||||
arr = arr.concat(RFB.messages.keyEvent(XK_Control_L, 1));
|
||||
arr = arr.concat(RFB.messages.keyEvent(XK_Alt_L, 1));
|
||||
arr = arr.concat(RFB.messages.keyEvent(XK_Delete, 1));
|
||||
arr = arr.concat(RFB.messages.keyEvent(XK_Delete, 0));
|
||||
arr = arr.concat(RFB.messages.keyEvent(XK_Alt_L, 0));
|
||||
arr = arr.concat(RFB.messages.keyEvent(XK_Control_L, 0));
|
||||
this._sock.send(arr);
|
||||
RFB.messages.keyEvent(this._sock, XK_Control_L, 1);
|
||||
RFB.messages.keyEvent(this._sock, XK_Alt_L, 1);
|
||||
RFB.messages.keyEvent(this._sock, XK_Delete, 1);
|
||||
RFB.messages.keyEvent(this._sock, XK_Delete, 0);
|
||||
RFB.messages.keyEvent(this._sock, XK_Alt_L, 0);
|
||||
RFB.messages.keyEvent(this._sock, XK_Control_L, 0);
|
||||
|
||||
this._sock.flush();
|
||||
},
|
||||
|
||||
xvpOp: function (ver, op) {
|
||||
@@ -292,21 +292,22 @@ var RFB;
|
||||
// followed by an up key.
|
||||
sendKey: function (code, down) {
|
||||
if (this._rfb_state !== "normal" || this._view_only) { return false; }
|
||||
var arr = [];
|
||||
if (typeof down !== 'undefined') {
|
||||
Util.Info("Sending key code (" + (down ? "down" : "up") + "): " + code);
|
||||
arr = arr.concat(RFB.messages.keyEvent(code, down ? 1 : 0));
|
||||
RFB.messages.keyEvent(this._sock, code, down ? 1 : 0);
|
||||
} else {
|
||||
Util.Info("Sending key code (down + up): " + code);
|
||||
arr = arr.concat(RFB.messages.keyEvent(code, 1));
|
||||
arr = arr.concat(RFB.messages.keyEvent(code, 0));
|
||||
RFB.messages.keyEvent(this._sock, code, 1);
|
||||
RFB.messages.keyEvent(this._sock, code, 0);
|
||||
}
|
||||
this._sock.send(arr);
|
||||
|
||||
this._sock.flush();
|
||||
},
|
||||
|
||||
clipboardPasteFrom: function (text) {
|
||||
if (this._rfb_state !== 'normal') { return; }
|
||||
this._sock.send(RFB.messages.clientCutText(text));
|
||||
RFB.messages.clientCutText(this._sock, text);
|
||||
this._sock.flush();
|
||||
},
|
||||
|
||||
setDesktopSize: function (width, height) {
|
||||
@@ -572,16 +573,10 @@ var RFB;
|
||||
}
|
||||
},
|
||||
|
||||
_checkEvents: function () {
|
||||
if (this._rfb_state === 'normal' && !this._viewportDragging && this._mouse_arr.length > 0) {
|
||||
this._sock.send(this._mouse_arr);
|
||||
this._mouse_arr = [];
|
||||
}
|
||||
},
|
||||
|
||||
_handleKeyPress: function (keysym, down) {
|
||||
if (this._view_only) { return; } // View only, skip keyboard, events
|
||||
this._sock.send(RFB.messages.keyEvent(keysym, down));
|
||||
RFB.messages.keyEvent(this._sock, keysym, down);
|
||||
this._sock.flush();
|
||||
},
|
||||
|
||||
_handleMouseButton: function (x, y, down, bmask) {
|
||||
@@ -605,10 +600,8 @@ var RFB;
|
||||
|
||||
if (this._view_only) { return; } // View only, skip mouse events
|
||||
|
||||
this._mouse_arr = this._mouse_arr.concat(
|
||||
RFB.messages.pointerEvent(this._display.absX(x), this._display.absY(y), this._mouse_buttonMask));
|
||||
this._sock.send(this._mouse_arr);
|
||||
this._mouse_arr = [];
|
||||
if (this._rfb_state !== "normal") { return; }
|
||||
RFB.messages.pointerEvent(this._sock, this._display.absX(x), this._display.absY(y), this._mouse_buttonMask);
|
||||
},
|
||||
|
||||
_handleMouseMove: function (x, y) {
|
||||
@@ -625,10 +618,8 @@ var RFB;
|
||||
|
||||
if (this._view_only) { return; } // View only, skip mouse events
|
||||
|
||||
this._mouse_arr = this._mouse_arr.concat(
|
||||
RFB.messages.pointerEvent(this._display.absX(x), this._display.absY(y), this._mouse_buttonMask));
|
||||
|
||||
this._checkEvents();
|
||||
if (this._rfb_state !== "normal") { return; }
|
||||
RFB.messages.pointerEvent(this._sock, this._display.absX(x), this._display.absY(y), this._mouse_buttonMask);
|
||||
},
|
||||
|
||||
// Message Handlers
|
||||
@@ -895,7 +886,7 @@ var RFB;
|
||||
/* Screen size */
|
||||
this._fb_width = this._sock.rQshift16();
|
||||
this._fb_height = this._sock.rQshift16();
|
||||
this._dest_buff = new Uint8Array(this._fb_width * this._fb_height * 4);
|
||||
this._destBuff = new Uint8Array(this._fb_width * this._fb_height * 4);
|
||||
|
||||
/* PIXEL_FORMAT */
|
||||
var bpp = this._sock.rQshift8();
|
||||
@@ -991,18 +982,13 @@ var RFB;
|
||||
this._fb_depth = 1;
|
||||
}
|
||||
|
||||
var response = RFB.messages.pixelFormat(this._fb_Bpp, this._fb_depth, this._true_color);
|
||||
response = response.concat(
|
||||
RFB.messages.clientEncodings(this._encodings, this._local_cursor, this._true_color));
|
||||
response = response.concat(
|
||||
RFB.messages.fbUpdateRequests(this._display.getCleanDirtyReset(),
|
||||
this._fb_width, this._fb_height));
|
||||
RFB.messages.pixelFormat(this._sock, this._fb_Bpp, this._fb_depth, this._true_color);
|
||||
RFB.messages.clientEncodings(this._sock, this._encodings, this._local_cursor, this._true_color);
|
||||
RFB.messages.fbUpdateRequests(this._sock, this._display.getCleanDirtyReset(), this._fb_width, this._fb_height);
|
||||
|
||||
this._timing.fbu_rt_start = (new Date()).getTime();
|
||||
this._timing.pixels = 0;
|
||||
this._sock.send(response);
|
||||
|
||||
this._checkEvents();
|
||||
this._sock.flush();
|
||||
|
||||
if (this._encrypt) {
|
||||
this._updateState('normal', 'Connected (encrypted) to: ' + this._fb_name);
|
||||
@@ -1104,8 +1090,8 @@ var RFB;
|
||||
case 0: // FramebufferUpdate
|
||||
var ret = this._framebufferUpdate();
|
||||
if (ret) {
|
||||
this._sock.send(RFB.messages.fbUpdateRequests(this._display.getCleanDirtyReset(),
|
||||
this._fb_width, this._fb_height));
|
||||
RFB.messages.fbUpdateRequests(this._sock, this._display.getCleanDirtyReset(), this._fb_width, this._fb_height);
|
||||
this._sock.flush();
|
||||
}
|
||||
return ret;
|
||||
|
||||
@@ -1279,64 +1265,111 @@ var RFB;
|
||||
|
||||
// Class Methods
|
||||
RFB.messages = {
|
||||
keyEvent: function (keysym, down) {
|
||||
var arr = [4];
|
||||
arr.push8(down);
|
||||
arr.push16(0);
|
||||
arr.push32(keysym);
|
||||
return arr;
|
||||
keyEvent: function (sock, keysym, down) {
|
||||
var buff = sock._sQ;
|
||||
var offset = sock._sQlen;
|
||||
|
||||
buff[offset] = 4; // msg-type
|
||||
buff[offset + 1] = down;
|
||||
|
||||
buff[offset + 2] = 0;
|
||||
buff[offset + 3] = 0;
|
||||
|
||||
buff[offset + 4] = (keysym >> 24);
|
||||
buff[offset + 5] = (keysym >> 16);
|
||||
buff[offset + 6] = (keysym >> 8);
|
||||
buff[offset + 7] = keysym;
|
||||
|
||||
sock._sQlen += 8;
|
||||
},
|
||||
|
||||
pointerEvent: function (x, y, mask) {
|
||||
var arr = [5]; // msg-type
|
||||
arr.push8(mask);
|
||||
arr.push16(x);
|
||||
arr.push16(y);
|
||||
return arr;
|
||||
pointerEvent: function (sock, x, y, mask) {
|
||||
var buff = sock._sQ;
|
||||
var offset = sock._sQlen;
|
||||
|
||||
buff[offset] = 5; // msg-type
|
||||
|
||||
buff[offset + 1] = mask;
|
||||
|
||||
buff[offset + 2] = x >> 8;
|
||||
buff[offset + 3] = x;
|
||||
|
||||
buff[offset + 4] = y >> 8;
|
||||
buff[offset + 5] = y;
|
||||
|
||||
sock._sQlen += 6;
|
||||
},
|
||||
|
||||
// TODO(directxman12): make this unicode compatible?
|
||||
clientCutText: function (text) {
|
||||
var arr = [6]; // msg-type
|
||||
arr.push8(0); // padding
|
||||
arr.push8(0); // padding
|
||||
arr.push8(0); // padding
|
||||
arr.push32(text.length);
|
||||
clientCutText: function (sock, text) {
|
||||
var buff = sock._sQ;
|
||||
var offset = sock._sQlen;
|
||||
|
||||
buff[offset] = 6; // msg-type
|
||||
|
||||
buff[offset + 1] = 0; // padding
|
||||
buff[offset + 2] = 0; // padding
|
||||
buff[offset + 3] = 0; // padding
|
||||
|
||||
var n = text.length;
|
||||
|
||||
buff[offset + 4] = n >> 24;
|
||||
buff[offset + 5] = n >> 16;
|
||||
buff[offset + 6] = n >> 8;
|
||||
buff[offset + 7] = n;
|
||||
|
||||
for (var i = 0; i < n; i++) {
|
||||
arr.push(text.charCodeAt(i));
|
||||
buff[offset + 8 + i] = text.charCodeAt(i);
|
||||
}
|
||||
|
||||
return arr;
|
||||
sock._sQlen += 8 + n;
|
||||
},
|
||||
|
||||
pixelFormat: function (bpp, depth, true_color) {
|
||||
var arr = [0]; // msg-type
|
||||
arr.push8(0); // padding
|
||||
arr.push8(0); // padding
|
||||
arr.push8(0); // padding
|
||||
pixelFormat: function (sock, bpp, depth, true_color) {
|
||||
var buff = sock._sQ;
|
||||
var offset = sock._sQlen;
|
||||
|
||||
arr.push8(bpp * 8); // bits-per-pixel
|
||||
arr.push8(depth * 8); // depth
|
||||
arr.push8(0); // little-endian
|
||||
arr.push8(true_color ? 1 : 0); // true-color
|
||||
buff[offset] = 0; // msg-type
|
||||
|
||||
arr.push16(255); // red-max
|
||||
arr.push16(255); // green-max
|
||||
arr.push16(255); // blue-max
|
||||
arr.push8(16); // red-shift
|
||||
arr.push8(8); // green-shift
|
||||
arr.push8(0); // blue-shift
|
||||
buff[offset + 1] = 0; // padding
|
||||
buff[offset + 2] = 0; // padding
|
||||
buff[offset + 3] = 0; // padding
|
||||
|
||||
arr.push8(0); // padding
|
||||
arr.push8(0); // padding
|
||||
arr.push8(0); // padding
|
||||
return arr;
|
||||
buff[offset + 4] = bpp * 8; // bits-per-pixel
|
||||
buff[offset + 5] = depth * 8; // depth
|
||||
buff[offset + 6] = 0; // little-endian
|
||||
buff[offset + 7] = true_color ? 1 : 0; // true-color
|
||||
|
||||
buff[offset + 8] = 0; // red-max
|
||||
buff[offset + 9] = 255; // red-max
|
||||
|
||||
buff[offset + 10] = 0; // green-max
|
||||
buff[offset + 11] = 255; // green-max
|
||||
|
||||
buff[offset + 12] = 0; // blue-max
|
||||
buff[offset + 13] = 255; // blue-max
|
||||
|
||||
buff[offset + 14] = 16; // red-shift
|
||||
buff[offset + 15] = 8; // green-shift
|
||||
buff[offset + 16] = 0; // blue-shift
|
||||
|
||||
buff[offset + 17] = 0; // padding
|
||||
buff[offset + 18] = 0; // padding
|
||||
buff[offset + 19] = 0; // padding
|
||||
|
||||
sock._sQlen += 20;
|
||||
},
|
||||
|
||||
clientEncodings: function (encodings, local_cursor, true_color) {
|
||||
var i, encList = [];
|
||||
clientEncodings: function (sock, encodings, local_cursor, true_color) {
|
||||
var buff = sock._sQ;
|
||||
var offset = sock._sQlen;
|
||||
|
||||
buff[offset] = 2; // msg-type
|
||||
buff[offset + 1] = 0; // padding
|
||||
|
||||
// offset + 2 and offset + 3 are encoding count
|
||||
|
||||
var i, j = offset + 4, cnt = 0;
|
||||
for (i = 0; i < encodings.length; i++) {
|
||||
if (encodings[i][0] === "Cursor" && !local_cursor) {
|
||||
Util.Debug("Skipping Cursor pseudo-encoding");
|
||||
@@ -1344,23 +1377,25 @@ var RFB;
|
||||
// TODO: remove this when we have tight+non-true-color
|
||||
Util.Warn("Skipping tight as it is only supported with true color");
|
||||
} else {
|
||||
encList.push(encodings[i][1]);
|
||||
var enc = encodings[i][1];
|
||||
buff[j] = enc >> 24;
|
||||
buff[j + 1] = enc >> 16;
|
||||
buff[j + 2] = enc >> 8;
|
||||
buff[j + 3] = enc;
|
||||
|
||||
j += 4;
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
|
||||
var arr = [2]; // msg-type
|
||||
arr.push8(0); // padding
|
||||
buff[offset + 2] = cnt >> 8;
|
||||
buff[offset + 3] = cnt;
|
||||
|
||||
arr.push16(encList.length); // encoding count
|
||||
for (i = 0; i < encList.length; i++) {
|
||||
arr.push32(encList[i]);
|
||||
}
|
||||
|
||||
return arr;
|
||||
sock._sQlen += j - offset;
|
||||
},
|
||||
|
||||
fbUpdateRequests: function (cleanDirty, fb_width, fb_height) {
|
||||
var arr = [];
|
||||
fbUpdateRequests: function (sock, cleanDirty, fb_width, fb_height) {
|
||||
var offsetIncrement = 0;
|
||||
|
||||
var cb = cleanDirty.cleanBox;
|
||||
var w, h;
|
||||
@@ -1368,7 +1403,7 @@ var RFB;
|
||||
w = typeof cb.w === "undefined" ? fb_width : cb.w;
|
||||
h = typeof cb.h === "undefined" ? fb_height : cb.h;
|
||||
// Request incremental for clean box
|
||||
arr = arr.concat(RFB.messages.fbUpdateRequest(1, cb.x, cb.y, w, h));
|
||||
RFB.messages.fbUpdateRequest(sock, 1, cb.x, cb.y, w, h);
|
||||
}
|
||||
|
||||
for (var i = 0; i < cleanDirty.dirtyBoxes.length; i++) {
|
||||
@@ -1376,24 +1411,33 @@ var RFB;
|
||||
// Force all (non-incremental) for dirty box
|
||||
w = typeof db.w === "undefined" ? fb_width : db.w;
|
||||
h = typeof db.h === "undefined" ? fb_height : db.h;
|
||||
arr = arr.concat(RFB.messages.fbUpdateRequest(0, db.x, db.y, w, h));
|
||||
RFB.messages.fbUpdateRequest(sock, 0, db.x, db.y, w, h);
|
||||
}
|
||||
|
||||
return arr;
|
||||
},
|
||||
|
||||
fbUpdateRequest: function (incremental, x, y, w, h) {
|
||||
fbUpdateRequest: function (sock, incremental, x, y, w, h) {
|
||||
var buff = sock._sQ;
|
||||
var offset = sock._sQlen;
|
||||
|
||||
if (typeof(x) === "undefined") { x = 0; }
|
||||
if (typeof(y) === "undefined") { y = 0; }
|
||||
|
||||
var arr = [3]; // msg-type
|
||||
arr.push8(incremental);
|
||||
arr.push16(x);
|
||||
arr.push16(y);
|
||||
arr.push16(w);
|
||||
arr.push16(h);
|
||||
buff[offset] = 3; // msg-type
|
||||
buff[offset + 1] = incremental;
|
||||
|
||||
return arr;
|
||||
buff[offset + 2] = (x >> 8) & 0xFF;
|
||||
buff[offset + 3] = x & 0xFF;
|
||||
|
||||
buff[offset + 4] = (y >> 8) & 0xFF;
|
||||
buff[offset + 5] = y & 0xFF;
|
||||
|
||||
buff[offset + 6] = (w >> 8) & 0xFF;
|
||||
buff[offset + 7] = w & 0xFF;
|
||||
|
||||
buff[offset + 8] = (h >> 8) & 0xFF;
|
||||
buff[offset + 9] = h & 0xFF;
|
||||
|
||||
sock._sQlen += 10;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -45,10 +45,14 @@ function Websock() {
|
||||
this._rQlen = 0; // Next write position in the receive queue
|
||||
this._rQbufferSize = 1024 * 1024 * 4; // Receive queue buffer size (4 MiB)
|
||||
this._rQmax = this._rQbufferSize / 8;
|
||||
this._sQ = []; // Send queue
|
||||
// called in init: this._rQ = new Uint8Array(this._rQbufferSize);
|
||||
this._rQ = null; // Receive queue
|
||||
|
||||
this._sQbufferSize = 1024 * 10; // 10 KiB
|
||||
// called in init: this._sQ = new Uint8Array(this._sQbufferSize);
|
||||
this._sQlen = 0;
|
||||
this._sQ = null; // Send queue
|
||||
|
||||
this._mode = 'binary'; // Current WebSocket mode: 'binary', 'base64'
|
||||
this.maxBufferedAmount = 200;
|
||||
|
||||
@@ -183,9 +187,9 @@ function Websock() {
|
||||
}
|
||||
|
||||
if (this._websocket.bufferedAmount < this.maxBufferedAmount) {
|
||||
if (this._sQ.length > 0) {
|
||||
if (this._sQlen > 0) {
|
||||
this._websocket.send(this._encode_message());
|
||||
this._sQ = [];
|
||||
this._sQlen = 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -197,8 +201,9 @@ function Websock() {
|
||||
},
|
||||
|
||||
send: function (arr) {
|
||||
this._sQ = this._sQ.concat(arr);
|
||||
return this.flush();
|
||||
this._sQ.set(arr, this._sQlen);
|
||||
this._sQlen += arr.length;
|
||||
return this.flush();
|
||||
},
|
||||
|
||||
send_string: function (str) {
|
||||
@@ -218,12 +223,12 @@ function Websock() {
|
||||
|
||||
_allocate_buffers: function () {
|
||||
this._rQ = new Uint8Array(this._rQbufferSize);
|
||||
this._sQ = new Uint8Array(this._sQbufferSize);
|
||||
},
|
||||
|
||||
init: function (protocols, ws_schema) {
|
||||
this._allocate_buffers();
|
||||
this._rQi = 0;
|
||||
this._sQ = [];
|
||||
this._websocket = null;
|
||||
|
||||
// Check for full typed array support
|
||||
@@ -327,7 +332,8 @@ function Websock() {
|
||||
// private methods
|
||||
_encode_message: function () {
|
||||
// Put in a binary arraybuffer
|
||||
return (new Uint8Array(this._sQ)).buffer;
|
||||
// according to the spec, you can send ArrayBufferViews with the send method
|
||||
return new Uint8Array(this._sQ.buffer, 0, this._sQlen);
|
||||
},
|
||||
|
||||
_decode_message: function (data) {
|
||||
|
||||
Reference in New Issue
Block a user