Search Unity

TextMesh Pro A way to have InputField (TMPro) not auto-enter edit mode on selection?

Discussion in 'UGUI & TextMesh Pro' started by Democide, Jul 21, 2020.

  1. Democide

    Democide

    Joined:
    Jan 29, 2013
    Posts:
    315
    Currently, the InputField behavior, if using keyboard/controller is as follows:

    Navigate to inputField
    It becomes selected & highlighted
    Text-entry is active (caret is visible)

    You can then hit cancel to back out of the text-entry

    inputField is selected & highlighted
    Text entry is inactive (caret is invisible)

    Now what I'd like to do is have the inputField NOT automatically go into text-entry, just by navigating/selecting it with a controller (while still doing so via mouse). Instead I'd like it to be in the mode it is in when you hit ESC: It is selected and highlighted but text entry is inactive. Once you hit SUBMIT the field moves to text entry mode.

    Does anyone know if that's possible without fiddling with the component code itself? (inheriting etc.)
     
  2. Democide

    Democide

    Joined:
    Jan 29, 2013
    Posts:
    315
    I've tried out a few things to solve this but to no avail, so I'm bumping it.

    For example: I tried a script on the same component that runs DeactivateInputField in OnSelect and ActivateInputField in OnSubmit. Or I tried the same with readOnly on the input field. Nothing seemed to do the trick.
     
  3. MaxPfeil

    MaxPfeil

    Joined:
    Dec 20, 2019
    Posts:
    10
    Regarding the auto-edit mode:
    One way would be to nest the input field under a button and setup explicit navigation between the rest of your UI and the nested button/input field (to avoid auto-navigating from a different UI element to the input field).
    The button On Click() would call InputField.Select, thus entering the edit mode.

    Regarding the text highlighting:
    You could add an event trigger to the button and set it to Select. It would need to call a helper method to edit the appearance of the underlying input field to highlight the text. The same for the OnSelect for the input field, but reversing the effect.
     
    WEsualize likes this.
  4. horsesNhalo

    horsesNhalo

    Joined:
    Dec 23, 2017
    Posts:
    2
    I hate to revive a dead thread but I couldn't find a solution anywhere and I have found a work around. I don't really like it but it works and it's compact.
    • Add a callback to TMPInputField OnSelect to toggle the enabled bool of the input field off
    • add an event trigger script to the object, add an OnSelect callback and toggle the enabled bool back on.
    This works because TMPro will attempt to activate immediately after invoking the OnSelect callbacks. Usually it will set itself to activate the next frame and there's nothing to stop it after this point. However, it won't set itself to activate if enabled is set to false beforehand. Then immediately after it skips this activation the event trigger is hit next and it sets enabled back on so it functions as normal. A hacky solution but it works.

    NOTE: this was edited as originally I toggled interactable. This gave the expected behavior, but was causing an error for me, so I changed it to toggle the enabled bool.
     
    Last edited: Jul 12, 2022
    AurochJapeth likes this.
  5. losingisfun

    losingisfun

    Joined:
    May 26, 2016
    Posts:
    36
    I ran into this problem as well and I'm shocked at how Unity has not addressed this properly as it's such a vital need. If you're adding controller or console support to your game this non-negotiable. I made a similar fix to the solution (although @horsesNhalo probably has a better solution). I just waited until the end of the frame to set the input to deactive.

    I created this script and I attach it to any game object with an InputField component. Heres an example:

    Code (CSharp):
    1. public class InputControllerHelper : MonoBehaviour, ISelectHandler, ISubmitHandler
    2.     {
    3.         [SerializeField] TouchScreenKeyboardType keyboardType;
    4.         [SerializeField] TMP_InputField inputField;
    5.         void Reset()
    6.         {
    7.             inputField = GetComponent<TMP_InputField>();
    8.         }
    9.  
    10.         public void OnSelect(BaseEventData eventData)
    11.         {
    12.             StartCoroutine(UnFocusByDefault());
    13.         }
    14.  
    15.         IEnumerator UnFocusByDefault()
    16.         {
    17.             yield return new WaitForEndOfFrame();
    18.             inputField.DeactivateInputField();
    19.         }
    20.  
    21.         public void OnSubmit(BaseEventData eventData)
    22.         {
    23.             TouchScreenKeyboard.Open(inputField.text, keyboardType);
    24.         }
    25.     }
    I also added OnSubmit to open up the OS virtual keyboard because if you do it with OnSelect it fails to edit the input because we deselect it the next frame :p
     
    _geo__ and horsesNhalo like this.
  6. _geo__

    _geo__

    Joined:
    Feb 26, 2014
    Posts:
    1,338
    Thanks for this, that's a great snippet.

    If a controller (Xbox, PlayStation) is used then it seems that there is no way to exit the textfield once entered. The culprit seems to be that the "Submit" input actions is nit recognized (only the ENTER key on the keyboard is). I have extended it a bit to support controllers better. Sadly I had to use Update() for this.

    I've also added auto detection for the Input so now you don't have to drag it in anymore. And I have added a RequireComponent attribute since ISelectHandler, ISubmitHandler would only work if the script is directly attached to the TMP gameobject.

    Code (CSharp):
    1.  
    2. [RequireComponent(typeof(TMP_InputField))]
    3. public class TMPInputFocusHelper : MonoBehaviour, ISelectHandler, ISubmitHandler
    4. {
    5.     [SerializeField]
    6.     TouchScreenKeyboardType keyboardType = TouchScreenKeyboardType.Default;
    7.  
    8.     protected TMP_InputField inputTf;
    9.     public TMP_InputField InputTf
    10.     {
    11.         get
    12.         {
    13.             if (inputTf == null)
    14.             {
    15.                 inputTf = this.GetComponent<TMP_InputField>();
    16.             }
    17.             return inputTf;
    18.         }
    19.     }
    20.        
    21.     public void OnSelect(BaseEventData eventData)
    22.     {
    23.         StartCoroutine(UnFocusByDefault());
    24.     }
    25.  
    26.     IEnumerator UnFocusByDefault()
    27.     {
    28.         yield return new WaitForEndOfFrame();
    29.         InputTf.DeactivateInputField();
    30.     }
    31.  
    32.     public void OnSubmit(BaseEventData eventData)
    33.     {
    34.         TouchScreenKeyboard.Open(InputTf.text, keyboardType);
    35.     }
    36.  
    37.     public void Update()
    38.     {
    39.         // Sadly while entering text the "Submit" action does not
    40.         // end the input if done with a controller (keyboard ENTER
    41.         // works just fine).
    42.            
    43.         // Catch Submit directly and end editing
    44.         if (Input.GetButtonDown("Submit") && InputTf.isFocused)
    45.         {
    46.             if (InputTf.isFocused
    47.                 && !Input.GetKeyDown(KeyCode.Return)
    48.                 && !Input.GetKeyDown(KeyCode.KeypadEnter))
    49.             {
    50.                 InputTf.DeactivateInputField();
    51.             }
    52.         }
    53.     }
    54. }
    55.  
     
    Last edited: Oct 27, 2022
  7. rodrigo_pomelo

    rodrigo_pomelo

    Joined:
    Aug 9, 2022
    Posts:
    1
    You can use IUpdateSelectedHandler to only run the update when it's selected (I'm using my own input implementation in this script)

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.EventSystems;
    3. using TMPro;
    4. using System.Collections;
    5.  
    6. [RequireComponent(typeof(TMP_InputField))]
    7. public class TMPInputFocusHelper : MonoBehaviour, ISelectHandler, ISubmitHandler, IUpdateSelectedHandler, IPointerClickHandler {
    8.     public TouchScreenKeyboardType KeyboardType = TouchScreenKeyboardType.Default;
    9.  
    10.     protected TMP_InputField inputTF;
    11.     public TMP_InputField InputTF {
    12.         get {
    13.             if (inputTF == null) {
    14.                 inputTF = this.GetComponent<TMP_InputField>();
    15.             }
    16.             return inputTF;
    17.         }
    18.     }
    19.     RectTransform rectTransform;
    20.  
    21.     private void Awake() {
    22.         rectTransform = transform as RectTransform;
    23.         InputTF.onSubmit.AddListener(SubmitText);
    24.         InputTF.onEndEdit.AddListener(SubmitText);
    25.     }
    26.  
    27.     public void OnSelect(BaseEventData eventData) {
    28.         StartCoroutine(UnFocusByDefault());
    29.     }
    30.  
    31.     IEnumerator UnFocusByDefault() {
    32.         yield return new WaitForEndOfFrame();
    33.         // Deactivating at the end of the frame makes it so
    34.         // it's selected but not in editing mode
    35.         InputTF.DeactivateInputField();
    36.     }
    37.  
    38.     public void OnSubmit(BaseEventData eventData) {
    39.         EditMode();
    40.     }
    41.  
    42.     void SubmitText(string text) {
    43.         InputController.MenuMode();
    44.     }
    45.  
    46.     public void OnUpdateSelected(BaseEventData eventData) {
    47.         if (
    48.             InputController.UI.Accept
    49.             ||
    50.             InputController.UI.Back
    51.             ||
    52.             InputController.UI.Dismiss
    53.         ) {
    54.             InputTF.DeactivateInputField();
    55.             InputController.MenuMode();
    56.         }
    57.     }
    58.  
    59.     public void OnPointerClick(PointerEventData eventData) {
    60.         EditMode();
    61.     }
    62.  
    63.     void EditMode() {
    64.         PlatformServices.ShowOnScreenKeyboard(InputTF.text, KeyboardType,
    65.             rectTransform.WorldRect());
    66.         InputController.TextInputMode();
    67.     }
    68. }