Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I´m having a rough time trying to figure out a proper way of dealing with key mapping and key bindings in unity. The built-in unity input manager is useless to me since it doesnt support key mapping ingame and you cant acces it via script, you can only change your key bindings on the game laucher, but not ingame.

I guess I will need to create my custom InputManager to replace the unity one but im pretty much lost in this matter. So far I´m beein doing some research and now I know how to create a basic but robust input manager in C++ (thanks mainly to this tutorial http://www.gamedev.net/blog/355/entry-2250186-designing-a-robust-input-handling-system-for-games ) But as i said I dont know how to translate this into unity c#.. My first idea was to create a complete new input manager from scratch that use an xml file to store the key binding data, but I dont know if you think this is the wrong way to follow. First of all I dont even know how could I acces RawInput in unity. Checking the script documentation was of no use in this matter, i found something about keyboard events but they only work under OnGUI function and I dont know if i should use it then...

I know there are some commercial plugin out there for that solve this purpose but thats not the point, I´m trying to do it this by myselft

Could someone explain to me how could I make my own InputManager from scratch or give me some indication to put me in the right way to this?

I apologize for my bad english btw

-EDIT FOR CLARIFICATION:

Im trying to achieve just the typical key mapping menu but I must be able to access this menu ingame, i mean, via pause menu. ingame->pause menu-> options-> controls. for example, I have the jump action mapped to the space bar, In my controls menu I select remap this this action. A dialog propt and wait for me to press the new key to map to the jump action. I press ctrl (or whatever key)...and then I update the dictionary, jump action = ctrl (or whatever keycode it is). But the issue is, how do I know which key did I just pressed while the dialog waiting for a new key was active? Should I use something like:

void OnGUI() {
    Event e = Event.current;
    if (e.isKey && remapping)
        remap(action, e.keycode);

or if not just a bunch of if statements, one for each keycode of the keyboard i mean

if Input.getKey('keycode') remap(action, keycode);

what surely will work but just use about 100 if statemens

I hope I explained myself clearly now. Anyway I was doing some research before start writting any code but I will do a script what I thought so far and then post it for a better understanding.

share|improve this question
    
If you're willing to pay $20 somebody else supposedly has already solved this: forum.unity3d.com/threads/…! –  Tetrad Apr 18 '13 at 18:53

4 Answers 4

Unity allows you to get individual key down events via the Input.GetKey function, and the appropriate key enum. Additionally, it supports axis information via the Input.GetAxis function.

If you want to build an input map around this, then you could write an input manager that sits "in between" the unity input events, and your own event system. An input map would esentially be a one to one or one to many relationship of input events, to unity key events. Updating which keys are tied to which events could be very reasonable achieved. The simplest way to do this would be to store a dictionary of KeyCodes, and a list of the events they are registered with, and simply update these event lists if necessary. Additionally, serializing this information to an xml file would not be unreasonable at all, especially with the extensive and easy to use system that .net provides.

share|improve this answer
    
I guess thats the main idea, but I´m stuck there. I mean, ok i could create my own event system but i cant acces the unity key events, I can only acces that in OnGUI function... That was what i tried at first but I realized I only could use Event.KeyCode in OnGUI() or i get an error. –  Scar4mouche6 Apr 18 '13 at 14:22
    
Your input manager should be listening to key codes directly from the unity input manager itself, did you debug the error message you got to figure out what the problem was? Event.KeyCode is probably an argument being passed to a callback. Input.GetKey is a static method that is accessible anywhere. –  Evan Apr 18 '13 at 14:45

Im not sure if this will work, I haven't actually tested it.

public abstract class KeyInputController{


  public  char forward = 'w';
  public  char backward = 's';
  public  char left = 'a';
  public  char right = 'd';

  //Add more   

  public abstract void moveForward();
  public abstract void moveBackward();   

  //Add functions for each input

  public void Update()
  {
       if(Input.inputString!="")
       {
         //only works for first input, 
         //if you want keys within the frame update,
         //you need to iterate over it, char by char.
         char input =Input.inputString[0];

         if(input == forward)
           moveForward();
         else if(input == backward)
           moveBackward();
         //Add checks for other inputs
      }
  }
}

Now you could write your keybindings to a simple text file. And just set those variables when you read them. ( havn't tried reading text/xml/json files in Unity but im sure it's possible )

The idea here is that the keys are stored in simple variables. Which you could easily change. It should be trivial then to read/write them away. So making an interface in game where you can set your keys shouldn't be a problem either.

share|improve this answer
    
thanks for the answer but I cant use inputString since that just give you ascii characters not every key. I was looking for something like vrtual keycode in win32, but i only could find Event.keyCode. At first I thought i could use it in a way similar as you said above, but for some reason Event only works under OnGUI function so i cant use it like that. Thats the main issue Im having I dont know how to access the raw input data from my keyboard so I could map the keys.. –  Scar4mouche6 Apr 18 '13 at 13:50
    
Im pretty sure every key has an ascii code. Well I honestly don't know myself though. Havnt worked much with Unity yet. –  Sidar Apr 18 '13 at 13:52
    
with inputString you can´t access special keys like ctrl, alt, shift , home,etc... It´s only for text input purposses –  Scar4mouche6 Apr 18 '13 at 14:14

You can use a Dictionary to map KeyCode to specific action, eventually you can change this at runtime:

using UnityEngine;
using System.Collections.Generic;
using System;

public class TestInput : MonoBehaviour {

    private Dictionary<KeyCode,Action> d;

    void Start () 
    {
        d = new Dictionary<KeyCode, Action>();
        d[KeyCode.A] = () => {Debug.Log("ACTION A");};
        d[KeyCode.S] = () => {Debug.Log("ACTION B");};
        d[KeyCode.I] = () => 
            {
                Action swap = d[KeyCode.A];
                d[KeyCode.A] = d[KeyCode.S];
                d[KeyCode.S] = swap;

            };
    }

    // Update is called once per frame
    void Update () {

        if (Input.GetKeyDown(KeyCode.A))
        {
            d[KeyCode.A]();

        }
        else if (Input.GetKeyDown(KeyCode.S))
        {
            d[KeyCode.S]();
        }
        else if (Input.GetKeyDown(KeyCode.I))
        {
            d[KeyCode.I]();
        }
    }
}

Btw it seems that Unity does't expose any method that returns a list of all pressed keys, so the code above isn't very elegant. Hope this help.

share|improve this answer
    
thanks for the answer, what you say was the idea i had in mind but again there is a problem with that, related with what you said about you dont have any list of pressed keys. It seems the only way yoy can acces the pressed keys is via Event.keycode and you can only do that in OnGUI(). If i want to remap a key in game i need to acces this event.keycode otherwise i wouldnt be able to detect what the new key for that action will be (unless i do one if statement for each key :S) –  Scar4mouche6 Apr 18 '13 at 16:09
    
you have to check all possible keys. Consider that you don't have to check always all the keys of the keyboard,but just the active ones. Keep a list of all binded keys in a given configuration and iterate through them. –  Heisenbug Apr 18 '13 at 16:13
    
OnGUI isn't called every frame. Btw I don't think you will have too much keys to check. And in any case, even using Input.GetAxis you need to explicitely check for every possible input at every frame. –  Heisenbug Apr 18 '13 at 16:22
    
no no, that wasnt what i meant, i was editing my comment while you were writting yours. I mean, when I want to remap a key ingame, I must wait for the new key for that specific action to be pressed and then update that key binding, but, how do i know what key did I just pressed? should i just make if statements with the whole keyboard? :S (i dont mean the keys already mapped I mean to detect a random key to be mapped next) –  Scar4mouche6 Apr 18 '13 at 16:34
    
I dont know any other way of detect which key is pressed since the only information available for this purpose is Input.inputString (and as i said below thats just for ascii text and no special keys are included) or maybe I could use event.current and I look for a keyboard event so I can see the keycode...but again, the issue here is any keyboard event call OnGUI()..i dont get what keyboard event has to do with GUI... Should I use the OnGUI() anyway or have i got any alternative? –  Scar4mouche6 Apr 18 '13 at 16:34

The story like this.... Unity Input Manager pain is lasting for years. On Unity site you can find request on the forum for InputManager programmatic access dating from 2004, and feedback from 2009 with state planned today 2014.

Below are some of the problems.

1) Ingame input controller mapping. Unity have user interface for mapping predefined bindings at start the of game. Changing mapping later need game restart.

2) Handling input in code based on states/tag abstracting real input. Some sort of abstraction is done thru InputManager well known "Horizontal" and "Vertical", but that abstraction is still bonded to axes and buttons and not to actions/states of the game(one of those might be AnimateStates of Mecanima).

