WebGLビルドでInput Fieldの日本語入力をする方法

本記事の内容

・WebGLのInputFieldで日本語入力をするための対処方法
・WebGLNativeInputFieldを使用する場合、Unity2023以降でのスクリプト書き換え内容

目次

WebGLではInputFieldで日本語入力が使えない

WebGLあるある:日本語入力出来ない

UnityのWebGLでビルドすると、InputFieldで日本語入力が出来なくて焦る人は多いと思います。
日本語に対応する対処法はいくつかあるので、方法を紹介します。

WebGLで日本語を入れる対処法

Unity公式のアセットを使う

Unity公式から、以下のGitHubで、回避するためのInputFieldが配布されています。
日本語の導入方法もあるのでわかりやすいです。
特徴としては、入力時にゲームが一度完全に止まり、入力画面が表示される仕様になっています。

GitHub
GitHub - unity3d-jp/WebGLNativeInputField: WebGLでIME入力を可能にします WebGLでIME入力を可能にします. Contribute to unity3d-jp/WebGLNativeInputField development by creating an account on GitHub.

ですが、このアセットを使った場合、問題が2つ発生しました。問題の解決策も書いておきます。

スマホ限定:プロンプトをキャンセルすると画面が勝手にアップされてしまう

スマホから、Safariでブラウザを開き、ビルドファイルを遊べるURLにアクセスし、Input Fieldをタップすると画面が勝手にスケールアップされ、戻らなくなりました。

画面が大きい端末では発生しなかったのですが、画面の小さいiPhone(SE2)のSafariで発生しました。また、OKボタンのときではなく、キャンセルボタンのときだけ発生しました。
完全に憶測ですが、Safari側で入力項目がある場合、文字が小さいからアップしといたろ!といういらない配慮をしてくれるからなのかと💩

フォントサイズを大きくもしてみたのですが、回避出来なかったので、ゲームを配置しているサイトのHTMLに以下のメタタグを仕込むことで強引に回避しました。
これは、スケールアップを強引に止めるためのコードです。

<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">

また、DialogTypeに「Prompt Popup」と「Overlay html」があるのですが、「Overlay html」はスマホでは動きませんでした。

また、WebGLNativeInputで使われているプロンプト画面は、端末ネイティブのものを呼び出しているので、プロンプト自体をカスタムする(キャンセルボタンを消すなど)ことは出来ませんでした。

Unity2023以降:ビルドすると、ブラウザでエラーが出る


ビルド時にブラウザで以下のエラーが出ました。

An error occurred running the Unity content on this page. See your browser JavaScript console for more info. The error was:
ReferenceError: writeStringToMemory is not defined

正直なことを書くと、ChatGPT君に聞いた答えを丸パクリしたら直りました。javascirptは詳しくないので...。
Unity2023から古いAPIが削除されたようで、WebGL Native InputFieldはそれを使っていたのが原因とのこと。

以下のパスにあるJavaScriptファイルを、以下のコードで書き換えたら直りました。

WebGLNativeInputField > Plugins > WebGL >WebNativeDialog(パズルピースみたいなアイコン)

具体的には元のコードにある、writeStringToMemoryと、writeStringToMemoryがNGみたいです。

