LibGDX html剪贴板

时间:2016-04-29 14:41:55

标签: javascript gwt libgdx clipboard

我正在开发LibGDX游戏,游戏中有登录界面和注册界面。 HTML版本的游戏具有剪贴板的沙箱环境,意味着:

从游戏中复制的任何东西都不能粘贴在游戏外面。 从外面复制的任何内容都不能粘贴在游戏的文本区域中

我只是想复制文本,有什么办法可以将沙箱剪贴板与系统剪贴板合并吗?

我想要的是: 当用户在文本字段中执行Ctr + V时,它应该从textfield&中的系统剪贴板中获取文本。当用户按Ctr + C时:它应该将文本放在系统剪贴板中

我正在尝试:

public class HtmlLauncher extends GwtApplication {
 private static HtmlLauncher instance;
 public void onModuleLoad() {
  instance = this;
  setLoadingListener(new LoadingListener() {
   @Override
   public void beforeSetup() {}

   @Override
   public void afterSetup() {
    setupCopyListener();
   }
  });
 }
 native void setupCopyListener()
  /*-{
         var htmlLauncher_onCopy = $entry(@com.myapp.game.client.HtmlLauncher::addToClipboard());
         $wnd.addEventListener("copy", htmlLauncher_onCopy, false);
     }-*/
 ;

 public static void addToClipboard() {
  instance.copy();
 }

 private void copy() {
  //getClipboard().setContents("");
  consoleLog("copied");
 }
}

任何人都可以帮助我:

  • 如何抓取参数到事件(抓取文本复制)
  • 只有在DOM中发生复制事件时才会触发,如何获取系统剪贴板

编辑(5月2日,尝试了JustACluelessNewbie的建议): 继承剪贴板:

public class MyClipboard implements com.badlogic.gdx.utils.Clipboard{
 private String cachedContent = "";

 public MyClipboard() {
  createTextArea();
 }

 @Override
 public String getContents() {
  String contents = getClipBoard();
  return (contents == null) ? cachedContent : cachedContent = contents;
 }

 @Override
 public void setContents(String content) {
  cachedContent = content == null ? "" : content;
  setClipBoard(content);
 }

 public static native void createTextArea() /*-{
         var textArea = document.createElement('textarea');
         textArea.style.position='fixed';
         textArea.style.top=0;
         textArea.style.left=0;
         textArea.style.width='2em';
         textArea.style.height='2em';
         textArea.style.padding=0;
         textArea.style.border='none';
         textArea.style.outline='none';
         textArea.style.boxShadow='none';
         textArea.style.background='transparent';
         $wnd._copy=textArea;
     }-*/;

 public static native String getClipBoard() /*-{
         if(window.clipboardData){
             return window.clipboardData.getData('Text');
         }else {
             document.body.appendChild($wnd._copy);
             try{
                 $wnd._copy.value = "";
                 $wnd._copy.focus();
                 $wnd._copy.select();
                 console.log(document.queryCommandSupported("paste")); //prints true
                 var result = document.execCommand('paste');
                 console.log(result);  //prints false
                 return $wnd._copy.value;
             }catch(err){
                 return null;
             }finally{
                 document.body.removeChild($wnd._copy);
             }
         }
     }-*/;

 public static native void setClipBoard(String content)  /*-{
         document.body.appendChild($wnd._copy);
         try{
             $wnd._copy.value = content;
             $wnd._copy.select();
             var result = document.execCommand('copy');
             console.log("after exec copy "+result)
         }catch(err){
             console.log("error:"+err);
         }finally{
             document.body.removeChild($wnd._copy);
         }
     }-*/ ;
}
  • 我正在运行最新的chrome,它说它支持粘贴命令但是 不粘贴
  • 它被复制到系统剪贴板,我可以在剪贴板中看到它 在按Ctr + V或右键单击粘贴
  • 时不粘贴

2 个答案:

