I feel like this a very basic text editor functionality that seems missing in unity input field.
This would be really nice indeed.
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.
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.
Very much appreciated Stephan
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;
}
}