Input device priority

Hello,

While on PS4 and Xbox, the button to validate menus is Cross or A (south button), on the Switch it’s the A button (East!). Is there some kind of way to setup both buttons for one action and have them have priority over the other?

I expected the “A” entry would take over the “Button South” because it’s before in the list, but what happens actually is that both inputs are taken into account. Which means that right now, on switch, whenever I press the A button, I both Submit and Cancel and when I press the B button, I both Cancel and Submit…

If you’re using PlayerInput, you should create a control scheme for Switch controller, and one for any generic gamepad for exemple. Control scheme are meant to handle this kind of situation I believe

A priority system would be better as it would avoid re-doing all the inputs when there is only one that changes. I’m going to try that in the meantime.

EDIT: The problem stays. I think both control schemes end up being enabled. I didn’t find a list of enabled control schemes in the debugger, is it somewhere? That would probably be a good addition if it’s not.

For the controller scheme solution to work, I think we would need a way to exclude certain controllers from the control schemes. However, I still think the priority system would be way better.

If you’re not using PlayerInput, control scheme don’t mean anything (if I understood correctly).
You can see what control scheme is in use on the PlayerInput inspector (greyed debug line at the bottom).
If you set up a control scheme with your switch gamepad as required, and nothing else, then it should get the priority over another control scheme that just has generic “Gamepad”

Agree. ATM we’re still missing the ability to make a guided decision between multiple control schemes that are applicable. What the system does right now is just pick the first one that matches – which gives the desired result if the control schemes are ordered by specificity but there’s no direct control over the ordering.

Looking at this is on the list for after 1.0.

In my case, it doesn’t seem to pick the first one that matches, it picks all of them. Which means I get inputs triggered twice when I press a button.

Yup, @Jichaels is correct that there is no automatic control scheme support except when using PlayerInput. The APIs it uses to drive control schemes are all public but it needs extra scripting. After 1.0 we want to add control scheme support to generated C# classes.

For now, you have to either use InputUser to set up actions, device pairings, and control schemes (the way that PlayerInput does) or user the underlying APIs on InputActions and related APIs directly.

// Instantiate generated C# class.
var actions = new MyGameActions();

// Restrict bindings to one specific control scheme.
// Binding group generally corresponds to control scheme
// name. Can be read out from InputControlScheme.bindingGroup.
actions.bindingMask = InputBinding.MaskByGroup("KeyboardMouse");

// Restricting bindings to pick only from a specific set of devices.
actions.devices = new[]
{
    Keyboard.current,
    Mouse.current
};

I’ve been trying to use PlayerInput or InputUser directly, but I find it rather difficult to control which system user is assigned to which PlayerInput entry or how to assign devices to the right user. For my use case, the whole automatic prefab instanciation is not convenient. Is there a clearer documentation somewhere about system user assignation for consoles ?

Docs still need improvement. Gist of InputUser should be relatively straightforward, though.

// On consoles specifically, pairing subtly different in that you're
// not really controlling which device to give to which user but the
// user does.
//
// So, say you have a title where you have an initial engagement screen which then
// leads to a main menu with a built-in lobby for more players to join (example: Overcooked).
//
// When engagement screen comes up, start listening for unpaired device activity. Let's
// say we specifically require the A button to be pressed for both initial engagement and
// for additional joins.
++InputUser.listenForUnpairedDeviceActivity;
InputUser.onUnpairedDeviceUsed +=
    (control, eventPtr) =>
    {
        if (control.device is Gamepad gamepad &&
            gamepad.buttonSouth.ReadValueFromEvent(eventPtr) >= gamepad.buttonSouth.pressPointOrDefault)
        {
            var user = InputUser.PerformPairingWithDevice(control.device);
            // If in initial engagement screen, first user has now joined.
            // Otherwise, an additional player has joined.
        }
    };

// If user unjoins, nuke the player with InputUser.UnpairDevicesAndRemoveUser.
// To get all current users, use InputUser.all.
// Use InputUser.id to associate user records with other records you keep for a player.
// Use InputUser.AssociateActionsWithUser() to associate a set of actions with one player. Actions
// will automatically be restricted to bind only to devices paired to the user.

Note that we haven’t yet hooked up user account management in the console backends. While InputUser is designed to deal with console-style user management and tie that into device pairings, the backend code on the three consoles are still missing and thus this part of the API won’t be functional yet.

When this is finished, the idea here is that PerformPairingWithDevice will, for example, automatically bring up the account picker on Xbox and for both Xbox and PS4 will return an InputUser with the right platform account info. Idea for Switch goes along similar lines but need to be looked at more.

Thanks for the details. It sounds nice for multiplayer but it maybe a little too high level still.

In my case I have a single player game and I just want to respect the controller tied to player 1, the one that started the app. On Xbox, an engagement screen is always necessary, but on PS4 and Switch, we just need to lookup which user started the app and which controller it is using. Right now it tends to pick any controller that works and that’s not really the goal.

I don’t mind getting my hands dirty and implementing what’s missing. I already downloaded the repo from github to help me figure stuff out and I did notice the switch implementation (which got from the dev forum, not github, obviously) is rather thin right now.

My goal is to simply have one InputUser with just the right InputDevices on it and using the action map I’ve created in the editor. I said InputDevices plural but on ps4 it will be just one controller. However on Switch it should change from handheld to dual joy-con to single joy-con as the user changes it from the home menu or from the controller applet whenever I trigger it.

I noticed the PerformPairingWithDevice and I noticed the UnpairCurrentDevicesFromUser but a UnpairDeviceFromOtherUsers would have been more useful in my opinion haha.

At this point, I instanciate an actionmap from the configured asset, set its devices to null and assign that actionmap to the InputSystemUIInputModule. I expected this would make the UI inputs to completely stop working but it still gets inputs from everything.

EDIT: Oh snap! I now why I’m still getting inputs everywhere. I’ve setup InputActionReferences everywhere which are still bound to the original asset. So all is fine I guess, I just need to change my design.

I think the code flow above should still be useful in the scenario you describe. You’ll have to handle the platform user account selection yourself, but otherwise I think it should give you what you’re looking for.

++InputUser.listenForUnpairedDeviceActivity;
InputUser.onUnpairedDeviceUsed +=
    (control, eventPtr) =>
    {
        #if UNITY_PS4 || UNITY_SWITCH
        // We know the user has engaged with the device from a control that isn't noise.
        // We have our device to start the game with.
        // To find the platform user, we unfortunately have to specifically cast to
        // DualShockGamepadPS4 or Npad to get to the user info for the platform.
        #elif UNITY_XBOXONE
        // Same thing here, we know the user has engaged. However, we don't know yet
        // whether it's from a device that no user is currently logged in on or not. Cast device
        // to XboxOneGamepad and take it from there, bringing up the account picker if
        // need be.
        //
        // NOTE: On this path, we probably also want to filter specifically for button presses.
        #endif

        // Can ignore any of the pairing functions, if we want to. If all we're interested in is
        // finding the device of initial engagement and making sure we have a user account,
        // we're set now.
        //
        // To let the user switch, we need to set up more to basically perform a similar thing
        // we've just done above but do it on the fly.
    };
1 Like

Is there a recommended way of doing this in 2022? I have a game which should use the platform-standard controls for game map and game menu. On Xbox, game map should be “Menu” button and game menu should be “View” button. On PS5 map should be “touchpadButton” and game menu should be “Options”. However, as far as I can tell there’s no obvious way to set this up.