xpra icon
Bug tracker and wiki

This bug tracker and wiki are being discontinued
please use https://github.com/Xpra-org/xpra instead.


Ticket #1424: html5-clipboard.patch

File html5-clipboard.patch, 10.3 KB (added by Antoine Martin, 4 years ago)

two-way clipboard

  • html5/index.html

     
    5353                <div class="notifications">
    5454                </div>
    5555
    56                 <input id="pasteboard" onblur="this.focus()" autofocus />
     56                <!--  <input id="pasteboard" onblur="this.focus()" autofocus />  -->
    5757
     58            <div>
     59                    <textarea id="pasteboard" onblur="this.focus()" autofocus style="display: block; position: absolute; left: -99em;"></textarea>
     60            </div>
     61
    5862                <script>
    5963
    60                         if (!window.location.getParameter ) {
     64                        if (!window.location.getParameter) {
    6165                                window.location.getParameter = function(key) {
    6266                                        function parseParams() {
    6367                                                        var params = {},
     
    248252                                var ssl = document.location.protocol=="https:";
    249253                            client.connect(server, port, ssl);
    250254
    251                             // attach a callback for paste on the screen
     255                            //clipboard hooks:
    252256                                $('#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;
    256260                                });
    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;
    264267                                });
     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                                });
    265290                        });
    266291                </script>
    267292        </body>
  • html5/js/Client.js

     
    190190XpraClient.prototype.init_clipboard = function() {
    191191        // the "clipboard"
    192192        this.clipboard_buffer = "";
     193        this.clipboard_pending = false;
    193194        this.clipboard_targets = ["UTF8_STRING", "TEXT", "STRING", "text/plain"];
    194195}
    195196
     
    207208        // to allow multiple clients on the same page
    208209        if (window.jQuery) {
    209210                jQuery(document).keydown(function (e) {
    210                         e.preventDefault();
    211                         me._keyb_onkeydown(e, me);
     211                        return me._keyb_onkeydown(e, me);
    212212                });
    213213                jQuery(document).keyup(function (e) {
    214                         e.preventDefault();
    215                         me._keyb_onkeyup(e, me);
     214                        return me._keyb_onkeyup(e, me);
    216215                });
    217216                jQuery(document).keypress(function (e) {
    218                         e.preventDefault();
    219                         me._keyb_onkeypress(e, me);
     217                        return me._keyb_onkeypress(e, me);
    220218                });
    221219        } else {
    222220                document.onkeydown = function (e) {
    223                         me._keyb_onkeydown(e, me);
     221                        return me._keyb_onkeydown(e, me);
    224222                };
    225223                document.onkeyup = function (e) {
    226                         me._keyb_onkeyup(e, me);
     224                        return me._keyb_onkeyup(e, me);
    227225                };
    228226                document.onkeypress = function (e) {
    229                         me._keyb_onkeypress(e, me);
     227                        return me._keyb_onkeypress(e, me);
    230228                };
    231229        }
    232230}
     
    394392        }
    395393}
    396394
    397 XpraClient.prototype.handle_paste = function(text) {
    398         // set our clipboard buffer
    399         this.clipboard_buffer = text;
    400         // send token
    401         var packet = ["clipboard-token", "CLIPBOARD"];
    402         this.protocol.send(packet);
    403         // tell user to paste in remote application
    404         // alert("Paste acknowledged. Please paste in remote application.");
    405 }
    406395
    407396XpraClient.prototype._keyb_get_modifiers = function(event) {
    408397        /**
     
    467456                str = str.toLowerCase();
    468457
    469458        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:
    471461                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);
    473467        }
     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;
    474489}
    475490
     491
    476492XpraClient.prototype._keyb_onkeydown = function(event, ctx) {
    477         ctx._keyb_process(true, event);
    478         return false;
     493        return ctx._keyb_process(true, event);
    479494};
    480495XpraClient.prototype._keyb_onkeyup = function(event, ctx) {
    481         ctx._keyb_process(false, event);
    482         return false;
     496        return ctx._keyb_process(false, event);
    483497};
    484498
    485499XpraClient.prototype._keyb_onkeypress = function(event, ctx) {
     
    498512        var modifiers = ctx._keyb_get_modifiers(event);
    499513
    500514        /* PITA: this only works for keypress event... */
    501         caps_lock = false;
    502515        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        }
    507525        //show("caps_lock="+caps_lock);
    508526        return false;
    509527};
     
    768786                //not handled yet, but we will:
    769787                "clipboard_enabled"                     : true,
    770788                "clipboard.want_targets"        : true,
    771                 "clipboard.selections"          : ["CLIPBOARD"],
     789                "clipboard.greedy"                      : true,
     790                "clipboard.selections"          : ["CLIPBOARD", "PRIMARY"],
    772791                "notifications"                         : true,
    773792                "cursors"                                       : true,
    774793                "bell"                                          : true,
     
    792811        mydiv.id = String(wid);
    793812        var mycanvas = document.createElement("canvas");
    794813        mydiv.appendChild(mycanvas);
    795         document.body.appendChild(mydiv);
     814        var screen = document.getElementById("screen");
     815        screen.appendChild(mydiv);
    796816        // set initial sizes
    797817        mycanvas.width = w;
    798818        mycanvas.height = h;
     
    16221642        }
    16231643}
    16241644
     1645
     1646XpraClient.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
    16251652XpraClient.prototype._process_clipboard_token = function(packet, ctx) {
     1653        ctx.log("clipboard token:", packet);
    16261654        // only accept some clipboard types
    16271655        if(ctx.clipboard_targets.indexOf(packet[3])>=0) {
    1628                 // we should probably update our clipboard buffer
    16291656                ctx.clipboard_buffer = packet[7];
    1630                 // prompt user
    1631                 prompt("Text was placed on the remote clipboard:", packet[7]);
     1657                ctx.clipboard_pending = true;
    16321658        }
    16331659}
    16341660
  • xpra/clipboard/clipboard_base.py

     
    196196        #older versions always claimed the selection when the token is received:
    197197        claim = True
    198198        if len(packet)>=10:
    199             claim = packet[8]
     199            claim = bool(packet[8])
    200200            #clients can now also change the greedy flag on the fly,
    201201            #this is needed for clipboard direction restrictions:
    202202            #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)
    205206
    206207    def _get_clipboard_from_remote_handler(self, proxy, selection, target):
    207208        for x in DISCARD_TARGETS:
     
    661662                    glib.idle_add(self.remove_block)
    662663        gtk.Invisible.do_selection_clear_event(self, event)
    663664
    664     def got_token(self, targets, target_data, claim):
     665    def got_token(self, targets, target_data, claim=True, synchronous_client=False):
    665666        # We got the anti-token.
    666667        if not self._enabled:
    667668            return
     
    672673            #re-enable the flag via idle_add so events like do_owner_changed
    673674            #get a chance to run first.
    674675            glib.idle_add(self.remove_block)
    675         if CLIPBOARD_GREEDY and self._can_receive:
     676        if (CLIPBOARD_GREEDY or synchronous_client) and self._can_receive:
    676677            if targets:
    677678                for target in targets:
    678679                    self.selection_add_target(self._selection, target, 0)
     
    682683                    if text_target in target_data:
    683684                        text_data = target_data.get(text_target)
    684685                        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))
    686687        if not claim:
    687688            log("token packet without claim, not setting the token flag")
    688689            #the other end is just telling us to send the token again next time something changes,