Commit 30059bdf authored by Joel Martin's avatar Joel Martin

Add cut and paste support.

- A textarea below the VNC area represents the state of the current
  VNC clipboard. If there is a server cut event, the textarea will be
  updated. If the user updates the contents of the textarea, the new
  data will be sent as a client paste (cut) event.

- One important change was to detect if the clipboard is focused and
  allow the user to type in the clipboard instead of in the VNC area.
parent 66a529d7
- Cut and paste support.
- Better status and error feedback. - Better status and error feedback.
- Get working in firefox using flash web-socket-js: - Get working in firefox using flash web-socket-js:
......
...@@ -16,6 +16,15 @@ ...@@ -16,6 +16,15 @@
style="border-style: dotted; border-width: 1px;"> style="border-style: dotted; border-width: 1px;">
Canvas not supported. Canvas not supported.
</canvas> </canvas>
<br><br>
VNC Clipboard:
<input id='clearButton' type="button" value="Clear"
onclick="RFB.clipboardClear();"><br>
<textarea id="clipboard" style="font-size:9;" cols=80 rows=5
onchange="RFB.clipboardPasteFrom();"
onfocus="RFB.clipboardFocus=true;"
onblur="RFB.clipboardFocus=false;"></textarea>
</body> </body>
<script src="include/mootools.js"></script> <script src="include/mootools.js"></script>
......
...@@ -33,6 +33,12 @@ Array.prototype.shiftStr = function (len) { ...@@ -33,6 +33,12 @@ Array.prototype.shiftStr = function (len) {
return arr.map(function (num) { return arr.map(function (num) {
return String.fromCharCode(num); } ).join(''); return String.fromCharCode(num); } ).join('');
} }
Array.prototype.pushStr = function (str) {
for (var i=0; i < str.length; i++) {
this.push(str.charCodeAt(i));
}
}
Array.prototype.shiftBytes = function (len) { Array.prototype.shiftBytes = function (len) {
return this.splice(0, len); return this.splice(0, len);
} }
...@@ -74,6 +80,10 @@ d : [], // Received data accumulator ...@@ -74,6 +80,10 @@ d : [], // Received data accumulator
version : "RFB 003.003\n", version : "RFB 003.003\n",
state : 'ProtocolVersion', state : 'ProtocolVersion',
cuttext : 'none', // ServerCutText wait state
ct_length : 0,
clipboardFocus: false,
shared : 1, shared : 1,
check_rate : 217, check_rate : 217,
req_rate : 1413, req_rate : 1413,
...@@ -233,6 +243,8 @@ normal_msg: function () { ...@@ -233,6 +243,8 @@ normal_msg: function () {
//console.log(">> normal_msg"); //console.log(">> normal_msg");
if (FBU.rects > 0) { if (FBU.rects > 0) {
var msg_type = 0; var msg_type = 0;
} else if (RFB.cuttext != 'none') {
var msg_type = 3;
} else { } else {
var msg_type = RFB.d.shift8(); var msg_type = RFB.d.shift8();
} }
...@@ -305,9 +317,25 @@ normal_msg: function () { ...@@ -305,9 +317,25 @@ normal_msg: function () {
break; break;
case 3: // ServerCutText case 3: // ServerCutText
console.log("ServerCutText"); console.log("ServerCutText");
RFB.d.shiftBytes(3); // Padding console.log("RFB.d:" + RFB.d.slice(0,20));
var length = RFB.d.shift32(); if (RFB.cuttext == 'none') {
RFB.d.shiftBytes(length); RFB.cuttext = 'header';
}
if (RFB.cuttext == 'header') {
if (RFB.d.length < 7) {
console.log("waiting for ServerCutText header");
break;
}
RFB.d.shiftBytes(3); // Padding
RFB.ct_length = RFB.d.shift32();
}
RFB.cuttext = 'bytes';
if (RFB.d.length < RFB.ct_length) {
console.log("waiting for ServerCutText bytes");
break;
}
RFB.clipboardCopyTo(RFB.d.shiftStr(RFB.ct_length));
RFB.cuttext = 'none';
break; break;
default: default:
console.log("Unknown server message type: " + msg_type); console.log("Unknown server message type: " + msg_type);
...@@ -618,7 +646,17 @@ pointerEvent: function (x, y) { ...@@ -618,7 +646,17 @@ pointerEvent: function (x, y) {
return arr; return arr;
}, },
clientCutText: function () { clientCutText: function (text) {
console.log(">> clientCutText");
var arr;
arr = [6]; // msg-type
arr.push8(0); // padding
arr.push8(0); // padding
arr.push8(0); // padding
arr.push32(text.length);
arr.pushStr(text);
console.log("<< clientCutText");
return arr;
}, },
...@@ -680,20 +718,24 @@ checkEvents: function () { ...@@ -680,20 +718,24 @@ checkEvents: function () {
} }
}, },
keyDown: function (e) { _keyX: function (e, down) {
//console.log(">> keyDown: " + Canvas.getKeysym(e)); if (RFB.clipboardFocus) {
return true;
}
e.stop(); e.stop();
var arr = RFB.keyEvent(Canvas.getKeysym(e), 1); var arr = RFB.keyEvent(Canvas.getKeysym(e), down);
arr = arr.concat(RFB.fbUpdateRequest(1)); arr = arr.concat(RFB.fbUpdateRequest(1));
RFB.send_array(arr); RFB.send_array(arr);
}, },
keyDown: function (e) {
//console.log(">> keyDown: " + Canvas.getKeysym(e));
RFB._keyX(e, 1);
},
keyUp: function (e) { keyUp: function (e) {
//console.log(">> keyUp: " + Canvas.getKeysym(e)); //console.log(">> keyUp: " + Canvas.getKeysym(e));
e.stop(); RFB._keyX(e, 0);
var arr = RFB.keyEvent(Canvas.getKeysym(e), 0);
arr = arr.concat(RFB.fbUpdateRequest(1));
RFB.send_array(arr);
}, },
mouseDown: function(e) { mouseDown: function(e) {
...@@ -729,6 +771,24 @@ mouseMove: function(e) { ...@@ -729,6 +771,24 @@ mouseMove: function(e) {
Mouse.arr = Mouse.arr.concat( RFB.pointerEvent(x, y) ); Mouse.arr = Mouse.arr.concat( RFB.pointerEvent(x, y) );
}, },
clipboardCopyTo: function (text) {
console.log(">> clipboardCopyTo: " + text.substr(0,40) + "...");
$('clipboard').value = text;
console.log("<< clipboardCopyTo");
},
clipboardPasteFrom: function () {
if (RFB.state != "normal") return;
var text = $('clipboard').value;
console.log(">> clipboardPasteFrom: " + text.substr(0,40) + "...");
RFB.send_array(RFB.clientCutText(text));
console.log("<< clipboardPasteFrom");
},
clipboardClear: function () {
$('clipboard').value = '';
RFB.clipboardPasteFrom();
},
/* /*
...@@ -781,10 +841,22 @@ connect: function () { ...@@ -781,10 +841,22 @@ connect: function () {
console.log("must set host and port"); console.log("must set host and port");
return; return;
} }
/* Reset state */
RFB.cuttext = 'none';
RFB.ct_length = 0;
FBU.rects = 0;
FBU.subrects = 0; // RRE and HEXTILE
FBU.lines = 0, // RAW
FBU.tiles = 0, // HEXTILE
Mouse.buttonmask = 0;
Mouse.arr = [];
if (RFB.ws) { if (RFB.ws) {
RFB.ws.close(); RFB.ws.close();
} }
RFB.init_ws(); RFB.init_ws();
$('connectButton').value = "Disconnect"; $('connectButton').value = "Disconnect";
$('connectButton').onclick = RFB.disconnect; $('connectButton').onclick = RFB.disconnect;
console.log("<< connect"); console.log("<< connect");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment