您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
502 行
17 KiB
502 行
17 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using System.Runtime.InteropServices;
|
|
using Unity.UIWidgets.engine;
|
|
using Unity.UIWidgets.external.simplejson;
|
|
using Unity.UIWidgets.foundation;
|
|
using Unity.UIWidgets.ui;
|
|
using UnityEngine;
|
|
|
|
#if UNITY_EDITOR
|
|
using UnityEditor;
|
|
#endif
|
|
|
|
namespace Unity.UIWidgets.service {
|
|
|
|
public delegate RawInputKeyResponse GlobalKeyEventHandlerDelegate(RawKeyEvent rawEvt, bool enableCustomAction = false);
|
|
|
|
public class RawInputKeyResponse {
|
|
public readonly bool swallow;
|
|
public readonly char input;
|
|
public readonly TextInputAction? inputAction;
|
|
|
|
public RawInputKeyResponse(bool swallow, char input = '\0', TextInputAction? inputAction = null) {
|
|
this.swallow = swallow;
|
|
this.input = input;
|
|
this.inputAction = inputAction;
|
|
}
|
|
|
|
public static RawInputKeyResponse convert(RawKeyEvent evt) {
|
|
return new RawInputKeyResponse(
|
|
false,
|
|
evt.data.unityEvent.character,
|
|
null);
|
|
}
|
|
|
|
public static readonly RawInputKeyResponse swallowResponse = new RawInputKeyResponse(true, '\0', null);
|
|
}
|
|
|
|
interface KeyboardDelegate: IDisposable {
|
|
void show();
|
|
void hide();
|
|
void setEditingState(TextEditingValue value);
|
|
|
|
void setIMEPos(Offset imeGlobalPos);
|
|
|
|
void setClient(int client, TextInputConfiguration configuration);
|
|
void clearClient();
|
|
|
|
bool imeRequired();
|
|
}
|
|
|
|
public interface TextInputUpdateListener {
|
|
void Update();
|
|
}
|
|
|
|
public interface TextInputOnGUIListener {
|
|
void OnGUI();
|
|
}
|
|
|
|
class DefaultKeyboardDelegate : KeyboardDelegate, TextInputOnGUIListener {
|
|
|
|
int _client;
|
|
|
|
TextEditingValue _value;
|
|
|
|
public void show() {
|
|
}
|
|
|
|
public void hide() {
|
|
}
|
|
|
|
public void setEditingState(TextEditingValue value) {
|
|
this._value = value;
|
|
}
|
|
|
|
Offset _editorWindowPosToScreenPos(Offset position) {
|
|
#if UNITY_EDITOR_WIN
|
|
return position * EditorGUIUtility.pixelsPerPoint;
|
|
#elif UNITY_EDITOR_OSX
|
|
//locate the IME 30 logical pixels lower than the caret
|
|
var offsetY = 30f;
|
|
return new Offset(position.dx, position.dy + offsetY);
|
|
#else
|
|
return position;
|
|
#endif
|
|
}
|
|
|
|
public void setIMEPos(Offset imeGlobalPos) {
|
|
var uiWidgetWindowAdapter = Window.instance as UIWidgetWindowAdapter;
|
|
Offset screenPos = uiWidgetWindowAdapter != null
|
|
? uiWidgetWindowAdapter.windowPosToScreenPos(imeGlobalPos)
|
|
: this._editorWindowPosToScreenPos(imeGlobalPos);
|
|
|
|
Input.compositionCursorPos = new Vector2(screenPos.dx, screenPos.dy);
|
|
}
|
|
|
|
public void setClient(int client, TextInputConfiguration configuration) {
|
|
this._client = client;
|
|
}
|
|
|
|
public void clearClient() {
|
|
this._client = 0;
|
|
}
|
|
|
|
public bool imeRequired() {
|
|
return true;
|
|
}
|
|
|
|
bool isIMEInput = false;
|
|
|
|
public void OnGUI() {
|
|
if (TouchScreenKeyboard.isSupported) {
|
|
return;
|
|
}
|
|
|
|
if (this._client == 0) {
|
|
return;
|
|
}
|
|
|
|
|
|
var currentEvent = Event.current;
|
|
var oldValue = this._value;
|
|
|
|
if (currentEvent != null && currentEvent.type == EventType.KeyDown) {
|
|
var response = TextInput._handleGlobalInputKey(this._client,
|
|
new RawKeyDownEvent(new RawKeyEventData(currentEvent)));
|
|
|
|
if (response.swallow) {
|
|
if (response.inputAction != null) {
|
|
Window.instance.run(() => { TextInput._performAction(this._client, response.inputAction.Value); });
|
|
}
|
|
|
|
if (_validateCharacter(response.input)) {
|
|
this._value = this._value.insert(new string(response.input, 1));
|
|
}
|
|
} else if (currentEvent.keyCode == KeyCode.Backspace) {
|
|
if (this._value.selection.isValid) {
|
|
this._value = this._value.deleteSelection(true);
|
|
}
|
|
} else if (currentEvent.character != '\0') {
|
|
this._value = this._value.clearCompose();
|
|
char ch = currentEvent.character;
|
|
if (ch == '\r' || ch == 3) {
|
|
ch = '\n';
|
|
}
|
|
|
|
if (ch == '\n') {
|
|
Window.instance.run(() => { TextInput._performAction(this._client, TextInputAction.newline); });
|
|
}
|
|
|
|
if (_validateCharacter(ch)) {
|
|
this._value = this._value.insert(new string(ch, 1));
|
|
}
|
|
}
|
|
else if (!string.IsNullOrEmpty(Input.compositionString)) {
|
|
this.isIMEInput = true;
|
|
this._value = this._value.compose(Input.compositionString);
|
|
}
|
|
|
|
currentEvent.Use();
|
|
}
|
|
|
|
if (this._value != oldValue) {
|
|
if (this.isIMEInput) {
|
|
var isIMEInput = this.isIMEInput;
|
|
Window.instance.run(() => { TextInput._updateEditingState(this._client, this._value, isIMEInput); });
|
|
this.isIMEInput = false;
|
|
}
|
|
else {
|
|
Window.instance.run(() => { TextInput._updateEditingState(this._client, this._value); });
|
|
}
|
|
}
|
|
}
|
|
|
|
public void Dispose() {
|
|
}
|
|
|
|
static bool _validateCharacter(char ch) {
|
|
return ch >= ' ' || ch == '\t' || ch == '\r' || ch == 10 || ch == '\n';
|
|
}
|
|
}
|
|
|
|
class UnityTouchScreenKeyboardDelegate : KeyboardDelegate, TextInputUpdateListener {
|
|
int _client;
|
|
string _lastCompositionString;
|
|
TextInputConfiguration _configuration;
|
|
TextEditingValue _value;
|
|
TouchScreenKeyboard _keyboard;
|
|
RangeInt? _pendingSelection;
|
|
bool _screenKeyboardDone;
|
|
readonly TextInput _textInput;
|
|
|
|
public void Update() {
|
|
if (this._client == 0 || this._keyboard == null) {
|
|
return;
|
|
}
|
|
|
|
if (this._keyboard.canSetSelection && this._pendingSelection != null) {
|
|
this._keyboard.selection = this._pendingSelection.Value;
|
|
this._pendingSelection = null;
|
|
}
|
|
|
|
if (this._keyboard.status == TouchScreenKeyboard.Status.Done) {
|
|
if (!this._screenKeyboardDone) {
|
|
this._screenKeyboardDone = true;
|
|
Window.instance.run(() => {
|
|
TextInput._performAction(this._client,
|
|
TextInputAction.done);
|
|
});
|
|
}
|
|
}
|
|
else if (this._keyboard.status == TouchScreenKeyboard.Status.Visible) {
|
|
var keyboardSelection = this._keyboard.selection;
|
|
var newValue = new TextEditingValue(
|
|
this._keyboard.text,
|
|
this._keyboard.canGetSelection
|
|
? new TextSelection(keyboardSelection.start, keyboardSelection.end)
|
|
: TextSelection.collapsed(0)
|
|
);
|
|
var changed = this._value != newValue;
|
|
|
|
this._value = newValue;
|
|
if (changed) {
|
|
Window.instance.run(() => {
|
|
TextInput._updateEditingState(this._client,
|
|
this._value);
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
public void show() {
|
|
var secure = this._configuration.obscureText;
|
|
var multiline = this._configuration.inputType == TextInputType.multiline;
|
|
var autocorrection = this._configuration.autocorrect;
|
|
this._keyboard = TouchScreenKeyboard.Open(this._value.text,
|
|
getKeyboardTypeForConfiguration(this._configuration),
|
|
autocorrection, multiline, secure, false, "", 0);
|
|
this._pendingSelection = null;
|
|
this._screenKeyboardDone = false;
|
|
if (this._value.selection != null && this._value.selection.isValid) {
|
|
int start = this._value.selection.start;
|
|
int end = this._value.selection.end;
|
|
this._pendingSelection = new RangeInt(start, end - start);
|
|
}
|
|
}
|
|
|
|
public void clearClient() {
|
|
this._client = 0;
|
|
}
|
|
|
|
public bool imeRequired() {
|
|
return false;
|
|
}
|
|
|
|
public void setIMEPos(Offset imeGlobalPos) {
|
|
}
|
|
|
|
public void setClient(int client, TextInputConfiguration configuration) {
|
|
this._client = client;
|
|
this._configuration = configuration;
|
|
}
|
|
|
|
public void hide() {
|
|
if (this._keyboard != null) {
|
|
this._keyboard.active = false;
|
|
this._keyboard = null;
|
|
}
|
|
}
|
|
|
|
public void setEditingState(TextEditingValue state) {
|
|
this._value = state;
|
|
if (this._keyboard != null && this._keyboard.active) {
|
|
this._keyboard.text = state.text;
|
|
if (this._value.selection != null && this._value.selection.isValid) {
|
|
int start = this._value.selection.start;
|
|
int end = this._value.selection.end;
|
|
this._pendingSelection = new RangeInt(start, end - start);
|
|
RangeInt selection = new RangeInt(state.selection.start, end - start);
|
|
|
|
if (this._keyboard.canGetSelection) {
|
|
this._pendingSelection = null;
|
|
this._keyboard.selection = selection;
|
|
}
|
|
else {
|
|
this._pendingSelection = selection;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static TouchScreenKeyboardType getKeyboardTypeForConfiguration(TextInputConfiguration config) {
|
|
var inputType = config.inputType;
|
|
|
|
if (inputType.index == TextInputType.url.index) {
|
|
return TouchScreenKeyboardType.URL;
|
|
}
|
|
|
|
if (inputType.index == TextInputType.emailAddress.index) {
|
|
return TouchScreenKeyboardType.EmailAddress;
|
|
}
|
|
|
|
if (inputType.index == TextInputType.phone.index) {
|
|
return TouchScreenKeyboardType.PhonePad;
|
|
}
|
|
|
|
if (inputType.index == TextInputType.number.index) {
|
|
return TouchScreenKeyboardType.NumberPad;
|
|
}
|
|
|
|
return TouchScreenKeyboardType.Default;
|
|
}
|
|
|
|
public void Dispose() {
|
|
}
|
|
}
|
|
|
|
abstract class AbstractUIWidgetsKeyboardDelegate : KeyboardDelegate {
|
|
|
|
protected AbstractUIWidgetsKeyboardDelegate() {
|
|
UIWidgetsMessageManager.instance.
|
|
AddChannelMessageDelegate("TextInput", this._handleMethodCall);
|
|
}
|
|
|
|
public void Dispose() {
|
|
UIWidgetsMessageManager.instance.
|
|
RemoveChannelMessageDelegate("TextInput", this._handleMethodCall);
|
|
}
|
|
|
|
public abstract void show();
|
|
|
|
public abstract void hide();
|
|
|
|
public abstract void setEditingState(TextEditingValue value);
|
|
public abstract void setIMEPos(Offset imeGlobalPos);
|
|
public abstract void setClient(int client, TextInputConfiguration configuration);
|
|
|
|
public abstract void clearClient();
|
|
public virtual bool imeRequired() {
|
|
return false;
|
|
}
|
|
|
|
void _handleMethodCall(string method, List<JSONNode> args) {
|
|
if (TextInput._currentConnection == null) {
|
|
return;
|
|
}
|
|
int client = args[0].AsInt;
|
|
if (client != TextInput._currentConnection._id) {
|
|
return;
|
|
}
|
|
|
|
using (TextInput._currentConnection._window.getScope()) {
|
|
switch (method) {
|
|
case "TextInputClient.updateEditingState":
|
|
TextInput._updateEditingState(client, TextEditingValue.fromJson(args[1].AsObject));
|
|
break;
|
|
case "TextInputClient.performAction":
|
|
TextInput._performAction(client, TextInputUtils._toTextInputAction(args[1].Value));
|
|
break;
|
|
default:
|
|
throw new UIWidgetsError($"unknown method ${method}");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#if UNITY_WEBGL
|
|
class UIWidgetsWebGLKeyboardDelegate : AbstractUIWidgetsKeyboardDelegate {
|
|
|
|
public override void show() {
|
|
Input.imeCompositionMode = IMECompositionMode.On;
|
|
}
|
|
|
|
public override void hide() {
|
|
}
|
|
|
|
public override void setEditingState(TextEditingValue value) {
|
|
UIWidgetsTextInputSetTextInputEditingState(value.toJson().ToString());
|
|
}
|
|
|
|
public override void setIMEPos(Offset imeGlobalPos) {
|
|
var window = Window.instance as UIWidgetWindowAdapter;
|
|
var canvasPos = window.windowPosToScreenPos(imeGlobalPos);
|
|
UIWidgetsTextInputSetIMEPos(canvasPos.dx, canvasPos.dy);
|
|
}
|
|
|
|
public override void setClient(int client, TextInputConfiguration configuration) {
|
|
WebGLInput.captureAllKeyboardInput = false;
|
|
Input.imeCompositionMode = IMECompositionMode.On;
|
|
UIWidgetsTextInputSetClient(client, configuration.toJson().ToString());
|
|
}
|
|
|
|
public override void clearClient() {
|
|
UIWidgetsTextInputClearTextInputClient();
|
|
}
|
|
|
|
public override bool imeRequired() {
|
|
return true;
|
|
}
|
|
|
|
[DllImport ("__Internal")]
|
|
internal static extern void UIWidgetsTextInputSetClient(int client, string configuration);
|
|
|
|
[DllImport ("__Internal")]
|
|
internal static extern void UIWidgetsTextInputSetTextInputEditingState(string jsonText);
|
|
|
|
[DllImport ("__Internal")]
|
|
internal static extern void UIWidgetsTextInputClearTextInputClient();
|
|
|
|
[DllImport ("__Internal")]
|
|
internal static extern void UIWidgetsTextInputSetIMEPos(float x, float y);
|
|
|
|
|
|
}
|
|
#endif
|
|
|
|
#if UNITY_IOS || UNITY_ANDROID
|
|
class UIWidgetsTouchScreenKeyboardDelegate : AbstractUIWidgetsKeyboardDelegate {
|
|
|
|
public override void show() {
|
|
UIWidgetsTextInputShow();
|
|
}
|
|
|
|
public override void hide() {
|
|
UIWidgetsTextInputHide();
|
|
}
|
|
|
|
public override void setEditingState(TextEditingValue value) {
|
|
UIWidgetsTextInputSetTextInputEditingState(value.toJson().ToString());
|
|
}
|
|
|
|
public override void setIMEPos(Offset imeGlobalPos) {
|
|
}
|
|
|
|
public override void setClient(int client, TextInputConfiguration configuration) {
|
|
UIWidgetsTextInputSetClient(client, configuration.toJson().ToString());
|
|
}
|
|
|
|
public override void clearClient() {
|
|
UIWidgetsTextInputClearTextInputClient();
|
|
}
|
|
|
|
#if UNITY_IOS
|
|
[DllImport ("__Internal")]
|
|
internal static extern void UIWidgetsTextInputShow();
|
|
|
|
[DllImport ("__Internal")]
|
|
internal static extern void UIWidgetsTextInputHide();
|
|
|
|
[DllImport ("__Internal")]
|
|
internal static extern void UIWidgetsTextInputSetClient(int client, string configuration);
|
|
|
|
[DllImport ("__Internal")]
|
|
internal static extern void UIWidgetsTextInputSetTextInputEditingState(string jsonText);
|
|
|
|
[DllImport ("__Internal")]
|
|
internal static extern void UIWidgetsTextInputClearTextInputClient();
|
|
#elif UNITY_ANDROID
|
|
internal static void UIWidgetsTextInputShow() {
|
|
using (
|
|
AndroidJavaClass pluginClass = new AndroidJavaClass("com.unity.uiwidgets.plugin.editing.TextInputPlugin")
|
|
) {
|
|
pluginClass.CallStatic("show");
|
|
}
|
|
}
|
|
|
|
internal static void UIWidgetsTextInputHide() {
|
|
using (
|
|
AndroidJavaClass pluginClass = new AndroidJavaClass("com.unity.uiwidgets.plugin.editing.TextInputPlugin")
|
|
) {
|
|
pluginClass.CallStatic("hide");
|
|
}
|
|
}
|
|
|
|
internal static void UIWidgetsTextInputSetClient(int client, string configuration) {
|
|
using (
|
|
AndroidJavaClass pluginClass = new AndroidJavaClass("com.unity.uiwidgets.plugin.editing.TextInputPlugin")
|
|
) {
|
|
|
|
pluginClass.CallStatic("setClient", client, configuration);
|
|
}
|
|
}
|
|
|
|
internal static void UIWidgetsTextInputSetTextInputEditingState(string jsonText) {
|
|
using (
|
|
AndroidJavaClass pluginClass = new AndroidJavaClass("com.unity.uiwidgets.plugin.editing.TextInputPlugin")
|
|
) {
|
|
pluginClass.CallStatic("setEditingState", jsonText);
|
|
}
|
|
}
|
|
|
|
internal static void UIWidgetsTextInputClearTextInputClient() {
|
|
using (
|
|
AndroidJavaClass pluginClass = new AndroidJavaClass("com.unity.uiwidgets.plugin.editing.TextInputPlugin")
|
|
) {
|
|
pluginClass.CallStatic("clearClient");
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
#endif
|
|
}
|