var base64_val = [ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 255,255,255,255,255,255,255,255,255,255,255, 62,255,255,255, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,255,255,255, 0,255,255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,255,255,255,255,255, 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,255,255,255,255,255 ] function base64_8(str, index) { var v = (base64_val[str.charCodeAt(index)]) + (base64_val[str.charCodeAt(index+1)] << 6); return v; } function base64_16(str, index) { var v = (base64_val[str.charCodeAt(index)]) + (base64_val[str.charCodeAt(index+1)] << 6) + (base64_val[str.charCodeAt(index+2)] << 12); return v; } function base64_16s(str, index) { var v = base64_16(str, index); if (v > 32767) return v - 65536; else return v; } function base64_24(str, index) { var v = (base64_val[str.charCodeAt(index)]) + (base64_val[str.charCodeAt(index+1)] << 6) + (base64_val[str.charCodeAt(index+2)] << 12) + (base64_val[str.charCodeAt(index+3)] << 18); return v; } function base64_32(str, index) { var v = (base64_val[str.charCodeAt(index)]) + (base64_val[str.charCodeAt(index+1)] << 6) + (base64_val[str.charCodeAt(index+2)] << 12) + (base64_val[str.charCodeAt(index+3)] << 18) + (base64_val[str.charCodeAt(index+4)] << 24) + (base64_val[str.charCodeAt(index+5)] << 30); return v; } function createXHR() { try { return new XMLHttpRequest(); } catch(e) {} try { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); } catch (e) {} try { return new ActiveXObject("Msxml2.XMLHTTP.3.0"); } catch (e) {} try { return new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) {} try { return new ActiveXObject("Microsoft.XMLHTTP"); } catch (e) {} return null; } var last_serial = 0; var last_x = 0; var last_y = 0; var window_with_mouse = 0; var surfaces = {}; var outstanding_commands = new Array(); var input_socket = null; function initContext(canvas, x, y, id) { canvas.surface_id = id; canvas.style["position"] = "absolute" canvas.style["left"] = x + "px" canvas.style["top"] = y + "px" canvas.style["display"] = "none" context = canvas.getContext("2d") context.globalCompositeOperation = "src-over" context.fillRect(0, 0, canvas.width, canvas.height); document.body.appendChild(canvas) return context } function handleCommands(cmd_obj) { var cmd = cmd_obj.data; var i = cmd_obj.pos; while (i < cmd.length) { var command = cmd[i++]; last_serial = base64_32(cmd, i); i = i + 6; switch (command) { /* create new surface */ case 's': var id = base64_16(cmd, i); i = i + 3; var x = base64_16(cmd, i); i = i + 3; var y = base64_16(cmd, i); i = i + 3; var w = base64_16(cmd, i); i = i + 3; var h = base64_16(cmd, i); i = i + 3; var surface = document.createElement("canvas"); surface.width = w; surface.height = h; surfaces[id] = initContext(surface, x, y, id); break; /* show a surface */ case 'S': var id = base64_16(cmd, i); i = i + 3; surfaces[id].canvas.style["display"] = "inline"; break; /* hide a surface */ case 'H': var id = base64_16(cmd, i); i = i + 3; surfaces[id].canvas.style["display"] = "inline"; break; /* delete surface */ case 'd': var id = base64_16(cmd, i); i = i + 3; var canvas = surfaces[id].canvas delete surfaces[id] canvas.parentNode.removeChild(canvas); break; /* move a surface */ case 'm': var id = base64_16(cmd, i); i = i + 3; var x = base64_16(cmd, i); i = i + 3; var y = base64_16(cmd, i); i = i + 3; surfaces[id].canvas.style["left"] = x + "px"; surfaces[id].canvas.style["top"] = y + "px"; break; /* resize a surface */ case 'r': var id = base64_16(cmd, i); i = i + 3; var w = base64_16(cmd, i); i = i + 3; var h = base64_16(cmd, i); i = i + 3; surfaces[id].canvas.width = w; surfaces[id].canvas.height = h; break; /* put image data surface */ case 'i': var id = base64_16(cmd, i); i = i + 3; var x = base64_16(cmd, i); i = i + 3; var y = base64_16(cmd, i); i = i + 3; var size = base64_32(cmd, i); i = i + 6; var url = cmd.slice(i, i + size); i = i + size; var img = new Image(); img.src = url if (img.complete) { surfaces[id].drawImage(img, x, y); } else { cmd_obj.pos = i; img.onload = function() { surfaces[id].drawImage(img, x, y); handleOutstanding(); } return false } break; /* copy rects */ case 'b': var id = base64_16(cmd, i); i = i + 3; var nrects = base64_16(cmd, i); i = i + 3; var context = surfaces[id]; context.save(); var minx; var miny; var maxx; var maxy; for (var r = 0; r < nrects; r++) { var x = base64_16(cmd, i); i = i + 3; var y = base64_16(cmd, i); i = i + 3; var w = base64_16(cmd, i); i = i + 3; var h = base64_16(cmd, i); i = i + 3; context.rect(x, y, w, h); if (r == 0) { minx = x; miny = y; maxx = x + w; maxy = y + h; } else { if (x < minx) minx = x; if (y < miny) miny = y; if (x + w > maxx) maxx = x + w; if (y + h > maxy) maxy = y + h; } } context.clip() var dx = base64_16s(cmd, i); i = i + 3; var dy = base64_16s(cmd, i); i = i + 3; context.drawImage(context.canvas, minx - dx, miny - dy, maxx - minx, maxy - miny, minx, miny, maxx - minx, maxy - miny); context.restore(); break; case 'q': // Query pointer var id = base64_16(cmd, i); i = i + 3; send_input ("q", [last_x, last_y]); break; default: alert("Unknown op " + command); } } return true; } function handleOutstanding() { while (outstanding_commands.length > 0) { var cmd = outstanding_commands.shift(); if (!handleCommands(cmd)) { outstanding_commands.unshift(cmd); return; } } } function handleLoad(event) { var cmd_obj = {}; cmd_obj.data = event.target.responseText; cmd_obj.pos = 0; outstanding_commands.push(cmd_obj); if (outstanding_commands.length == 1) { handleOutstanding() } } function get_surface_id(ev) { var id = ev.target.surface_id; if (id != undefined) return id; return 0; } function send_input(cmd, args) { if (input_socket != null) { input_socket.send(cmd + ([last_serial].concat(args)).join(",")); } } function get_document_coordinates(element) { var res = new Object(); res.x = element.offsetLeft; res.y = element.offsetTop; var offsetParent = element.offsetParent; while (offsetParent != null) { res.x += offsetParent.offsetLeft; res.y += offsetParent.offsetTop; offsetParent = offsetParent.offsetParent; } return res; } function getPositionsFromEvent(ev, relativeId) { var res = Object(); res.root_x = ev.pageX; res.root_y = ev.pageY; res.win_x = ev.pageX; res.win_y = ev.pageY; if (relativeId != 0) { var pos = get_document_coordinates(ev.target); res.win_x = res.win_x - pos.x; res.win_y = res.win_y - pos.y; } last_x = res.root_x; last_y = res.root_y; return res; } function on_mouse_move (ev) { var id = get_surface_id(ev); var pos = getPositionsFromEvent(ev, id); send_input ("m", [id, pos.root_x, pos.root_y, pos.win_x, pos.win_y, ev.timeStamp]); } function on_mouse_over (ev) { var id = get_surface_id(ev); var pos = getPositionsFromEvent(ev, id); window_with_mouse = id; if (window_with_mouse != 0) { send_input ("e", [id, pos.root_x, pos.root_y, pos.win_x, pos.win_y, ev.timeStamp]); } } function on_mouse_out (ev) { var id = get_surface_id(ev); var pos = getPositionsFromEvent(ev, id); if (id != 0) { send_input ("l", [id, pos.root_x, pos.root_y, pos.win_x, pos.win_y, ev.timeStamp]); } window_with_mouse = 0; } function on_mouse_down (ev) { var id = get_surface_id(ev); var pos = getPositionsFromEvent(ev, id); send_input ("b", [id, pos.root_x, pos.root_y, pos.win_x, pos.win_y, ev.timeStamp, ev.button]); } function on_mouse_up (ev) { var id = get_surface_id(ev); var pos = getPositionsFromEvent(ev, id); send_input ("B", [id, pos.root_x, pos.root_y, pos.win_x, pos.win_y, ev.timeStamp, ev.button]); } var last_key_down = 0; function on_key_down (ev) { var key_code = ev.keyCode; if (key_code != last_key_down) { send_input ("k", [key_code, ev.timeStamp]); last_key_down = key_code; } } function on_key_up (ev) { var key_code = ev.keyCode; send_input ("K", [key_code, ev.timeStamp]); last_key_down = 0; } function cancel_event(ev) { ev = ev ? ev : window.event; if (ev.stopPropagation) ev.stopPropagation(); if (ev.preventDefault) ev.preventDefault(); ev.cancelBubble = true; ev.cancel = true; ev.returnValue = false; return false; } function on_mouse_wheel(ev) { ev = ev ? ev : window.event; var id = get_surface_id(ev); var pos = getPositionsFromEvent(ev, id); var offset = ev.detail ? ev.detail : ev.wheelDelta; var dir = 0 if (offset > 0) dir = 1; send_input ("s", [id, pos.root_x, pos.root_y, pos.win_x, pos.win_y, ev.timeStamp, dir]) return cancel_event(ev); } function connect() { var xhr = createXHR(); if (xhr) { if (typeof xhr.multipart == 'undefined') { alert("Sorry, this example only works in browsers that support multipart."); return; } xhr.multipart = true; xhr.open("GET", "/output", true); xhr.onload = handleLoad; xhr.send(null); } if ("WebSocket" in window) { var loc = window.location.toString().replace("http:", "ws:"); loc = loc.substr(0, loc.lastIndexOf('/')) + "/input"; var ws = new WebSocket(loc, "broadway"); ws.onopen = function() { input_socket = ws; }; ws.onclose = function() { input_socket = null; }; } else { alert("WebSocket not supported, input will not work!"); } document.oncontextmenu = function () { return false; } document.onmousemove = on_mouse_move; document.onmouseover = on_mouse_over; document.onmouseout = on_mouse_out; document.onmousedown = on_mouse_down; document.onmouseup = on_mouse_up; document.onkeydown = on_key_down; document.onkeyup = on_key_up; if (document.addEventListener) { document.addEventListener('DOMMouseScroll', on_mouse_wheel, false); document.addEventListener('mousewheel', on_mouse_wheel, false); } else if (document.attachEvent) { element.attachEvent("onmousewheel", on_mouse_wheel); } }