diff --git a/RemoteDesktop/README.md b/RemoteDesktop/README.md index c085aef..f616122 100644 --- a/RemoteDesktop/README.md +++ b/RemoteDesktop/README.md @@ -7,6 +7,8 @@ Further information on **wvnc**: [https://blog.lxsang.me/post/id/23](https://blo ## Change logs +* v0.1.15 - Only send ACK command when finish rendering the received frame, this allows to vastly improve performance and bandwidth +* v0.1.14 - Add toolbar for canvas size control * v0.1.13 - support AntOS v2.0.x * v0.1.12 - improve UI handling * v0.1.11 - Support 16 bits per pixel diff --git a/RemoteDesktop/assets/main.css b/RemoteDesktop/assets/main.css index ecb3e43..4a806e6 100644 --- a/RemoteDesktop/assets/main.css +++ b/RemoteDesktop/assets/main.css @@ -1,6 +1,7 @@ afx-app-window[data-id="RemoteDesktop"] div[data-id="container"] { background-color: #272822; + overflow: hidden; } afx-app-window[data-id="RemoteDesktop"] canvas[data-id="screen"] { diff --git a/RemoteDesktop/assets/scheme.html b/RemoteDesktop/assets/scheme.html index 08bbe4c..d038277 100644 --- a/RemoteDesktop/assets/scheme.html +++ b/RemoteDesktop/assets/scheme.html @@ -1,7 +1,17 @@ - +
-
+ + +
+ +
+ + + + +
+
\ No newline at end of file diff --git a/RemoteDesktop/build/debug/README.md b/RemoteDesktop/build/debug/README.md index c085aef..f616122 100644 --- a/RemoteDesktop/build/debug/README.md +++ b/RemoteDesktop/build/debug/README.md @@ -7,6 +7,8 @@ Further information on **wvnc**: [https://blog.lxsang.me/post/id/23](https://blo ## Change logs +* v0.1.15 - Only send ACK command when finish rendering the received frame, this allows to vastly improve performance and bandwidth +* v0.1.14 - Add toolbar for canvas size control * v0.1.13 - support AntOS v2.0.x * v0.1.12 - improve UI handling * v0.1.11 - Support 16 bits per pixel diff --git a/RemoteDesktop/build/debug/main.css b/RemoteDesktop/build/debug/main.css index ecb3e43..4a806e6 100644 --- a/RemoteDesktop/build/debug/main.css +++ b/RemoteDesktop/build/debug/main.css @@ -1,6 +1,7 @@ afx-app-window[data-id="RemoteDesktop"] div[data-id="container"] { background-color: #272822; + overflow: hidden; } afx-app-window[data-id="RemoteDesktop"] canvas[data-id="screen"] { diff --git a/RemoteDesktop/build/debug/main.js b/RemoteDesktop/build/debug/main.js index 2d8801e..41afa34 100644 --- a/RemoteDesktop/build/debug/main.js +++ b/RemoteDesktop/build/debug/main.js @@ -1,770 +1 @@ -(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); +(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.zoom=this.find("zoom"),this.btreset=this.find("btreset"),this.zoom.max=200,this.zoom.value=100,this.zoom.onvaluechange=e=>this.setScale(),this.find("scroll_down").onbtclick=e=>this.container.scrollTop+=20,this.find("scroll_up").onbtclick=e=>this.container.scrollTop-=20,this.find("scroll_left").onbtclick=e=>this.container.scrollLeft-=20,this.find("scroll_right").onbtclick=e=>this.container.scrollLeft+=20,this.btreset.onbtclick=e=>{var t,n,s,i;return i=$(this.container).width(),t=$(this.container).height(),n=i/this.client.resolution.w,s=t/this.client.resolution.h,this.zoom.value=n>s?100*s:100*n,this.setScale()},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("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(){if(console.log("scale changed"),this.client&&this.client.resolution)return this.client.setScale(this.zoom.value/100),this.container.scrollLeft=0,this.container.scrollTop=0}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),this.socket.send(this.buildCommand(4,1));this.socket.send(this.buildCommand(4,1))}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]);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 diff --git a/RemoteDesktop/build/debug/package.json b/RemoteDesktop/build/debug/package.json index d39faba..d1c46be 100644 --- a/RemoteDesktop/build/debug/package.json +++ b/RemoteDesktop/build/debug/package.json @@ -7,7 +7,7 @@ "author": "Dany LE", "email": "contact@iohub.dev" }, - "version":"0.1.13-b", + "version":"0.1.15-b", "dependencies": [], "category":"Internet", "icon": "icon.png", diff --git a/RemoteDesktop/build/debug/scheme.html b/RemoteDesktop/build/debug/scheme.html index 08bbe4c..d038277 100644 --- a/RemoteDesktop/build/debug/scheme.html +++ b/RemoteDesktop/build/debug/scheme.html @@ -1,7 +1,17 @@ - +
-
+ + +
+ +
+ + + + +
+
\ No newline at end of file diff --git a/RemoteDesktop/build/release/RemoteDesktop.zip b/RemoteDesktop/build/release/RemoteDesktop.zip index 2b913a1..770dbd8 100644 Binary files a/RemoteDesktop/build/release/RemoteDesktop.zip and b/RemoteDesktop/build/release/RemoteDesktop.zip differ diff --git a/RemoteDesktop/coffees/main.coffee b/RemoteDesktop/coffees/main.coffee index 36ba28e..2c67497 100644 --- a/RemoteDesktop/coffees/main.coffee +++ b/RemoteDesktop/coffees/main.coffee @@ -57,7 +57,6 @@ class CredentialDialog extends this.OS.GUI.BasicDialog password: (@find "txtPass").value @handle data @quit() - @find("bt-cancel").onbtclick = () => @quit() @@ -83,6 +82,29 @@ class RemoteDesktop extends this.OS.application.BaseApplication main: () -> @canvas = @find "screen" @container = @find "container" + @zoom = @find "zoom" + @btreset = @find "btreset" + @zoom.max = 200 + @zoom.value = 100 + @zoom.onvaluechange = (e) => @setScale() + @find("scroll_down").onbtclick = (e) => + @container.scrollTop += 20 + @find("scroll_up").onbtclick = (e) => + @container.scrollTop -= 20 + @find("scroll_left").onbtclick = (e) => + @container.scrollLeft -= 20 + @find("scroll_right").onbtclick = (e) => + @container.scrollLeft += 20 + @btreset.onbtclick = (e) => + w = $(@container).width() + h = $(@container).height() + sx = w / @client.resolution.w + sy = h / @client.resolution.h + if sx > sy + @zoom.value = sy*100 + else + @zoom.value = sx*100 + @setScale() @client = new WVNC { element: @canvas } @@ -113,7 +135,7 @@ class RemoteDesktop extends this.OS.application.BaseApplication @openDialog new CredentialDialog, { title: __("User credential") } .then (d) -> r(d.username, d.password) - @on "resize", (e)=> @setScale() + # @on "resize", (e)=> @setScale() @on "focus", (e) => $(@canvas).focus() @client.init().then () => @showConnectionDialog() @@ -136,12 +158,11 @@ class RemoteDesktop extends this.OS.application.BaseApplication .catch (err) => @error err.toString(), err setScale: () -> + console.log "scale changed" return unless @client and @client.resolution - w = $(@container).width() - h = $(@container).height() - sx = w / @client.resolution.w - sy = h / @client.resolution.h - if sx > sy then @client.setScale sy else @client.setScale sx + @client.setScale @zoom.value / 100.0 + @container.scrollLeft = 0 + @container.scrollTop = 0 menu: () -> diff --git a/RemoteDesktop/package.json b/RemoteDesktop/package.json index d39faba..d1c46be 100644 --- a/RemoteDesktop/package.json +++ b/RemoteDesktop/package.json @@ -7,7 +7,7 @@ "author": "Dany LE", "email": "contact@iohub.dev" }, - "version":"0.1.13-b", + "version":"0.1.15-b", "dependencies": [], "category":"Internet", "icon": "icon.png", diff --git a/packages.json b/packages.json index da4cab1..d74ea52 100644 --- a/packages.json +++ b/packages.json @@ -365,7 +365,7 @@ "description": "https://raw.githubusercontent.com/lxsang/antosdk-apps/2.0.x/RemoteDesktop/README.md", "category": "Internet", "author": "Dany LE", - "version": "0.1.13-b", + "version": "0.1.15-b", "dependencies": [],"category":"Internet","icon":"icon.png","mimes":["none"], "download": "https://raw.githubusercontent.com/lxsang/antosdk-apps/2.0.x/RemoteDesktop/build/release/RemoteDesktop.zip" },