| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480 | #if UNITY_2018_2_OR_NEWER#define TMP_WEBGL_SUPPORT#endifusing System.Collections.Generic;using UnityEngine;using UnityEngine.UI;using System;using AOT;using System.Runtime.InteropServices; // for DllImportusing 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();            }        }    }}
 |