Search Unity

Tab indexing? Tab to go to next input field (forms, for example) like vanilla .NET form?

Discussion in 'UGUI & TextMesh Pro' started by MrLucid72, Sep 30, 2016.

  1. MrLucid72

    MrLucid72

    Joined:
    Jan 12, 2016
    Posts:
    992
    Example:

    Input1 (TAB >> Focus Input2 and highlight text)
    Input2 (TAB >> Focus Input3 and highlight text)
    Input3 (TAB >> Focus Input1 and highlight text)

    (Shift+tab = backwards)

    https://community.unity.com/t5/Unity-UI/Tab-between-input-fields/td-p/1855003

    I'm looking at this thread made in 2014 -- a Unity dev implified it should already be here (by reporting as a bug rather than feedback), but isn't found so far:

    > Hi, we don't support this currently, but the functionality should be added, please file a bug.

    Anyone have any 2016 solutions? All the workarounds seem super outdated that I've seen, other than to make a khook for tab and do something a bit ghetto :)
     
  2. Brathnann

    Brathnann

    Joined:
    Aug 12, 2014
    Posts:
    7,188
  3. Zaflis

    Zaflis

    Joined:
    May 26, 2014
    Posts:
    438
    Input should also inherit class Selectable, which has this function https://docs.unity3d.com/ScriptReference/UI.Selectable-allSelectables.html
    You might have to keep a cache of the list, unless you want to redo the search everytime you hit tab. That could be cpu costly though, or maybe not too much. Either way, find index of the currently selected button that EventSystem.currentSelectedGameObject tells, and select the next one.

    And this sort of global script you could add once to the same object that holds EventSystem component.
    Code (CSharp):
    1. void Update() {
    2.   if(Input.GetKeyDown(KeyCode.Tab)) {
    3.     // ...
    4.   }
    5. }
     
    Kasi2302 and MrLucid72 like this.
  4. MrLucid72

    MrLucid72

    Joined:
    Jan 12, 2016
    Posts:
    992
    `if(Input.GetKeyDown(KeyCode.Tab)){`

    This is the method I ended up using. I'd revamp it in a heartbeat for tab indexes, but this is good for now. Unfortunately with this, you'd have to manually throw them to the next box for every input. Luckily I don't have many inputs!

    Shift tab would also have to be coded separately
     
    Kasi2302 likes this.
  5. Kaze47

    Kaze47

    Joined:
    May 24, 2016
    Posts:
    1
    Code (CSharp):
    1.  
    2. if (Input.GetKeyDown(KeyCode.Tab))
    3. {
    4.     if (Input.GetKey(KeyCode.LeftShift))
    5.     {
    6.         if (EventSystem.current.currentSelectedGameObject != null)
    7.         {
    8.             Selectable selectable = EventSystem.current.currentSelectedGameObject.GetComponent<Selectable>().FindSelectableOnUp();
    9.             if (selectable != null)
    10.                 selectable.Select();
    11.         }
    12.     }
    13.     else
    14.     {
    15.         if (EventSystem.current.currentSelectedGameObject != null)
    16.         {
    17.             Selectable selectable = EventSystem.current.currentSelectedGameObject.GetComponent<Selectable>().FindSelectableOnDown();
    18.             if (selectable != null)
    19.                 selectable.Select();
    20.         }
    21.     }
    22. }
    23.  
     
  6. Fattie

    Fattie

    Joined:
    Jul 5, 2012
    Posts:
    476
    Code (CSharp):
    1. if (Input.GetKeyDown(KeyCode.Tab))
    2.         {
    3.             GameObject c = EventSystem.current.currentSelectedGameObject;
    4.             if (c == null) { return; }
    5.        
    6.             Selectable s = c.GetComponent<Selectable>();
    7.             if (s == null) { return; }
    8.  
    9.             Selectable jump = Input.GetKey(KeyCode.LeftShift)
    10.                 ? s.FindSelectableOnUp() : s.FindSelectableOnDown();
    11.             if (jump != null) { jump.Select(); }
    12.         }
     
    Kasi2302 likes this.
  7. capgunmatt

    capgunmatt

    Joined:
    Feb 29, 2020
    Posts:
    8
    The way I did it was out of necessity because the methods "FindSelectableOnDown" or left or right etc, didn't work. They would skip fields that were directly left or right, etc. So I needed to do this.

    Basic hierarchy of GameObjects:
    Note main common parent "InvestigateTimeStackedSelectionPanel, which has the InputNavigator script/Component attached as per step 1.

    Note the Year, Month, Day, Hour, Minute, Seconds GameObjects which each have a InputField on them (example selected in blue). These objects will have the InputFieldDetector script attached as per step 2.

    upload_2021-1-19_10-7-59.png


    Step 1)

    As per ideas in this thread https://forum.unity.com/threads/tab-between-input-fields.263779/

    I create a class that allows you to manually put the Gameobjects in a list in the Unity Editor

    Code (CSharp):
    1. using System;
    2. using System.Collections.Generic;
    3. using System.Linq;
    4. using System.Text;
    5. using System.Threading.Tasks;
    6. using UnityEngine;
    7. using System.Collections;
    8. using UnityEngine.UI;
    9. using UnityEngine.EventSystems;
    10.  
    11.  
    12.     /// <summary>
    13.     /// Implements basic tabbing/cycling through a list of GameObjects which have InputField components on them
    14.     /// </summary>
    15.     public class InputNavigator : MonoBehaviour
    16.     {
    17.         EventSystem EventSystem;
    18.  
    19.         /// <summary>
    20.         /// List of GameObjects that are selectable
    21.         /// </summary>
    22.         public List<GameObject> Selectables;
    23.  
    24.         /// <summary>
    25.         /// The index of the current selected GameObject
    26.         /// </summary>
    27.         public int CurrentSelectableIndex = 0;
    28.  
    29.         void Start()
    30.         {
    31.             EventSystem = EventSystem.current;
    32.         }
    33.  
    34.         void Update()
    35.         {
    36.             if (Input.GetKeyDown(KeyCode.Tab)
    37.                 || Input.GetKeyDown(KeyCode.RightArrow))
    38.             {
    39.                 CurrentSelectableIndex += 1;
    40.                 EventSystem.SetSelectedGameObject(Selectables[CurrentSelectableIndex % Selectables.Count()], new BaseEventData(EventSystem));
    41.             }
    42.  
    43.             if (Input.GetKeyDown(KeyCode.LeftArrow))
    44.             {
    45.                 CurrentSelectableIndex -= 1;
    46.                 EventSystem.SetSelectedGameObject(Selectables[CurrentSelectableIndex % Selectables.Count()], new BaseEventData(EventSystem));
    47.             }
    48.         }
    49.     }
    50.  
    upload_2021-1-19_10-7-10.png


    Step 2)


    As per this Thread https://forum.unity.com/threads/inputfield-onclick.399590/ I'd add the following script to each GameObject with an InputField component. I then manually number these gameobjects in their instance of this script

    Code (CSharp):
    1. using System;
    2. using System.Collections.Generic;
    3. using System.Linq;
    4. using System.Text;
    5. using System.Threading.Tasks;
    6. using UnityEngine;
    7. using System.Collections;
    8. using UnityEngine.UI;
    9. using UnityEngine.EventSystems;
    10.  
    11. public class InputFieldFocusDetector : MonoBehaviour, ISelectHandler
    12.     {
    13.         public InputNavigator InputNavigator;
    14.  
    15.         /// <summary>
    16.         /// The index of this InputField according to its order in the Selectables List in its <see cref="InputNavigator"/> instance
    17.         /// </summary>
    18.         public int InputIndex;
    19.  
    20.         public void OnSelect(BaseEventData data)
    21.         {
    22.             InputNavigator.CurrentSelectableIndex = InputIndex;
    23.         }
    24.     }
    25.  
    26.  
    upload_2021-1-19_10-7-36.png


    Yes it involves some manual setting in the editor, but yes it works.

    I could implement shift+tab but haven't seen the importance of it yet.
     
    Kasi2302 likes this.
  8. Acreates

    Acreates

    Joined:
    Dec 12, 2016
    Posts:
    41
    I've looked far and wide...THIS IS THE WAY!