Unity 4.6 UI: How to prevent Deselect(losing focus) in InputField

Hi guys, I need to prevent deselect in InputField. For example : I have smiles popup and I want to show it when you got focus on InputField (you see native keyboard and I want to show that popup above keyboard for example) now when I click on popup item, InputField is losing focus and keyboard is hiding, Is it possible to make my popup items unselectable or something like that, so they won’t get focus and leave it for InputField?
P.S. Return focus to InputField is not a point for me. I need to prevent a losing of focus or getting it by popup;)
Thanks :wink:

I’ll bump this. In conventional UI systems I would use something like “element.SetFocusable(false)” to prevent it from stealing focus when the element is clicked. Is there some way to do it for UI objects?

Can anyone @ Unity answer this?
Only workaround I found is an ugly hack with overriding OnDeselect on InputField which shouldn’t lose the focus and then forcing return of the focus back with SetSelectedGameObject.

right now there isnt anything in place that will help you with what you want to do. That being said i understand your use case and it fits nicely into somethign i’ve been thinking about for a while that just hasnt been done.

I know thats not the answer you were hoping for but hopefully i’ll be able to get some time to fix this sort of problem. If you submit a bug it would let us keep track of it.

Thanks for the answer, at least now we know it’s being looked at :slight_smile:
638430

I had a similar issue as you ortin. I’m making an ingame console with the new UI system and wanted the input field to be constantly focused while the console is visible. After trying for quite a while, I settled on a temporary solution to use while I wait for a better solution. Posting it here in case others stumble across your post as well while searching for solutions.

void Update()
{
    if(inputField.isFocused == false)
    {
          EventSystem.current.SetSelectedGameObject(inputField.gameObject, null);
          inputField.OnPointerClick(new PointerEventData(EventSystem.current));
     }
}

Edit: Realized that I’m not sure if it’s fully viable for your problem, you said you didn’t want to refocus on it but that it instead should never lose focus. Oh well, better than nothing I suppose? :slight_smile:

@ Zec your solution applys an unnormal behavior to my InputField. There is always a new Line added to the text and you can’t see what gets written inside the InputField.

I’m working on a Chat Prototype right now. Lets hope that we’ll get such a functionality soon :slight_smile:

this.inputField.ActivateInputField();

1 Like

Reviving old thread.
Any news on your “something”? :slight_smile:

I want this to.

My work around is to re-activate the input field after the user has pressed my button.

However, I don’t want the text to hilight - which is standard behaviour after the inputField is re-activated (which doesn’t occur until LateUpdate()).

My work requires me to not patch the InputField, so my solution is to wait until the activation occurs and then move the caret to the end:

        void ReactivateInputField(InputField inputField)
        {
            if (inputField != null)
            {
                StartCoroutine(ActivateInputFieldWithoutSelection(inputField));
            }
        }

        IEnumerator ActivateInputFieldWithoutSelection(InputField inputField)
        {
            inputField.ActivateInputField();
            // wait for the activation to occur in a lateupdate
            yield return new WaitForEndOfFrame();
            // make sure we're still the active ui
            if (EventSystem.current.currentSelectedGameObject == inputField.gameObject)
            {
                // To remove hilight we'll just show the caret at the end of the line
                inputField.MoveTextEnd(false);
            }
        }

However, if you are happy to patch InputField, you should be able to override it, and run code after the LateUpdate().

1 Like

@peterept
code works but caret is not blinking any more. Any idea ?

looks like setting inputField.caretPosition forces it to blink too :slight_smile:

IEnumerator ActivateInputFieldWithoutSelection(InputField inputField)
    {
        yield return null;
        inputField.ActivateInputField();

        
        if (EventSystem.current.currentSelectedGameObject == inputField.gameObject)
        {
           // i am using StringBuilder inputBuffer to manually get and set text on inputField
            inputField.caretPosition = inputBuffer.ToString().Length;
        
        }

    }

I know this is pretty late and not exactly what you were doing but I managed to get it (more or less) working. Here’s how I’m typing into input fields using my VR keyboard.

Build your keyboard out of buttons. Build a second set of buttons for shifted key presses. Child one set to “LowerCaseKeys” and the other to “UpperCaseKeys” game objects. The script for the shift button is at the bottom but obviously you just toggle the game objects.

Place the following script on all your buttons (except the shift key) and name the game object of the button the string code for that key press, from here: C# list of string name for Input.GetKey(string name) - Questions & Answers - Unity Discussions
Check “capitalized” on all capital letter keys.

using UnityEngine;
using UnityEngine.UI;

public class VRKeyboardKey: MonoBehaviour
{
    [SerializeField] private bool capitalized;

    private void Start()
    {
        GetComponent<Button>().onClick.AddListener(() => Press());
    }

    public void Press()
    {
        VRInputField input = VRInputField.lastSelected;

        if (input == null) return;
      
        if (input.edited == false)
        {
            input.caretPosition = input.caretPos;
            input.selectionAnchorPosition = input.selectionAnchorPos;
        }

        Event keyPress = Event.KeyboardEvent(transform.name);

        if (capitalized) keyPress.character = char.ToUpper(keyPress.character);

        input.ProcessEvent(keyPress);
          
        input.ForceLabelUpdate();

        if (input.edited == false)
        {
            input.edited = true;
            input.caretPos = input.selectionAnchorPos;
            input.selectionAnchorPos = -1;
        }
    }
}

Then replace all the relevant input fields with this derived class.

public class VRInputField : UnityEngine.UI.InputField
{
    public int caretPos;
    public int selectionAnchorPos;
    public bool edited;

    public static VRInputField lastSelected;

    // Update is called once per frame
    void Update()
    {
        if (isFocused)
        {
            selectionAnchorPos = selectionAnchorPosition;
            caretPos = caretPosition;
            edited = false;

            lastSelected = this;
        }
    }
}

As for capital letters, here’s my shift key script for toggling the keyboard button sets:

using UnityEngine;
using UnityEngine.UI;

public class ShiftKey : MonoBehaviour
{
    private bool shiftOn;

    [SerializeField] private GameObject lowerCaseKeys;
    [SerializeField] private GameObject upperCaseKeys;

    private void Start()
    {
        GetComponent<Button>().onClick.AddListener(() => ToggleShiftKeys());
    }

    public void ToggleShiftKeys()
    {
        shiftOn = !shiftOn;

        lowerCaseKeys.SetActive(!shiftOn);
        upperCaseKeys.SetActive(shiftOn);
    }
}

The caret wont show while you’re typing but otherwise this works pretty well and is surprisingly simple. If someone can work out the caret please let me know.

2 Likes

Super-necro but I solved this by extending the relevant UI class and this is a top google result. Here’s the snippet for inputfields on iOS at least:

using UnityEngine.EventSystems;
using UnityEngine.UI;

public class PermanentInput : InputField
{
    public override void OnDeselect(BaseEventData eventData)
    {
        //I don't think is necessary but I'm too lazy to rebuild to ios to check. You can probably just return.
        this.OnSelect(eventData);
    }
}

Christ it kills me that this is still unsolved. Adding my “solution”, since this thread is still current on google.

Here’s a script with lots of functions for saving and restoring the selected input field (+text mesh pro input), including the carat/selection state, using much of the wisdom presented here. Activates in the same frame, removing the single frame visual glitch where the keyboard starts hiding before it comes back again.

User is in charge of handling when the state should be saved and restored, since it’s often a bit situational - although if you add the script as a component in your scene it’ll keep track of the last selected input field state.

In my case, I save the state when the user first selects an input field, and some buttons in my app force it to be restored. Note that my buttons needed to switch to OnDown rather than OnClick to make this work nicely (although you could just restore on both events instead)

Wow, it’s been almost a decade and there’s still no official solution. I’ve come up with 2 solutions for this: the quick one and the longer one.

1. The quick solution:
Uses the IPointerClickHandler interface to reestablish focus to a fallback selectable when it’s unintentionally deselected.

This component:

  • Requires a reference to the selectable you want to keep the focus on.
  • Doesn’t prevent your fallback selectable from losing focus like OP wanted, it just instantly reestablishes it when it’s lost.
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

public class UnfocusableSelectable : MonoBehaviour, IPointerClickHandler
{
    [Tooltip("The Selectable that will retrieve the focus when this one is clicked.")]
    [SerializeField] private Selectable _focusFallbackSelectable;

    public void OnPointerClick(PointerEventData eventData) =>
        eventData.selectedObject = _focusFallbackSelectable.gameObject
    ;
}

2. The longer solution:
Involves using an image, colors, interfaces and events to create an interactable that operates outside the UI navigation system.

This component:

  • Is highly extensible.
  • Makes your interactables truly unfocusable.

Here’s a version that should serve most cases:

using System;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

[RequireComponent(typeof(Image))]
public class UnfocusableInteractable :
    MonoBehaviour,
    IPointerClickHandler,
    IPointerDownHandler,
    IPointerEnterHandler,
    IPointerExitHandler,
    IPointerUpHandler
{
    // Variables.
    private Image _interactableImage;
    private bool _interactable = true;


    // Properties.
    public bool Interactable
    {
        get => _interactable;
        set
        {
            _interactableImage.color = value ?
                ColorBlock.defaultColorBlock.normalColor :
                ColorBlock.defaultColorBlock.disabledColor
            ;
            _interactable = value;
        }
    }


    // Events.
    public Action OnClick;


    // MonoBehaviour.
    private void Awake() => _interactableImage = GetComponent<Image>();


    // Interface Methods.
    public void OnPointerClick(PointerEventData eventData)
    {
        if (Interactable) OnClick?.Invoke();
    }

    public void OnPointerDown(PointerEventData eventData)
    {
        if (Interactable) _interactableImage.color = ColorBlock.defaultColorBlock.pressedColor;
    }

    public void OnPointerEnter(PointerEventData eventData)
    {
        if (Interactable) _interactableImage.color = ColorBlock.defaultColorBlock.highlightedColor;
    }

    public void OnPointerExit(PointerEventData eventData)
    {
        if (Interactable) _interactableImage.color = ColorBlock.defaultColorBlock.normalColor;
    }

    public void OnPointerUp(PointerEventData eventData)
    {
        if (Interactable) _interactableImage.color = ColorBlock.defaultColorBlock.selectedColor;
    }
}