Search Unity

Copy / Paste - has anyone built a good solution for this?

Discussion in 'Web' started by Aurigan, May 3, 2016.

  1. Aurigan

    Aurigan

    Joined:
    Jun 30, 2013
    Posts:
    291
    Copy / Paste doesn't work into or out of a Unity (and NGUI) WebGL game. As far as I can tell this is a JS issue by (security) design.

    One of the top results for this issue on google points to a closed bug : https://issuetracker.unity3d.com/is...s-not-support-copy-slash-paste-on-webgl-build which incorrectly claims it's 'fixed'

    It sounds like from various other snippets and hints from Unity staff in the forums like it *should* be possible to make this work by some combination of special keyboard access mode and having a hidden text field on the page. Has anyone actually done this successfully? Or have some other working method for copying/pasting text into/out of Unity? I'm looking for a working example implementation. Thanks!
     
    Last edited: May 3, 2016
  2. alexsuvorov

    alexsuvorov

    Unity Technologies

    Joined:
    Nov 15, 2015
    Posts:
    327
    Hello Aurigan.

    When original issue was submitted, copy-paste also did not work correctly between Unity input fields, which has been fixed.

    You are talking about copy to and paste from the system clipboard. Yes, it is in fact should be possible in the latest versions of major browsers (except, probably, Safari). The fix however requires nontrivial changes in the Unity input processing scheme. The main issue here is that due to the browser security policy, such actions can only be performed inside a JavaScript event handler initiated by the user, while all the Unity input events are queued and processed in the main loop when the initial JavaScript handler has already exited. One possible workaround for that would be to process clipboard events outside of the input queue and out of order, which however may cause undesired side effects. When all those issues are resolved, this functionality will be added.
     
    GDevTeam likes this.
  3. Aurigan

    Aurigan

    Joined:
    Jun 30, 2013
    Posts:
    291
    Hey Alex, thanks for the reply. Great to hear that this might actually get fixed so hacks aren't needed.

    In the short term are you aware of any solution out there that can make this work? I found this post : http://forum.unity3d.com/threads/webgl-and-html-overlay.398283/#post-2599929 which looks like it creates an overlay whos contents are then forwarded to Unity - any improvement over that concept?
     
  4. alexsuvorov

    alexsuvorov

    Unity Technologies

    Joined:
    Nov 15, 2015
    Posts:
    327
    I don't have ready to use code to share at the moment, but I might prepare it and post here later. For now you might check out the document.execCommand functionality (https://developer.mozilla.org/en-US/docs/Web/API/Document/execCommand). In addition you might consider the document.onpaste event. This will let you create a much nicer solution. However the mentioned html edit field overlay is also a valid fallback.
     
    Aurigan likes this.
  5. Aurigan

    Aurigan

    Joined:
    Jun 30, 2013
    Posts:
    291
    Example clean code would be much appreciated!

    The specific use-case I'm trying to solve for is that I generate some text in my game and want the player to be able to copy that. I also then want the player to be able to paste it back into the game.
     
  6. Aurigan

    Aurigan

    Joined:
    Jun 30, 2013
    Posts:
    291
    Ok so I worked out how to get an overlay solution working. The way this works is to add a div on top of the unity game canvas that contains a textarea and two buttons (cancel overlay and import text). It's (really) ugly but it works :)

    Code (JavaScript):
    1. var ImportExportPlugin = {
    2.     ShowOverlay: function(stringPointer)
    3.     {
    4.  
    5.       if (!document.getElementById('inputOverlay')) {
    6.         var myoverlay = document.createElement('div');
    7.         myoverlay.setAttribute('id', 'inputOverlay');
    8.         document.body.appendChild(myoverlay);          
    9.         document.getElementById('inputOverlay').innerHTML = "<textarea id='saveGameInput'></textarea><br><button onClick='SendMessage(\"Import Export Panel(Clone)\",\"ImportFromWebOverlay\",document.getElementById(\"saveGameInput\").value)'>Import</button><button onClick='SendMessage(\"Import Export Panel(Clone)\",\"CloseOverlay\",\"\")'>Cancel</button>";
    10.       }
    11.      
    12.       var exported = Pointer_stringify(stringPointer);
    13.       document.getElementById('saveGameInput').value = exported;
    14.       document.getElementById('inputOverlay').setAttribute('style','display:block;');
    15.       document.getElementById('inputOverlay').focus();
    16.     },
    17.     HideOverlay: function()
    18.     {
    19.         document.getElementById('inputOverlay').setAttribute('style','display:none;');
    20.     }
    21. };
    22. mergeInto(LibraryManager.library, ImportExportPlugin);

    Code (CSharp):
    1.     [DllImport("__Internal")]
    2.     private static extern void ShowOverlay(string exportedGameSave);
    3.  
    4.     [DllImport("__Internal")]
    5.     private static extern void HideOverlay();
    6.  
    7.     void ShowImportExportOverlay (string gameSave) {
    8.         ShowOverlay(gameSave);
    9.         ToggleCaptureAllInput(false);
    10.     }
    11.  
    12.     public void ImportFromWebOverlay(string importStr){
    13.         HideOverlay();
    14.         LoadGameFromImportedString(importStr);
    15.         ToggleCaptureAllInput(true);
    16.     }
    17.  
    18.     public void CloseOverlay(string param){
    19.         HideOverlay();
    20.         ToggleCaptureAllInput(true);
    21.     }
    22.  
    23.     void ToggleCaptureAllInput(bool captureAll){
    24.         #if !UNITY_EDITOR && UNITY_WEBGL
    25.         WebGLInput.captureAllKeyboardInput = captureAll;
    26.         #endif
    27.     }

    Code (JavaScript):
    1. button {
    2.     background-color: white;
    3.     border: none;
    4.     color: black;
    5.     padding: 10px;
    6.     margin: 10px;
    7.     text-align: center;
    8.     text-decoration: none;
    9.     display: inline-block;
    10.     font-size: 16px;
    11. }
    12.  
    13. div#inputOverlay{
    14.   text-align:center;
    15.   margin:0;
    16.   padding:10px;
    17.   width:100%;
    18.   height:100%;
    19.   background-color: purple;
    20.   z-index: 1;
    21.   position: fixed;
    22. }
    23.  
    24. textArea{
    25.   width:600px;
    26.   height:200px;
    27.   padding:5px;
    28.   margin:10px;
    29. }

    This was adapted from http://forum.unity3d.com/threads/webgl-and-html-overlay.398283/#post-2599929, for my specific use-case I needed to import / export an encrypted save game string.
     
    Last edited: May 3, 2016
    skullthug likes this.
  7. AFrisby

    AFrisby

    Joined:
    Apr 14, 2010
    Posts:
    223
    Is this on Unity's plans to fix; or is it likely to stay broken for the medium/long-term?
     
  8. alexsuvorov

    alexsuvorov

    Unity Technologies

    Joined:
    Nov 15, 2015
    Posts:
    327
    Hello AFrisby.

    There is nothing that can be described as 'broken' here. Browser security policy implies the following limitations:

    1) You can only get the content of the system clipboard from paste event, and, specifically in Firefox, the paste event is only sent when an editable element on the page is focused. You can technically make the canvas editable, however in most versions this will result in the edit cursor overlaying the canvas and other issues. So it seems that currently the only way to make it work is to add an additional hidden editable element (like a hidden textarea) to the page. This will not work reliably for the browser Paste menu command, unless the hidden element is constantly focused, which might not be desirable for some WebGL applications.
    P.S. contrary to the popular belief, Flash wont help you capture the system clipboard content, as clearly stated here http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/desktop/Clipboard.html (unless you are utilizing the same paste event, which basically makes Flash approach useless)

    2) Although most modern browsers support execCommand, currently it does not seem to be supported by Safari, which means there is no universal solution for copying content into the system clipboard. However, it can be easily done in Chrome 42+, Firefox 41+, Edge and Opera 29+ using the following code:
    Code (JavaScript):
    1.   var textToCopy = 'Hello World!';
    2.  
    3.   var clipboardBuffer = document.createElement('textarea');
    4.   clipboardBuffer.style.cssText = 'position:fixed; top:-10px; left:-10px; height:0; width:0; opacity:0;';
    5.   document.body.appendChild(clipboardBuffer);
    6.  
    7.   var copyButton = document.createElement('button');
    8.   copyButton.innerHTML = 'Copy "' + textToCopy + '" to the system clipboard';
    9.   copyButton.onclick = function() {
    10.     clipboardBuffer.focus();
    11.     clipboardBuffer.value = textToCopy;
    12.     clipboardBuffer.setSelectionRange(0, clipboardBuffer.value.length);
    13.     var succeeded;
    14.     try { succeeded = document.execCommand('copy'); } catch (e) {}
    15.     alert(succeeded ? 'Copied successfully' : 'Error: current browser does not fully support execCommand functionality or this event handler was not initiated by the user');
    16.   }
    17.   document.body.appendChild(copyButton);
    3) According to the browser security policy, execCommand can only be successfully executed from an event handler initiated by the user (for example, it will work from onkeydown or onclick, but not from onload or setTimeout). Normally, one would register a keyup event handler after the copy shortcut has been pressed, but this solution is not universal, as in recent versions of Firefox on Mac you are not able to execute execCommand from a keyup event handler while the Command key is down. Unity is processing events through an intermediate queue, therefore performing security restricted action would require bypassing the input queue and processing the event out of order, which is quite challenging to perform reliably in the current version.

    Nevertheless, we are planning to provide a workaround for the copy/paste browser security restriction, supporting keyboard shortcuts in most of the recent browsers (except copying into system clipboard in Safari) starting from Unity 5.5

    For the current Unity version I can propose a simple workaround, a Paste UI button near the input field which will popup an html input field where user can paste the system clipboard and click OK (no need for overlays, just use the JavaScript prompt function for that); and a Copy UI button near the input field that will copy the field content into the system clipboard (using the code above) when user clicks the button (expect Safari). Also you might need an example of how to perform an action restricted by the browser security policy from a Unity UI button OnButtonPointerDown event http://forum.unity3d.com/threads/ho...rddrive-into-a-webgl-app.380985/#post-2474594
     
    Last edited: Jun 10, 2016
    GDevTeam and gresolio like this.
  9. Aurigan

    Aurigan

    Joined:
    Jun 30, 2013
    Posts:
    291
    This is good news :)
     
  10. Rojoss

    Rojoss

    Joined:
    Aug 21, 2016
    Posts:
    2
    Could you give us an update about the status of this?
     
  11. alexsuvorov

    alexsuvorov

    Unity Technologies

    Joined:
    Nov 15, 2015
    Posts:
    327
    Hello Rojoss.
    No update on this yet, but it is being worked on.
     
    GDevTeam likes this.
  12. KristianE

    KristianE

    Joined:
    Nov 16, 2012
    Posts:
    4
    Hi alexsuvorov

    It's good to hear that people are working on this. It certainly seems like an important feature. We are currently looking for the paste functionality - and I don't seem to be able to persuade our UI designer that a javascript text box is a good idea...

    So, any news if this will make it into Unity 5.5? .. I just tried the 5.5.0b3 and I could not paste text in both Windows and OS X.
     
  13. jfcampos

    jfcampos

    Joined:
    May 6, 2013
    Posts:
    5
    Hi there! any updates?
     
  14. nfmelendez

    nfmelendez

    Joined:
    Feb 26, 2015
    Posts:
    22
    hey any update here?
     
  15. nsmith1024

    nsmith1024

    Joined:
    Mar 18, 2014
    Posts:
    870
    You have to write Javascript code (outside of Unity that Unity calls), that pops up a little dialog with an edit box, have the user past into that, then send that pasted string to your Unity App using messages, thats the only way I know becuase you cant do copy/paste i dont think.
     
  16. tarek-hentati

    tarek-hentati

    Joined:
    Sep 30, 2014
    Posts:
    4
    Hey, Any update for the fix of the bug in Unity 5.5?
     
  17. fwalkerCirca

    fwalkerCirca

    Joined:
    Apr 10, 2017
    Posts:
    57
    Also looking for some updates on this. document.onpaste event seems like a decent work around. Are there any example son how to use this?
     
  18. Avelblood

    Avelblood

    Joined:
    May 5, 2016
    Posts:
    6
    This thread
    Is dead.
     
    adamstone711 likes this.
  19. powellreid

    powellreid

    Joined:
    Dec 18, 2017
    Posts:
    5
    Any update on this or any other workaround? We are developing game using c#, so i am not sure how can we use above snippet in our code? Any guidence?
     
  20. Stream

    Stream

    Joined:
    Oct 28, 2013
    Posts:
    37
    Still no progress?
     
  21. JJJohan

    JJJohan

    Joined:
    Mar 18, 2016
    Posts:
    214
    I'd say hold out just a little longer. Looks like there's some development for a clipboard API happening in Emscripten.

    https://github.com/kripken/emscripten/issues/6377

    I've had luck using newer versions of Emscripten with Unity with very few changes (No luck with their experimental threading support yet though :)!)
     
  22. Deacon2099

    Deacon2099

    Joined:
    Nov 23, 2015
    Posts:
    3
  23. bondk

    bondk

    Joined:
    Feb 14, 2017
    Posts:
    4
  24. Chintan-Kansagara

    Chintan-Kansagara

    Joined:
    Jul 16, 2016
    Posts:
    19
    hello everyone.
    [finally solved copy / paste issues in WebGL]

    Step 1 : unity side

    public void CopyToClipboard()
    {
    string str = "Hello Word";
    Application.ExternalCall("CopyToClipboard", str);
    }

    Step 2 : index.html file edit side
    <head>
    <style>
    .textToCopy {
    opacity: 0
    }
    </style>

    </head>

    <body>
    <div class="webgl-content">
    <input type='text' class='textToCopy' id="textToCopy">
    </div>
    </body>

    function CopyToClipboard(arg){
    var copyText = arg;
    $('.textToCopy').val(copyText);
    var textToCopy = $('.textToCopy').val();
    console.log('copyText',textToCopy);
    $('.textToCopy').select();
    document.execCommand('copy');
    }
     
  25. FlolF

    FlolF

    Joined:
    Nov 20, 2012
    Posts:
    14
    Hi Chintan, I edited your code like the followig:

    <script>function CopyToClipboard(arg){
    var copyText = arg;
    $('.textToCopy').val(copyText);
    var textToCopy = $('.textToCopy').val();
    console.log('copyText',textToCopy);
    $('.textToCopy').select();
    document.execCommand('copy');
    }</script>

    But still no luck. It doesn't work for me. Could you elaborate further?
     
  26. Nodrap

    Nodrap

    Joined:
    Nov 4, 2011
    Posts:
    83
    Finally got it working by grabbing the function from another site. Used the webgl templates so the modifications are always there on export.
    Use the same Unity side as above but this is how my index.html turned out.


    <!DOCTYPE html>
    <html lang="en-us">
    <head>
    <meta charset="utf-8">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>Unity WebGL Player | MyProject</title>
    <link rel="shortcut icon" href="TemplateData/favicon.ico">
    <link rel="stylesheet" href="TemplateData/style.css">
    <script src="TemplateData/UnityProgress.js"></script>
    <script src="Build/UnityLoader.js"></script>
    <script>
    var unityInstance = UnityLoader.instantiate("unityContainer", "Build/Output.json", {onProgress: UnityProgress});
    function CopyToClipboard(arg){
    var tempInput = document.createElement("input");
    tempInput.value = arg;
    document.body.appendChild(tempInput);
    tempInput.select();
    document.execCommand("copy");
    document.body.removeChild(tempInput); }
    </script>
    </head>
    <body>
    <div class="webgl-content">
    <input type='text' class='textToCopy' id="textToCopy">
    <div id="unityContainer" style="width: 1024px; height: 576px"></div>
    <div class="footer">
    <div class="webgl-logo"></div>
    <div class="fullscreen" onclick="unityInstance.SetFullscreen(1)"></div>
    <div class="title">MyProject</div>
    </div>
    </div>
    </body>
    </html>
     
    IsaGDC likes this.
  27. IsaGDC

    IsaGDC

    Joined:
    Jan 8, 2017
    Posts:
    6
    Thank you so much!! It finally work in WebGL and editing its index.html!
    I have tested in any PC browser, Android and iOs. However, it does not work in iOs.
    Does somebody know why? It should be the same...!
    @Nodrap
     
  28. Nodrap

    Nodrap

    Joined:
    Nov 4, 2011
    Posts:
    83
    Afraid was only using it for testing on WebGL and it stretched my skill even there! As I understand it Unity discourage running WebGL in browsers on mobiles
     
  29. greggman

    greggman

    Joined:
    Nov 30, 2013
    Posts:
    24
    I don't know if this works well but an attempt at a solution is to use the browser's copy and paste events. In paste pass that into Unity and append to the current InputField. On copy ask the inputfield to copy then pass unity's clipboard back to the browser

    Here's some code and a working example

    https://github.com/greggman/unity-webg-copy-and-paste

    note this solution is for `UnityEngine.UI.InputField` and `TMPro.TMP_InputField`. I didn't work on supporting any other text fields
     
    Liam-McHara likes this.
  30. garethdenyer

    garethdenyer

    Joined:
    Aug 16, 2020
    Posts:
    6
    Thank you all very much for this - especially Nodrap for providing such an easy to crib template.
    Using that, I have managed to get my WebGL deployed game to copy stuff to the clipboard. Many thanks!!

    However, I have a small problem with forming line breaks in the copied text.
    I am constructing the string that is to be copied to the clipboard using with a mixture of 'tab' and 'line break' markers as below (this is to create a table that can be pasted into a spreadsheet). Although the information copied on the clipboard recognizes the 'tabs' it does not correctly put the line breaks in.
    Should I be using something other than '\n', perhaps?


    string DataToCopy =

    "A" + '\t' + varA1 + '\t' + varA2 + '\t' + varA3 + '\n'
    +
    "B" + '\t' + varB1 + '\t' + varB2 + '\t' + varB3;


    In normal Unity, the above is copied as a nice two line, four column table.
     
  31. Nodrap

    Nodrap

    Joined:
    Nov 4, 2011
    Posts:
    83
    @garethdenyer Could try '\r' or even a combination '\n\r' or '\r\n'
     
  32. garethdenyer

    garethdenyer

    Joined:
    Aug 16, 2020
    Posts:
    6
    Thank you, Nodrap!!
     
  33. MFKJ

    MFKJ

    Joined:
    May 13, 2015
    Posts:
    264
    where did you used CopyToClipboard function?
     
  34. RedRival

    RedRival

    Joined:
    Nov 23, 2012
    Posts:
    5
    Just a little help for those who is still struggling.
    I've made a plugin from Nodrap code. Just look an attachment.
    You can simply call it using this C# code f.e.:
    Code (CSharp):
    1. using System;
    2. using System.Runtime.InteropServices;
    3. using UnityEngine;
    4.  
    5. namespace Rock
    6. {
    7.     public static class Clipboard
    8.     {
    9.         [DllImport("__Internal")]
    10.         private static extern void CopyToClipboard(string text);
    11.      
    12.         public static void SetText(string text)
    13.         {          
    14. #if UNITY_WEBGL && UNITY_EDITOR == false
    15.             CopyToClipboard(text);
    16. #else
    17.             GUIUtility.systemCopyBuffer = text;
    18. #endif
    19.         }
    20.     }
    21. }
     

    Attached Files:

  35. ujz

    ujz

    Joined:
    Feb 17, 2020
    Posts:
    29
    Thank you. But it does not work across mobile browsers right? Cannot get it to copy on Safari iOS.
     
  36. Lifeisluckbased

    Lifeisluckbased

    Joined:
    May 17, 2022
    Posts:
    2
    Hello @alexsuvorov, could you update us if this is a feature Unity is working on or if it has been put on hold?
     
  37. HernandoNJ

    HernandoNJ

    Joined:
    May 13, 2018
    Posts:
    75