mirror of
https://github.com/antos-rde/antosdk-apps.git
synced 2024-12-24 11:18:21 +01:00
update remoteDesktop
This commit is contained in:
parent
b31cd4302d
commit
0a6f8c0f8c
@ -5,11 +5,8 @@ A web based VNC client allowing to control remote VNC desktop from browser. The
|
||||
|
||||
Further information on **wvnc**: [https://blog.lxsang.me/post/id/23](https://blog.lxsang.me/post/id/23)
|
||||
|
||||
**Credit**
|
||||
* antd-wvnc-plugin: [https://github.com/lxsang/antd-wvnc-plugin](https://github.com/lxsang/antd-wvnc-plugin)
|
||||
* wvnc.js: [https://github.com/lxsang/wvnc.js](https://github.com/lxsang/wvnc.js)
|
||||
*
|
||||
|
||||
## Change logs
|
||||
|
||||
* v0.1.5 - add package dependencies and use the new **libwvnc**
|
||||
* v0.1.0 - adapt to the new AntOS API
|
@ -5,11 +5,8 @@ A web based VNC client allowing to control remote VNC desktop from browser. The
|
||||
|
||||
Further information on **wvnc**: [https://blog.lxsang.me/post/id/23](https://blog.lxsang.me/post/id/23)
|
||||
|
||||
**Credit**
|
||||
* antd-wvnc-plugin: [https://github.com/lxsang/antd-wvnc-plugin](https://github.com/lxsang/antd-wvnc-plugin)
|
||||
* wvnc.js: [https://github.com/lxsang/wvnc.js](https://github.com/lxsang/wvnc.js)
|
||||
*
|
||||
|
||||
## Change logs
|
||||
|
||||
* v0.1.5 - add package dependencies and use the new **libwvnc**
|
||||
* v0.1.0 - adapt to the new AntOS API
|
File diff suppressed because one or more lines are too long
@ -6,7 +6,8 @@
|
||||
"author": "",
|
||||
"email": ""
|
||||
},
|
||||
"version":"0.1.0-a",
|
||||
"version":"0.1.5-a",
|
||||
"dependencies": ["libwvnc@0.1.2-a"],
|
||||
"category":"Other",
|
||||
"icon": "icon.png",
|
||||
"mimes":["none"]
|
||||
|
Binary file not shown.
@ -6,14 +6,12 @@ class ConnectionDialog extends this.OS.GUI.BasicDialog
|
||||
main: () ->
|
||||
super.main()
|
||||
@find("bbp").data = [
|
||||
{ text: "16 bits", value: 16, selected: true },
|
||||
{ text: "16 bits", value: 16, selected: true },
|
||||
{ text: "32 bits", value: 32 }
|
||||
]
|
||||
@find("compression").data = [
|
||||
{text: "No compression", value:0},
|
||||
{text: "JPEG", value:1},
|
||||
{text: "zLib", value:2},
|
||||
{text: "JPEG & zLib", value:3, selected:true}
|
||||
{text: "JPEG", value:1, selected: true}
|
||||
]
|
||||
@find("jq").value = 40
|
||||
@find("bt-ok").onbtclick = (e) =>
|
||||
@ -38,7 +36,7 @@ ConnectionDialog.scheme = """
|
||||
<afx-label text="__(WVNC Websocket)" data-height="25" class="header" ></afx-label>
|
||||
<input data-height="25" data-id="txtWVNC" value="wss://localhost/wvnc"></input>
|
||||
<afx-label text="__(VNC Server)" data-height="25" class="header" ></afx-label>
|
||||
<input data-height="25" data-id="txtServer" value="192.168.1.10:5900"></input>
|
||||
<input data-height="25" data-id="txtServer" value="192.168.1.27:5901"></input>
|
||||
<div data-height="5"></div>
|
||||
<afx-label text="__(Bits per pixel)" data-height="25" class="header" ></afx-label>
|
||||
<afx-list-view dropdown = "true" data-id ="bbp" data-height="25" ></afx-list-view>
|
||||
@ -106,7 +104,7 @@ class RemoteDesktop extends this.OS.application.BaseApplication
|
||||
@container = @find "container"
|
||||
@client = new WVNC {
|
||||
element: @canvas,
|
||||
worker: "#{@_api.handle.get}/#{@meta().path}/decoder.js"
|
||||
libjpeg: "pkg://libjpeg/jpg.js".asFileHandle().getlink()
|
||||
}
|
||||
@client.onerror = (m) =>
|
||||
@error m
|
||||
@ -118,7 +116,7 @@ class RemoteDesktop extends this.OS.application.BaseApplication
|
||||
@openDialog "PromptDialog", {
|
||||
title: __("VNC password"),
|
||||
label: __("VNC password"),
|
||||
value: "!x$@n9ph",
|
||||
value: "password",
|
||||
type: "password"
|
||||
}
|
||||
.then (d) ->
|
||||
@ -156,7 +154,7 @@ class RemoteDesktop extends this.OS.application.BaseApplication
|
||||
]
|
||||
|
||||
actionConnection: (e) ->
|
||||
@client.disconnect() if @client
|
||||
@client.disconnect(false) if @client
|
||||
@showConnectionDialog()
|
||||
|
||||
showConnectionDialog: () ->
|
||||
@ -164,11 +162,12 @@ class RemoteDesktop extends this.OS.application.BaseApplication
|
||||
@openDialog new ConnectionDialog, { title: __("Connection")}
|
||||
.then (d) =>
|
||||
@client.ws = d.wvnc
|
||||
console.log d
|
||||
@client.connect d.server, d
|
||||
|
||||
cleanup: () ->
|
||||
@client.disconnect() if @client
|
||||
|
||||
|
||||
@client.disconnect(true) if @client
|
||||
|
||||
RemoteDesktop.dependencies = [
|
||||
"pkg://libwvnc/main.js"
|
||||
]
|
||||
this.OS.register "RemoteDesktop", RemoteDesktop
|
@ -1 +0,0 @@
|
||||
var api,onmessage,resolution,wasm_update;importScripts("wvnc_asm.js"),api={},resolution=void 0,Module.onRuntimeInitialized=function(){return api={createBuffer:Module.cwrap("create_buffer","number",["number","number"]),destroyBuffer:Module.cwrap("destroy_buffer","",["number"]),updateBuffer:Module.cwrap("update","number",["number","number","number","number","number","number"]),decodeBuffer:Module.cwrap("decode","number",["number","number","number","number"])}},wasm_update=function(e){var r,u,n,t,a,o,d,f,i,s,m;if(s=(r=new Uint8Array(e))[1]|r[2]<<8,m=r[3]|r[4]<<8,i=r[5]|r[6]<<8,t=r[7]|r[8]<<8,n=r[9],a=api.createBuffer(r.length),Module.HEAP8.set(r,a),d=i*t*4,o=api.decodeBuffer(a,r.length,resolution.depth,d),u=new Uint8Array(Module.HEAP8.buffer,o,d),e={},(f=new Uint8Array(d)).set(u,0),e.pixels=f.buffer,e.x=s,e.y=m,e.w=i,e.h=t,postMessage(e,[e.pixels]),api.destroyBuffer(a),0!==n||32!==resolution.depth)return api.destroyBuffer(o)},onmessage=function(e){return e.data.depth?resolution=e.data:wasm_update(e.data)};
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
@ -6,7 +6,8 @@
|
||||
"author": "",
|
||||
"email": ""
|
||||
},
|
||||
"version":"0.1.0-a",
|
||||
"version":"0.1.5-a",
|
||||
"dependencies": ["libwvnc@0.1.2-a"],
|
||||
"category":"Other",
|
||||
"icon": "icon.png",
|
||||
"mimes":["none"]
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "RemoteDesktop",
|
||||
"css": ["assets/main.css"],
|
||||
"javascripts": ["javascripts/wvnc.js"],
|
||||
"javascripts": [],
|
||||
"coffees": ["coffees/main.coffee"],
|
||||
"copies": ["assets/scheme.html", "package.json", "README.md", "javascripts/decoder.js", "javascripts/wvnc_asm.js", "javascripts/wvnc_asm.wasm", "assets/icon.png"]
|
||||
"copies": ["assets/scheme.html", "package.json", "README.md","assets/icon.png"]
|
||||
}
|
74
libwvnc/README.md
Normal file
74
libwvnc/README.md
Normal file
@ -0,0 +1,74 @@
|
||||
# libwvnc
|
||||
|
||||
Overview about WVNC: [https://blog.lxsang.me/r/id/23](https://blog.lxsang.me/r/id/23)
|
||||
|
||||
**libwvnc** is the client side protocol API for my [Antd's **wvnc**](https://github.com/lxsang/antd-wvnc-plugin) server side plugin. It allows to acess VNC server from the web using websocket (via the **wvnc** server plugin).
|
||||
|
||||
Since the **wvnc** plugin offers data compression using JPEG, **wvnc.js** depends on the **libjpeg** package and **web worker** to speed up the data decoding process, thus speed up the screen rendering on HTML canvas.
|
||||
|
||||
|
||||
## Example
|
||||
It is straight forward to use the api:
|
||||
|
||||
Html code:
|
||||
|
||||
```html
|
||||
...
|
||||
<canvas id = "screen"></canvas>
|
||||
```
|
||||
|
||||
Javascript:
|
||||
|
||||
```javascript
|
||||
var args, client;
|
||||
args = {
|
||||
// the canvas element
|
||||
element: 'screen',
|
||||
// The websocket uri to the wvnc server side plugin
|
||||
ws: 'wss://localhost/wvnc',
|
||||
// the decoder worker
|
||||
libjpeg: 'path/to/jpg.js'
|
||||
};
|
||||
client = new WVNC(args);
|
||||
|
||||
// This function responds to a VNC server password request
|
||||
// should return a promise
|
||||
client.onpassword = function() {
|
||||
return new Promise(function(r, e) {
|
||||
return r('password');
|
||||
});
|
||||
};
|
||||
|
||||
// this function responds to the remote OS username and password request
|
||||
// should return a promise
|
||||
client.oncredential = function() {
|
||||
return new Promise(function(r, e) {
|
||||
return r('username', 'password');
|
||||
});
|
||||
};
|
||||
// event fired when a text is copied on
|
||||
// the remote computer
|
||||
client.oncopy = function(text) {
|
||||
console.log(text);
|
||||
};
|
||||
// init the WVNC client
|
||||
client.init()
|
||||
.then(function() {
|
||||
client.connect(
|
||||
// VNC server
|
||||
"192.168.1.20:5901",
|
||||
{
|
||||
// bits per pixel
|
||||
bbp: 32,
|
||||
// data compression flag
|
||||
// 1 is for both JPEG
|
||||
// 0 is for raw data
|
||||
flag: 1,
|
||||
// JPEG quality %
|
||||
quality: 50
|
||||
});
|
||||
})
|
||||
.catch(function(m, s) {
|
||||
return console.error(m, s);
|
||||
});
|
||||
```
|
74
libwvnc/build/debug/README.md
Normal file
74
libwvnc/build/debug/README.md
Normal file
@ -0,0 +1,74 @@
|
||||
# libwvnc
|
||||
|
||||
Overview about WVNC: [https://blog.lxsang.me/r/id/23](https://blog.lxsang.me/r/id/23)
|
||||
|
||||
**libwvnc** is the client side protocol API for my [Antd's **wvnc**](https://github.com/lxsang/antd-wvnc-plugin) server side plugin. It allows to acess VNC server from the web using websocket (via the **wvnc** server plugin).
|
||||
|
||||
Since the **wvnc** plugin offers data compression using JPEG, **wvnc.js** depends on the **libjpeg** package and **web worker** to speed up the data decoding process, thus speed up the screen rendering on HTML canvas.
|
||||
|
||||
|
||||
## Example
|
||||
It is straight forward to use the api:
|
||||
|
||||
Html code:
|
||||
|
||||
```html
|
||||
...
|
||||
<canvas id = "screen"></canvas>
|
||||
```
|
||||
|
||||
Javascript:
|
||||
|
||||
```javascript
|
||||
var args, client;
|
||||
args = {
|
||||
// the canvas element
|
||||
element: 'screen',
|
||||
// The websocket uri to the wvnc server side plugin
|
||||
ws: 'wss://localhost/wvnc',
|
||||
// the decoder worker
|
||||
libjpeg: 'path/to/jpg.js'
|
||||
};
|
||||
client = new WVNC(args);
|
||||
|
||||
// This function responds to a VNC server password request
|
||||
// should return a promise
|
||||
client.onpassword = function() {
|
||||
return new Promise(function(r, e) {
|
||||
return r('password');
|
||||
});
|
||||
};
|
||||
|
||||
// this function responds to the remote OS username and password request
|
||||
// should return a promise
|
||||
client.oncredential = function() {
|
||||
return new Promise(function(r, e) {
|
||||
return r('username', 'password');
|
||||
});
|
||||
};
|
||||
// event fired when a text is copied on
|
||||
// the remote computer
|
||||
client.oncopy = function(text) {
|
||||
console.log(text);
|
||||
};
|
||||
// init the WVNC client
|
||||
client.init()
|
||||
.then(function() {
|
||||
client.connect(
|
||||
// VNC server
|
||||
"192.168.1.20:5901",
|
||||
{
|
||||
// bits per pixel
|
||||
bbp: 32,
|
||||
// data compression flag
|
||||
// 1 is for both JPEG
|
||||
// 0 is for raw data
|
||||
flag: 1,
|
||||
// JPEG quality %
|
||||
quality: 50
|
||||
});
|
||||
})
|
||||
.catch(function(m, s) {
|
||||
return console.error(m, s);
|
||||
});
|
||||
```
|
112
libwvnc/build/debug/decoder.js
Normal file
112
libwvnc/build/debug/decoder.js
Normal file
@ -0,0 +1,112 @@
|
||||
let resolution;
|
||||
|
||||
decode_jpeg = (raw, msg) =>
|
||||
{
|
||||
if(!JpegImage)
|
||||
{
|
||||
console.error("The JPEG library is not available");
|
||||
return 0;
|
||||
}
|
||||
let jpeg = new JpegImage()
|
||||
jpeg.parse(raw)
|
||||
if(jpeg.width != msg.w || jpeg.height != msg.h)
|
||||
{
|
||||
console.error("Incorrect data size: expect " + msg.w*msg.h*4 + " got " + jpeg.width*jpeg.height*4);
|
||||
return 0;
|
||||
}
|
||||
msg.pixels = new Uint8Array(msg.w*msg.h*4);
|
||||
let data = jpeg.getData(msg.w, msg.h);
|
||||
for(let j = 0; j < msg.h; j++)
|
||||
{
|
||||
for(let i = 0; i < msg.w; i++)
|
||||
{
|
||||
let index = j*msg.w*4 + i*4;
|
||||
msg.pixels[index] = data[j*msg.w*3 + i*3];
|
||||
msg.pixels[index+1] = data[j*msg.w*3 + i*3 + 1];
|
||||
msg.pixels[index+2] = data[j*msg.w*3 + i*3 + 2];
|
||||
msg.pixels[index+3] = 255;
|
||||
}
|
||||
}
|
||||
return msg.pixels.length;
|
||||
}
|
||||
|
||||
decode_raw = (raw, msg) =>
|
||||
{
|
||||
let size =raw.length;
|
||||
if(resolution.depth == 32)
|
||||
{
|
||||
msg.pixels = new Uint8Array(raw);
|
||||
return size;
|
||||
}
|
||||
if(resolution.depth != 16)
|
||||
{
|
||||
console.error("Unsupported depth" + resolution.depth);
|
||||
return 0;
|
||||
}
|
||||
let bytes = resolution.depth/8;
|
||||
let npixels = size / bytes;
|
||||
let outsize = npixels*4;
|
||||
if(outsize != msg.w*msg.h*4)
|
||||
{
|
||||
console.error("Incorrect data size: expect " + msg.w*msg.h*4 + " got " + outsize);
|
||||
return 0;
|
||||
}
|
||||
msg.pixels = new Uint8Array(outsize);
|
||||
let value = 0;
|
||||
let px = {};
|
||||
for(let i = 0; i < npixels; i++)
|
||||
{
|
||||
value = 0;
|
||||
for(let j=0; j < bytes; j++ )
|
||||
value = (raw[i * bytes + j] << (j*8)) | value ;
|
||||
// lookup for pixel
|
||||
msg.pixels[i*4] = (value & 0x1F) * (255 / 31);
|
||||
msg.pixels[i*4+1] = ((value >> 5) & 0x3F) * (255 / 63);
|
||||
msg.pixels[i*4+2] = ((value >> 11) & 0x1F) * (255 / 31);
|
||||
msg.pixels[i*4+3] = 255;
|
||||
}
|
||||
return outsize;
|
||||
}
|
||||
|
||||
decode = (arr) =>
|
||||
{
|
||||
let datain = new Uint8Array(arr);
|
||||
let msg = {
|
||||
x: datain[1] | (datain[2] << 8),
|
||||
y: datain[3] | (datain[4] << 8),
|
||||
w: datain[5] | (datain[6] << 8),
|
||||
h: datain[7] | (datain[8] << 8),
|
||||
flag: datain[9],
|
||||
pixels: undefined
|
||||
}
|
||||
switch (msg.flag) {
|
||||
case 0x0:
|
||||
decode_raw(datain.subarray(10), msg);
|
||||
break;
|
||||
case 0x1:
|
||||
decode_jpeg(datain.subarray(10), msg);
|
||||
break;
|
||||
default:
|
||||
console.error("Unknow flag: " + msg.flag);
|
||||
}
|
||||
if(msg.pixels)
|
||||
{
|
||||
msg.pixels = msg.pixels.buffer;
|
||||
postMessage(msg, [msg.pixels]);
|
||||
}
|
||||
}
|
||||
|
||||
onmessage = (e) => {
|
||||
if(e.data.depth)
|
||||
{
|
||||
resolution = e.data;
|
||||
}
|
||||
else if(e.data.libjpeg)
|
||||
{
|
||||
importScripts(e.data.libjpeg);
|
||||
}
|
||||
else
|
||||
{
|
||||
decode(e.data);
|
||||
}
|
||||
}
|
1
libwvnc/build/debug/main.js
Normal file
1
libwvnc/build/debug/main.js
Normal file
File diff suppressed because one or more lines are too long
15
libwvnc/build/debug/package.json
Normal file
15
libwvnc/build/debug/package.json
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"pkgname": "libwvnc",
|
||||
"name":"libwvnc",
|
||||
"description":"libwvnc: client side VNC protocol via websocket",
|
||||
"info":{
|
||||
"author": "",
|
||||
"email": ""
|
||||
},
|
||||
"version":"0.1.2-a",
|
||||
"category":"Library",
|
||||
"iconclass":"fa fa-cog",
|
||||
"mimes":["none"],
|
||||
"dependencies":["libjpeg@0.1.1-a"],
|
||||
"locale": {}
|
||||
}
|
BIN
libwvnc/build/release/libwvnc.zip
Normal file
BIN
libwvnc/build/release/libwvnc.zip
Normal file
Binary file not shown.
112
libwvnc/decoder.js
Normal file
112
libwvnc/decoder.js
Normal file
@ -0,0 +1,112 @@
|
||||
let resolution;
|
||||
|
||||
decode_jpeg = (raw, msg) =>
|
||||
{
|
||||
if(!JpegImage)
|
||||
{
|
||||
console.error("The JPEG library is not available");
|
||||
return 0;
|
||||
}
|
||||
let jpeg = new JpegImage()
|
||||
jpeg.parse(raw)
|
||||
if(jpeg.width != msg.w || jpeg.height != msg.h)
|
||||
{
|
||||
console.error("Incorrect data size: expect " + msg.w*msg.h*4 + " got " + jpeg.width*jpeg.height*4);
|
||||
return 0;
|
||||
}
|
||||
msg.pixels = new Uint8Array(msg.w*msg.h*4);
|
||||
let data = jpeg.getData(msg.w, msg.h);
|
||||
for(let j = 0; j < msg.h; j++)
|
||||
{
|
||||
for(let i = 0; i < msg.w; i++)
|
||||
{
|
||||
let index = j*msg.w*4 + i*4;
|
||||
msg.pixels[index] = data[j*msg.w*3 + i*3];
|
||||
msg.pixels[index+1] = data[j*msg.w*3 + i*3 + 1];
|
||||
msg.pixels[index+2] = data[j*msg.w*3 + i*3 + 2];
|
||||
msg.pixels[index+3] = 255;
|
||||
}
|
||||
}
|
||||
return msg.pixels.length;
|
||||
}
|
||||
|
||||
decode_raw = (raw, msg) =>
|
||||
{
|
||||
let size =raw.length;
|
||||
if(resolution.depth == 32)
|
||||
{
|
||||
msg.pixels = new Uint8Array(raw);
|
||||
return size;
|
||||
}
|
||||
if(resolution.depth != 16)
|
||||
{
|
||||
console.error("Unsupported depth" + resolution.depth);
|
||||
return 0;
|
||||
}
|
||||
let bytes = resolution.depth/8;
|
||||
let npixels = size / bytes;
|
||||
let outsize = npixels*4;
|
||||
if(outsize != msg.w*msg.h*4)
|
||||
{
|
||||
console.error("Incorrect data size: expect " + msg.w*msg.h*4 + " got " + outsize);
|
||||
return 0;
|
||||
}
|
||||
msg.pixels = new Uint8Array(outsize);
|
||||
let value = 0;
|
||||
let px = {};
|
||||
for(let i = 0; i < npixels; i++)
|
||||
{
|
||||
value = 0;
|
||||
for(let j=0; j < bytes; j++ )
|
||||
value = (raw[i * bytes + j] << (j*8)) | value ;
|
||||
// lookup for pixel
|
||||
msg.pixels[i*4] = (value & 0x1F) * (255 / 31);
|
||||
msg.pixels[i*4+1] = ((value >> 5) & 0x3F) * (255 / 63);
|
||||
msg.pixels[i*4+2] = ((value >> 11) & 0x1F) * (255 / 31);
|
||||
msg.pixels[i*4+3] = 255;
|
||||
}
|
||||
return outsize;
|
||||
}
|
||||
|
||||
decode = (arr) =>
|
||||
{
|
||||
let datain = new Uint8Array(arr);
|
||||
let msg = {
|
||||
x: datain[1] | (datain[2] << 8),
|
||||
y: datain[3] | (datain[4] << 8),
|
||||
w: datain[5] | (datain[6] << 8),
|
||||
h: datain[7] | (datain[8] << 8),
|
||||
flag: datain[9],
|
||||
pixels: undefined
|
||||
}
|
||||
switch (msg.flag) {
|
||||
case 0x0:
|
||||
decode_raw(datain.subarray(10), msg);
|
||||
break;
|
||||
case 0x1:
|
||||
decode_jpeg(datain.subarray(10), msg);
|
||||
break;
|
||||
default:
|
||||
console.error("Unknow flag: " + msg.flag);
|
||||
}
|
||||
if(msg.pixels)
|
||||
{
|
||||
msg.pixels = msg.pixels.buffer;
|
||||
postMessage(msg, [msg.pixels]);
|
||||
}
|
||||
}
|
||||
|
||||
onmessage = (e) => {
|
||||
if(e.data.depth)
|
||||
{
|
||||
resolution = e.data;
|
||||
}
|
||||
else if(e.data.libjpeg)
|
||||
{
|
||||
importScripts(e.data.libjpeg);
|
||||
}
|
||||
else
|
||||
{
|
||||
decode(e.data);
|
||||
}
|
||||
}
|
315
libwvnc/main.coffee
Normal file
315
libwvnc/main.coffee
Normal file
@ -0,0 +1,315 @@
|
||||
class WVNC
|
||||
constructor: (args) ->
|
||||
@socket = undefined
|
||||
@ws = undefined
|
||||
@canvas = undefined
|
||||
worker = "pkg://libwvnc/decoder.js".asFileHandle().getlink()
|
||||
@scale = 1.0
|
||||
@ws = args.ws if args.ws
|
||||
@canvas = args.element
|
||||
@canvas = document.getElementById @canvas if typeof @canvas is 'string'
|
||||
libjpeg = args.libjpeg if args.libjpeg
|
||||
@decoder = new Worker worker
|
||||
@enableEvent = true
|
||||
me = @
|
||||
@mouseMask = 0
|
||||
@decoder.postMessage {libjpeg: libjpeg}
|
||||
@decoder.onmessage = (e) ->
|
||||
me.process e.data
|
||||
init: () ->
|
||||
me = @
|
||||
return new Promise (r, e) ->
|
||||
return e('Canvas is not set') if not me.canvas
|
||||
# fix keyboard event problem
|
||||
$(me.canvas).attr 'tabindex', '1'
|
||||
me.initInputEvent()
|
||||
r()
|
||||
|
||||
initInputEvent: () ->
|
||||
me = @
|
||||
return unless @canvas
|
||||
getMousePos = (e) ->
|
||||
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 = (e) ->
|
||||
return unless me.enableEvent
|
||||
p = getMousePos e
|
||||
me.sendPointEvent p.x, p.y, me.mouseMask
|
||||
|
||||
return unless me.canvas
|
||||
me.canvas.oncontextmenu = (e) ->
|
||||
e.preventDefault()
|
||||
return false
|
||||
|
||||
me.canvas.onmousemove = (e) -> sendMouseLocation e
|
||||
|
||||
me.canvas.onmousedown = (e) ->
|
||||
state = 1 << e.button
|
||||
me.mouseMask = me.mouseMask | state
|
||||
sendMouseLocation e
|
||||
#e.preventDefault()
|
||||
|
||||
me.canvas.onmouseup = (e) ->
|
||||
state = 1 << e.button
|
||||
me.mouseMask = me.mouseMask & (~state)
|
||||
sendMouseLocation e
|
||||
#e.preventDefault()
|
||||
|
||||
me.canvas.onkeydown = me.canvas.onkeyup = (e) ->
|
||||
# get the key code
|
||||
keycode = e.keyCode
|
||||
#console.log e
|
||||
switch keycode
|
||||
when 8 then code = 0xFF08 #back space
|
||||
when 9 then code = 0xff89 #0xFF09 # tab ?
|
||||
when 13 then code = 0xFF0D # return
|
||||
when 27 then code = 0xFF1B # esc
|
||||
when 46 then code = 0xFFFF # delete to verify
|
||||
when 38 then code = 0xFF52 # up
|
||||
when 40 then code = 0xFF54 # down
|
||||
when 37 then code = 0xFF51 # left
|
||||
when 39 then code = 0xFF53 # right
|
||||
when 91 then code = 0xFFE7 # meta left
|
||||
when 93 then code = 0xFFE8 # meta right
|
||||
when 16 then code = 0xFFE1 # shift left
|
||||
when 17 then code = 0xFFE3 # ctrl left
|
||||
when 18 then code = 0xFFE9 # alt left
|
||||
when 20 then code = 0xFFE5 # capslock
|
||||
when 113 then code = 0xFFBF # f2
|
||||
when 112 then code = 0xFFBE # f1
|
||||
when 114 then code = 0xFFC0 # f3
|
||||
when 115 then code = 0xFFC1 # f4
|
||||
when 116 then code = 0xFFC2 # f5
|
||||
when 117 then code = 0xFFC3 # f6
|
||||
when 118 then code = 0xFFC4 # f7
|
||||
when 119 then code = 0xFFC5 # f8
|
||||
when 120 then code = 0xFFC6 # f9
|
||||
when 121 then code = 0xFFC7 # f10
|
||||
when 122 then code = 0xFFC8 # f11
|
||||
when 123 then code = 0xFFC9 # f12
|
||||
else
|
||||
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()
|
||||
return unless code
|
||||
if e.type is "keydown"
|
||||
me.sendKeyEvent code, 1
|
||||
else if e.type is "keyup"
|
||||
me.sendKeyEvent code, 0
|
||||
|
||||
# mouse wheel event
|
||||
@canvas.addEventListener 'wheel', (e) ->
|
||||
return unless me.enableEvent
|
||||
#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
|
||||
me.sendPointEvent p.x, p.y, 0
|
||||
# paste event
|
||||
@canvas.onpaste = (e) ->
|
||||
return unless me.enableEvent
|
||||
pastedText = undefined
|
||||
if window.clipboardData and window.clipboardData.getData #IE
|
||||
pastedText = window.clipboardData.getData 'Text'
|
||||
else if e.clipboardData and e.clipboardData.getData
|
||||
pastedText = e.clipboardData.getData 'text/plain'
|
||||
return false unless pastedText
|
||||
e.preventDefault()
|
||||
me.sendTextAsClipboard pastedText
|
||||
# global event
|
||||
fn = (e) =>
|
||||
@disconnect(true)
|
||||
|
||||
window.addEventListener "unload", fn
|
||||
window.addEventListener "beforeunload", fn
|
||||
|
||||
initCanvas: (w, h , d) ->
|
||||
me = @
|
||||
@depth = d
|
||||
@canvas.width = w
|
||||
@canvas.height = h
|
||||
@resolution =
|
||||
w: w,
|
||||
h: h,
|
||||
depth: @depth
|
||||
@decoder.postMessage @resolution
|
||||
me.canvas.style.cursor = "none"
|
||||
@setScale @scale
|
||||
|
||||
process: (msg) ->
|
||||
if not @socket
|
||||
return
|
||||
data = new Uint8Array msg.pixels
|
||||
#w = @buffer.width * @scale
|
||||
#h = @buffer.height * @scale
|
||||
ctx = @canvas.getContext "2d", { alpha: false }
|
||||
imgData = ctx.createImageData msg.w, msg.h
|
||||
imgData.data.set data
|
||||
ctx.putImageData imgData, msg.x, msg.y
|
||||
|
||||
|
||||
setScale: (n) ->
|
||||
@scale = n
|
||||
return unless @canvas
|
||||
@canvas.style.transformOrigin = '0 0'
|
||||
@canvas.style.transform = 'scale(' + n + ')'
|
||||
|
||||
|
||||
connect: (url, args) ->
|
||||
me = @
|
||||
@socket.close() if @socket
|
||||
return unless @ws
|
||||
@socket = new WebSocket @ws
|
||||
@socket.binaryType = "arraybuffer"
|
||||
@socket.onopen = () ->
|
||||
console.log "socket opened"
|
||||
me.initConnection(url, args)
|
||||
|
||||
@socket.onmessage = (e) ->
|
||||
me.consume e
|
||||
@socket.onclose = () ->
|
||||
me.socket = null
|
||||
me.canvas.style.cursor = "auto"
|
||||
me.canvas.getContext('2d').clearRect 0,0, me.resolution.w, me.resolution.h if me.canvas and me.resolution
|
||||
console.log "socket closed"
|
||||
|
||||
disconnect: (close_worker) ->
|
||||
@socket.close() if @socket
|
||||
@decoder.terminate() if @decoder and close_worker
|
||||
|
||||
initConnection: (vncserver, params) ->
|
||||
#vncserver = "192.168.1.20:5901"
|
||||
data = new Uint8Array vncserver.length + 3
|
||||
data[0] = 32 # bbp
|
||||
###
|
||||
flag:
|
||||
0: raw data no compress
|
||||
1: jpeg no compress
|
||||
###
|
||||
data[1] = 1
|
||||
data[2] = 50 # jpeg quality
|
||||
if params
|
||||
data[0] = params.bbp if params.bbp
|
||||
data[1] = params.flag if params.flag
|
||||
data[2] = params.quality if params.quality
|
||||
## rate in milisecond
|
||||
|
||||
data.set (new TextEncoder()).encode(vncserver), 3
|
||||
@socket.send(@buildCommand 0x01, data)
|
||||
|
||||
sendPointEvent: (x, y, mask) ->
|
||||
return unless @socket
|
||||
data = new Uint8Array 5
|
||||
data[0] = x & 0xFF
|
||||
data[1] = x >> 8
|
||||
data[2] = y & 0xFF
|
||||
data[3] = y >> 8
|
||||
data[4] = mask
|
||||
@socket.send( @buildCommand 0x05, data )
|
||||
|
||||
sendKeyEvent: (code, v) ->
|
||||
#console.log code, v
|
||||
return unless @socket
|
||||
return unless @enableEvent
|
||||
data = new Uint8Array 3
|
||||
data[0] = code & 0xFF
|
||||
data[1] = code >> 8
|
||||
data[2] = v
|
||||
@socket.send( @buildCommand 0x06, data )
|
||||
|
||||
buildCommand: (hex, o) ->
|
||||
data = undefined
|
||||
switch typeof o
|
||||
when 'string'
|
||||
data = (new TextEncoder()).encode(o)
|
||||
when 'number'
|
||||
data = new Uint8Array [o]
|
||||
else
|
||||
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) ->
|
||||
console.log "Get clipboard text: " + text
|
||||
|
||||
onpassword: () ->
|
||||
return new Promise (resolve, reject) ->
|
||||
reject("onpassword is not implemented")
|
||||
|
||||
sendTextAsClipboard: (text) ->
|
||||
return unless @socket
|
||||
console.log "send ", text
|
||||
@socket.send (@buildCommand 0x07, text)
|
||||
|
||||
oncredential: () ->
|
||||
return new Promise (resolve, reject) ->
|
||||
reject("oncredential is not implemented")
|
||||
|
||||
onerror: (m) ->
|
||||
console.log "Error", m
|
||||
|
||||
onresize: () ->
|
||||
console.log "resize"
|
||||
|
||||
consume: (e) ->
|
||||
data = new Uint8Array e.data
|
||||
cmd = data[0]
|
||||
me = @
|
||||
switch cmd
|
||||
when 0xFE #error
|
||||
data = data.subarray 1, data.length - 1
|
||||
dec = new TextDecoder("utf-8")
|
||||
@onerror dec.decode(data)
|
||||
when 0x81
|
||||
console.log "Request for password"
|
||||
@enableEvent = false
|
||||
@onpassword().then (pass) ->
|
||||
me.socket.send (me.buildCommand 0x02, pass)
|
||||
me.enableEvent = true
|
||||
when 0x82
|
||||
console.log "Request for login"
|
||||
@enableEvent = false
|
||||
@oncredential().then (user, pass) ->
|
||||
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)
|
||||
me.enableEvent = true
|
||||
when 0x83
|
||||
w = data[1] | (data[2]<<8)
|
||||
h = data[3] | (data[4]<<8)
|
||||
depth = data[5]
|
||||
@initCanvas w, h, depth
|
||||
# status command for ack
|
||||
@socket.send(@buildCommand 0x04, 1)
|
||||
@onresize()
|
||||
when 0x84
|
||||
# send data to web assembly for decoding
|
||||
@decoder.postMessage data.buffer, [data.buffer]
|
||||
when 0x85
|
||||
# clipboard data from server
|
||||
data = data.subarray 1
|
||||
dec = new TextDecoder "utf-8"
|
||||
@oncopy dec.decode data
|
||||
@socket.send(@buildCommand 0x04, 1)
|
||||
else
|
||||
console.log cmd
|
||||
|
||||
window.WVNC = WVNC
|
15
libwvnc/package.json
Normal file
15
libwvnc/package.json
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"pkgname": "libwvnc",
|
||||
"name":"libwvnc",
|
||||
"description":"libwvnc: client side VNC protocol via websocket",
|
||||
"info":{
|
||||
"author": "",
|
||||
"email": ""
|
||||
},
|
||||
"version":"0.1.2-a",
|
||||
"category":"Library",
|
||||
"iconclass":"fa fa-cog",
|
||||
"mimes":["none"],
|
||||
"dependencies":["libjpeg@0.1.1-a"],
|
||||
"locale": {}
|
||||
}
|
7
libwvnc/project.json
Normal file
7
libwvnc/project.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "libwvnc",
|
||||
"css": [],
|
||||
"javascripts": [],
|
||||
"coffees": ["main.coffee"],
|
||||
"copies": [ "decoder.js","package.json", "README.md"]
|
||||
}
|
@ -149,6 +149,16 @@
|
||||
"dependencies": [],
|
||||
"download": "https://raw.githubusercontent.com/lxsang/antosdk-apps/master/libjpeg/build/release/libjpeg.zip"
|
||||
},
|
||||
{
|
||||
"pkgname": "libwvnc",
|
||||
"name": "libwvnc",
|
||||
"description": "https://raw.githubusercontent.com/lxsang/antosdk-apps/master/libwvnc/README.md",
|
||||
"category": "Library",
|
||||
"author": "",
|
||||
"version": "0.1.2-a",
|
||||
"dependencies": ["libjpeg@0.1.1-a"],
|
||||
"download": "https://raw.githubusercontent.com/lxsang/antosdk-apps/master/libwvnc/build/release/libwvnc.zip"
|
||||
},
|
||||
{
|
||||
"pkgname": "LuaPlayground",
|
||||
"name": "LuaPlayground",
|
||||
@ -205,8 +215,8 @@
|
||||
"description": "https://raw.githubusercontent.com/lxsang/antosdk-apps/master/RemoteDesktop/README.md",
|
||||
"category": "Other",
|
||||
"author": "",
|
||||
"version": "0.1.0-a",
|
||||
"dependencies": [],
|
||||
"version": "0.1.5-a",
|
||||
"dependencies": ["libwvnc@0.1.2-a"],"category":"Other","icon":"icon.png","mimes":["none"],
|
||||
"download": "https://raw.githubusercontent.com/lxsang/antosdk-apps/master/RemoteDesktop/build/release/RemoteDesktop.zip"
|
||||
},
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user