Unity WebGL 实现中文IME输入

参考项目:https://github.com/unity3d-jp/WebGLNativeInputField (项目实现了采用 html native input 可以激活中文输入法)

提醒:UI控件不能显示中文是中文字体的原因(把中文字体包含进去,可以去下载这个字体DroidSansFallback,体较小),能使用中文输入法和显示中文字体是不同的问题。

需求实现:

我使用的UI插件是NGUI,点击UIInput或者UILabel时,将会调用native html input,并且我会传递 x y w h 4个参数给html (jslib),然后html根据坐标和宽高创建input并且覆盖在我的游戏UI,功能实现简单,xywh正确计算即可。

下方例子控件是NGUI的UILabel,添加点击事件,调用Native Input,用户输入完毕后,更新UIlabel。

------------------------------------------ 分割线 --------------------------------------------

核心代码是这两个文件,我希望能先看github的项目,再看我修改的代码,这样会比较清楚。

  • WebNativeDialog.jslib  //Native 文件
var WebNativeDialog = {
  SetupOverlayDialogHtml:function(defaultValue,x,y,w,h){
      try {
          defaultValue = Pointer_stringify(defaultValue);
      } catch (e) {
      }

      if(!document.getElementById("nativeInputDialog")) {
          // setup html
          var html = '<div id="nativeInputDialog" style="background:transparent; width:100%; height:100%; margin: 0; padding: 0; position: absolute; left: 0; top:0; z-index:888;">' +
              '<input id="nativeInputDialogInput" type="text" style="border: none; background: none; color: white; outline: none; display: block; position: relative; font-size: 20px; ">' +
              '</div>';
          $(document.body).append(html);
          $('#nativeInputDialogInput').keypress(function (event) {
              if (event.keyCode == 13) {
                  $('#nativeInputDialog').hide();
              }
          });
          $('#nativeInputDialogInput').click(function () {
              return false;
          });

          $('#nativeInputDialog').click(function () {
              $('#nativeInputDialog').hide();
          });
      }

      $('#nativeInputDialogInput').val(defaultValue);
      $('#nativeInputDialogInput').css({left: x + 'px', top: y + 'px', width: w, height: h});

      $('#nativeInputDialog').show();
      $('#nativeInputDialogInput').focus();
  },
  HideUnityScreenIfHtmlOverlayCant:function(){
    if( navigator.userAgent.indexOf("Chrome/") < 0 ){
      document.getElementById("canvas").style.display="none";
    }
  },
  IsRunningOnEdgeBrowser:function(){
    if( navigator.userAgent.indexOf("Edge/") < 0 ){
      return false;
    }
    return true;
  },
  IsOverlayDialogHtmlActive:function(){
      return $('#nativeInputDialog').is(':visible');
  },
  IsOverlayDialogHtmlCanceled:function(){
      return ($('#nativeInputDialog').is(':visible'));
  },
  GetOverlayHtmlInputFieldValue:function(){
    var returnStr = $('#nativeInputDialogInput').val();
    var bufferSize = lengthBytesUTF8(returnStr) + 1;
    var buffer = _malloc(bufferSize);
    stringToUTF8(returnStr, buffer, bufferSize);
    return buffer;
  }

};
mergeInto( LibraryManager.library , WebNativeDialog );
  • WebGLNativeInputField.cs
public class WebGLNativeInputField : MonoBehaviour {

	UILabel mInput;
	// Use this for initialization
	void Start () {
		mInput = GetComponentInChildren<UILabel>();
	}

	public void OnClickInput (){
		var inputbounds = CalculateWidgetScreenBounds (gameObject.GetComponentInChildren<UILabel> ().gameObject.transform);
		WebNativeDialog.SetUpOverlayDialog (mInput.text,(int)inputbounds.min.x, (int)inputbounds.min.y, (int)inputbounds.size.x, (int)inputbounds.size.y);
		mInput.text = "";
		StartCoroutine(this.OverlayHtmlCoroutine());
	}

	private IEnumerator OverlayHtmlCoroutine(){
		yield return new WaitForEndOfFrame();
		#if UNITY_WEBGL && !UNITY_EDITOR
		WebGLInput.captureAllKeyboardInput = false;
		while (WebNativeDialog.IsOverlayDialogActive())
		{
			yield return null;
		}
		WebGLInput.captureAllKeyboardInput = true;

		if (!WebNativeDialog.IsOverlayDialogCanceled())
		{
			mInput.text = WebNativeDialog.GetOverlayDialogValue();
		}
		#endif
	}

	static public Bounds CalculateWidgetScreenBounds (Transform child){
		UIWidget[] widgets = child.GetComponentsInChildren<UIWidget>(true) as UIWidget[];
		Bounds b = new Bounds(Vector3.zero, Vector3.zero);
		bool first = true;

		for (int i = 0, imax = widgets.Length; i < imax; ++i)
		{
			UIWidget w = widgets[i];
			Vector2 size = w.localSize;
			Vector2 offset = w.pivotOffset;
			Transform toWorld = w.cachedTransform;

			float x = (offset.x + 0.5f) * size.x;
			float y = (offset.y - 0.5f) * size.y;
			size *= 0.5f;

			// Start with the corner of the widget
			Vector3 v = new Vector3(x - size.x, y - size.y, 0f);

			// Transform the coordinate from relative-to-widget to world space
			v = toWorld.TransformPoint(v);
			v = UICamera.currentCamera.WorldToScreenPoint(v);
			v.y = Screen.height - v.y;

			if (first)
			{
				first = false;
				b = new Bounds(v, Vector3.zero);
			}
			else
			{
				b.Encapsulate(v);
			}

			// Repeat for the other 3 corners
			v = new Vector3(x - size.x, y + size.y, 0f);
			v = toWorld.TransformPoint(v);
			v = UICamera.currentCamera.WorldToScreenPoint(v);
			v.y = Screen.height - v.y;
			b.Encapsulate(v);

			v = new Vector3(x + size.x, y - size.y, 0f);
			v = toWorld.TransformPoint(v);
			v = UICamera.currentCamera.WorldToScreenPoint(v);
			v.y = Screen.height - v.y;
			b.Encapsulate(v);

			v = new Vector3(x + size.x, y + size.y, 0f);
			v = toWorld.TransformPoint(v);
			v = UICamera.currentCamera.WorldToScreenPoint(v);
			v.y = Screen.height - v.y;
			b.Encapsulate(v);
		}
		return b;
	} 
}

警告:2018-06-14:

现在遇到一个问题,WebGL 在全屏下,这个不能使用(无法显示出这个 native input),怀疑可能和全屏一些深度显示有关,没有解决这个问题。 临时方案是全屏下不开启native input,如果有解决这个问题的,希望可以告诉我。

猜你喜欢

转载自blog.csdn.net/lile1234_show/article/details/79173141