123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480 |
- #if UNITY_2018_2_OR_NEWER
- #define TMP_WEBGL_SUPPORT
- #endif
- using System.Collections.Generic;
- using UnityEngine;
- using UnityEngine.UI;
- using System;
- using AOT;
- using System.Runtime.InteropServices; // for DllImport
- using System.Collections;
- using UnityEngine.EventSystems;
- namespace WebGLSupport
- {
- internal class WebGLInputPlugin
- {
- #if UNITY_WEBGL && !UNITY_EDITOR
- [DllImport("__Internal")]
- public static extern void WebGLInputInit();
- [DllImport("__Internal")]
- public static extern int WebGLInputCreate(string canvasId, int x, int y, int width, int height, int fontsize, string text, string placeholder, bool isMultiLine, bool isPassword, bool isHidden, bool isMobile);
- [DllImport("__Internal")]
- public static extern void WebGLInputEnterSubmit(int id, bool flag);
- [DllImport("__Internal")]
- public static extern void WebGLInputTab(int id, Action<int, int> cb);
- [DllImport("__Internal")]
- public static extern void WebGLInputFocus(int id);
- [DllImport("__Internal")]
- public static extern void WebGLInputOnFocus(int id, Action<int> cb);
- [DllImport("__Internal")]
- public static extern void WebGLInputOnBlur(int id, Action<int> cb);
- [DllImport("__Internal")]
- public static extern void WebGLInputOnValueChange(int id, Action<int, string> cb);
-
- [DllImport("__Internal")]
- public static extern void WebGLInputOnEditEnd(int id, Action<int, string> cb);
- [DllImport("__Internal")]
- public static extern void WebGLInputOnKeyboardEvent(int id, Action<int, int, string, int, int, int, int> cb);
- [DllImport("__Internal")]
- public static extern int WebGLInputSelectionStart(int id);
- [DllImport("__Internal")]
- public static extern int WebGLInputSelectionEnd(int id);
- [DllImport("__Internal")]
- public static extern int WebGLInputSelectionDirection(int id);
- [DllImport("__Internal")]
- public static extern void WebGLInputSetSelectionRange(int id, int start, int end);
- [DllImport("__Internal")]
- public static extern void WebGLInputMaxLength(int id, int maxlength);
- [DllImport("__Internal")]
- public static extern void WebGLInputText(int id, string text);
- [DllImport("__Internal")]
- public static extern bool WebGLInputIsFocus(int id);
- [DllImport("__Internal")]
- public static extern void WebGLInputDelete(int id);
- [DllImport("__Internal")]
- public static extern void WebGLInputForceBlur(int id);
- #if WEBGLINPUT_TAB
- [DllImport("__Internal")]
- public static extern void WebGLInputEnableTabText(int id, bool enable);
- #endif
- #else
- public static void WebGLInputInit() { }
- public static int WebGLInputCreate(string canvasId, int x, int y, int width, int height, int fontsize, string text, string placeholder, bool isMultiLine, bool isPassword, bool isHidden, bool isMobile) { return 0; }
- public static void WebGLInputEnterSubmit(int id, bool flag) { }
- public static void WebGLInputTab(int id, Action<int, int> cb) { }
- public static void WebGLInputFocus(int id) { }
- public static void WebGLInputOnFocus(int id, Action<int> cb) { }
- public static void WebGLInputOnBlur(int id, Action<int> cb) { }
- public static void WebGLInputOnValueChange(int id, Action<int, string> cb) { }
- public static void WebGLInputOnEditEnd(int id, Action<int, string> cb) { }
- public static void WebGLInputOnKeyboardEvent(int id, Action<int, int, string, int, int, int, int> cb) { }
- public static int WebGLInputSelectionStart(int id) { return 0; }
- public static int WebGLInputSelectionEnd(int id) { return 0; }
- public static int WebGLInputSelectionDirection(int id) { return 0; }
- public static void WebGLInputSetSelectionRange(int id, int start, int end) { }
- public static void WebGLInputMaxLength(int id, int maxlength) { }
- public static void WebGLInputText(int id, string text) { }
- public static bool WebGLInputIsFocus(int id) { return false; }
- public static void WebGLInputDelete(int id) { }
- public static void WebGLInputForceBlur(int id) { }
- #if WEBGLINPUT_TAB
- public static void WebGLInputEnableTabText(int id, bool enable) { }
- #endif
- #endif
- }
- public class WebGLInput : MonoBehaviour, IComparable<WebGLInput>
- {
- public static event KeyboardEventHandler OnKeyboardDown;
- public static event KeyboardEventHandler OnKeyboardUp;
- static Dictionary<int, WebGLInput> instances = new Dictionary<int, WebGLInput>();
- public static string CanvasId { get; set; }
- #if WEBGLINPUT_TAB
- public bool enableTabText = false;
- #endif
- static WebGLInput()
- {
- CanvasId = WebGLWindow.GetCanvasName();
- WebGLInputPlugin.WebGLInputInit();
- }
- public int Id { get { return id; } }
- internal int id = -1;
- public IInputField input { get; private set; }
- bool blurBlock = false;
- [TooltipAttribute("show input element on canvas. this will make you select text by drag.")]
- public bool showHtmlElement = false;
- private IInputField Setup()
- {
- if (GetComponent<InputField>()) return new WrappedInputField(GetComponent<InputField>());
- if (GetComponent<WebGLUIToolkitTextField>()) return new WrappedUIToolkit(GetComponent<WebGLUIToolkitTextField>());
- #if TMP_WEBGL_SUPPORT
- if (GetComponent<TMPro.TMP_InputField>()) return new WrappedTMPInputField(GetComponent<TMPro.TMP_InputField>());
- #endif // TMP_WEBGL_SUPPORT
- throw new Exception("Can not Setup WebGLInput!!");
- }
- private void Awake()
- {
- input = Setup();
- #if !(UNITY_WEBGL && !UNITY_EDITOR)
- // WebGL 以外、更新メソッドは動作しないようにします
- enabled = false;
- #endif
- // for mobile platform
- if (Application.isMobilePlatform)
- {
- if (input.EnableMobileSupport)
- {
- gameObject.AddComponent<WebGLInputMobile>();
- }
- else
- {
- // when disable mobile input. disable self!
- enabled = false;
- }
- }
- }
- /// <summary>
- /// Get the element rect of input
- /// </summary>
- /// <returns></returns>
- RectInt GetElemetRect()
- {
- var rect = input.GetScreenCoordinates();
- // モバイルの場合、強制表示する
- if (showHtmlElement || Application.isMobilePlatform)
- {
- var x = (int)(rect.x);
- var y = (int)(Screen.height - (rect.y + rect.height));
- return new RectInt(x, y, (int)rect.width, (int)rect.height);
- }
- else
- {
- var x = (int)(rect.x);
- var y = (int)(Screen.height - (rect.y));
- return new RectInt(x, y, (int)rect.width, (int)1);
- }
- }
- /// <summary>
- /// 対象が選択されたとき
- /// </summary>
- /// <param name="eventData"></param>
- public void OnSelect()
- {
- if (id != -1) throw new Exception("OnSelect : id != -1");
- var rect = GetElemetRect();
- bool isPassword = input.contentType == ContentType.Password;
- var fontSize = Mathf.Max(14, input.fontSize); // limit font size : 14 !!
- // モバイルの場合、強制表示する
- var isHidden = !(showHtmlElement || Application.isMobilePlatform);
- id = WebGLInputPlugin.WebGLInputCreate(WebGLInput.CanvasId, rect.x, rect.y, rect.width, rect.height, fontSize, input.text, input.placeholder, input.lineType != LineType.SingleLine, isPassword, isHidden, Application.isMobilePlatform);
- instances[id] = this;
- WebGLInputPlugin.WebGLInputEnterSubmit(id, input.lineType != LineType.MultiLineNewline);
- WebGLInputPlugin.WebGLInputOnFocus(id, OnFocus);
- WebGLInputPlugin.WebGLInputOnBlur(id, OnBlur);
- WebGLInputPlugin.WebGLInputOnValueChange(id, OnValueChange);
- WebGLInputPlugin.WebGLInputOnEditEnd(id, OnEditEnd);
- WebGLInputPlugin.WebGLInputOnKeyboardEvent(id, OnKeyboardEvent);
- WebGLInputPlugin.WebGLInputTab(id, OnTab);
- // default value : https://www.w3schools.com/tags/att_input_maxlength.asp
- WebGLInputPlugin.WebGLInputMaxLength(id, (input.characterLimit > 0) ? input.characterLimit : 524288);
- WebGLInputPlugin.WebGLInputFocus(id);
- #if WEBGLINPUT_TAB
- WebGLInputPlugin.WebGLInputEnableTabText(id, enableTabText);
- #endif
- if (input.OnFocusSelectAll)
- {
- WebGLInputPlugin.WebGLInputSetSelectionRange(id, 0, input.text.Length);
- }
- else
- {
- WebGLInputPlugin.WebGLInputSetSelectionRange(id, input.caretPosition, input.caretPosition);
- }
- WebGLWindow.OnBlurEvent += OnWindowBlur;
- }
- /// <summary>
- /// sync text from inputfield
- /// </summary>
- /// <param name="cursorIndex"></param>
- public void SyncText(int? cursorIndex = null)
- {
- if (!instances.ContainsKey(id)) return;
- var instance = instances[id];
- WebGLInputPlugin.WebGLInputText(id, instance.input.text);
- if (cursorIndex.HasValue)
- {
- WebGLInputPlugin.WebGLInputSetSelectionRange(id, cursorIndex.Value, cursorIndex.Value);
- }
- }
- private void OnWindowBlur()
- {
- blurBlock = true;
- }
- internal void DeactivateInputField()
- {
- if (!instances.ContainsKey(id)) return;
- WebGLInputPlugin.WebGLInputDelete(id);
- input.DeactivateInputField();
- instances.Remove(id);
- id = -1; // reset id to -1;
- WebGLWindow.OnBlurEvent -= OnWindowBlur;
- }
- [MonoPInvokeCallback(typeof(Action<int>))]
- static void OnFocus(int id)
- {
- #if UNITY_WEBGL && !UNITY_EDITOR
- Input.ResetInputAxes(); // Inputの状態リセット
- UnityEngine.WebGLInput.captureAllKeyboardInput = false;
- #endif
- }
- [MonoPInvokeCallback(typeof(Action<int>))]
- static void OnBlur(int id)
- {
- #if UNITY_WEBGL && !UNITY_EDITOR
- UnityEngine.WebGLInput.captureAllKeyboardInput = true;
- Input.ResetInputAxes(); // Inputの状態リセット
- #endif
- instances[id].StartCoroutine(Blur(id));
- }
- static IEnumerator Blur(int id)
- {
- yield return null;
- if (!instances.ContainsKey(id)) yield break;
- var block = instances[id].blurBlock; // get blur block state
- instances[id].blurBlock = false; // reset instalce block state
- if (block) yield break; // if block. break it!!
- instances[id].DeactivateInputField();
- }
- [MonoPInvokeCallback(typeof(Action<int, string>))]
- static void OnValueChange(int id, string value)
- {
- if (!instances.ContainsKey(id)) return;
- var instance = instances[id];
- if (!instance.input.ReadOnly)
- {
- instance.input.text = value;
- }
- // InputField.ContentType.Name が Name の場合、先頭文字が強制的大文字になるため小文字にして比べる
- if (instance.input.contentType == ContentType.Name)
- {
- if (string.Compare(instance.input.text, value, true) == 0)
- {
- value = instance.input.text;
- }
- }
- // InputField の ContentType による整形したテキストを HTML の input に再設定します
- if (value != instance.input.text)
- {
- var start = WebGLInputPlugin.WebGLInputSelectionStart(id);
- var end = WebGLInputPlugin.WebGLInputSelectionEnd(id);
- // take the offset.when char remove from input.
- var offset = instance.input.text.Length - value.Length;
- WebGLInputPlugin.WebGLInputText(id, instance.input.text);
- // reset the input element selection range!!
- WebGLInputPlugin.WebGLInputSetSelectionRange(id, start + offset, end + offset);
- }
- }
- [MonoPInvokeCallback(typeof(Action<int, string>))]
- static void OnEditEnd(int id, string value)
- {
- if (!instances[id].input.ReadOnly)
- {
- instances[id].input.text = value;
- }
- }
- [MonoPInvokeCallback(typeof(Action<int, int>))]
- static void OnTab(int id, int value)
- {
- WebGLInputTabFocus.OnTab(instances[id], value);
- }
- [MonoPInvokeCallback(typeof(Action<int, int, string, int, int, int, int>))]
- static void OnKeyboardEvent(int id, int mode, string key, int code, int shiftKey, int ctrlKey, int altKey)
- {
- if (!instances.ContainsKey(id)) return;
- var instance = instances[id];
- // mode : keydown(1) keyup(3)
- var cb = mode switch
- {
- 1 => OnKeyboardDown,
- 2 => OnKeyboardUp,
- _ => default
- };
- if (cb != null)
- {
- cb(instance, new KeyboardEvent(key, code, shiftKey != 0, ctrlKey != 0, altKey != 0));
- }
- }
- void Update()
- {
- if (input == null || !input.isFocused)
- {
- CheckOutFocus();
- return;
- }
- // 未登録の場合、選択する
- if (!instances.ContainsKey(id))
- {
- if (Application.isMobilePlatform)
- {
- return;
- }
- else
- {
- OnSelect();
- }
- }
- else if (!WebGLInputPlugin.WebGLInputIsFocus(id))
- {
- if (Application.isMobilePlatform)
- {
- //input.DeactivateInputField();
- return;
- }
- else
- {
- // focus this id
- WebGLInputPlugin.WebGLInputFocus(id);
- }
- }
- var start = WebGLInputPlugin.WebGLInputSelectionStart(id);
- var end = WebGLInputPlugin.WebGLInputSelectionEnd(id);
- // 選択方向によって設定します
- if (WebGLInputPlugin.WebGLInputSelectionDirection(id) == -1)
- {
- input.selectionFocusPosition = start;
- input.selectionAnchorPosition = end;
- }
- else
- {
- input.selectionFocusPosition = end;
- input.selectionAnchorPosition = start;
- }
- input.Rebuild();
- }
- private void OnDestroy()
- {
- if (!instances.ContainsKey(id)) return;
- #if UNITY_WEBGL && !UNITY_EDITOR
- UnityEngine.WebGLInput.captureAllKeyboardInput = true;
- Input.ResetInputAxes(); // Inputの状態リセット
- #endif
- DeactivateInputField();
- }
- private void OnEnable()
- {
- WebGLInputTabFocus.Add(this);
- }
- private void OnDisable()
- {
- WebGLInputTabFocus.Remove(this);
- }
- public int CompareTo(WebGLInput other)
- {
- var a = input.GetScreenCoordinates();
- var b = other.input.GetScreenCoordinates();
- var res = b.y.CompareTo(a.y);
- if (res == 0) res = a.x.CompareTo(b.x);
- return res;
- }
- private void CheckOutFocus()
- {
- if (!Application.isMobilePlatform) return;
- if (!instances.ContainsKey(id)) return;
- var current = EventSystem.current.currentSelectedGameObject;
- if (current != null) return;
- WebGLInputPlugin.WebGLInputForceBlur(id); // Input ではないし、キーボードを閉じる
- }
- /// <summary>
- /// to manage tab focus
- /// base on scene position
- /// </summary>
- static class WebGLInputTabFocus
- {
- static List<WebGLInput> inputs = new List<WebGLInput>();
- public static void Add(WebGLInput input)
- {
- inputs.Add(input);
- inputs.Sort();
- }
- public static void Remove(WebGLInput input)
- {
- inputs.Remove(input);
- }
- public static void OnTab(WebGLInput input, int value)
- {
- if (inputs.Count <= 1) return;
- var index = inputs.IndexOf(input);
- index += value;
- if (index < 0) index = inputs.Count - 1;
- else if (index >= inputs.Count) index = 0;
- inputs[index].input.ActivateInputField();
- }
- }
- }
- }
|