How to Create a Custom Keybind Script in Unity C#

I’d like to share something I worked on last week. I’m thinking every couple weeks I’ll share stuff I learned through trial-and-error (and lots of research!) and hopefully help another newcomer out there save some time.

Since I learn by trial-and-error I don’t learn things the “best way”, I just learn a way that works in my situation, then I make improvements over time. Criticism/tips are fully welcomed and encouraged, I’m trying to improve as much as I can.

One of the things I learned this week in Unity C# was coding my own custom keybind UI menu without using Unity’s built-in input scripts. My menu lets the user rebind control keys with one mouseclick followed by a single keypress. It hasn’t been rigorously tested but it gets the job done right now.

Here’s how it works:

1           Machine generated alternative text: Player 1  Player 2  RightArrow  LeftArrow  Move Right  Move Left  Move Right  Move Left
A GUI displays our current controls and which keys are bound to them

2Machine generated alternative text: Player 1  Player 2  RightArrow  LeftArrow  Move Right  Move Left  Move Right  Move Left

Clicking on the button next to “Player 1 Move Right” then pressing F1 will immediately set F1 as the move right key.

Now my player can instantly move right with F1, and the UI text is updated at the same time to show my new bound key! This works for any of these 4 buttons and I can bind almost any key I want (Including controller buttons).

3Machine generated alternative text: Player 1  LeftBracket  Alpha7  Player 2  PageDown  Tab  Move Right  Move Left  Move Right  Move Left

I can rebind any keys I want, quick and easy!

So how is this all coded?

There are 11 classes involved in my menu, but 8 of those are just for the buttons & the text. Also I try to keep my classes small (below 100 lines each), so it’s not as hard as it might sound. Here are the classes used in my example:

  1. The ControlKeybinds class contains the dictionary storing the control Keycode values.
  2. The “Player1Controls” & “Player2Controls” both contain the inputs for the players. Their controls are stored as KeyCode variables, like GetKeyDown ( variable ). There is a method “RefreshKeybinds” which sets all KeyCode variables equal to the dictionary’s values (picture of this later)
  3. As for UI, there are 4 classes (one for each bindable action). These are named UIConfigBindPlayer1MoveLeft, UIConfigBindPlayer2MoveLeft etc.
  4. There are also 4 classes used for the 4 text objects displaying which key is currently bound. I called these UIConfigCurrentlyBoundKeyP1MoveLeft etc. Long names, but at least I’ll always know exactly what these classes are for.

I’ll explain how I made the “player 1 move right” button, and that will be enough info for you to make as many buttons as you want (if I succeed in explaining it well!)

First, I store all of my game’s player controls in a dictionary which is located inside a class I call “ControlKeybinds“. For some reason I couldn’t get a dictionary to be recognized by the compiler, but I fixed it by adding the using statement System.Collections.Generic.

4Machine generated alternative text: using UnityEngine;  using System.CoIIections;  using System.CoIIections.Generic;  public class  ControlKeybinds : Monoaehaviour  new Dictionary  string,  KeyCode O;  void Start ()  Saved Keyainds ();  public static  Diction aw  string,  public void SavedKeyainds ()  KeyCode keyainds  keyainds . Add (  keyainds . Add (  keyainds . Add (  keyainds . Add (  keyainds . Add (  keyainds . Add (  "PlayerIRight", KeyCode.D ) ;  "PlayerILeft", KeyCode.A ) ;  "PlayerIPerformAction", KeyCode.E ) ;  "PlayerILightAttack", KeyCode.Space ) ;  " Player2Left" ,  "Player2Right" ,  KeyCode. LeftArrow ) ;  KeyCode. RightArrow ) ;

Player 1 has a couple extra controls I’m in the middle of implementing, those aren’t important.

Next, in Player1Controls I store a variable for each keycode I’ll be using. Seen here I have my KeyCode variables for left and right movement.

5Machine generated alternative text: private  private  private  KeyCode  Key Code  float  rrcveRi ght ;  rrcveLeft ;  rrcve ;  stats.  Speed,  rigidBody2D . ty . y  void Movement  if ( Input . GetKey ( moveRight ) )  rrcve on  else if ( Input . GetKey ( moveLeft  rrcve on  else rrcveDirection  new Vector2  rrcve on

I then have a method I call “RefreshKeybinds”, which I call in Start(). All this does is fill those movement variables with dictionary values of the correct key. This method gets called as soon as we bind a new key. This is what actually “binds” the new dictionary value to our player.

6Machine generated alternative text: public RefreshKeybinds ( )  false;  rrcveLeft ControlKeybirNfls . keyBinds I "Playez2Left" ) ;  moveRight ControlKeybinds . keyBinds I ) ;  perforrrÄction ControlKeybinds . keyBinds I "PLayez2PezfazrrÄcti_ar."  lightÄttack ControlKeybirnfls . keyBinds I "Playez2LightÄttack" ) ;

The bool “refreshKeybindRequest” is what initiates the method. This is controlled by a simple if statement in my update function:

7Machine generated alternative text: if ( refreshKeybindRequest  RefreshKeybinds ;  true )

Now for the script the button uses. It begins with an array holding every possible keycode we could want.