3) Saving and restoring user preferences PlayerPref might do the trick if you not plan to support Web, Droid and if file size is not bigger then 1 megabyte. File type that can be readable by humans and machines, and easy exchangeable( players can exchange their game settings) between them might be XML.

4) Recognize positive and negative part of the axis. Unity recognize Axis as whole part and gives value 1 <--- (-1) ---> 1. It is expected to gives value from 1<---- (0) ----> -1, so turning left/right on wheel input controller or joystick push/pull forward/backward can be achieved, trigger shooting rapid fire... .

5) OS independent driver and easy expansion with drivers supporting other devices and special properties Unity internal input handler might not recognize the controller or it will identify layout in different system differently and would not offer support of device extra features like force feedback, IR pointer, accelerators, gyros ...of modern input controllers. So instead of use pluggin-paid OS dependent drivers, seem much better OS dependent HID interfaces with OS independent pluggable drivers.

6) Handling input axis and buttons as digital or analog In Unity thru Input class you can handle axes only as analog and buttons as analog/digital. Its handy to have axes as digital events UP,DOWN ,HOLD...

7) Create combination of inputs that would trigger action/state Unity doesn't offer out of the box combining input action like 2 keys in row,button press and axis move, ....like in fighting game scenario 2times joystick left + fire (Mustafa kick Cadillacs and Dinosaurs)