var WebNativeDialog = {
  NativeDialogPrompt: function (title, defaultValue) {
    defaultValue = UTF8ToString(defaultValue);
    title = UTF8ToString(title);
    var result = window.prompt(title, defaultValue);
    if (!result) {
      result = defaultValue;
    }
    var buffer = _malloc(lengthBytesUTF8(result) + 1);
    stringToUTF8(result, buffer, lengthBytesUTF8(result) + 1);
    return buffer;
  },
  SetupOverlayDialogHtml: function (title, defaultValue, okBtnText, cancelBtnText) {
    title = UTF8ToString(title);
    defaultValue = UTF8ToString(defaultValue);
    okBtnText = UTF8ToString(okBtnText);
    cancelBtnText = UTF8ToString(cancelBtnText);

    if (!document.getElementById("nativeInputDialogInput")) {
      // setup css
      var style = document.createElement('style');
      style.setAttribute('id', 'inputDialogTextSelect');
      style.appendChild(document.createTextNode('#nativeInputDialogInput::-moz-selection { background-color:#00ffff;}'));
      style.appendChild(document.createTextNode('#nativeInputDialogInput::selection { background-color:#00ffff;}'));
      document.head.appendChild(style);
    }
    if (!document.getElementById("nativeInputDialog")) {
      // setup html
      var html = '<div id="nativeInputDialog" style="background:#000000;opacity:0.9;width:100%;height:100%;position:fixed;top:0%;z-index:2147483647;">' +
        '  <div style="position:relative;top:30%;" align="center" vertical-align="middle">' +
        '    <div id="nativeInputDialogTitle" style="color:#ffffff;">Here is title</div>' +
        '    <div>' +
        '      <input id="nativeInputDialogInput" type="text" size="40">' +
        '    </div>' +
        '    <div style="margin-top:10px">' +
        '      <input id="nativeInputDialogOkBtn" type="button" value="OK" onclick="">' +
        '      <input id="nativeInputDialogCancelBtn" type="button" value="Cancel" onclick ="">' +
        '      <input id="nativeInputDialogCheck" type="checkBox" style="display:none;">' +
        '    </div>' +
        '  </div>' +
        '</div>';
      var element = document.createElement('div');
      element.innerHTML = html;
      // write to html
      document.body.appendChild(element);

      // set Event
      var okFunction =
        'document.getElementById("nativeInputDialog").style.display = "none";' +
        'document.getElementById("nativeInputDialogCheck").checked = false;' +
        'document.getElementById("canvas").style.display="";';
      var cancelFunction =
        'document.getElementById("nativeInputDialog").style.display = "none";' +
        'document.getElementById("nativeInputDialogCheck").checked = true;' +
        'document.getElementById("canvas").style.display="";';

      var okBtn = document.getElementById("nativeInputDialogOkBtn");
      okBtn.setAttribute("onclick", okFunction);
      var cancelBtn = document.getElementById("nativeInputDialogCancelBtn");
      cancelBtn.setAttribute("onclick", cancelFunction);
    }
    document.getElementById("nativeInputDialogTitle").innerText = title;
    document.getElementById("nativeInputDialogInput").value = defaultValue;

    document.getElementById("nativeInputDialogOkBtn").value = okBtnText;
    document.getElementById("nativeInputDialogCancelBtn").value = cancelBtnText;
    document.getElementById("nativeInputDialog").style.display = "";
  },
  HideUnityScreenIfHtmlOverlayCant: function () {
    if (navigator.userAgent.indexOf("Chrome/") < 0) {
      document.getElementById("canvas").style.display = "none";
    }
  },
  IsRunningOnEdgeBrowser: function () {
    return navigator.userAgent.indexOf("Edge/") >= 0;
  },
  IsOverlayDialogHtmlActive: function () {
    var nativeDialog = document.getElementById("nativeInputDialog");
    return nativeDialog && nativeDialog.style.display != 'none';
  },
  IsOverlayDialogHtmlCanceled: function () {
    var check = document.getElementById("nativeInputDialogCheck");
    return check && check.checked;
  },
  GetOverlayHtmlInputFieldValue: function () {
    var inputField = document.getElementById("nativeInputDialogInput");
    var result = inputField && inputField.value ? inputField.value : "";
    var buffer = _malloc(lengthBytesUTF8(result) + 1);
    stringToUTF8(result, buffer, lengthBytesUTF8(result) + 1);
    return buffer;
  }
};
mergeInto(LibraryManager.library, WebNativeDialog);

WebGL Input

こちらの配布されているプラグインでも、日本語入力が出来ます。

GitHub
GitHub - kou-yeung/WebGLInput: IME for Unity WebGL IME for Unity WebGL. Contribute to kou-yeung/WebGLInput development by creating an account on GitHub.

ただ、モバイルで実行すると、入力パネルが消えなくなったり、入力した文字が大きくなったりと思わぬ挙動が発生しました。
ただ、PCブラウザで動かす分には問題なかったです。

まとめ

WebGLのInput Field問題は、Unity6で解決するのかと思っていましたが(正式にWebGLのモバイルにも対応したので)、逆に手間が増えてしまいました。ぜひとも、これは公式対応してほしいところです。

それでは、素敵なゲーム制作ライフを!

この記事が気に入ったら
フォローしてね!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

ゲーム制作の敷居を下げ、もっと多くの人にゲーム作りを楽しんでもらうために、ゲームをカンタンに作る方法を”網羅的に”解説しています。
よかったらブックマークお願いします。
Twitter(X)もよければフォローお願いします。

コメント

コメントする

目次