diff --git a/RemoteDesktop/build/debug/main.js b/RemoteDesktop/build/debug/main.js index 114a526..2d8801e 100644 --- a/RemoteDesktop/build/debug/main.js +++ b/RemoteDesktop/build/debug/main.js @@ -1 +1,770 @@ -(function(){var e,t,n,s;(e=class e extends this.OS.GUI.BasicDialog{constructor(){super("ConnectionDialog",e.scheme)}main(){return super.main(),this.find("bbp").data=[{text:"16 bits",value:16,selected:!0},{text:"32 bits",value:32}],this.find("jq").value=40,this.find("bt-ok").onbtclick=e=>{var t;if(this.handle)return t={wvnc:this.find("txtWVNC").value,server:this.find("txtServer").value,bbp:this.find("bbp").selectedItem.data.value,quality:this.find("jq").value},this.handle(t),this.quit()},this.find("bt-cancel").onbtclick=e=>this.quit()}}).scheme='\n \n \n \n
\n \n \n
\n \n \n \n
\n \n \n
\n
\n
\n
\n',(t=class e extends this.OS.GUI.BasicDialog{constructor(){super("CredentialDialog",e.scheme)}main(){return this.find("bt-ok").onbtclick=()=>{var e;return this.handle?(e={username:this.find("txtUser").value,password:this.find("txtPass").value},this.handle(e),this.quit()):this.quit()},this.find("bt-cancel").onbtclick=()=>this.quit()}}).scheme='\n \n \n \n \n
\n \n \n
\n
\n
\n
',n=class extends this.OS.application.BaseApplication{constructor(e){super("RemoteDesktop",e)}main(){return this.canvas=this.find("screen"),this.container=this.find("container"),this.client=new s({element:this.canvas}),this.bindKey("CTRL-SHIFT-V",e=>this.pasteText()),this.client.ondisconnect=()=>this.showConnectionDialog(),this.client.onresize=()=>this.setScale(),this.client.onpassword=()=>new Promise((e,t)=>this.openDialog("PromptDialog",{title:__("VNC password"),label:__("VNC password"),value:"password",type:"password"}).then((function(t){return e(t)}))),this.client.oncopy=e=>this._api.setClipboard(e),this.client.oncredential=()=>new Promise((e,n)=>this.openDialog(new t,{title:__("User credential")}).then((function(t){return e(t.username,t.password)}))),this.on("resize",e=>this.setScale()),this.on("focus",e=>$(this.canvas).focus()),this.client.init().then(()=>this.showConnectionDialog())}pasteText(){var e;if(this.client)return e=e=>{if(e&&""!==e)return this.client.sendTextAsClipboard(e)},this._api.getClipboard().then(t=>e(t)).catch(t=>(this.error(__("Unable to paste"),t),this.openDialog("TextDialog",{title:"Paste text"}).then(t=>e(t)).catch(e=>this.error(e.toString(),e))))}setScale(){var e,t,n,s;if(this.client&&this.client.resolution)return s=$(this.container).width(),e=$(this.container).height(),(t=s/this.client.resolution.w)>(n=e/this.client.resolution.h)?this.client.setScale(n):this.client.setScale(t)}menu(){return[{text:"__(Connection)",nodes:[{text:"__(New Connection)",dataid:this.name+"-new"},{text:"__(Disconnect)",dataid:this.name+"-close"}],onchildselect:e=>{if(this.client)return this.client.disconnect(!1)}}]}showConnectionDialog(){if(this.client)return this.openDialog(new e,{title:__("Connection")}).then(e=>(this.client.ws=e.wvnc,this.client.connect(e.server,e)))}cleanup(){return this.client&&this.client.disconnect(!0),this.client=void 0}},this.OS.register("RemoteDesktop",n),s=class{constructor(e){var t,n;this.socket=void 0,this.ws=void 0,this.canvas=void 0,n="pkg://RemoteDesktop/decoder_asm.js".asFileHandle().getlink(),this.scale=1,e.ws&&(this.ws=e.ws),this.canvas=e.element,"string"==typeof this.canvas&&(this.canvas=document.getElementById(this.canvas)),this.decoder=new Worker(n),this.enableEvent=!1,this.pingto=!1,t=this,this.mouseMask=0,this.decoder.onmessage=function(e){return t.process(e.data)}}init(){var e;return e=this,new Promise((function(t,n){return e.canvas?($(e.canvas).attr("tabindex","1"),$(e.canvas).on("focus",()=>e.resetModifierKeys()),e.initInputEvent(),t()):n("Canvas is not set")}))}initInputEvent(){var e,t,n,s;if(n=this,this.canvas&&(t=function(e){var t;return t=n.canvas.getBoundingClientRect(),{x:Math.floor((e.clientX-t.left)/n.scale),y:Math.floor((e.clientY-t.top)/n.scale)}},s=function(e){var s;if(n.enableEvent)return s=t(e),n.sendPointEvent(s.x,s.y,n.mouseMask)},n.canvas))return n.canvas.oncontextmenu=function(e){return e.preventDefault(),!1},n.canvas.onmousemove=function(e){return s(e)},n.canvas.onmousedown=function(e){var t;return t=1<this.disconnect(!0),window.addEventListener("unload",e),window.addEventListener("beforeunload",e)}initCanvas(e,t,n){return this.canvas.width=e,this.canvas.height=t,this.resolution={w:e,h:t},this.decoder.postMessage(this.resolution),this.setScale(this.scale)}process(e){var t,n,s;if(this.socket)return n=new Uint8Array(e.pixels),(s=(t=this.canvas.getContext("2d",{alpha:!1})).createImageData(e.w,e.h)).data.set(n),t.putImageData(s,e.x,e.y)}setScale(e){if(this.scale=e,this.canvas)return this.canvas.style.transformOrigin="0 0",this.canvas.style.transform="scale("+e+")"}connect(e,t){var n;if(n=this,this.disconnect(!1),this.ws)return this.socket=new WebSocket(this.ws),this.socket.binaryType="arraybuffer",this.socket.onopen=function(){return console.log("socket opened"),n.initConnection(e,t)},this.socket.onmessage=function(e){return n.consume(e)},this.socket.onerror=e=>n.onerror("Websocket error"),this.socket.onclose=function(){return n.socket=null,n.canvas.style.cursor="auto",n.canvas&&n.resolution&&n.canvas.getContext("2d").clearRect(0,0,n.resolution.w,n.resolution.h),n.pingto&&clearTimeout(n.pingto),n.pingto=void 0,n.ondisconnect(),console.log("socket closed")}}disconnect(e){return this.socket&&this.socket.close(),this.socket=void 0,e&&this.decoder.terminate(),this.enableEvent=!1}initConnection(e,t){var n;return(n=new Uint8Array(e.length+2))[0]=16,n[1]=50,t&&(t.bbp&&(n[0]=t.bbp),t.quality&&(n[1]=t.quality)),n.set((new TextEncoder).encode(e),2),this.socket.send(this.buildCommand(1,n))}resetModifierKeys(){if(this.socket&&this.enableEvent)return this.sendKeyEvent(65511,0),this.sendKeyEvent(65512,0),this.sendKeyEvent(65505,0),this.sendKeyEvent(65507,0),this.sendKeyEvent(65513,0)}sendPointEvent(e,t,n){var s;if(this.socket&&this.enableEvent)return(s=new Uint8Array(5))[0]=255&e,s[1]=e>>8,s[2]=255&t,s[3]=t>>8,s[4]=n,this.socket.send(this.buildCommand(5,s))}sendKeyEvent(e,t){var n;if(this.socket&&this.enableEvent)return(n=new Uint8Array(3))[0]=255&e,n[1]=e>>8&255,n[2]=t,this.socket.send(this.buildCommand(6,n))}sendPing(){if(this.socket)return this.socket.send(this.buildCommand(8,"PING WVNC"))}buildCommand(e,t){var n,s;switch(s=void 0,typeof t){case"string":s=(new TextEncoder).encode(t);break;case"number":s=new Uint8Array([t]);break;default:s=t}return(n=new Uint8Array(s.length+3))[0]=e,n[2]=s.length>>8,n[1]=15&s.length,n.set(s,3),n.buffer}oncopy(e){return console.log("Get clipboard text: "+e)}onpassword(){return new Promise((function(e,t){return t("onpassword is not implemented")}))}sendTextAsClipboard(e){var t;if(this.socket)return this.socket.send(this.buildCommand(7,e)),t="v".charCodeAt(0),this.sendKeyEvent(65507,1),this.sendKeyEvent(t,1),this.sendKeyEvent(t,0),this.sendKeyEvent(65507,0)}oncredential(){return new Promise((function(e,t){return t("oncredential is not implemented")}))}onerror(e){return console.log("Error",e)}onresize(){return console.log("resize")}ondisconnect(){return console.log("disconnect")}consume(e){var t,n,s,i,a,o,r;switch(t=(n=new Uint8Array(e.data))[0],o=this,t){case 254:return n=n.subarray(1,n.length-1),s=new TextDecoder("utf-8"),this.onerror(s.decode(n));case 129:return console.log("Request for password"),this.enableEvent=!1,this.onpassword().then((function(e){return o.socket.send(o.buildCommand(2,e)),o.enableEvent=!0}));case 130:return console.log("Request for login"),this.enableEvent=!1,this.oncredential().then((function(e,t){var n;return(n=new Uint8Array(e.length+t.length+1)).set((new TextEncoder).encode(e),0),n.set(["\0"],e.length),n.set((new TextEncoder).encode(t),e.length+1),o.socket.send(o.buildCommand(3,n)),o.enableEvent=!0}));case 131:if(r=n[1]|n[2]<<8,a=n[3]|n[4]<<8,this.initCanvas(r,a),this.socket.send(this.buildCommand(4,1)),this.enableEvent=!0,this.onresize(),this.pingto)return;return i=()=>(this.sendPing(),this.pingto=setTimeout(i,5e3)),this.pingto=setTimeout(i,5e3);case 132:return this.decoder.postMessage(n.buffer,[n.buffer]),this.socket.send(this.buildCommand(4,1));case 133:return n=n.subarray(1),s=new TextDecoder("utf-8"),this.oncopy(s.decode(n)),this.socket.send(this.buildCommand(4,1));default:return console.log(t)}}},window.WVNC=s}).call(this); \ No newline at end of file +(function() { + var ConnectionDialog, CredentialDialog, RemoteDesktop, WVNC; + + ConnectionDialog = class ConnectionDialog extends this.OS.GUI.BasicDialog { + constructor() { + super("ConnectionDialog", ConnectionDialog.scheme); + } + + main() { + super.main(); + this.find("bbp").data = [ + { + text: "16 bits", + value: 16, + selected: true + }, + { + text: "32 bits", + value: 32 + } + ]; + this.find("jq").value = 40; + this.find("bt-ok").onbtclick = (e) => { + var data; + if (!this.handle) { + return; + } + data = { + wvnc: (this.find("txtWVNC")).value, + server: (this.find("txtServer")).value, + bbp: (this.find("bbp")).selectedItem.data.value, + quality: (this.find("jq")).value + }; + this.handle(data); + return this.quit(); + }; + return this.find("bt-cancel").onbtclick = (e) => { + return this.quit(); + }; + } + + }; + + ConnectionDialog.scheme = ` + + + +
+ + +
+ + + +
+ + +
+
+
+
+`; + + CredentialDialog = class CredentialDialog extends this.OS.GUI.BasicDialog { + constructor() { + super("CredentialDialog", CredentialDialog.scheme); + } + + main() { + this.find("bt-ok").onbtclick = () => { + var data; + if (!this.handle) { + return this.quit(); + } + data = { + username: (this.find("txtUser")).value, + password: (this.find("txtPass")).value + }; + this.handle(data); + return this.quit(); + }; + return this.find("bt-cancel").onbtclick = () => { + return this.quit(); + }; + } + + }; + + CredentialDialog.scheme = ` + + + + +
+ + +
+
+
+
`; + + RemoteDesktop = class RemoteDesktop extends this.OS.application.BaseApplication { + constructor(args) { + super("RemoteDesktop", args); + } + + main() { + this.canvas = this.find("screen"); + this.container = this.find("container"); + this.client = new WVNC({ + element: this.canvas + }); + this.bindKey("CTRL-SHIFT-V", (e) => { + return this.pasteText(); + }); + //@client.onerror = (m) => + // @error m.toString() + // @showConnectionDialog() + this.client.ondisconnect = () => { + return this.showConnectionDialog(); + }; + this.client.onresize = () => { + return this.setScale(); + }; + this.client.onpassword = () => { + return new Promise((r, e) => { + return this.openDialog("PromptDialog", { + title: __("VNC password"), + label: __("VNC password"), + value: "password", + type: "password" + }).then(function(d) { + return r(d); + }); + }); + }; + this.client.oncopy = (text) => { + return this._api.setClipboard(text); + }; + this.client.oncredential = () => { + return new Promise((r, e) => { + return this.openDialog(new CredentialDialog(), { + title: __("User credential") + }).then(function(d) { + return r(d.username, d.password); + }); + }); + }; + this.on("resize", (e) => { + return this.setScale(); + }); + this.on("focus", (e) => { + return $(this.canvas).focus(); + }); + return this.client.init().then(() => { + return this.showConnectionDialog(); + }); + } + + pasteText() { + var cb; + if (!this.client) { + return; + } + cb = (text) => { + if (!(text && text !== "")) { + return; + } + return this.client.sendTextAsClipboard(text); + }; + return this._api.getClipboard().then((text) => { + return cb(text); + }).catch((e) => { + this.error(__("Unable to paste"), e); + //ask for user to enter the text manually + return this.openDialog("TextDialog", { + title: "Paste text" + }).then((text) => { + return cb(text); + }).catch((err) => { + return this.error(err.toString(), err); + }); + }); + } + + setScale() { + var h, sx, sy, w; + if (!(this.client && this.client.resolution)) { + return; + } + w = $(this.container).width(); + h = $(this.container).height(); + sx = w / this.client.resolution.w; + sy = h / this.client.resolution.h; + if (sx > sy) { + return this.client.setScale(sy); + } else { + return this.client.setScale(sx); + } + } + + menu() { + return [ + { + text: "__(Connection)", + nodes: [ + { + text: "__(New Connection)", + dataid: `${this.name}-new` + }, + { + text: "__(Disconnect)", + dataid: `${this.name}-close` + } + ], + onchildselect: (e) => { + if (this.client) { + return this.client.disconnect(false); + } + } + } + ]; + } + + showConnectionDialog() { + if (!this.client) { + return; + } + return this.openDialog(new ConnectionDialog(), { + title: __("Connection") + }).then((d) => { + this.client.ws = d.wvnc; + return this.client.connect(d.server, d); + }); + } + + cleanup() { + if (this.client) { + this.client.disconnect(true); + } + return this.client = void 0; + } + + }; + + this.OS.register("RemoteDesktop", RemoteDesktop); + + WVNC = class WVNC { + constructor(args) { + var me, worker; + this.socket = void 0; + this.ws = void 0; + this.canvas = void 0; + worker = "pkg://RemoteDesktop/decoder_asm.js".asFileHandle().getlink(); + this.scale = 1.0; + if (args.ws) { + this.ws = args.ws; + } + this.canvas = args.element; + if (typeof this.canvas === 'string') { + this.canvas = document.getElementById(this.canvas); + } + this.decoder = new Worker(worker); + this.enableEvent = false; + this.pingto = false; + me = this; + this.mouseMask = 0; + this.decoder.onmessage = function(e) { + return me.process(e.data); + }; + } + + init() { + var me; + me = this; + return new Promise(function(r, e) { + if (!me.canvas) { + return e('Canvas is not set'); + } + // fix keyboard event problem + $(me.canvas).attr('tabindex', '1'); + $(me.canvas).on("focus", () => { + return me.resetModifierKeys(); + }); + me.initInputEvent(); + return r(); + }); + } + + initInputEvent() { + var fn, getMousePos, me, sendMouseLocation; + me = this; + if (!this.canvas) { + return; + } + getMousePos = function(e) { + var pos, rect; + rect = me.canvas.getBoundingClientRect(); + pos = { + x: Math.floor((e.clientX - rect.left) / me.scale), + y: Math.floor((e.clientY - rect.top) / me.scale) + }; + return pos; + }; + sendMouseLocation = function(e) { + var p; + if (!me.enableEvent) { + return; + } + p = getMousePos(e); + return me.sendPointEvent(p.x, p.y, me.mouseMask); + }; + if (!me.canvas) { + return; + } + me.canvas.oncontextmenu = function(e) { + e.preventDefault(); + return false; + }; + me.canvas.onmousemove = function(e) { + return sendMouseLocation(e); + }; + me.canvas.onmousedown = function(e) { + var state; + state = 1 << e.button; + me.mouseMask = me.mouseMask | state; + return sendMouseLocation(e); + }; + //e.preventDefault() + me.canvas.onmouseup = function(e) { + var state; + state = 1 << e.button; + me.mouseMask = me.mouseMask & (~state); + return sendMouseLocation(e); + }; + //e.preventDefault() + me.canvas.onkeydown = me.canvas.onkeyup = function(e) { + var code, keycode; + // get the key code + keycode = e.keyCode; + //console.log e + switch (keycode) { + case 8: + code = 0xFF08; //back space + break; + case 9: + code = 0xFF09; // tab ? 0xff89 + break; + case 13: + code = 0xFF0D; // return + break; + case 27: + code = 0xFF1B; // esc + break; + case 46: + code = 0xFFFF; // delete to verify + break; + case 38: + code = 0xFF52; // up + break; + case 40: + code = 0xFF54; // down + break; + case 37: + code = 0xFF51; // left + break; + case 39: + code = 0xFF53; // right + break; + case 91: + code = 0xFFE7; // meta left + break; + case 93: + code = 0xFFE8; // meta right + break; + case 16: + code = 0xFFE1; // shift left + break; + case 17: + code = 0xFFE3; // ctrl left + break; + case 18: + code = 0xFFE9; // alt left + break; + case 20: + code = 0xFFE5; // capslock + break; + case 113: + code = 0xFFBF; // f2 + break; + case 112: + code = 0xFFBE; // f1 + break; + case 114: + code = 0xFFC0; // f3 + break; + case 115: + code = 0xFFC1; // f4 + break; + case 116: + code = 0xFFC2; // f5 + break; + case 117: + code = 0xFFC3; // f6 + break; + case 118: + code = 0xFFC4; // f7 + break; + case 119: + code = 0xFFC5; // f8 + break; + case 120: + code = 0xFFC6; // f9 + break; + case 121: + code = 0xFFC7; // f10 + break; + case 122: + code = 0xFFC8; // f11 + break; + case 123: + code = 0xFFC9; // f12 + break; + default: + code = e.key.charCodeAt(0); //if not e.ctrlKey and not e.altKey + } + //if ((keycode > 47 and keycode < 58) or (keycode > 64 and keycode < 91) or (keycode > 95 and keycode < 112) or (keycode > 185 and keycode < 193) or (keycode > 218 && keycode < 223)) + // code = e.key.charCodeAt(0) + //else + // code = keycode + e.preventDefault(); + if (!code) { + return; + } + if (e.type === "keydown") { + return me.sendKeyEvent(code, 1); + } else if (e.type === "keyup") { + return me.sendKeyEvent(code, 0); + } + }; + // mouse wheel event + this.canvas.addEventListener('wheel', function(e) { + var p; + if (!me.enableEvent) { + return; + } + //if (e.deltaY < 0) # up + p = getMousePos(e); + e.preventDefault(); + if (e.deltaY < 0) { + me.sendPointEvent(p.x, p.y, 8); + me.sendPointEvent(p.x, p.y, 0); + return; + } + me.sendPointEvent(p.x, p.y, 16); + return me.sendPointEvent(p.x, p.y, 0); + }); + // paste event + this.canvas.onpaste = function(e) { + var pastedText; + if (!me.enableEvent) { + return; + } + pastedText = void 0; + if (window.clipboardData && window.clipboardData.getData) { //IE + pastedText = window.clipboardData.getData('Text'); + } else if (e.clipboardData && e.clipboardData.getData) { + pastedText = e.clipboardData.getData('text/plain'); + } + if (!pastedText) { + return false; + } + e.preventDefault(); + return me.sendTextAsClipboard(pastedText); + }; + // global event + fn = (e) => { + return this.disconnect(true); + }; + window.addEventListener("unload", fn); + return window.addEventListener("beforeunload", fn); + } + + initCanvas(w, h, d) { + var me; + me = this; + this.canvas.width = w; + this.canvas.height = h; + this.resolution = { + w: w, + h: h + }; + this.decoder.postMessage(this.resolution); + //me.canvas.style.cursor = "none" + return this.setScale(this.scale); + } + + process(msg) { + var ctx, data, imgData; + if (!this.socket) { + this.socket.send(this.buildCommand(0x04, 1)); + return; + } + data = new Uint8Array(msg.pixels); + ctx = this.canvas.getContext("2d", { + alpha: false + }); + imgData = ctx.createImageData(msg.w, msg.h); + imgData.data.set(data); + ctx.putImageData(imgData, msg.x, msg.y); + // tell the server that we are ready + return this.socket.send(this.buildCommand(0x04, 1)); + } + + setScale(n) { + this.scale = n; + if (!this.canvas) { + return; + } + this.canvas.style.transformOrigin = '0 0'; + return this.canvas.style.transform = 'scale(' + n + ')'; + } + + connect(url, args) { + var me; + me = this; + this.disconnect(false); + if (!this.ws) { + return; + } + this.socket = new WebSocket(this.ws); + this.socket.binaryType = "arraybuffer"; + this.socket.onopen = function() { + console.log("socket opened"); + return me.initConnection(url, args); + }; + this.socket.onmessage = function(e) { + return me.consume(e); + }; + this.socket.onerror = (e) => { + return me.onerror("Websocket error"); + }; + return this.socket.onclose = function() { + me.socket = null; + me.canvas.style.cursor = "auto"; + if (me.canvas && me.resolution) { + me.canvas.getContext('2d').clearRect(0, 0, me.resolution.w, me.resolution.h); + } + if (me.pingto) { + clearTimeout(me.pingto); + } + me.pingto = void 0; + me.ondisconnect(); + return console.log("socket closed"); + }; + } + + disconnect(close_worker) { + if (this.socket) { + this.socket.close(); + } + this.socket = void 0; + if (close_worker) { + this.decoder.terminate(); + } + return this.enableEvent = false; + } + + initConnection(vncserver, params) { + var data; + //vncserver = "192.168.1.20:5901" + data = new Uint8Array(vncserver.length + 2); + data[0] = 16; // bbp + data[1] = 50; // jpeg quality + if (params) { + if (params.bbp) { + data[0] = params.bbp; + } + if (params.quality) { + data[1] = params.quality; + } + } + //# rate in milisecond + data.set((new TextEncoder()).encode(vncserver), 2); + return this.socket.send(this.buildCommand(0x01, data)); + } + + resetModifierKeys() { + if (!this.socket) { + return; + } + if (!this.enableEvent) { + return; + } + this.sendKeyEvent(0xFFE7, 0); // meta left + this.sendKeyEvent(0xFFE8, 0); // meta right + this.sendKeyEvent(0xFFE1, 0); // shift left + this.sendKeyEvent(0xFFE3, 0); // ctrl left + return this.sendKeyEvent(0xFFE9, 0); // alt left + } + + sendPointEvent(x, y, mask) { + var data; + if (!this.socket) { + return; + } + if (!this.enableEvent) { + return; + } + data = new Uint8Array(5); + data[0] = x & 0xFF; + data[1] = x >> 8; + data[2] = y & 0xFF; + data[3] = y >> 8; + data[4] = mask; + return this.socket.send(this.buildCommand(0x05, data)); + } + + sendKeyEvent(code, v) { + var data; + // console.log code, v + if (!this.socket) { + return; + } + if (!this.enableEvent) { + return; + } + data = new Uint8Array(3); + data[0] = code & 0xFF; + data[1] = (code >> 8) & 0xFF; + data[2] = v; + return this.socket.send(this.buildCommand(0x06, data)); + } + + sendPing() { + if (!this.socket) { + return; + } + return this.socket.send(this.buildCommand(0x08, 'PING WVNC')); + } + + buildCommand(hex, o) { + var cmd, data; + data = void 0; + switch (typeof o) { + case 'string': + data = (new TextEncoder()).encode(o); + break; + case 'number': + data = new Uint8Array([o]); + break; + default: + data = o; + } + cmd = new Uint8Array(data.length + 3); + cmd[0] = hex; + cmd[2] = data.length >> 8; + cmd[1] = data.length & 0x0F; + cmd.set(data, 3); + //console.log "the command is", cmd.buffer + return cmd.buffer; + } + + oncopy(text) { + return console.log("Get clipboard text: " + text); + } + + onpassword() { + return new Promise(function(resolve, reject) { + return reject("onpassword is not implemented"); + }); + } + + sendTextAsClipboard(text) { + var charcode; + if (!this.socket) { + return; + } + this.socket.send(this.buildCommand(0x07, text)); + // send ctrl-v to paste + charcode = 'v'.charCodeAt(0); + this.sendKeyEvent(0xFFE3, 1); // CTRL down + this.sendKeyEvent(charcode, 1); // v down + this.sendKeyEvent(charcode, 0); // v up + return this.sendKeyEvent(0xFFE3, 0); // CTRL up + } + + oncredential() { + return new Promise(function(resolve, reject) { + return reject("oncredential is not implemented"); + }); + } + + onerror(m) { + return console.log("Error", m); + } + + onresize() { + return console.log("resize"); + } + + ondisconnect() { + return console.log("disconnect"); + } + + consume(e) { + var cmd, data, dec, fn, h, me, w; + data = new Uint8Array(e.data); + cmd = data[0]; + me = this; + switch (cmd) { + case 0xFE: //error + data = data.subarray(1, data.length - 1); + dec = new TextDecoder("utf-8"); + return this.onerror(dec.decode(data)); + case 0x81: + console.log("Request for password"); + this.enableEvent = false; + return this.onpassword().then(function(pass) { + me.socket.send(me.buildCommand(0x02, pass)); + return me.enableEvent = true; + }); + case 0x82: + console.log("Request for login"); + this.enableEvent = false; + return this.oncredential().then(function(user, pass) { + var arr; + arr = new Uint8Array(user.length + pass.length + 1); + arr.set((new TextEncoder()).encode(user), 0); + arr.set(['\0'], user.length); + arr.set((new TextEncoder()).encode(pass), user.length + 1); + me.socket.send(me.buildCommand(0x03, arr)); + return me.enableEvent = true; + }); + case 0x83: + w = data[1] | (data[2] << 8); + h = data[3] | (data[4] << 8); + this.initCanvas(w, h); + // status command for ack + this.socket.send(this.buildCommand(0x04, 1)); + this.enableEvent = true; + // @resetModifierKeys() + this.onresize(); + if (this.pingto) { + return; + } + fn = () => { + this.sendPing(); + return this.pingto = setTimeout(fn, 5000); + }; + return this.pingto = setTimeout(fn, 5000); + case 0x84: + // send data to web assembly for decoding + return this.decoder.postMessage(data.buffer, [data.buffer]); + case 0x85: + // clipboard data from server + data = data.subarray(1); + dec = new TextDecoder("utf-8"); + this.oncopy(dec.decode(data)); + return this.socket.send(this.buildCommand(0x04, 1)); + default: + return console.log(cmd); + } + } + + }; + + window.WVNC = WVNC; + +}).call(this); diff --git a/RemoteDesktop/coffees/WVNC.coffee b/RemoteDesktop/coffees/WVNC.coffee index ef3268c..f547327 100644 --- a/RemoteDesktop/coffees/WVNC.coffee +++ b/RemoteDesktop/coffees/WVNC.coffee @@ -149,12 +149,15 @@ class WVNC process: (msg) -> if not @socket + @socket.send(@buildCommand 0x04, 1) return data = new Uint8Array msg.pixels ctx = @canvas.getContext "2d", { alpha: false } imgData = ctx.createImageData msg.w, msg.h imgData.data.set data ctx.putImageData imgData,msg.x, msg.y + # tell the server that we are ready + @socket.send(@buildCommand 0x04, 1) setScale: (n) -> @@ -329,7 +332,6 @@ class WVNC when 0x84 # send data to web assembly for decoding @decoder.postMessage data.buffer, [data.buffer] - @socket.send(@buildCommand 0x04, 1) when 0x85 # clipboard data from server data = data.subarray 1