├── README.md
└── WebGLInputField
├── Plugins.meta
├── Plugins
├── WebGLInputField.jslib
└── WebGLInputField.jslib.meta
├── WebGLInputField.cs
├── WebGLInputField.cs.meta
├── WebGLInputFieldHelper.cs
└── WebGLInputFieldHelper.cs.meta
/README.md:
--------------------------------------------------------------------------------
1 | # UnityWebGLInputfield
2 | 支持在webgl输入中文
3 |
--------------------------------------------------------------------------------
/WebGLInputField/Plugins.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 817d05e37c348394d8c41173525d88e8
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/WebGLInputField/Plugins/WebGLInputField.jslib:
--------------------------------------------------------------------------------
1 | var WebGLInputField = {
2 | //打开输入框
3 | ShowInputFieldDialog:function(defaultValue){
4 |
5 | try {
6 | defaultValue = Pointer_stringify(defaultValue);
7 | } catch (e) {
8 | alert(e);
9 | return;
10 | }
11 |
12 | if(!document.getElementById("nativeInputDialog")) {
13 | var element = document.createElement('div');
14 | // setup html
15 | var html = '
' +
16 | '' +
17 | '
';
18 | element.innerHTML = html;
19 | document.body.appendChild(element);
20 |
21 | var m_nativeInputDialogInput = document.getElementById("nativeInputDialogInput");
22 | m_nativeInputDialogInput.onkeypress = function (event) {
23 | //点击回车键,隐藏输入框
24 | if (event.keyCode == 13) {
25 | document.getElementById("nativeInputDialog").style.display="none";
26 | }
27 | };
28 |
29 | document.onmousemove=function(event){
30 | event = event||window.event;
31 | document.getElementById("nativeInputDialog").style.left = event.clientX + 'px';
32 | document.getElementById("nativeInputDialog").style.top = event.clientY + 20 + 'px';
33 | }
34 | }
35 | var m_nativeInputDialog = document.getElementById("nativeInputDialogInput");
36 | m_nativeInputDialog.value = defaultValue;
37 | document.getElementById("nativeInputDialog").style.display="";
38 | document.getElementById("nativeInputDialogInput").focus();
39 |
40 | },
41 | //隐藏输入框
42 | HideInputFieldDialog :function(){
43 | document.getElementById("nativeInputDialog").style.display="none";
44 | },
45 | IsInputFieldDialogActive:function(){
46 | var nativeDialog = document.getElementById("nativeInputDialog" );
47 | if(!nativeDialog ){
48 | return false;
49 | }
50 | return ( nativeDialog.style.display != 'none' );
51 | },
52 | GetInputFieldValue:function(){
53 | var elem = document.getElementById("nativeInputDialogInput");
54 | var returnStr = elem.value;
55 | var bufferSize = lengthBytesUTF8(returnStr) + 1;
56 | var buffer = _malloc(bufferSize);
57 | stringToUTF8(returnStr, buffer, bufferSize);
58 | return buffer;
59 | },
60 | GetInputFieldCursortPosition:function () {
61 | var dialog = document.getElementById("nativeInputDialogInput");
62 | var index = dialog.selectionStart;
63 | return index;
64 | },
65 | GetInputFieldCursortFocusPosition:function () {
66 | var dialog = document.getElementById("nativeInputDialogInput");
67 | var index = dialog.selectionEnd;
68 | return index;
69 | },
70 | SetInputFieldCursortPosition:function (selectionStart,selectionEnd) {
71 | var elem = document.getElementById("nativeInputDialogInput");
72 | var val = elem.value
73 | var len = val.length
74 |
75 | // 超过文本长度直接返回
76 | if (len < selectionStart || len < selectionEnd) return;
77 |
78 | setTimeout(function() {
79 | elem.focus()
80 | if (elem.setSelectionRange) { // 标准浏览器
81 | elem.setSelectionRange(selectionStart, selectionEnd);
82 | }
83 | }, 10)
84 | }
85 |
86 | };
87 | mergeInto(LibraryManager.library , WebGLInputField );
--------------------------------------------------------------------------------
/WebGLInputField/Plugins/WebGLInputField.jslib.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 71bd5924bbc149849866762a69ebaf9a
3 | PluginImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | iconMap: {}
7 | executionOrder: {}
8 | isPreloaded: 0
9 | isOverridable: 0
10 | platformData:
11 | - first:
12 | Any:
13 | second:
14 | enabled: 0
15 | settings: {}
16 | - first:
17 | Editor: Editor
18 | second:
19 | enabled: 0
20 | settings:
21 | DefaultValueInitialized: true
22 | - first:
23 | Facebook: WebGL
24 | second:
25 | enabled: 1
26 | settings: {}
27 | - first:
28 | WebGL: WebGL
29 | second:
30 | enabled: 1
31 | settings: {}
32 | userData:
33 | assetBundleName:
34 | assetBundleVariant:
35 |
--------------------------------------------------------------------------------
/WebGLInputField/WebGLInputField.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Generic;
3 | using UnityEngine;
4 | using UnityEngine.UI;
5 | using UnityEngine.EventSystems;
6 | using System.Runtime.InteropServices;
7 | using System;
8 |
9 | public class WebGLInputField : InputField
10 | {
11 | #if UNITY_WEBGL && !UNITY_EDITOR
12 | [DllImport("__Internal")]//显示对话框
13 | private static extern void ShowInputFieldDialog(string text);
14 | [DllImport("__Internal")]//隐藏对话框
15 | private static extern void HideInputFieldDialog();
16 | [DllImport("__Internal")]//对话框是否显示中
17 | private static extern bool IsInputFieldDialogActive();
18 | [DllImport("__Internal")]//获取对话框的数据
19 | private static extern string GetInputFieldValue();
20 | [DllImport("__Internal")]//获取光标选中坐标(起点点)
21 | private static extern int GetInputFieldCursortPosition();
22 | [DllImport("__Internal")]//获取光标选中坐标(终点)
23 | private static extern int GetInputFieldCursortFocusPosition();
24 | [DllImport("__Internal")]//设置光标选择
25 | private static extern void SetInputFieldCursortPosition(int selectionStart, int selectionEnd);
26 | private bool captureAllKeyboardInput
27 | {
28 | get
29 | {
30 | return WebGLInput.captureAllKeyboardInput;
31 | }
32 | set
33 | {
34 | WebGLInput.captureAllKeyboardInput = value;
35 | }
36 | }
37 | private float timer;
38 | private Coroutine overlayhtml;
39 | private Coroutine setposCoroutine;
40 |
41 | public override void OnPointerClick(PointerEventData eventData)
42 | {
43 | base.OnPointerClick(eventData);
44 |
45 | captureAllKeyboardInput = false;
46 |
47 | ShowInputFieldDialog(text);
48 |
49 | if (IsInputFieldDialogActive() && overlayhtml != null)
50 | {
51 | //更新光标
52 | if(setposCoroutine != null)
53 | {
54 | SetSelection();
55 | }
56 | else
57 | {
58 | setposCoroutine = StartCoroutine(DelySetPostion());
59 | }
60 | }
61 | else
62 | {
63 | //打开html端的输入框
64 | overlayhtml = StartCoroutine(this.OverlayHtmlCoroutine());
65 | }
66 | }
67 |
68 | private IEnumerator DelySetPostion()
69 | {
70 | captureAllKeyboardInput = true;
71 | yield return null;
72 | SetSelection();
73 | captureAllKeyboardInput = false;
74 | setposCoroutine = null;
75 | System.GC.Collect();
76 | }
77 |
78 |
79 |
80 | private IEnumerator OverlayHtmlCoroutine()
81 | {
82 | yield return DelySetPostion();
83 | //设置选中对象为
84 | while (IsInputFieldDialogActive() && isFocused)
85 | {
86 | yield return null;
87 | var textFromHtml = GetInputFieldValue();
88 | if (textFromHtml != this.text)
89 | {
90 | this.text = textFromHtml;
91 | ForceLabelUpdate();
92 | yield return null;
93 | }
94 |
95 | if (!captureAllKeyboardInput && setposCoroutine == null && !Input.GetMouseButton(0))
96 | {
97 | UpdateCaretPositions();
98 | yield return null;
99 | }
100 | }
101 | HideInputFieldDialog();
102 | EventSystem.current.SetSelectedGameObject(null);
103 | captureAllKeyboardInput = true;
104 | overlayhtml = null;
105 | System.GC.Collect();
106 | }
107 |
108 | ///
109 | /// 设置选中区域
110 | ///
111 | private void SetSelection()
112 | {
113 | var selectionStart = selectionAnchorPosition < selectionFocusPosition ? selectionAnchorPosition : selectionFocusPosition;
114 | var selectionEnd = selectionAnchorPosition > selectionFocusPosition ? selectionAnchorPosition : selectionFocusPosition;
115 | SetInputFieldCursortPosition(selectionStart, selectionEnd);
116 | }
117 |
118 | ///
119 | /// 从html更新caretPosition
120 | ///
121 | private void UpdateCaretPositions()
122 | {
123 | var cpos = GetInputFieldCursortPosition();
124 | var fpos = GetInputFieldCursortFocusPosition();
125 | var changed = false;
126 | if (cpos != caretPosition)
127 | {
128 | caretPosition = cpos;
129 | changed = true;
130 | }
131 | if (fpos != selectionFocusPosition)
132 | {
133 | selectionFocusPosition = fpos;
134 | changed = true;
135 | }
136 |
137 | if (changed)
138 | {
139 | ForceLabelUpdate();
140 | }
141 | }
142 |
143 |
144 | #endif
145 | //注意Time.timeScale = 0 会无法更新信息
146 | //private void Update()
147 | //{
148 | // if(Input.GetMouseButtonDown(1) && isFocused)
149 | // {
150 | // Debug.Log("caretPosition:" + caretPosition);//光标坐标
151 | // Debug.Log("currentSelectionState:" + currentSelectionState);//选中状态
152 | // Debug.Log("selectionAnchorPosition:" + selectionAnchorPosition);//选择起点
153 | // Debug.Log("selectionFocusPosition:" + selectionFocusPosition);//选择结束点
154 | // }
155 | //}
156 | }
--------------------------------------------------------------------------------
/WebGLInputField/WebGLInputField.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 38b726831cb5bdd4981bb7b9961d4957
3 | timeCreated: 1531893617
4 | licenseType: Pro
5 | MonoImporter:
6 | serializedVersion: 2
7 | defaultReferences: []
8 | executionOrder: 0
9 | icon: {instanceID: 0}
10 | userData:
11 | assetBundleName:
12 | assetBundleVariant:
13 |
--------------------------------------------------------------------------------
/WebGLInputField/WebGLInputFieldHelper.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Generic;
3 | using System.Runtime.InteropServices;
4 | using UnityEngine;
5 | using UnityEngine.EventSystems;
6 | using UnityEngine.UI;
7 |
8 | //可以直接拖到inputfield上 对原项目无影响
9 | public class WebGLInputFieldHelper : MonoBehaviour, IPointerClickHandler
10 | {
11 | private InputField inputField;
12 | private string text;
13 | private bool isFocused;
14 |
15 |
16 | //#if UNITY_WEBGL && !UNITY_EDITOR
17 | [DllImport("__Internal")]//显示对话框
18 | private static extern void ShowInputFieldDialog(string text);
19 | [DllImport("__Internal")]//隐藏对话框
20 | private static extern void HideInputFieldDialog();
21 | [DllImport("__Internal")]//对话框是否显示中
22 | private static extern bool IsInputFieldDialogActive();
23 | [DllImport("__Internal")]//获取对话框的数据
24 | private static extern string GetInputFieldValue();
25 | [DllImport("__Internal")]//获取光标选中坐标(起点点)
26 | private static extern int GetInputFieldCursortPosition();
27 | [DllImport("__Internal")]//获取光标选中坐标(终点)
28 | private static extern int GetInputFieldCursortFocusPosition();
29 | [DllImport("__Internal")]//设置光标选择
30 | private static extern void SetInputFieldCursortPosition(int selectionStart, int selectionEnd);
31 |
32 | private bool captureAllKeyboardInput
33 | {
34 | get
35 | {
36 | return WebGLInput.captureAllKeyboardInput;
37 | }
38 | set
39 | {
40 | WebGLInput.captureAllKeyboardInput = value;
41 | }
42 | }
43 | private float timer;
44 | private Coroutine overlayhtml;
45 | private Coroutine setposCoroutine;
46 |
47 | void Start()
48 | {
49 | inputField = GetComponent();
50 | text = inputField.text;
51 | isFocused = inputField.isFocused;
52 | }
53 |
54 | public void OnPointerClick(PointerEventData eventData)
55 | {
56 |
57 | captureAllKeyboardInput = false;
58 |
59 | ShowInputFieldDialog(text);
60 |
61 | if (IsInputFieldDialogActive() && overlayhtml != null)
62 | {
63 | //更新光标
64 | if(setposCoroutine != null)
65 | {
66 | SetSelection();
67 | }
68 | else
69 | {
70 | setposCoroutine = StartCoroutine(DelySetPostion());
71 | }
72 | }
73 | else
74 | {
75 | //打开html端的输入框
76 | overlayhtml = StartCoroutine(this.OverlayHtmlCoroutine());
77 | }
78 | }
79 |
80 | private IEnumerator DelySetPostion()
81 | {
82 | captureAllKeyboardInput = true;
83 | yield return null;
84 | SetSelection();
85 | captureAllKeyboardInput = false;
86 | setposCoroutine = null;
87 | System.GC.Collect();
88 | }
89 |
90 | private IEnumerator OverlayHtmlCoroutine()
91 | {
92 | yield return DelySetPostion();
93 | //设置选中对象为
94 | while (IsInputFieldDialogActive() && isFocused)
95 | {
96 | yield return null;
97 | var textFromHtml = GetInputFieldValue();
98 | if (textFromHtml != this.text)
99 | {
100 | this.text = textFromHtml;
101 | inputField.ForceLabelUpdate();
102 | yield return null;
103 | }
104 |
105 | if (!captureAllKeyboardInput && setposCoroutine == null && !Input.GetMouseButton(0))
106 | {
107 | UpdateCaretPositions();
108 | yield return null;
109 | }
110 | }
111 | HideInputFieldDialog();
112 | EventSystem.current.SetSelectedGameObject(null);
113 | captureAllKeyboardInput = true;
114 | overlayhtml = null;
115 | System.GC.Collect();
116 | }
117 |
118 | ///
119 | /// 设置选中区域
120 | ///
121 | private void SetSelection()
122 | {
123 | var selectionStart =inputField.selectionAnchorPosition < inputField.selectionFocusPosition ? inputField.selectionAnchorPosition : inputField.selectionFocusPosition;
124 | var selectionEnd = inputField.selectionAnchorPosition > inputField.selectionFocusPosition ? inputField.selectionAnchorPosition : inputField.selectionFocusPosition;
125 | SetInputFieldCursortPosition(selectionStart, selectionEnd);
126 | }
127 |
128 | ///
129 | /// 从html更新caretPosition
130 | ///
131 | private void UpdateCaretPositions()
132 | {
133 | var cpos = GetInputFieldCursortPosition();
134 | var fpos = GetInputFieldCursortFocusPosition();
135 | var changed = false;
136 | if (cpos != inputField.caretPosition)
137 | {
138 | inputField.caretPosition = cpos;
139 | changed = true;
140 | }
141 | if (fpos != inputField.selectionFocusPosition)
142 | {
143 | inputField.selectionFocusPosition = fpos;
144 | changed = true;
145 | }
146 |
147 | if (changed)
148 | {
149 | inputField.ForceLabelUpdate();
150 | }
151 | }
152 |
153 | //#endif
154 | }
155 |
--------------------------------------------------------------------------------
/WebGLInputField/WebGLInputFieldHelper.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: b9a89c14dfba72c40b88ab7d3155335c
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------