Merge 24439f5bf2 into 757653c007
This commit is contained in:
commit
8d1109a540
|
|
@ -128,6 +128,7 @@ use a WebSockets to TCP socket proxy. There is a python proxy included
|
|||
* UI and Icons : Chris Gordon
|
||||
* Original Logo : Michael Sersen
|
||||
* tight encoding : Michael Tinglof (Mercuri.ca)
|
||||
* pixel format conversion and ATEN iKVM support : [Alexander Clouter](http://www.digriz.org.uk/)
|
||||
|
||||
* Included libraries:
|
||||
* web-socket-js : Hiroshi Ichikawa (github.com/gimite/web-socket-js)
|
||||
|
|
|
|||
|
|
@ -415,21 +415,12 @@ var Display;
|
|||
|
||||
blitImage: function (x, y, width, height, arr, offset) {
|
||||
if (this._true_color) {
|
||||
this._bgrxImageData(x, y, this._viewportLoc.x, this._viewportLoc.y, width, height, arr, offset);
|
||||
this._imageData(x, y, this._viewportLoc.x, this._viewportLoc.y, width, height, arr, offset);
|
||||
} else {
|
||||
this._cmapImageData(x, y, this._viewportLoc.x, this._viewportLoc.y, width, height, arr, offset);
|
||||
}
|
||||
},
|
||||
|
||||
blitRgbImage: function (x, y , width, height, arr, offset) {
|
||||
if (this._true_color) {
|
||||
this._rgbImageData(x, y, this._viewportLoc.x, this._viewportLoc.y, width, height, arr, offset);
|
||||
} else {
|
||||
// probably wrong?
|
||||
this._cmapImageData(x, y, this._viewportLoc.x, this._viewportLoc.y, width, height, arr, offset);
|
||||
}
|
||||
},
|
||||
|
||||
blitStringImage: function (str, x, y) {
|
||||
var img = new Image();
|
||||
img.onload = function () {
|
||||
|
|
@ -547,7 +538,7 @@ var Display;
|
|||
}
|
||||
},
|
||||
|
||||
_rgbImageData: function (x, y, vx, vy, width, height, arr, offset) {
|
||||
_imageData: function (x, y, vx, vy, width, height, arr, offset) {
|
||||
var img = this._drawCtx.createImageData(width, height);
|
||||
var data = img.data;
|
||||
for (var i = 0, j = offset; i < width * height * 4; i += 4, j += 3) {
|
||||
|
|
@ -559,18 +550,6 @@ var Display;
|
|||
this._drawCtx.putImageData(img, x - vx, y - vy);
|
||||
},
|
||||
|
||||
_bgrxImageData: function (x, y, vx, vy, width, height, arr, offset) {
|
||||
var img = this._drawCtx.createImageData(width, height);
|
||||
var data = img.data;
|
||||
for (var i = 0, j = offset; i < width * height * 4; i += 4, j += 4) {
|
||||
data[i] = arr[j + 2];
|
||||
data[i + 1] = arr[j + 1];
|
||||
data[i + 2] = arr[j];
|
||||
data[i + 3] = 255; // Alpha
|
||||
}
|
||||
this._drawCtx.putImageData(img, x - vx, y - vy);
|
||||
},
|
||||
|
||||
_cmapImageData: function (x, y, vx, vy, width, height, arr, offset) {
|
||||
var img = this._drawCtx.createImageData(width, height);
|
||||
var data = img.data;
|
||||
|
|
@ -599,9 +578,6 @@ var Display;
|
|||
case 'blit':
|
||||
this.blitImage(a.x, a.y, a.width, a.height, a.data, 0);
|
||||
break;
|
||||
case 'blitRgb':
|
||||
this.blitRgbImage(a.x, a.y, a.width, a.height, a.data, 0);
|
||||
break;
|
||||
case 'img':
|
||||
if (a.img.complete) {
|
||||
this.drawImage(a.img, a.x, a.y);
|
||||
|
|
|
|||
|
|
@ -376,3 +376,80 @@ XK_udiaeresis = 0x00fc, /* U+00FC LATIN SMALL LETTER U WITH DIA
|
|||
XK_yacute = 0x00fd, /* U+00FD LATIN SMALL LETTER Y WITH ACUTE */
|
||||
XK_thorn = 0x00fe, /* U+00FE LATIN SMALL LETTER THORN */
|
||||
XK_ydiaeresis = 0x00ff; /* U+00FF LATIN SMALL LETTER Y WITH DIAERESIS */
|
||||
|
||||
var XK2HID = {};
|
||||
|
||||
// F{1..12}
|
||||
for (var i = XK_F1; i <= XK_F12; i++) {
|
||||
XK2HID[i] = 0x3a + (i - XK_F1);
|
||||
}
|
||||
// A-Za-z
|
||||
for (var i = XK_A; i <= XK_Z; i++) {
|
||||
XK2HID[i] = 0x04 + (i - XK_A);
|
||||
XK2HID[i + (XK_a - XK_A)] = 0x04 + (i - XK_A);
|
||||
}
|
||||
// 1-9
|
||||
for (var i = XK_1; i <= XK_9; i++) {
|
||||
XK2HID[i] = 0x1e + (i - XK_1);
|
||||
}
|
||||
|
||||
XK2HID[XK_0] = 0x27;
|
||||
XK2HID[XK_Return] = 0x28;
|
||||
XK2HID[XK_Escape] = 0x29;
|
||||
XK2HID[XK_BackSpace] = 0x2a;
|
||||
XK2HID[XK_Tab] = 0x2b;
|
||||
XK2HID[XK_space] = 0x2c;
|
||||
XK2HID[XK_minus] = 0x2d;
|
||||
XK2HID[XK_equal] = 0x2e;
|
||||
XK2HID[XK_bracketleft] = 0x2f;
|
||||
XK2HID[XK_bracketright] = 0x30;
|
||||
XK2HID[XK_backslash] = 0x31;
|
||||
XK2HID[XK_semicolon] = 0x33;
|
||||
XK2HID[XK_apostrophe] = 0x34;
|
||||
XK2HID[XK_grave] = 0x35;
|
||||
XK2HID[XK_comma] = 0x36;
|
||||
XK2HID[XK_period] = 0x37;
|
||||
XK2HID[XK_slash] = 0x38;
|
||||
|
||||
XK2HID[XK_Print] = 0x46;
|
||||
XK2HID[XK_Scroll_Lock] = 0x47;
|
||||
XK2HID[XK_Pause] = 0x48;
|
||||
XK2HID[XK_Insert] = 0x49;
|
||||
XK2HID[XK_Home] = 0x4a;
|
||||
XK2HID[XK_Page_Up] = 0x4b;
|
||||
XK2HID[XK_Delete] = 0x4c;
|
||||
XK2HID[XK_End] = 0x4d;
|
||||
XK2HID[XK_Page_Down] = 0x4e;
|
||||
XK2HID[XK_Right] = 0x4f;
|
||||
XK2HID[XK_Left] = 0x50;
|
||||
XK2HID[XK_Down] = 0x51;
|
||||
XK2HID[XK_Up] = 0x52;
|
||||
|
||||
XK2HID[XK_Control_L] = 0xe0;
|
||||
XK2HID[XK_Control_R] = XK2HID[XK_Control_L];
|
||||
XK2HID[XK_Shift_L] = 0xe1;
|
||||
XK2HID[XK_Shift_R] = XK2HID[XK_Shift_L];
|
||||
XK2HID[XK_Alt_L] = 0xe2;
|
||||
XK2HID[XK_Alt_R] = XK2HID[XK_Alt_L];
|
||||
XK2HID[XK_Super_L] = 0xe3;
|
||||
XK2HID[XK_Super_R] = XK2HID[XK_Super_L];
|
||||
|
||||
XK2HID[XK_Caps_Lock] = 0x39;
|
||||
|
||||
// locale hardcoded hack
|
||||
XK2HID[XK_less] = XK2HID[XK_comma];
|
||||
XK2HID[XK_greater] = XK2HID[XK_period];
|
||||
XK2HID[XK_exclam] = XK2HID[XK_1];
|
||||
XK2HID[XK_at] = XK2HID[XK_2];
|
||||
XK2HID[XK_numbersign] = XK2HID[XK_3];
|
||||
XK2HID[XK_dollar] = XK2HID[XK_4];
|
||||
XK2HID[XK_percent] = XK2HID[XK_5];
|
||||
XK2HID[XK_asciicircum] = XK2HID[XK_6];
|
||||
XK2HID[XK_ampersand] = XK2HID[XK_7];
|
||||
XK2HID[XK_asterisk] = XK2HID[XK_8];
|
||||
XK2HID[XK_parenleft] = XK2HID[XK_9];
|
||||
XK2HID[XK_parenright] = XK2HID[XK_0];
|
||||
XK2HID[XK_underscore] = XK2HID[XK_minus];
|
||||
XK2HID[XK_bar] = XK2HID[XK_backslash];
|
||||
XK2HID[XK_quotedbl] = XK2HID[XK_apostrophe];
|
||||
XK2HID[XK_asciitilde] = XK2HID[XK_grave];
|
||||
|
|
|
|||
547
include/rfb.js
547
include/rfb.js
|
|
@ -33,6 +33,7 @@ var RFB;
|
|||
this._rfb_auth_scheme = '';
|
||||
|
||||
this._rfb_tightvnc = false;
|
||||
this._rfb_atenikvm = false;
|
||||
this._rfb_xvp_ver = 0;
|
||||
|
||||
// In preference order
|
||||
|
|
@ -43,6 +44,7 @@ var RFB;
|
|||
['HEXTILE', 0x05 ],
|
||||
['RRE', 0x02 ],
|
||||
['RAW', 0x00 ],
|
||||
['ATEN', 0x59 ],
|
||||
['DesktopSize', -223 ],
|
||||
['Cursor', -239 ],
|
||||
|
||||
|
|
@ -74,6 +76,8 @@ var RFB;
|
|||
subrects: 0, // RRE
|
||||
lines: 0, // RAW
|
||||
tiles: 0, // HEXTILE
|
||||
aten_len: -1, // ATEN
|
||||
aten_type: -1, // ATEN
|
||||
bytes: 0,
|
||||
x: 0,
|
||||
y: 0,
|
||||
|
|
@ -85,8 +89,7 @@ var RFB;
|
|||
zlib: [] // TIGHT zlib streams
|
||||
};
|
||||
|
||||
this._fb_Bpp = 4;
|
||||
this._fb_depth = 3;
|
||||
this._pixelFormat = {};
|
||||
this._fb_width = 0;
|
||||
this._fb_height = 0;
|
||||
this._fb_name = "";
|
||||
|
|
@ -117,10 +120,11 @@ var RFB;
|
|||
'target': 'null', // VNC display rendering Canvas object
|
||||
'focusContainer': document, // DOM element that captures keyboard input
|
||||
'encrypt': false, // Use TLS/SSL/wss encryption
|
||||
'true_color': true, // Request true color pixel data
|
||||
'convertColor': false, // Client will not honor request for native color
|
||||
'local_cursor': false, // Request locally rendered cursor
|
||||
'shared': true, // Request shared mode
|
||||
'view_only': false, // Disable client mouse/keyboard
|
||||
'aten_password_sep': ':', // Separator for ATEN iKVM password fields
|
||||
'xvp_password_sep': '@', // Separator for XVP password fields
|
||||
'disconnectTimeout': 3, // Time (s) to wait for disconnection
|
||||
'wsProtocols': ['binary', 'base64'], // Protocols to use in the WebSocket connection
|
||||
|
|
@ -334,9 +338,12 @@ var RFB;
|
|||
this._FBU.lines = 0; // RAW
|
||||
this._FBU.tiles = 0; // HEXTILE
|
||||
this._FBU.zlibs = []; // TIGHT zlib encoders
|
||||
this._FBU.aten_len = -1 // ATEN
|
||||
this._FBU.aten_type = -1; // ATEN
|
||||
this._mouse_buttonMask = 0;
|
||||
this._mouse_arr = [];
|
||||
this._rfb_tightvnc = false;
|
||||
this._rfb_atenikvm = false;
|
||||
|
||||
// Clear the per connection encoding stats
|
||||
var i;
|
||||
|
|
@ -690,6 +697,36 @@ var RFB;
|
|||
},
|
||||
|
||||
// authentication
|
||||
_negotiate_aten_auth: function () {
|
||||
var aten_sep = this._aten_password_sep;
|
||||
var aten_auth = this._rfb_password.split(aten_sep);
|
||||
if (aten_auth.length < 2) {
|
||||
this._updateState('password', 'ATEN iKVM credentials required (user' + aten_sep +
|
||||
'password) -- got only ' + this._rfb_password);
|
||||
this._onPasswordRequired(this);
|
||||
return false;
|
||||
}
|
||||
|
||||
this._rfb_atenikvm = true;
|
||||
|
||||
if (this._rfb_tightvnc) {
|
||||
this._rfb_tightvnc = false;
|
||||
} else {
|
||||
this._sock.rQskipBytes(4);
|
||||
}
|
||||
|
||||
this._sock.rQskipBytes(16);
|
||||
|
||||
var username = aten_auth[0];
|
||||
username += Array(24-username.length+1).join("\x00");
|
||||
var password = aten_auth.slice(1).join(aten_sep);
|
||||
password += Array(24-password.length+1).join("\x00");
|
||||
|
||||
this._sock.send_string(username+password);
|
||||
this._updateState("SecurityResult");
|
||||
return true;
|
||||
},
|
||||
|
||||
_negotiate_xvp_auth: function () {
|
||||
var xvp_sep = this._xvp_password_sep;
|
||||
var xvp_auth = this._rfb_password.split(xvp_sep);
|
||||
|
|
@ -757,6 +794,7 @@ var RFB;
|
|||
if (!this._rfb_tightvnc) { // first pass, do the tunnel negotiation
|
||||
if (this._sock.rQwait("num tunnels", 4)) { return false; }
|
||||
var numTunnels = this._sock.rQshift32();
|
||||
if (this._rfb_version === 3.8 && (numTunnels & 0xffff0ff0) >>> 0 === 0xaff90fb0) { return this._negotiate_aten_auth(); }
|
||||
if (numTunnels > 0 && this._sock.rQwait("tunnel capabilities", 16 * numTunnels, 4)) { return false; }
|
||||
|
||||
this._rfb_tightvnc = true;
|
||||
|
|
@ -772,6 +810,12 @@ var RFB;
|
|||
var subAuthCount = this._sock.rQshift32();
|
||||
if (this._sock.rQwait("sub auth capabilities", 16 * subAuthCount, 4)) { return false; }
|
||||
|
||||
// Newer X10 Supermicro motherboards get here
|
||||
if (this._rfb_version === 3.8 && numTunnels === 0 && subAuthCount === 0) {
|
||||
Util.Warn("Newer ATEN iKVM detected, you may get an 'unsupported encoding 87'");
|
||||
return this._negotiate_aten_auth();
|
||||
}
|
||||
|
||||
var clientSupportedTypes = {
|
||||
'STDVNOAUTH__': 1,
|
||||
'STDVVNCAUTH_': 2
|
||||
|
|
@ -858,23 +902,24 @@ var RFB;
|
|||
|
||||
_negotiate_server_init: function () {
|
||||
if (this._sock.rQwait("server initialization", 24)) { return false; }
|
||||
if (this._rfb_atenikvm && this._sock.rQwait("ATEN server initialization", 36)) { return false; }
|
||||
|
||||
/* Screen size */
|
||||
this._fb_width = this._sock.rQshift16();
|
||||
this._fb_height = this._sock.rQshift16();
|
||||
this._fb_width = this._sock.rQshift16();
|
||||
this._fb_height = this._sock.rQshift16();
|
||||
|
||||
/* PIXEL_FORMAT */
|
||||
var bpp = this._sock.rQshift8();
|
||||
var depth = this._sock.rQshift8();
|
||||
var big_endian = this._sock.rQshift8();
|
||||
var true_color = this._sock.rQshift8();
|
||||
this._pixelFormat.bpp = this._sock.rQshift8();
|
||||
this._pixelFormat.depth = this._sock.rQshift8();
|
||||
this._pixelFormat.big_endian = (this._sock.rQshift8() === 1) ? true : false;
|
||||
this._pixelFormat.true_color = (this._sock.rQshift8() === 1) ? true : false;
|
||||
|
||||
var red_max = this._sock.rQshift16();
|
||||
var green_max = this._sock.rQshift16();
|
||||
var blue_max = this._sock.rQshift16();
|
||||
var red_shift = this._sock.rQshift8();
|
||||
var green_shift = this._sock.rQshift8();
|
||||
var blue_shift = this._sock.rQshift8();
|
||||
this._pixelFormat.red_max = this._sock.rQshift16();
|
||||
this._pixelFormat.green_max = this._sock.rQshift16();
|
||||
this._pixelFormat.blue_max = this._sock.rQshift16();
|
||||
this._pixelFormat.red_shift = this._sock.rQshift8();
|
||||
this._pixelFormat.green_shift = this._sock.rQshift8();
|
||||
this._pixelFormat.blue_shift = this._sock.rQshift8();
|
||||
this._sock.rQskipBytes(3); // padding
|
||||
|
||||
// NB(directxman12): we don't want to call any callbacks or print messages until
|
||||
|
|
@ -885,6 +930,14 @@ var RFB;
|
|||
if (this._sock.rQwait('server init name', name_length, 24)) { return false; }
|
||||
this._fb_name = Util.decodeUTF8(this._sock.rQshiftStr(name_length));
|
||||
|
||||
if (this._rfb_atenikvm) {
|
||||
this._sock.rQskipBytes(8); // unknown
|
||||
this._sock.rQskip8(); // IKVMVideoEnable
|
||||
this._sock.rQskip8(); // IKVMKMEnable
|
||||
this._sock.rQskip8(); // IKVMKickEnable
|
||||
this._sock.rQskip8(); // VUSBEnable
|
||||
}
|
||||
|
||||
if (this._rfb_tightvnc) {
|
||||
if (this._sock.rQwait('TightVNC extended server init header', 8, 24 + name_length)) { return false; }
|
||||
// In TightVNC mode, ServerInit message is extended
|
||||
|
|
@ -913,56 +966,167 @@ var RFB;
|
|||
// NB(directxman12): these are down here so that we don't run them multiple times
|
||||
// if we backtrack
|
||||
Util.Info("Screen: " + this._fb_width + "x" + this._fb_height +
|
||||
", bpp: " + bpp + ", depth: " + depth +
|
||||
", big_endian: " + big_endian +
|
||||
", true_color: " + true_color +
|
||||
", red_max: " + red_max +
|
||||
", green_max: " + green_max +
|
||||
", blue_max: " + blue_max +
|
||||
", red_shift: " + red_shift +
|
||||
", green_shift: " + green_shift +
|
||||
", blue_shift: " + blue_shift);
|
||||
|
||||
if (big_endian !== 0) {
|
||||
Util.Warn("Server native endian is not little endian");
|
||||
}
|
||||
|
||||
if (red_shift !== 16) {
|
||||
Util.Warn("Server native red-shift is not 16");
|
||||
}
|
||||
|
||||
if (blue_shift !== 0) {
|
||||
Util.Warn("Server native blue-shift is not 0");
|
||||
}
|
||||
", bpp: " + this._pixelFormat.bpp + ", depth: " + this._pixelFormat.depth +
|
||||
", big_endian: " + this._pixelFormat.big_endian +
|
||||
", true_color: " + this._pixelFormat.true_color +
|
||||
", red_max: " + this._pixelFormat.red_max +
|
||||
", green_max: " + this._pixelFormat.green_max +
|
||||
", blue_max: " + this._pixelFormat.blue_max +
|
||||
", red_shift: " + this._pixelFormat.red_shift +
|
||||
", green_shift: " + this._pixelFormat.green_shift +
|
||||
", blue_shift: " + this._pixelFormat.blue_shift);
|
||||
|
||||
// we're past the point where we could backtrack, so it's safe to call this
|
||||
this._onDesktopName(this, this._fb_name);
|
||||
|
||||
if (this._true_color && this._fb_name === "Intel(r) AMT KVM") {
|
||||
Util.Warn("Intel AMT KVM only supports 8/16 bit depths. Disabling true color");
|
||||
this._true_color = false;
|
||||
if (this._fb_name === "Intel(r) AMT KVM") {
|
||||
Util.Warn("Intel AMT KVM only supports 8/16 bit depths, using server pixel format");
|
||||
this._convertColor = true;
|
||||
}
|
||||
|
||||
this._display.set_true_color(this._true_color);
|
||||
// ATEN 'wisdom' from chicken-aten-ikvm:lens/lens.rb
|
||||
// tested against the following Supermicro motherboards
|
||||
// (use 'dmidecode -s baseboard-product-name' for model):
|
||||
// - X7SPA-F
|
||||
// - X8DTL
|
||||
// - X8SIE-F
|
||||
// - X9SCL/X9SCM
|
||||
// - X9SCM-F
|
||||
// - X9DRD-iF
|
||||
// - X9SRE/X9SRE-3F/X9SRi/X9SRi-3F
|
||||
// - X9DRL-3F/X9DRL-6F
|
||||
// - X10SLD
|
||||
//
|
||||
// Not supported (uses encoding 87):
|
||||
// - X10SL7-F
|
||||
// - X10SLD-F
|
||||
// - X10SLM-F
|
||||
// - X10SLE
|
||||
//
|
||||
// Simply does not work:
|
||||
// Hermon (WPMC450) [hangs at login]:
|
||||
// - X7SB3-F
|
||||
// - X8DTU-F
|
||||
// - X8STi-3F
|
||||
// Peppercon (Raritan/Kira100) [connection refused]:
|
||||
// - X7SBi
|
||||
//
|
||||
// Thanks to Brian Rak and Erik Smit for testing
|
||||
if (this._rfb_atenikvm) {
|
||||
// we do not know the resolution till the first fbupdate so go large
|
||||
// although, not necessary, saves a pointless full screen refresh
|
||||
this._fb_width = 10000;
|
||||
this._fb_height = 10000;
|
||||
|
||||
// lies about what it supports
|
||||
Util.Warn("ATEN iKVM lies and only does 15 bit depth with RGB555");
|
||||
this._convertColor = true;
|
||||
this._pixelFormat.bpp = 16;
|
||||
this._pixelFormat.depth = 15;
|
||||
this._pixelFormat.red_max = (1 << 5) - 1;
|
||||
this._pixelFormat.green_max = (1 << 5) - 1;
|
||||
this._pixelFormat.blue_max = (1 << 5) - 1;
|
||||
this._pixelFormat.red_shift = 10;
|
||||
this._pixelFormat.green_shift = 5;
|
||||
this._pixelFormat.blue_shift = 0;
|
||||
|
||||
// changes to protocol format
|
||||
RFB.messages.keyEvent = function (keysym, down) {
|
||||
if (XK2HID[keysym] === undefined) {
|
||||
Util.Warn("XK2HID["+keysym+"] returns undefined");
|
||||
return;
|
||||
}
|
||||
|
||||
var arr = [4];
|
||||
arr.push8(0);
|
||||
arr.push8(down);
|
||||
arr.push16(0);
|
||||
arr.push32(XK2HID[keysym]);
|
||||
arr.push32(0);
|
||||
arr.push32(0);
|
||||
arr.push8(0);
|
||||
return arr;
|
||||
};
|
||||
RFB.messages.pointerEvent = function (x, y, mask) {
|
||||
var arr = [5];
|
||||
arr.push8(0);
|
||||
arr.push8(mask);
|
||||
arr.push16(x);
|
||||
arr.push16(y);
|
||||
arr.push32(0);
|
||||
arr.push32(0);
|
||||
arr.push16(0);
|
||||
arr.push8(0);
|
||||
return arr;
|
||||
};
|
||||
}
|
||||
|
||||
if (this._convertColor)
|
||||
this._display.set_true_color(this._pixelFormat.true_color);
|
||||
this._onFBResize(this, this._fb_width, this._fb_height);
|
||||
this._display.resize(this._fb_width, this._fb_height);
|
||||
this._keyboard.grab();
|
||||
this._mouse.grab();
|
||||
|
||||
if (this._true_color) {
|
||||
this._fb_Bpp = 4;
|
||||
this._fb_depth = 3;
|
||||
} else {
|
||||
this._fb_Bpp = 1;
|
||||
this._fb_depth = 1;
|
||||
var response = [];
|
||||
|
||||
// only send if not native, and we think the server will honor the conversion
|
||||
if (!this._convertColor) {
|
||||
if (this._pixelFormat.big_endian !== false
|
||||
|| this._pixelFormat.red_max !== 255
|
||||
|| this._pixelFormat.green_max !== 255
|
||||
|| this._pixelFormat.blue_max !== 255
|
||||
|| this._pixelFormat.red_shift !== 16
|
||||
|| this._pixelFormat.green_shift !== 8
|
||||
|| this._pixelFormat.blue_shift !== 0
|
||||
|| !( this._pixelFormat.bpp === 32
|
||||
&& this._pixelFormat.depth === 24
|
||||
&& this._pixelFormat.true_color === true )
|
||||
|| !( this._pixelFormat.bpp === 8
|
||||
&& this._pixelFormat.depth === 8
|
||||
&& this._pixelFormat.true_color === false )) {
|
||||
this._pixelFormat.big_endian = false;
|
||||
this._pixelFormat.red_max = 255;
|
||||
this._pixelFormat.green_max = 255;
|
||||
this._pixelFormat.blue_max = 255;
|
||||
this._pixelFormat.red_shift = 16;
|
||||
this._pixelFormat.green_shift = 8;
|
||||
this._pixelFormat.blue_shift = 0;
|
||||
if (this._pixelFormat.true_color) {
|
||||
this._pixelFormat.bpp = 32;
|
||||
this._pixelFormat.depth = 24;
|
||||
} else {
|
||||
this._pixelFormat.bpp = 8;
|
||||
this._pixelFormat.depth = 8;
|
||||
}
|
||||
response = response.concat(RFB.messages.pixelFormat(this._pixelFormat));
|
||||
} else {
|
||||
Util.Warn("Server pixel format matches our preferred native, disabling color conversion");
|
||||
this._convertColor = false;
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
this._pixelFormat.Bpp = this._pixelFormat.bpp / 8;
|
||||
this._pixelFormat.Bdepth = Math.ceil(this._pixelFormat.depth / 8);
|
||||
|
||||
if (this._pixelFormat.bpp < this._pixelFormat.depth) {
|
||||
return this._fail('server claims greater depth than bpp');
|
||||
}
|
||||
|
||||
if (this._pixelFormat.true_color
|
||||
&& this._pixelFormat.depth >
|
||||
Math.ceil(Math.log(this._pixelFormat.red_max)/Math.LN2)
|
||||
+ Math.ceil(Math.log(this._pixelFormat.green_max)/Math.LN2)
|
||||
+ Math.ceil(Math.log(this._pixelFormat.blue_max)/Math.LN2)) {
|
||||
return this._fail('server claims greater depth than sum of RGB maximums');
|
||||
}
|
||||
|
||||
response = response.concat(RFB.messages.clientEncodings(
|
||||
this._encodings, this._local_cursor,
|
||||
this._pixelFormat.true_color));
|
||||
response = response.concat(RFB.messages.fbUpdateRequests(
|
||||
this._display.getCleanDirtyReset(),
|
||||
this._fb_width, this._fb_height));
|
||||
|
||||
this._timing.fbu_rt_start = (new Date()).getTime();
|
||||
this._timing.pixels = 0;
|
||||
|
|
@ -1066,6 +1230,42 @@ var RFB;
|
|||
msg_type = this._sock.rQshift8();
|
||||
}
|
||||
|
||||
if (this._rfb_atenikvm) {
|
||||
switch (msg_type) {
|
||||
case 4: // Front Ground Event
|
||||
Util.Debug("ATEN iKVM Front Ground Event");
|
||||
this._sock.rQskipBytes(20);
|
||||
return true;
|
||||
|
||||
case 22: // Keep Alive Event
|
||||
Util.Debug("ATEN iKVM Keep Alive Event");
|
||||
this._sock.rQskipBytes(1);
|
||||
return true;
|
||||
|
||||
case 51: // Video Get Info
|
||||
Util.Debug("ATEN iKVM Video Get Info");
|
||||
this._sock.rQskipBytes(4);
|
||||
return true;
|
||||
|
||||
case 55: // Mouse Get Info
|
||||
Util.Debug("ATEN iKVM Mouse Get Info");
|
||||
this._sock.rQskipBytes(2);
|
||||
return true;
|
||||
|
||||
case 57: // Session Message
|
||||
Util.Debug("ATEN iKVM Session Message");
|
||||
this._sock.rQskipBytes(4); // u32
|
||||
this._sock.rQskipBytes(4); // u32
|
||||
this._sock.rQskipBytes(256);
|
||||
return true;
|
||||
|
||||
case 60: // Get Viewer Lang
|
||||
Util.Debug("ATEN iKVM Get Viewer Lang");
|
||||
this._sock.rQskipBytes(8);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
switch (msg_type) {
|
||||
case 0: // FramebufferUpdate
|
||||
var ret = this._framebufferUpdate();
|
||||
|
|
@ -1139,6 +1339,11 @@ var RFB;
|
|||
this._FBU.encoding);
|
||||
return false;
|
||||
}
|
||||
|
||||
// ATEN uses 0x00 even when it is meant to be 0x59
|
||||
if (this._rfb_atenikvm && this._FBU.encoding === 0x00) {
|
||||
this._FBU.encoding = 0x59;
|
||||
}
|
||||
}
|
||||
|
||||
this._timing.last_fbu = (new Date()).getTime();
|
||||
|
|
@ -1190,16 +1395,62 @@ var RFB;
|
|||
|
||||
return true; // We finished this FBU
|
||||
},
|
||||
|
||||
// input: byte stream in pixel format
|
||||
// output: RGB
|
||||
_convert_color: function (arr, Bpp) {
|
||||
if (Bpp === undefined)
|
||||
Bpp = this._pixelFormat.Bpp;
|
||||
|
||||
if (!this._convertColor
|
||||
// HACK? Xtightvnc needs this and I have no idea why
|
||||
|| (this._FBU.encoding === 0x07 && this._pixelFormat.depth === 24)) {
|
||||
switch (Bpp) {
|
||||
case 4:
|
||||
for (var i = arr.length; i > 0; i -= 4) {
|
||||
arr.splice(i - 1, 1); // convert from RGBX to RGB
|
||||
}
|
||||
case 3:
|
||||
return arr;
|
||||
default:
|
||||
Util.Error('convert color disabled, but Bpp is not 3 or 4!');
|
||||
}
|
||||
}
|
||||
|
||||
var data = [];
|
||||
|
||||
for (var i = 0; i < arr.length; i += Bpp) {
|
||||
var pix = 0;
|
||||
|
||||
for (var j = 0; j < Bpp; j++) {
|
||||
if (this._pixelFormat.big_endian) {
|
||||
pix = (pix << 8) | arr[i + j];
|
||||
} else {
|
||||
pix = (arr[i + j] << (j*8)) | pix;
|
||||
}
|
||||
}
|
||||
|
||||
data.push(((pix >>> this._pixelFormat.red_shift) & this._pixelFormat.red_max)
|
||||
* (256/(this._pixelFormat.red_max + 1)));
|
||||
data.push(((pix >>> this._pixelFormat.green_shift) & this._pixelFormat.green_max)
|
||||
* (256/(this._pixelFormat.green_max + 1)));
|
||||
data.push(((pix >>> this._pixelFormat.blue_shift) & this._pixelFormat.blue_max)
|
||||
* (256/(this._pixelFormat.blue_max + 1)));
|
||||
}
|
||||
|
||||
return data;
|
||||
},
|
||||
};
|
||||
|
||||
Util.make_properties(RFB, [
|
||||
['target', 'wo', 'dom'], // VNC display rendering Canvas object
|
||||
['focusContainer', 'wo', 'dom'], // DOM element that captures keyboard input
|
||||
['encrypt', 'rw', 'bool'], // Use TLS/SSL/wss encryption
|
||||
['true_color', 'rw', 'bool'], // Request true color pixel data
|
||||
['convertColor', 'rw', 'bool'], // Client will not honor request for native color
|
||||
['local_cursor', 'rw', 'bool'], // Request locally rendered cursor
|
||||
['shared', 'rw', 'bool'], // Request shared mode
|
||||
['view_only', 'rw', 'bool'], // Disable client mouse/keyboard
|
||||
['aten_password_sep', 'rw', 'str'], // Separator for ATEN iKVM password fields
|
||||
['xvp_password_sep', 'rw', 'str'], // Separator for XVP password fields
|
||||
['disconnectTimeout', 'rw', 'int'], // Time (s) to wait for disconnection
|
||||
['wsProtocols', 'rw', 'arr'], // Protocols to use in the WebSocket connection
|
||||
|
|
@ -1268,23 +1519,23 @@ var RFB;
|
|||
return arr;
|
||||
},
|
||||
|
||||
pixelFormat: function (bpp, depth, true_color) {
|
||||
pixelFormat: function (pf) {
|
||||
var arr = [0]; // msg-type
|
||||
arr.push8(0); // padding
|
||||
arr.push8(0); // padding
|
||||
arr.push8(0); // padding
|
||||
|
||||
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
|
||||
arr.push8(pf.bpp);
|
||||
arr.push8(pf.depth);
|
||||
arr.push8(pf.big_endian ? 1 : 0);
|
||||
arr.push8(pf.true_color ? 1 : 0);
|
||||
|
||||
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
|
||||
arr.push16(pf.red_max);
|
||||
arr.push16(pf.green_max);
|
||||
arr.push16(pf.blue_max);
|
||||
arr.push8(pf.red_shift);
|
||||
arr.push8(pf.green_shift);
|
||||
arr.push8(pf.blue_shift);
|
||||
|
||||
arr.push8(0); // padding
|
||||
arr.push8(0); // padding
|
||||
|
|
@ -1373,19 +1624,25 @@ var RFB;
|
|||
this._FBU.lines = this._FBU.height;
|
||||
}
|
||||
|
||||
this._FBU.bytes = this._FBU.width * this._fb_Bpp; // at least a line
|
||||
this._FBU.bytes = this._FBU.width * this._pixelFormat.Bpp; // at least a line
|
||||
if (this._sock.rQwait("RAW", this._FBU.bytes)) { return false; }
|
||||
var cur_y = this._FBU.y + (this._FBU.height - this._FBU.lines);
|
||||
var curr_height = Math.min(this._FBU.lines,
|
||||
Math.floor(this._sock.rQlen() / (this._FBU.width * this._fb_Bpp)));
|
||||
this._display.blitImage(this._FBU.x, cur_y, this._FBU.width,
|
||||
curr_height, this._sock.get_rQ(),
|
||||
this._sock.get_rQi());
|
||||
this._sock.rQskipBytes(this._FBU.width * curr_height * this._fb_Bpp);
|
||||
Math.floor(this._sock.rQlen() / (this._FBU.width * this._pixelFormat.Bpp)));
|
||||
|
||||
this._display.renderQ_push({
|
||||
'type': 'blit',
|
||||
'data': this._convert_color(this._sock.rQshiftBytes(curr_height * this._FBU.width * this._pixelFormat.Bpp)),
|
||||
'x': this._FBU.x,
|
||||
'y': cur_y,
|
||||
'width': this._FBU.width,
|
||||
'height': curr_height
|
||||
});
|
||||
|
||||
this._FBU.lines -= curr_height;
|
||||
|
||||
if (this._FBU.lines > 0) {
|
||||
this._FBU.bytes = this._FBU.width * this._fb_Bpp; // At least another line
|
||||
this._FBU.bytes = this._FBU.width * this._pixelFormat.Bpp; // At least another line
|
||||
} else {
|
||||
this._FBU.rects--;
|
||||
this._FBU.bytes = 0;
|
||||
|
|
@ -1414,15 +1671,15 @@ var RFB;
|
|||
RRE: function () {
|
||||
var color;
|
||||
if (this._FBU.subrects === 0) {
|
||||
this._FBU.bytes = 4 + this._fb_Bpp;
|
||||
if (this._sock.rQwait("RRE", 4 + this._fb_Bpp)) { return false; }
|
||||
this._FBU.bytes = 4 + this._pixelFormat.Bpp;
|
||||
if (this._sock.rQwait("RRE", 4 + this._pixelFormat.Bpp)) { return false; }
|
||||
this._FBU.subrects = this._sock.rQshift32();
|
||||
color = this._sock.rQshiftBytes(this._fb_Bpp); // Background
|
||||
color = this._convert_color(this._sock.rQshiftBytes(this._pixelFormat.Bpp)).reverse(); // Background
|
||||
this._display.fillRect(this._FBU.x, this._FBU.y, this._FBU.width, this._FBU.height, color);
|
||||
}
|
||||
|
||||
while (this._FBU.subrects > 0 && this._sock.rQlen() >= (this._fb_Bpp + 8)) {
|
||||
color = this._sock.rQshiftBytes(this._fb_Bpp);
|
||||
while (this._FBU.subrects > 0 && this._sock.rQlen() >= (this._pixelFormat.Bpp + 8)) {
|
||||
color = this._convert_color(this._sock.rQshiftBytes(this._pixelFormat.Bpp)).reverse();
|
||||
var x = this._sock.rQshift16();
|
||||
var y = this._sock.rQshift16();
|
||||
var width = this._sock.rQshift16();
|
||||
|
|
@ -1433,7 +1690,7 @@ var RFB;
|
|||
|
||||
if (this._FBU.subrects > 0) {
|
||||
var chunk = Math.min(this._rre_chunk_sz, this._FBU.subrects);
|
||||
this._FBU.bytes = (this._fb_Bpp + 8) * chunk;
|
||||
this._FBU.bytes = (this._pixelFormat.Bpp + 8) * chunk;
|
||||
} else {
|
||||
this._FBU.rects--;
|
||||
this._FBU.bytes = 0;
|
||||
|
|
@ -1473,20 +1730,20 @@ var RFB;
|
|||
|
||||
// Figure out how much we are expecting
|
||||
if (subencoding & 0x01) { // Raw
|
||||
this._FBU.bytes += w * h * this._fb_Bpp;
|
||||
this._FBU.bytes += w * h * this._pixelFormat.Bpp;
|
||||
} else {
|
||||
if (subencoding & 0x02) { // Background
|
||||
this._FBU.bytes += this._fb_Bpp;
|
||||
this._FBU.bytes += this._pixelFormat.Bpp;
|
||||
}
|
||||
if (subencoding & 0x04) { // Foreground
|
||||
this._FBU.bytes += this._fb_Bpp;
|
||||
this._FBU.bytes += this._pixelFormat.Bpp;
|
||||
}
|
||||
if (subencoding & 0x08) { // AnySubrects
|
||||
this._FBU.bytes++; // Since we aren't shifting it off
|
||||
if (this._sock.rQwait("hextile subrects header", this._FBU.bytes)) { return false; }
|
||||
subrects = rQ[rQi + this._FBU.bytes - 1]; // Peek
|
||||
if (subencoding & 0x10) { // SubrectsColoured
|
||||
this._FBU.bytes += subrects * (this._fb_Bpp + 2);
|
||||
this._FBU.bytes += subrects * (this._pixelFormat.Bpp + 2);
|
||||
} else {
|
||||
this._FBU.bytes += subrects * 2;
|
||||
}
|
||||
|
|
@ -1506,16 +1763,23 @@ var RFB;
|
|||
this._display.fillRect(x, y, w, h, this._FBU.background);
|
||||
}
|
||||
} else if (this._FBU.subencoding & 0x01) { // Raw
|
||||
this._display.blitImage(x, y, w, h, rQ, rQi);
|
||||
this._display.renderQ_push({
|
||||
'type': 'blit',
|
||||
'data': this._convert_color(rQ.slice(rQi, rQi + this._FBU.bytes - 1)),
|
||||
'x': x,
|
||||
'y': y,
|
||||
'width': w,
|
||||
'height': h
|
||||
});
|
||||
rQi += this._FBU.bytes - 1;
|
||||
} else {
|
||||
if (this._FBU.subencoding & 0x02) { // Background
|
||||
this._FBU.background = rQ.slice(rQi, rQi + this._fb_Bpp);
|
||||
rQi += this._fb_Bpp;
|
||||
this._FBU.background = this._convert_color(rQ.slice(rQi, rQi + this._pixelFormat.Bpp)).reverse();
|
||||
rQi += this._pixelFormat.Bpp;
|
||||
}
|
||||
if (this._FBU.subencoding & 0x04) { // Foreground
|
||||
this._FBU.foreground = rQ.slice(rQi, rQi + this._fb_Bpp);
|
||||
rQi += this._fb_Bpp;
|
||||
this._FBU.foreground = this._convert_color(rQ.slice(rQi, rQi + this._pixelFormat.Bpp)).reverse();
|
||||
rQi += this._pixelFormat.Bpp;
|
||||
}
|
||||
|
||||
this._display.startTile(x, y, w, h, this._FBU.background);
|
||||
|
|
@ -1526,8 +1790,8 @@ var RFB;
|
|||
for (var s = 0; s < subrects; s++) {
|
||||
var color;
|
||||
if (this._FBU.subencoding & 0x10) { // SubrectsColoured
|
||||
color = rQ.slice(rQi, rQi + this._fb_Bpp);
|
||||
rQi += this._fb_Bpp;
|
||||
color = this._convert_color(rQ.slice(rQi, rQi + this._pixelFormat.Bpp)).reverse();
|
||||
rQi += this._pixelFormat.Bpp;
|
||||
} else {
|
||||
color = this._FBU.foreground;
|
||||
}
|
||||
|
|
@ -1574,7 +1838,7 @@ var RFB;
|
|||
},
|
||||
|
||||
display_tight: function (isTightPNG) {
|
||||
if (this._fb_depth === 1) {
|
||||
if (this._pixelFormat.Bdepth === 1) {
|
||||
this._fail("Tight protocol handler only implements true color mode");
|
||||
}
|
||||
|
||||
|
|
@ -1658,7 +1922,7 @@ var RFB;
|
|||
|
||||
var handlePalette = function () {
|
||||
var numColors = rQ[rQi + 2] + 1;
|
||||
var paletteSize = numColors * this._fb_depth;
|
||||
var paletteSize = numColors * this._pixelFormat.Bdepth;
|
||||
this._FBU.bytes += paletteSize;
|
||||
if (this._sock.rQwait("TIGHT palette " + cmode, this._FBU.bytes)) { return false; }
|
||||
|
||||
|
|
@ -1678,7 +1942,7 @@ var RFB;
|
|||
|
||||
// Shift ctl, filter id, num colors, palette entries, and clength off
|
||||
this._sock.rQskipBytes(3);
|
||||
var palette = this._sock.rQshiftBytes(paletteSize);
|
||||
var palette = this._convert_color(this._sock.rQshiftBytes(paletteSize), this._pixelFormat.Bdepth);
|
||||
this._sock.rQskipBytes(clength[0]);
|
||||
|
||||
if (raw) {
|
||||
|
|
@ -1691,7 +1955,7 @@ var RFB;
|
|||
var rgb = indexedToRGB(data, numColors, palette, this._FBU.width, this._FBU.height);
|
||||
|
||||
this._display.renderQ_push({
|
||||
'type': 'blitRgb',
|
||||
'type': 'blit',
|
||||
'data': rgb,
|
||||
'x': this._FBU.x,
|
||||
'y': this._FBU.y,
|
||||
|
|
@ -1704,7 +1968,7 @@ var RFB;
|
|||
|
||||
var handleCopy = function () {
|
||||
var raw = false;
|
||||
var uncompressedSize = this._FBU.width * this._FBU.height * this._fb_depth;
|
||||
var uncompressedSize = this._FBU.width * this._FBU.height * this._pixelFormat.Bdepth;
|
||||
if (uncompressedSize < 12) {
|
||||
raw = true;
|
||||
clength = [0, uncompressedSize];
|
||||
|
|
@ -1724,8 +1988,8 @@ var RFB;
|
|||
}
|
||||
|
||||
this._display.renderQ_push({
|
||||
'type': 'blitRgb',
|
||||
'data': data,
|
||||
'type': 'blit',
|
||||
'data': this._convert_color(data, this._pixelFormat.Bdepth),
|
||||
'x': this._FBU.x,
|
||||
'y': this._FBU.y,
|
||||
'width': this._FBU.width,
|
||||
|
|
@ -1758,7 +2022,7 @@ var RFB;
|
|||
switch (cmode) {
|
||||
// fill use fb_depth because TPIXELs drop the padding byte
|
||||
case "fill": // TPIXEL
|
||||
this._FBU.bytes += this._fb_depth;
|
||||
this._FBU.bytes += this._pixelFormat.Bdepth;
|
||||
break;
|
||||
case "jpeg": // max clength
|
||||
this._FBU.bytes += 3;
|
||||
|
|
@ -1779,14 +2043,13 @@ var RFB;
|
|||
switch (cmode) {
|
||||
case "fill":
|
||||
this._sock.rQskip8(); // shift off ctl
|
||||
var color = this._sock.rQshiftBytes(this._fb_depth);
|
||||
this._display.renderQ_push({
|
||||
'type': 'fill',
|
||||
'x': this._FBU.x,
|
||||
'y': this._FBU.y,
|
||||
'width': this._FBU.width,
|
||||
'height': this._FBU.height,
|
||||
'color': [color[2], color[1], color[0]]
|
||||
'color': this._convert_color(this._sock.rQshiftBytes(this._pixelFormat.Bdepth), this._pixelFormat.Bdepth).reverse(),
|
||||
});
|
||||
break;
|
||||
case "png":
|
||||
|
|
@ -1861,7 +2124,7 @@ var RFB;
|
|||
var w = this._FBU.width;
|
||||
var h = this._FBU.height;
|
||||
|
||||
var pixelslength = w * h * this._fb_Bpp;
|
||||
var pixelslength = w * h * this._pixelFormat.Bpp;
|
||||
var masklength = Math.floor((w + 7) / 8) * h;
|
||||
|
||||
this._FBU.bytes = pixelslength + masklength;
|
||||
|
|
@ -1884,6 +2147,92 @@ var RFB;
|
|||
|
||||
compress_lo: function () {
|
||||
Util.Error("Server sent compress level pseudo-encoding");
|
||||
},
|
||||
|
||||
ATEN: function () {
|
||||
if (this._FBU.aten_len === - 1) {
|
||||
this._FBU.bytes = 8;
|
||||
if (this._sock.rQwait("ATEN", this._FBU.bytes)) { return false; }
|
||||
this._FBU.bytes = 0;
|
||||
this._sock.rQskipBytes(4);
|
||||
this._FBU.aten_len = this._sock.rQshift32();
|
||||
|
||||
if (this._FBU.width === 64896 && this._FBU.height === 65056) {
|
||||
Util.Info("ATEN iKVM screen is probably off");
|
||||
if (this._FBU.aten_len !== 10) {
|
||||
Util.Debug(">> ATEN iKVM screen off (aten_len="+this._FBU.aten_len+")");
|
||||
this._fail('expected aten_len to be 10 when screen is off');
|
||||
}
|
||||
this._FBU.aten_len -= 10;
|
||||
return true;
|
||||
}
|
||||
if (this._fb_width !== this._FBU.width && this._fb_height !== this._FBU.height) {
|
||||
Util.Debug(">> ATEN resize desktop");
|
||||
this._fb_width = this._FBU.width;
|
||||
this._fb_height = this._FBU.height;
|
||||
this._onFBResize(this, this._fb_width, this._fb_height);
|
||||
this._display.resize(this._fb_width, this._fb_height);
|
||||
Util.Debug("<< ATEN resize desktop");
|
||||
}
|
||||
}
|
||||
|
||||
if (this._FBU.aten_type === -1) {
|
||||
this._FBU.bytes = 10;
|
||||
if (this._sock.rQwait("ATEN", this._FBU.bytes)) { return false; }
|
||||
this._FBU.bytes = 0;
|
||||
this._FBU.aten_type = this._sock.rQshift8();
|
||||
this._sock.rQskip8();
|
||||
|
||||
this._sock.rQshift32(); // number of subrects
|
||||
if (this._FBU.aten_len !== this._sock.rQshift32()) {
|
||||
return this._fail('ATEN RAW len mis-match');
|
||||
}
|
||||
this._FBU.aten_len -= 10;
|
||||
}
|
||||
|
||||
while (this._FBU.aten_len > 0) {
|
||||
switch (this._FBU.aten_type) {
|
||||
case 0: // Subrects
|
||||
this._FBU.bytes = 6 + (16 * 16 * this._pixelFormat.Bpp); // at least a subrect
|
||||
if (this._sock.rQwait("ATEN", this._FBU.bytes)) { return false; }
|
||||
var a = this._sock.rQshift16();
|
||||
var b = this._sock.rQshift16();
|
||||
var y = this._sock.rQshift8();
|
||||
var x = this._sock.rQshift8();
|
||||
this._display.renderQ_push({
|
||||
'type': 'blit',
|
||||
'data': this._convert_color(this._sock.rQshiftBytes(this._FBU.bytes - 6)),
|
||||
'x': x * 16,
|
||||
'y': y * 16,
|
||||
'width': 16,
|
||||
'height': 16
|
||||
});
|
||||
this._FBU.aten_len -= this._FBU.bytes;
|
||||
this._FBU.bytes = 0;
|
||||
break;
|
||||
case 1: // RAW
|
||||
var olines = (this._FBU.lines === 0) ? this._FBU.height : this._FBU.lines;
|
||||
this._encHandlers.RAW();
|
||||
this._FBU.aten_len -= (olines - this._FBU.lines) * this._FBU.width * this._pixelFormat.Bpp;
|
||||
if (this._FBU.bytes > 0) return false;
|
||||
break;
|
||||
default:
|
||||
return this._fail('unknown ATEN type: '+this._FBU.aten_type);
|
||||
}
|
||||
}
|
||||
|
||||
if (this._FBU.aten_len < 0) {
|
||||
this._fail('aten_len dropped below zero');
|
||||
}
|
||||
|
||||
if (this._FBU.aten_type === 0) {
|
||||
this._FBU.rects--;
|
||||
}
|
||||
|
||||
this._FBU.aten_len = -1;
|
||||
this._FBU.aten_type = -1;
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ var UI;
|
|||
UI.initSetting('port', port);
|
||||
UI.initSetting('password', '');
|
||||
UI.initSetting('encrypt', (window.location.protocol === "https:"));
|
||||
UI.initSetting('true_color', true);
|
||||
UI.initSetting('convertColor', false);
|
||||
UI.initSetting('cursor', !UI.isTouchDevice);
|
||||
UI.initSetting('shared', true);
|
||||
UI.initSetting('view_only', false);
|
||||
|
|
@ -419,7 +419,7 @@ var UI;
|
|||
UI.closeSettingsMenu();
|
||||
} else {
|
||||
UI.updateSetting('encrypt');
|
||||
UI.updateSetting('true_color');
|
||||
UI.updateSetting('convertColor');
|
||||
if (UI.rfb.get_display().get_cursor_uri()) {
|
||||
UI.updateSetting('cursor');
|
||||
} else {
|
||||
|
|
@ -474,7 +474,7 @@ var UI;
|
|||
settingsApply: function() {
|
||||
//Util.Debug(">> settingsApply");
|
||||
UI.saveSetting('encrypt');
|
||||
UI.saveSetting('true_color');
|
||||
UI.saveSetting('convertColor');
|
||||
if (UI.rfb.get_display().get_cursor_uri()) {
|
||||
UI.saveSetting('cursor');
|
||||
}
|
||||
|
|
@ -587,7 +587,7 @@ var UI;
|
|||
|
||||
//Util.Debug(">> updateVisualState");
|
||||
$D('noVNC_encrypt').disabled = connected;
|
||||
$D('noVNC_true_color').disabled = connected;
|
||||
$D('noVNC_convertColor').disabled = connected;
|
||||
if (UI.rfb && UI.rfb.get_display() &&
|
||||
UI.rfb.get_display().get_cursor_uri()) {
|
||||
$D('noVNC_cursor').disabled = connected;
|
||||
|
|
@ -674,7 +674,7 @@ var UI;
|
|||
}
|
||||
|
||||
UI.rfb.set_encrypt(UI.getSetting('encrypt'));
|
||||
UI.rfb.set_true_color(UI.getSetting('true_color'));
|
||||
UI.rfb.set_convertColor(UI.getSetting('convertColor'));
|
||||
UI.rfb.set_local_cursor(UI.getSetting('cursor'));
|
||||
UI.rfb.set_shared(UI.getSetting('shared'));
|
||||
UI.rfb.set_view_only(UI.getSetting('view_only'));
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
"test": "tests"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "karma start karma.conf.js"
|
||||
"test": "PATH=$PATH:node_modules/karma/bin karma start karma.conf.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
|
|
|||
|
|
@ -208,26 +208,14 @@ describe('Display/Canvas Helper', function () {
|
|||
expect(display).to.have.displayed(checked_data);
|
||||
});
|
||||
|
||||
it('should support drawing BGRX blit images with true color via #blitImage', function () {
|
||||
var data = [];
|
||||
for (var i = 0; i < 16; i++) {
|
||||
data[i * 4] = checked_data[i * 4 + 2];
|
||||
data[i * 4 + 1] = checked_data[i * 4 + 1];
|
||||
data[i * 4 + 2] = checked_data[i * 4];
|
||||
data[i * 4 + 3] = checked_data[i * 4 + 3];
|
||||
}
|
||||
display.blitImage(0, 0, 4, 4, data, 0);
|
||||
expect(display).to.have.displayed(checked_data);
|
||||
});
|
||||
|
||||
it('should support drawing RGB blit images with true color via #blitRgbImage', function () {
|
||||
it('should support drawing RGB blit images with true color via #blitImage', function () {
|
||||
var data = [];
|
||||
for (var i = 0; i < 16; i++) {
|
||||
data[i * 3] = checked_data[i * 4];
|
||||
data[i * 3 + 1] = checked_data[i * 4 + 1];
|
||||
data[i * 3 + 2] = checked_data[i * 4 + 2];
|
||||
}
|
||||
display.blitRgbImage(0, 0, 4, 4, data, 0);
|
||||
display.blitImage(0, 0, 4, 4, data, 0);
|
||||
expect(display).to.have.displayed(checked_data);
|
||||
});
|
||||
|
||||
|
|
@ -322,13 +310,6 @@ describe('Display/Canvas Helper', function () {
|
|||
expect(display.blitImage).to.have.been.calledWith(3, 4, 5, 6, [7, 8, 9], 0);
|
||||
});
|
||||
|
||||
it('should draw a blit RGB image on type "blitRgb"', function () {
|
||||
display.blitRgbImage = sinon.spy();
|
||||
display.renderQ_push({ type: 'blitRgb', x: 3, y: 4, width: 5, height: 6, data: [7, 8, 9] });
|
||||
expect(display.blitRgbImage).to.have.been.calledOnce;
|
||||
expect(display.blitRgbImage).to.have.been.calledWith(3, 4, 5, 6, [7, 8, 9], 0);
|
||||
});
|
||||
|
||||
it('should copy a region on type "copy"', function () {
|
||||
display.copyImage = sinon.spy();
|
||||
display.renderQ_push({ type: 'copy', x: 3, y: 4, width: 5, height: 6, old_x: 7, old_y: 8 });
|
||||
|
|
|
|||
|
|
@ -807,6 +807,51 @@ describe('Remote Frame Buffer Protocol Client', function() {
|
|||
expect(client._rfb_state).to.equal('failed');
|
||||
});
|
||||
});
|
||||
|
||||
describe('ATEN iKVM Authentication Handler', function () {
|
||||
var client;
|
||||
|
||||
beforeEach(function () {
|
||||
client = make_rfb();
|
||||
client.connect('host', 8675);
|
||||
client._sock._websocket._open();
|
||||
client._rfb_state = 'Security';
|
||||
client._rfb_version = 3.8;
|
||||
send_security(16, client);
|
||||
client._sock._websocket._get_sent_data(); // skip the security reply
|
||||
client._rfb_password = 'test1:test2';
|
||||
});
|
||||
|
||||
var auth = [
|
||||
116, 101, 115, 116, 49, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
116, 101, 115, 116, 50, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0];
|
||||
|
||||
it('via old style method', function () {
|
||||
client._sock._websocket._receive_data(new Uint8Array([
|
||||
0xaf, 0xf9, 0x0f, 0xb0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0]));
|
||||
expect(client._rfb_tightvnc).to.be.false;
|
||||
expect(client._rfb_atenikvm).to.be.true;
|
||||
expect(client._sock).to.have.sent(auth);
|
||||
});
|
||||
|
||||
it('via new style method', function () {
|
||||
client._sock._websocket._receive_data(new Uint8Array([
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0]));
|
||||
expect(client._rfb_tightvnc).to.be.false;
|
||||
expect(client._rfb_atenikvm).to.be.true;
|
||||
expect(client._sock).to.have.sent(auth);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('SecurityResult', function () {
|
||||
|
|
@ -925,8 +970,6 @@ describe('Remote Frame Buffer Protocol Client', function() {
|
|||
expect(client._fb_height).to.equal(84);
|
||||
});
|
||||
|
||||
// NB(sross): we just warn, not fail, for endian-ness and shifts, so we don't test them
|
||||
|
||||
it('should set the framebuffer name and call the callback', function () {
|
||||
client.set_onDesktopName(sinon.spy());
|
||||
send_server_init({ name: 'some name' }, client);
|
||||
|
|
@ -956,12 +999,21 @@ describe('Remote Frame Buffer Protocol Client', function() {
|
|||
expect(client._rfb_state).to.equal('normal');
|
||||
});
|
||||
|
||||
it('should set the true color mode on the display to the configuration variable', function () {
|
||||
client.set_true_color(false);
|
||||
sinon.spy(client._display, 'set_true_color');
|
||||
send_server_init({ true_color: 1 }, client);
|
||||
expect(client._display.set_true_color).to.have.been.calledOnce;
|
||||
expect(client._display.set_true_color).to.have.been.calledWith(false);
|
||||
it('should handle an ATEN iKVM server initialization', function () {
|
||||
client._rfb_atenikvm = true;
|
||||
send_server_init({ true_color: 1, bpp: 32 }, client);
|
||||
client._sock._websocket._receive_data(new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]));
|
||||
expect(client._pixelFormat.bpp).to.equal(16);
|
||||
expect(client._pixelFormat.depth).to.equal(15);
|
||||
expect(client._pixelFormat.red_max).to.equal(31);
|
||||
expect(client._pixelFormat.green_max).to.equal(31);
|
||||
expect(client._pixelFormat.blue_max).to.equal(31);
|
||||
expect(client._pixelFormat.red_shift).to.equal(10);
|
||||
expect(client._pixelFormat.green_shift).to.equal(5);
|
||||
expect(client._pixelFormat.blue_shift).to.equal(0);
|
||||
expect(client._pixelFormat.Bpp).to.equal(2);
|
||||
expect(client._pixelFormat.Bdepth).to.equal(2);
|
||||
expect(client._rfb_state).to.equal('normal');
|
||||
});
|
||||
|
||||
it('should call the resize callback and resize the display', function () {
|
||||
|
|
@ -985,25 +1037,30 @@ describe('Remote Frame Buffer Protocol Client', function() {
|
|||
expect(client._mouse.grab).to.have.been.calledOnce;
|
||||
});
|
||||
|
||||
it('should set the BPP and depth to 4 and 3 respectively if in true color mode', function () {
|
||||
client.set_true_color(true);
|
||||
send_server_init({}, client);
|
||||
expect(client._fb_Bpp).to.equal(4);
|
||||
expect(client._fb_depth).to.equal(3);
|
||||
it('should set the BPP and depth to 4 and 3 respectively if server can send native (true color)', function () {
|
||||
send_server_init({ true_color: 1, bpp: 8, depth: 8 }, client);
|
||||
expect(client._pixelFormat.Bpp).to.equal(4);
|
||||
expect(client._pixelFormat.Bdepth).to.equal(3);
|
||||
});
|
||||
|
||||
it('should set the BPP and depth to 1 and 1 respectively if not in true color mode', function () {
|
||||
client.set_true_color(false);
|
||||
send_server_init({}, client);
|
||||
expect(client._fb_Bpp).to.equal(1);
|
||||
expect(client._fb_depth).to.equal(1);
|
||||
it('should set the BPP and depth to 2 and 2 respectively if server cannot send native (true color)', function () {
|
||||
client.set_convertColor(true);
|
||||
send_server_init({ true_color: 1, bpp: 16, depth: 15 }, client);
|
||||
expect(client._pixelFormat.Bpp).to.equal(2);
|
||||
expect(client._pixelFormat.Bdepth).to.equal(2);
|
||||
});
|
||||
|
||||
it('should set the BPP and depth to 1 and 1 respectively if server cannot send native (not true color)', function () {
|
||||
client.set_convertColor(true);
|
||||
send_server_init({ true_color: 0, bpp: 8, depth: 8 }, client);
|
||||
expect(client._pixelFormat.Bpp).to.equal(1);
|
||||
expect(client._pixelFormat.Bdepth).to.equal(1);
|
||||
});
|
||||
|
||||
// TODO(directxman12): test the various options in this configuration matrix
|
||||
it('should reply with the pixel format, client encodings, and initial update request', function () {
|
||||
client.set_true_color(true);
|
||||
client.set_local_cursor(false);
|
||||
var expected = RFB.messages.pixelFormat(4, 3, true);
|
||||
var expected = RFB.messages.pixelFormat({ bpp: 32, depth: 24, big_endian: false, true_color: true, red_max: 255, green_max: 255, blue_max: 255, red_shift: 16, green_shift: 8, blue_shift: 0 });
|
||||
expected = expected.concat(RFB.messages.clientEncodings(client._encodings, false, true));
|
||||
var expected_cdr = { cleanBox: { x: 0, y: 0, w: 0, h: 0 },
|
||||
dirtyBoxes: [ { x: 0, y: 0, w: 27, h: 32 } ] };
|
||||
|
|
@ -1054,10 +1111,10 @@ describe('Remote Frame Buffer Protocol Client', function() {
|
|||
});
|
||||
|
||||
var target_data_arr = [
|
||||
0xff, 0x00, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255,
|
||||
0x00, 0xff, 0x00, 255, 0xff, 0x00, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255,
|
||||
0xee, 0x00, 0xff, 255, 0x00, 0xee, 0xff, 255, 0xaa, 0xee, 0xff, 255, 0xab, 0xee, 0xff, 255,
|
||||
0xee, 0x00, 0xff, 255, 0x00, 0xee, 0xff, 255, 0xaa, 0xee, 0xff, 255, 0xab, 0xee, 0xff, 255
|
||||
0xf8, 0x00, 0x00, 255, 0x00, 0xf8, 0x00, 255, 0x00, 0x00, 0xf8, 255, 0x00, 0x00, 0xf8, 255,
|
||||
0x00, 0xf8, 0x00, 255, 0xf8, 0x00, 0x00, 255, 0x00, 0x00, 0xf8, 255, 0x00, 0x00, 0xf8, 255,
|
||||
0xe8, 0x00, 0xf8, 255, 0x00, 0xe8, 0xf8, 255, 0xa8, 0xe8, 0xf8, 255, 0xa8, 0xe8, 0xf8, 255,
|
||||
0xe8, 0x00, 0xf8, 255, 0x00, 0xe8, 0xf8, 255, 0xa8, 0xe8, 0xf8, 255, 0xa8, 0xe8, 0xf8, 255
|
||||
];
|
||||
var target_data;
|
||||
|
||||
|
|
@ -1206,22 +1263,95 @@ describe('Remote Frame Buffer Protocol Client', function() {
|
|||
client._display._fb_height = 4;
|
||||
client._display._viewportLoc.w = 4;
|
||||
client._display._viewportLoc.h = 4;
|
||||
client._fb_Bpp = 4;
|
||||
client._pixelFormat.Bpp = 4;
|
||||
});
|
||||
|
||||
it('should handle the RAW encoding', function () {
|
||||
var info = [{ x: 0, y: 0, width: 2, height: 2, encoding: 0x00 },
|
||||
{ x: 2, y: 0, width: 2, height: 2, encoding: 0x00 },
|
||||
{ x: 0, y: 2, width: 4, height: 1, encoding: 0x00 },
|
||||
{ x: 0, y: 3, width: 4, height: 1, encoding: 0x00 }];
|
||||
// data is in bgrx
|
||||
var rects = [
|
||||
[0x00, 0x00, 0xff, 0, 0x00, 0xff, 0x00, 0, 0x00, 0xff, 0x00, 0, 0x00, 0x00, 0xff, 0],
|
||||
[0xff, 0x00, 0x00, 0, 0xff, 0x00, 0x00, 0, 0xff, 0x00, 0x00, 0, 0xff, 0x00, 0x00, 0],
|
||||
[0xff, 0x00, 0xee, 0, 0xff, 0xee, 0x00, 0, 0xff, 0xee, 0xaa, 0, 0xff, 0xee, 0xab, 0],
|
||||
[0xff, 0x00, 0xee, 0, 0xff, 0xee, 0x00, 0, 0xff, 0xee, 0xaa, 0, 0xff, 0xee, 0xab, 0]];
|
||||
send_fbu_msg(info, rects, client);
|
||||
expect(client._display).to.have.displayed(target_data);
|
||||
// warning: the fbupdates *overlap* so you have to send all rects for the numbers
|
||||
// to even make sense; this means (ironically) no iterative building of your tests
|
||||
describe('should handle the RAW encoding', function () {
|
||||
it('24bit depth (RGBX888) @ 32bpp [native]', function () {
|
||||
var info = [{ x: 0, y: 0, width: 2, height: 2, encoding: 0x00 },
|
||||
{ x: 2, y: 0, width: 2, height: 2, encoding: 0x00 },
|
||||
{ x: 0, y: 2, width: 4, height: 1, encoding: 0x00 },
|
||||
{ x: 0, y: 3, width: 4, height: 1, encoding: 0x00 }];
|
||||
var rects = [
|
||||
[0xf8, 0x00, 0x00, 0, 0x00, 0xf8, 0x00, 0, 0x00, 0xf8, 0x00, 0, 0xf8, 0x00, 0x00, 0],
|
||||
[0x00, 0x00, 0xf8, 0, 0x00, 0x00, 0xf8, 0, 0x00, 0x00, 0xf8, 0, 0x00, 0x00, 0xf8, 0],
|
||||
[0xe8, 0x00, 0xf8, 0, 0x00, 0xe8, 0xf8, 0, 0xa8, 0xe8, 0xf8, 0, 0xa8, 0xe8, 0xf8, 0],
|
||||
[0xe8, 0x00, 0xf8, 0, 0x00, 0xe8, 0xf8, 0, 0xa8, 0xe8, 0xf8, 0, 0xa8, 0xe8, 0xf8, 0]];
|
||||
send_fbu_msg(info, rects, client);
|
||||
expect(client._display).to.have.displayed(target_data);
|
||||
});
|
||||
|
||||
it('24bit depth (BGRX888) @ 32bpp', function () {
|
||||
client._convertColor = true;
|
||||
client._pixelFormat.big_endian = false;
|
||||
client._pixelFormat.red_shift = 16;
|
||||
client._pixelFormat.red_max = 255;
|
||||
client._pixelFormat.green_shift = 8;
|
||||
client._pixelFormat.green_max = 255;
|
||||
client._pixelFormat.blue_shift = 0;
|
||||
client._pixelFormat.blue_max = 255;
|
||||
var info = [{ x: 0, y: 0, width: 2, height: 2, encoding: 0x00 },
|
||||
{ x: 2, y: 0, width: 2, height: 2, encoding: 0x00 },
|
||||
{ x: 0, y: 2, width: 4, height: 1, encoding: 0x00 },
|
||||
{ x: 0, y: 3, width: 4, height: 1, encoding: 0x00 }];
|
||||
var rects = [
|
||||
[0x00, 0x00, 0xf8, 0, 0x00, 0xf8, 0x00, 0, 0x00, 0xf8, 0x00, 0, 0x00, 0x00, 0xf8, 0],
|
||||
[0xf8, 0x00, 0x00, 0, 0xf8, 0x00, 0x00, 0, 0xf8, 0x00, 0x00, 0, 0xf8, 0x00, 0x00, 0],
|
||||
[0xf8, 0x00, 0xe8, 0, 0xf8, 0xe8, 0x00, 0, 0xf8, 0xe8, 0xa8, 0, 0xf8, 0xe8, 0xa8, 0],
|
||||
[0xf8, 0x00, 0xe8, 0, 0xf8, 0xe8, 0x00, 0, 0xf8, 0xe8, 0xa8, 0, 0xf8, 0xe8, 0xa8, 0]];
|
||||
send_fbu_msg(info, rects, client);
|
||||
expect(client._display).to.have.displayed(target_data);
|
||||
});
|
||||
|
||||
// for wisdom: perl -e '($w, $r, $g, $b) = @ARGV; $W=2**$w; $nb = $b*($W/256); $ng = $g*($W/256); $nr = $r*($W/256); printf "%f:%f:%f %04x\n", $nr, $ng, $nb, unpack("S", pack("n", ($nr << (2*$w)) | ($ng << (1*$w)) | ($nb << (0*$w))))' 5 0 248 0
|
||||
it('15bit depth (BGR555) @ 16bpp', function () {
|
||||
client._convertColor = true;
|
||||
client._pixelFormat.big_endian = false;
|
||||
client._pixelFormat.Bpp = 2;
|
||||
client._pixelFormat.red_shift = 10;
|
||||
client._pixelFormat.red_max = 31;
|
||||
client._pixelFormat.green_shift = 5;
|
||||
client._pixelFormat.green_max = 31;
|
||||
client._pixelFormat.blue_shift = 0;
|
||||
client._pixelFormat.blue_max = 31;
|
||||
var info = [{ x: 0, y: 0, width: 2, height: 2, encoding: 0x00 },
|
||||
{ x: 2, y: 0, width: 2, height: 2, encoding: 0x00 },
|
||||
{ x: 0, y: 2, width: 4, height: 1, encoding: 0x00 },
|
||||
{ x: 0, y: 3, width: 4, height: 1, encoding: 0x00 }];
|
||||
var rects = [
|
||||
[0x00, 0x7c, 0xe0, 0x03, 0xe0, 0x03, 0x00, 0x7c],
|
||||
[0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00],
|
||||
[0x1f, 0x74, 0xbf, 0x03, 0xbf, 0x57, 0xbf, 0x57],
|
||||
[0x1f, 0x74, 0xbf, 0x03, 0xbf, 0x57, 0xbf, 0x57]];
|
||||
send_fbu_msg(info, rects, client);
|
||||
expect(client._display).to.have.displayed(target_data);
|
||||
});
|
||||
|
||||
it('15bit depth (BGR555) @ 16bpp big-endian', function () {
|
||||
client._convertColor = true;
|
||||
client._pixelFormat.big_endian = false;
|
||||
client._pixelFormat.Bpp = 2;
|
||||
client._pixelFormat.big_endian = true;
|
||||
client._pixelFormat.red_shift = 10;
|
||||
client._pixelFormat.red_max = 31;
|
||||
client._pixelFormat.green_shift = 5;
|
||||
client._pixelFormat.green_max = 31;
|
||||
client._pixelFormat.blue_shift = 0;
|
||||
client._pixelFormat.blue_max = 31;
|
||||
var info = [{ x: 0, y: 0, width: 2, height: 2, encoding: 0x00 },
|
||||
{ x: 2, y: 0, width: 2, height: 2, encoding: 0x00 },
|
||||
{ x: 0, y: 2, width: 4, height: 1, encoding: 0x00 },
|
||||
{ x: 0, y: 3, width: 4, height: 1, encoding: 0x00 }];
|
||||
var rects = [
|
||||
[0x7c, 0x00, 0x03, 0xe0, 0x03, 0xe0, 0x7c, 0x00],
|
||||
[0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f],
|
||||
[0x74, 0x1f, 0x03, 0xbf, 0x57, 0xbf, 0x57, 0xbf],
|
||||
[0x74, 0x1f, 0x03, 0xbf, 0x57, 0xbf, 0x57, 0xbf]];
|
||||
send_fbu_msg(info, rects, client);
|
||||
expect(client._display).to.have.displayed(target_data);
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle the COPYRECT encoding', function () {
|
||||
|
|
@ -1247,18 +1377,18 @@ describe('Remote Frame Buffer Protocol Client', function() {
|
|||
var rect = [];
|
||||
rect.push32(2); // 2 subrects
|
||||
rect.push32(0xff00ff); // becomes 00ff00ff --> #00FF00 bg color
|
||||
rect.push(0xff); // becomes ff0000ff --> #0000FF color
|
||||
rect.push(0x00);
|
||||
rect.push(0x00); // becomes 0000ffff --> #0000FF color
|
||||
rect.push(0x00);
|
||||
rect.push(0xff);
|
||||
rect.push(0xff);
|
||||
rect.push16(0); // x: 0
|
||||
rect.push16(0); // y: 0
|
||||
rect.push16(2); // width: 2
|
||||
rect.push16(2); // height: 2
|
||||
rect.push(0xff); // becomes ff0000ff --> #0000FF color
|
||||
rect.push(0x00);
|
||||
rect.push(0x00); // becomes 0000ffff --> #0000FF color
|
||||
rect.push(0x00);
|
||||
rect.push(0xff);
|
||||
rect.push(0xff);
|
||||
rect.push16(2); // x: 2
|
||||
rect.push16(2); // y: 2
|
||||
rect.push16(2); // width: 2
|
||||
|
|
@ -1283,7 +1413,7 @@ describe('Remote Frame Buffer Protocol Client', function() {
|
|||
client._display._fb_height = 4;
|
||||
client._display._viewportLoc.w = 4;
|
||||
client._display._viewportLoc.h = 4;
|
||||
client._fb_Bpp = 4;
|
||||
client._pixelFormat.Bpp = 4;
|
||||
});
|
||||
|
||||
it('should handle a tile with fg, bg specified, normal subrects', function () {
|
||||
|
|
@ -1291,10 +1421,10 @@ describe('Remote Frame Buffer Protocol Client', function() {
|
|||
var rect = [];
|
||||
rect.push(0x02 | 0x04 | 0x08); // bg spec, fg spec, anysubrects
|
||||
rect.push32(0xff00ff); // becomes 00ff00ff --> #00FF00 bg color
|
||||
rect.push(0xff); // becomes ff0000ff --> #0000FF fg color
|
||||
rect.push(0x00);
|
||||
rect.push(0x00); // becomes 0000ffff --> #0000FF fg color
|
||||
rect.push(0x00);
|
||||
rect.push(0xff);
|
||||
rect.push(0xff);
|
||||
rect.push(2); // 2 subrects
|
||||
rect.push(0); // x: 0, y: 0
|
||||
rect.push(1 | (1 << 4)); // width: 2, height: 2
|
||||
|
|
@ -1309,9 +1439,9 @@ describe('Remote Frame Buffer Protocol Client', function() {
|
|||
var rect = [];
|
||||
rect.push(0x01); // raw
|
||||
for (var i = 0; i < target_data.length; i += 4) {
|
||||
rect.push(target_data[i + 2]);
|
||||
rect.push(target_data[i + 1]);
|
||||
rect.push(target_data[i]);
|
||||
rect.push(target_data[i + 1]);
|
||||
rect.push(target_data[i + 2]);
|
||||
rect.push(target_data[i + 3]);
|
||||
}
|
||||
send_fbu_msg(info, [rect], client);
|
||||
|
|
@ -1362,16 +1492,16 @@ describe('Remote Frame Buffer Protocol Client', function() {
|
|||
rect.push(0x02 | 0x08 | 0x10); // bg spec, anysubrects, colouredsubrects
|
||||
rect.push32(0xff00ff); // becomes 00ff00ff --> #00FF00 bg color
|
||||
rect.push(2); // 2 subrects
|
||||
rect.push(0xff); // becomes ff0000ff --> #0000FF fg color
|
||||
rect.push(0x00);
|
||||
rect.push(0x00); // becomes 0000ffff --> #0000FF fg color
|
||||
rect.push(0x00);
|
||||
rect.push(0xff);
|
||||
rect.push(0xff);
|
||||
rect.push(0); // x: 0, y: 0
|
||||
rect.push(1 | (1 << 4)); // width: 2, height: 2
|
||||
rect.push(0xff); // becomes ff0000ff --> #0000FF fg color
|
||||
rect.push(0x00);
|
||||
rect.push(0x00); // becomes 0000ffff --> #0000FF fg color
|
||||
rect.push(0x00);
|
||||
rect.push(0xff);
|
||||
rect.push(0xff);
|
||||
rect.push(2 | (2 << 4)); // x: 2, y: 2
|
||||
rect.push(1 | (1 << 4)); // width: 2, height: 2
|
||||
send_fbu_msg(info, [rect], client);
|
||||
|
|
@ -1387,10 +1517,10 @@ describe('Remote Frame Buffer Protocol Client', function() {
|
|||
var rect = [];
|
||||
rect.push(0x02 | 0x04 | 0x08); // bg spec, fg spec, anysubrects
|
||||
rect.push32(0xff00ff); // becomes 00ff00ff --> #00FF00 bg color
|
||||
rect.push(0xff); // becomes ff0000ff --> #0000FF fg color
|
||||
rect.push(0x00);
|
||||
rect.push(0x00); // becomes 0000ffff --> #0000FF fg color
|
||||
rect.push(0x00);
|
||||
rect.push(0xff);
|
||||
rect.push(0xff);
|
||||
rect.push(8); // 8 subrects
|
||||
var i;
|
||||
for (i = 0; i < 4; i++) {
|
||||
|
|
@ -1427,6 +1557,96 @@ describe('Remote Frame Buffer Protocol Client', function() {
|
|||
// TODO(directxman12): test this
|
||||
});
|
||||
|
||||
describe('the ATEN encoding handler', function () {
|
||||
var client;
|
||||
beforeEach(function () {
|
||||
client = make_rfb();
|
||||
client.connect('host', 8675);
|
||||
client._sock._websocket._open();
|
||||
client._rfb_state = 'normal';
|
||||
client._fb_name = 'some device';
|
||||
client._rfb_atenikvm = true;
|
||||
// start large, then go small
|
||||
client._fb_width = 10000;
|
||||
client._fb_height = 10000;
|
||||
client._display._fb_width = 10000;
|
||||
client._display._fb_height = 10000;
|
||||
client._display._viewportLoc.w = 10000;
|
||||
client._display._viewportLoc.h = 10000;
|
||||
client._convertColor = true;
|
||||
client._pixelFormat.Bpp = 2;
|
||||
client._pixelFormat.big_endian = false;
|
||||
client._pixelFormat.red_shift = 10;
|
||||
client._pixelFormat.red_max = 31;
|
||||
client._pixelFormat.green_shift = 5;
|
||||
client._pixelFormat.green_max = 31;
|
||||
client._pixelFormat.blue_shift = 0;
|
||||
client._pixelFormat.blue_max = 31;
|
||||
});
|
||||
|
||||
var aten_target_data_arr = [0xa8, 0xe8, 0xf8, 0xff];
|
||||
var aten_target_data;
|
||||
|
||||
before(function () {
|
||||
for (var i = 0; i < 10; i++) {
|
||||
aten_target_data_arr = aten_target_data_arr.concat(aten_target_data_arr);
|
||||
}
|
||||
aten_target_data = new Uint8Array(aten_target_data_arr);
|
||||
});
|
||||
|
||||
it('should handle subtype subrect encoding', function () {
|
||||
var info = [{ x: 0, y: 0, width: 32, height: 32, encoding: 0x59 }];
|
||||
var rect = [];
|
||||
|
||||
rect.push32(0); // padding
|
||||
rect.push32(2082); // 10 + 32x32x2Bpp + 6*(num of subrects)
|
||||
|
||||
rect.push8(0); // type
|
||||
rect.push8(0); // padding
|
||||
|
||||
rect.push32(4); // num of subrects (32/16)*(32/16)
|
||||
rect.push32(2082); // length (again)
|
||||
|
||||
for (var y = 0; y < 2; y++) {
|
||||
for (var x = 0; x < 2; x++) {
|
||||
rect.push16(0); // a
|
||||
rect.push16(0); // b
|
||||
rect.push8(y);
|
||||
rect.push8(x);
|
||||
|
||||
for (var i = 0; i < 16*16; i++) {
|
||||
rect.push16(0xbf57);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
send_fbu_msg(info, [rect], client);
|
||||
expect(client._display).to.have.displayed(aten_target_data);
|
||||
});
|
||||
|
||||
it('should handle subtype RAW encoding', function () {
|
||||
// do not use encoding=0x59 here, as rfb.js should override it
|
||||
var info = [{ x: 0, y: 0, width: 32, height: 32, encoding: 0x00 }];
|
||||
var rect = [];
|
||||
|
||||
rect.push32(0); // padding
|
||||
rect.push32(2058); // 10 + 32x32x2Bpp
|
||||
|
||||
rect.push8(1); // type
|
||||
rect.push8(0); // padding
|
||||
|
||||
rect.push32(0); // padding
|
||||
rect.push32(2058); // length (again)
|
||||
|
||||
for (var i = 0; i < 32*32; i++) {
|
||||
rect.push16(0xbf57);
|
||||
}
|
||||
|
||||
send_fbu_msg(info, [rect], client);
|
||||
expect(client._display).to.have.displayed(aten_target_data);
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle the DesktopSize pseduo-encoding', function () {
|
||||
client.set_onFBResize(sinon.spy());
|
||||
sinon.spy(client._display, 'resize');
|
||||
|
|
|
|||
4
vnc.html
4
vnc.html
|
|
@ -10,7 +10,7 @@
|
|||
This file is licensed under the 2-Clause BSD license (see LICENSE.txt).
|
||||
|
||||
Connect parameters are provided in query string:
|
||||
http://example.com/?host=HOST&port=PORT&encrypt=1&true_color=1
|
||||
http://example.com/?host=HOST&port=PORT&encrypt=1&convertColor=1
|
||||
-->
|
||||
<title>noVNC</title>
|
||||
|
||||
|
|
@ -154,7 +154,7 @@
|
|||
<span id="noVNC_settings_menu">
|
||||
<ul>
|
||||
<li><input id="noVNC_encrypt" type="checkbox"> Encrypt</li>
|
||||
<li><input id="noVNC_true_color" type="checkbox" checked> True Color</li>
|
||||
<li><input id="noVNC_convertColor" type="checkbox" checked> Convert Color</li>
|
||||
<li><input id="noVNC_cursor" type="checkbox"> Local Cursor</li>
|
||||
<li><input id="noVNC_clip" type="checkbox"> Clip to Window</li>
|
||||
<li><input id="noVNC_shared" type="checkbox"> Shared Mode</li>
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
This file is licensed under the 2-Clause BSD license (see LICENSE.txt).
|
||||
|
||||
Connect parameters are provided in query string:
|
||||
http://example.com/?host=HOST&port=PORT&encrypt=1&true_color=1
|
||||
http://example.com/?host=HOST&port=PORT&encrypt=1&convertColor=1
|
||||
-->
|
||||
<title>noVNC</title>
|
||||
|
||||
|
|
@ -194,7 +194,7 @@
|
|||
'encrypt': WebUtil.getQueryVar('encrypt',
|
||||
(window.location.protocol === "https:")),
|
||||
'repeaterID': WebUtil.getQueryVar('repeaterID', ''),
|
||||
'true_color': WebUtil.getQueryVar('true_color', true),
|
||||
'convertColor': WebUtil.getQueryVar('convertColor', true),
|
||||
'local_cursor': WebUtil.getQueryVar('cursor', true),
|
||||
'shared': WebUtil.getQueryVar('shared', true),
|
||||
'view_only': WebUtil.getQueryVar('view_only', false),
|
||||
|
|
|
|||
Loading…
Reference in New Issue