Search Unity

GUI controlable by keyboard

Discussion in 'Scripting' started by piorun, Feb 10, 2011.

  1. piorun

    piorun

    Joined:
    Feb 8, 2011
    Posts:
    3
    Hi,
    can someone post an idea how to make GUI elements (buttons, sliders ets.) to be controlable (selectable) by keyboard or gamepad? I was thinking about add ID property to these elements but I'm not sure how to do this. Maybe is other way to do this?
    I've made control of 3d objects by asign script to 3d game objects but GUI are created by script so I can'd do this that way. Any ideas?
    TIA
     
  2. andeeeee

    andeeeee

    Joined:
    Jul 19, 2005
    Posts:
    8,768
    Hi, welcome to the forum!

    Do you want all GUI elements to have a keyboard alternative (activated by tabbing through, say) or do you want specific things in your game to have keyboard shortcuts?
     
  3. piorun

    piorun

    Joined:
    Feb 8, 2011
    Posts:
    3
    I just want menu based on Unity GUI/GUILayout and controlable by keyboard. Simple game menus build using GUI and selectable without mouse.
     
  4. Farfarer

    Farfarer

    Joined:
    Aug 17, 2010
    Posts:
    2,249
    I came across the same issue recently, trying to control a menu with a gamepad.

    Here's the roughly code I used (had to piece some of it back together, but you should be able to work with it and automate it some more, maybe).

    Code (csharp):
    1.  
    2. // Array of menu item control names.
    3. var menuOptions = new String[4];
    4. menuOptions[0] = "Tutorial";
    5. menuOptions[1] = "Play";
    6. menuOptions[2] = "High Scores";
    7. menuOptions[3] = "Exit";
    8.  
    9. // Default selected menu item (in this case, Tutorial).
    10. var selectedIndex = 0;
    11.  
    12.  
    13. // Function to scroll through possible menu items array, looping back to start/end depending on direction of movement.
    14. function menuSelection (menuItems, selectedItem, direction) {
    15.     if (direction == "up") {
    16.         if (selectedItem == 0) {
    17.             selectedItem = menuItems.length - 1;
    18.         } else {
    19.             selectedItem -= 1;
    20.         }
    21.     }
    22.    
    23.     if (direction == "down") {
    24.         if (selectedItem == menuItems.length - 1) {
    25.             selectedItem = 0;
    26.         } else {
    27.             selectedItem += 1;
    28.         }
    29.     }
    30.    
    31.     return selectedItem;
    32. }
    33.  
    34. function Update ()
    35. {
    36.     if ([key press down arrow]) {
    37.         selectedIndex = menuSelection(menuOptions, selectedIndex, "down");
    38.     }
    39.  
    40.     if ([key press up arrow]) {
    41.         selectedIndex = menuSelection(menuOptions, selectedIndex, "up");
    42.     }
    43. }
    44.  
    45. function OnGUI ()
    46. {
    47.     GUI.SetNextControlName ("Tutorial");
    48.     if (GUI.Button(Rect(10,70,50,30), "View Tutorial")) {
    49.         //Do tutorial stuff.
    50.     }
    51.    
    52.     GUI.SetNextControlName ("Play");
    53.     if (GUI.Button(Rect(10,100,50,30), "Play Game")) {
    54.         //Do game stuff.
    55.     }
    56.    
    57.     GUI.SetNextControlName ("High Scores");
    58.     if (GUI.Button(Rect(10,130,50,30), "High Scores")) {
    59.         //Do high score stuff.
    60.     }
    61.    
    62.     GUI.SetNextControlName ("Exit");
    63.     if (GUI.Button(Rect(10,160,50,30), "Exit")) {
    64.         //Do quit stuff.
    65.     }
    66.  
    67.     GUI.FocusControl (menuOptions[selectedIndex]);
    68. }
    69.  
     
    taxvi and BitWarp like this.
  5. piorun

    piorun

    Joined:
    Feb 8, 2011
    Posts:
    3
    Yeah, thanks. That works :>
    I've missed "GUI.SetNextControlName" function in scripting reference so that's why I couldn't do this.
     
  6. naf456

    naf456

    Joined:
    Apr 26, 2011
    Posts:
    44
    Despite Being An Old Thread, can I say, nice Code Farfarer (better then mine anyway :/)

    I need to read the reference more....

    EDIT:
    I'm now stuck with trying to get the user to selected the focused control...My User is taken to a map select screen- part of the initial main menu, so it's a little hard to figure out, then passing an index towards App.LevelLoad....
     
    Last edited: Dec 13, 2011
  7. bingont

    bingont

    Joined:
    Mar 10, 2012
    Posts:
    2
    great script i got it to work with my gamepad but i still don't get how to make the buttons clickable when i press a certain button. does anybody have any ideas?
     
  8. chelnok

    chelnok

    Joined:
    Jul 2, 2012
    Posts:
    680
    @Farfarer
    Thanks for the snippet ..very helpful!

    This is how i made the buttons clickable:

    Code (csharp):
    1.  
    2. // Array of menu item control names.
    3. var menuOptions = new String[4];
    4.  
    5. menuOptions[0] = "Tutorial";
    6. menuOptions[1] = "Play";
    7. menuOptions[2] = "High Scores";
    8. menuOptions[3] = "Exit";
    9.  
    10. // Default selected menu item (in this case, Tutorial).
    11.  
    12. var selectedIndex = 0;
    13.  
    14. // Function to scroll through possible menu items array, looping back to start/end depending on direction of movement.
    15.  
    16. function menuSelection (menuItems, selectedItem, direction) {
    17.  
    18.     if (direction == "up") {
    19.         if (selectedItem == 0) {
    20.             selectedItem = menuItems.length - 1;
    21.         } else {
    22.             selectedItem -= 1;
    23.         }
    24.     }
    25.    
    26.     if (direction == "down") {
    27.         if (selectedItem == menuItems.length - 1) {
    28.             selectedItem = 0;
    29.         } else {
    30.             selectedItem += 1;
    31.         }
    32.     }
    33.  
    34.     return selectedItem;
    35. }
    36.  
    37.  
    38.  
    39. function Update ()
    40. {
    41.     if (Input.GetKeyDown("down")) {
    42.         selectedIndex = menuSelection(menuOptions, selectedIndex, "down");
    43.     }
    44.  
    45.     if (Input.GetKeyDown("up")) {
    46.         selectedIndex = menuSelection(menuOptions, selectedIndex, "up");
    47.     }
    48.  
    49.     if (Input.GetKeyDown("space")) {   
    50.         handleSelection();
    51.     }
    52. }
    53.  
    54. function handleSelection()
    55. {
    56.     GUI.FocusControl (menuOptions[selectedIndex]);
    57.    
    58.     switch (selectedIndex)
    59.     {
    60.         case 0:  
    61.                Debug.Log("Selected name: " + GUI.GetNameOfFocusedControl () + " / id: " +selectedIndex);
    62.                break;
    63.         case 1:
    64.                Debug.Log("Selected name: " + GUI.GetNameOfFocusedControl () + " / id: " +selectedIndex);
    65.                break;
    66.         case 2:
    67.                Debug.Log("Selected name: " + GUI.GetNameOfFocusedControl () + " / id: " +selectedIndex);
    68.                break;
    69.         case 3:
    70.                Debug.Log("Selected name: " + GUI.GetNameOfFocusedControl () + " / id: " +selectedIndex);
    71.                break;          
    72.         default:
    73.                Debug.Log ("None of the above selected..");
    74.                break;
    75.     }
    76. }
    77.  
    78. function OnGUI ()
    79. {
    80.     GUI.SetNextControlName ("Tutorial");
    81.     if (GUI.Button(Rect(10,70,170,30), "Button 1 (tutorial,id:0)")) {
    82.         selectedIndex = 0;
    83.         handleSelection();
    84.     }
    85.  
    86.     GUI.SetNextControlName ("Play");
    87.     if (GUI.Button(Rect(10,100,170,30), "Button 2 (play, id:1)")) {
    88.         selectedIndex = 1;
    89.         handleSelection();
    90.     }
    91.  
    92.     GUI.SetNextControlName ("High Scores");
    93.     if (GUI.Button(Rect(10,130,170,30), "Button 3 (high scores, id:2)")) {
    94.         selectedIndex = 2;
    95.         handleSelection();
    96.     }
    97.  
    98.     GUI.SetNextControlName ("Exit");
    99.     if (GUI.Button(Rect(10,160,170,30), "Button 4 (exit, id:3)")) {
    100.         selectedIndex = 3;
    101.         handleSelection();
    102.     }
    103.  
    104.     GUI.FocusControl (menuOptions[selectedIndex]);
    105. }
    106.  
     
    BitWarp likes this.
  9. eko1892

    eko1892

    Joined:
    Mar 28, 2011
    Posts:
    139
    Thanks for your snippet Farfarer. Does anyone knows how can I apply something like that to a gui slider ?
     
  10. tomandjerry-tas

    tomandjerry-tas

    Joined:
    Feb 7, 2013
    Posts:
    22
    Does anyone have C# version for this ??
     
  11. Namshub

    Namshub

    Joined:
    Jan 26, 2014
    Posts:
    1
    I'm pretty sure you just need to change 'function' to 'void'
     
    taxvi likes this.
  12. tomandjerry-tas

    tomandjerry-tas

    Joined:
    Feb 7, 2013
    Posts:
    22
    No. You can't simply just change to void. But Thank you for your reply.
     
  13. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    12,694
    Here's some C# code from this answer: http://answers.unity3d.com/questions/660805/navigating-unitygui-menus-without-a-mouse.html

    The Dialogue System for Unity maintains a list of navigable controls. It looks something like below (simplified for this answer):
    Code (csharp):
    1.  
    2. public class GUIButton {
    3.     public string controlName;
    4.     public string text;
    5.     public Rect rect;
    6. }
    7.      
    8. GUIButton[] buttons; // Array of buttons to navigate through; could generalize for any control type.
    9. int current; // Index into buttons[].
    10.  
    OnGUI draws it like this:
    Code (csharp):
    1.  
    2. foreach (var button in buttons) {
    3.     GUI.SetNextControlName(button.controlName);
    4.     if (GUI.Button(button.rect, button.text)) {
    5.         // do whatever action is assigned to this button.
    6.     }
    7. }
    8. GUI.FocusControl(buttons[current].controlName);
    9.  
    But it also checks the value of an input axis (e.g., "Vertical") and changes current accordingly:
    Code (csharp):
    1.  
    2. float axis = Input.GetAxis("Vertical");
    3. if (axis < 0) {
    4.     current--; // Move to previous button.
    5. } else if (axis > 0) {
    6.     current++; // Move to next button.
    7. }
    8. current = Mathf.Clamp(current, 0, buttons.Length-1);
    9. foreach (var button in buttons) {
    10.     GUI.SetNextControlName(button.controlName);
    11.     if (GUI.Button(button.rect, button.text)) {...}
    12. }
    13. GUI.FocusControl(buttons[current].controlName);
    14.  
    And to check for the gamepad button:
    Code (csharp):
    1.  
    2. bool buttonPressed = false;
    3.  
    4. void Update() {
    5.     if (Input.GetButtonDown("Fire1")) {
    6.         // do whatever is assigned to buttons[current].
    7.     }
    8. }
    9.  
    The actual implementation is quite a bit more sophisticated, but this is the basic idea.

    Enhancements could include:
    • Record the time when the axis changes from neutral to a direction (up or down) and wait 0.5 seconds or so before changing current. Otherwise when you move up or down it'll flip through the buttons very quickly.
    • If the axis returns to neutral before the 0.5 seconds elapse, move immediately. This allows the user to quickly tap the axis to move between buttons.
    • Check Event.current and set axis to -1 or +1 based on other navigation keys that you define. By default WASD and the arrow keys already set the Horizontal Vertical axes, so you don't need to handle those specially.
    • Instead of comparing the axis value to zero, give it a threshold. Some gamepads might be misaligned and register neutral as 0.001f or so.
    Note that the code above allows Unity GUI to click buttons using its hard-coded built-in handling of KeyCode.Space to click the currently-focused button, or when button "Fire1" is pressed. You could also check Event.current for a different trigger key.
     
  14. tomandjerry-tas

    tomandjerry-tas

    Joined:
    Feb 7, 2013
    Posts:
    22
    Thank you :mrgreen::mrgreen: