Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Question How to detect that a TextField is focused?

Discussion in 'UI Toolkit' started by Refeas, Sep 8, 2020.

  1. Refeas

    Refeas

    Joined:
    Nov 8, 2016
    Posts:
    192
    As the title says - how do I detect that a certain TextField is focused? My use case is I want to detect that there is no focused input for the player movement input etc. In uGUI, I used the Selectable APi for this. Is there any alternative in UITK?

    Thanks!
     
  2. Refeas

    Refeas

    Joined:
    Nov 8, 2016
    Posts:
    192
    So there's currently no way to do this?
     
  3. JuliaP_Unity

    JuliaP_Unity

    Unity Technologies

    Joined:
    Mar 26, 2020
    Posts:
    696
    Hi there, have you tried looking into the FocusController? https://docs.unity3d.com/ScriptReference/UIElements.FocusController-focusedElement.html

    For example:

    if (textField.panel.focusController.focusedElement == textField) DoSomething();


    But it's possible that the TextField in particular doesn't behave like the others when focus is concerned (maybe it's one of its children that gets the focus for some reason) so possibly you'll have to do something else to get it to work, like testing focusedElement?.parent== textField or maybe you'll need to use some kind of textField.Q(someChildSelector).

    Hope that helps!
     
    _geo__, jjbish and Nexer8 like this.
  4. Refeas

    Refeas

    Joined:
    Nov 8, 2016
    Posts:
    192
    Hey @JuliaP_Unity,
    thank you for your reply! Indeed, the first code snippet you provided works as expected. However, it's really verbose. It would be great to add some simpler public API like
    textField.IsFocused
    or something similar, for inputs it's especially useful. Also, TextFields should probably have the Focus() behaviour overridden to focus the input directly, right now I have to do
    textField.elementAt(0).Focus();
    to focus the input itself. I will go with your solution for now. :)
     
  5. JuliaP_Unity

    JuliaP_Unity

    Unity Technologies

    Joined:
    Mar 26, 2020
    Posts:
    696
    Thanks for the feedback @Refeas , we're taking a note of it ;)
     
    Doomchecker and Nexer8 like this.
  6. Crouching-Tuna

    Crouching-Tuna

    Joined:
    Apr 4, 2014
    Posts:
    82
    Hi. Bumping this a bit..

    So in my case, i have a ListView, with templates added containing TextField at runtime
    I update a list to contain all TextField under my window, and then iterate through all of them if it has panel.focusController.focusElement == tf;
    This didn't work, and apparently focusElement points to the ListView.

    So i then do a:
    Code (CSharp):
    1. VisualElement tocheck = tf;
    2. while(toCheck.parent != panel)
    3. {
    4. if(tf.panel.focusController.focusElement == toCheck)
    5.    return true;
    6. toCheck = toCheck.parent;
    7. }
    8. return false;
    9.  
    Anyways, this works. But now i'm having trouble doing Blur() to unfocus
    I changed the above to return the toCheck VE, and doing that.Blur();, but the focus doesn't unfocus

    All in all, i'm not sure how the focusController works. From the docs it says "Each Panel should have an instance of this class. The instance holds the currently focused VisualElement and is responsible for changing it"

    So if i have a hierarchy of VE, each of their focusController can have its focusElement pointing to random other stuff? What determines what the focused VE is?

    edit:
    To clarify: I have HasInputActive() which is the above snippet, and i have a Unfocus() method, which does HasInputActive to find the focused TextField, and if there is, call Blur() on it.
    My TextField has .isDelayed = true, so the OnValuChangedCallback only fires when i press submit
    I call this Unfocus when i press submit. But on submit, HasInputActive returns null and so didn't call the Blur. So maybe Submit releases focus?
    But the weird thing is, HasInputActive (which is called in Update) still says that the ListView is the focusElement, even after Submit

    So to make it simpler, maybe i'll rephrase what i'm looking for:
    How do i Unfocus on whatever it is that has the current focus?
    And.. why do i have to check if(tf.focusController.focusElement == tf) ? Is it not enough to just check if tf.focusController.focusElement != null ?
     
    Last edited: Jan 1, 2021
  7. uBenoitA

    uBenoitA

    Unity Technologies

    Joined:
    Apr 15, 2020
    Posts:
    214
    Hi,

    Just to be clear, FocusController is one-per-panel, not one-per-element.

    I'm not sure what is exactly happening in your case, but I can see one possible problem. You're reacting to the submit event, which already acts on the focus of the TextField (it deselects the text input area). Maybe there is interference between your method calls and the TextField's reaction?

    To unfocus whatever has the focus, you can try
    panel.focusController.focusedElement?.Blur();
    . The only case where it wouldn't work is if there are other focus changes happening on the call stack from the ongoing events. In that case, you could try setting a local variable to true and calling that Blur() on Update. That's not the prettiest way to code though.

    We're still fixing some bugs and loose ends here and there, and there are some that relate to the FocusController unfortunately. We're not trying to encourage programming defensively but it might be necessary sometimes, when your use case is exposing a bug that's a bit rarer for the rest of the users and that we might not have had the time to tackle at this point in time.

    I hope this helps you fix your issues :)
     
  8. thelebaron

    thelebaron

    Joined:
    Jun 2, 2013
    Posts:
    851
    Does this still work in 2021.2 alpha 9? In my debugging, the
    panel
    part is null for my textfield. Kinda hard to track down what changed from 2020.x to 2021.2 with the package being internal now and no changelog

    edit resolved - I think this was just my unconventional convoluted setup as for whatever reason it worked in prior editor versions but the latest it didnt, simplifying my own code fixed my issues.
     
    Last edited: Apr 5, 2021
  9. MarcGFJ

    MarcGFJ

    Joined:
    May 16, 2019
    Posts:
    24
    The FocusController trick didn't work for me.

    I have an IntegerField in a cell of MultiColumnListView which has to update every frame to display the value of something in the game, but when the user selects the field to type a number in it, I don't want the field to keep changing constantly. So in the code that updates the field I tried:

    Code (CSharp):
    1. _numField.panel.focusController.focusedElement ==_numField
    But that didn't work. In fact, `focusedElement` returned the `MultiColumnListView` itself and not the IntegerField I was typing into.

    Registering to `FocusEvent` and `BlurEvent` worked though. However, I might need something else for doing this because after pressing Enter the field remains focused without actually "being edited" and in this case I'd expect it to update again.
    I tried registering also to KeyDownEvent listening to Return, Tab and Escape, but that also wasn't enough because for some reason the Return and Escape keydowns are immediately followed by both a Blur and a Focus event, which thwarts my attempt at detecting when the textfield is no longer "being edited".

    (note: in case using a binding somehow resolves this use case magically, I can't use the binding system because apparently it only works with SerializedObject, and what I'm editing is not a unity object, though it does have hierarchical key/values)
     
    Last edited: Aug 30, 2023
  10. dimitroff

    dimitroff

    Joined:
    Apr 3, 2013
    Posts:
    131
    @MarcGFJ did you find a solution, we are in the same boat, I expect when pressing enter or ecs on a TextField that is isDelayed, will put that Textfield out of focus, but it still focused :(
     
  11. HugoBD-Unity

    HugoBD-Unity

    Unity Technologies

    Joined:
    May 14, 2018
    Posts:
    492
    Hi @dimitroff! The TextField's focus system is a bit complex as it's a composite root. Meaning it has multiple children. The TextField itself might preserve focus on ESCAPE, but the editing area doesn't.

    We are planning on opening up APIs to track this better. In the meantime, have a look at the following post, it might be useful.
     
  12. dimitroff

    dimitroff

    Joined:
    Apr 3, 2013
    Posts:
    131
    The way I was able to solve it temp is listen for the TextElement Focus In/Focus Out events and add a class "is-editing" on the TextField when it is in Focus. Seems to behave consistent, I guess this is what you mean by "the editing area doesn't keep focus".
     
    HugoBD-Unity likes this.