8Machine generated alternative text: public class UIConfigBindPIayerIMoveRight : MonoBehavic  ) KeyCode . UpÄrrow,  private int l)  all Possibl eKeyBinds  int  int  int  int  int  int  int  int  int  int  int  int  int  int  int  int  int  int  int  int  int  int  int  int  int  int  int  int  ) KeyCode . A,  ) KeyCcde . B,  ) KeyCode . C,  ) KeyCode . D  ) KeyCode . E,  ) KeyCode . G,  ) KeyCode . H  ) KeyCode . I,  ) KeyCode . J,  ) KeyCode . K,  ) KeyCode . L  ) KeyCode . M,  ) KeyCode . N,  ) KeyCode . O,  ) KeyCode . P,  ) KeyCode . Q,  ) KeyCcde . R,  ) KeyCode . S,  ) KeyCode . T,  ) KeyCode . U,  ) KeyCode . V,  ) KeyCode . W,  ) KeyCode . X,  ) KeyCode . Y,  ) KeyCcde . Z,  ) KeyCode . Space ,

This next part is where the dictionary gets written with a new value. When we click a rebind button, the following method is called.

9Machine generated alternative text: public void RebindKey()  Control Keybinds . keyBinds . Rerrcve ( "Player 2 Right" ) •  UIConfigCurrentIyBourdKeyPIMoveRight . CurrentlyBindingNewKey  awai t aye rlnput  true ;  true ;

This method removes our dictionary value and turns on 2 bools. The UI bool stops the UIText from trying to display an empty dictionary key (the UI will throw errors like crazy if not in place). The second bool prevents us from binding more than one key in the same instance.

The update method is where the bind overwrite happens. As we press a key, a for loop iterates through the array to check if any values are equal to the key we pressed. If it finds one, it replaces the correct dictionary value with the new key. At the end of the method the Player’s keybinds are refreshed with the new values in the dictionary. Awesome!

10Machine generated alternative text: private bool  void Update  awai t aye rlnput  false;  if ( awai tingPIayerInput  true )  for ( int  c: all PossibleKeyBinds . Length; 1++ )  if ( Input . GetKeyDown ( ( KeyCode ) all PossibleKeyBinds i ) ) ) @  Control Keybinds . keyBinds.Ädd (  ( KeyCode ) all PossibleKeyBinds  UIConfigCurrentIyBounflKeyPIMoveRight . CurrentlyBindingNewKey  false;  awai t aye rlnput  false;  PlayerIControIs . refreshKeybindRequest  true ;

I should written this as a separate method that gets called in update for cleaner looking code.

Now for the actual button UI itself. I’m not going to explain how to work with basic Unity UI. You can learn about basic Unity UI here and here

Buttons can only reference methods through objects holding scripts, you can’t directly attach a script or a method to a button. My button keybind scripts are stored in an empty object I just call “RebindKeys” which is held in an empty “system” object. I drag this RebindKeys object onto my button, then I choose the correct script & method.

11Machine generated alternative text: System  RebindKeys  Scenery  Collectibles  Enemies  ParticleFire I  PlayerObjects  *Canvas  EventSystem  Console  Static  ag untagged  Rect Transform  Posy  Pos z  Anchors  Max  Pivot  Rotation  Scale  Pos x  Width  Height  x 0.5  x 0.5  Y 0.5  Y 0.5  Y 0.5  UI Config Bind Player I Move Left (ScriC O,  UIConfigaindPIayerIMoveLef @  UI Config Bind Player I Move Right (SCC O,  UIConfigaindPIayerIMoveRig @  UI Config Bind Player 2 Move Left (ScriC  UIConfigaindPIayer2MoveLef @  UI Config Bind Player 2 Move Right (SCC O,  UIConfigaindPIayer2MoveRig @  Script  Script  Script  Script

Drag this onto the button method field

12Machine generated alternative text: Player  Du PR htK V  ButtonPIMoveLeftKeybind  auttonPIMoveRightKeybind  Text  MoveRightKey  PlayerIText  Player2Text  ButtonP2MoveLeftKeybind  ButtonP2MoveRightKeybind  Pivot  Rotation  Scale  Stats  pro ect  Gizmos •  Canvas Renderer  ' r;lMImage (Script)  Button (Script)  lor Tint  him  Interactable  Transition  Target Graphic  Normal Color  Highlighted Colo  Pressed Color  EventSystem  Console  bool enabled  string name  string tag  bool useGUILayout  BroadcastMessage (string)  Cancellnvoke (string)  Cancellnvoke O  RebindKey O  SendMessage (string)  SendMessageUpwards (string)  StopAIICoroutines O  StopCoroutine (string)  22  Automatic  No Function  GameObject  RectTransform  UI Config8indPIayerI MoveLeft  UIConfigBindPIayerI MoveRight  UI Config8indPIayer2MoveLeft  UI Config8indPIayer2MoveRight

Select the correct script, then method

Finally I just need to display what key we have bound. This script is held by the text directly on the button, updating it in real time except when we have nothing bound to the key (which is when we are currently binding a new key).

13Machine generated alternative text: Sing  using  using  Uni tyEngine ;  System. Collections;  tyEngine . ;  Mon 0B eh avi our  public class UIConfigCurrentIyBounKeyPIMoveRight  private Text text;  private KeyCode moveRightBoundKey;  void Start  text  Ge tComponen t  Text  public static bool CurrentlyBindingNewKey  false;  void Update ( )  if ( CurrentlyBindingNewKey  false )  moveRightBoundKey Control Keybinds . keyBinds  moveRightBoundKey . T CSC ring ( ) ;  text . text  "Playez2Right"

Now that I think about it this could be optimized to only update when a key has been changed instead of refreshing every frame. Whoops! Once again I just do things a way, then worry about making improvements later when I try implementing it again in another practice project.

Hopefully I was able to assist someone out there with their code. At the very least I noticed a few of my own mistakes by writing this post because I was forced to organize my thoughts.

If you liked this, please follow me on my social media profiles.


One thought on “How to Create a Custom Keybind Script in Unity C#”

Leave a Reply

Your email address will not be published. Required fields are marked *