Search Unity

Resolved How to prevent TextField taking focus upon keyboard input?

Discussion in 'UI Toolkit' started by Inter42, Jun 8, 2021.

  1. Inter42

    Inter42

    Joined:
    May 17, 2021
    Posts:
    13
    Hi, I'm trying out UI Toolkit for building my first UI; a simple dev tools panel.

    This panel has a handful of TextElements and some TextFields. Eventually, I want to be able to edit some game variables using these TextFields (similar to public/serialized variables in the Inspector). i.e. select the field with the mouse, enter a value, press enter, have a variable change, such as player speed.

    I started out by simply setting the values of the TextFields using uQuery, it worked well! But as soon as the user tries to move the player, using WASD (which are horizontal/vertical axes within Input Manager), my TextField elements take focus, and gets filled with W/A/S/D keystrokes.

    Is there a way to only let mouse input grant focus to a TextField? Or mouse input and tab key?

    I can see there is a "focusable" attribute, but this also prevents the field being focused from mouse input.

    I tried unticking "Send Navigation Events" in the the "Event System" attached to the UI Document, but that didnt work. Neither did completely removing both the "Event System" and "Standalone Input Module" components:
    upload_2021-6-8_22-41-56.png

    Any ideas? Thanks in advance!

    PS I'm so glad Unity is working on a HTML/CSS/JS -like UI tool. Very handy for people with these common skill sets. Looking forward to runtime databinding!
     
  2. Inter42

    Inter42

    Joined:
    May 17, 2021
    Posts:
    13
    Idea: I could make a Button field, which when clicked on could set all my TextFields as focusable/focusable, and even show/hide the whole panel. But I worry then the button will simply grab focus from keyboard input also, and likely get 'pressed' when the user hits space to Jump.

    I'm posting here because I feel I must be missing something simple, and my idea seems like 'doing it wrong'.
     
  3. uBenoitA

    uBenoitA

    Unity Technologies

    Joined:
    Apr 15, 2020
    Posts:
    220
    Hi Inter42,

    StandaloneInputModule uses Input Manager's configured axes and buttons, which you can modify in the Edit > Project Settings > Input Manager menu. My first suggestion to you is to create 2 new axes, say "HorizontalUI" and "VerticalUI", and map only the exact input from which you wish to allow UI navigation. Then, edit the StandaloneInputModule component so that it uses those HorizontalUI and VerticalUI axes instead of the default Horizontal and Vertical.

    I'm surprised that ticking off the Send Navigation Events box doesn't make a difference though. I'll have a quick look into that.

    upload_2021-6-8_15-20-31.png
     
  4. uBenoitA

    uBenoitA

    Unity Technologies

    Joined:
    Apr 15, 2020
    Posts:
    220
    EDIT: Oh, nevermind, the problem is probably that all keyboard input for UI Toolkit has nowhere else to go than in the TextField, which causes it to receive focus and add text. It's probably not navigation events, but rather keyboard events, that do it.

    I'm not entirely sure it's going to work in your particular setup, but in theory you should have a way to intercept keyboard events before they reach the TextField, say with
    panel.visualTree.RegisterCallback<KeyDownEvent>(e => e.StopImmediatePropagation(), TrickleDown.TrickleDown)

    .

    You could add some condition that detect whether you're moving your hero or you're focused in the UI, before stopping the keyboard event. Also, you might need to also prevent KeyUpEvents. If this doesn't work on the first try, add some other callback on the TextField directly and Debug.Log to see if you're getting all the events. You might need to place another parent VisualElement between the TextField and the Panel's visualTree to capture all the events, depending on your setup.
     
  5. Inter42

    Inter42

    Joined:
    May 17, 2021
    Posts:
    13
    Hi uBenoitA, thanks for your detailed responses.

    It is just navigation commands that get intercepted, it seems. Simply pressing random letters on the keyboard (which *arent* set to be an axis in Input Manager) do not cause the TextField to gain focus. Only WASD/Arrows and tab cause focus gain.

    So I tried your first suggestion, creating UI specific horizontal and vertical input:
    upload_2021-6-9_14-57-45.png

    upload_2021-6-9_14-58-21.png

    However this seems to be ignored completely. WASD still sends navigation input to the UI, and the new keybinds (TFGH) do not.

    I then tried adding:
    Code (CSharp):
    1. root.Q<VisualElement>("container").RegisterCallback<KeyDownEvent>(e => e.StopImmediatePropagation(), TrickleDown.TrickleDown);
    to my DevToolsHandler script (root is the UIDocument rootVisualElement, #container is my wrapper for my flexbox), in the Start() function. I thought that might achieve your second suggestion, but that also doesnt seem to do anything; I can still move my hero, and TextFields still get focus on keydown.
    EDIT: I'm using the same uQuery technique to set values on my TextFields, so I know that part is working.

    Code (CSharp):
    1. root.panel.visualTree.RegisterCallback<KeyDownEvent>(e => e.StopImmediatePropagation(), TrickleDown.TrickleDown);
    didnt change things either.


    I initially wanted to use UIElements/Toolkit because I have around 50 of these kind of variables to display, and I after 15 minutes of manually placing uGUI gameobjects on my scene view, I thought there must be a better way, I just need a simple CSS grid or flexbox. So I went with UI Toolkit. However I've just seen GridLayoutGroup... I'll give that a go in the meantime. I'd still like to keep using UI Toolkit though, so I welcome any other suggestions and I'm happy to try reproducing things if it helps you find bugs.
     
    Last edited: Jun 9, 2021
  6. Inter42

    Inter42

    Joined:
    May 17, 2021
    Posts:
    13
    Well at least I got the uGUI version working.

    1. Added a container object inside Canvas (to attach my new DevToolsUGUI script to).
    2. Added a subcontainer with GridLayoutGroup component on it.
    3. Put a bunch of gameobjects inside it as children. Simple Text components are fine, but InputFields don't come with a label by default! So I needed yet another subcontainer per InputField, using HorizontalLayoutGroup for each Text + InputField combination to make my own 'label' system.
    4. Then I manually linked each Text and InputField in the inspector for my DevToolsUGUI script.
    5. Then on Start(), register listeners for each InputField.onEndEdit and write methods to handle the new input.

    (I'm sure there must be a more efficient way to do those last two steps, using some name matching technique and looping through all children, but this is my PoC for my first ever UI in Unity, and I'm learning C# at the same time).

    Coming from a web development background, and with experience with Angular, React, etc, this seems so antiquated :(. I'm really looking forward to runtime binding in UI Toolkit so I don't need to learn to create my own technique to efficiently handle 100+ fields.

    With this uGUI method, the focus behaves as I desired. Until I actually click on the fields, they don't get focus (not even tab gives it focus).

    But it really shows the difference in workflow from uGUI to UI Toolkit. And now I have a huge amount of GameObjects in my scene just for a table of values. Eh maybe that's normal, I'm new to Unity.
     
  7. uBenoitA

    uBenoitA

    Unity Technologies

    Joined:
    Apr 15, 2020
    Posts:
    220
    Your situation intrigues me, I don't see why it would do that and I'd like to reproduce it on my side if possible. Could you maybe submit a bug report with a simple repro project? Also, what version of Unity are you using, and are you using UI Toolkit's runtime from a package release or directly from Unity 2021.2 without the package?
     
  8. Inter42

    Inter42

    Joined:
    May 17, 2021
    Posts:
    13
    I'll probably keep using uGUI for this current UI component now that I've made it -- but yeah no problem, tomorrow I'll put something quick together to show easy reproduction.

    I'll post here with a github link when it's up.
     
  9. Inter42

    Inter42

    Joined:
    May 17, 2021
    Posts:
    13
  10. uBenoitA

    uBenoitA

    Unity Technologies

    Joined:
    Apr 15, 2020
    Posts:
    220
    Hi Inter42, I can't access your project files on GitHub. Are you sure it's a public repo?
     
  11. Inter42

    Inter42

    Joined:
    May 17, 2021
    Posts:
    13
    Doh! It's public now @uBenoitA
     
  12. uBenoitA

    uBenoitA

    Unity Technologies

    Joined:
    Apr 15, 2020
    Posts:
    220
    Hello again,

    I've just opened your project in 2021.2.0b1, removed the preview-14 package and upgraded the project, to see if your bug is fixed in the latest state of things, and it does seem to be fixed. It upgrading to 2021.2 an option for you right now? Otherwise, I can try to see if our next package update (1.0.0-preview.15) also fixes it, though it's not yet available to the public.
     
    Inter42 likes this.
  13. Inter42

    Inter42

    Joined:
    May 17, 2021
    Posts:
    13
    Hi @uBenoitA,

    Cool thanks for checking. I'm using the old Unity UI for now on this particular project. But next project I'll give UI Toolkit with 2021.2 a go.
     
  14. VisionEEG

    VisionEEG

    Joined:
    Aug 29, 2018
    Posts:
    28
    Still not fixed in preview-16. I can reproduce the problem in 2020.3.16 preview 16, but as pointed out, it's fixed in 2021.2.0b8.
     
  15. VisionEEG

    VisionEEG

    Joined:
    Aug 29, 2018
    Posts:
    28
    Not fixed in preview-18 with 2020.3.17.
     
  16. zim22

    zim22

    Joined:
    Feb 25, 2018
    Posts:
    44
    +1, not fixed in latest preview18 in 2020.3
     
  17. uBenoitA

    uBenoitA

    Unity Technologies

    Joined:
    Apr 15, 2020
    Posts:
    220
    Hi there again,

    It's been some time, but trying to remember as best I can what the issue was, let's go over a few points again:

    Solution 1. Changing the key mapping of the "Horizontal" and "Vertical" axes. This wouldn't work for your use case because those axes also drive the hero's movement in the world.

    Solution 2. Upgrading to Unity 2021.2+ (then you can depend on the StandaloneInputModule's configuration to use other axes, like "HorizontalUI" and "VerticalUI"). This wouldn't work for you because it would require too much change to the rest of the project.

    Solution 3. Intercept events going into the TextField. I was suggesting to RegisterCallback<KeyDownEvent>, but as you correctly pointed out, this doesn't work because what's moving the cursor is actually a NavigationMoveEvent. Might I suggest again that you try using a similar interception pattern but with that event instead?

    Code (CSharp):
    1. panel.visualTree.RegisterCallback<NavigationMoveEvent>(e => e.StopImmediatePropagation(), TrickleDown.TrickleDown);

    The interaction between the keyboard navigation input and the TextField content is a rather fragile part of UI Toolkit right now, and we're aware of it. We are currently reworking the way the TextField is implemented, so you may expect some changes and fixes in the future in that area, but it might not be coming to the package anymore, unfortunately. The UI Toolkit package is still experimental, whereas the built-in version of UI Toolkit that is now fully shipping with the Unity Editor is where the new features and major refactors (like the TextField rework) will be implemented going forward.

    I hope this helps. With some luck the RegisterCallback<NavigationMoveEvent> should do the trick, but if it doesn't, I'm afraid upgrading the Unity Editor version might be the best solution left.
     
  18. VisionEEG

    VisionEEG

    Joined:
    Aug 29, 2018
    Posts:
    28
    Hi,
    We finally upgraded to 2021.3.2. The camera is controlled using an InputAction with the keyboard WASD mapped. The problem is still present in those conditions. After a few seconds, some TextField will get focus.
     
    Last edited: Jul 23, 2022
  19. antoine-unity

    antoine-unity

    Unity Technologies

    Joined:
    Sep 10, 2015
    Posts:
    780
  20. VisionEEG

    VisionEEG

    Joined:
    Aug 29, 2018
    Posts:
    28
    I deleted both Horizontal and Vertical from the Input Manager axes array. The TextFields still receive focus when using WASD to move camera.
     
  21. Unique-Player

    Unique-Player

    Joined:
    May 6, 2017
    Posts:
    78
    Any changes were made? I am on 2022.3, Unity UI 1.0.0.
    I want to stop the propagation so arrows or WASD will not trigger a focus change.
    Code (CSharp):
    1. panel.visualTree.RegisterCallback<NavigationMoveEvent>(e => e.StopImmediatePropagation(), TrickleDown.TrickleDown);
    This one tied to a specific element not working. I need to keep vertical navigation, but disable horizontal one.