achooley / Unity3d-InputMapper

Unity3d InputMapper

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

 Unity Input Manger pain is lasting for years. On Unity site you can find request for
InputManager programmatic access dating from 2004,and some new from 2014. Futile.
Flows of current InputManager are numerous and need to restart game just to change mapping as genial solution is one of them.I know there are libraries like cInput... based on trick modifing InputManager.asset with all possible? joystick,buttons,axes ... but wasn't satisfied of level of automation, and I beleave that level should be high so game developing is fun.

Following that direction I started and build the InputMapper editor and library.

Input Mapper allows you easily to map Animation States from your Animation Controller or custom states
to inputs 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 Mouse1 double clicks + Joystick1AxisYForward (Long push forward of the Joystick) + double click of letter Y.


You can set modifier format or clicks sensitivity. 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.

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");
   }
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 is count as analog 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);

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.CONT+=new EventHandler(Handle1); ev.CONT+= 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.
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 I built small HID interface system that allows you to bind your driver for custom devices(at least similar to joystick/pad) with 2 points that your driver need to handle:
 
 (1)public IJoystickDevice ResolveDevice(IHIDDeviceInfo info)...

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

Resolve device where HIDInterface provide you with device info from the OS, you can check VID and PID to decide to handle device or not returning null. Your Update function should query device and fill the structures so can be accessed by InputManager. If you have async handling you don't need to implement Update.At start add your device driver like this:

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

Please check XInputDriver.cs(Someone with this kind of device pls test) and WinMMDriver.cs (Default one that would try to handle device if custom driver isn't supplied). There is similar HIDInterface for OSX as for WIN but didn't have chance to try it.(APPLE GUYS HELP!)



 Unity Input Manager pain is lasting for years. On Unity site you can find request for InputManager programmatic access dating from 2004, and some new from 2014. Futile.

Problems:
1) Ingame input controller mapping.
   Unity offer user interface so you can map input before start the game. Changing that setting 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/FSM of the game(one of those 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.

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

5) OS independent driver and easy expansion with drivers supporting other devices and special properties Unity internal handler might not recognize device or identify same button in different system differently and not offer support of device extra features like force feedback, IR pointer, accelerators, gyros ...of modern input controllers. So instead of offer of 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 like in fighting game scenario 2times joystick left + fire (Mustafa kick
Cadillacs and Dinosaurs)


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 ...don't want to speak of combination of axis and keys and mouse together.

8) Handling inputs by events
Seem whole Unity engine is not much planned as event-based, 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.

10) Profiles - Layouts

Why not InControl or CInput? 
Both are based on bad foundation which is Unity InputManager and even they give you runtime mapping and change they have same sickness even worse.
They create InputManager.asset with all possible Joystick#+Buttons# (Joystick1Button1,...Joystick2Button2... combinations and by reading name of joystick they give you button layout(profiles) calming they support bunch of devices. Actually they didn't support anything else then what Unity default driver support(on button-axis level),... so NO AXIS DIR RECOGNITION, NO PLUG and PLAY, NO FFD or SPECIAL FEATURES ACCELEROMETERS, GYROS, IR CAM...., NO SUPPORT EXPANSION TO NEW DEVICES...AND NOT FREE


Input Mapper system try to address above issues.





1) Ingame input controller mapping.
Input Mapper allows you easily to map 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 Mouse1 double clicks + Joystick1AxisYForward (Long push forward of the Joystick) + double click of letter Y.

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");
   }

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.CONT+=new EventHandler(Handle1);
        ev.CONT+= 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 plugging for all OSes InputMapper system had built HID interface systems for (Win,Web,Droid and OS) that allows writing only one device specified driver OS in independent.

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)...

Resolve device 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 and fill the JoystickDevice structures, so can be accessed by InputManager.

Device would be handled by default driver (WinMMDriver for Win and OSXDriver for OSX) or by custom driver if added like:
 
//supporting devices with custom drivers
   InputManager.AddDriver(new XInputDriver());

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

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.
'

19.08.14 Thrustmaster wheel RGT FFD demo WIN+DROID



Code is free if you contribute by solving bug or enhance something !!! Joking :) Who can stop you/us.

Feedback, Forks are welcome if you aren't too smart, too movie star or too busy making money.
Gmail me as winxalex.

Knowledge should be free. 

13.07.2014 Added WiimoteDevice and WiimoteDriver Skeleton
22.07.2014 Quite more stability and plug in/out supported added.
26.07.2014 Web Player joystick support (Chrome, FireFox)




01.10.2014 WiiDevice and WiiDriver 
05.10.2014 XInput driver pure C# (No DirectX xinput.dll wrappers)
13.10.2014 (OSXDriver default driver pure C#)
17.10.2014 (Thrustmaster Wheel FFD and XBOX360W working on OSX) 
CONCEPT PROVED!!!




PROFILES:

I'll show you some of next post how you show for example WiiButtonA instead JoystickButton1....

<script type="text/javascript"> SyntaxHighlighter.highlight(); </script>

About

Unity3d InputMapper

License:MIT License