答案 0 :(得分:1)

你是对的 - GWT剪贴板甚至不尝试访问“全局”剪贴板,仅在应用程序本身内复制和粘贴数据。您可以尝试将GwtClipboard替换为使用本机代码访问剪贴板数据的实现。您可以尝试转换Clipboard实施实验,未完成Dragome backend:您可以找到它here。它基本上是这样的:

public class DragomeClipboard implements Clipboard {
    private String cachedContent = "";

    public DragomeClipboard () {
        ScriptHelper.evalNoResult(
            "var textArea=document.createElement('textarea');textArea.style.position='fixed';textArea.style.top=0;textArea.style.left=0;textArea.style.width='2em';textArea.style.height='2em';textArea.style.padding=0;textArea.style.border='none';textArea.style.outline='none';textArea.style.boxShadow='none';textArea.style.background='transparent';this._copy=textArea;",
            this);
    }

    @Override
    public String getContents () {
        try {
            ScriptHelper.put("_cache", cachedContent, this);
            final String content = String.valueOf(ScriptHelper.eval(
                "if(window.clipboardData){return window.clipboardData.getData('Text');}else{document.body.appendChild(this._copy);try{this._copy.select();document.execCommand('paste');return this._copy.value;}catch(err){return _cache;}finally{document.body.removeChild(this._copy;}}",
                this));
            cachedContent = content;
            return content;
        } catch (final Throwable exception) {
            Exceptions.ignore(exception);
            return cachedContent;
        }
    }

    @Override
    public void setContents (final String content) {
        cachedContent = content == null ? "" : content;
        ScriptHelper.evalNoResult(
            "document.body.appendChild(this._copy);try{this._copy.select();document.execCommand('copy');}catch(err){}finally{document.body.removeChild(this._copy);}",
            this);
    }
}

我认为这是未经测试的,但绝对值得一试。请记住,大多数浏览器都会禁止访问剪贴板,除非它是由用户输入事件进行的;由于复制很可能是直接由本机事件侦听器处理(事件被轮询并稍后处理),因此它可能无法正常工作。

您可以覆盖GwtApplication#getClipboard()并返回已转换的实现 - 如果这样做,它应该被所有LibGDX实用程序使用,例如Scene2D小部件。

答案 1 :(得分:0)

最后,我得到了它的工作,如果有人还在寻找这个

,我会发布我的答案
package myPackage;

public class HtmlLauncher extends GwtApplication {
    private static HtmlLauncher instance;

    @Override
    public void onModuleLoad() {
        super.onModuleLoad();
        instance = this;
        setLoadingListener(new LoadingListener() {
            @Override
            public void beforeSetup() {
            }

            @Override
            public void afterSetup() {
                setupCopyListener();
            }
        });
    }

