HTML5远程桌面 - 第二部分






4.67/5 (3投票s)
基于 AJAX、JSON 和 HTML5 构建的远程桌面软件
引言
在本文的第一部分中,我展示了如何逐个窗口进行屏幕捕获,以及如何使用剪切区域和位图比较来构建一个包含要发送给客户端的已更改位图区域的列表。 在第二部分中,我们将看到如何将所有这些信息发送给客户端。
代码 (第二部分)
以下 JSON 是一个桌面捕获的示例
{"status:":1,"desktopWidth":1280,"desktopHeight":800,
"cursor":"default","cursorX":241,"cursorY":525,
"windows": [ { "hwnd":"196724","zidx":1,"desktop":"Default",
"left":0,"top":0,"width":1280,"height":800},
{ "hwnd":"8521744","zidx":2,"desktop":"Default","left":364,
"top":59,"width":806,"height":667},
{ "hwnd":"8129930","zidx":3,"desktop":"Default","left":-8,
"top":-8,"width":1296,"height":776},
{ "hwnd":"1247020","zidx":4,"desktop":"Default","left":244,
"top":28,"width":1023,"height":728},
{ "hwnd":"8785068","zidx":5,"desktop":"Default","left":-8,
"top":-8,"width":1296,"height":776,"imgs": [
{ "x":8,"y":8,"w":1280,"h":123,"img":
"data:image/jpeg;base64,/9j/4......" }]},
{ "hwnd":"6033806","zidx":6,"desktop":"Default","left":-1,
"top":479,"width":426,"height":22,"imgs": [
{ "x":1,"y":0,"w":425,"h":22,"img":
"data:image/jpeg;base64,/9j/4AAQ......" }]},
{ "hwnd":"196708","zidx":7,"desktop":"Default","left":0,
"top":760,"width":1280,"height":40,"imgs": [
{ "x":53,"y":0,"w":1227,"h":40,"img":
"data:image/jpeg;base64,/9j/4AA......" }]},
{ "hwnd":"131186","zidx":8,"desktop":"Default","left":0,
"top":760,"width":54,"height":40,"imgs": [
{ "x":0,"y":0,"w":54,"h":40,"img":
"data:image/jpeg;base64,/9j/4AAQSkZJ......" }]}]]}
“windows” 数组包含桌面上的所有可见窗口。 每个项目包含窗口句柄(用于标识目的)、其边界矩形、其所属的桌面、其相对 z 顺序以及一个图像数组。 每个图像对应于该特定窗口上已更改的区域。 如果没有更改,则不存在“imgs
” 数组。
function reload() {
scale = getScale();
var url = baseUrl + "json?id=" + sessionStatus.id;
clearTimeout(jsonTimeout);
jsonTimeout = setTimeout(onJsonTimeout,jsonTimeoutValue);
$.getJSON(url, function (obj) {
try {
$.each(obj.windows, function (i, win) {
processWindow(win);
})
for (var i = deskDiv.children.length - 1; i >= 0; i--) {
var found = false;
var canvas = deskDiv.children[i];
$.each(obj.windows, function (i, win) {
var canvasid = "canvas" + win.hwnd;
if (canvas.id == canvasid) {
found = true;
}
})
if (!found) {
canvas.style.display = "none";
canvas.innerHTML = '';
deskDiv.removeChild(canvas);
}
}
}
catch (err) {
if (sessionStatus.active) {
setTimeout(reload, 1);
}
}
});
}
对于收到的每个“window”项目,都会调用 processWindow
方法,创建或重用一个 canvas 元素。 所有属于 JSON 中不存在的窗口的 canvas 元素都对应于已经关闭的窗口。 这些将在“for (var i = deskDiv.children.length - 1; i >= 0; i--)
”循环中被清除。
ProcessWindows
函数使用 hwnd
作为其 id 的一部分,为每个窗口创建或重用一个 canvas。 它还根据收到的信息设置 canvas 坐标及其 zindex
,并遍历图像数组以将它们复制到 canvas 表面。
function createCanvas(win) {
var canvas = document.createElement("canvas");
canvas.visibility = 'visible';
canvas.display = 'block';
canvas.style.position = 'absolute';
canvas.style.left = (win.left-sessionStatus.viewLeft)+'px';
canvas.style.top = (win.top-sessionStatus.viewTop)+'px';
canvas.style.zIndex = win.zidx;
canvas.width = deskDiv.offsetWidth;
canvas.height = deskDiv.offsetHeight;
canvas.id = "canvas" + win.hwnd;
deskDiv.appendChild(canvas);
return canvas;
}
function processWindow(win) {
var canvasid = "canvas" + win.hwnd;
var canvas = document.getElementById(canvasid);
if (!canvas) {
canvas = createCanvas(win);
}
deskDiv.style.marginLeft = getDeltaX() + 'px';
deskDiv.style.marginTop = getDeltaY() + 'px';
if ((win.width == 0) || (win.height == 0)) {
canvas.style.visibility = "hidden";
canvas.style.zIndex = -1;
} else {
canvas.style.left = (win.left-sessionStatus.viewLeft) + 'px';
canvas.style.top = (win.top-sessionStatus.viewTop) + 'px';
canvas.style.clip = 'rect(0px,' + win.width + 'px,' + win.height + 'px,0px)';
canvas.style.visibility = "visible";
canvas.style.zIndex = win.zidx;
}
if (win.imgs != null) {
var context = canvas.getContext('2d');
if (!context || !context.drawImage) {
alert("no hay canvas");
return;
};
$.each(win.imgs, function (i, imgpart) {
var img = new Image();
img.id = "imgcanvas";
img.style.display = "none";
img.onload = function () {
context.drawImage(img, imgpart.x , imgpart.y, img.width, img.height);
}
img.src = imgpart.img;
})
}
};
更新后的源代码始终可以在 此处找到。
历史
本文的第一部分可以在 此处找到。 ThinVNC 目前是 Beta 软件。