├── .gitignore ├── README.md ├── mainmenu.json ├── package.json └── vnc.js /.gitignore: -------------------------------------------------------------------------------- 1 | lib-cov 2 | *.seed 3 | *.log 4 | *.csv 5 | *.dat 6 | *.out 7 | *.pid 8 | *.gz 9 | 10 | pids 11 | logs 12 | results 13 | 14 | node_modules 15 | npm-debug.log -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | node-vnc 2 | ========= 3 | 4 | VNC client. X11-based UI for rfb2 vnc protocol client 5 | -------------------------------------------------------------------------------- /mainmenu.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 0, 3 | "children-display": "submenu", 4 | "submenu": [ 5 | { 6 | "id": 1, 7 | "children-display": "submenu", 8 | "label": "File", 9 | "submenu": [ 10 | { 11 | "id": 2, 12 | "label": "Quit", 13 | "shortcut": [["Control", "q"]] 14 | }, 15 | { 16 | "id": 3, 17 | "label": "Open Recording" 18 | }, 19 | { 20 | "id": 94, 21 | "label": "Connect...", 22 | "shortcut": [["Control", "n"]] 23 | } 24 | ] 25 | }, 26 | { 27 | "id": 95, 28 | "children-display": "submenu", 29 | "label": "View", 30 | "submenu": [ 31 | { 32 | "id": 96, 33 | "children-display": "submenu", 34 | "label": "Zoom", 35 | "submenu": [ 36 | { 37 | "id": 100, 38 | "label": "50%" 39 | }, 40 | { 41 | "id": 101, 42 | "label": "100%" 43 | }, 44 | { 45 | "id": 102, 46 | "label": "20%" 47 | } 48 | ] 49 | } 50 | ] 51 | } 52 | ] 53 | } 54 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vnc", 3 | "author": "Andrey Sidorov ", 4 | "version": "0.1.2", 5 | "keywords": [ 6 | "vnc", 7 | "rfb", 8 | "viewer", 9 | "record" 10 | ], 11 | "description": "VNC viewer in native JS", 12 | "main": "vnc.js", 13 | "bin": { 14 | "vnc": "./vnc.js" 15 | }, 16 | "maintainers": [ 17 | { 18 | "name": "Andrey Sidorov", 19 | "email": "sidoares@yandex.ru" 20 | } 21 | ], 22 | "license": "MIT", 23 | "repository": { 24 | "type": "git", 25 | "url": "http://github.com/sidorares/node-vnc.git" 26 | }, 27 | "dependencies": { 28 | "x11": "~0.1.2", 29 | "optimist": "~0.3.5", 30 | "dbusmenu": "~0.1.0", 31 | "underscore": "~1.4.3", 32 | "ntk": "*", 33 | "rfb2": "*" 34 | }, 35 | "devDependencies": { 36 | "mocha": "*" 37 | }, 38 | "scripts": { 39 | "test": "mocha", 40 | "prepublish": "npm prune" 41 | }, 42 | "engine": { 43 | "node": ">=0.6.0" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /vnc.js: -------------------------------------------------------------------------------- 1 | //var rfb = require('rfb2'); 2 | var rfb = require('rfb2'); 3 | var ui = require('ntk'); 4 | var argv = require('optimist').argv; 5 | var _ = require('underscore'); 6 | 7 | var menu = require('./mainmenu'); 8 | 9 | ui.createClient(main); 10 | function main(err, app) { 11 | var mainwnd; 12 | var r = rfb.createConnection(argv); 13 | r.on('connect', afterConnect); 14 | function afterConnect() { 15 | mainwnd = app.createWindow(_.pick(r, 'title', 'width', 'height')).map(); 16 | var buttonsState = 0; 17 | 18 | // updates from window to vnc server 19 | mainwnd.on('mousemove', function(ev) { r.pointerEvent(ev.x, ev.y, buttonsState) }); 20 | var handleMouseClick = function(ev) { 21 | var buttonBit = 1 << (ev.keycode - 1); 22 | // set button bit 23 | if (ev.type == 4) // TODO use event name 24 | buttonsState |= buttonBit; 25 | else 26 | buttonsState &= ~buttonBit; 27 | r.pointerEvent(ev.x, ev.y, buttonsState); 28 | }; 29 | mainwnd.on('mouseup', handleMouseClick); 30 | mainwnd.on('mousedown', handleMouseClick); 31 | var handleKeyClick = function(ev) { 32 | console.log('MOUSE CLICK!!!'); 33 | var shift = ev.buttons & 1; 34 | var isDown = (ev.type == 2) ? 1 : 0; 35 | r.keyEvent(ev.keysym, isDown); 36 | }; 37 | mainwnd.on('keyup', handleKeyClick); 38 | mainwnd.on('keydown', handleKeyClick); 39 | 40 | // updates from vnc server 41 | r.on('resize', mainwnd.resize.bind(mainwnd)); 42 | var ctx = mainwnd.getContext('2d', function(err, ctx) { 43 | r.on('rect', function(rect) { 44 | if (rect.encoding == rfb.encodings.raw) { 45 | rect.data = rect.buffer; // TODO: rename in rfb 46 | ctx.putImageData(rect, rect.x, rect.y); 47 | } else if (rect.encoding == rfb.encodings.copyRect) { 48 | //ctx.drawImage(canvas, rect.src.x, rect.src.y, rect.width, rect.height, rect.x, rect.y); 49 | } else if (rect.encoding == rfb.encodings.hextile) { 50 | console.log('hextile rec! (currently not fully supported'); 51 | rect.on('tile', function(tile) { 52 | console.log('tile:', tile); 53 | }); 54 | } 55 | }); 56 | }); 57 | mainwnd.on('close', r.end.bind(r)); 58 | //var mainmenu = mainwnd.addMenu(menu); 59 | //mainmenu.on('clicked', console.log); 60 | } 61 | } 62 | --------------------------------------------------------------------------------