    native void setupCopyListener() /*-{
        var self = this;
        var isSafari = navigator.appVersion.search('Safari') != -1 && navigator.appVersion.search('Chrome') == -1 && navigator.appVersion.search('CrMo') == -1 && navigator.appVersion.search('CriOS') == -1;
        var isIe = (navigator.userAgent.toLowerCase().indexOf("msie") != -1 || navigator.userAgent.toLowerCase().indexOf("trident") != -1);

        var ieClipboardDiv = $doc.getElementById('#ie-clipboard-contenteditable');
        var hiddenInput = $doc.getElementById("hidden-input");
        var getTextToCopy = $entry(function(){
            return self.@myPackage.HtmlLauncher::copy()();
        });
        var pasteText = $entry(function(text){
            self.@myPackage.HtmlLauncher::paste(Ljava/lang/String;)(text);
        });

        var focusHiddenArea = function() {
            // In order to ensure that the browser will fire clipboard events, we always need to have something selected
            hiddenInput.value = '';
            hiddenInput.focus();
            hiddenInput.select();
        };

        // Focuses an element to be ready for copy/paste (used exclusively for IE)
        var focusIeClipboardDiv = function() {
            ieClipboardDiv.focus();
            var range = document.createRange();
            range.selectNodeContents((ieClipboardDiv.get(0)));
            var selection = window.getSelection();
            selection.removeAllRanges();
            selection.addRange(range);
        };

        // For IE, we can get/set Text or URL just as we normally would,
        // but to get HTML, we need to let the browser perform the copy or paste
        // in a contenteditable div.
        var ieClipboardEvent = function(clipboardEvent) {
            var clipboardData = window.clipboardData;
            if (clipboardEvent == 'cut' || clipboardEvent == 'copy') {
                clipboardData.setData('Text', getTextToCopy());
                focusIeClipboardDiv();
                setTimeout(function() {
                    focusHiddenArea();
                    ieClipboardDiv.empty();
                }, 0);
            }
            if (clipboardEvent == 'paste') {
                var clipboardText = clipboardData.getData('Text');
                ieClipboardDiv.empty();
                setTimeout(function() {
                    pasteText(clipboardText);
                    ieClipboardDiv.empty();
                    focusHiddenArea();
                }, 0);
            }
        };

        // For every broswer except IE, we can easily get and set data on the clipboard
        var standardClipboardEvent = function(clipboardEvent, event) {
            var clipboardData = event.clipboardData;
            if (clipboardEvent == 'cut' || clipboardEvent == 'copy') {
                clipboardData.setData('text/plain', getTextToCopy());
            }
            if (clipboardEvent == 'paste') {
                pasteText(clipboardData.getData('text/plain'));
            }
        };

        ['cut', 'copy', 'paste'].forEach(function (event) {
            $doc.addEventListener(event,function (e) {
                console.log(event);
                if(isIe) {
                    ieClipboardEvent(event);
                } else {
                    standardClipboardEvent(event, e);
                    focusHiddenArea();
                    e.preventDefault();
                }
            })
        })
    }-*/;

    private void paste(String text) {
        consoleLog("in paste"+text);
        String oldText = getClipboard().getContents();
        if(!oldText.equals(text)){
            getClipboard().setContents(text);
            Actor focusedActor = ((BasicScreen)((Game)getApplicationListener()).getScreen()).getStage().getKeyboardFocus();
            if (focusedActor != null && focusedActor instanceof TextField) {
                if(!oldText.equals("")) {
                    String textFieldText = ((TextField)focusedActor).getText();
                    textFieldText = textFieldText.substring(0,textFieldText.lastIndexOf(oldText));
                    ((TextField)focusedActor).setText(textFieldText);
                }
                ((TextField)focusedActor).appendText(text);
            }
        }
    }

    private String copy() {
        return getClipboard().getContents();
    }
}

我为所有屏幕创建了一个超类,这个问题需要的最小结构:

public abstract class BasicScreen extends ScreenAdapter implements InputProcessor {
    protected MyStage stage;

    public BasicScreen () {
        stage = new MyStage();
    }

     public MyStage getStage () {
        return stage;
     }
}

您需要在同一阶段添加文本字段

在index.html中,在内部添加以下两行:

<div id="ie-clipboard-contenteditable" class="hidden" contenteditable="true"></div>
<input id="hidden-input" class="hidden" type="text" value=""/>

在css中,添加:

.hidden {
    position: fixed;
    bottom: 0;
    left: 0;
    width: 10px;
    height: 10px;
    display: block;
    font-size: 1;
    z-index: -1;
    color: transparent;
    background: transparent;
    overflow: hidden;
    border: none;
    padding: 0;
    resize: none;
    outline: none;
    -webkit-user-select: text;
    user-select: text;
    /* Because for user-select:none, Safari won't allow input */
}

它在chrome中运行得很好,没有在其他浏览器上测试过。

我参考了: https://www.lucidchart.com/techblog/2014/12/02/definitive-guide-copying-pasting-javascript/