Working with Raw rectangles and capital letter keys.

This commit is contained in:
Joel Martin 2010-04-05 23:54:30 -05:00
parent c8460b0310
commit 64ab5c4ded
5 changed files with 314 additions and 239 deletions

View File

@ -2,7 +2,7 @@
<head><title>Canvas Experiments</title></head>
<body>
Canvas:<br>
<canvas id="tutorial" width="500" height="300">
<canvas id="tutorial" width="640" height="480">
Canvas not supported.
</canvas>
@ -16,6 +16,6 @@
<script src="canvas.js"></script>
<script>
window.onload = function() { init_canvas('tutorial'); }
window.onload = function() { init_canvas('tutorial', 640, 480); }
</script>
</html>

View File

@ -28,8 +28,9 @@ c_x : 0,
c_y : 0,
c_wx : 0,
c_wy : 0,
ctx : null,
mousedown: function (e) {
mouseDown: function (e) {
evt = e.event || window.event;
e.stop();
debug('mouse ' + evt.which + '/' + evt.button + ' down:' +
@ -64,14 +65,21 @@ ctxDisable: function (e) {
},
init: function (canvas) {
init: function (canvas, width, height, keyDown, keyUp, mouseDown, mouseUp) {
debug(">> init_canvas");
if (! keyDown) keyDown = Canvas.keyDown;
if (! keyUp) keyUp = Canvas.keyUp;
if (! mouseDown) mouseDown = Canvas.mouseDown;
if (! mouseUp) mouseUp = Canvas.mouseUp;
c = $(canvas);
c.addEvent('mousedown', Canvas.mouseDown);
c.addEvent('mouseup', Canvas.mouseUp);
document.addEvent('keydown', Canvas.keyDown);
document.addEvent('keyup', Canvas.keyUp);
c.width = width;
c.height = height;
document.addEvent('keydown', keyDown);
document.addEvent('keyup', keyUp);
c.addEvent('mousedown', mouseDown);
c.addEvent('mouseup', mouseUp);
/* Work around right and middle click browser behaviors */
document.addEvent('click', Canvas.ctxDisable);
@ -83,22 +91,22 @@ init: function (canvas) {
Canvas.c_wy = c.getSize().y;
if (! c.getContext) return;
var ctx = c.getContext('2d');
Canvas.ctx = c.getContext('2d');
/* Border */
ctx.stroke();
ctx.rect(0, 0, Canvas.c_wx, Canvas.c_wy);
ctx.stroke();
Canvas.ctx.stroke();
Canvas.ctx.rect(0, 0, Canvas.c_wx, Canvas.c_wy);
Canvas.ctx.stroke();
/*
// Does not work in firefox
var himg = new Image();
himg.src = "head_ani2.gif"
ctx.drawImage(himg, 10, 10);
Canvas.ctx.drawImage(himg, 10, 10);
*/
/* Test array image data */
var img = ctx.createImageData(50, 50);
var img = Canvas.ctx.createImageData(50, 50);
for (y=0; y< 50; y++) {
for (x=0; x< 50; x++) {
img.data[(y*50 + x)*4 + 0] = 255 - parseInt((255 / 50) * y);
@ -107,9 +115,21 @@ init: function (canvas) {
img.data[(y*50 + x)*4 + 3] = 255;
}
}
ctx.putImageData(img, 100, 100);
Canvas.ctx.putImageData(img, 100, 100);
debug("<< init_canvas");
},
rfbImage: function(x, y, width, height, arr) {
var img = Canvas.ctx.createImageData(width, height);
for (var i=0; i < (width * height); i++) {
img.data[i*4 + 0] = arr[i*4 + 0];
img.data[i*4 + 1] = arr[i*4 + 1];
img.data[i*4 + 2] = arr[i*4 + 2];
img.data[i*4 + 3] = 255; // Set Alpha
}
Canvas.ctx.putImageData(img, x, y);
}
};

View File

@ -17,6 +17,7 @@
<script src="include/mootools.js"></script>
<script src="include/mootools-more.js"></script>
<script src="include/base64a.js"></script>
<script src="include/des2.js"></script>
<script src="canvas.js"></script>
<script src="vnc.js"></script>
@ -30,12 +31,11 @@
debug("must set host and port");
return;
}
init_ws(host, port);
RFB.init_ws(host, port);
debug("<< connect");
}
window.onload = function() {
Canvas.init('vnc');
connect();
}
</script>

477
vnc.js
View File

@ -1,178 +1,267 @@
var ws = null;
var vnc_host = '';
var vnc_port = 5900;
var rfb_state = 'ProtocolVersion';
var rfb_continue = -1;
var rfb_shared = 1;
var fbu = {
rects : 0,
bytes : 0,
x : 0,
y : 0,
width : 0,
height : 0,
encoding : 0,
arr : null};
var fb_width = 0;
var fb_height = 0;
var fb_name = "";
var fb_Bpp = 4;
Array.prototype.card8 = function (pos) {
return this[pos];
Array.prototype.shift8 = function () {
return this.shift();
}
Array.prototype.pushCard8 = function (num) {
Array.prototype.push8 = function (num) {
this.push(num & 0xFF);
}
Array.prototype.card16 = function (pos) {
return (this[pos] << 8) +
(this[pos+1] );
Array.prototype.shift16 = function () {
return (this.shift() << 8) +
(this.shift() );
}
Array.prototype.pushCard16 = function (num) {
Array.prototype.push16 = function (num) {
this.push((num >> 8) & 0xFF,
(num ) & 0xFF );
}
Array.prototype.card32 = function (pos) {
return (this[pos] << 24) +
(this[pos+1] << 16) +
(this[pos+2] << 8) +
(this[pos+3] );
Array.prototype.shift32 = function () {
return (this.shift() << 24) +
(this.shift() << 16) +
(this.shift() << 8) +
(this.shift() );
}
Array.prototype.pushCard32 = function (num) {
Array.prototype.push32 = function (num) {
this.push((num >> 24) & 0xFF,
(num >> 16) & 0xFF,
(num >> 8) & 0xFF,
(num ) & 0xFF );
}
Array.prototype.substr = function (start, len) {
return this.slice(start, start+len).map(
function (num) { return String.fromCharCode(num); } ).join('');
Array.prototype.shiftStr = function (len) {
var arr = this.splice(0, len);
return arr.map(function (num) {
return String.fromCharCode(num); } ).join('');
}
Array.prototype.shiftBytes = function (len) {
return this.splice(0, len);
}
/*
* Server message handlers
*/
/* RFB/VNC initialisation */
function rfb_init_msg(data) {
debug(">> rfb_init_msg");
RFB = {
switch (rfb_state) {
state : 'ProtocolVersion',
shared : 1,
poll_rate : 3000,
/* RFB/VNC initialisation */
init_msg: function (data) {
debug(">> init_msg");
switch (RFB.state) {
case 'ProtocolVersion' :
debug("ProtocolVersion: " + data)
debug("ProtocolVersion:")
if (data.length != 12) {
debug("Invalid protocol version from server");
rfb_state = 'reset';
RFB.state = 'reset';
return;
}
send_string("RFB 003.003\n");
rfb_state = 'Authentication';
debug("Server ProtocolVersion: " + data.shiftStr(11))
RFB.send_string("RFB 003.003\n");
RFB.state = 'Authentication';
break;
case 'Authentication' :
debug("Authentication")
if (data.length != 4) {
debug("Invalid auth scheme");
rfb_state = 'reset';
if (data.length < 4) {
debug("Invalid auth frame");
RFB.state = 'reset';
return;
}
var scheme = data.card32(0);
var scheme = data.shift32();
debug("Auth scheme: " + scheme);
switch (scheme) {
case 0: // connection failed
var strlen = data.card32(4);
var reason = data.substr(8, strlen);
var strlen = data.shift32();
var reason = data.shiftStr(strlen);
debug("auth failed: " + reason);
rfb_state = "reset";
RFB.state = "failed";
return;
case 1: // no authentication
send_array([rfb_shared]); // ClientInitialisation
rfb_state = "ServerInitialisation";
RFB.send_array([RFB.shared]); // ClientInitialisation
RFB.state = "ServerInitialisation";
break;
case 2: // VNC authentication
var challenge = data.substr(4, 16);
var challenge = data.shiftStr(16);
// TODO:
//var crypt = des(challenge, password);
//send_string(crypt);
rfb_state = "Authentication-VNC";
//RFB.send_string(crypt);
RFB.state = "SecurityResult";
debug("challenge: " + challenge + "(" + challenge.length + ")");
//response = Javacrypt.crypt(challenge, "jdm239").toString();
//response = Javacrypt.crypt("jdm239", challenge).toString();
//response = des("jdm239", challenge, 1)
/* COWCOW bit mirrored */
passwd = [194, 242, 234, 194, 242, 234, 0, 0].shiftStr(8);
debug("passwd: " + passwd + "(" + passwd.length + ")");
response = des(passwd, challenge, 1)
debug("reponse: " + response + "(" + response.length + ")");
RFB.send_string(response);
break;
}
break;
case 'Authentication-VNC' :
debug("Authentication-VNC")
case 'SecurityResult' :
debug("SecurityResult")
if (data.length != 4) {
debug("Invalid server auth response");
rfb_state = 'reset';
RFB.state = 'reset';
return;
}
var resp = data.card32(0);
var resp = data.shift32();
switch (resp) {
case 0: // OK
debug("Authentication OK");
break;
case 1: // failed
debug("Authentication failed");
rfb_state = "reset";
RFB.state = "reset";
return;
case 2: // too-many
debug("Too many authentication attempts");
rfb_state = "reset";
RFB.state = "failed";
return;
}
send_array([rfb_shared]); // ClientInitialisation
rfb_state = "ServerInitialisation";
RFB.send_array([RFB.shared]); // ClientInitialisation
RFB.state = "ServerInitialisation";
break;
case 'ServerInitialisation' :
debug("ServerInitialisation")
if (data.length < 24) {
debug("Invalid server initialisation");
rfb_state = 'reset';
RFB.state = 'reset';
return;
}
/* Screen size */
debug("data: " + data);
fb_width = data.card16(0);
fb_height = data.card16(2);
//debug("data: " + data);
fb_width = data.shift16();
fb_height = data.shift16();
debug("Screen size: " + fb_width + "x" + fb_height);
/* PIXEL_FORMAT */
var bits_per_pixel = data.card8(4);
var depth = data.card8(5);
var big_endian = data.card8(6);
var true_color = data.card8(7);
var bpp = data.shift8();
var depth = data.shift8();
var big_endian = data.shift8();
var true_color = data.shift8();
debug("bits per pixel: " + bits_per_pixel);
debug("bpp: " + bpp);
debug("depth: " + depth);
debug("big_endian: " + big_endian);
debug("true_color: " + true_color);
/* Connection name/title */
var name_length = data.card32(20);
fb_name = data.substr(24, name_length);
data.shiftStr(12);
var name_length = data.shift32();
fb_name = data.shiftStr(name_length);
debug("Name: " + fb_name);
setEncodings();
Canvas.init('vnc', fb_width, fb_height, RFB.keyDown, RFB.keyUp);
fbUpdateRequest(0, 0, 0, 10, 10);
RFB.setEncodings();
RFB.setPixelFormat();
rfb_state = 'normal';
RFB.fbUpdateRequest(0, 0, 0, fb_width, fb_height);
RFB.state = 'normal';
break;
}
debug("<< rfb_init_msg");
}
debug("<< init_msg");
},
/* Normal RFB/VNC messages */
function rfb_msg(data) {
debug(">> rfb_msg");
if (rfb_continue >= 0) {
var msg_type = rfb_continue;
normal_msg: function (data) {
//debug(">> normal_msg");
if ((fbu.rects > 0) || (fbu.bytes > 0)) {
var msg_type = 0;
} else {
var msg_type = data.card8(0);
var msg_type = data.shift8();
}
switch (msg_type) {
case 0: // FramebufferUpdate
debug("FramebufferUpdate");
if (fbu.rects == 0) {
data.shift8();
fbu.rects = data.shift16();
debug("FramebufferUpdate, " + fbu.rects + " rects");
fbu.bytes = 0;
fbu.arr = [];
} else {
//debug("FramebufferUpdate continuation");
}
while (data.length > 0) {
//debug("data.length: " + data.length);
if (fbu.bytes == 0) {
fbu.x = data.shift16();
fbu.y = data.shift16();
fbu.width = data.shift16();
fbu.height = data.shift16();
fbu.encoding = data.shift32();
//debug('New rect: ' + fbu.x + "," + fbu.y + " -> " + (fbu.x + fbu.width) + "," + (fbu.y + fbu.height));
switch (fbu.encoding) {
case 0: // Raw
fbu.bytes = fbu.width * fbu.height * fb_Bpp;
break;
case 1: // Copy-Rect
fbu_bytes = 4;
break;
}
} else {
if (data.length >= fbu.bytes) {
//debug('Done rect: ' + fbu.x + "," + fbu.y + " -> " + (fbu.x + fbu.width) + "," + (fbu.y + fbu.height));
fbu.arr = fbu.arr.concat(data.shiftBytes(fbu.bytes))
fbu.bytes = 0;
switch (fbu.encoding) {
case 0: // Raw
debug('Raw-Rect: ' + fbu.x + "," + fbu.y + " -> " + (fbu.x + fbu.width) + "," + (fbu.y + fbu.height));
Canvas.rfbImage(fbu.x, fbu.y, fbu.width, fbu.height, fbu.arr);
break;
case 1: // Copy-Rect
debug('Copy-Rect: ' + fbu.x + "," + fbu.y + " -> " + (fbu.x + fbu.width) + "," + (fbu.y + fbu.height));
var new_x = fbu.arr.shift16();
var new_y = fbu.arr.shift16();
Canvas.ctx.drawImage(Canvas.c, fbu.x, fbu.y, fbu.width, fbu.height, new_x, new_y, fbu.width, fbu.height);
break;
}
fbu.arr = [];
fbu.rects --;
} else {
//debug('Part rect: ' + fbu.x + "," + fbu.y + " -> " + (fbu.x + fbu.width) + "," + (fbu.y + fbu.height));
fbu.bytes = fbu.bytes - data.length;
fbu.arr = fbu.arr.concat(data.shiftBytes(data.length))
}
}
//debug("Bytes remaining: " + fbu.bytes);
}
//debug("Finished frame buffer update");
break;
case 1: // SetColourMapEntries
debug("SetColourMapEntries");
@ -187,203 +276,167 @@ function rfb_msg(data) {
debug("Unknown server message type: " + msg_type);
break;
}
debug("<< rfb_msg");
}
//debug("<< normal_msg");
},
/*
* Client message routines
*/
function send_string(str) {
ws.send(Base64.encode(str));
}
setPixelFormat: function () {
debug(">> setPixelFormat");
var arr = [0]; // msg-type
arr.push8(0); // padding
arr.push8(0); // padding
arr.push8(0); // padding
function send_array(arr) {
debug("encoded array: " + Base64.encode_array(arr));
ws.send(Base64.encode_array(arr));
}
arr.push8(fb_Bpp * 8); // bits-per-pixel
arr.push8(24); // depth
arr.push8(0); // little-endian
arr.push8(1); // true-color
function setPixelFormat() {
}
arr.push16(255); // red-max
arr.push16(255); // green-max
arr.push16(255); // blue-max
arr.push8(16); // red-shift
arr.push8(8); // green-shift
arr.push8(0); // blue-shift
function fixColourMapEntries() {
}
arr.push8(0); // padding
arr.push8(0); // padding
arr.push8(0); // padding
RFB.send_array(arr);
debug("<< setPixelFormat");
},
function setEncodings() {
fixColourMapEntries: function () {
},
setEncodings: function () {
debug(">> setEncodings");
var arr = [2]; // msg-type
arr.pushCard8(0); // padding
arr.pushCard16(1); // encoding count
arr.pushCard32(0); // raw encoding
send_array(arr);
arr.push8(0); // padding
arr.push16(2); // encoding count
arr.push32(1); // copy-rect encoding
arr.push32(0); // raw encoding
RFB.send_array(arr);
debug("<< setEncodings");
}
},
function fbUpdateRequest(incremental, x, y, xw, yw) {
fbUpdateRequest: function (incremental, x, y, xw, yw) {
debug(">> fbUpdateRequest");
var arr = [3]; // msg-type
arr.pushCard8(incremental);
arr.pushCard16(x);
arr.pushCard16(y);
arr.pushCard16(xw);
arr.pushCard16(yw);
send_array(arr);
arr.push8(incremental);
arr.push16(x);
arr.push16(y);
arr.push16(xw);
arr.push16(yw);
RFB.send_array(arr);
debug("<< fbUpdateRequest");
}
},
function keyEvent() {
}
keyEvent: function (key, code, down) {
debug(">> keyEvent: " + key + "(" + code + ") " + down);
var arr = [4]; // msg-type
arr.push8(down);
arr.push16(0);
arr.push32(code);
RFB.send_array(arr);
RFB.fbUpdateRequest(1, 0, 0, fb_width, fb_height);
debug("<< keyEvent");
},
function pointerEvent() {
}
pointerEvent: function () {
},
function clientCutText() {
}
clientCutText: function () {
},
/*
* Utility routines
*/
send_string: function (str) {
ws.send(Base64.encode(str));
},
send_array: function (arr) {
debug("encoded array: " + Base64.encode_array(arr));
ws.send(Base64.encode_array(arr));
},
poller: function () {
if (RFB.state == 'normal') {
RFB.fbUpdateRequest(1, 0, 0, fb_width, fb_height);
RFB.poller.delay(RFB.poll_rate);
}
},
keyDown: function (e) {
e.stop();
RFB.keyEvent(e.key, e.code, 1);
},
keyUp: function (e) {
e.stop();
RFB.keyEvent(e.key, e.code, 0);
},
/*
* Setup routines
*/
function _init_ws() {
_init_ws: function () {
debug(">> _init_ws");
var uri = "ws://" + vnc_host + ":" + vnc_port;
debug("connecting to " + uri);
ws = new WebSocket(uri);
ws.onmessage = function(e) {
debug(">> onmessage");
//debug(">> onmessage");
var data = Base64.decode_array(e.data);
//debug("decoded array: " + data);
if (rfb_state != 'normal') {
rfb_init_msg(data);
if (RFB.state != 'normal') {
RFB.init_msg(data);
} else {
rfb_msg(data);
RFB.normal_msg(data);
}
if (rfb_state == 'reset') {
if (RFB.state == 'reset') {
/* close and reset connection */
ws.close();
_init_ws();
RFB._init_ws();
} else if (RFB.state == 'failed') {
debug("Giving up!");
ws.close();
}
debug("<< onmessage");
//debug("<< onmessage");
};
ws.onopen = function(e) {
debug(">> onopen");
rfb_state = "ProtocolVersion";
RFB.state = "ProtocolVersion";
debug("<< onopen");
};
ws.onclose = function(e) {
debug(">> onclose");
rfb_state = "closed";
RFB.state = "closed";
debug("<< onclose");
}
debug("<< _init_ws");
}
RFB.poller.delay(RFB.poll_rate);
function init_ws(host, port) {
debug("<< _init_ws");
},
init_ws: function (host, port) {
debug(">> init_ws");
vnc_host = host;
vnc_port = port;
if (ws) {
ws.close();
}
_init_ws();
RFB._init_ws();
debug("<< init_ws");
}
/*
function draw() {
var canvas = document.getElementById('vnc');
if (! canvas.getContext) return;
var ctx = canvas.getContext('2d');
ctx.fillStyle = "rgb(50,50,50)";
ctx.fillRect(0, 0, 800, 600);
var img = new Image();
img.src = "head_ani2.gif"
ctx.drawImage(img, 10, 10);
ctx.drawImage(canvas, 20, 20, 30, 30, 70, 70, 30, 30);
}
function draw2() {
var canvas = document.getElementById('tutorial');
if (! canvas.getContext) return;
var ctx = canvas.getContext('2d');
roundedRect(ctx,12,12,150,150,15);
roundedRect(ctx,19,19,150,150,9);
roundedRect(ctx,53,53,49,33,10);
roundedRect(ctx,53,119,49,16,6);
roundedRect(ctx,135,53,49,33,10);
roundedRect(ctx,135,119,25,49,10);
ctx.beginPath();
ctx.arc(37,37,13,Math.PI/7,-Math.PI/7,true);
ctx.lineTo(31,37);
ctx.fill();
for(var i=0;i<8;i++){
ctx.fillRect(51+i*16,35,4,4);
}
for(i=0;i<6;i++){
ctx.fillRect(115,51+i*16,4,4);
}
for(i=0;i<8;i++){
ctx.fillRect(51+i*16,99,4,4);
}
ctx.beginPath();
ctx.moveTo(83,116);
ctx.lineTo(83,102);
ctx.bezierCurveTo(83,94,89,88,97,88);
ctx.bezierCurveTo(105,88,111,94,111,102);
ctx.lineTo(111,116);
ctx.lineTo(106.333,111.333);
ctx.lineTo(101.666,116);
ctx.lineTo(97,111.333);
ctx.lineTo(92.333,116);
ctx.lineTo(87.666,111.333);
ctx.lineTo(83,116);
ctx.fill();
ctx.fillStyle = "white";
ctx.beginPath();
ctx.moveTo(91,96);
ctx.bezierCurveTo(88,96,87,99,87,101);
ctx.bezierCurveTo(87,103,88,106,91,106);
ctx.bezierCurveTo(94,106,95,103,95,101);
ctx.bezierCurveTo(95,99,94,96,91,96);
ctx.moveTo(103,96);
ctx.bezierCurveTo(100,96,99,99,99,101);
ctx.bezierCurveTo(99,103,100,106,103,106);
ctx.bezierCurveTo(106,106,107,103,107,101);
ctx.bezierCurveTo(107,99,106,96,103,96);
ctx.fill();
ctx.fillStyle = "black";
ctx.beginPath();
ctx.arc(101,102,2,0,Math.PI*2,true);
ctx.fill();
ctx.beginPath();
ctx.arc(89,102,2,0,Math.PI*2,true);
ctx.fill();
}
function roundedRect(ctx,x,y,width,height,radius){
ctx.beginPath();
ctx.moveTo(x,y+radius);
ctx.lineTo(x,y+height-radius);
ctx.quadraticCurveTo(x,y+height,x+radius,y+height);
ctx.lineTo(x+width-radius,y+height);
ctx.quadraticCurveTo(x+width,y+height,x+width,y+height-radius);
ctx.lineTo(x+width,y+radius);
ctx.quadraticCurveTo(x+width,y,x+width-radius,y);
ctx.lineTo(x+radius,y);
ctx.quadraticCurveTo(x,y,x,y+radius);
ctx.stroke();
}
*/
debug("here10");
}; /* End of RFB */

View File

@ -4,6 +4,8 @@ import sys, os, socket, time, traceback
from base64 import b64encode, b64decode
from select import select
buffer_size = 65536
server_handshake = """HTTP/1.1 101 Web Socket Protocol Handshake\r
Upgrade: WebSocket\r
Connection: Upgrade\r
@ -35,30 +37,30 @@ def proxy(client, target):
if excepts: raise Exception("Socket exception")
if client in ins:
buf = client.recv(1024)
buf = client.recv(buffer_size)
if len(buf) == 0: raise Exception("Client closed")
tqueue.append(b64decode(buf[1:-1]))
print "Client recv: %s (%d)" % (repr(buf[1:-1]), len(buf))
#traffic("}")
#print "Client recv: %s (%d)" % (repr(buf[1:-1]), len(buf))
traffic("}")
if target in ins:
buf = target.recv(1024)
buf = target.recv(buffer_size)
if len(buf) == 0: raise Exception("Target closed")
cqueue.append("\x00" + b64encode(buf) + "\xff")
print "Target recv: %s (%d)" % (repr(buf), len(buf))
#traffic("{")
#print "Target recv: %s (%d)" % (repr(buf), len(buf))
traffic("{")
if cqueue and client in outs:
while cqueue:
print "Client send: %s" % repr(cqueue[0])
#print "Client send: %s" % repr(cqueue[0])
client.send(cqueue.pop(0))
#traffic("<")
traffic("<")
if tqueue and target in outs:
while tqueue:
print "Target send: %s" % repr(tqueue[0])
#print "Target send: %s" % repr(tqueue[0])
target.send(tqueue.pop(0))
#traffic(">")
traffic(">")
def start_server(listen_port, target_host, target_port):
lsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)