1#if UNITY_2018_2_OR_NEWER
2#define TMP_WEBGL_SUPPORT
5using System.Collections.Generic;
10using System.Runtime.InteropServices;
11using System.Collections;
15 internal class WebGLInputPlugin
17#if UNITY_WEBGL && !UNITY_EDITOR
18 [DllImport(
"__Internal")]
19 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);
21 [DllImport(
"__Internal")]
22 public static extern void WebGLInputEnterSubmit(
int id,
bool flag);
24 [DllImport(
"__Internal")]
25 public static extern void WebGLInputTab(
int id, Action<int, int> cb);
27 [DllImport(
"__Internal")]
28 public static extern void WebGLInputFocus(
int id);
30 [DllImport(
"__Internal")]
31 public static extern void WebGLInputOnFocus(
int id, Action<int> cb);
33 [DllImport(
"__Internal")]
34 public static extern void WebGLInputOnBlur(
int id, Action<int> cb);
36 [DllImport(
"__Internal")]
37 public static extern void WebGLInputOnValueChange(
int id, Action<int, string> cb);
39 [DllImport(
"__Internal")]
40 public static extern void WebGLInputOnEditEnd(
int id, Action<int, string> cb);
42 [DllImport(
"__Internal")]
43 public static extern int WebGLInputSelectionStart(
int id);
45 [DllImport(
"__Internal")]
46 public static extern int WebGLInputSelectionEnd(
int id);
48 [DllImport(
"__Internal")]
49 public static extern int WebGLInputSelectionDirection(
int id);
51 [DllImport(
"__Internal")]
52 public static extern void WebGLInputSetSelectionRange(
int id,
int start,
int end);
54 [DllImport(
"__Internal")]
55 public static extern void WebGLInputMaxLength(
int id,
int maxlength);
57 [DllImport(
"__Internal")]
58 public static extern void WebGLInputText(
int id,
string text);
60 [DllImport(
"__Internal")]
61 public static extern bool WebGLInputIsFocus(
int id);
63 [DllImport(
"__Internal")]
64 public static extern void WebGLInputDelete(
int id);
67 [DllImport(
"__Internal")]
68 public static extern void WebGLInputEnableTabText(
int id,
bool enable);
72 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) {
return 0; }
73 public static void WebGLInputEnterSubmit(
int id,
bool flag) { }
74 public static void WebGLInputTab(
int id, Action<int, int> cb) { }
75 public static void WebGLInputFocus(
int id) { }
76 public static void WebGLInputOnFocus(
int id, Action<int> cb) { }
77 public static void WebGLInputOnBlur(
int id, Action<int> cb) { }
78 public static void WebGLInputOnValueChange(
int id, Action<int, string> cb) { }
79 public static void WebGLInputOnEditEnd(
int id, Action<int, string> cb) { }
80 public static int WebGLInputSelectionStart(
int id) {
return 0; }
81 public static int WebGLInputSelectionEnd(
int id) {
return 0; }
82 public static int WebGLInputSelectionDirection(
int id) {
return 0; }
83 public static void WebGLInputSetSelectionRange(
int id,
int start,
int end) { }
84 public static void WebGLInputMaxLength(
int id,
int maxlength) { }
85 public static void WebGLInputText(
int id,
string text) { }
86 public static bool WebGLInputIsFocus(
int id) {
return false; }
87 public static void WebGLInputDelete(
int id) { }
90 public static void WebGLInputEnableTabText(
int id,
bool enable) { }
96 public class WebGLInput : MonoBehaviour, IComparable<WebGLInput>
98 static Dictionary<int, WebGLInput> instances =
new Dictionary<int, WebGLInput>();
102 public bool enableTabText =
false;
107#if UNITY_2020_1_OR_NEWER
109#elif UNITY_2019_1_OR_NEWER
116 internal int id = -1;
118 bool blurBlock =
false;
120 [TooltipAttribute(
"show input element on canvas. this will make you select text by drag.")]
125 if (GetComponent<InputField>())
return new WrappedInputField(GetComponent<InputField>());
127 if (GetComponent<TMPro.TMP_InputField>())
return new WrappedTMPInputField(GetComponent<TMPro.TMP_InputField>());
129 throw new Exception(
"Can not Setup WebGLInput!!");
135#if !(UNITY_WEBGL && !UNITY_EDITOR)
140 if (Application.isMobilePlatform)
152 var rect = GetScreenCoordinates(input.RectTransform());
153 bool isPassword = input.contentType ==
ContentType.Password;
155 var fontSize = Mathf.Max(14, input.fontSize);
160 var x = (int)(rect.x);
161 var y = (int)(Screen.height - (rect.y + rect.height));
162 id = WebGLInputPlugin.WebGLInputCreate(
WebGLInput.
CanvasId, x, y, (
int)rect.width, (int)rect.height, fontSize, input.text, input.placeholder, input.lineType !=
LineType.SingleLine, isPassword,
false);
166 var x = (int)(rect.x);
167 var y = (int)(Screen.height - (rect.y));
168 id = WebGLInputPlugin.WebGLInputCreate(
WebGLInput.
CanvasId, x, y, (
int)rect.width, (int)1, fontSize, input.text, input.placeholder, input.lineType !=
LineType.SingleLine, isPassword,
true);
171 instances[id] =
this;
172 WebGLInputPlugin.WebGLInputEnterSubmit(
id, input.lineType !=
LineType.MultiLineNewline);
173 WebGLInputPlugin.WebGLInputOnFocus(
id, OnFocus);
174 WebGLInputPlugin.WebGLInputOnBlur(
id, OnBlur);
175 WebGLInputPlugin.WebGLInputOnValueChange(
id, OnValueChange);
176 WebGLInputPlugin.WebGLInputOnEditEnd(
id, OnEditEnd);
177 WebGLInputPlugin.WebGLInputTab(
id, OnTab);
179 WebGLInputPlugin.WebGLInputMaxLength(
id, (input.characterLimit > 0) ? input.characterLimit : 524288);
180 WebGLInputPlugin.WebGLInputFocus(
id);
182 WebGLInputPlugin.WebGLInputEnableTabText(
id, enableTabText);
184 if (input.OnFocusSelectAll)
186 WebGLInputPlugin.WebGLInputSetSelectionRange(
id, 0, input.text.Length);
189 WebGLWindow.OnBlurEvent += OnWindowBlur;
202 Rect GetScreenCoordinates(RectTransform uiElement)
204 var worldCorners =
new Vector3[4];
205 uiElement.GetWorldCorners(worldCorners);
208 var canvas = uiElement.GetComponentInParent<Canvas>();
209 var useCamera = (canvas.renderMode != RenderMode.ScreenSpaceOverlay);
210 if (canvas && useCamera)
212 var camera = canvas.worldCamera;
213 if (!camera) camera = Camera.main;
215 for (var i = 0; i < worldCorners.Length; i++)
217 worldCorners[i] = camera.WorldToScreenPoint(worldCorners[i]);
221 var min =
new Vector3(
float.MaxValue,
float.MaxValue);
222 var max =
new Vector3(
float.MinValue,
float.MinValue);
223 for (var i = 0; i < worldCorners.Length; i++)
225 min.x = Mathf.Min(min.x, worldCorners[i].x);
226 min.y = Mathf.Min(min.y, worldCorners[i].y);
227 max.x = Mathf.Max(max.x, worldCorners[i].x);
228 max.y = Mathf.Max(max.y, worldCorners[i].y);
231 return new Rect(min.x, min.y, max.x - min.x, max.y - min.y);
234 internal void DeactivateInputField()
236 if (!instances.ContainsKey(
id))
return;
238 WebGLInputPlugin.WebGLInputDelete(
id);
239 input.DeactivateInputField();
240 instances.Remove(
id);
242 WebGLWindow.OnBlurEvent -= OnWindowBlur;
245 [MonoPInvokeCallback(typeof(Action<int>))]
246 static void OnFocus(
int id)
248#if UNITY_WEBGL && !UNITY_EDITOR
249 Input.ResetInputAxes();
250 UnityEngine.WebGLInput.captureAllKeyboardInput =
false;
254 [MonoPInvokeCallback(typeof(Action<int>))]
255 static void OnBlur(
int id)
257#if UNITY_WEBGL && !UNITY_EDITOR
258 UnityEngine.WebGLInput.captureAllKeyboardInput =
true;
259 Input.ResetInputAxes();
261 instances[id].StartCoroutine(Blur(
id));
264 static IEnumerator Blur(
int id)
267 if (!instances.ContainsKey(
id)) yield
break;
269 var block = instances[id].blurBlock;
270 instances[id].blurBlock =
false;
271 if (block) yield
break;
273 instances[id].DeactivateInputField();
276 [MonoPInvokeCallback(typeof(Action<int, string>))]
277 static void OnValueChange(
int id,
string value)
279 if (!instances.ContainsKey(
id))
return;
281 var instance = instances[id];
282 if (!instance.input.ReadOnly)
284 instance.input.text = value;
288 if (instance.input.contentType ==
ContentType.Name)
290 if (
string.Compare(instance.input.text, value,
true) == 0)
292 value = instance.input.text;
297 if (value != instance.input.text)
299 var start = WebGLInputPlugin.WebGLInputSelectionStart(
id);
300 var end = WebGLInputPlugin.WebGLInputSelectionEnd(
id);
302 var offset = instance.input.text.Length - value.Length;
304 WebGLInputPlugin.WebGLInputText(
id, instance.input.text);
306 WebGLInputPlugin.WebGLInputSetSelectionRange(
id, start + offset, end + offset);
309 [MonoPInvokeCallback(typeof(Action<int, string>))]
310 static void OnEditEnd(
int id,
string value)
312 if (!instances[
id].input.ReadOnly)
314 instances[id].input.text = value;
317 [MonoPInvokeCallback(typeof(Action<int, int>))]
318 static void OnTab(
int id,
int value)
320 WebGLInputTabFocus.OnTab(instances[
id], value);
325 if (input ==
null || !input.isFocused)
return;
327 if (!instances.ContainsKey(
id))
329 if (Application.isMobilePlatform)
return;
333 else if (!WebGLInputPlugin.WebGLInputIsFocus(
id))
336 WebGLInputPlugin.WebGLInputFocus(
id);
339 var start = WebGLInputPlugin.WebGLInputSelectionStart(
id);
340 var end = WebGLInputPlugin.WebGLInputSelectionEnd(
id);
342 if (WebGLInputPlugin.WebGLInputSelectionDirection(
id) == -1)
344 input.selectionFocusPosition = start;
345 input.selectionAnchorPosition = end;
349 input.selectionFocusPosition = end;
350 input.selectionAnchorPosition = start;
356 private void OnDestroy()
358 if (!instances.ContainsKey(
id))
return;
360#if UNITY_WEBGL && !UNITY_EDITOR
361 UnityEngine.WebGLInput.captureAllKeyboardInput =
true;
362 Input.ResetInputAxes();
364 instances[id].DeactivateInputField();
367 private void OnEnable()
369 WebGLInputTabFocus.Add(
this);
371 private void OnDisable()
373 WebGLInputTabFocus.Remove(
this);
377 var a = GetScreenCoordinates(input.RectTransform());
379 var res = b.y.CompareTo(a.y);
380 if (res == 0) res = a.x.CompareTo(b.x);
388 static class WebGLInputTabFocus
390 static List<WebGLInput> inputs =
new List<WebGLInput>();
398 public static void Remove(WebGLInput input)
400 inputs.Remove(input);
403 public static void OnTab(WebGLInput input,
int value)
405 if (inputs.Count <= 1)
return;
406 var index = inputs.IndexOf(input);
408 if (index < 0) index = inputs.Count - 1;
409 else if (index >= inputs.Count) index = 0;
410 inputs[index].input.ActivateInputField();