In Unity, it is easy to detect if a controller is connected. A call to Input.GetJoystickNames()
will return a String
list of connected controller names. If the list has non-empty entries, you have at least one connected controller.
Referring to either Unity controller mentioned previously, in The Middle Buttons section’s notes for the Left Most button, using the GetKey
functions to check for Keycode.Escape usually means you are checking for the Android BACK key. Notice that none of the GetKey
functions, or their input, allow for indication of a particular controller. So any controller pushing BACK will return true from these functions. This is not the only case where this happens.
In the table below, you will see other cases where you must use GetKey
functions. In the cases where a joystick button is also emitted, it is highly recommended that you use the button, which is also listed in the Unity controller charts shown previously; nothing is contradicted. It is only listed here for reference, in case you are checking for both the key and button (i.e. using Button11
and Keycode.Pause
).
Android Keycode (from controller) | Unity Keycode | Unity Button (v4.3 and later) | Notes |
---|---|---|---|
KEYCODE_BACK | Keycode.Escape | ||
KEYCODE_MENU | Keycode.Menu | ||
KEYCODE_SELECT | Keycode.Pause | Button11 | Both values emitted. |
KEYCODE_START | Keycode.Return | Button10 | Both values emitted. |
KEYCODE_DPAD_UP | Keycode.UpArrow | Consider adding these in single controller games in addition to the normal check for Axis5/6 , see The DPAD from the Unity controller charts. Some Mini-Controllers and Remotes only emit DPAD; see Android TV and Micro-Consoles. | |
KEYCODE_DPAD_DOWN | Keycode.DownArrow | ||
KEYCODE_DPAD_LEFT | Keycode.LeftArrow | ||
KEYCODE_DPAD_RIGHT | Keycode.RightArrow | ||
KEYCODE_BUTTON_L1 | Keycode.LeftShift | Button4 | Both values emitted. |
KEYCODE_BUTTON_R1 | Keycode.RightShift | Button5 | Both values emitted. |
In Unity v4.5 and later, controller disconnects are much improved. The next section describes handling disconnects when using v4.5 and later. However, it may help to finish reading this section, so a contrast between both versions can be made. The following is for Unity pre-v4.5.
Unfortunately, Unity doesn’t have all the APIs necessary to handle disconnects gracefully. A developer’s sole way of detecting a controller is using Input.GetJoystickNames()
. An application also does not get a notification that a controller has connected or disconnected. Handling these situations will take some thoughtfulness and reluctant acceptance.
When the application launches, all controllers that have ever connected will be contained in the joystick names list. This holds true whether they are connected or not, the controller name will remain in the list. However, there is an exception to this, if a controller that is being connected is the same model as a controller (or controllers) that were previously connected but are now disconnected, it will take the place of the first disconnected controller of that model.
For instance, consider an Android device with a USB hub connected to it. Connected to the hub are two controllers which are the same model. We’ll call those Xcontroller #1, plugged in first, and Xcontroller #2. Xcontroller #1 is first in the joystick names list, Xcontroller #2 is second. A couple of scenarios which will outline the problem:
The problem with this controller swapping, where Xcontroller #2 took the place of Xcontroller #1, is that the player who was on controller #2 is now controlling player #1’s character. If controller #1 reconnects, it will controller player #2’s character. Order of reconnection matters; there is no easy way to avoid this in Unity today.
There are several other scenarios that can be run through, but they all should follow the same rule: if a controller that is being connected is the same model as a controller (or controllers) that were previously connected but are now disconnected, it will take the place of the first disconnected controller of that model.
A couple of options a developer can consider:
There is currently no elegant solution in Unity version previous to v4.5.
As stated in the previous section, a developer’s sole way of detecting a controller is using Input.GetJoystickNames()
. An application also does not get a specific notification that a controller has connected or disconnected. However, unlike Unity versions previous to v4.5, the joystick names list entry does get cleared of a joystick when it disconnects. This will be the mechanism that the developer uses to query for disconnects.
Keep in mind that a developer still needs to manage what joystick name entry goes with which player. To illustrate this need, a similar scenario from the previous section will be used below.
Consider an Android device with a USB hub connected to it. Connected to the hub are three controllers, two of which are the same model. We’ll call those Xcontroller #1, plugged in first, Ycontroller #1, and then Xcontroller #2. Xcontroller #1 is first in the joystick names list, Ycontroller #1 is second, and Xcontroller #2 is third.
If Xcontroller #1 is disconnected, its name is removed from names list. The list will still have a length of 3, except the first entry will be empty. Then Xcontroller #2 is disconnected. The list still has a length of 3, except the first and third entries are empty. Now, Xcontroller #2 is reconnected, it will now occupy the first entry. Two items to notice: one, joystick list length remains the same even after disconnects, and two, Xcontroller #2 is now the first entry instead of the third.
Continuing with this scenario, disconnect the Ycontroller #1. The list contains only the Xcontroller #2 in the first entry and the next two entries are empty. Reconnect Xcontroller #1. One might expect it to occupy the next entry in the list, the second entry. However, it occupies the third entry, which makes the list have an Xcontroller in the first and third entries. A reconnected controller will occupy the first entry of any previously-connected but now disconnected controller if they are the same model, otherwise it will take the first empty entry that was never occupied by any controller. While this idiosyncrasy shouldn’t matter to a disconnection handling algorithm, it is important to know since you may consider this a bug.
A typical disconnect algorithm would poll the joystick names list every so often and wait for a cleared name, indicating a disconnect. Once a disconnect is signaled, the application pauses and, in single joystick applications, just waits for input again. It shouldn’t care which joystick it comes from. In multi-joystick applications, an application, once it notices a new joystick, needs a UI that can ask the users which joystick goes to which player. If there is only one disconnect, it could be implied that any new joystick should be attached to the only player without one. A typical UI has a metaphorical grid pattern where the joysticks are the rows and the players are the columns. Then each user moves their joystick icon down the row to the proper player column and locks it in. Once everyone has done that, the application can continue.
A call to Input.GetJoystickNames()
will return a String
list of connected controller names. This is also a list in which each joystick name’s index is the same number used to identify the controller in the Input Manager. Not using this index and selecting the options that concatenate all controller inputs, Get Motion for all Joysticks
for Joy Num
on axes, or joystick button n
for a Positive Button
, there is no way to tell what input came from what controller. So it is important to setup the Input Manager correctly.
To setup the manager correctly, every controller, up to the amount of controllers you support, must use its index — abridged Input Manager entry examples below. A special note in Unity pre-v4.3: because of how the triggers on a controller must be handled, a developer should define at least two controllers — see the Unity pre-v4.3 section below.
Name | Joystick1Button0 | Joystick2Button0 | Joystick3Button0 |
Positive Button |
| joystick 2 button 0 | joystick 3 button 0 |
Type | Key or Mouse Button | Key or Mouse Button | Key or Mouse Button |
Name | Joystick1AxisX | Joystick2AxisX | Joystick3AxisX |
Type | Joystick Axis | Joystick Axis | Joystick Axis |
Axis | X axis | X axis | X axis |
Joy Num | Joystick 1 | Joystick 2 | Joystick 3 |
A controller name can be tied to its index. A developer, through their application design, can now tie the index or name to a player. Using the index will allow the developer to differentiate between controllers. To highlight the point, consider this simple function:
function GetButton0Status(nControllerIndex:int) : float {
var flValue:float = 0.0;
flValue = Input.GetAxis(“Joystick” + nControllerIndex + “Button0”);
return flValue;
}
At the time of this writing, version v4.5.3 was the latest, which would not change any of the information below. Keep the “time of this writing” in mind when evaluating new Unity updates. Unless the input APIs or underlying frameworks change considerably, we believe the information below to be useful.
If you are familiar with the complexity needed to handle the triggers in previous versions of Unity (pre-v4.3) to meet the specification, Unity v4.3 has resolved that. Even so, triggers still take some care to implement.
Please, re-read The Bumpers and Triggers section of the Unity v4.3 and later specification. The implementation is different than other axes, but should be trivial.
In older versions of Unity, we recommended that developers define at least two controllers. This was for the scenario in which two controllers might be attached to a device, but only one is being used. Think of a SHIELD connected to a TV with a Bluetooth controller attached. It would seem logical not to care which controller an input came from in a single player scenario. However, in Unity versions previous to v4.3, some controllers would output transposed trigger values — controller group A would output 7th Axis/8th Axis
for LT and RT respectively, and controller group B would output 8th Axis/7th Axis
.
Thankfully, developers don’t need to consider this anymore. Couple that with wide adoption of the specification; in general, it is our recommendation that developers setup the Input Manager where all inputs are concatenated. For example, use Get Motion for all Joysticks
for Joy Num
on axes, and joystick button n
for a Positive Button
on buttons.
The Unity IDE only allows a limited number of axes to be defined. To fully implement the specification, more axes are needed than the IDE drop-down will allow. To address this, assets need to be saved in text mode. Forcing assets to be saved as text is easy; open the IDE, then go to Edit > Project Settings > Editor.
In the Editor Settings dialog, switch the Asset Serialization Mode to Force Text.
Before you start editing, it is recommended that you set up one controller as much as possible through the IDE. This will allow you the template needed to add more axes or buttons when editing.
Edit the InputManager.asset in the ProjectSettings folder of your Scene. Use the previously set up controller entries as templates to create all the axes or buttons needed. Note that if you look at those numbered axes that are not support in the IDE drop down, it will show up as blank in the Joy Num
entry. This is expected.
In a single player game, the reason for handling multiple connected controllers isn’t so obvious on the surface. However, consider the micro-console, which may have several controllers connected at any given time, or a SHIELD connected to a TV and a Bluetooth controller. In these scenarios, it would be impossible for an application using Get Motion for all Joysticks
to tell from which of the joysticks an input came.
One important case where a developer needs to tell which controller an input came from is described in Handling the Triggers below. Not handling this case will seriously decrease the amount of controllers your game will support “out of the box.” We will forgo a sample in this section, as handling multiple controllers folds right into handling the triggers.
The controller specification in Unity, when it comes to the triggers, involves some thought and handling. The specification shows that some controllers will give inputs of 7th Axis/8th Axis
for LT and RT respectively; while other controllers will give the reverse. If this reversing doesn’t matter to your application, this section can be safely skipped.
There are a few ways to handle this situation. Two will be described below and should give a developer a decent foundation on developing a solution specific to their application, even in multiplayer situations. By necessity, the solutions below will also handle multiple connected controllers. It is recommended an application handle at least one extra controller connected, for a total of two in a single controller application.
These solutions will use some short-hand and pseudo-code, especially when it comes to the Input Manager, without hurting the clarity. The scenario is a single player game in which the LT is “use scope” and RT is “fire.”
Name
, Type
, Axis
, and Joy Num
are listed7th Axis
Name | JoyAllFire | Joy1Fire | Joy2Fire |
Type | Joystick Axis | Joystick Axis | Joystick Axis |
Axis | 8th Axis | 8th Axis | 8th Axis |
Joy Num | Get Motion from all Joysticks | Joystick 1 | Joystick 2 |
function IsTriggerFlipped (strController : String) : boolean {
// The controllers below are known to NOT need the triggers
// flipped from what we’ve defined in the InputManager. There
// are less of these to check against.
if (strController.StartsWith("NVIDIA Corporation NVIDIA Controller v01"))
return false;
// These are true in 4.3 and modern NVIDIA devices.
if (strController == "Microsoft X-Box 360 pad") return false;
if (strController == "Generic X-Box pad") return false;
if (strController == "OnLive Wireless Controller") return false;
return true;
}
// Handles 2 controllers well. Any controller after the 2nd
// controller will be considered non-flipped. Extending this
// to n-controllers is trivial.
var flScope:float = Input.GetAxis("JoyAllScope");
var flFire:float = Input.GetAxis("JoyAllFire");
var nUsingJoyNum:int = -1;
if (flFire > AXIS_FIRE_THRESHOLD) {
if (Input.GetAxis("Joy1Fire") == flFire) nUsingJoyNum = 0;
if (Input.GetAxis("Joy2Fire") == flFire) nUsingJoyNum = 1;
}
if ((flScope > AXIS_SCOPE_THRESHOLD) && (nUsingJoyNum < 0)) {
if (Input.GetAxis("Joy1Scope") == flScope) nUsingJoyNum = 0;
if (Input.GetAxis("Joy2Scope") == flScope) nUsingJoyNum = 1;
}
if (nUsingJoyNum >= 0) {
if (IsTriggerFlipped(Input.GetJoystickNames()[nUsingJoyNum])) {
var flTemp:float = flScope;
flScope = flFire;
flFire = flTemp;
}
}
// Will handle any number of controllers that are connected. The
// part that needs some care is deciding when a particular
// controller is _the_ controller.
var flFire:float = 0.0f;
var flScope:float = 0.0f;
var nControllerNdx:int = 0;
var strControllerTable:String[] = Input.GetJoystickNames();
while (nControllerNdx < strControllerTable.length) {
if (IsTriggerFlipped(Input.GetJoystickNames()[nControllerNdx])) {
flScope = Input.GetAxis("Joy" + nControllerNdx + "Fire");
flFire = Input.GetAxis("Joy" + nControllerNdx + "Scope");
} else {
flFire = Input.GetAxis("Joy" + nControllerNdx + "Fire");
flScope = Input.GetAxis("Joy" + nControllerNdx + "Scope");
}
// Insert heuristic on what controller is being used.
if ((flFire > AXIS_FIRE_THRESHOLD) || (flScope > AXIS_SCOPE_THRESHOLD))
break;
nControllerNdx++;
}
NVIDIA® GameWorks™ Documentation Rev. 1.0.220830 ©2014-2022. NVIDIA Corporation and affiliates. All Rights Reserved.