['JPEG_quality_med', -26 ],
//['JPEG_quality_hi', -23 ],
//['compress_lo', -255 ],
- ['compress_hi', -247 ],
+ ['compress_hi', -254 ],
+ //['compress_max', -247 ],
['DesktopSize', -223 ],
['last_rect', -224 ],
zlib: [] // TIGHT zlib streams
};
- this._fb_Bpp = 4;
- this._fb_depth = 3;
this._fb_width = 0;
this._fb_height = 0;
this._fb_name = "";
'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
'local_cursor': false, // Request locally rendered cursor
'shared': true, // Request shared mode
'view_only': false, // Disable client mouse/keyboard
this._mouse = new Mouse({target: this._target,
onMouseButton: this._handleMouseButton.bind(this),
- onMouseMove: this._handleMouseMove.bind(this),
- notify: this._keyboard.sync.bind(this._keyboard)});
+ onMouseMove: this._handleMouseMove.bind(this)});
this._sock = new Websock();
this._sock.on('message', this._handle_message.bind(this));
return true;
}
- if (this._qemuExtKeyEventSupported) {
- var scancode = XtScancode[code];
+ var scancode = XtScancode[code];
- if (scancode === undefined) {
- Log.Error('Unable to find a xt scancode for code: ' + code);
- // FIXME: not in the spec, but this is what
- // gtk-vnc does
- scancode = 0;
- }
+ if (this._qemuExtKeyEventSupported && scancode) {
+ // 0 is NoSymbol
+ keysym = keysym || 0;
Log.Info("Sending key (" + (down ? "down" : "up") + "): keysym " + keysym + ", scancode " + scancode);
RFB.messages.QEMUExtendedKeyEvent(this._sock, keysym, down, scancode);
} else {
+ if (!keysym) {
+ return false;
+ }
Log.Info("Sending keysym (" + (down ? "down" : "up") + "): " + keysym);
RFB.messages.keyEvent(this._sock, keysym, down ? 1 : 0);
}
if (down) {
this._mouse_buttonMask |= bmask;
} else {
- this._mouse_buttonMask ^= bmask;
+ this._mouse_buttonMask &= ~bmask;
}
if (this._viewportDrag) {
} else {
return this._fail("Authentication failure");
}
- return false;
case 2:
return this._fail("Too many authentication attempts");
default:
if (this._sock.rQwait("server initialization", 24)) { return false; }
/* Screen size */
- this._fb_width = this._sock.rQshift16();
- this._fb_height = this._sock.rQshift16();
- this._destBuff = new Uint8Array(this._fb_width * this._fb_height * 4);
+ var width = this._sock.rQshift16();
+ var height = this._sock.rQshift16();
/* PIXEL_FORMAT */
var bpp = this._sock.rQshift8();
// NB(directxman12): these are down here so that we don't run them multiple times
// if we backtrack
- Log.Info("Screen: " + this._fb_width + "x" + this._fb_height +
+ Log.Info("Screen: " + width + "x" + height +
", bpp: " + bpp + ", depth: " + depth +
", big_endian: " + big_endian +
", true_color: " + true_color +
// 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") {
- Log.Warn("Intel AMT KVM only supports 8/16 bit depths. Disabling true color");
- this._true_color = false;
- }
-
- this._display.set_true_color(this._true_color);
- this._display.resize(this._fb_width, this._fb_height);
- this._onFBResize(this, this._fb_width, this._fb_height);
+ this._resize(width, height);
if (!this._view_only) { this._keyboard.grab(); }
if (!this._view_only) { this._mouse.grab(); }
- if (this._true_color) {
- this._fb_Bpp = 4;
- this._fb_depth = 3;
- } else {
- this._fb_Bpp = 1;
- this._fb_depth = 1;
- }
-
- 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.pixelFormat(this._sock, 4, 3, true);
+ RFB.messages.clientEncodings(this._sock, this._encodings, this._local_cursor);
RFB.messages.fbUpdateRequest(this._sock, false, 0, 0, this._fb_width, this._fb_height);
this._timing.fbu_rt_start = (new Date()).getTime();
_handle_set_colour_map_msg: function () {
Log.Debug("SetColorMapEntries");
- this._sock.rQskip8(); // Padding
-
- var first_colour = this._sock.rQshift16();
- var num_colours = this._sock.rQshift16();
- if (this._sock.rQwait('SetColorMapEntries', num_colours * 6, 6)) { return false; }
-
- for (var c = 0; c < num_colours; c++) {
- var red = parseInt(this._sock.rQshift16() / 256, 10);
- var green = parseInt(this._sock.rQshift16() / 256, 10);
- var blue = parseInt(this._sock.rQshift16() / 256, 10);
- this._display.set_colourMap([blue, green, red], first_colour + c);
- }
- Log.Debug("colourMap: " + this._display.get_colourMap());
- Log.Info("Registered " + num_colours + " colourMap entries");
- return true;
+ return this._fail("Protocol error", "Unexpected SetColorMapEntries message");
},
_handle_server_cut_text: function () {
RFB.messages.enableContinuousUpdates(this._sock, true, 0, 0,
this._fb_width, this._fb_height);
+ },
+
+ _resize: function(width, height) {
+ this._fb_width = width;
+ this._fb_height = height;
+
+ this._destBuff = new Uint8Array(this._fb_width * this._fb_height * 4);
+
+ this._display.resize(this._fb_width, this._fb_height);
+ this._onFBResize(this, this._fb_width, this._fb_height);
+
+ this._timing.fbu_rt_start = (new Date()).getTime();
+ this._updateContinuousUpdates();
}
};
['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
['local_cursor', 'rw', 'bool'], // Request locally rendered cursor
['shared', 'rw', 'bool'], // Request shared mode
['view_only', 'rw', 'bool'], // Disable client mouse/keyboard
// Need to send an updated list of encodings if we are connected
if (this._rfb_connection_state === "connected") {
- RFB.messages.clientEncodings(this._sock, this._encodings, cursor,
- this._true_color);
+ RFB.messages.clientEncodings(this._sock, this._encodings, cursor);
}
};
sock.flush();
},
- clientEncodings: function (sock, encodings, local_cursor, true_color) {
+ clientEncodings: function (sock, encodings, local_cursor) {
var buff = sock._sQ;
var offset = sock._sQlen;
for (i = 0; i < encodings.length; i++) {
if (encodings[i][0] === "Cursor" && !local_cursor) {
Log.Debug("Skipping Cursor pseudo-encoding");
- } else if (encodings[i][0] === "TIGHT" && !true_color) {
- // TODO: remove this when we have tight+non-true-color
- Log.Warn("Skipping tight as it is only supported with true color");
} else {
var enc = encodings[i][1];
buff[j] = enc >> 24;
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 * 4; // 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)));
+ Math.floor(this._sock.rQlen() / (this._FBU.width * 4)));
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);
+ this._sock.rQskipBytes(this._FBU.width * curr_height * 4);
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 * 4; // At least another line
} else {
this._FBU.rects--;
this._FBU.bytes = 0;
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 + 4;
+ if (this._sock.rQwait("RRE", 4 + 4)) { return false; }
this._FBU.subrects = this._sock.rQshift32();
- color = this._sock.rQshiftBytes(this._fb_Bpp); // Background
+ color = this._sock.rQshiftBytes(4); // 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() >= (4 + 8)) {
+ color = this._sock.rQshiftBytes(4);
var x = this._sock.rQshift16();
var y = this._sock.rQshift16();
var width = this._sock.rQshift16();
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 = (4 + 8) * chunk;
} else {
this._FBU.rects--;
this._FBU.bytes = 0;
// Figure out how much we are expecting
if (subencoding & 0x01) { // Raw
- this._FBU.bytes += w * h * this._fb_Bpp;
+ this._FBU.bytes += w * h * 4;
} else {
if (subencoding & 0x02) { // Background
- this._FBU.bytes += this._fb_Bpp;
+ this._FBU.bytes += 4;
}
if (subencoding & 0x04) { // Foreground
- this._FBU.bytes += this._fb_Bpp;
+ this._FBU.bytes += 4;
}
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 * (4 + 2);
} else {
this._FBU.bytes += subrects * 2;
}
rQi += this._FBU.bytes - 1;
} else {
if (this._FBU.subencoding & 0x02) { // Background
- if (this._fb_Bpp == 1) {
- this._FBU.background = rQ[rQi];
- } else {
- // fb_Bpp is 4
- this._FBU.background = [rQ[rQi], rQ[rQi + 1], rQ[rQi + 2], rQ[rQi + 3]];
- }
- rQi += this._fb_Bpp;
+ this._FBU.background = [rQ[rQi], rQ[rQi + 1], rQ[rQi + 2], rQ[rQi + 3]];
+ rQi += 4;
}
if (this._FBU.subencoding & 0x04) { // Foreground
- if (this._fb_Bpp == 1) {
- this._FBU.foreground = rQ[rQi];
- } else {
- // this._fb_Bpp is 4
- this._FBU.foreground = [rQ[rQi], rQ[rQi + 1], rQ[rQi + 2], rQ[rQi + 3]];
- }
- rQi += this._fb_Bpp;
+ this._FBU.foreground = [rQ[rQi], rQ[rQi + 1], rQ[rQi + 2], rQ[rQi + 3]];
+ rQi += 4;
}
this._display.startTile(x, y, w, h, this._FBU.background);
for (var s = 0; s < subrects; s++) {
var color;
if (this._FBU.subencoding & 0x10) { // SubrectsColoured
- if (this._fb_Bpp === 1) {
- color = rQ[rQi];
- } else {
- // _fb_Bpp is 4
- color = [rQ[rQi], rQ[rQi + 1], rQ[rQi + 2], rQ[rQi + 3]];
- }
- rQi += this._fb_Bpp;
+ color = [rQ[rQi], rQ[rQi + 1], rQ[rQi + 2], rQ[rQi + 3]];
+ rQi += 4;
} else {
color = this._FBU.foreground;
}
return true;
},
- getTightCLength: function (arr) {
- var header = 1, data = 0;
- data += arr[0] & 0x7f;
- if (arr[0] & 0x80) {
- header++;
- data += (arr[1] & 0x7f) << 7;
- if (arr[1] & 0x80) {
- header++;
- data += arr[2] << 14;
- }
- }
- return [header, data];
- },
-
- display_tight: function (isTightPNG) {
- if (this._fb_depth === 1) {
- this._fail("Internal error",
- "Tight protocol handler only implements " +
- "true color mode");
- }
-
+ TIGHT: function () {
this._FBU.bytes = 1; // compression-control byte
if (this._sock.rQwait("TIGHT compression-control", this._FBU.bytes)) { return false; }
var handlePalette = function () {
var numColors = rQ[rQi + 2] + 1;
- var paletteSize = numColors * this._fb_depth;
+ var paletteSize = numColors * 3;
this._FBU.bytes += paletteSize;
if (this._sock.rQwait("TIGHT palette " + cmode, this._FBU.bytes)) { return false; }
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 * 3;
if (uncompressedSize < 12) {
raw = true;
cl_header = 0;
"Illegal tight compression received, " +
"ctl: " + ctl);
- if (isTightPNG && (cmode === "filter" || cmode === "copy")) {
- return this._fail("Unexpected server message",
- "filter/copy received in tightPNG mode");
- }
-
switch (cmode) {
- // fill use fb_depth because TPIXELs drop the padding byte
+ // fill use depth because TPIXELs drop the padding byte
case "fill": // TPIXEL
- this._FBU.bytes += this._fb_depth;
+ this._FBU.bytes += 3;
break;
case "jpeg": // max clength
this._FBU.bytes += 3;
return true;
},
- TIGHT: function () { return this._encHandlers.display_tight(false); },
- TIGHT_PNG: function () { return this._encHandlers.display_tight(true); },
-
last_rect: function () {
this._FBU.rects = 0;
return true;
},
- handle_FB_resize: function () {
- this._fb_width = this._FBU.width;
- this._fb_height = this._FBU.height;
- this._destBuff = new Uint8Array(this._fb_width * this._fb_height * 4);
- this._display.resize(this._fb_width, this._fb_height);
- this._onFBResize(this, this._fb_width, this._fb_height);
- this._timing.fbu_rt_start = (new Date()).getTime();
- this._updateContinuousUpdates();
-
- this._FBU.bytes = 0;
- this._FBU.rects -= 1;
- return true;
- },
-
ExtendedDesktopSize: function () {
this._FBU.bytes = 1;
if (this._sock.rQwait("ExtendedDesktopSize", this._FBU.bytes)) { return false; }
}
this._notification("Server did not accept the resize request: "
+ msg, 'normal');
- return true;
+ } else {
+ this._resize(this._FBU.width, this._FBU.height);
}
- this._encHandlers.handle_FB_resize();
+ this._FBU.bytes = 0;
+ this._FBU.rects -= 1;
return true;
},
DesktopSize: function () {
- this._encHandlers.handle_FB_resize();
+ this._resize(this._FBU.width, this._FBU.height);
+ this._FBU.bytes = 0;
+ this._FBU.rects -= 1;
return true;
},
var w = this._FBU.width;
var h = this._FBU.height;
- var pixelslength = w * h * this._fb_Bpp;
+ var pixelslength = w * h * 4;
var masklength = Math.floor((w + 7) / 8) * h;
this._FBU.bytes = pixelslength + masklength;
QEMUExtendedKeyEvent: function () {
this._FBU.rects--;
- var keyboardEvent = document.createEvent("keyboardEvent");
- if (keyboardEvent.code !== undefined) {
- this._qemuExtKeyEventSupported = true;
- this._keyboard.setQEMUVNCKeyboardHandler();
+ // Old Safari doesn't support creating keyboard events
+ try {
+ var keyboardEvent = document.createEvent("keyboardEvent");
+ if (keyboardEvent.code !== undefined) {
+ this._qemuExtKeyEventSupported = true;
+ }
+ } catch (err) {
}
},
-
- JPEG_quality_lo: function () {
- Log.Error("Server sent jpeg_quality pseudo-encoding");
- },
-
- compress_lo: function () {
- Log.Error("Server sent compress level pseudo-encoding");
- }
};