Make input field support Ctrl+Backspace to erase a word.

I feel like this a very basic text editor functionality that seems missing in unity input field.

2 Likes

This would be really nice indeed.

1 Like

Are there any news to this? Unity or the Text Mesh Pro Team should implement this basic function. I just implemented it myself by writing a script extending from TMP_Inputfield and trimming the string as usually done by pressing CTRL + Backspace. Let me know if you are interested in this little fix.

1 Like

I’ll consider adding this the next time I work on the Input Field and try to get this into the next set of preview releases which I am still working on.

3 Likes

Very much appreciated Stephan

1 Like

Any chance you can post the script to save me the hassle of writing it up myself?

Here is the whole Inputfield I did, it also has case transformation (uppercase to lower case, and vice versa) as well a a callback when you finished editing the textfield by hitting tab or enter. The Trim String function is actually the one just taking care of the ctrl + backspace stuff… Have Fun.

public class KK_InputField : TMP_InputField
    {
        enum CaseTransformation { none, toLower, toUpper }

        Coroutine inputChecker;

        protected TMP_Text placeholderText;
        protected string fallBackText; //Standard text displayed in placeholder
        protected Color32 fallBackTextColor; //Standard Color for placeholder Text

        Selectable nextField;

        [SerializeField]
        CaseTransformation caseTransformation = CaseTransformation.none;

        protected override void Awake()
        {
            base.Awake();
            placeholderText = placeholder.GetComponent<TMP_Text>();
            fallBackText = placeholderText.text;
            fallBackTextColor = placeholderText.color;
        }

        protected override void OnEnable()
        {
            base.OnEnable();
            onSelect.AddListener(OnSelect);
            onValueChanged.AddListener(OnValueChanged);
            onDeselect.AddListener((string s) => onSubmit?.Invoke(s));
        }

        protected override void OnDisable()
        {
            base.OnDisable();
            onSelect.RemoveListener(OnSelect);
            onValueChanged.RemoveListener(OnValueChanged);
            onDeselect.RemoveAllListeners();
            if (inputChecker != null) StopCoroutine(inputChecker);
        }

        protected virtual void OnSelect(string s)
        {
            inputChecker = StartCoroutine(CustomInputCheck());
            nextField = GetComponent<Selectable>().FindSelectableOnRight();
            if (nextField == null || nextField.gameObject.activeSelf == false) nextField = GetComponent<Selectable>().FindSelectableOnDown();
        }
        void OnValueChanged(string s)
        {
            onValueChanged.RemoveListener(OnValueChanged);
            if (caseTransformation == CaseTransformation.none) return;
            if (caseTransformation == CaseTransformation.toUpper) text = text.ToUpper();
            else text = text.ToLower();
            onValueChanged.AddListener(OnValueChanged);
        }
        IEnumerator CustomInputCheck()
        {
            yield return new WaitForSeconds(0.2f);

            while (EventSystem.current.currentSelectedGameObject == gameObject)
            {
                while (Input.GetKey(KeyCode.LeftControl) && Input.GetKey(KeyCode.Backspace))
                {
                    if (string.IsNullOrEmpty(text)) break;
                    text = TrimString(text);

                    yield return new WaitForSeconds(0.2f);
                }

                if ((Input.GetKeyDown(KeyCode.Tab) || Input.GetKeyDown(KeyCode.Return)) && TabOrEnter()) yield break;

                yield return null;
            }
        }

        public virtual bool TabOrEnter()
        {
            onSubmit?.Invoke(text);
            if (nextField == null || nextField.gameObject.activeSelf == false) return false;
            TMP_InputField inputField = nextField.GetComponent<TMP_InputField>();
            if (inputField != null) inputField.OnPointerClick(new PointerEventData(EventSystem.current));
            EventSystem.current.SetSelectedGameObject(nextField.gameObject, new BaseEventData(EventSystem.current));
            return true;
        }

        string TrimString(string s)
        {
            if (s[s.Length - 1] == ' ') s.Trim();

            string returnString;

            if (s.Contains(" "))
            {
                returnString = s.Substring(0, s.LastIndexOf(' '));
            }
            else
            {
                returnString = "";
            }

            return returnString;
        }
    }
1 Like