【Unity+WebGL】コピペが上手く使えない問題

2022年6月18日

UnityのWebGL環境でコピペが上手くいかなかったので,クリップボードに小細工をしてみる

経緯

Unity + WebGLでクリップボードを使おうとしたところ,GUIUtility.systemCopyBufferはUnity独自のクリップボードを使っているようで,通常のクリップボードとの連携ができませんでした.調べてみると,WebGLInputパッケージなどを使うとInputFieldではコピペできるようですが,私の環境では上手く動作しませんでした.

そこで,クリップボードの共有機能を自作することにしました.

概要

構造としてはこんな感じで実装します.

  • Unity側のクリップボードを監視し,コピーされたら通常のクリップボードに上書きする処理
  • 通常のクリップボードを監視し,コピーされたらUnity側のクリップボードに上書きする処理

実装方法

まずは,Unityでの処理を書いていきます.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System.Runtime.InteropServices;

public class CopyPaste : MonoBehaviour
{
    #if UNITY_WEBGL && !UNITY_EDITOR
    //コピー
    [DllImport("__Internal")]
    private static extern void CopyWebGL(string str);
    //ペースト
    [DllImport("__Internal")]
    private static extern void PasteWeb();
    private string unityClip;
    private string webClip;

    void Start()
    {
        unityClip = "";
        webClip = "";
        PasteWeb(); 
    }

    void Update()
    {
        if(GUIUtility.systemCopyBuffer != unityClip){
            unityClip = GUIUtility.systemCopyBuffer;
            CopyWebGL(unityClip);
            Debug.Log("Copy unity to clip");
        }
        PasteWeb();
    }
    public void paste(string text){
        if(text != webClip){
            webClip = text;
            GUIUtility.systemCopyBuffer = webClip;
        }
    }
    #else
    #endif
}

これを適当なゲームオブジェクトに張り付けておきます.

次にPluginsフォルダに以下のCopyWebGL.jslib

ファイルを作成します.

mergeInto(LibraryManager.library, { 
  CopyWebGL: function(str) {
    if(navigator.clipboard){
      navigator.clipboard.writeText(str) //httpでは使えない(httpsのみ)
      .then(function(text){
    });
    }else{
      var str = Pointer_stringify(str);
      var listener = function(e){
        e.clipboardData.setData("text/plain" , str);    
        e.preventDefault();
        document.removeEventListener("copy", listener);
      }
      document.addEventListener("copy" , listener);
      document.execCommand("copy");
    }
  },

  PasteWeb: function() {
    if(navigator.clipboard){
    navigator.clipboard.readText()
    .then(function(text){
        SendMessage('CopyPaste', 'paste', text); 
        //クリップボードから取得したテキストを渡す(ゲームオブジェクト名,メソッド名,クリップボードの値)
    });
    }
  }
});

これでクリップボードの共有ができるようになりました.

あとは,普通にGUIUtility.systemCopyBufferを使えばUnity外部ともコピペできます.

所感

コピペは問題なくできますが,Webページのロード時にクリップボードへのアクセス許可が必要になってしまいました.セキュリティ的な問題だと思いますので,早く公式の方で直感的にクリップボードが使える機能を実装してほしいものです…