Search Unity

How to make EventSystem keyboard navigation automatically select something?

Discussion in 'UGUI & TextMesh Pro' started by JoeStrout, Aug 11, 2017.

  1. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    Given a canvas with a couple of selectable objects (buttons, in my case), I want these buttons to initially start off with neither selected. But if the user starts mashing navigation inputs (e.g. arrow keys), it should select a button and let them get on with it.

    How do I do this?

    The standard solution to making keyboard navigation actually work, is to either set something as the First Selected on the EventSystem (which implies having one EventSystem for each menu), or using a script to .Select some item when the UI is presented (e.g., OnActivate).

    But both of these solutions actually highlight the first item. I don't want that. When you have two buttons, and one appears a different color than the other, it may not even be clear what the different colors mean — and it's certainly going to look goofy, especially to a mouse user.

    I suppose as a work-around I could put some invisible Selectable into the navigation hierarchy, and initially select that. But that means that as they cycle through the controls, there's going to be a gap where it appears nothing is selected. Better than the alternatives above, but not ideal.

    What would be ideal is a script that somehow detects that a navigation input has been received, sees that nothing is selected, and selects something. But I don't see how to detect that. Any ideas?

    (Well, OK, what would be ideal would be for the navigation system to not suck right out of the box. But I'm not holding my breath for that.)
     
  2. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    12,697
    I use an "InputDeviceManager" script. When it starts, it hides the mouse cursor.

    If the player moves or clicks the mouse, it shows the mouse cursor.

    If the player uses a joystick, it hides the mouse cursor.

    If the player uses keyboard or joystick and nothing is selected, it selects the "current selectable". As UI panels appear, they push themselves onto a stack. The top UI panel keeps track of its default selectable and most-recently-selected selectable. The "current selectable" is the most-recently-selected selectable or, if there is no most-recently-selected, the default selectable.

    Sadly, my InputDeviceManager script is a little more complicated even than that, but that's the basic idea.
     
    JoeStrout likes this.
  3. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    Sounds about right.

    For our immediate needs, I ended up adding an invisible (and off-screen) button to take the initial focus, and use explicit navigation to get from there to the visible buttons, without ever going back. I further created a little script you can attach to whatever object you want to be selected by default, and it simple selects itself on activate.

    The net effect of all this is that when the menu first appears, nothing is visibly selected; but you can use the game controller or the mouse to highlight and select buttons, and either one works fine.

    But your script's automatic hiding and showing of the mouse is a great idea. We'll probably have to incorporate that at some point.