Cheap Way
You can exploit the fact that the system tags numbers onto names to make them unique. For example, you can take a binding to “trigger” on “MyJoystick” (replace that with whatever the layout you are using is), toggle it into text mode (the little “T” button) and edit it to read
<MyJoystick>*1/trigger
to only bind to the second (first one is 0 which is not actually tagged onto the name) MyJoystick.
However, you will be dependent on the order in which devices are added.
Better Way
You can bind to devices by “role”. These are just string tags and each device can have however many you want/need.
So, you can go and tag the devices at runtime like so
InputSystem.AddDeviceUsage(joystickForPlayer1, "Player1");
InputSystem.AddDeviceUsage(joystickForPlayer2, "Player2");
InputSystem.AddDeviceUsage(joystickForPlayer3, "Player3");
InputSystem.AddDeviceUsage(joystickForPlayer4, "Player4");
And in bindings you can drop into text mode (like above) and edit paths like so
<Joystick>{Player1}/trigger
If the joystick happens to be a layout you have added, you can also set the “commonUsages” property on the layout. This way, the usages show up in the control picker and you don’t have to do the manual text editing dance.
[InputControlLayout(commonUsages = new[] { "Player1", "Player2", "Player3", "Player4" })]
public class MyJoystick : Joystick
{
//...
////EDIT: Just to add that, there’s a “CommonDeviceUsages” sample that comes with the input system which demonstrates this feature and pretty much does what the second option here outlines.