8) Handling inputs by events Seem whole Unity engine is not much planned as event, signal or reaction based system and encouraging of use of Broadcast messaging and handling complex input inside Update is far from good solution even if you need last processor ns.

9) Plug and play instead of plug and pray. Attach or remove controllers while game is running and continue playing. If you using "Any joystick" option hot seat multiplayer isn't an option. Joystick numeration might be change on while replugged.

10) Profiles - Layouts.....

If you expect few lines of miracle code u can dream of it. So the answer is make robust clean solution or use some of existing. From existing don't use that one like CInput or InControl that are wrappers of Unity InputManager would get same hackish trouble soon... You can try Rewired or you can try my solution so you not reinvent the wheel First you can start mapping even in editor.Save. https://www.youtube.com/watch?v=kX0j69ZgeCw and then remap in game.Save. https://www.youtube.com/watch?v=uoH-RfopGzk works with OSX,Win,Droid and Web

1) Ingame input controller mapping. Input Mapper allows you easily to map game controller input to Animation States from your Animation Controller or custom states

7) Create combination of inputs that would trigger action/state Map inputs to state by just clicking keys/mouse/buttons or moving joystick as SINGLE, DOUBLE and LONG and make combination of inputs(Combos). Primary and secondary. In bellow example I've map to Wave state combo of Mouse0 double clicks + Joystick1AxisYNegative (Long pull backward of the Joystick) + double click of letter Y. enter image description here

You can set modifier format or clicks sensitivity.

3) Saving and restoring user preferences Saving would export your settings to .xml file and States.cs will be generated containing enum of your mapped states.

public enum States:int{
         Wave=1397315813,
         MyCustomState=-1624475888,

Now you can forget about:

//  static int idleState = Animator.StringToHash("Base Layer.Idle"); 
//  static int locoState = Animator.StringToHash("Base Layer.Locomotion");  
as we are tought in Unity tutorials, but you can use States.[some state].

Library contains simple component so you can test user perspective right away. Just drag saved .xml and Play.

2) Handling input in code based on states/tag abstracting real input. InputMapper API are very similar to Unity API's with the big difference and that is abstraction on 2 levels.First you not program with real inputs like KeyCode.Q or Joystick1Button99, but with states which also allows player to map different input to same action state.

if(InputManager.GetInputDown((int)States.Wave)){
  Debug.Log("Wave Down");
   }


 if (InputManager.GetInputUp((int)States.MyCustomState))
            {
                Debug.Log(States.MyCustomState + "-Up");
                // animator.Play((int)States.Wave);
            }


//atOnce (default=false)
//Function returns true when combination pressed in row  If set to true function return true 
//when all keys/buttons in combination are pressed.
bool bCombo = (InputManager.GetInput((int)States.Click_W+C_State, atOnce
));

