function Telnet(target, connect_callback, disconnect_callback, initscr) { var that = {}, // Public API interface vd, ws, sQ = []; termType = "Viewdata"; Array.prototype.pushStr = function (str) { var n = str.length; for (var i=0; i < n; i++) { this.push(str.charCodeAt(i)); } } function do_send() { if (sQ.length > 0) { ws.send(sQ); sQ = []; } } function do_recv() { vd.write(ws.rQshiftStr(ws.rQlen())); } that.connect = function(host, port, encrypt, url) { var host = host, port = port, scheme = "ws://", uri; if ((!host) || (!port)) { console.log("must set host and port"); return; } if (ws) { ws.close(); } if (encrypt) { scheme = "wss://"; } uri = scheme + host + ":" + port + url; ws.open(uri); vd.write("\x1e\x11Connecting ..."); } that.disconnect = function() { if (ws) { ws.close(); } disconnect_callback(); } function constructor() { /* Initialize Websock object */ ws = new Websock(); ws.on('message', do_recv); ws.on('open', function(e) { vd.curs_set(true, true); connect_callback(); }); ws.on('close', function(e) { that.disconnect(); }); ws.on('error', function(e) { that.disconnect(); }); /* Initialize the terminal emulator/renderer */ vd = new VD(40, 24, target, initscr); /* * Override VD I/O routines */ // Set handler for sending characters vd.getch( function send_chr(chr, vt) { var i; for (i = 0; i < chr.length; i++) { sQ.push(chr.charCodeAt(i)); } do_send(); vd.getch(send_chr); } ); vd.curs_set = function(vis, grab, eventist) { if (vis !== undefined) this.cursor_vis_ = (vis > 0); if (eventist === undefined) eventist = window; if (grab === true || grab === false) { if (grab === this.grab_events_) return; if (grab) { this.grab_events_ = true; VD.the_vt_ = this; Util.addEvent(eventist, 'keydown', vd.key_down); Util.addEvent(eventist, 'keyup', vd.key_up); } else { Util.removeEvent(eventist, 'keydown', vd.key_down); Util.removeEvent(eventist, 'keyup', vd.key_up); this.grab_events_ = false; VD.the_vt_ = undefined; } } } vd.key_down = function(e) { var vt = VD.the_vt_, keysym, ch, str = ""; if (vt === undefined) return true; keysym = getKeysym(e); if (keysym < 128) { if (e.ctrlKey) { if (keysym == 64) { // control 0 ch = 0; } else if ((keysym >= 97) && (keysym <= 122)) { // control codes 1-26 ch = keysym - 96; } else if ((keysym >= 91) && (keysym <= 95)) { // control codes 27-31 ch = keysym - 64; } } else { ch = keysym; switch (ch) { case 34: ch = 126; break; case 126: ch = 0x40; break; case 64: ch = 0x22; break; case 39: ch = 0x5f; break; case 95: ch = 0x23; break; case 96: ch = 0x27; break; } } str = String.fromCharCode(ch); } else { switch (keysym) { case 65505: // Shift, do not send directly break; case 65507: // Ctrl, do not send directly break; case 65293: // Carriage return, line feed str = '_'; break; case 65288: // Backspace str = '\b'; break; case 65307: // Escape str = '\x1b'; break; case 65361: // Left arrow str = '\x08'; break; case 65362: // Up arrow str = '\x0b'; break; case 65363: // Right arrow str = '\x09'; break; case 65364: // Down arrow str = '\x0a'; break; case 0xffc0: // f3 vd.reveal_ ^= 1; vd.refresh(); break; case 0xffc4: // f7 str = '\x1b'; break } } if (str) { vt.key_buf_.push(str); setTimeout(VD.go_getch_, 0); } Util.stopEvent(e); return false; } vd.key_up = function(e) { var vt = VD.the_vt_; if (vt === undefined) return true; Util.stopEvent(e); return false; } return that; } return constructor(); // Return the public API interface }