Search Unity

  1. We are migrating the Unity Forums to Unity Discussions. On July 12, the Unity Forums will become read-only.

    Please, do not make any changes to your username or email addresses at id.unity.com during this transition time.

    It's still possible to reply to existing private message conversations during the migration, but any new replies you post will be missing after the main migration is complete. We'll do our best to migrate these messages in a follow-up step.

    On July 15, Unity Discussions will become read-only until July 18, when the new design and the migrated forum contents will go live.


    Read our full announcement for more information and let us know if you have any questions.

Question Help me Read this Script please

Discussion in 'Scripting' started by Mortalanimal, Jun 15, 2020.

  1. Mortalanimal

    Mortalanimal

    Joined:
    Jun 7, 2014
    Posts:
    577
    I have been trying to make an event with Input-Field UI (Text mesh Pro) whenever I deselect or change focused from the input field.

    TMP Input Field has its own Trigger for this:



    but its not working, So I started to read the Script for TMP.

    I believe, this only activates when the following lines return true (I could be wrong):

    Code (CSharp):
    1. public bool isFocused
    2.         {
    3.             get { return m_AllowInput; }
    4.         }
    my Question is; Under what Conditions by reading the following script, does this return true?

    TMP Input Field Script:

    Code (CSharp):
    1. //#define TMP_DEBUG_MODE
    2.  
    3. using System;
    4. using System.Collections;
    5. using System.Collections.Generic;
    6. using System.Text;
    7. using System.Text.RegularExpressions;
    8. using UnityEngine;
    9. using UnityEngine.UI;
    10. using UnityEngine.Events;
    11. using UnityEngine.EventSystems;
    12. using UnityEngine.Serialization;
    13.  
    14.  
    15. namespace TMPro
    16. {
    17.     /// <summary>
    18.     /// Editable text input field.
    19.     /// </summary>
    20.     [AddComponentMenu("UI/TextMeshPro - Input Field", 11)]
    21.     public class TMP_InputField : Selectable,
    22.         IUpdateSelectedHandler,
    23.         IBeginDragHandler,
    24.         IDragHandler,
    25.         IEndDragHandler,
    26.         IPointerClickHandler,
    27.         ISubmitHandler,
    28.         ICanvasElement,
    29.         ILayoutElement,
    30.         IScrollHandler
    31.     {
    32.  
    33.         // Setting the content type acts as a shortcut for setting a combination of InputType, CharacterValidation, LineType, and TouchScreenKeyboardType
    34.         public enum ContentType
    35.         {
    36.             Standard,
    37.             Autocorrected,
    38.             IntegerNumber,
    39.             DecimalNumber,
    40.             Alphanumeric,
    41.             Name,
    42.             EmailAddress,
    43.             Password,
    44.             Pin,
    45.             Custom
    46.         }
    47.  
    48.         public enum InputType
    49.         {
    50.             Standard,
    51.             AutoCorrect,
    52.             Password,
    53.         }
    54.  
    55.         public enum CharacterValidation
    56.         {
    57.             None,
    58.             Digit,
    59.             Integer,
    60.             Decimal,
    61.             Alphanumeric,
    62.             Name,
    63.             Regex,
    64.             EmailAddress,
    65.             CustomValidator
    66.         }
    67.  
    68.         public enum LineType
    69.         {
    70.             SingleLine,
    71.             MultiLineSubmit,
    72.             MultiLineNewline
    73.         }
    74.  
    75.         public delegate char OnValidateInput(string text, int charIndex, char addedChar);
    76.  
    77.         [Serializable]
    78.         public class SubmitEvent : UnityEvent<string> { }
    79.  
    80.         [Serializable]
    81.         public class OnChangeEvent : UnityEvent<string> { }
    82.  
    83.         [Serializable]
    84.         public class SelectionEvent : UnityEvent<string> { }
    85.  
    86.         [Serializable]
    87.         public class TextSelectionEvent : UnityEvent<string, int, int> { }
    88.  
    89.         [Serializable]
    90.         public class TouchScreenKeyboardEvent : UnityEvent<TouchScreenKeyboard.Status> { }
    91.  
    92.         protected TouchScreenKeyboard m_SoftKeyboard;
    93.         static private readonly char[] kSeparators = { ' ', '.', ',', '\t', '\r', '\n' };
    94.  
    95.         #region Exposed properties
    96.         /// <summary>
    97.         /// Text Text used to display the input's value.
    98.         /// </summary>
    99.  
    100.         [SerializeField]
    101.         protected RectTransform m_TextViewport;
    102.  
    103.         //Vector3[] m_ViewportCorners = new Vector3[4];
    104.  
    105.         [SerializeField]
    106.         protected TMP_Text m_TextComponent;
    107.  
    108.         protected RectTransform m_TextComponentRectTransform;
    109.  
    110.         [SerializeField]
    111.         protected Graphic m_Placeholder;
    112.  
    113.         [SerializeField]
    114.         protected Scrollbar m_VerticalScrollbar;
    115.  
    116.         [SerializeField]
    117.         protected TMP_ScrollbarEventHandler m_VerticalScrollbarEventHandler;
    118.         //private bool m_ForceDeactivation;
    119.  
    120.         private bool m_IsDrivenByLayoutComponents = false;
    121.  
    122.         /// <summary>
    123.         /// Used to keep track of scroll position
    124.         /// </summary>
    125.         private float m_ScrollPosition;
    126.  
    127.         /// <summary>
    128.         ///
    129.         /// </summary>
    130.         [SerializeField]
    131.         protected float m_ScrollSensitivity = 1.0f;
    132.  
    133.         //[SerializeField]
    134.         //protected TMP_Text m_PlaceholderTextComponent;
    135.  
    136.         [SerializeField]
    137.         private ContentType m_ContentType = ContentType.Standard;
    138.  
    139.         /// <summary>
    140.         /// Type of data expected by the input field.
    141.         /// </summary>
    142.         [SerializeField]
    143.         private InputType m_InputType = InputType.Standard;
    144.  
    145.         /// <summary>
    146.         /// The character used to hide text in password field.
    147.         /// </summary>
    148.         [SerializeField]
    149.         private char m_AsteriskChar = '*';
    150.  
    151.         /// <summary>
    152.         /// Keyboard type applies to mobile keyboards that get shown.
    153.         /// </summary>
    154.         [SerializeField]
    155.         private TouchScreenKeyboardType m_KeyboardType = TouchScreenKeyboardType.Default;
    156.  
    157.         [SerializeField]
    158.         private LineType m_LineType = LineType.SingleLine;
    159.  
    160.         /// <summary>
    161.         /// Should hide mobile input field part of the virtual keyboard.
    162.         /// </summary>
    163.         [SerializeField]
    164.         private bool m_HideMobileInput = false;
    165.  
    166.         /// <summary>
    167.         /// Should hide soft / virtual keyboard.
    168.         /// </summary>
    169.         [SerializeField]
    170.         private bool m_HideSoftKeyboard = false;
    171.  
    172.         /// <summary>
    173.         /// What kind of validation to use with the input field's data.
    174.         /// </summary>
    175.         [SerializeField]
    176.         private CharacterValidation m_CharacterValidation = CharacterValidation.None;
    177.  
    178.         /// <summary>
    179.         /// The Regex expression used for validating the text input.
    180.         /// </summary>
    181.         [SerializeField]
    182.         private string m_RegexValue = string.Empty;
    183.  
    184.         /// <summary>
    185.         /// The point sized used by the placeholder and input text object.
    186.         /// </summary>
    187.         [SerializeField]
    188.         private float m_GlobalPointSize = 14;
    189.  
    190.         /// <summary>
    191.         /// Maximum number of characters allowed before input no longer works.
    192.         /// </summary>
    193.         [SerializeField]
    194.         private int m_CharacterLimit = 0;
    195.  
    196.         /// <summary>
    197.         /// Event delegates triggered when the input field submits its data.
    198.         /// </summary>
    199.         [SerializeField]
    200.         private SubmitEvent m_OnEndEdit = new SubmitEvent();
    201.  
    202.         /// <summary>
    203.         /// Event delegates triggered when the input field submits its data.
    204.         /// </summary>
    205.         [SerializeField]
    206.         private SubmitEvent m_OnSubmit = new SubmitEvent();
    207.  
    208.         /// <summary>
    209.         /// Event delegates triggered when the input field is focused.
    210.         /// </summary>
    211.         [SerializeField]
    212.         private SelectionEvent m_OnSelect = new SelectionEvent();
    213.  
    214.         /// <summary>
    215.         /// Event delegates triggered when the input field focus is lost.
    216.         /// </summary>
    217.         [SerializeField]
    218.         private SelectionEvent m_OnDeselect = new SelectionEvent();
    219.  
    220.         /// <summary>
    221.         /// Event delegates triggered when the text is selected / highlighted.
    222.         /// </summary>
    223.         [SerializeField]
    224.         private TextSelectionEvent m_OnTextSelection = new TextSelectionEvent();
    225.  
    226.         /// <summary>
    227.         /// Event delegates triggered when text is no longer select / highlighted.
    228.         /// </summary>
    229.         [SerializeField]
    230.         private TextSelectionEvent m_OnEndTextSelection = new TextSelectionEvent();
    231.  
    232.         /// <summary>
    233.         /// Event delegates triggered when the input field changes its data.
    234.         /// </summary>
    235.         [SerializeField]
    236.         private OnChangeEvent m_OnValueChanged = new OnChangeEvent();
    237.  
    238.         /// <summary>
    239.         /// Event delegates triggered when the status of the TouchScreenKeyboard changes.
    240.         /// </summary>
    241.         [SerializeField]
    242.         private TouchScreenKeyboardEvent m_OnTouchScreenKeyboardStatusChanged = new TouchScreenKeyboardEvent();
    243.  
    244.         /// <summary>
    245.         /// Custom validation callback.
    246.         /// </summary>
    247.         [SerializeField]
    248.         private OnValidateInput m_OnValidateInput;
    249.  
    250.         [SerializeField]
    251.         private Color m_CaretColor = new Color(50f / 255f, 50f / 255f, 50f / 255f, 1f);
    252.  
    253.         [SerializeField]
    254.         private bool m_CustomCaretColor = false;
    255.  
    256.         [SerializeField]
    257.         private Color m_SelectionColor = new Color(168f / 255f, 206f / 255f, 255f / 255f, 192f / 255f);
    258.  
    259.         /// <summary>
    260.         /// Input field's value.
    261.         /// </summary>
    262.  
    263.         [SerializeField]
    264.         [TextArea(5, 10)]
    265.         protected string m_Text = string.Empty;
    266.  
    267.         [SerializeField]
    268.         [Range(0f, 4f)]
    269.         private float m_CaretBlinkRate = 0.85f;
    270.  
    271.         [SerializeField]
    272.         [Range(1, 5)]
    273.         private int m_CaretWidth = 1;
    274.  
    275.         [SerializeField]
    276.         private bool m_ReadOnly = false;
    277.  
    278.         [SerializeField]
    279.         private bool m_RichText = true;
    280.  
    281.         #endregion
    282.  
    283.         protected int m_StringPosition = 0;
    284.         protected int m_StringSelectPosition = 0;
    285.         protected int m_CaretPosition = 0;
    286.         protected int m_CaretSelectPosition = 0;
    287.  
    288.         private RectTransform caretRectTrans = null;
    289.         protected UIVertex[] m_CursorVerts = null;
    290.         private CanvasRenderer m_CachedInputRenderer;
    291.         private Vector2 m_LastPosition;
    292.  
    293.         [NonSerialized]
    294.         protected Mesh m_Mesh;
    295.         private bool m_AllowInput = false;
    296.         //bool m_HasLostFocus = false;   //Why did they comment this out? Because they dont use it since they dont need it
    297.         private bool m_ShouldActivateNextUpdate = false;
    298.         private bool m_UpdateDrag = false;
    299.         private bool m_DragPositionOutOfBounds = false;
    300.         private const float kHScrollSpeed = 0.05f;
    301.         private const float kVScrollSpeed = 0.10f;
    302.         protected bool m_CaretVisible;
    303.         private Coroutine m_BlinkCoroutine = null;
    304.         private float m_BlinkStartTime = 0.0f;
    305.         private Coroutine m_DragCoroutine = null;
    306.         private string m_OriginalText = "";
    307.         private bool m_WasCanceled = false;
    308.         private bool m_HasDoneFocusTransition = false;
    309.         private WaitForSecondsRealtime m_WaitForSecondsRealtime;
    310.         private bool m_PreventCallback = false;
    311.  
    312.         private bool m_TouchKeyboardAllowsInPlaceEditing = false;
    313.  
    314.         private bool m_IsTextComponentUpdateRequired = false;
    315.         private bool m_IsScrollbarUpdateRequired = false;
    316.         private bool m_IsUpdatingScrollbarValues = false;
    317.  
    318.         private bool m_isLastKeyBackspace = false;
    319.         private float m_PointerDownClickStartTime;
    320.         private float m_KeyDownStartTime;
    321.         private float m_DoubleClickDelay = 0.5f;
    322.  
    323.         // Doesn't include dot and @ on purpose! See usage for details.
    324.         const string kEmailSpecialCharacters = "!#$%&'*+-/=?^_`{|}~";
    325.  
    326.         private BaseInput inputSystem
    327.         {
    328.             get
    329.             {
    330.                 if (EventSystem.current && EventSystem.current.currentInputModule)
    331.                     return EventSystem.current.currentInputModule.input;
    332.                 return null;
    333.             }
    334.         }
    335.  
    336.         private string compositionString
    337.         {
    338.             get { return inputSystem != null ? inputSystem.compositionString : Input.compositionString; }
    339.         }
    340.  
    341.  
    342.  
    343.         protected TMP_InputField()
    344.         {
    345.             SetTextComponentWrapMode();
    346.         }
    347.  
    348.         protected Mesh mesh
    349.         {
    350.             get
    351.             {
    352.                 if (m_Mesh == null)
    353.                     m_Mesh = new Mesh();
    354.                 return m_Mesh;
    355.             }
    356.         }
    357.  
    358.         /// <summary>
    359.         /// Should the mobile keyboard input be hidden.
    360.         /// </summary>
    361.         public bool shouldHideMobileInput
    362.         {
    363.             get
    364.             {
    365.                 switch (Application.platform)
    366.                 {
    367.                     case RuntimePlatform.Android:
    368.                     case RuntimePlatform.IPhonePlayer:
    369.                     case RuntimePlatform.tvOS:
    370.                         return m_HideMobileInput;
    371.                     default:
    372.                         return true;
    373.                 }
    374.             }
    375.  
    376.             set
    377.             {
    378.                 switch(Application.platform)
    379.                 {
    380.                     case RuntimePlatform.Android:
    381.                     case RuntimePlatform.IPhonePlayer:
    382.                     case RuntimePlatform.tvOS:
    383.                         SetPropertyUtility.SetStruct(ref m_HideMobileInput, value);
    384.                         break;
    385.                     default:
    386.                         m_HideMobileInput = true;
    387.                         break;
    388.                 }
    389.             }
    390.         }
    391.  
    392.         public bool shouldHideSoftKeyboard
    393.         {
    394.             get
    395.             {
    396.                 switch (Application.platform)
    397.                 {
    398.                     case RuntimePlatform.Android:
    399.                     case RuntimePlatform.IPhonePlayer:
    400.                     case RuntimePlatform.tvOS:
    401.                     case RuntimePlatform.WSAPlayerX86:
    402.                     case RuntimePlatform.WSAPlayerX64:
    403.                     case RuntimePlatform.WSAPlayerARM:
    404.                         return m_HideSoftKeyboard;
    405.                     default:
    406.                         return true;
    407.                 }
    408.             }
    409.  
    410.             set
    411.             {
    412.                 switch (Application.platform)
    413.                 {
    414.                     case RuntimePlatform.Android:
    415.                     case RuntimePlatform.IPhonePlayer:
    416.                     case RuntimePlatform.tvOS:
    417.                     case RuntimePlatform.WSAPlayerX86:
    418.                     case RuntimePlatform.WSAPlayerX64:
    419.                     case RuntimePlatform.WSAPlayerARM:
    420.                         SetPropertyUtility.SetStruct(ref m_HideSoftKeyboard, value);
    421.                         break;
    422.                     default:
    423.                         m_HideSoftKeyboard = true;
    424.                         break;
    425.                 }
    426.              
    427.                 if (m_HideSoftKeyboard == true && m_SoftKeyboard != null && TouchScreenKeyboard.isSupported && m_SoftKeyboard.active)
    428.                 {
    429.                     m_SoftKeyboard.active = false;
    430.                     m_SoftKeyboard = null;
    431.                 }
    432.             }
    433.         }
    434.  
    435.         private bool isKeyboardUsingEvents()
    436.         {
    437.             switch (Application.platform)
    438.             {
    439.                 case RuntimePlatform.Android:
    440.                 case RuntimePlatform.IPhonePlayer:
    441.                 case RuntimePlatform.tvOS:
    442.                     return false;
    443.                 default:
    444.                     return true;
    445.             }
    446.         }
    447.  
    448.         /// <summary>
    449.         /// Input field's current text value. This is not necessarily the same as what is visible on screen.
    450.         /// </summary>
    451.         /// <remarks>
    452.         /// Note that null is invalid value  for InputField.text.
    453.         /// </remarks>
    454.         /// <example>
    455.         /// <code>
    456.         /// using UnityEngine;
    457.         /// using System.Collections;
    458.         /// using UnityEngine.UI; // Required when Using UI elements.
    459.         ///
    460.         /// public class Example : MonoBehaviour
    461.         /// {
    462.         ///     public InputField mainInputField;
    463.         ///
    464.         ///     public void Start()
    465.         ///     {
    466.         ///         mainInputField.text = "Enter Text Here...";
    467.         ///     }
    468.         /// }
    469.         /// </code>
    470.         /// </example>
    471.         public string text
    472.         {
    473.             get
    474.             {
    475.                 return m_Text;
    476.             }
    477.             set
    478.             {
    479.                 SetText(value);
    480.             }
    481.         }
    482.  
    483.         /// <summary>
    484.         /// Set Input field's current text value without invoke onValueChanged. This is not necessarily the same as what is visible on screen.
    485.         /// </summary>
    486.         public void SetTextWithoutNotify(string input)
    487.         {
    488.             SetText(input, false);
    489.         }
    490.  
    491.         void SetText(string value, bool sendCallback = true)
    492.         {
    493.             if (this.text == value)
    494.                 return;
    495.  
    496.             if (value == null)
    497.                 value = "";
    498.  
    499.             value = value.Replace("\0", string.Empty); // remove embedded nulls
    500.  
    501.             m_Text = value;
    502.  
    503.             /*
    504.             if (m_LineType == LineType.SingleLine)
    505.                 value = value.Replace("\n", "").Replace("\t", "");
    506.  
    507.             // If we have an input validator, validate the input and apply the character limit at the same time.
    508.             if (onValidateInput != null || characterValidation != CharacterValidation.None)
    509.             {
    510.                 m_Text = "";
    511.                 OnValidateInput validatorMethod = onValidateInput ?? Validate;
    512.                 m_CaretPosition = m_CaretSelectPosition = value.Length;
    513.                 int charactersToCheck = characterLimit > 0 ? Math.Min(characterLimit, value.Length) : value.Length;
    514.                 for (int i = 0; i < charactersToCheck; ++i)
    515.                 {
    516.                     char c = validatorMethod(m_Text, m_Text.Length, value[i]);
    517.                     if (c != 0)
    518.                         m_Text += c;
    519.                 }
    520.             }
    521.             else
    522.             {
    523.                 m_Text = characterLimit > 0 && value.Length > characterLimit ? value.Substring(0, characterLimit) : value;
    524.             }
    525.             */
    526.  
    527.             #if UNITY_EDITOR
    528.             if (!Application.isPlaying)
    529.             {
    530.                 SendOnValueChangedAndUpdateLabel();
    531.                 return;
    532.             }
    533.             #endif
    534.  
    535.             if (m_SoftKeyboard != null)
    536.                 m_SoftKeyboard.text = m_Text;
    537.  
    538.             if (m_StringPosition > m_Text.Length)
    539.                 m_StringPosition = m_StringSelectPosition = m_Text.Length;
    540.             else if (m_StringSelectPosition > m_Text.Length)
    541.                 m_StringSelectPosition = m_Text.Length;
    542.  
    543.             // Set RectTransform relative position to top of viewport.
    544.             AdjustTextPositionRelativeToViewport(0);
    545.  
    546.             m_forceRectTransformAdjustment = true;
    547.  
    548.             m_IsTextComponentUpdateRequired = true;
    549.             UpdateLabel();
    550.  
    551.             if (sendCallback)
    552.                 SendOnValueChanged();
    553.         }
    554.  
    555.  
    556.         public bool isFocused
    557.         {
    558.             get { return m_AllowInput; }
    559.         }
    560.  
    561.         public float caretBlinkRate
    562.         {
    563.             get { return m_CaretBlinkRate; }
    564.             set
    565.             {
    566.                 if (SetPropertyUtility.SetStruct(ref m_CaretBlinkRate, value))
    567.                 {
    568.                     if (m_AllowInput)
    569.                         SetCaretActive();
    570.                 }
    571.             }
    572.         }
    573.  
    574.         public int caretWidth { get { return m_CaretWidth; } set { if (SetPropertyUtility.SetStruct(ref m_CaretWidth, value)) MarkGeometryAsDirty(); } }
    575.  
    576.         public RectTransform textViewport { get { return m_TextViewport; } set { SetPropertyUtility.SetClass(ref m_TextViewport, value); } }
    577.  
    578.         public TMP_Text textComponent
    579.         {
    580.             get { return m_TextComponent; }
    581.             set
    582.             {
    583.                 if (SetPropertyUtility.SetClass(ref m_TextComponent, value))
    584.                 {
    585.                     SetTextComponentWrapMode();
    586.                 }
    587.             }
    588.         }
    589.  
    590.         //public TMP_Text placeholderTextComponent { get { return m_PlaceholderTextComponent; } set { SetPropertyUtility.SetClass(ref m_PlaceholderTextComponent, value); } }
    591.  
    592.         public Graphic placeholder { get { return m_Placeholder; } set { SetPropertyUtility.SetClass(ref m_Placeholder, value); } }
    593.  
    594.         public Scrollbar verticalScrollbar
    595.         {
    596.             get { return m_VerticalScrollbar; }
    597.             set
    598.             {
    599.                 if (m_VerticalScrollbar != null)
    600.                     m_VerticalScrollbar.onValueChanged.RemoveListener(OnScrollbarValueChange);
    601.  
    602.                 SetPropertyUtility.SetClass(ref m_VerticalScrollbar, value);
    603.  
    604.                 if (m_VerticalScrollbar)
    605.                 {
    606.                     m_VerticalScrollbar.onValueChanged.AddListener(OnScrollbarValueChange);
    607.                  
    608.                 }
    609.             }
    610.         }
    611.  
    612.         public float scrollSensitivity { get { return m_ScrollSensitivity; } set { if (SetPropertyUtility.SetStruct(ref m_ScrollSensitivity, value)) MarkGeometryAsDirty(); } }
    613.  
    614.         public Color caretColor { get { return customCaretColor ? m_CaretColor : textComponent.color; } set { if (SetPropertyUtility.SetColor(ref m_CaretColor, value)) MarkGeometryAsDirty(); } }
    615.  
    616.         public bool customCaretColor { get { return m_CustomCaretColor; } set { if (m_CustomCaretColor != value) { m_CustomCaretColor = value; MarkGeometryAsDirty(); } } }
    617.  
    618.         public Color selectionColor { get { return m_SelectionColor; } set { if (SetPropertyUtility.SetColor(ref m_SelectionColor, value)) MarkGeometryAsDirty(); } }
    619.  
    620.         public SubmitEvent onEndEdit { get { return m_OnEndEdit; } set { SetPropertyUtility.SetClass(ref m_OnEndEdit, value); } }
    621.  
    622.         public SubmitEvent onSubmit { get { return m_OnSubmit; } set { SetPropertyUtility.SetClass(ref m_OnSubmit, value); } }
    623.  
    624.         public SelectionEvent onSelect { get { return m_OnSelect; } set { SetPropertyUtility.SetClass(ref m_OnSelect, value); } }
    625.  
    626.         public SelectionEvent onDeselect { get { return m_OnDeselect; } set { SetPropertyUtility.SetClass(ref m_OnDeselect, value); } }
    627.  
    628.         public TextSelectionEvent onTextSelection { get { return m_OnTextSelection; } set { SetPropertyUtility.SetClass(ref m_OnTextSelection, value); } }
    629.  
    630.         public TextSelectionEvent onEndTextSelection { get { return m_OnEndTextSelection; } set { SetPropertyUtility.SetClass(ref m_OnEndTextSelection, value); } }
    631.  
    632.         public OnChangeEvent onValueChanged { get { return m_OnValueChanged; } set { SetPropertyUtility.SetClass(ref m_OnValueChanged, value); } }
    633.  
    634.         public TouchScreenKeyboardEvent onTouchScreenKeyboardStatusChanged { get { return m_OnTouchScreenKeyboardStatusChanged; } set { SetPropertyUtility.SetClass(ref m_OnTouchScreenKeyboardStatusChanged, value); } }
    635.  
    636.         public OnValidateInput onValidateInput { get { return m_OnValidateInput; } set { SetPropertyUtility.SetClass(ref m_OnValidateInput, value); } }
    637.  
    638.         public int characterLimit
    639.         {
    640.             get { return m_CharacterLimit; }
    641.             set
    642.             {
    643.                 if (SetPropertyUtility.SetStruct(ref m_CharacterLimit, Math.Max(0, value)))
    644.                 {
    645.                     UpdateLabel();
    646.                     if (m_SoftKeyboard != null)
    647.                         m_SoftKeyboard.characterLimit = value;
    648.                 }
    649.             }
    650.         }
    651.  
    652.         //public bool isInteractableControl { set { if ( } }
    653.  
    654.         /// <summary>
    655.         /// Set the point size on both Placeholder and Input text object.
    656.         /// </summary>
    657.         public float pointSize
    658.         {
    659.             get { return m_GlobalPointSize; }
    660.             set {
    661.                     if (SetPropertyUtility.SetStruct(ref m_GlobalPointSize, Math.Max(0, value)))
    662.                     {
    663.                         SetGlobalPointSize(m_GlobalPointSize);
    664.                         UpdateLabel();
    665.                     }
    666.                 }
    667.         }
    668.  
    669.         /// <summary>
    670.         /// Sets the Font Asset on both Placeholder and Input child objects.
    671.         /// </summary>
    672.         public TMP_FontAsset fontAsset
    673.         {
    674.             get { return m_GlobalFontAsset; }
    675.             set
    676.             {
    677.                 if (SetPropertyUtility.SetClass(ref m_GlobalFontAsset, value))
    678.                 {
    679.                     SetGlobalFontAsset(m_GlobalFontAsset);
    680.                     UpdateLabel();
    681.                 }
    682.             }
    683.         }
    684.         [SerializeField]
    685.         protected TMP_FontAsset m_GlobalFontAsset;
    686.  
    687.         /// <summary>
    688.         /// Determines if the whole text will be selected when focused.
    689.         /// </summary>
    690.         public bool onFocusSelectAll
    691.         {
    692.             get { return m_OnFocusSelectAll; }
    693.             set { m_OnFocusSelectAll = value; }
    694.         }
    695.         [SerializeField]
    696.         protected bool m_OnFocusSelectAll = true;
    697.         protected bool m_isSelectAll;
    698.  
    699.         /// <summary>
    700.         /// Determines if the text and caret position as well as selection will be reset when the input field is deactivated.
    701.         /// </summary>
    702.         public bool resetOnDeActivation
    703.         {
    704.             get { return m_ResetOnDeActivation; }
    705.             set { m_ResetOnDeActivation = value; }
    706.         }
    707.         [SerializeField]
    708.         protected bool m_ResetOnDeActivation = true;
    709.         private bool m_SelectionStillActive = false;
    710.         private bool m_ReleaseSelection = false;
    711.  
    712.         private GameObject m_SelectedObject;
    713.  
    714.         /// <summary>
    715.         /// Controls whether the original text is restored when pressing "ESC".
    716.         /// </summary>
    717.         public bool restoreOriginalTextOnEscape
    718.         {
    719.             get { return m_RestoreOriginalTextOnEscape; }
    720.             set { m_RestoreOriginalTextOnEscape = value; }
    721.         }
    722.         [SerializeField]
    723.         private bool m_RestoreOriginalTextOnEscape = true;
    724.  
    725.         /// <summary>
    726.         /// Is Rich Text editing allowed?
    727.         /// </summary>
    728.         public bool isRichTextEditingAllowed
    729.         {
    730.             get { return m_isRichTextEditingAllowed; }
    731.             set { m_isRichTextEditingAllowed = value; }
    732.         }
    733.         [SerializeField]
    734.         protected bool m_isRichTextEditingAllowed = false;
    735.  
    736.  
    737.         // Content Type related
    738.         public ContentType contentType { get { return m_ContentType; } set { if (SetPropertyUtility.SetStruct(ref m_ContentType, value)) EnforceContentType(); } }
    739.  
    740.         public LineType lineType
    741.         {
    742.             get { return m_LineType; }
    743.             set
    744.             {
    745.                 if (SetPropertyUtility.SetStruct(ref m_LineType, value))
    746.                 {
    747.                     SetToCustomIfContentTypeIsNot(ContentType.Standard, ContentType.Autocorrected);
    748.                     SetTextComponentWrapMode();
    749.                 }
    750.             }
    751.         }
    752.  
    753.         /// <summary>
    754.         /// Limits the number of lines of text in the Input Field.
    755.         /// </summary>
    756.         public int lineLimit
    757.         {
    758.             get { return m_LineLimit; }
    759.             set
    760.             {
    761.                 if (m_LineType == LineType.SingleLine)
    762.                     m_LineLimit = 1;
    763.                 else
    764.                     SetPropertyUtility.SetStruct(ref m_LineLimit, value);
    765.  
    766.             }
    767.         }
    768.         [SerializeField]
    769.         protected int m_LineLimit = 0;
    770.  
    771.         public InputType inputType { get { return m_InputType; } set { if (SetPropertyUtility.SetStruct(ref m_InputType, value)) SetToCustom(); } }
    772.  
    773.         public TouchScreenKeyboardType keyboardType
    774.         {
    775.             get { return m_KeyboardType; }
    776.             set
    777.             {
    778.                 if (SetPropertyUtility.SetStruct(ref m_KeyboardType, value))
    779.                     SetToCustom();
    780.             }
    781.         }
    782.  
    783.         public CharacterValidation characterValidation { get { return m_CharacterValidation; } set { if (SetPropertyUtility.SetStruct(ref m_CharacterValidation, value)) SetToCustom(); } }
    784.  
    785.         /// <summary>
    786.         /// Sets the Input Validation to use a Custom Input Validation script.
    787.         /// </summary>
    788.         public TMP_InputValidator inputValidator
    789.         {
    790.             get { return m_InputValidator; }
    791.             set {  if (SetPropertyUtility.SetClass(ref m_InputValidator, value)) SetToCustom(CharacterValidation.CustomValidator); }
    792.         }
    793.         [SerializeField]
    794.         protected TMP_InputValidator m_InputValidator = null;
    795.  
    796.         public bool readOnly { get { return m_ReadOnly; } set { m_ReadOnly = value; } }
    797.  
    798.         public bool richText { get { return m_RichText; } set { m_RichText = value; SetTextComponentRichTextMode(); } }
    799.  
    800.         // Derived property
    801.         public bool multiLine { get { return m_LineType == LineType.MultiLineNewline || lineType == LineType.MultiLineSubmit; } }
    802.         // Not shown in Inspector.
    803.         public char asteriskChar { get { return m_AsteriskChar; } set { if (SetPropertyUtility.SetStruct(ref m_AsteriskChar, value)) UpdateLabel(); } }
    804.         public bool wasCanceled { get { return m_WasCanceled; } }
    805.  
    806.  
    807.         protected void ClampStringPos(ref int pos)
    808.         {
    809.             if (pos < 0)
    810.                 pos = 0;
    811.             else if (pos > text.Length)
    812.                 pos = text.Length;
    813.         }
    814.  
    815.         protected void ClampCaretPos(ref int pos)
    816.         {
    817.             if (pos < 0)
    818.                 pos = 0;
    819.             else if (pos > m_TextComponent.textInfo.characterCount - 1)
    820.                 pos = m_TextComponent.textInfo.characterCount - 1;
    821.         }
    822.  
    823.         /// <summary>
    824.         /// Current position of the cursor.
    825.         /// Getters are public Setters are protected
    826.         /// </summary>
    827.  
    828.         protected int caretPositionInternal { get { return m_CaretPosition + compositionString.Length; } set { m_CaretPosition = value; ClampCaretPos(ref m_CaretPosition); } }
    829.         protected int stringPositionInternal { get { return m_StringPosition + compositionString.Length; } set { m_StringPosition = value; ClampStringPos(ref m_StringPosition); } }
    830.  
    831.         protected int caretSelectPositionInternal { get { return m_CaretSelectPosition + compositionString.Length; } set { m_CaretSelectPosition = value; ClampCaretPos(ref m_CaretSelectPosition); } }
    832.         protected int stringSelectPositionInternal { get { return m_StringSelectPosition + compositionString.Length; } set { m_StringSelectPosition = value; ClampStringPos(ref m_StringSelectPosition); } }
    833.  
    834.         private bool hasSelection { get { return stringPositionInternal != stringSelectPositionInternal; } }
    835.         private bool m_isSelected;
    836.         private bool m_IsStringPositionDirty;
    837.         private bool m_IsCaretPositionDirty;
    838.         private bool m_forceRectTransformAdjustment;
    839.  
    840.         /// <summary>
    841.         /// Get: Returns the focus position as thats the position that moves around even during selection.
    842.         /// Set: Set both the anchor and focus position such that a selection doesn't happen
    843.         /// </summary>
    844.         public int caretPosition
    845.         {
    846.             get { return caretSelectPositionInternal; }
    847.             set { selectionAnchorPosition = value; selectionFocusPosition = value; m_IsStringPositionDirty = true; }
    848.         }
    849.  
    850.         /// <summary>
    851.         /// Get: Returns the fixed position of selection
    852.         /// Set: If compositionString is 0 set the fixed position
    853.         /// </summary>
    854.         public int selectionAnchorPosition
    855.         {
    856.             get
    857.             {
    858.                 return caretPositionInternal;
    859.             }
    860.  
    861.             set
    862.             {
    863.                 if (compositionString.Length != 0)
    864.                     return;
    865.  
    866.                 caretPositionInternal = value;
    867.                 m_IsStringPositionDirty = true;
    868.             }
    869.         }
    870.  
    871.         /// <summary>
    872.         /// Get: Returns the variable position of selection
    873.         /// Set: If compositionString is 0 set the variable position
    874.         /// </summary>
    875.         public int selectionFocusPosition
    876.         {
    877.             get
    878.             {
    879.                 return caretSelectPositionInternal;
    880.             }
    881.             set
    882.             {
    883.                 if (compositionString.Length != 0)
    884.                     return;
    885.  
    886.                 caretSelectPositionInternal = value;
    887.                 m_IsStringPositionDirty = true;
    888.             }
    889.         }
    890.  
    891.  
    892.         /// <summary>
    893.         ///
    894.         /// </summary>
    895.         public int stringPosition
    896.         {
    897.             get { return stringSelectPositionInternal; }
    898.             set { selectionStringAnchorPosition = value; selectionStringFocusPosition = value; m_IsCaretPositionDirty = true; }
    899.         }
    900.  
    901.  
    902.         /// <summary>
    903.         /// The fixed position of the selection in the raw string which may contains rich text.
    904.         /// </summary>
    905.         public int selectionStringAnchorPosition
    906.         {
    907.             get
    908.             {
    909.                 return stringPositionInternal;
    910.             }
    911.  
    912.             set
    913.             {
    914.                 if (compositionString.Length != 0)
    915.                     return;
    916.  
    917.                 stringPositionInternal = value;
    918.                 m_IsCaretPositionDirty = true;
    919.             }
    920.         }
    921.  
    922.  
    923.         /// <summary>
    924.         /// The variable position of the selection in the raw string which may contains rich text.
    925.         /// </summary>
    926.         public int selectionStringFocusPosition
    927.         {
    928.             get
    929.             {
    930.                 return stringSelectPositionInternal;
    931.             }
    932.             set
    933.             {
    934.                 if (compositionString.Length != 0)
    935.                     return;
    936.  
    937.                 stringSelectPositionInternal = value;
    938.                 m_IsCaretPositionDirty = true;
    939.             }
    940.         }
    941.  
    942.  
    943.         #if UNITY_EDITOR
    944.         // Remember: This is NOT related to text validation!
    945.         // This is Unity's own OnValidate method which is invoked when changing values in the Inspector.
    946.         protected override void OnValidate()
    947.         {
    948.             base.OnValidate();
    949.             EnforceContentType();
    950.  
    951.             m_CharacterLimit = Math.Max(0, m_CharacterLimit);
    952.  
    953.             //This can be invoked before OnEnabled is called. So we shouldn't be accessing other objects, before OnEnable is called.
    954.             if (!IsActive())
    955.                 return;
    956.  
    957.             SetTextComponentRichTextMode();
    958.  
    959.             UpdateLabel();
    960.             if (m_AllowInput)
    961.                 SetCaretActive();
    962.         }
    963.         #endif
    964.  
    965.         protected override void OnEnable()
    966.         {
    967.             //Debug.Log("*** OnEnable() *** - " + this.name);
    968.  
    969.             base.OnEnable();
    970.  
    971.             if (m_Text == null)
    972.                 m_Text = string.Empty;
    973.  
    974.             if (Application.isPlaying)
    975.             {
    976.                 if (m_CachedInputRenderer == null && m_TextComponent != null)
    977.                 {
    978.                     // Check if Input Field is driven by any layout components
    979.                     m_IsDrivenByLayoutComponents = GetComponent<ILayoutController>() != null ? true : false;
    980.  
    981.                     GameObject go = new GameObject(transform.name + " Input Caret", typeof(RectTransform));
    982.  
    983.                     // Add MaskableGraphic Component
    984.                     TMP_SelectionCaret caret = go.AddComponent<TMP_SelectionCaret>();
    985.                     caret.raycastTarget = false;
    986.                     caret.color = Color.clear;
    987.  
    988.                     go.hideFlags = HideFlags.DontSave;
    989.                     go.transform.SetParent(m_TextComponent.transform.parent);
    990.                     go.transform.SetAsFirstSibling();
    991.                     go.layer = gameObject.layer;
    992.  
    993.                     caretRectTrans = go.GetComponent<RectTransform>();
    994.                     m_CachedInputRenderer = go.GetComponent<CanvasRenderer>();
    995.                     m_CachedInputRenderer.SetMaterial(Graphic.defaultGraphicMaterial, Texture2D.whiteTexture);
    996.  
    997.                     // Needed as if any layout is present we want the caret to always be the same as the text area.
    998.                     go.AddComponent<LayoutElement>().ignoreLayout = true;
    999.  
    1000.                     AssignPositioningIfNeeded();
    1001.                 }
    1002.             }
    1003.  
    1004.             // If we have a cached renderer then we had OnDisable called so just restore the material.
    1005.             if (m_CachedInputRenderer != null)
    1006.                 m_CachedInputRenderer.SetMaterial(Graphic.defaultGraphicMaterial, Texture2D.whiteTexture);
    1007.  
    1008.             if (m_TextComponent != null)
    1009.             {
    1010.                 m_TextComponent.RegisterDirtyVerticesCallback(MarkGeometryAsDirty);
    1011.                 m_TextComponent.RegisterDirtyVerticesCallback(UpdateLabel);
    1012.                 //m_TextComponent.ignoreRectMaskCulling = multiLine;
    1013.  
    1014.                 //m_DefaultTransformPosition = m_TextComponent.rectTransform.localPosition;
    1015.  
    1016.                 // Cache reference to Vertical Scrollbar RectTransform and add listener.
    1017.                 if (m_VerticalScrollbar != null)
    1018.                 {
    1019.                     m_TextComponent.ignoreRectMaskCulling = true;
    1020.                     m_VerticalScrollbar.onValueChanged.AddListener(OnScrollbarValueChange);
    1021.                 }
    1022.  
    1023.                 UpdateLabel();
    1024.             }
    1025.  
    1026.             // Subscribe to event fired when text object has been regenerated.
    1027.             TMPro_EventManager.TEXT_CHANGED_EVENT.Add(ON_TEXT_CHANGED);
    1028.         }
    1029.  
    1030.         protected override void OnDisable()
    1031.         {
    1032.             // the coroutine will be terminated, so this will ensure it restarts when we are next activated
    1033.             m_BlinkCoroutine = null;
    1034.  
    1035.             DeactivateInputField();
    1036.             if (m_TextComponent != null)
    1037.             {
    1038.                 m_TextComponent.UnregisterDirtyVerticesCallback(MarkGeometryAsDirty);
    1039.                 m_TextComponent.UnregisterDirtyVerticesCallback(UpdateLabel);
    1040.  
    1041.                 if (m_VerticalScrollbar != null)
    1042.                     m_VerticalScrollbar.onValueChanged.RemoveListener(OnScrollbarValueChange);
    1043.  
    1044.             }
    1045.             CanvasUpdateRegistry.UnRegisterCanvasElementForRebuild(this);
    1046.  
    1047.             // Clear needs to be called otherwise sync never happens as the object is disabled.
    1048.             if (m_CachedInputRenderer != null)
    1049.                 m_CachedInputRenderer.Clear();
    1050.  
    1051.             if (m_Mesh != null)
    1052.                 DestroyImmediate(m_Mesh);
    1053.             m_Mesh = null;
    1054.  
    1055.             // Unsubscribe to event triggered when text object has been regenerated
    1056.             TMPro_EventManager.TEXT_CHANGED_EVENT.Remove(ON_TEXT_CHANGED);
    1057.  
    1058.             base.OnDisable();
    1059.         }
    1060.  
    1061.  
    1062.         /// <summary>
    1063.         /// Method used to update the tracking of the caret position when the text object has been regenerated.
    1064.         /// </summary>
    1065.         /// <param name="obj"></param>
    1066.         private void ON_TEXT_CHANGED(UnityEngine.Object obj)
    1067.         {
    1068.             if (obj == m_TextComponent && Application.isPlaying && compositionString.Length == 0)
    1069.             {
    1070.                 caretPositionInternal = GetCaretPositionFromStringIndex(stringPositionInternal);
    1071.                 caretSelectPositionInternal = GetCaretPositionFromStringIndex(stringSelectPositionInternal);
    1072.  
    1073.                 #if TMP_DEBUG_MODE
    1074.                     Debug.Log("Caret Position: " + caretPositionInternal + " Selection Position: " + caretSelectPositionInternal + "  String Position: " + stringPositionInternal + " String Select Position: " + stringSelectPositionInternal);
    1075.                 #endif
    1076.             }
    1077.         }
    1078.  
    1079.  
    1080.         IEnumerator CaretBlink()
    1081.         {
    1082.             // Always ensure caret is initially visible since it can otherwise be confusing for a moment.
    1083.             m_CaretVisible = true;
    1084.             yield return null;
    1085.  
    1086.             while ((isFocused || m_SelectionStillActive) && m_CaretBlinkRate > 0)
    1087.             {
    1088.                 // the blink rate is expressed as a frequency
    1089.                 float blinkPeriod = 1f / m_CaretBlinkRate;
    1090.  
    1091.                 // the caret should be ON if we are in the first half of the blink period
    1092.                 bool blinkState = (Time.unscaledTime - m_BlinkStartTime) % blinkPeriod < blinkPeriod / 2;
    1093.                 if (m_CaretVisible != blinkState)
    1094.                 {
    1095.                     m_CaretVisible = blinkState;
    1096.                     if (!hasSelection)
    1097.                         MarkGeometryAsDirty();
    1098.                 }
    1099.  
    1100.                 // Then wait again.
    1101.                 yield return null;
    1102.             }
    1103.             m_BlinkCoroutine = null;
    1104.         }
    1105.  
    1106.         void SetCaretVisible()
    1107.         {
    1108.             if (!m_AllowInput)
    1109.                 return;
    1110.  
    1111.             m_CaretVisible = true;
    1112.             m_BlinkStartTime = Time.unscaledTime;
    1113.             SetCaretActive();
    1114.         }
    1115.  
    1116.         // SetCaretActive will not set the caret immediately visible - it will wait for the next time to blink.
    1117.         // However, it will handle things correctly if the blink speed changed from zero to non-zero or non-zero to zero.
    1118.         void SetCaretActive()
    1119.         {
    1120.             if (!m_AllowInput)
    1121.                 return;
    1122.  
    1123.             if (m_CaretBlinkRate > 0.0f)
    1124.             {
    1125.                 if (m_BlinkCoroutine == null)
    1126.                     m_BlinkCoroutine = StartCoroutine(CaretBlink());
    1127.             }
    1128.             else
    1129.             {
    1130.                 m_CaretVisible = true;
    1131.             }
    1132.         }
    1133.  
    1134.         protected void OnFocus()
    1135.         {
    1136.             if (m_OnFocusSelectAll)
    1137.                 SelectAll();
    1138.         }
    1139.  
    1140.         protected void SelectAll()
    1141.         {
    1142.             m_isSelectAll = true;
    1143.             stringPositionInternal = text.Length;
    1144.             stringSelectPositionInternal = 0;
    1145.         }
    1146.  
    1147.         /// <summary>
    1148.         /// Move to the end of the text.
    1149.         /// </summary>
    1150.         /// <param name="shift"></param>
    1151.         public void MoveTextEnd(bool shift)
    1152.         {
    1153.             if (m_isRichTextEditingAllowed)
    1154.             {
    1155.                 int position = text.Length;
    1156.  
    1157.                 if (shift)
    1158.                 {
    1159.                     stringSelectPositionInternal = position;
    1160.                 }
    1161.                 else
    1162.                 {
    1163.                     stringPositionInternal = position;
    1164.                     stringSelectPositionInternal = stringPositionInternal;
    1165.                 }
    1166.             }
    1167.             else
    1168.             {
    1169.                 int position = m_TextComponent.textInfo.characterCount - 1;
    1170.  
    1171.                 if (shift)
    1172.                 {
    1173.                     caretSelectPositionInternal = position;
    1174.                     stringSelectPositionInternal = GetStringIndexFromCaretPosition(position);
    1175.                 }
    1176.                 else
    1177.                 {
    1178.                     caretPositionInternal = caretSelectPositionInternal = position;
    1179.                     stringSelectPositionInternal = stringPositionInternal = GetStringIndexFromCaretPosition(position);
    1180.                 }
    1181.             }
    1182.  
    1183.             UpdateLabel();
    1184.         }
    1185.  
    1186.         /// <summary>
    1187.         /// Move to the start of the text.
    1188.         /// </summary>
    1189.         /// <param name="shift"></param>
    1190.         public void MoveTextStart(bool shift)
    1191.         {
    1192.             if (m_isRichTextEditingAllowed)
    1193.             {
    1194.                 int position = 0;
    1195.  
    1196.                 if (shift)
    1197.                 {
    1198.                     stringSelectPositionInternal = position;
    1199.                 }
    1200.                 else
    1201.                 {
    1202.                     stringPositionInternal = position;
    1203.                     stringSelectPositionInternal = stringPositionInternal;
    1204.                 }
    1205.             }
    1206.             else
    1207.             {
    1208.                 int position = 0;
    1209.  
    1210.                 if (shift)
    1211.                 {
    1212.                     caretSelectPositionInternal = position;
    1213.                     stringSelectPositionInternal = GetStringIndexFromCaretPosition(position);
    1214.                 }
    1215.                 else
    1216.                 {
    1217.                     caretPositionInternal = caretSelectPositionInternal = position;
    1218.                     stringSelectPositionInternal = stringPositionInternal = GetStringIndexFromCaretPosition(position);
    1219.                 }
    1220.             }
    1221.  
    1222.             UpdateLabel();
    1223.         }
    1224.  
    1225.  
    1226.         /// <summary>
    1227.         /// Move to the end of the current line of text.
    1228.         /// </summary>
    1229.         /// <param name="shift"></param>
    1230.         public void MoveToEndOfLine(bool shift, bool ctrl)
    1231.         {
    1232.             // Get the line the caret is currently located on.
    1233.             int currentLine = m_TextComponent.textInfo.characterInfo[caretPositionInternal].lineNumber;
    1234.  
    1235.             // Get the last character of the given line.
    1236.             int characterIndex = ctrl == true ? m_TextComponent.textInfo.characterCount - 1 : m_TextComponent.textInfo.lineInfo[currentLine].lastCharacterIndex;
    1237.  
    1238.             int position = m_TextComponent.textInfo.characterInfo[characterIndex].index;
    1239.  
    1240.             if (shift)
    1241.             {
    1242.                 stringSelectPositionInternal = position;
    1243.  
    1244.                 caretSelectPositionInternal = characterIndex;
    1245.             }
    1246.             else
    1247.             {
    1248.                 stringPositionInternal = position;
    1249.                 stringSelectPositionInternal = stringPositionInternal;
    1250.  
    1251.                 caretSelectPositionInternal = caretPositionInternal = characterIndex;
    1252.             }
    1253.  
    1254.             UpdateLabel();
    1255.         }
    1256.  
    1257.         /// <summary>
    1258.         /// Move to the start of the current line of text.
    1259.         /// </summary>
    1260.         /// <param name="shift"></param>
    1261.         public void MoveToStartOfLine(bool shift, bool ctrl)
    1262.         {
    1263.             // Get the line the caret is currently located on.
    1264.             int currentLine = m_TextComponent.textInfo.characterInfo[caretPositionInternal].lineNumber;
    1265.  
    1266.             // Get the first character of the given line.
    1267.             int characterIndex = ctrl == true ? 0 : m_TextComponent.textInfo.lineInfo[currentLine].firstCharacterIndex;
    1268.  
    1269.             int position = 0;
    1270.             if (characterIndex > 0)
    1271.                 position = m_TextComponent.textInfo.characterInfo[characterIndex - 1].index + m_TextComponent.textInfo.characterInfo[characterIndex - 1].stringLength;
    1272.  
    1273.             if (shift)
    1274.             {
    1275.                 stringSelectPositionInternal = position;
    1276.  
    1277.                 caretSelectPositionInternal = characterIndex;
    1278.             }
    1279.             else
    1280.             {
    1281.                 stringPositionInternal = position;
    1282.                 stringSelectPositionInternal = stringPositionInternal;
    1283.  
    1284.                 caretSelectPositionInternal = caretPositionInternal = characterIndex;
    1285.             }
    1286.  
    1287.             UpdateLabel();
    1288.         }
    1289.  
    1290.  
    1291.         static string clipboard
    1292.         {
    1293.             get
    1294.             {
    1295.                 return GUIUtility.systemCopyBuffer;
    1296.             }
    1297.             set
    1298.             {
    1299.                 GUIUtility.systemCopyBuffer = value;
    1300.             }
    1301.         }
    1302.  
    1303.         private bool InPlaceEditing()
    1304.         {
    1305.             if (m_TouchKeyboardAllowsInPlaceEditing || (TouchScreenKeyboard.isSupported && (Application.platform == RuntimePlatform.WSAPlayerX86 || Application.platform == RuntimePlatform.WSAPlayerX64 || Application.platform == RuntimePlatform.WSAPlayerARM)))
    1306.                 return true;
    1307.  
    1308.             if (TouchScreenKeyboard.isSupported && shouldHideSoftKeyboard)
    1309.                 return true;
    1310.  
    1311.             if (TouchScreenKeyboard.isSupported && shouldHideSoftKeyboard == false && shouldHideMobileInput == false)
    1312.                 return false;
    1313.  
    1314.             return true;
    1315.         }
    1316.  
    1317.         void UpdateStringPositionFromKeyboard()
    1318.         {
    1319.             // TODO: Might want to add null check here.
    1320.             var selectionRange = m_SoftKeyboard.selection;
    1321.  
    1322.             if (selectionRange.start == 0 && selectionRange.length == 0)
    1323.                 return;
    1324.  
    1325.             var selectionStart = selectionRange.start;
    1326.             var selectionEnd = selectionRange.end;
    1327.  
    1328.             var stringPositionChanged = false;
    1329.  
    1330.             if (stringPositionInternal != selectionStart)
    1331.             {
    1332.                 stringPositionChanged = true;
    1333.                 stringPositionInternal = selectionStart;
    1334.  
    1335.                 caretPositionInternal = GetCaretPositionFromStringIndex(stringPositionInternal);
    1336.             }
    1337.  
    1338.             if (stringSelectPositionInternal != selectionEnd)
    1339.             {
    1340.                 stringSelectPositionInternal = selectionEnd;
    1341.                 stringPositionChanged = true;
    1342.  
    1343.                 caretSelectPositionInternal = GetCaretPositionFromStringIndex(stringSelectPositionInternal);
    1344.             }
    1345.  
    1346.             if (stringPositionChanged)
    1347.             {
    1348.                 m_BlinkStartTime = Time.unscaledTime;
    1349.  
    1350.                 UpdateLabel();
    1351.             }
    1352.         }
    1353.  
    1354.         /// <summary>
    1355.         /// Update the text based on input.
    1356.         /// </summary>
    1357.         // TODO: Make LateUpdate a coroutine instead. Allows us to control the update to only be when the field is active.
    1358.         protected virtual void LateUpdate()
    1359.         {
    1360.             // Only activate if we are not already activated.
    1361.             if (m_ShouldActivateNextUpdate)
    1362.             {
    1363.                 if (!isFocused)
    1364.                 {
    1365.                     ActivateInputFieldInternal();
    1366.                     m_ShouldActivateNextUpdate = false;
    1367.                     return;
    1368.                 }
    1369.  
    1370.                 // Reset as we are already activated.
    1371.                 m_ShouldActivateNextUpdate = false;
    1372.             }
    1373.  
    1374.             // Update Scrollbar if needed
    1375.             if (m_IsScrollbarUpdateRequired)
    1376.             {
    1377.                 UpdateScrollbar();
    1378.                 m_IsScrollbarUpdateRequired = false;
    1379.             }
    1380.  
    1381.             // Handle double click to reset / deselect Input Field when ResetOnActivation is false.
    1382.             if (!isFocused && m_SelectionStillActive)
    1383.             {
    1384.                 GameObject selectedObject = EventSystem.current != null ? EventSystem.current.currentSelectedGameObject : null;
    1385.  
    1386.                 if (selectedObject != null && selectedObject != this.gameObject)
    1387.                 {
    1388.                     if (selectedObject != m_SelectedObject)
    1389.                     {
    1390.                         m_SelectedObject = selectedObject;
    1391.  
    1392.                         // Check if object has a TMP Input Field
    1393.                         if (selectedObject.GetComponent<TMP_InputField>() != null)
    1394.                         {
    1395.                             // Release selection
    1396.                             m_SelectionStillActive = false;
    1397.                             MarkGeometryAsDirty();
    1398.                             m_SelectedObject = null;
    1399.                         }
    1400.                     }
    1401.  
    1402.                     return;
    1403.                 }
    1404.  
    1405.                 if (Input.GetKeyDown(KeyCode.Mouse0))
    1406.                 {
    1407.                     // Check for Double Click
    1408.                     bool isDoubleClick = false;
    1409.                     float timeStamp = Time.unscaledTime;
    1410.  
    1411.                     if (m_KeyDownStartTime + m_DoubleClickDelay > timeStamp)
    1412.                         isDoubleClick = true;
    1413.  
    1414.                     m_KeyDownStartTime = timeStamp;
    1415.  
    1416.                     if (isDoubleClick)
    1417.                     {
    1418.                         //m_StringPosition = m_StringSelectPosition = 0;
    1419.                         //m_CaretPosition = m_CaretSelectPosition = 0;
    1420.                         //m_TextComponent.rectTransform.localPosition = m_DefaultTransformPosition;
    1421.  
    1422.                         //if (caretRectTrans != null)
    1423.                         //    caretRectTrans.localPosition = Vector3.zero;
    1424.  
    1425.                         m_SelectionStillActive = false;
    1426.  
    1427.                         MarkGeometryAsDirty();
    1428.  
    1429.                         return;
    1430.                     }
    1431.                 }
    1432.             }
    1433.  
    1434.             if (InPlaceEditing() && isKeyboardUsingEvents() || !isFocused)
    1435.             {
    1436.                 return;
    1437.             }
    1438.  
    1439.             AssignPositioningIfNeeded();
    1440.  
    1441.             if (m_SoftKeyboard == null || m_SoftKeyboard.status != TouchScreenKeyboard.Status.Visible)
    1442.             {
    1443.                 if (m_SoftKeyboard != null)
    1444.                 {
    1445.                     if (!m_ReadOnly)
    1446.                         text = m_SoftKeyboard.text;
    1447.  
    1448.                     if (m_SoftKeyboard.status == TouchScreenKeyboard.Status.LostFocus)
    1449.                         SendTouchScreenKeyboardStatusChanged();
    1450.  
    1451.                     if (m_SoftKeyboard.status == TouchScreenKeyboard.Status.Canceled)
    1452.                     {
    1453.                         m_ReleaseSelection = true;
    1454.                         m_WasCanceled = true;
    1455.                         SendTouchScreenKeyboardStatusChanged();
    1456.                     }
    1457.  
    1458.                     if (m_SoftKeyboard.status == TouchScreenKeyboard.Status.Done)
    1459.                     {
    1460.                         m_ReleaseSelection = true;
    1461.                         OnSubmit(null);
    1462.                         SendTouchScreenKeyboardStatusChanged();
    1463.                     }
    1464.                 }
    1465.  
    1466.                 OnDeselect(null);
    1467.                 return;
    1468.             }
    1469.  
    1470.             string val = m_SoftKeyboard.text;
    1471.  
    1472.             if (m_Text != val)
    1473.             {
    1474.                 if (m_ReadOnly)
    1475.                 {
    1476.                     m_SoftKeyboard.text = m_Text;
    1477.                 }
    1478.                 else
    1479.                 {
    1480.                     m_Text = "";
    1481.  
    1482.                     for (int i = 0; i < val.Length; ++i)
    1483.                     {
    1484.                         char c = val[i];
    1485.  
    1486.                         if (c == '\r' || (int)c == 3)
    1487.                             c = '\n';
    1488.  
    1489.                         if (onValidateInput != null)
    1490.                             c = onValidateInput(m_Text, m_Text.Length, c);
    1491.                         else if (characterValidation != CharacterValidation.None)
    1492.                             c = Validate(m_Text, m_Text.Length, c);
    1493.  
    1494.                         if (lineType == LineType.MultiLineSubmit && c == '\n')
    1495.                         {
    1496.                             m_SoftKeyboard.text = m_Text;
    1497.  
    1498.                             OnSubmit(null);
    1499.                             OnDeselect(null);
    1500.                             return;
    1501.                         }
    1502.  
    1503.                         if (c != 0)
    1504.                             m_Text += c;
    1505.                     }
    1506.  
    1507.                     if (characterLimit > 0 && m_Text.Length > characterLimit)
    1508.                         m_Text = m_Text.Substring(0, characterLimit);
    1509.  
    1510.                     UpdateStringPositionFromKeyboard();
    1511.  
    1512.                     // Set keyboard text before updating label, as we might have changed it with validation
    1513.                     // and update label will take the old value from keyboard if we don't change it here
    1514.                     if (m_Text != val)
    1515.                         m_SoftKeyboard.text = m_Text;
    1516.  
    1517.                     SendOnValueChangedAndUpdateLabel();
    1518.                 }
    1519.             }
    1520.             else if (m_HideMobileInput && Application.platform == RuntimePlatform.Android)
    1521.             {
    1522.                 UpdateStringPositionFromKeyboard();
    1523.             }
    1524.  
    1525.             //else if (m_HideMobileInput) // m_Keyboard.canSetSelection
    1526.             //{
    1527.             //    int length = stringPositionInternal < stringSelectPositionInternal ? stringSelectPositionInternal - stringPositionInternal : stringPositionInternal - stringSelectPositionInternal;
    1528.             //    m_SoftKeyboard.selection = new RangeInt(stringPositionInternal < stringSelectPositionInternal ? stringPositionInternal : stringSelectPositionInternal, length);
    1529.             //}
    1530.             //else if (!m_HideMobileInput) // m_Keyboard.canGetSelection)
    1531.             //{
    1532.             //    UpdateStringPositionFromKeyboard();
    1533.             //}
    1534.  
    1535.             if (m_SoftKeyboard.status != TouchScreenKeyboard.Status.Visible)
    1536.             {
    1537.                 if (m_SoftKeyboard.status == TouchScreenKeyboard.Status.Canceled)
    1538.                     m_WasCanceled = true;
    1539.  
    1540.                 OnDeselect(null);
    1541.             }
    1542.         }
    1543.  
    1544.  
    1545.         private bool MayDrag(PointerEventData eventData)
    1546.         {
    1547.             return IsActive() &&
    1548.                    IsInteractable() &&
    1549.                    eventData.button == PointerEventData.InputButton.Left &&
    1550.                    m_TextComponent != null &&
    1551.                    (m_SoftKeyboard == null || shouldHideSoftKeyboard || shouldHideMobileInput);
    1552.         }
    1553.  
    1554.         public virtual void OnBeginDrag(PointerEventData eventData)
    1555.         {
    1556.             if (!MayDrag(eventData))
    1557.                 return;
    1558.  
    1559.             m_UpdateDrag = true;
    1560.         }
    1561.  
    1562.         public virtual void OnDrag(PointerEventData eventData)
    1563.         {
    1564.             if (!MayDrag(eventData))
    1565.                 return;
    1566.  
    1567.             int insertionIndex = TMP_TextUtilities.GetCursorIndexFromPosition(m_TextComponent, eventData.position, eventData.pressEventCamera, out CaretPosition insertionSide);
    1568.  
    1569.             if (m_isRichTextEditingAllowed)
    1570.             {
    1571.                 if (insertionSide == CaretPosition.Left)
    1572.                 {
    1573.                     stringSelectPositionInternal = m_TextComponent.textInfo.characterInfo[insertionIndex].index;
    1574.                 }
    1575.                 else if (insertionSide == CaretPosition.Right)
    1576.                 {
    1577.                     stringSelectPositionInternal = m_TextComponent.textInfo.characterInfo[insertionIndex].index + m_TextComponent.textInfo.characterInfo[insertionIndex].stringLength;
    1578.                 }
    1579.             }
    1580.             else
    1581.             {
    1582.                 if (insertionSide == CaretPosition.Left)
    1583.                 {
    1584.                     stringSelectPositionInternal = insertionIndex == 0
    1585.                         ? m_TextComponent.textInfo.characterInfo[0].index
    1586.                         : m_TextComponent.textInfo.characterInfo[insertionIndex - 1].index + m_TextComponent.textInfo.characterInfo[insertionIndex - 1].stringLength;
    1587.                 }
    1588.                 else if (insertionSide == CaretPosition.Right)
    1589.                 {
    1590.                     stringSelectPositionInternal = m_TextComponent.textInfo.characterInfo[insertionIndex].index + m_TextComponent.textInfo.characterInfo[insertionIndex].stringLength;
    1591.                 }
    1592.             }
    1593.  
    1594.             caretSelectPositionInternal = GetCaretPositionFromStringIndex(stringSelectPositionInternal);
    1595.  
    1596.             MarkGeometryAsDirty();
    1597.  
    1598.             m_DragPositionOutOfBounds = !RectTransformUtility.RectangleContainsScreenPoint(textViewport, eventData.position, eventData.pressEventCamera);
    1599.             if (m_DragPositionOutOfBounds && m_DragCoroutine == null)
    1600.                 m_DragCoroutine = StartCoroutine(MouseDragOutsideRect(eventData));
    1601.  
    1602.             eventData.Use();
    1603.  
    1604.             #if TMP_DEBUG_MODE
    1605.                 Debug.Log("Caret Position: " + caretPositionInternal + " Selection Position: " + caretSelectPositionInternal + "  String Position: " + stringPositionInternal + " String Select Position: " + stringSelectPositionInternal);
    1606.             #endif
    1607.         }
    1608.  
    1609.         IEnumerator MouseDragOutsideRect(PointerEventData eventData)
    1610.         {
    1611.             while (m_UpdateDrag && m_DragPositionOutOfBounds)
    1612.             {
    1613.                 RectTransformUtility.ScreenPointToLocalPointInRectangle(textViewport, eventData.position, eventData.pressEventCamera, out Vector2 localMousePos);
    1614.  
    1615.                 Rect rect = textViewport.rect;
    1616.  
    1617.                 if (multiLine)
    1618.                 {
    1619.                     if (localMousePos.y > rect.yMax)
    1620.                         MoveUp(true, true);
    1621.                     else if (localMousePos.y < rect.yMin)
    1622.                         MoveDown(true, true);
    1623.                 }
    1624.                 else
    1625.                 {
    1626.                     if (localMousePos.x < rect.xMin)
    1627.                         MoveLeft(true, false);
    1628.                     else if (localMousePos.x > rect.xMax)
    1629.                         MoveRight(true, false);
    1630.                 }
    1631.  
    1632.                 UpdateLabel();
    1633.  
    1634.                 float delay = multiLine ? kVScrollSpeed : kHScrollSpeed;
    1635.  
    1636.                 if (m_WaitForSecondsRealtime == null)
    1637.                     m_WaitForSecondsRealtime = new WaitForSecondsRealtime(delay);
    1638.                 else
    1639.                     m_WaitForSecondsRealtime.waitTime = delay;
    1640.  
    1641.                 yield return m_WaitForSecondsRealtime;
    1642.             }
    1643.             m_DragCoroutine = null;
    1644.         }
    1645.  
    1646.         public virtual void OnEndDrag(PointerEventData eventData)
    1647.         {
    1648.             if (!MayDrag(eventData))
    1649.                 return;
    1650.  
    1651.             m_UpdateDrag = false;
    1652.         }
    1653.  
    1654.         public override void OnPointerDown(PointerEventData eventData)
    1655.         {
    1656.             if (!MayDrag(eventData))
    1657.                 return;
    1658.  
    1659.             EventSystem.current.SetSelectedGameObject(gameObject, eventData);
    1660.  
    1661.             bool hadFocusBefore = m_AllowInput;
    1662.             base.OnPointerDown(eventData);
    1663.  
    1664.             if (InPlaceEditing() == false)
    1665.             {
    1666.                 if (m_SoftKeyboard == null || !m_SoftKeyboard.active)
    1667.                 {
    1668.                     OnSelect(eventData);
    1669.                     return;
    1670.                 }
    1671.             }
    1672.  
    1673.             bool shift = Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift);
    1674.  
    1675.             // Check for Double Click
    1676.             bool isDoubleClick = false;
    1677.             float timeStamp = Time.unscaledTime;
    1678.  
    1679.             if (m_PointerDownClickStartTime + m_DoubleClickDelay > timeStamp)
    1680.                 isDoubleClick = true;
    1681.  
    1682.             m_PointerDownClickStartTime = timeStamp;
    1683.  
    1684.             // Only set caret position if we didn't just get focus now.
    1685.             // Otherwise it will overwrite the select all on focus.
    1686.             if (hadFocusBefore || !m_OnFocusSelectAll)
    1687.             {
    1688.                 int insertionIndex = TMP_TextUtilities.GetCursorIndexFromPosition(m_TextComponent, eventData.position, eventData.pressEventCamera, out CaretPosition insertionSide);
    1689.  
    1690.                 if (shift)
    1691.                 {
    1692.                     if (m_isRichTextEditingAllowed)
    1693.                     {
    1694.                         if (insertionSide == CaretPosition.Left)
    1695.                         {
    1696.                             stringSelectPositionInternal = m_TextComponent.textInfo.characterInfo[insertionIndex].index;
    1697.                         }
    1698.                         else if (insertionSide == CaretPosition.Right)
    1699.                         {
    1700.                             stringSelectPositionInternal = m_TextComponent.textInfo.characterInfo[insertionIndex].index + m_TextComponent.textInfo.characterInfo[insertionIndex].stringLength;
    1701.                         }
    1702.                     }
    1703.                     else
    1704.                     {
    1705.                         if (insertionSide == CaretPosition.Left)
    1706.                         {
    1707.                             stringSelectPositionInternal = insertionIndex == 0
    1708.                                 ? m_TextComponent.textInfo.characterInfo[0].index
    1709.                                 : m_TextComponent.textInfo.characterInfo[insertionIndex - 1].index + m_TextComponent.textInfo.characterInfo[insertionIndex - 1].stringLength;
    1710.                         }
    1711.                         else if (insertionSide == CaretPosition.Right)
    1712.                         {
    1713.                             stringSelectPositionInternal = m_TextComponent.textInfo.characterInfo[insertionIndex].index + m_TextComponent.textInfo.characterInfo[insertionIndex].stringLength;
    1714.                         }
    1715.                     }
    1716.                 }
    1717.                 else
    1718.                 {
    1719.                     if (m_isRichTextEditingAllowed)
    1720.                     {
    1721.                         if (insertionSide == CaretPosition.Left)
    1722.                         {
    1723.                             stringPositionInternal = stringSelectPositionInternal = m_TextComponent.textInfo.characterInfo[insertionIndex].index;
    1724.                         }
    1725.                         else if (insertionSide == CaretPosition.Right)
    1726.                         {
    1727.                             stringPositionInternal = stringSelectPositionInternal = m_TextComponent.textInfo.characterInfo[insertionIndex].index + m_TextComponent.textInfo.characterInfo[insertionIndex].stringLength;
    1728.                         }
    1729.                     }
    1730.                     else
    1731.                     {
    1732.                         if (insertionSide == CaretPosition.Left)
    1733.                         {
    1734.                             stringPositionInternal = stringSelectPositionInternal = insertionIndex == 0
    1735.                                 ? m_TextComponent.textInfo.characterInfo[0].index
    1736.                                 : m_TextComponent.textInfo.characterInfo[insertionIndex - 1].index + m_TextComponent.textInfo.characterInfo[insertionIndex - 1].stringLength;
    1737.                         }
    1738.                         else if (insertionSide == CaretPosition.Right)
    1739.                         {
    1740.                             stringPositionInternal = stringSelectPositionInternal = m_TextComponent.textInfo.characterInfo[insertionIndex].index + m_TextComponent.textInfo.characterInfo[insertionIndex].stringLength;
    1741.                         }
    1742.                     }
    1743.                 }
    1744.  
    1745.  
    1746.                 if (isDoubleClick)
    1747.                 {
    1748.                     int wordIndex = TMP_TextUtilities.FindIntersectingWord(m_TextComponent, eventData.position, eventData.pressEventCamera);
    1749.  
    1750.                     if (wordIndex != -1)
    1751.                     {
    1752.                         // TODO: Should behavior be different if rich text editing is enabled or not?
    1753.  
    1754.                         // Select current word
    1755.                         caretPositionInternal = m_TextComponent.textInfo.wordInfo[wordIndex].firstCharacterIndex;
    1756.                         caretSelectPositionInternal = m_TextComponent.textInfo.wordInfo[wordIndex].lastCharacterIndex + 1;
    1757.  
    1758.                         stringPositionInternal = m_TextComponent.textInfo.characterInfo[caretPositionInternal].index;
    1759.                         stringSelectPositionInternal = m_TextComponent.textInfo.characterInfo[caretSelectPositionInternal - 1].index + m_TextComponent.textInfo.characterInfo[caretSelectPositionInternal - 1].stringLength;
    1760.                     }
    1761.                     else
    1762.                     {
    1763.                         // Select current character
    1764.                         caretPositionInternal = insertionIndex;
    1765.                         caretSelectPositionInternal = caretPositionInternal + 1;
    1766.  
    1767.                         stringPositionInternal = m_TextComponent.textInfo.characterInfo[insertionIndex].index;
    1768.                         stringSelectPositionInternal = stringPositionInternal + m_TextComponent.textInfo.characterInfo[insertionIndex].stringLength;
    1769.                     }
    1770.                 }
    1771.                 else
    1772.                 {
    1773.                     caretPositionInternal = caretSelectPositionInternal = GetCaretPositionFromStringIndex(stringPositionInternal);
    1774.                 }
    1775.             }
    1776.  
    1777.             UpdateLabel();
    1778.             eventData.Use();
    1779.  
    1780.             #if TMP_DEBUG_MODE
    1781.                 Debug.Log("Caret Position: " + caretPositionInternal + " Selection Position: " + caretSelectPositionInternal + "  String Position: " + stringPositionInternal + " String Select Position: " + stringSelectPositionInternal);
    1782.             #endif
    1783.         }
    1784.  
    1785.         protected enum EditState
    1786.         {
    1787.             Continue,
    1788.             Finish
    1789.         }
    1790.  
    1791.         protected EditState KeyPressed(Event evt)
    1792.         {
    1793.             var currentEventModifiers = evt.modifiers;
    1794.             bool ctrl = SystemInfo.operatingSystemFamily == OperatingSystemFamily.MacOSX ? (currentEventModifiers & EventModifiers.Command) != 0 : (currentEventModifiers & EventModifiers.Control) != 0;
    1795.             bool shift = (currentEventModifiers & EventModifiers.Shift) != 0;
    1796.             bool alt = (currentEventModifiers & EventModifiers.Alt) != 0;
    1797.             bool ctrlOnly = ctrl && !alt && !shift;
    1798.  
    1799.             switch (evt.keyCode)
    1800.             {
    1801.                 case KeyCode.Backspace:
    1802.                     {
    1803.                         Backspace();
    1804.                         return EditState.Continue;
    1805.                     }
    1806.  
    1807.                 case KeyCode.Delete:
    1808.                     {
    1809.                         DeleteKey();
    1810.                         return EditState.Continue;
    1811.                     }
    1812.  
    1813.                 case KeyCode.Home:
    1814.                     {
    1815.                         MoveToStartOfLine(shift, ctrl);
    1816.                         return EditState.Continue;
    1817.                     }
    1818.  
    1819.                 case KeyCode.End:
    1820.                     {
    1821.                         MoveToEndOfLine(shift, ctrl);
    1822.                         return EditState.Continue;
    1823.                     }
    1824.  
    1825.                 // Select All
    1826.                 case KeyCode.A:
    1827.                     {
    1828.                         if (ctrlOnly)
    1829.                         {
    1830.                             SelectAll();
    1831.                             return EditState.Continue;
    1832.                         }
    1833.                         break;
    1834.                     }
    1835.  
    1836.                 // Copy
    1837.                 case KeyCode.C:
    1838.                     {
    1839.                         if (ctrlOnly)
    1840.                         {
    1841.                             if (inputType != InputType.Password)
    1842.                                 clipboard = GetSelectedString();
    1843.                             else
    1844.                                 clipboard = "";
    1845.                             return EditState.Continue;
    1846.                         }
    1847.                         break;
    1848.                     }
    1849.  
    1850.                 // Paste
    1851.                 case KeyCode.V:
    1852.                     {
    1853.                         if (ctrlOnly)
    1854.                         {
    1855.                             Append(clipboard);
    1856.                             return EditState.Continue;
    1857.                         }
    1858.                         break;
    1859.                     }
    1860.  
    1861.                 // Cut
    1862.                 case KeyCode.X:
    1863.                     {
    1864.                         if (ctrlOnly)
    1865.                         {
    1866.                             if (inputType != InputType.Password)
    1867.                                 clipboard = GetSelectedString();
    1868.                             else
    1869.                                 clipboard = "";
    1870.                             Delete();
    1871.                             UpdateTouchKeyboardFromEditChanges();
    1872.                             SendOnValueChangedAndUpdateLabel();
    1873.                             return EditState.Continue;
    1874.                         }
    1875.                         break;
    1876.                     }
    1877.  
    1878.                 case KeyCode.LeftArrow:
    1879.                     {
    1880.                         MoveLeft(shift, ctrl);
    1881.                         return EditState.Continue;
    1882.                     }
    1883.  
    1884.                 case KeyCode.RightArrow:
    1885.                     {
    1886.                         MoveRight(shift, ctrl);
    1887.                         return EditState.Continue;
    1888.                     }
    1889.  
    1890.                 case KeyCode.UpArrow:
    1891.                     {
    1892.                         MoveUp(shift);
    1893.                         return EditState.Continue;
    1894.                     }
    1895.  
    1896.                 case KeyCode.DownArrow:
    1897.                     {
    1898.                         MoveDown(shift);
    1899.                         return EditState.Continue;
    1900.                     }
    1901.  
    1902.                 case KeyCode.PageUp:
    1903.                     {
    1904.                         MovePageUp(shift);
    1905.                         return EditState.Continue;
    1906.                     }
    1907.  
    1908.                 case KeyCode.PageDown:
    1909.                     {
    1910.                         MovePageDown(shift);
    1911.                         return EditState.Continue;
    1912.                     }
    1913.  
    1914.                 // Submit
    1915.                 case KeyCode.Return:
    1916.                 case KeyCode.KeypadEnter:
    1917.                     {
    1918.                         if (lineType != LineType.MultiLineNewline)
    1919.                         {
    1920.                             m_ReleaseSelection = true;
    1921.                             return EditState.Finish;
    1922.                         }
    1923.                         break;
    1924.                     }
    1925.  
    1926.                 case KeyCode.Escape:
    1927.                     {
    1928.                         m_ReleaseSelection = true;
    1929.                         m_WasCanceled = true;
    1930.                         return EditState.Finish;
    1931.                     }
    1932.             }
    1933.  
    1934.             char c = evt.character;
    1935.  
    1936.             // Don't allow return chars or tabulator key to be entered into single line fields.
    1937.             if (!multiLine && (c == '\t' || c == '\r' || c == 10))
    1938.                 return EditState.Continue;
    1939.  
    1940.             // Convert carriage return and end-of-text characters to newline.
    1941.             if (c == '\r' || (int)c == 3)
    1942.                 c = '\n';
    1943.  
    1944.             if (IsValidChar(c))
    1945.             {
    1946.                 Append(c);
    1947.             }
    1948.  
    1949.             if (c == 0)
    1950.             {
    1951.                 if (compositionString.Length > 0)
    1952.                 {
    1953.                     UpdateLabel();
    1954.                 }
    1955.             }
    1956.             return EditState.Continue;
    1957.         }
    1958.  
    1959.         protected virtual bool IsValidChar(char c)
    1960.         {
    1961.             // Delete key on mac
    1962.             if ((int)c == 127)
    1963.                 return false;
    1964.             // Accept newline and tab
    1965.             if (c == '\t' || c == '\n')
    1966.                 return true;
    1967.  
    1968.             return true;
    1969.  
    1970.             // With the addition of Dynamic support, I think this will best be handled by the text component.
    1971.             //return m_TextComponent.font.HasCharacter(c, true);
    1972.         }
    1973.  
    1974.         /// <summary>
    1975.         /// Handle the specified event.
    1976.         /// </summary>
    1977.         private Event m_ProcessingEvent = new Event();
    1978.  
    1979.         public void ProcessEvent(Event e)
    1980.         {
    1981.             KeyPressed(e);
    1982.         }
    1983.  
    1984.  
    1985.         /// <summary>
    1986.         ///
    1987.         /// </summary>
    1988.         /// <param name="eventData"></param>
    1989.         public virtual void OnUpdateSelected(BaseEventData eventData)
    1990.         {
    1991.             if (!isFocused)
    1992.                 return;
    1993.  
    1994.             bool consumedEvent = false;
    1995.             while (Event.PopEvent(m_ProcessingEvent))
    1996.             {
    1997.                 if (m_ProcessingEvent.rawType == EventType.KeyDown)
    1998.                 {
    1999.                     //Debug.Log("Event: " + m_ProcessingEvent.ToString());
    2000.  
    2001.                     consumedEvent = true;
    2002.                     var shouldContinue = KeyPressed(m_ProcessingEvent);
    2003.                     if (shouldContinue == EditState.Finish)
    2004.                     {
    2005.                         SendOnSubmit();
    2006.                         DeactivateInputField();
    2007.                         break;
    2008.                     }
    2009.                 }
    2010.  
    2011.                 switch (m_ProcessingEvent.type)
    2012.                 {
    2013.                     case EventType.ValidateCommand:
    2014.                     case EventType.ExecuteCommand:
    2015.                         switch (m_ProcessingEvent.commandName)
    2016.                         {
    2017.                             case "SelectAll":
    2018.                                 SelectAll();
    2019.                                 consumedEvent = true;
    2020.                                 break;
    2021.                         }
    2022.                         break;
    2023.                 }
    2024.             }
    2025.  
    2026.             if (consumedEvent)
    2027.                 UpdateLabel();
    2028.  
    2029.             eventData.Use();
    2030.         }
    2031.  
    2032.  
    2033.         /// <summary>
    2034.         ///
    2035.         /// </summary>
    2036.         /// <param name="eventData"></param>
    2037.         public virtual void OnScroll(PointerEventData eventData)
    2038.         {
    2039.             if (m_TextComponent.preferredHeight < m_TextViewport.rect.height) return;
    2040.  
    2041.             float scrollDirection = -eventData.scrollDelta.y;
    2042.  
    2043.             m_ScrollPosition = m_ScrollPosition + (1f / m_TextComponent.textInfo.lineCount) * scrollDirection * m_ScrollSensitivity;
    2044.  
    2045.             m_ScrollPosition = Mathf.Clamp01(m_ScrollPosition);
    2046.  
    2047.             AdjustTextPositionRelativeToViewport(m_ScrollPosition);
    2048.  
    2049.             // Disable focus until user re-selected the input field.
    2050.             m_AllowInput = false;
    2051.  
    2052.             if (m_VerticalScrollbar)
    2053.             {
    2054.                 m_IsUpdatingScrollbarValues = true;
    2055.                 m_VerticalScrollbar.value = m_ScrollPosition;
    2056.             }
    2057.  
    2058.             //Debug.Log("Scroll Position:" + m_ScrollPosition);
    2059.         }
    2060.  
    2061.  
    2062.         private string GetSelectedString()
    2063.         {
    2064.             if (!hasSelection)
    2065.                 return "";
    2066.  
    2067.             int startPos = stringPositionInternal;
    2068.             int endPos = stringSelectPositionInternal;
    2069.  
    2070.             // Ensure pos is always less then selPos to make the code simpler
    2071.             if (startPos > endPos)
    2072.             {
    2073.                 int temp = startPos;
    2074.                 startPos = endPos;
    2075.                 endPos = temp;
    2076.             }
    2077.  
    2078.             //for (int i = m_CaretPosition; i < m_CaretSelectPosition; i++)
    2079.             //{
    2080.             //    Debug.Log("Character [" + m_TextComponent.textInfo.characterInfo[i].character + "] using Style [" + m_TextComponent.textInfo.characterInfo[i].style + "] has been selected.");
    2081.             //}
    2082.  
    2083.  
    2084.             return text.Substring(startPos, endPos - startPos);
    2085.         }
    2086.  
    2087.         private int FindNextWordBegin()
    2088.         {
    2089.             if (stringSelectPositionInternal + 1 >= text.Length)
    2090.                 return text.Length;
    2091.  
    2092.             int spaceLoc = text.IndexOfAny(kSeparators, stringSelectPositionInternal + 1);
    2093.  
    2094.             if (spaceLoc == -1)
    2095.                 spaceLoc = text.Length;
    2096.             else
    2097.                 spaceLoc++;
    2098.  
    2099.             return spaceLoc;
    2100.         }
    2101.  
    2102.         private void MoveRight(bool shift, bool ctrl)
    2103.         {
    2104.             if (hasSelection && !shift)
    2105.             {
    2106.                 // By convention, if we have a selection and move right without holding shift,
    2107.                 // we just place the cursor at the end.
    2108.                 stringPositionInternal = stringSelectPositionInternal = Mathf.Max(stringPositionInternal, stringSelectPositionInternal);
    2109.                 caretPositionInternal = caretSelectPositionInternal = GetCaretPositionFromStringIndex(stringSelectPositionInternal);
    2110.  
    2111.                 #if TMP_DEBUG_MODE
    2112.                     Debug.Log("Caret Position: " + caretPositionInternal + " Selection Position: " + caretSelectPositionInternal + "  String Position: " + stringPositionInternal + " String Select Position: " + stringSelectPositionInternal);
    2113.                 #endif
    2114.                 return;
    2115.             }
    2116.  
    2117.             int position;
    2118.             if (ctrl)
    2119.                 position = FindNextWordBegin();
    2120.             else
    2121.             {
    2122.                 if (m_isRichTextEditingAllowed)
    2123.                 {
    2124.                     // Special handling for Surrogate pairs and Diacritical marks.
    2125.                     if (stringSelectPositionInternal < text.Length && char.IsHighSurrogate(text[stringSelectPositionInternal]))
    2126.                         position = stringSelectPositionInternal + 2;
    2127.                     else
    2128.                         position = stringSelectPositionInternal + 1;
    2129.                 }
    2130.                 else
    2131.                 {
    2132.                     position = m_TextComponent.textInfo.characterInfo[caretSelectPositionInternal].index + m_TextComponent.textInfo.characterInfo[caretSelectPositionInternal].stringLength;
    2133.                 }
    2134.  
    2135.             }
    2136.  
    2137.             if (shift)
    2138.             {
    2139.                 stringSelectPositionInternal = position;
    2140.                 caretSelectPositionInternal = GetCaretPositionFromStringIndex(stringSelectPositionInternal);
    2141.             }
    2142.             else
    2143.             {
    2144.                 stringSelectPositionInternal = stringPositionInternal = position;
    2145.  
    2146.                 // Only increase caret position as we cross character boundary.
    2147.                 if (stringPositionInternal >= m_TextComponent.textInfo.characterInfo[caretPositionInternal].index + m_TextComponent.textInfo.characterInfo[caretPositionInternal].stringLength)
    2148.                     caretSelectPositionInternal = caretPositionInternal = GetCaretPositionFromStringIndex(stringSelectPositionInternal);
    2149.             }
    2150.  
    2151.             #if TMP_DEBUG_MODE
    2152.                 Debug.Log("Caret Position: " + caretPositionInternal + "  Selection Position: " + caretSelectPositionInternal + "  String Position: " + stringPositionInternal + "  String Select Position: " + stringSelectPositionInternal);
    2153.             #endif
    2154.         }
    2155.  
    2156.         private int FindPrevWordBegin()
    2157.         {
    2158.             if (stringSelectPositionInternal - 2 < 0)
    2159.                 return 0;
    2160.  
    2161.             int spaceLoc = text.LastIndexOfAny(kSeparators, stringSelectPositionInternal - 2);
    2162.  
    2163.             if (spaceLoc == -1)
    2164.                 spaceLoc = 0;
    2165.             else
    2166.                 spaceLoc++;
    2167.  
    2168.             return spaceLoc;
    2169.         }
    2170.  
    2171.         private void MoveLeft(bool shift, bool ctrl)
    2172.         {
    2173.             if (hasSelection && !shift)
    2174.             {
    2175.                 // By convention, if we have a selection and move left without holding shift,
    2176.                 // we just place the cursor at the start.
    2177.                 stringPositionInternal = stringSelectPositionInternal = Mathf.Min(stringPositionInternal, stringSelectPositionInternal);
    2178.                 caretPositionInternal = caretSelectPositionInternal = GetCaretPositionFromStringIndex(stringSelectPositionInternal);
    2179.  
    2180.                 #if TMP_DEBUG_MODE
    2181.                     Debug.Log("Caret Position: " + caretPositionInternal + " Selection Position: " + caretSelectPositionInternal + "  String Position: " + stringPositionInternal + " String Select Position: " + stringSelectPositionInternal);
    2182.                 #endif
    2183.                 return;
    2184.             }
    2185.  
    2186.             int position;
    2187.             if (ctrl)
    2188.                 position = FindPrevWordBegin();
    2189.             else
    2190.             {
    2191.                 if (m_isRichTextEditingAllowed)
    2192.                 {
    2193.                     // Special handling for Surrogate pairs and Diacritical marks.
    2194.                     if (stringSelectPositionInternal > 0 && char.IsLowSurrogate(text[stringSelectPositionInternal - 1]))
    2195.                         position = stringSelectPositionInternal - 2;
    2196.                     else
    2197.                         position =  stringSelectPositionInternal - 1;
    2198.                 }
    2199.                 else
    2200.                 {
    2201.                     //position = GetStringIndexFromCaretPosition(caretSelectPositionInternal - 1);
    2202.                     position = caretSelectPositionInternal < 2
    2203.                         ? m_TextComponent.textInfo.characterInfo[0].index
    2204.                         : m_TextComponent.textInfo.characterInfo[caretSelectPositionInternal - 2].index + m_TextComponent.textInfo.characterInfo[caretSelectPositionInternal - 2].stringLength;
    2205.                 }
    2206.             }
    2207.  
    2208.             if (shift)
    2209.             {
    2210.                 stringSelectPositionInternal = position;
    2211.                 caretSelectPositionInternal = GetCaretPositionFromStringIndex(stringSelectPositionInternal);
    2212.             }
    2213.             else
    2214.             {
    2215.                 stringSelectPositionInternal = stringPositionInternal = position;
    2216.  
    2217.                 // Only decrease caret position as we cross character boundary.
    2218.                 if (caretPositionInternal > 0 && stringPositionInternal <= m_TextComponent.textInfo.characterInfo[caretPositionInternal - 1].index)
    2219.                     caretSelectPositionInternal = caretPositionInternal = GetCaretPositionFromStringIndex(stringSelectPositionInternal);
    2220.             }
    2221.  
    2222.             #if TMP_DEBUG_MODE
    2223.                 Debug.Log("Caret Position: " + caretPositionInternal + "  Selection Position: " + caretSelectPositionInternal + "  String Position: " + stringPositionInternal + "  String Select Position: " + stringSelectPositionInternal);
    2224.             #endif
    2225.         }
    2226.  
    2227.  
    2228.         private int LineUpCharacterPosition(int originalPos, bool goToFirstChar)
    2229.         {
    2230.             if (originalPos >= m_TextComponent.textInfo.characterCount)
    2231.                 originalPos -= 1;
    2232.  
    2233.             TMP_CharacterInfo originChar = m_TextComponent.textInfo.characterInfo[originalPos];
    2234.             int originLine = originChar.lineNumber;
    2235.  
    2236.             // We are on the first line return first character
    2237.             if (originLine - 1 < 0)
    2238.                 return goToFirstChar ? 0 : originalPos;
    2239.  
    2240.             int endCharIdx = m_TextComponent.textInfo.lineInfo[originLine].firstCharacterIndex - 1;
    2241.  
    2242.             int closest = -1;
    2243.             float distance = TMP_Math.FLOAT_MAX;
    2244.             float range = 0;
    2245.  
    2246.             for (int i = m_TextComponent.textInfo.lineInfo[originLine - 1].firstCharacterIndex; i < endCharIdx; ++i)
    2247.             {
    2248.                 TMP_CharacterInfo currentChar = m_TextComponent.textInfo.characterInfo[i];
    2249.  
    2250.                 float d = originChar.origin - currentChar.origin;
    2251.                 float r = d / (currentChar.xAdvance - currentChar.origin);
    2252.  
    2253.                 if (r >= 0 && r <= 1)
    2254.                 {
    2255.                     if (r < 0.5f)
    2256.                         return i;
    2257.                     else
    2258.                         return i + 1;
    2259.                 }
    2260.  
    2261.                 d = Mathf.Abs(d);
    2262.  
    2263.                 if (d < distance)
    2264.                 {
    2265.                     closest = i;
    2266.                     distance = d;
    2267.                     range = r;
    2268.                 }
    2269.             }
    2270.  
    2271.             if (closest == -1) return endCharIdx;
    2272.  
    2273.             //Debug.Log("Returning nearest character with Range = " + range);
    2274.  
    2275.             if (range < 0.5f)
    2276.                 return closest;
    2277.             else
    2278.                 return closest + 1;
    2279.         }
    2280.  
    2281.  
    2282.         private int LineDownCharacterPosition(int originalPos, bool goToLastChar)
    2283.         {
    2284.             if (originalPos >= m_TextComponent.textInfo.characterCount)
    2285.                 return m_TextComponent.textInfo.characterCount - 1; // text.Length;
    2286.  
    2287.             TMP_CharacterInfo originChar = m_TextComponent.textInfo.characterInfo[originalPos];
    2288.             int originLine = originChar.lineNumber;
    2289.  
    2290.             //// We are on the last line return last character
    2291.             if (originLine + 1 >= m_TextComponent.textInfo.lineCount)
    2292.                 return goToLastChar ? m_TextComponent.textInfo.characterCount - 1 : originalPos;
    2293.  
    2294.             // Need to determine end line for next line.
    2295.             int endCharIdx = m_TextComponent.textInfo.lineInfo[originLine + 1].lastCharacterIndex;
    2296.  
    2297.             int closest = -1;
    2298.             float distance = TMP_Math.FLOAT_MAX;
    2299.             float range = 0;
    2300.  
    2301.             for (int i = m_TextComponent.textInfo.lineInfo[originLine + 1].firstCharacterIndex; i < endCharIdx; ++i)
    2302.             {
    2303.                 TMP_CharacterInfo currentChar = m_TextComponent.textInfo.characterInfo[i];
    2304.  
    2305.                 float d = originChar.origin - currentChar.origin;
    2306.                 float r = d / (currentChar.xAdvance - currentChar.origin);
    2307.  
    2308.                 if (r >= 0 && r <= 1)
    2309.                 {
    2310.                     if (r < 0.5f)
    2311.                         return i;
    2312.                     else
    2313.                         return i + 1;
    2314.                 }
    2315.  
    2316.                 d = Mathf.Abs(d);
    2317.  
    2318.                 if (d < distance)
    2319.                 {
    2320.                     closest = i;
    2321.                     distance = d;
    2322.                     range = r;
    2323.                 }
    2324.             }
    2325.  
    2326.             if (closest == -1) return endCharIdx;
    2327.  
    2328.             //Debug.Log("Returning nearest character with Range = " + range);
    2329.  
    2330.             if (range < 0.5f)
    2331.                 return closest;
    2332.             else
    2333.                 return closest + 1;
    2334.         }
    2335.  
    2336.  
    2337.          private int PageUpCharacterPosition(int originalPos, bool goToFirstChar)
    2338.         {
    2339.             if (originalPos >= m_TextComponent.textInfo.characterCount)
    2340.                 originalPos -= 1;
    2341.  
    2342.             TMP_CharacterInfo originChar = m_TextComponent.textInfo.characterInfo[originalPos];
    2343.             int originLine = originChar.lineNumber;
    2344.  
    2345.             // We are on the first line return first character
    2346.             if (originLine - 1 < 0)
    2347.                 return goToFirstChar ? 0 : originalPos;
    2348.  
    2349.             float viewportHeight = m_TextViewport.rect.height;
    2350.  
    2351.             int newLine = originLine - 1;
    2352.             // Iterate through each subsequent line to find the first baseline that is not visible in the viewport.
    2353.             for (; newLine > 0; newLine--)
    2354.             {
    2355.                 if (m_TextComponent.textInfo.lineInfo[newLine].baseline > m_TextComponent.textInfo.lineInfo[originLine].baseline + viewportHeight)
    2356.                     break;
    2357.             }
    2358.  
    2359.             int endCharIdx = m_TextComponent.textInfo.lineInfo[newLine].lastCharacterIndex;
    2360.  
    2361.             int closest = -1;
    2362.             float distance = TMP_Math.FLOAT_MAX;
    2363.             float range = 0;
    2364.  
    2365.             for (int i = m_TextComponent.textInfo.lineInfo[newLine].firstCharacterIndex; i < endCharIdx; ++i)
    2366.             {
    2367.                 TMP_CharacterInfo currentChar = m_TextComponent.textInfo.characterInfo[i];
    2368.  
    2369.                 float d = originChar.origin - currentChar.origin;
    2370.                 float r = d / (currentChar.xAdvance - currentChar.origin);
    2371.  
    2372.                 if (r >= 0 && r <= 1)
    2373.                 {
    2374.                     if (r < 0.5f)
    2375.                         return i;
    2376.                     else
    2377.                         return i + 1;
    2378.                 }
    2379.  
    2380.                 d = Mathf.Abs(d);
    2381.  
    2382.                 if (d < distance)
    2383.                 {
    2384.                     closest = i;
    2385.                     distance = d;
    2386.                     range = r;
    2387.                 }
    2388.             }
    2389.  
    2390.             if (closest == -1) return endCharIdx;
    2391.  
    2392.             //Debug.Log("Returning nearest character with Range = " + range);
    2393.  
    2394.             if (range < 0.5f)
    2395.                 return closest;
    2396.             else
    2397.                 return closest + 1;
    2398.         }
    2399.  
    2400.  
    2401.          private int PageDownCharacterPosition(int originalPos, bool goToLastChar)
    2402.         {
    2403.             if (originalPos >= m_TextComponent.textInfo.characterCount)
    2404.                 return m_TextComponent.textInfo.characterCount - 1;
    2405.  
    2406.             TMP_CharacterInfo originChar = m_TextComponent.textInfo.characterInfo[originalPos];
    2407.             int originLine = originChar.lineNumber;
    2408.  
    2409.             // We are on the last line return last character
    2410.             if (originLine + 1 >= m_TextComponent.textInfo.lineCount)
    2411.                 return goToLastChar ? m_TextComponent.textInfo.characterCount - 1 : originalPos;
    2412.  
    2413.             float viewportHeight = m_TextViewport.rect.height;
    2414.  
    2415.             int newLine = originLine + 1;
    2416.             // Iterate through each subsequent line to find the first baseline that is not visible in the viewport.
    2417.             for (; newLine < m_TextComponent.textInfo.lineCount - 1; newLine++)
    2418.             {
    2419.                 if (m_TextComponent.textInfo.lineInfo[newLine].baseline < m_TextComponent.textInfo.lineInfo[originLine].baseline - viewportHeight)
    2420.                     break;
    2421.             }
    2422.  
    2423.             // Need to determine end line for next line.
    2424.             int endCharIdx = m_TextComponent.textInfo.lineInfo[newLine].lastCharacterIndex;
    2425.  
    2426.             int closest = -1;
    2427.             float distance = TMP_Math.FLOAT_MAX;
    2428.             float range = 0;
    2429.  
    2430.             for (int i = m_TextComponent.textInfo.lineInfo[newLine].firstCharacterIndex; i < endCharIdx; ++i)
    2431.             {
    2432.                 TMP_CharacterInfo currentChar = m_TextComponent.textInfo.characterInfo[i];
    2433.  
    2434.                 float d = originChar.origin - currentChar.origin;
    2435.                 float r = d / (currentChar.xAdvance - currentChar.origin);
    2436.  
    2437.                 if (r >= 0 && r <= 1)
    2438.                 {
    2439.                     if (r < 0.5f)
    2440.                         return i;
    2441.                     else
    2442.                         return i + 1;
    2443.                 }
    2444.  
    2445.                 d = Mathf.Abs(d);
    2446.  
    2447.                 if (d < distance)
    2448.                 {
    2449.                     closest = i;
    2450.                     distance = d;
    2451.                     range = r;
    2452.                 }
    2453.             }
    2454.  
    2455.             if (closest == -1) return endCharIdx;
    2456.  
    2457.             if (range < 0.5f)
    2458.                 return closest;
    2459.             else
    2460.                 return closest + 1;
    2461.         }
    2462.  
    2463.  
    2464.         private void MoveDown(bool shift)
    2465.         {
    2466.             MoveDown(shift, true);
    2467.         }
    2468.  
    2469.  
    2470.         private void MoveDown(bool shift, bool goToLastChar)
    2471.         {
    2472.             if (hasSelection && !shift)
    2473.             {
    2474.                 // If we have a selection and press down without shift,
    2475.                 // set caret to end of selection before we move it down.
    2476.                 caretPositionInternal = caretSelectPositionInternal = Mathf.Max(caretPositionInternal, caretSelectPositionInternal);
    2477.             }
    2478.  
    2479.             int position = multiLine ? LineDownCharacterPosition(caretSelectPositionInternal, goToLastChar) : m_TextComponent.textInfo.characterCount - 1; // text.Length;
    2480.  
    2481.             if (shift)
    2482.             {
    2483.                 caretSelectPositionInternal = position;
    2484.                 stringSelectPositionInternal = GetStringIndexFromCaretPosition(caretSelectPositionInternal);
    2485.             }
    2486.             else
    2487.             {
    2488.                 caretSelectPositionInternal = caretPositionInternal = position;
    2489.                 stringSelectPositionInternal = stringPositionInternal = GetStringIndexFromCaretPosition(caretSelectPositionInternal);
    2490.             }
    2491.  
    2492.             #if TMP_DEBUG_MODE
    2493.                 Debug.Log("Caret Position: " + caretPositionInternal + " Selection Position: " + caretSelectPositionInternal + "  String Position: " + stringPositionInternal + " String Select Position: " + stringSelectPositionInternal);
    2494.             #endif
    2495.         }
    2496.  
    2497.         private void MoveUp(bool shift)
    2498.         {
    2499.             MoveUp(shift, true);
    2500.         }
    2501.  
    2502.  
    2503.         private void MoveUp(bool shift, bool goToFirstChar)
    2504.         {
    2505.             if (hasSelection && !shift)
    2506.             {
    2507.                 // If we have a selection and press up without shift,
    2508.                 // set caret position to start of selection before we move it up.
    2509.                 caretPositionInternal = caretSelectPositionInternal = Mathf.Min(caretPositionInternal, caretSelectPositionInternal);
    2510.             }
    2511.  
    2512.             int position = multiLine ? LineUpCharacterPosition(caretSelectPositionInternal, goToFirstChar) : 0;
    2513.  
    2514.             if (shift)
    2515.             {
    2516.                 caretSelectPositionInternal = position;
    2517.                 stringSelectPositionInternal = GetStringIndexFromCaretPosition(caretSelectPositionInternal);
    2518.             }
    2519.             else
    2520.             {
    2521.                 caretSelectPositionInternal = caretPositionInternal = position;
    2522.                 stringSelectPositionInternal = stringPositionInternal = GetStringIndexFromCaretPosition(caretSelectPositionInternal);
    2523.             }
    2524.  
    2525.             #if TMP_DEBUG_MODE
    2526.                 Debug.Log("Caret Position: " + caretPositionInternal + " Selection Position: " + caretSelectPositionInternal + "  String Position: " + stringPositionInternal + " String Select Position: " + stringSelectPositionInternal);
    2527.             #endif
    2528.         }
    2529.  
    2530.  
    2531.         private void MovePageUp(bool shift)
    2532.         {
    2533.             MovePageUp(shift, true);
    2534.         }
    2535.  
    2536.         private void MovePageUp(bool shift, bool goToFirstChar)
    2537.         {
    2538.             if (hasSelection && !shift)
    2539.             {
    2540.                 // If we have a selection and press up without shift,
    2541.                 // set caret position to start of selection before we move it up.
    2542.                 caretPositionInternal = caretSelectPositionInternal = Mathf.Min(caretPositionInternal, caretSelectPositionInternal);
    2543.             }
    2544.  
    2545.             int position = multiLine ? PageUpCharacterPosition(caretSelectPositionInternal, goToFirstChar) : 0;
    2546.  
    2547.             if (shift)
    2548.             {
    2549.                 caretSelectPositionInternal = position;
    2550.                 stringSelectPositionInternal = GetStringIndexFromCaretPosition(caretSelectPositionInternal);
    2551.             }
    2552.             else
    2553.             {
    2554.                 caretSelectPositionInternal = caretPositionInternal = position;
    2555.                 stringSelectPositionInternal = stringPositionInternal = GetStringIndexFromCaretPosition(caretSelectPositionInternal);
    2556.             }
    2557.  
    2558.  
    2559.             // Scroll to top of viewport
    2560.             //int currentLine = m_TextComponent.textInfo.characterInfo[position].lineNumber;
    2561.             //float lineAscender = m_TextComponent.textInfo.lineInfo[currentLine].ascender;
    2562.  
    2563.             // Adjust text area up or down if not in single line mode.
    2564.             if (m_LineType != LineType.SingleLine)
    2565.             {
    2566.                 float offset = m_TextViewport.rect.height; // m_TextViewport.rect.yMax - (m_TextComponent.rectTransform.anchoredPosition.y + lineAscender);
    2567.  
    2568.                 float topTextBounds = m_TextComponent.rectTransform.position.y + m_TextComponent.textBounds.max.y;
    2569.                 float topViewportBounds = m_TextViewport.position.y + m_TextViewport.rect.yMax;
    2570.  
    2571.                 offset = topViewportBounds > topTextBounds + offset ? offset : topViewportBounds - topTextBounds;
    2572.  
    2573.                 m_TextComponent.rectTransform.anchoredPosition += new Vector2(0, offset);
    2574.                 AssignPositioningIfNeeded();
    2575.                 m_IsScrollbarUpdateRequired = true;
    2576.             }
    2577.  
    2578.             #if TMP_DEBUG_MODE
    2579.                 Debug.Log("Caret Position: " + caretPositionInternal + " Selection Position: " + caretSelectPositionInternal + "  String Position: " + stringPositionInternal + " String Select Position: " + stringSelectPositionInternal);
    2580.             #endif
    2581.  
    2582.         }
    2583.  
    2584.  
    2585.         private void MovePageDown(bool shift)
    2586.         {
    2587.             MovePageDown(shift, true);
    2588.         }
    2589.  
    2590.         private void MovePageDown(bool shift, bool goToLastChar)
    2591.         {
    2592.              if (hasSelection && !shift)
    2593.             {
    2594.                 // If we have a selection and press down without shift,
    2595.                 // set caret to end of selection before we move it down.
    2596.                 caretPositionInternal = caretSelectPositionInternal = Mathf.Max(caretPositionInternal, caretSelectPositionInternal);
    2597.             }
    2598.  
    2599.             int position = multiLine ? PageDownCharacterPosition(caretSelectPositionInternal, goToLastChar) : m_TextComponent.textInfo.characterCount - 1;
    2600.  
    2601.             if (shift)
    2602.             {
    2603.                 caretSelectPositionInternal = position;
    2604.                 stringSelectPositionInternal = GetStringIndexFromCaretPosition(caretSelectPositionInternal);
    2605.             }
    2606.             else
    2607.             {
    2608.                 caretSelectPositionInternal = caretPositionInternal = position;
    2609.                 stringSelectPositionInternal = stringPositionInternal = GetStringIndexFromCaretPosition(caretSelectPositionInternal);
    2610.             }
    2611.  
    2612.             // Scroll to top of viewport
    2613.             //int currentLine = m_TextComponent.textInfo.characterInfo[position].lineNumber;
    2614.             //float lineAscender = m_TextComponent.textInfo.lineInfo[currentLine].ascender;
    2615.  
    2616.             // Adjust text area up or down if not in single line mode.
    2617.             if (m_LineType != LineType.SingleLine)
    2618.             {
    2619.                 float offset = m_TextViewport.rect.height; // m_TextViewport.rect.yMax - (m_TextComponent.rectTransform.anchoredPosition.y + lineAscender);
    2620.  
    2621.                 float bottomTextBounds = m_TextComponent.rectTransform.position.y + m_TextComponent.textBounds.min.y;
    2622.                 float bottomViewportBounds = m_TextViewport.position.y + m_TextViewport.rect.yMin;
    2623.  
    2624.                 offset = bottomViewportBounds > bottomTextBounds + offset ? offset : bottomViewportBounds - bottomTextBounds;
    2625.  
    2626.                 m_TextComponent.rectTransform.anchoredPosition += new Vector2(0, offset);
    2627.                 AssignPositioningIfNeeded();
    2628.                 m_IsScrollbarUpdateRequired = true;
    2629.             }
    2630.  
    2631.             #if TMP_DEBUG_MODE
    2632.                 Debug.Log("Caret Position: " + caretPositionInternal + " Selection Position: " + caretSelectPositionInternal + "  String Position: " + stringPositionInternal + " String Select Position: " + stringSelectPositionInternal);
    2633.             #endif
    2634.  
    2635.         }
    2636.  
    2637.         private void Delete()
    2638.         {
    2639.             if (m_ReadOnly)
    2640.                 return;
    2641.  
    2642.             if (stringPositionInternal == stringSelectPositionInternal)
    2643.                 return;
    2644.  
    2645.             if (m_isRichTextEditingAllowed || m_isSelectAll)
    2646.             {
    2647.                 // Handling of Delete when Rich Text is allowed.
    2648.                 if (stringPositionInternal < stringSelectPositionInternal)
    2649.                 {
    2650.                     m_Text = text.Remove(stringPositionInternal, stringSelectPositionInternal - stringPositionInternal);
    2651.                     stringSelectPositionInternal = stringPositionInternal;
    2652.                 }
    2653.                 else
    2654.                 {
    2655.                     m_Text = text.Remove(stringSelectPositionInternal, stringPositionInternal - stringSelectPositionInternal);
    2656.                     stringPositionInternal = stringSelectPositionInternal;
    2657.                 }
    2658.  
    2659.                 m_isSelectAll = false;
    2660.             }
    2661.             else
    2662.             {
    2663.                 if (caretPositionInternal < caretSelectPositionInternal)
    2664.                 {
    2665.                     stringPositionInternal = m_TextComponent.textInfo.characterInfo[caretPositionInternal].index;
    2666.                     stringSelectPositionInternal = m_TextComponent.textInfo.characterInfo[caretSelectPositionInternal - 1].index + m_TextComponent.textInfo.characterInfo[caretSelectPositionInternal - 1].stringLength;
    2667.  
    2668.                     m_Text = text.Remove(stringPositionInternal, stringSelectPositionInternal - stringPositionInternal);
    2669.  
    2670.                     stringSelectPositionInternal = stringPositionInternal;
    2671.                     caretSelectPositionInternal = caretPositionInternal;
    2672.                 }
    2673.                 else
    2674.                 {
    2675.                     stringPositionInternal = m_TextComponent.textInfo.characterInfo[caretPositionInternal - 1].index + m_TextComponent.textInfo.characterInfo[caretPositionInternal - 1].stringLength;
    2676.                     stringSelectPositionInternal = m_TextComponent.textInfo.characterInfo[caretSelectPositionInternal].index;
    2677.  
    2678.                     m_Text = text.Remove(stringSelectPositionInternal, stringPositionInternal - stringSelectPositionInternal);
    2679.  
    2680.                     stringPositionInternal = stringSelectPositionInternal;
    2681.                     caretPositionInternal = caretSelectPositionInternal;
    2682.                 }
    2683.             }
    2684.  
    2685.             #if TMP_DEBUG_MODE
    2686.                 Debug.Log("Caret Position: " + caretPositionInternal + " Selection Position: " + caretSelectPositionInternal + "  String Position: " + stringPositionInternal + " String Select Position: " + stringSelectPositionInternal);
    2687.             #endif
    2688.         }
    2689.  
    2690.         /// <summary>
    2691.         /// Handling of DEL key
    2692.         /// </summary>
    2693.         private void DeleteKey()
    2694.         {
    2695.             if (m_ReadOnly)
    2696.                 return;
    2697.  
    2698.             if (hasSelection)
    2699.             {
    2700.                 Delete();
    2701.                 UpdateTouchKeyboardFromEditChanges();
    2702.                 SendOnValueChangedAndUpdateLabel();
    2703.             }
    2704.             else
    2705.             {
    2706.                 if (m_isRichTextEditingAllowed)
    2707.                 {
    2708.                     if (stringPositionInternal < text.Length)
    2709.                     {
    2710.                         // Special handling for Surrogate Pairs
    2711.                         if (char.IsHighSurrogate(text[stringPositionInternal]))
    2712.                             m_Text = text.Remove(stringPositionInternal, 2);
    2713.                         else
    2714.                             m_Text = text.Remove(stringPositionInternal, 1);
    2715.  
    2716.                         UpdateTouchKeyboardFromEditChanges();
    2717.                         SendOnValueChangedAndUpdateLabel();
    2718.                     }
    2719.                 }
    2720.                 else
    2721.                 {
    2722.                     if (caretPositionInternal < m_TextComponent.textInfo.characterCount - 1)
    2723.                     {
    2724.                         int numberOfCharactersToRemove = m_TextComponent.textInfo.characterInfo[caretPositionInternal].stringLength;
    2725.  
    2726.                         // Adjust string position to skip any potential rich text tags.
    2727.                         int nextCharacterStringPosition = m_TextComponent.textInfo.characterInfo[caretPositionInternal].index;
    2728.  
    2729.                         m_Text = text.Remove(nextCharacterStringPosition, numberOfCharactersToRemove);
    2730.  
    2731.                         SendOnValueChangedAndUpdateLabel();
    2732.                     }
    2733.                 }
    2734.             }
    2735.  
    2736.             #if TMP_DEBUG_MODE
    2737.                 Debug.Log("Caret Position: " + caretPositionInternal + " Selection Position: " + caretSelectPositionInternal + "  String Position: " + stringPositionInternal + " String Select Position: " + stringSelectPositionInternal);
    2738.             #endif
    2739.         }
    2740.  
    2741.         /// <summary>
    2742.         /// Handling of Backspace key
    2743.         /// </summary>
    2744.         private void Backspace()
    2745.         {
    2746.             if (m_ReadOnly)
    2747.                 return;
    2748.  
    2749.             if (hasSelection)
    2750.             {
    2751.                 Delete();
    2752.                 UpdateTouchKeyboardFromEditChanges();
    2753.                 SendOnValueChangedAndUpdateLabel();
    2754.             }
    2755.             else
    2756.             {
    2757.                 if (m_isRichTextEditingAllowed)
    2758.                 {
    2759.                     if (stringPositionInternal > 0)
    2760.                     {
    2761.                         int numberOfCharactersToRemove = 1;
    2762.  
    2763.                         // Special handling for Surrogate pairs and Diacritical marks
    2764.                         if (char.IsLowSurrogate(text[stringPositionInternal - 1]))
    2765.                             numberOfCharactersToRemove = 2;
    2766.  
    2767.                         stringSelectPositionInternal = stringPositionInternal = stringPositionInternal - numberOfCharactersToRemove;
    2768.  
    2769.                         m_Text = text.Remove(stringPositionInternal, numberOfCharactersToRemove);
    2770.  
    2771.                         caretSelectPositionInternal = caretPositionInternal = caretPositionInternal - 1;
    2772.  
    2773.                         m_isLastKeyBackspace = true;
    2774.  
    2775.                         UpdateTouchKeyboardFromEditChanges();
    2776.                         SendOnValueChangedAndUpdateLabel();
    2777.                     }
    2778.                 }
    2779.                 else
    2780.                 {
    2781.                     if (caretPositionInternal > 0)
    2782.                     {
    2783.                         int numberOfCharactersToRemove = m_TextComponent.textInfo.characterInfo[caretPositionInternal - 1].stringLength;
    2784.  
    2785.                         // Delete the previous character
    2786.                         m_Text = text.Remove(m_TextComponent.textInfo.characterInfo[caretPositionInternal - 1].index, numberOfCharactersToRemove);
    2787.  
    2788.                         // Get new adjusted string position
    2789.                         stringSelectPositionInternal = stringPositionInternal = caretPositionInternal < 2
    2790.                             ? m_TextComponent.textInfo.characterInfo[0].index
    2791.                             : m_TextComponent.textInfo.characterInfo[caretPositionInternal - 2].index + m_TextComponent.textInfo.characterInfo[caretPositionInternal - 2].stringLength;
    2792.  
    2793.                         caretSelectPositionInternal = caretPositionInternal = caretPositionInternal - 1;
    2794.                     }
    2795.  
    2796.                     m_isLastKeyBackspace = true;
    2797.  
    2798.                     UpdateTouchKeyboardFromEditChanges();
    2799.                     SendOnValueChangedAndUpdateLabel();
    2800.                 }
    2801.  
    2802.             }
    2803.  
    2804.             #if TMP_DEBUG_MODE
    2805.                 Debug.Log("Caret Position: " + caretPositionInternal + " Selection Position: " + caretSelectPositionInternal + "  String Position: " + stringPositionInternal + " String Select Position: " + stringSelectPositionInternal);
    2806.             #endif
    2807.         }
    2808.  
    2809.  
    2810.         /// <summary>
    2811.         /// Append the specified text to the end of the current.
    2812.         /// </summary>
    2813.         protected virtual void Append(string input)
    2814.         {
    2815.             if (m_ReadOnly)
    2816.                 return;
    2817.  
    2818.             if (InPlaceEditing() == false)
    2819.                 return;
    2820.  
    2821.             for (int i = 0, imax = input.Length; i < imax; ++i)
    2822.             {
    2823.                 char c = input[i];
    2824.  
    2825.                 if (c >= ' ' || c == '\t' || c == '\r' || c == 10