4) Recognize positive and negative part of the axis. System recognize Forward,Backward,Left,Right of POV axis and Positive/Negative of normal axes.

6) Handling input axis and buttons as digital or analog Second abstraction is that you can use digital or analog output no matter your real input source is digital or analog meaning for ex. Joystick Axis count as analog source can produce normalized values from 0 to 1, but also pushed true/false, or key or even mouse button.

//using input as digital
bool bHold=(InputManager.GetInput((int)States.Walk_Forward,false));

//using input as analog value   
float analogValue=InputManager.GetInput((int)States.Walk_Forward,false,0.3f,0.1f,0f);

8) Handling inputs by events As Update method get overcrowded, library offer modern input handling solution by use of Event based system.

     //Event Based input handling
           InputEvent ev = new InputEvent("Click_W+C_State");
         //InputEvent ev = new InputEvent((int)States.SomeState);

           ev.INPUT += new EventHandler(Handle1);
           ev.INPUT += new EventHandler(Handle2);
           ev.UP += new EventHandler(onUp);//this wouldn't fire for combo inputs(single only)
           ev.DOWN += new EventHandler(onDown);//this wouldn't fire for combo inputs(single only)
}


   void onUp(object o, EventArgs args)
   {
       Debug.Log("Up");
   }

   void onDown(object o, EventArgs args)
   {
       Debug.Log("Down");
   }

   void Handle1(object o, EventArgs args)
   {
       Debug.Log("Handle1");
   }

   void Handle2(object o, EventArgs args)
   {
       Debug.Log("Handle2");
   }

Hardcode developers can manually map input to states and even mix with loaded settings.

InputManager.loadSettings(Path.Combine(Application.streamingAssetsPath,"InputSettings.xml"));

//adding input-states pairs manually
InputManager.MapStateToInput("My State1",new InputCombination("Mouse1+Joystick12AxisXPositive(x2)+B"));

InputManager.MapStateToInput("Click_W+C_State", KeyCodeExtension.Alpha0.DOUBLE,KeyCodeExtension.JoystickAxisPovYPositive.SINGLE);

In KeyCodeExtension all KeyCode stuff are supported plus additional for Joystick Axis mapping.

5) OS independent driver and easy expansion with drivers supporting other devices and special properties I understood Unity couldn't support all game devices but some system that allows simple binding of driver might be good idea (Yeah they have pluggins.....).
So instead building pluggins for all OSes, you use InputMapper system built-in mini HID interface systems for (Win,Web,Droid and OS) and OS independent driver. (Yes you can make C driver and compile in anything...) Device would be handled by default driver (WinMMDriver for Win and OSXDriver for OSX) or by custom driver if added like this:

//supporting devices with custom drivers
   InputManager.AddDriver(new XInputDriver());

Your implementation of custom device driver had 2 entry points that need implementation:

(1)public IJoystickDevice ResolveDevice(IHIDDeviceInfo info)...

(2)public void Update(IJoystickDevice joystick)...

ResolveDevice where HIDInterface provide device info from the OS, you can check VID and PID to decide to handle and init device properties and structures, or not returning null, and Update function to query device by use of provided Read/Write methods methods and fill the JoystickDevice structures, so can be accessed by InputManager. Scare about handling few bytes??? :)

Originally OS implementation of ResolveDevice point is by using Report HID Page from device description, but that restrict using devices that aren't planned to work with that OS, like Wiimote,Xbox Gamepad... In Input Mapper you need simply to extend JoystickDevice Class, which already contains some basic functionality supporting axes and buttons, by adding specialized properties of device you are planning to support.

Update point is synchronization point with Unity. System use high level synch and async ReadXXX methods and return buffered byte array. What each of bytes means is easy to decipher as there are many web sites about any devices. Developer task is to fill JoystickDevice structure with values processed from byte array returned. Write methods are used for setup the device...like light leds, start FFD, enable disable....

Still want to use Unity InputManger as backup

InputManager.AddDriver(new UnityDriver());//(-1 to 1 to -1) Swap your InputManger.asset with InputManager.asset from github source code.

Devices used during testing: XBox360W controller, ThrustMaster Wheel FFD, Wiimote + Nunchuk. One classic Gamepad controller, one Wheel and complex controller.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.