Ticket #1424: html5-clipboard.patch
File html5-clipboard.patch, 10.3 KB (added by , 5 years ago) |
---|
-
html5/index.html
53 53 <div class="notifications"> 54 54 </div> 55 55 56 < input id="pasteboard" onblur="this.focus()" autofocus />56 <!-- <input id="pasteboard" onblur="this.focus()" autofocus /> --> 57 57 58 <div> 59 <textarea id="pasteboard" onblur="this.focus()" autofocus style="display: block; position: absolute; left: -99em;"></textarea> 60 </div> 61 58 62 <script> 59 63 60 if (!window.location.getParameter 64 if (!window.location.getParameter) { 61 65 window.location.getParameter = function(key) { 62 66 function parseParams() { 63 67 var params = {}, … … 248 252 var ssl = document.location.protocol=="https:"; 249 253 client.connect(server, port, ssl); 250 254 251 // attach a callback for paste on the screen255 //clipboard hooks: 252 256 $('#pasteboard').on('paste', function (e) { 253 e.preventDefault();254 var text = (e.originalEvent || e).clipboardData.getData('text/plain');255 client.handle_paste(text);257 var paste_data = (e.originalEvent || e).clipboardData.getData('text/plain'); 258 client._send_clipboard_token(paste_data); 259 return false; 256 260 }); 257 258 // try to ensure the browser doesn't fire shortcuts 259 // (ie: we want control-S to be sent to the application, not trigger the save-page browser action) 260 $(window).bind('keydown', function(event) { 261 if (event.ctrlKey || event.metaKey) { 262 event.preventDefault(); 263 } 261 $('#pasteboard').on('copy', function (e) { 262 var paste_data = (e.originalEvent || e).clipboardData.getData('text/plain'); 263 $('#pasteboard').text(client.clipboard_buffer); 264 $('#pasteboard').select(); 265 client.clipboard_pending = false; 266 return true; 264 267 }); 268 $('#pasteboard').on('cut', function (e) { 269 var paste_data = (e.originalEvent || e).clipboardData.getData('text/plain'); 270 $('#pasteboard').text(client.clipboard_buffer); 271 $('#pasteboard').select(); 272 client.clipboard_pending = false; 273 return true; 274 }); 275 $('#screen').on('click', function (e) { 276 //console.log("click pending=", client.clipboard_pending, "buffer=", client.clipboard_buffer); 277 if (client.clipboard_pending) { 278 $('#pasteboard').text(client.clipboard_buffer); 279 $('#pasteboard').select(); 280 //for IE: 281 if (window.clipboardData && window.clipboardData.setData) { 282 clipboardData.setData("Text", this.clipboard_buffer); 283 } 284 else { 285 var success = document.execCommand('copy'); 286 //console.log("copy success=", success); 287 } 288 } 289 }); 265 290 }); 266 291 </script> 267 292 </body> -
html5/js/Client.js
190 190 XpraClient.prototype.init_clipboard = function() { 191 191 // the "clipboard" 192 192 this.clipboard_buffer = ""; 193 this.clipboard_pending = false; 193 194 this.clipboard_targets = ["UTF8_STRING", "TEXT", "STRING", "text/plain"]; 194 195 } 195 196 … … 207 208 // to allow multiple clients on the same page 208 209 if (window.jQuery) { 209 210 jQuery(document).keydown(function (e) { 210 e.preventDefault(); 211 me._keyb_onkeydown(e, me); 211 return me._keyb_onkeydown(e, me); 212 212 }); 213 213 jQuery(document).keyup(function (e) { 214 e.preventDefault(); 215 me._keyb_onkeyup(e, me); 214 return me._keyb_onkeyup(e, me); 216 215 }); 217 216 jQuery(document).keypress(function (e) { 218 e.preventDefault(); 219 me._keyb_onkeypress(e, me); 217 return me._keyb_onkeypress(e, me); 220 218 }); 221 219 } else { 222 220 document.onkeydown = function (e) { 223 me._keyb_onkeydown(e, me);221 return me._keyb_onkeydown(e, me); 224 222 }; 225 223 document.onkeyup = function (e) { 226 me._keyb_onkeyup(e, me);224 return me._keyb_onkeyup(e, me); 227 225 }; 228 226 document.onkeypress = function (e) { 229 me._keyb_onkeypress(e, me);227 return me._keyb_onkeypress(e, me); 230 228 }; 231 229 } 232 230 } … … 394 392 } 395 393 } 396 394 397 XpraClient.prototype.handle_paste = function(text) {398 // set our clipboard buffer399 this.clipboard_buffer = text;400 // send token401 var packet = ["clipboard-token", "CLIPBOARD"];402 this.protocol.send(packet);403 // tell user to paste in remote application404 // alert("Paste acknowledged. Please paste in remote application.");405 }406 395 407 396 XpraClient.prototype._keyb_get_modifiers = function(event) { 408 397 /** … … 467 456 str = str.toLowerCase(); 468 457 469 458 if (this.topwindow != null) { 470 //show("win="+win.toSource()+", keycode="+keycode+", modifiers=["+modifiers+"], str="+str); 459 //send via a timer so we get a chance to capture the clipboard value, 460 //before we send control-V to the server: 471 461 var packet = ["key-action", this.topwindow, keyname, pressed, modifiers, keyval, str, keycode, group]; 472 this.protocol.send(packet); 462 var protocol = this.protocol; 463 setTimeout(function () { 464 //show("win="+win.toSource()+", keycode="+keycode+", modifiers=["+modifiers+"], str="+str); 465 protocol.send(packet); 466 }, 0); 473 467 } 468 this.log("key", keyname); 469 //only allow key events that need to be seen by the browser 470 //for handling the clipboard 471 if (keyname=="Control_L" || keyname=="Control_R") { 472 return true; 473 } 474 if (keyname=="Shift_L" || keyname=="Shift_R") { 475 return true; 476 } 477 if (shift && keyname=="Insert") { 478 return true; 479 } 480 var control = modifiers.indexOf("control")>=0; 481 if (control) { 482 var l = keyname.toLowerCase(); 483 if (control && (l=="c" || l=="x" || l=="v")) { 484 return true; 485 } 486 } 487 //this.log("keyname=", keyname, "modifiers=", modifiers); 488 return false; 474 489 } 475 490 491 476 492 XpraClient.prototype._keyb_onkeydown = function(event, ctx) { 477 ctx._keyb_process(true, event); 478 return false; 493 return ctx._keyb_process(true, event); 479 494 }; 480 495 XpraClient.prototype._keyb_onkeyup = function(event, ctx) { 481 ctx._keyb_process(false, event); 482 return false; 496 return ctx._keyb_process(false, event); 483 497 }; 484 498 485 499 XpraClient.prototype._keyb_onkeypress = function(event, ctx) { … … 498 512 var modifiers = ctx._keyb_get_modifiers(event); 499 513 500 514 /* PITA: this only works for keypress event... */ 501 caps_lock = false;502 515 var shift = modifiers.indexOf("shift")>=0; 503 if (keycode>=97 && keycode<=122 && shift) 504 caps_lock = true; 505 else if (keycode>=65 && keycode<=90 && !shift) 506 caps_lock = true; 516 if (keycode>=97 && keycode<=122 && shift) { 517 ctx.caps_lock = true; 518 } 519 else if (keycode>=65 && keycode<=90 && !shift) { 520 ctx.caps_lock = true; 521 } 522 else { 523 ctx.caps_lock = false; 524 } 507 525 //show("caps_lock="+caps_lock); 508 526 return false; 509 527 }; … … 768 786 //not handled yet, but we will: 769 787 "clipboard_enabled" : true, 770 788 "clipboard.want_targets" : true, 771 "clipboard.selections" : ["CLIPBOARD"], 789 "clipboard.greedy" : true, 790 "clipboard.selections" : ["CLIPBOARD", "PRIMARY"], 772 791 "notifications" : true, 773 792 "cursors" : true, 774 793 "bell" : true, … … 792 811 mydiv.id = String(wid); 793 812 var mycanvas = document.createElement("canvas"); 794 813 mydiv.appendChild(mycanvas); 795 document.body.appendChild(mydiv); 814 var screen = document.getElementById("screen"); 815 screen.appendChild(mydiv); 796 816 // set initial sizes 797 817 mycanvas.width = w; 798 818 mycanvas.height = h; … … 1622 1642 } 1623 1643 } 1624 1644 1645 1646 XpraClient.prototype._send_clipboard_token = function(data) { 1647 this.log("sending clipboard token with data:", data); 1648 var packet = ["clipboard-token", "CLIPBOARD", [], "STRING", "STRING", data.length, "bytes", data, false, true, true]; 1649 this.protocol.send(packet); 1650 } 1651 1625 1652 XpraClient.prototype._process_clipboard_token = function(packet, ctx) { 1653 ctx.log("clipboard token:", packet); 1626 1654 // only accept some clipboard types 1627 1655 if(ctx.clipboard_targets.indexOf(packet[3])>=0) { 1628 // we should probably update our clipboard buffer1629 1656 ctx.clipboard_buffer = packet[7]; 1630 // prompt user 1631 prompt("Text was placed on the remote clipboard:", packet[7]); 1657 ctx.clipboard_pending = true; 1632 1658 } 1633 1659 } 1634 1660 -
xpra/clipboard/clipboard_base.py
196 196 #older versions always claimed the selection when the token is received: 197 197 claim = True 198 198 if len(packet)>=10: 199 claim = packet[8]199 claim = bool(packet[8]) 200 200 #clients can now also change the greedy flag on the fly, 201 201 #this is needed for clipboard direction restrictions: 202 202 #the client may want to be notified of clipboard changes, just like a greedy client 203 proxy._greedy_client = packet[9] 204 proxy.got_token(targets, target_data, claim) 203 proxy._greedy_client = bool(packet[9]) 204 synchronous_client = len(packet)>=11 and bool(packet[10]) 205 proxy.got_token(targets, target_data, claim, synchronous_client) 205 206 206 207 def _get_clipboard_from_remote_handler(self, proxy, selection, target): 207 208 for x in DISCARD_TARGETS: … … 661 662 glib.idle_add(self.remove_block) 662 663 gtk.Invisible.do_selection_clear_event(self, event) 663 664 664 def got_token(self, targets, target_data, claim ):665 def got_token(self, targets, target_data, claim=True, synchronous_client=False): 665 666 # We got the anti-token. 666 667 if not self._enabled: 667 668 return … … 672 673 #re-enable the flag via idle_add so events like do_owner_changed 673 674 #get a chance to run first. 674 675 glib.idle_add(self.remove_block) 675 if CLIPBOARD_GREEDYand self._can_receive:676 if (CLIPBOARD_GREEDY or synchronous_client) and self._can_receive: 676 677 if targets: 677 678 for target in targets: 678 679 self.selection_add_target(self._selection, target, 0) … … 682 683 if text_target in target_data: 683 684 text_data = target_data.get(text_target) 684 685 log("clipboard %s set to '%s'", self._selection, repr_ellipsized(text_data)) 685 self._clipboard.set_text(text_data )686 self._clipboard.set_text(text_data, len=len(text_data)) 686 687 if not claim: 687 688 log("token packet without claim, not setting the token flag") 688 689 #the other end is just telling us to send the token again next time something changes,