1
0
Fork 0
mirror of https://github.com/Ylianst/MeshCentral.git synced 2025-03-09 15:40:18 +00:00

Improved WebRTC support

This commit is contained in:
Ylian Saint-Hilaire 2018-01-18 15:43:43 -08:00
parent 92aaf754fb
commit 4106b322d6
16 changed files with 2854 additions and 128 deletions

View file

@ -23,6 +23,8 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
obj.useZRLE = true;
obj.showmouse = true;
obj.buttonmask = 0;
//obj.inbytes = 0;
//obj.outbytes = 0;
obj.spare = null;
obj.sparew = 0;
obj.spareh = 0;
@ -33,9 +35,10 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
obj.onScreenSizeChange = null;
obj.frameRateDelay = 0;
// ###BEGIN###{DesktopRotation}
obj.noMouseRotate = false;
obj.rotation = 0;
// ###END###{DesktopRotation}
// ###BEGIN###{DesktopFocus}
obj.mx = 0; // Last mouse x position
obj.my = 0; // Last mouse y position
@ -43,10 +46,13 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
obj.oy = -1; // Old mouse y position
obj.focusmode = 0;
// ###END###{DesktopFocus}
// ###BEGIN###{Inflate}
obj.inflate = ZLIB.inflateInit(-15);
// ###END###{Inflate}
// Private method
obj.Debug = function (msg) { console.log(msg); }
obj.xxStateChange = function (newstate) {
if (newstate == 0) {
obj.canvas.fillStyle = '#000000';
@ -58,10 +64,12 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
if (!obj.showmouse) { QS(obj.canvasid).cursor = 'none'; }
}
}
obj.ProcessData = function (data) {
if (!data) return;
// obj.Debug("KRecv(" + data.length + "): " + rstr2hex(data));
//obj.inbytes += data.length;
//obj.Debug("KRecv(" + obj.inbytes + ")");
obj.acc += data;
while (obj.acc.length > 0) {
//obj.Debug("KAcc(" + obj.acc.length + "): " + rstr2hex(obj.acc));
@ -90,12 +98,15 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
}
else if (obj.state == 3 && obj.acc.length >= 24) {
// Getting server init
// ###BEGIN###{DesktopRotation}
obj.rotation = 0; // We don't currently support screen init while rotated.
// ###END###{DesktopRotation}
var namelen = ReadInt(obj.acc, 20);
if (obj.acc.length < 24 + namelen) return;
cmdsize = 24 + namelen;
obj.canvas.canvas.width = obj.rwidth = obj.width = obj.ScreenWidth = ReadShort(obj.acc, 0);
obj.canvas.canvas.height = obj.rheight = obj.height = obj.ScreenHeight = ReadShort(obj.acc, 2);
// These are all values we don't really need, we are going to only run in RGB565 or RGB332 and not use the flexibility provided by these settings.
// Makes the javascript code smaller and maybe a bit faster.
/*
@ -126,22 +137,22 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
var supportedEncodings = '';
if (obj.useZRLE) supportedEncodings += IntToStr(16);
supportedEncodings += IntToStr(0);
obj.Send(String.fromCharCode(2, 0) + ShortToStr((supportedEncodings.length / 4) + 1) + supportedEncodings + IntToStr(-223)); // Supported Encodings + Desktop Size
// Set the pixel encoding to something much smaller
// obj.Send(String.fromCharCode(0, 0, 0, 0, 16, 16, 0, 1) + ShortToStr(31) + ShortToStr(63) + ShortToStr(31) + String.fromCharCode(11, 5, 0, 0, 0, 0)); // Setup 16 bit color RGB565 (This is the default, so we don't need to set it)
if (obj.bpp == 1) obj.Send(String.fromCharCode(0, 0, 0, 0, 8, 8, 0, 1) + ShortToStr(7) + ShortToStr(7) + ShortToStr(3) + String.fromCharCode(5, 2, 0, 0, 0, 0)); // Setup 8 bit color RGB332
obj.state = 4;
obj.parent.xxStateChange(3);
_SendRefresh();
//obj.timer = setInterval(obj.xxOnTimer, 50);
// ###BEGIN###{DesktopFocus}
obj.ox = -1; // Old mouse x position
// ###END###{DesktopFocus}
if (obj.onScreenSizeChange != null) { obj.onScreenSizeChange(obj, obj.ScreenWidth, obj.ScreenHeight); }
}
else if (obj.state == 4) {
@ -161,10 +172,10 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
height = ReadShort(obj.acc, 6),
s = width * height,
encoding = ReadInt(obj.acc, 8);
if (encoding < 17) {
if (width < 1 || width > 64 || height < 1 || height > 64) { console.log("Invalid tile size (" + width + "," + height + "), disconnecting."); return obj.Stop(); }
// Set the spare bitmap to the rigth size if it's not already. This allows us to recycle the spare most if not all the time.
if (obj.sparew != width || obj.spareh != height) {
obj.sparew = obj.sparew2 = width;
@ -178,7 +189,7 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
}
}
if (encoding == 0xFFFFFF21) {
// Desktop Size (0xFFFFFF21, -223)
obj.canvas.canvas.width = obj.rwidth = obj.width = width;
@ -193,7 +204,7 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
var ptr = 12, cs = 12 + (s * obj.bpp);
if (obj.acc.length < cs) return; // Check we have all the data needed and we can only draw 64x64 tiles.
cmdsize = cs;
// CRITICAL LOOP, optimize this as much as possible
for (var i = 0; i < s; i++) { _setPixel(obj.acc.charCodeAt(ptr++) + ((obj.bpp == 2) ? (obj.acc.charCodeAt(ptr++) << 8) : 0), i); }
_putImage(obj.spare, x, y);
@ -205,23 +216,22 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
if (obj.acc.length < (16 + datalen)) return;
//obj.Debug("RECT ZRLE (" + x + "," + y + "," + width + "," + height + ") LEN = " + datalen);
//obj.Debug("RECT ZRLE LEN: " + ReadShortX(obj.acc, 17) + ", DATA: " + rstr2hex(obj.acc.substring(16)));
// Process the ZLib header if this is the first block
var ptr = 16, delta = 5, dx = 0;
if (obj.ZRLEfirst == 1) { obj.ZRLEfirst = 0; ptr += 2; delta = 7; dx = 2; } // Skip the ZLib header
if (datalen > 5 && obj.acc.charCodeAt(ptr) == 0 && ReadShortX(obj.acc, ptr + 1) == (datalen - delta)) {
// This is an uncompressed ZLib data block
_decodeLRE(obj.acc, ptr + 5, x, y, width, height, s, datalen);
}
// ###BEGIN###{Inflate}
// ###BEGIN###{Inflate}
else {
// This is compressed ZLib data, decompress and process it.
var arr = inflate(obj.acc.substring(ptr, ptr + datalen - dx));
if (arr.length > 0) { _decodeLRE(String.fromCharCode.apply(null, new Uint8Array(arr)), 0, x, y, width, height, s, arr.length); } else { obj.Debug("Invalid deflate data"); }
var arr = obj.inflate.inflate(obj.acc.substring(ptr, ptr + datalen - dx));
if (arr.length > 0) { _decodeLRE(arr, 0, x, y, width, height, s, arr.length); } else { obj.Debug("Invalid deflate data"); }
}
// ###END###{Inflate}
cmdsize = 16 + datalen;
}
else {
@ -237,12 +247,12 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
}
}
}
if (cmdsize == 0) return;
obj.acc = obj.acc.substring(cmdsize);
}
}
function _decodeLRE(data, ptr, x, y, width, height, s, datalen) {
var subencoding = data.charCodeAt(ptr++), index, v, runlengthdecode, palette = {}, rlecount = 0, runlength = 0, i;
// obj.Debug("RECT RLE (" + (datalen - 5) + ", " + subencoding + "):" + rstr2hex(data.substring(21, 21 + (datalen - 5))));
@ -255,23 +265,23 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
// Solid color tile
v = data.charCodeAt(ptr++) + ((obj.bpp == 2) ? (data.charCodeAt(ptr++) << 8) : 0);
obj.canvas.fillStyle = 'rgb(' + ((obj.bpp == 1) ? ((v & 224) + ',' + ((v & 28) << 3) + ',' + _fixColor((v & 3) << 6)) : (((v >> 8) & 248) + ',' + ((v >> 3) & 252) + ',' + ((v & 31) << 3))) + ')';
// ###BEGIN###{DesktopRotation}
var xx = _rotX(x, y);
y = _rotY(x, y);
x = xx;
// ###END###{DesktopRotation}
obj.canvas.fillRect(x, y, width, height);
}
else if (subencoding > 1 && subencoding < 17) { // Packed palette encoded tile
// Read the palette
var br = 4, bm = 15; // br is BitRead and bm is BitMask. By adjusting these two we can support all the variations in this encoding.
for (i = 0; i < subencoding; i++) { palette[i] = data.charCodeAt(ptr++) + ((obj.bpp == 2) ? (data.charCodeAt(ptr++) << 8) : 0); }
// Compute bits to read & bit mark
if (subencoding == 2) { br = 1; bm = 1; } else if (subencoding <= 4) { br = 2; bm = 3; }
// Display all the bits
while (rlecount < s && ptr < data.length) { v = data.charCodeAt(ptr++); for (i = (8 - br) ; i >= 0; i -= br) { _setPixel(palette[(v >> i) & bm], rlecount++); } }
_putImage(obj.spare, x, y);
@ -280,10 +290,10 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
while (rlecount < s && ptr < data.length) {
// Get the run color
v = data.charCodeAt(ptr++) + ((obj.bpp == 2) ? (data.charCodeAt(ptr++) << 8) : 0);
// Decode the run length. This is the fastest and most compact way I found to do this.
runlength = 1; do { runlength += (runlengthdecode = data.charCodeAt(ptr++)); } while (runlengthdecode == 255);
// Draw a run
while (--runlength >= 0) { _setPixel(v, rlecount++); }
}
@ -292,22 +302,22 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
else if (subencoding > 129) { // Palette RLE encoded tile
// Read the palette
for (i = 0; i < (subencoding - 128) ; i++) { palette[i] = data.charCodeAt(ptr++) + ((obj.bpp == 2) ? (data.charCodeAt(ptr++) << 8) : 0); }
// Decode RLE on palette
while (rlecount < s && ptr < data.length) {
// Setup the run, get the color index and get the color from the palette.
runlength = 1; index = data.charCodeAt(ptr++); v = palette[index % 128];
// If the index starts with high order bit 1, this is a run and decode the run length.
if (index > 127) { do { runlength += (runlengthdecode = data.charCodeAt(ptr++)); } while (runlengthdecode == 255); }
// Draw a run
while (--runlength >= 0) { _setPixel(v, rlecount++); }
}
_putImage(obj.spare, x, y);
}
}
function _putImage(i, x, y) {
// ###BEGIN###{DesktopRotation}
var xx = _arotX(x, y);
@ -316,10 +326,10 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
// ###END###{DesktopRotation}
obj.canvas.putImageData(i, x, y);
}
function _setPixel(v, p) {
var pp = p * 4;
// ###BEGIN###{DesktopRotation}
if (obj.rotation > 0) {
if (obj.rotation == 1) {
@ -337,7 +347,7 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
}
}
// ###END###{DesktopRotation}
if (obj.bpp == 1) {
// Set 8bit color RGB332
obj.spare.data[pp++] = v & 224;
@ -351,7 +361,7 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
}
obj.spare.data[pp] = 0xFF; // Set alpha channel to opaque.
}
// ###BEGIN###{DesktopRotation}
function _arotX(x, y) {
if (obj.rotation == 0) return x;
@ -360,7 +370,7 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
if (obj.rotation == 3) return y;
return 0;
}
function _arotY(x, y) {
if (obj.rotation == 0) return y;
if (obj.rotation == 1) return x;
@ -368,7 +378,7 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
if (obj.rotation == 3) return obj.canvas.canvas.height - obj.spareh - x;
return 0;
}
function _crotX(x, y) {
if (obj.rotation == 0) return x;
if (obj.rotation == 1) return y;
@ -376,7 +386,7 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
if (obj.rotation == 3) return obj.canvas.canvas.height - y;
return 0;
}
function _crotY(x, y) {
if (obj.rotation == 0) return y;
if (obj.rotation == 1) return obj.canvas.canvas.width - x;
@ -384,7 +394,7 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
if (obj.rotation == 3) return x;
return 0;
}
function _rotX(x, y) {
if (obj.rotation == 0) return x;
if (obj.rotation == 1) return x;
@ -392,7 +402,7 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
if (obj.rotation == 3) return x - obj.canvas.canvas.height;
return 0;
}
function _rotY(x, y) {
if (obj.rotation == 0) return y;
if (obj.rotation == 1) return y - obj.canvas.canvas.width;
@ -400,7 +410,7 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
if (obj.rotation == 3) return y;
return 0;
}
obj.tcanvas = null;
obj.setRotation = function (x) {
while (x < 0) { x += 4; }
@ -409,7 +419,7 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
var rw = obj.canvas.canvas.width;
var rh = obj.canvas.canvas.height;
if (obj.rotation == 1 || obj.rotation == 3) { rw = obj.canvas.canvas.height; rh = obj.canvas.canvas.width; }
// Copy the canvas, put it back in the correct direction
if (obj.tcanvas == null) obj.tcanvas = document.createElement('canvas');
var tcanvasctx = obj.tcanvas.getContext('2d');
@ -421,7 +431,7 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
if (obj.rotation == 1) tcanvasctx.drawImage(obj.canvas.canvas, -obj.canvas.canvas.width, 0);
if (obj.rotation == 2) tcanvasctx.drawImage(obj.canvas.canvas, -obj.canvas.canvas.width, -obj.canvas.canvas.height);
if (obj.rotation == 3) tcanvasctx.drawImage(obj.canvas.canvas, 0, -obj.canvas.canvas.height);
// Change the size and orientation and copy the canvas back into the rotation
if (obj.rotation == 0 || obj.rotation == 2) { obj.canvas.canvas.height = rw; obj.canvas.canvas.width = rh; }
if (obj.rotation == 1 || obj.rotation == 3) { obj.canvas.canvas.height = rh; obj.canvas.canvas.width = rw; }
@ -429,16 +439,16 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
obj.canvas.rotate((newrotation * 90) * Math.PI / 180);
obj.rotation = newrotation;
obj.canvas.drawImage(obj.tcanvas, _rotX(0, 0), _rotY(0, 0));
obj.width = obj.canvas.canvas.width;
obj.height = obj.canvas.canvas.height;
if (obj.onScreenResize != null) obj.onScreenResize(obj, obj.width, obj.height, obj.CanvasId);
return true;
}
// ###END###{DesktopRotation}
function _fixColor(c) { return (c > 127) ? (c + 32) : c; }
function _SendRefresh() {
// ###BEGIN###{DesktopFocus}
if (obj.focusmode > 0) {
@ -447,34 +457,40 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
obj.Send(String.fromCharCode(3, 1) + ShortToStr(Math.max(Math.min(obj.ox, obj.mx) - obj.focusmode, 0)) + ShortToStr(Math.max(Math.min(obj.oy, obj.my) - obj.focusmode, 0)) + ShortToStr(df + Math.abs(obj.ox - obj.mx)) + ShortToStr(df + Math.abs(obj.oy - obj.my))); // FramebufferUpdateRequest
obj.ox = obj.mx;
obj.oy = obj.my;
} else
// ###END###{DesktopFocus} {
} else {
// ###END###{DesktopFocus}
// Request the entire screen
obj.Send(String.fromCharCode(3, 1, 0, 0, 0, 0) + ShortToStr(obj.rwidth) + ShortToStr(obj.rheight)); // FramebufferUpdateRequest
// ###BEGIN###{DesktopFocus}
}
// ###END###{DesktopFocus}
}
obj.Start = function () {
//obj.Debug("KVM-Start");
obj.state = 0;
obj.acc = "";
obj.ZRLEfirst = 1;
//obj.inbytes = 0;
//obj.outbytes = 0;
// ###BEGIN###{Inflate}
inflate_start();
obj.inflate.inflateReset();
// ###END###{Inflate}
for (var i in obj.sparecache) { delete obj.sparecache[i]; }
}
obj.Stop = function () {
obj.UnGrabMouseInput();
obj.UnGrabKeyInput();
obj.parent.Stop();
}
obj.Send = function (x) {
//obj.Debug("KSend(" + x.length + "): " + rstr2hex(x));
//obj.outbytes += x.length;
obj.parent.Send(x);
}
/*
Intel AMT only recognizes a small subset of keysym characters defined in the keysymdef.h so you dont need to
implement all the languages (this is taken care by the USB Scancode Extension in RFB4.0 protocol).
@ -535,9 +551,9 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
obj.sendkey(kk, d);
return obj.haltEvent(e);
}
obj.sendkey = function (k, d) { obj.Send(String.fromCharCode(4, d, 0, 0) + IntToStr(k)); }
obj.SendCtrlAltDelMsg = function () { obj.sendcad(); }
obj.sendcad = function () {
obj.sendkey(0xFFE3, 1); // Control
@ -547,10 +563,10 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
obj.sendkey(0xFFE9, 0); // Alt
obj.sendkey(0xFFE3, 0); // Control
}
var _MouseInputGrab = false;
var _KeyInputGrab = false;
obj.GrabMouseInput = function () {
if (_MouseInputGrab == true) return;
var c = obj.canvas.canvas;
@ -560,7 +576,7 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
//if (navigator.userAgent.match(/mozilla/i)) c.DOMMouseScroll = obj.xxDOMMouseScroll; else c.onmousewheel = obj.xxMouseWheel;
_MouseInputGrab = true;
}
obj.UnGrabMouseInput = function () {
if (_MouseInputGrab == false) return;
var c = obj.canvas.canvas;
@ -570,7 +586,7 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
//if (navigator.userAgent.match(/mozilla/i)) c.DOMMouseScroll = null; else c.onmousewheel = null;
_MouseInputGrab = false;
}
obj.GrabKeyInput = function () {
if (_KeyInputGrab == true) return;
document.onkeyup = obj.handleKeyUp;
@ -578,7 +594,7 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
document.onkeypress = obj.handleKeys;
_KeyInputGrab = true;
}
obj.UnGrabKeyInput = function () {
if (_KeyInputGrab == false) return;
document.onkeyup = null;
@ -586,12 +602,12 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
document.onkeypress = null;
_KeyInputGrab = false;
}
obj.handleKeys = function (e) { return obj.haltEvent(e); }
obj.handleKeyUp = function (e) { return _keyevent(0, e); }
obj.handleKeyDown = function (e) { return _keyevent(1, e); }
obj.haltEvent = function (e) { if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); return false; }
// RFB "PointerEvent" and mouse handlers
obj.mousedown = function (e) { obj.buttonmask |= (1 << e.button); return obj.mousemove(e); }
obj.mouseup = function (e) { obj.buttonmask &= (0xFFFF - (1 << e.button)); return obj.mousemove(e); }
@ -600,15 +616,17 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
var pos = obj.getPositionOfControl(Q(obj.canvasid));
obj.mx = (e.pageX - pos[0]) * (obj.canvas.canvas.height / Q(obj.canvasid).offsetHeight);
obj.my = ((e.pageY - pos[1] + (scrolldiv ? scrolldiv.scrollTop : 0)) * (obj.canvas.canvas.width / Q(obj.canvasid).offsetWidth));
// ###BEGIN###{DesktopRotation}
obj.mx2 = _crotX(obj.mx, obj.my);
obj.my = _crotY(obj.mx, obj.my);
obj.mx = obj.mx2;
if (obj.noMouseRotate != true) {
obj.mx2 = _crotX(obj.mx, obj.my);
obj.my = _crotY(obj.mx, obj.my);
obj.mx = obj.mx2;
}
// ###END###{DesktopRotation}
obj.Send(String.fromCharCode(5, obj.buttonmask) + ShortToStr(obj.mx) + ShortToStr(obj.my));
// ###BEGIN###{DesktopFocus}
// Update focus area if we are in focus mode
QV('DeskFocus', obj.focusmode);
@ -627,11 +645,10 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
q.height = ((df * qx) - 6) + 'px';
}
// ###END###{DesktopFocus}
return obj.haltEvent(e);
}
obj.mousewheel = function (e) { }
obj.getPositionOfControl = function (Control) {
var Position = Array(2);
Position[0] = Position[1] = 0;
@ -642,6 +659,6 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
}
return Position;
}
return obj;
}