Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

TextField cannt input chinese

Discussion in 'UI Toolkit' started by wang37921, Jan 25, 2019.

  1. wang37921

    wang37921

    Joined:
    Aug 1, 2014
    Posts:
    101
    Use Google's Pinyin ime.
     
  2. jeanfrancois_unity

    jeanfrancois_unity

    Unity Technologies

    Joined:
    Oct 24, 2018
    Posts:
    4
    Can you confirm the Unity version you are using and that this behaviour is with UIElements TextField ?
     
  3. wang37921

    wang37921

    Joined:
    Aug 1, 2014
    Posts:
    101
    Unity 2018.3.0f2
     
  4. Seto

    Seto

    Joined:
    Oct 10, 2010
    Posts:
    244
    The same here.
    2019.1.0b6
     
  5. Seto

    Seto

    Joined:
    Oct 10, 2010
    Posts:
    244
    @jeanfrancois_unity When will it be resolved? It's the main issue keep us away from it. Not only Chinese, but also Japanese can't be inputted.
     
  6. benoitd_unity

    benoitd_unity

    Unity Technologies

    Joined:
    Jan 2, 2018
    Posts:
    328
    It's in the backlog but sadly we have no ETA.
     
  7. Seto

    Seto

    Joined:
    Oct 10, 2010
    Posts:
    244
    It's just in the backlog or it's being fixed? If it's not fixed. I can't even use it for real projects.
     
  8. antoine-unity

    antoine-unity

    Unity Technologies

    Joined:
    Sep 10, 2015
    Posts:
    737
    We're looking into it as a bug and planning to fix it but the issue seems to affect the Editor at large and require coordination with some other teams.
     
  9. Seto

    Seto

    Joined:
    Oct 10, 2010
    Posts:
    244
    I finally find out a workaround for it. Could you please apply TextField by default?
    Code (CSharp):
    1.             m_TextField = new TextField();
    2.             m_TextField.RegisterCallback<FocusInEvent>(evt => { Input.imeCompositionMode = IMECompositionMode.On; });
    3.             m_TextField.RegisterCallback<FocusOutEvent>(evt => { Input.imeCompositionMode = IMECompositionMode.Auto; });
     
    wang37921 and YuGu_Zhang like this.
  10. wang37921

    wang37921

    Joined:
    Aug 1, 2014
    Posts:
    101
    Seto found the problem, could fix it?

    blow code is modify base on UnityReferenceSource branch 2019.3
    style base on exist code.
    insert line 309
    insert line 707~715

    Code (CSharp):
    1. // Unity C# reference source
    2. // Copyright (c) Unity Technologies. For terms of use, see
    3. // https://unity3d.com/legal/licenses/Unity_Reference_Only_License
    4.  
    5. using System;
    6.  
    7. namespace UnityEngine.UIElements
    8. {
    9.     internal interface ITextInputField : IEventHandler, ITextElement
    10.     {
    11.         bool hasFocus { get; }
    12.  
    13.         bool doubleClickSelectsWord { get; }
    14.         bool tripleClickSelectsLine { get; }
    15.  
    16.         bool isReadOnly { get; }
    17.  
    18.         bool isDelayed { get; }
    19.  
    20.         bool isPasswordField { get; }
    21.  
    22.         TextEditorEngine editorEngine { get; }
    23.  
    24.         void SyncTextEngine();
    25.         bool AcceptCharacter(char c);
    26.         string CullString(string s);
    27.         void UpdateText(string value);
    28.         void UpdateValueFromText();
    29.     }
    30.  
    31.     public abstract class TextInputBaseField<TValueType> : BaseField<TValueType>
    32.     {
    33.         static CustomStyleProperty<Color> s_SelectionColorProperty = new CustomStyleProperty<Color>("--unity-selection-color");
    34.         static CustomStyleProperty<Color> s_CursorColorProperty = new CustomStyleProperty<Color>("--unity-cursor-color");
    35.  
    36.         public new class UxmlTraits : BaseFieldTraits<string, UxmlStringAttributeDescription>
    37.         {
    38.             UxmlIntAttributeDescription m_MaxLength = new UxmlIntAttributeDescription { name = "max-length", obsoleteNames = new[] { "maxLength" }, defaultValue = kMaxLengthNone };
    39.             UxmlBoolAttributeDescription m_Password = new UxmlBoolAttributeDescription { name = "password" };
    40.             UxmlStringAttributeDescription m_MaskCharacter = new UxmlStringAttributeDescription { name = "mask-character", obsoleteNames = new[] { "maskCharacter" }, defaultValue = kMaskCharDefault.ToString()};
    41.             UxmlStringAttributeDescription m_Text = new UxmlStringAttributeDescription { name = "text" };
    42.             UxmlBoolAttributeDescription m_IsReadOnly = new UxmlBoolAttributeDescription { name = "readonly" };
    43.  
    44.             public override void Init(VisualElement ve, IUxmlAttributes bag, CreationContext cc)
    45.             {
    46.                 base.Init(ve, bag, cc);
    47.  
    48.                 var field = ((TextInputBaseField<TValueType>)ve);
    49.                 field.maxLength = m_MaxLength.GetValueFromBag(bag, cc);
    50.                 field.isPasswordField = m_Password.GetValueFromBag(bag, cc);
    51.                 field.isReadOnly = m_IsReadOnly.GetValueFromBag(bag, cc);
    52.                 string maskCharacter = m_MaskCharacter.GetValueFromBag(bag, cc);
    53.                 if (maskCharacter != null && maskCharacter.Length > 0)
    54.                 {
    55.                     field.maskChar = maskCharacter[0];
    56.                 }
    57.                 field.text = m_Text.GetValueFromBag(bag, cc);
    58.             }
    59.         }
    60.  
    61.         TextInputBase m_TextInputBase;
    62.         protected TextInputBase textInputBase => m_TextInputBase;
    63.  
    64.         internal const int kMaxLengthNone = -1;
    65.         internal const char kMaskCharDefault = '*';
    66.  
    67.         internal TextHandle textHandle { get; private set; } = TextHandle.New();
    68.  
    69.         public new static readonly string ussClassName = "unity-base-text-field";
    70.         public new static readonly string labelUssClassName = ussClassName + "__label";
    71.         public new static readonly string inputUssClassName = ussClassName + "__input";
    72.  
    73.         public static readonly string textInputUssName = "unity-text-input";
    74.  
    75.  
    76.         public string text
    77.         {
    78.             get { return m_TextInputBase.text; }
    79.             protected set
    80.             {
    81.                 m_TextInputBase.text = value;
    82.             }
    83.         }
    84.  
    85.         public bool isReadOnly
    86.         {
    87.             get { return m_TextInputBase.isReadOnly; }
    88.             set { m_TextInputBase.isReadOnly = value; }
    89.         }
    90.  
    91.         // Password field (indirectly lossy behaviour when activated via multiline)
    92.         public bool isPasswordField
    93.         {
    94.             get { return m_TextInputBase.isPasswordField; }
    95.             set { m_TextInputBase.isPasswordField = value; }
    96.         }
    97.  
    98.         public Color selectionColor => m_TextInputBase.selectionColor;
    99.         public Color cursorColor => m_TextInputBase.cursorColor;
    100.  
    101.  
    102.         public int cursorIndex => m_TextInputBase.cursorIndex;
    103.         public int selectIndex => m_TextInputBase.selectIndex;
    104.         public int maxLength
    105.         {
    106.             get { return m_TextInputBase.maxLength; }
    107.             set { m_TextInputBase.maxLength = value; }
    108.         }
    109.  
    110.         public bool doubleClickSelectsWord
    111.         {
    112.             get { return m_TextInputBase.doubleClickSelectsWord; }
    113.             set { m_TextInputBase.doubleClickSelectsWord = value; }
    114.         }
    115.         public bool tripleClickSelectsLine
    116.         {
    117.             get { return m_TextInputBase.tripleClickSelectsLine; }
    118.             set { m_TextInputBase.tripleClickSelectsLine = value; }
    119.         }
    120.  
    121.         public bool isDelayed
    122.         {
    123.             get { return m_TextInputBase.isDelayed; }
    124.             set { m_TextInputBase.isDelayed = value; }
    125.         }
    126.  
    127.         public char maskChar
    128.         {
    129.             get { return m_TextInputBase.maskChar; }
    130.             set { m_TextInputBase.maskChar = value; }
    131.         }
    132.  
    133.         /* internal for VisualTree tests */
    134.         internal TextEditorEventHandler editorEventHandler => m_TextInputBase.editorEventHandler;
    135.  
    136.         /* internal for VisualTree tests */
    137.         internal TextEditorEngine editorEngine  => m_TextInputBase.editorEngine;
    138.  
    139.         internal bool hasFocus => m_TextInputBase.hasFocus;
    140.  
    141.         public void SelectAll()
    142.         {
    143.             m_TextInputBase.SelectAll();
    144.         }
    145.  
    146.         internal void SyncTextEngine()
    147.         {
    148.             m_TextInputBase.SyncTextEngine();
    149.         }
    150.  
    151.         internal void DrawWithTextSelectionAndCursor(MeshGenerationContext mgc, string newText)
    152.         {
    153.             m_TextInputBase.DrawWithTextSelectionAndCursor(mgc, newText, scaledPixelsPerPoint);
    154.         }
    155.  
    156.         protected TextInputBaseField(int maxLength, char maskChar, TextInputBase textInputBase)
    157.             : this(null, maxLength, maskChar, textInputBase) {}
    158.  
    159.         protected TextInputBaseField(string label, int maxLength, char maskChar, TextInputBase textInputBase)
    160.             : base(label, textInputBase)
    161.         {
    162.             tabIndex = 0;
    163.             delegatesFocus = false;
    164.  
    165.             AddToClassList(ussClassName);
    166.             labelElement.AddToClassList(labelUssClassName);
    167.             visualInput.AddToClassList(inputUssClassName);
    168.  
    169.             m_TextInputBase = textInputBase;
    170.             m_TextInputBase.maxLength = maxLength;
    171.             m_TextInputBase.maskChar = maskChar;
    172.  
    173.             RegisterCallback<AttachToPanelEvent>(OnAttachToPanel);
    174.         }
    175.  
    176.         private void OnAttachToPanel(AttachToPanelEvent e)
    177.         {
    178.             var h = textHandle;
    179.             h.useLegacy = e.destinationPanel.contextType == ContextType.Editor;
    180.             textHandle = h;
    181.         }
    182.  
    183.         protected override void ExecuteDefaultActionAtTarget(EventBase evt)
    184.         {
    185.             base.ExecuteDefaultActionAtTarget(evt);
    186.  
    187.             if (evt == null)
    188.             {
    189.                 return;
    190.             }
    191.  
    192.             if (evt.eventTypeId == KeyDownEvent.TypeId())
    193.             {
    194.                 KeyDownEvent keyDownEvt = evt as KeyDownEvent;
    195.  
    196.                 // We must handle the ETX (char 3) or the \n instead of the KeypadEnter or Return because the focus will
    197.                 //     have the drawback of having the second event to be handled by the focused field.
    198.                 if ((keyDownEvt?.character == 3) ||     // KeyCode.KeypadEnter
    199.                     (keyDownEvt?.character == '\n'))    // KeyCode.Return
    200.                 {
    201.                     visualInput?.Focus();
    202.                 }
    203.             }
    204.         }
    205.  
    206.         protected abstract class TextInputBase : VisualElement, ITextInputField
    207.         {
    208.             string m_OriginalText;
    209.  
    210.             void SaveValueAndText()
    211.             {
    212.                 // When getting the FocusIn, we must keep the value in case of Escape...
    213.                 m_OriginalText = text;
    214.             }
    215.  
    216.             void RestoreValueAndText()
    217.             {
    218.                 text = m_OriginalText;
    219.             }
    220.  
    221.             public void SelectAll()
    222.             {
    223.                 editorEngine?.SelectAll();
    224.             }
    225.  
    226.             internal void SelectNone()
    227.             {
    228.                 editorEngine?.SelectNone();
    229.             }
    230.  
    231.             private void UpdateText(string value)
    232.             {
    233.                 if (text != value)
    234.                 {
    235.                     // Setting the VisualElement text here cause a repaint since it dirty the layout flag.
    236.                     using (InputEvent evt = InputEvent.GetPooled(text, value))
    237.                     {
    238.                         evt.target = parent;
    239.                         text = value;
    240.                         parent?.SendEvent(evt);
    241.                     }
    242.                 }
    243.             }
    244.  
    245.             protected virtual TValueType StringToValue(string str)
    246.             {
    247.                 throw new NotSupportedException();
    248.             }
    249.  
    250.             internal void UpdateValueFromText()
    251.             {
    252.                 var newValue = StringToValue(text);
    253.                 TextInputBaseField<TValueType> parentTextField = (TextInputBaseField<TValueType>)parent;
    254.                 parentTextField.value = newValue;
    255.             }
    256.  
    257.             public int cursorIndex
    258.             {
    259.                 get { return editorEngine.cursorIndex; }
    260.             }
    261.  
    262.             public int selectIndex
    263.             {
    264.                 get { return editorEngine.selectIndex; }
    265.             }
    266.  
    267.             bool ITextInputField.isReadOnly => isReadOnly;
    268.  
    269.             public bool isReadOnly { get; set; }
    270.             public int maxLength { get; set; }
    271.             public char maskChar { get; set; }
    272.  
    273.             public virtual bool isPasswordField { get; set; }
    274.  
    275.             public bool doubleClickSelectsWord { get; set; }
    276.             public bool tripleClickSelectsLine { get; set; }
    277.             internal bool isDelayed { get; set; }
    278.  
    279.             internal bool isDragging { get; set; }
    280.  
    281.             bool touchScreenTextField
    282.             {
    283.                 get { return TouchScreenKeyboard.isSupported && !TouchScreenKeyboard.isInPlaceEditingAllowed; }
    284.             }
    285.  
    286.  
    287.             Color m_SelectionColor = Color.clear;
    288.             Color m_CursorColor = Color.grey;
    289.  
    290.             public Color selectionColor => m_SelectionColor;
    291.             public Color cursorColor => m_CursorColor;
    292.  
    293.  
    294.             internal bool hasFocus
    295.             {
    296.                 get { return elementPanel != null && elementPanel.focusController.GetLeafFocusedElement() == this; }
    297.             }
    298.  
    299.             /* internal for VisualTree tests */
    300.             internal TextEditorEventHandler editorEventHandler { get; private set; }
    301.  
    302.             /* internal for VisualTree tests */
    303.             internal TextEditorEngine editorEngine { get; private set; }
    304.  
    305.             private TextHandle m_TextHandle = TextHandle.New();
    306.  
    307.             private string m_Text;
    308.  
    309.             private IMECompositionMode _savedInputImeCompositionMode;
    310.  
    311.             public string text
    312.             {
    313.                 get { return m_Text; }
    314.                 set
    315.                 {
    316.                     if (m_Text == value)
    317.                         return;
    318.  
    319.                     m_Text = value;
    320.                     editorEngine.text = value;
    321.                     IncrementVersion(VersionChangeType.Layout | VersionChangeType.Repaint);
    322.                 }
    323.             }
    324.  
    325.             internal TextInputBase()
    326.             {
    327.                 isReadOnly = false;
    328.                 focusable = true;
    329.  
    330.                 AddToClassList(inputUssClassName);
    331.                 m_Text = string.Empty;
    332.                 name = TextField.textInputUssName;
    333.  
    334.                 requireMeasureFunction = true;
    335.  
    336.                 editorEngine = new TextEditorEngine(OnDetectFocusChange, OnCursorIndexChange);
    337.  
    338.                 if (touchScreenTextField)
    339.                 {
    340.                     editorEventHandler = new TouchScreenTextEditorEventHandler(editorEngine, this);
    341.                 }
    342.                 else
    343.                 {
    344.                     // TODO: Default values should come from GUI.skin.settings
    345.                     doubleClickSelectsWord = true;
    346.                     tripleClickSelectsLine = true;
    347.  
    348.                     editorEventHandler = new KeyboardTextEditorEventHandler(editorEngine, this);
    349.                 }
    350.  
    351.                 // Make the editor style unique across all textfields
    352.                 editorEngine.style = new GUIStyle(editorEngine.style);
    353.  
    354.                 RegisterCallback<CustomStyleResolvedEvent>(OnCustomStyleResolved);
    355.                 RegisterCallback<AttachToPanelEvent>(OnAttachToPanel);
    356.                 this.generateVisualContent += OnGenerateVisualContent;
    357.             }
    358.  
    359.             DropdownMenuAction.Status CutCopyActionStatus(DropdownMenuAction a)
    360.             {
    361.                 return (editorEngine.hasSelection && !isPasswordField) ? DropdownMenuAction.Status.Normal : DropdownMenuAction.Status.Disabled;
    362.             }
    363.  
    364.             DropdownMenuAction.Status PasteActionStatus(DropdownMenuAction a)
    365.             {
    366.                 return (editorEngine.CanPaste() ? DropdownMenuAction.Status.Normal : DropdownMenuAction.Status.Disabled);
    367.             }
    368.  
    369.             void ProcessMenuCommand(string command)
    370.             {
    371.                 using (ExecuteCommandEvent evt = ExecuteCommandEvent.GetPooled(command))
    372.                 {
    373.                     evt.target = this;
    374.                     SendEvent(evt);
    375.                 }
    376.             }
    377.  
    378.             void Cut(DropdownMenuAction a)
    379.             {
    380.                 ProcessMenuCommand(EventCommandNames.Cut);
    381.             }
    382.  
    383.             void Copy(DropdownMenuAction a)
    384.             {
    385.                 ProcessMenuCommand(EventCommandNames.Copy);
    386.             }
    387.  
    388.             void Paste(DropdownMenuAction a)
    389.             {
    390.                 ProcessMenuCommand(EventCommandNames.Paste);
    391.             }
    392.  
    393.             private void OnCustomStyleResolved(CustomStyleResolvedEvent e)
    394.             {
    395.                 Color selectionValue = Color.clear;
    396.                 Color cursorValue = Color.clear;
    397.  
    398.                 ICustomStyle customStyle = e.customStyle;
    399.                 if (customStyle.TryGetValue(s_SelectionColorProperty, out selectionValue))
    400.                     m_SelectionColor = selectionValue;
    401.  
    402.                 if (customStyle.TryGetValue(s_CursorColorProperty, out cursorValue))
    403.                     m_CursorColor = cursorValue;
    404.  
    405.                 SyncGUIStyle(this, editorEngine.style);
    406.             }
    407.  
    408.             private void OnAttachToPanel(AttachToPanelEvent e)
    409.             {
    410.                 m_TextHandle.useLegacy = e.destinationPanel.contextType == ContextType.Editor;
    411.             }
    412.  
    413.             internal virtual void SyncTextEngine()
    414.             {
    415.                 editorEngine.text = CullString(text);
    416.  
    417.                 editorEngine.SaveBackup();
    418.  
    419.                 editorEngine.position = layout;
    420.  
    421.                 editorEngine.DetectFocusChange();
    422.             }
    423.  
    424.             internal string CullString(string s)
    425.             {
    426.                 if (maxLength >= 0 && s != null && s.Length > maxLength)
    427.                     return s.Substring(0, maxLength);
    428.                 return s;
    429.             }
    430.  
    431.             internal void OnGenerateVisualContent(MeshGenerationContext mgc)
    432.             {
    433.                 string drawText = text;
    434.                 if (isPasswordField)
    435.                 {
    436.                     drawText = "".PadRight(text.Length, maskChar);
    437.                 }
    438.  
    439.                 if (touchScreenTextField)
    440.                 {
    441.                     var touchScreenEditor = editorEventHandler as TouchScreenTextEditorEventHandler;
    442.                     if (touchScreenEditor != null)
    443.                     {
    444.                         mgc.Text(MeshGenerationContextUtils.TextParams.MakeStyleBased(this, drawText), m_TextHandle, scaledPixelsPerPoint);
    445.                     }
    446.                 }
    447.                 else
    448.                 {
    449.                     if (!hasFocus)
    450.                     {
    451.                         mgc.Text(MeshGenerationContextUtils.TextParams.MakeStyleBased(this, drawText), m_TextHandle, scaledPixelsPerPoint);
    452.                     }
    453.                     else
    454.                     {
    455.                         DrawWithTextSelectionAndCursor(mgc, drawText, scaledPixelsPerPoint);
    456.                     }
    457.                 }
    458.             }
    459.  
    460.             internal void DrawWithTextSelectionAndCursor(MeshGenerationContext mgc, string newText, float pixelsPerPoint)
    461.             {
    462.                 var playmodeTintColor = panel.contextType == ContextType.Editor
    463.                     ? UIElementsUtility.editorPlayModeTintColor
    464.                     : Color.white;
    465.  
    466.                 var keyboardTextEditor = editorEventHandler as KeyboardTextEditorEventHandler;
    467.                 if (keyboardTextEditor == null)
    468.                     return;
    469.  
    470.                 keyboardTextEditor.PreDrawCursor(newText);
    471.  
    472.                 int cursorIndex = editorEngine.cursorIndex;
    473.                 int selectIndex = editorEngine.selectIndex;
    474.                 Rect localPosition = editorEngine.localPosition;
    475.                 var scrollOffset = editorEngine.scrollOffset;
    476.  
    477.                 float textScaling = TextHandle.ComputeTextScaling(worldTransform, pixelsPerPoint);
    478.  
    479.                 var textParams = MeshGenerationContextUtils.TextParams.MakeStyleBased(this, text);
    480.                 textParams.text = " ";
    481.                 textParams.wordWrapWidth = 0.0f;
    482.                 textParams.wordWrap = false;
    483.  
    484.                 float lineHeight = m_TextHandle.ComputeTextHeight(textParams, textScaling);
    485.  
    486.                 float wordWrapWidth = 0.0f;
    487.  
    488.                 // Make sure to take into account the word wrap style...
    489.                 if (editorEngine.multiline && (resolvedStyle.whiteSpace == WhiteSpace.Normal))
    490.                 {
    491.                     wordWrapWidth = contentRect.width;
    492.  
    493.                     // Since the wrapping is enabled, there is no need to offset the text... It will always fit the space on screen !
    494.                     scrollOffset = Vector2.zero;
    495.                 }
    496.  
    497.                 GUIUtility.compositionCursorPos = editorEngine.graphicalCursorPos - scrollOffset +
    498.                     new Vector2(localPosition.x, localPosition.y + lineHeight);
    499.  
    500.                 Color drawCursorColor = cursorColor;
    501.  
    502.                 int selectionEndIndex = string.IsNullOrEmpty(GUIUtility.compositionString)
    503.                     ? selectIndex
    504.                     : cursorIndex + GUIUtility.compositionString.Length;
    505.  
    506.                 CursorPositionStylePainterParameters cursorParams;
    507.  
    508.                 // Draw highlighted section, if any
    509.                 if ((cursorIndex != selectionEndIndex) && !isDragging)
    510.                 {
    511.                     int min = cursorIndex < selectionEndIndex ? cursorIndex : selectionEndIndex;
    512.                     int max = cursorIndex > selectionEndIndex ? cursorIndex : selectionEndIndex;
    513.  
    514.                     cursorParams = CursorPositionStylePainterParameters.GetDefault(this, text);
    515.                     cursorParams.text = editorEngine.text;
    516.                     cursorParams.wordWrapWidth = wordWrapWidth;
    517.                     cursorParams.cursorIndex = min;
    518.  
    519.                     Vector2 minPos = m_TextHandle.GetCursorPosition(cursorParams, textScaling);
    520.  
    521.                     cursorParams.cursorIndex = max;
    522.                     Vector2 maxPos = m_TextHandle.GetCursorPosition(cursorParams, textScaling);
    523.  
    524.                     minPos -= scrollOffset;
    525.                     maxPos -= scrollOffset;
    526.  
    527.                     if (Mathf.Approximately(minPos.y, maxPos.y))
    528.                     {
    529.                         mgc.Rectangle(new MeshGenerationContextUtils.RectangleParams()
    530.                         {
    531.                             rect = new Rect(minPos.x, minPos.y, maxPos.x - minPos.x, lineHeight),
    532.                             color = selectionColor,
    533.                             playmodeTintColor = playmodeTintColor
    534.                         });
    535.                     }
    536.                     else
    537.                     {
    538.                         // Draw first line
    539.                         mgc.Rectangle(new MeshGenerationContextUtils.RectangleParams()
    540.                         {
    541.                             rect = new Rect(minPos.x, minPos.y, contentRect.xMax - minPos.x, lineHeight),
    542.                             color = selectionColor,
    543.                             playmodeTintColor = playmodeTintColor
    544.                         });
    545.  
    546.                         var inbetweenHeight = (maxPos.y - minPos.y) - lineHeight;
    547.                         if (inbetweenHeight > 0f)
    548.                         {
    549.                             // Draw all lines in-between
    550.                             mgc.Rectangle(new MeshGenerationContextUtils.RectangleParams()
    551.                             {
    552.                                 rect = new Rect(contentRect.xMin, minPos.y + lineHeight, contentRect.width, inbetweenHeight),
    553.                                 color = selectionColor,
    554.                                 playmodeTintColor = playmodeTintColor
    555.                             });
    556.                         }
    557.  
    558.                         // Draw last line if not empty
    559.                         if (maxPos.x != contentRect.x)
    560.                         {
    561.                             mgc.Rectangle(new MeshGenerationContextUtils.RectangleParams()
    562.                             {
    563.                                 rect = new Rect(contentRect.xMin, maxPos.y, maxPos.x, lineHeight),
    564.                                 color = selectionColor,
    565.                                 playmodeTintColor = playmodeTintColor
    566.                             });
    567.                         }
    568.                     }
    569.                 }
    570.  
    571.                 // Draw the text with the scroll offset
    572.                 if (!string.IsNullOrEmpty(editorEngine.text) && contentRect.width > 0.0f && contentRect.height > 0.0f)
    573.                 {
    574.                     textParams = MeshGenerationContextUtils.TextParams.MakeStyleBased(this, text);
    575.                     textParams.rect = new Rect(contentRect.x - scrollOffset.x, contentRect.y - scrollOffset.y, contentRect.width + scrollOffset.x, contentRect.height + scrollOffset.y);
    576.                     textParams.text = editorEngine.text;
    577.  
    578.                     mgc.Text(textParams, m_TextHandle, scaledPixelsPerPoint);
    579.                 }
    580.  
    581.                 // Draw the cursor
    582.                 if (!isReadOnly && !isDragging)
    583.                 {
    584.                     if (cursorIndex == selectionEndIndex && computedStyle.unityFont.value != null)
    585.                     {
    586.                         cursorParams = CursorPositionStylePainterParameters.GetDefault(this, text);
    587.                         cursorParams.text = editorEngine.text;
    588.                         cursorParams.wordWrapWidth = wordWrapWidth;
    589.                         cursorParams.cursorIndex = cursorIndex;
    590.  
    591.                         Vector2 cursorPosition = m_TextHandle.GetCursorPosition(cursorParams, textScaling);
    592.                         cursorPosition -= scrollOffset;
    593.                         mgc.Rectangle(new MeshGenerationContextUtils.RectangleParams
    594.                         {
    595.                             rect = new Rect(cursorPosition.x, cursorPosition.y, 1f, lineHeight),
    596.                             color = drawCursorColor,
    597.                             playmodeTintColor = playmodeTintColor
    598.                         });
    599.                     }
    600.  
    601.                     // Draw alternate cursor, if any
    602.                     if (editorEngine.altCursorPosition != -1)
    603.                     {
    604.                         cursorParams = CursorPositionStylePainterParameters.GetDefault(this, text);
    605.                         cursorParams.text = editorEngine.text.Substring(0, editorEngine.altCursorPosition);
    606.                         cursorParams.wordWrapWidth = wordWrapWidth;
    607.                         cursorParams.cursorIndex = editorEngine.altCursorPosition;
    608.  
    609.                         Vector2 altCursorPosition = m_TextHandle.GetCursorPosition(cursorParams, textScaling);
    610.                         altCursorPosition -= scrollOffset;
    611.                         mgc.Rectangle(new MeshGenerationContextUtils.RectangleParams
    612.                         {
    613.                             rect = new Rect(altCursorPosition.x, altCursorPosition.y, 1f, lineHeight),
    614.                             color = drawCursorColor,
    615.                             playmodeTintColor = playmodeTintColor
    616.                         });
    617.                     }
    618.                 }
    619.  
    620.                 keyboardTextEditor.PostDrawCursor();
    621.             }
    622.  
    623.             internal virtual bool AcceptCharacter(char c)
    624.             {
    625.                 // when readonly, we do not accept any character
    626.                 return !isReadOnly;
    627.             }
    628.  
    629.             protected virtual void BuildContextualMenu(ContextualMenuPopulateEvent evt)
    630.             {
    631.                 if (evt?.target is TextInputBase)
    632.                 {
    633.                     if (!isReadOnly)
    634.                     {
    635.                         evt.menu.AppendAction("Cut", Cut, CutCopyActionStatus);
    636.                     }
    637.                     evt.menu.AppendAction("Copy", Copy, CutCopyActionStatus);
    638.                     if (!isReadOnly)
    639.                     {
    640.                         evt.menu.AppendAction("Paste", Paste, PasteActionStatus);
    641.                     }
    642.                 }
    643.             }
    644.  
    645.             private void OnDetectFocusChange()
    646.             {
    647.                 if (editorEngine.m_HasFocus && !hasFocus)
    648.                 {
    649.                     editorEngine.OnFocus();
    650.                 }
    651.  
    652.                 if (!editorEngine.m_HasFocus && hasFocus)
    653.                     editorEngine.OnLostFocus();
    654.             }
    655.  
    656.             private void OnCursorIndexChange()
    657.             {
    658.                 IncrementVersion(VersionChangeType.Repaint);
    659.             }
    660.  
    661.             protected internal override Vector2 DoMeasure(float desiredWidth, MeasureMode widthMode, float desiredHeight, MeasureMode heightMode)
    662.             {
    663.                 // If the text is empty, we should make sure it returns at least the height/width of 1 character...
    664.                 var textToUse = m_Text;
    665.                 if (string.IsNullOrEmpty(textToUse))
    666.                 {
    667.                     textToUse = " ";
    668.                 }
    669.  
    670.                 return TextElement.MeasureVisualElementTextSize(this, textToUse, desiredWidth, widthMode, desiredHeight, heightMode, m_TextHandle);
    671.             }
    672.  
    673.             protected override void ExecuteDefaultActionAtTarget(EventBase evt)
    674.             {
    675.                 base.ExecuteDefaultActionAtTarget(evt);
    676.  
    677.                 if (elementPanel != null && elementPanel.contextualMenuManager != null)
    678.                 {
    679.                     elementPanel.contextualMenuManager.DisplayMenuIfEventMatches(evt, this);
    680.                 }
    681.  
    682.                 if (evt?.eventTypeId == ContextualMenuPopulateEvent.TypeId())
    683.                 {
    684.                     ContextualMenuPopulateEvent e = evt as ContextualMenuPopulateEvent;
    685.                     int count = e.menu.MenuItems().Count;
    686.                     BuildContextualMenu(e);
    687.  
    688.                     if (count > 0 && e.menu.MenuItems().Count > count)
    689.                     {
    690.                         e.menu.InsertSeparator(null, count);
    691.                     }
    692.                 }
    693.                 else if (evt.eventTypeId == FocusInEvent.TypeId())
    694.                 {
    695.                     SaveValueAndText();
    696.                 }
    697.                 else if (evt.eventTypeId == KeyDownEvent.TypeId())
    698.                 {
    699.                     KeyDownEvent keyDownEvt = evt as KeyDownEvent;
    700.  
    701.                     if (keyDownEvt?.keyCode == KeyCode.Escape)
    702.                     {
    703.                         RestoreValueAndText();
    704.                         parent.Focus();
    705.                     }
    706.                 }
    707.                 else if (evt.eventTypeId == FocusInEvent.TypeId())
    708.                 {
    709.                     _savedInputImeCompositionMode = Input.imeCompositionMode;
    710.                     Input.imeCompositionMode = IMECompositionMode.On;
    711.                 }
    712.                 else if (evt.eventTypeId == FocusOutEvent.TypeId())
    713.                 {
    714.                     Input.imeCompositionMode = _savedInputImeCompositionMode;
    715.                 }
    716.  
    717.                 editorEventHandler.ExecuteDefaultActionAtTarget(evt);
    718.             }
    719.  
    720.             protected override void ExecuteDefaultAction(EventBase evt)
    721.             {
    722.                 base.ExecuteDefaultAction(evt);
    723.  
    724.                 editorEventHandler.ExecuteDefaultAction(evt);
    725.             }
    726.  
    727.             bool ITextInputField.hasFocus => hasFocus;
    728.  
    729.             void ITextInputField.SyncTextEngine()
    730.             {
    731.                 SyncTextEngine();
    732.             }
    733.  
    734.             bool ITextInputField.AcceptCharacter(char c)
    735.             {
    736.                 return AcceptCharacter(c);
    737.             }
    738.  
    739.             string ITextInputField.CullString(string s)
    740.             {
    741.                 return CullString(s);
    742.             }
    743.  
    744.             void ITextInputField.UpdateText(string value)
    745.             {
    746.                 UpdateText(value);
    747.             }
    748.  
    749.             TextEditorEngine ITextInputField.editorEngine => editorEngine;
    750.  
    751.             bool ITextInputField.isDelayed => isDelayed;
    752.  
    753.             void ITextInputField.UpdateValueFromText()
    754.             {
    755.                 UpdateValueFromText();
    756.             }
    757.  
    758.             private void DeferGUIStyleRectSync()
    759.             {
    760.                 RegisterCallback<GeometryChangedEvent>(OnPercentResolved);
    761.             }
    762.  
    763.             private void OnPercentResolved(GeometryChangedEvent evt)
    764.             {
    765.                 UnregisterCallback<GeometryChangedEvent>(OnPercentResolved);
    766.  
    767.                 var guiStyle = editorEngine.style;
    768.                 int left = (int)resolvedStyle.marginLeft;
    769.                 int top = (int)resolvedStyle.marginTop;
    770.                 int right = (int)resolvedStyle.marginRight;
    771.                 int bottom = (int)resolvedStyle.marginBottom;
    772.                 AssignRect(guiStyle.margin, left, top, right, bottom);
    773.  
    774.                 left = (int)resolvedStyle.paddingLeft;
    775.                 top = (int)resolvedStyle.paddingTop;
    776.                 right = (int)resolvedStyle.paddingRight;
    777.                 bottom = (int)resolvedStyle.paddingBottom;
    778.                 AssignRect(guiStyle.padding, left, top, right, bottom);
    779.             }
    780.  
    781.             private static void SyncGUIStyle(TextInputBase textInput, GUIStyle style)
    782.             {
    783.                 var computedStyle = textInput.computedStyle;
    784.                 style.alignment = computedStyle.unityTextAlign.GetSpecifiedValueOrDefault(style.alignment);
    785.                 style.wordWrap = computedStyle.whiteSpace.specificity != StyleValueExtensions.UndefinedSpecificity
    786.                     ? computedStyle.whiteSpace.value == WhiteSpace.Normal
    787.                     : style.wordWrap;
    788.                 bool overflowVisible = computedStyle.overflow.specificity != StyleValueExtensions.UndefinedSpecificity
    789.                     ? computedStyle.overflow.value == Overflow.Visible
    790.                     : style.clipping == TextClipping.Overflow;
    791.                 style.clipping = overflowVisible ? TextClipping.Overflow : TextClipping.Clip;
    792.                 if (computedStyle.unityFont.value != null)
    793.                 {
    794.                     style.font = computedStyle.unityFont.value;
    795.                 }
    796.  
    797.                 style.fontSize = (int)computedStyle.fontSize.GetSpecifiedValueOrDefault((float)style.fontSize);
    798.                 style.fontStyle = computedStyle.unityFontStyleAndWeight.GetSpecifiedValueOrDefault(style.fontStyle);
    799.  
    800.                 int left = computedStyle.unitySliceLeft.value;
    801.                 int top = computedStyle.unitySliceTop.value;
    802.                 int right = computedStyle.unitySliceRight.value;
    803.                 int bottom = computedStyle.unitySliceBottom.value;
    804.                 AssignRect(style.border, left, top, right, bottom);
    805.  
    806.                 if (IsLayoutUsingPercent(textInput))
    807.                 {
    808.                     textInput.DeferGUIStyleRectSync();
    809.                 }
    810.                 else
    811.                 {
    812.                     left = (int)computedStyle.marginLeft.value.value;
    813.                     top = (int)computedStyle.marginTop.value.value;
    814.                     right = (int)computedStyle.marginRight.value.value;
    815.                     bottom = (int)computedStyle.marginBottom.value.value;
    816.                     AssignRect(style.margin, left, top, right, bottom);
    817.  
    818.                     left = (int)computedStyle.paddingLeft.value.value;
    819.                     top = (int)computedStyle.paddingTop.value.value;
    820.                     right = (int)computedStyle.paddingRight.value.value;
    821.                     bottom = (int)computedStyle.paddingBottom.value.value;
    822.                     AssignRect(style.padding, left, top, right, bottom);
    823.                 }
    824.             }
    825.  
    826.             private static bool IsLayoutUsingPercent(VisualElement ve)
    827.             {
    828.                 var computedStyle = ve.computedStyle;
    829.  
    830.                 // Margin
    831.                 if (computedStyle.marginLeft.value.unit == LengthUnit.Percent ||
    832.                     computedStyle.marginTop.value.unit == LengthUnit.Percent ||
    833.                     computedStyle.marginRight.value.unit == LengthUnit.Percent ||
    834.                     computedStyle.marginBottom.value.unit == LengthUnit.Percent)
    835.                     return true;
    836.  
    837.                 // Padding
    838.                 if (computedStyle.paddingLeft.value.unit == LengthUnit.Percent ||
    839.                     computedStyle.paddingTop.value.unit == LengthUnit.Percent ||
    840.                     computedStyle.paddingRight.value.unit == LengthUnit.Percent ||
    841.                     computedStyle.paddingBottom.value.unit == LengthUnit.Percent)
    842.                     return true;
    843.  
    844.                 return false;
    845.             }
    846.  
    847.             private static void AssignRect(RectOffset rect, int left, int top, int right, int bottom)
    848.             {
    849.                 rect.left = left;
    850.                 rect.top = top;
    851.                 rect.right = right;
    852.                 rect.bottom = bottom;
    853.             }
    854.         }
    855.     }
    856. }
    857.  
     
    Last edited: May 20, 2020
  11. Sangemdoko

    Sangemdoko

    Joined:
    Dec 15, 2013
    Posts:
    218
    Hi

    I'm working on an asset on the asset store and some of our clients have complained that they couldn't write in Chinese or Japanese in our text fields.

    I tried the both work arounds, neither worked for me. This is the class I created to replace the base TextField:
    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.UIElements;
    3. /// <summary>
    4. /// A custom textfield that fixes a bug which hides 2-byte characters.
    5. /// </summary>
    6. public class UnicodeTextField : TextField
    7. {
    8.     private IMECompositionMode m_SavedInputImeCompositionMode;
    9.     public UnicodeTextField() : base()
    10.     {
    11.         RegisterCallback<FocusInEvent>(evt => { Input.imeCompositionMode = IMECompositionMode.On; });
    12.         RegisterCallback<FocusOutEvent>(evt => { Input.imeCompositionMode = IMECompositionMode.Auto; });
    13.     }
    14.     public UnicodeTextField(string name) : base(name)
    15.     {
    16.         RegisterCallback<FocusInEvent>(evt => { Input.imeCompositionMode = IMECompositionMode.On; });
    17.         RegisterCallback<FocusOutEvent>(evt => { Input.imeCompositionMode = IMECompositionMode.Auto; });
    18.     }
    19.  
    20.     /*protected override void ExecuteDefaultActionAtTarget(EventBase evt)
    21.     {
    22.         base.ExecuteDefaultActionAtTarget(evt);
    23.         if (evt?.eventTypeId == ContextualMenuPopulateEvent.TypeId())
    24.         { }
    25.         else if (evt.eventTypeId == FocusInEvent.TypeId())
    26.         { }
    27.         else if (evt.eventTypeId == KeyDownEvent.TypeId())
    28.         { }
    29.         else if (evt.eventTypeId == FocusInEvent.TypeId())
    30.         {
    31.             m_SavedInputImeCompositionMode = Input.imeCompositionMode;
    32.             Input.imeCompositionMode = IMECompositionMode.On;
    33.         }
    34.         else if (evt.eventTypeId == FocusOutEvent.TypeId())
    35.         {
    36.             Input.imeCompositionMode = m_SavedInputImeCompositionMode;
    37.         }
    38.     }*/
    39. }
    I'm using the default IME pad that comes with Windows 10 when you add Japanese as a language.
    Any news on a potential fix for this? Or another workaround? Or maybe the issue is the IME pad I'm using?

    Any help would be greatly appriciated

    EDIT: It works now, It seems closing and reopening the IME Pad and the custom Unity Editor refreshed something and now characters appear as they should
     
    Last edited: Jan 21, 2021
  12. Amane224

    Amane224

    Joined:
    May 4, 2016
    Posts:
    5
    Two years have passed, but no progress has been made. Are they going to let this bug continue?
     
  13. optimise

    optimise

    Joined:
    Jan 22, 2014
    Posts:
    2,046
    Hi @antoine-unity. Any new progress update?
     
  14. JuliaP_Unity

    JuliaP_Unity

    Unity Technologies

    Joined:
    Mar 26, 2020
    Posts:
    666
    We're actively working on the text field right now and there should be new stuff coming out at some point in the 2022 release cycle :cool:
     
  15. optimise

    optimise

    Joined:
    Jan 22, 2014
    Posts:
    2,046
    @JuliaP_Unity Awesome. Btw will it backport to 2021 release cycle?
     
  16. JuliaP_Unity

    JuliaP_Unity

    Unity Technologies

    Joined:
    Mar 26, 2020
    Posts:
    666
    It will not be backported as far as I know, it's a full new feature for 2022.
     
    Amane224 likes this.