Keyboard Splitter (Local Multiplayer Keyboard)

Hey all, wanted to share this with everyone!

I wrote a utility that creates virtual keyboards and shuffles events around to make PlayerInput/PlayerInputManager think there are more devices and made it really easy to remap keys.

Attached unitypackage to this post.

5750836–604843–Arugula_KeyboardSplitter.unitypackage (3.87 KB)

9 Likes

@Rene-Damm

If you would sir :slight_smile:

Take a peek at the code here - its pretty obvious my keypresses will probably be “One frame late” using this method.
Is there a way to create new StateEvents and have them processed immediately? Calling InputSystem.Update() at the end of an event callback seems like a bad idea heh.

Hi, thank you so much for your script, happy to have this solution !
I just have errors (NullReferenceExceptions) when using it, it seems very low level related


Any idea? Is this really caused by your script or have I done something wrong on my side?

Hmm, what version of Unity and InputPackage do you have?

Yeah, there’s a couple other pieces of code that are confronted with the same problem. ATM it’s not possible to queue input events from within input event processing and have the events flushed out in the same cycle. Only events queued from within onBeforeUpdate will make it into the same frame.

What you can do, however, is bypass event processing through InputState.Change. This will still trigger action monitors and process the state change in a controlled way but it allows to basically jam state changes directly and immediately into the system.

InputState.Change(Keyboard.current, new KeyboardState(Key.A));
1 Like

Hi @Fenrisul thank you for your solution it will really help us debug & playtest our game when no controllers are around.

I can’t seem to get a second keyboard player set up properly. I followed the instructions in the video but only the first player config is working (ie, it works with the default keyboard controls as well as if I remap the controls of player 1) but player to is never recognized (irregardless of remapping it or not).

Using InputSystem 1.0.0 and tried it on my scene and also the Simple Multiplayer sample that comes with InputSystem. No luck. Any help is appreciated!

I seem to have gotten it working. My control scheme had both “Keyboard” and “Mouse” in the required devices (as did the Simple Multiplayer sample). Removing “Mouse” fixed the issue and the utility works as expected now. Thanks!

@Fenrisul I see that the script only works with the “Join Players When Button Is Pressed” option on PlayerInputManager. When selecting “Join Players When Join Action Is Triggered” and given a reference it works once (accepting the Join Action from either layout) but not from the second layout that attempts to join.
Any easy workaround for this that you can think of?

The script works, I think.
The splitter now feeds output to both of the joined players, which I think is because I implemented my input into my player by making an instance of the input asset and getting my input from there.

void Awake()
    {
       
        BodyController = GetComponent<BodyController>();
        Controls = new PlayerControls();
    }

    private void OnEnable() { Controls.Enable(); }

    private void OnDisable() { Controls.Disable(); }

void ManageInput()
    {
        InputVector.x = Controls.Player.Movement.ReadValue<Vector2>().x;
    }

any workarounds to this?

Hey @Fenrisul ,

great Video! I was searching for weeks and couldnt find a working solution, but i feel your script is the closest i can get. Just like shown in the video i added the keyboard splitter component and i am (finally) able to spawn a second player (with the keyboard), but they both move in sync all the time. When i use the right half of my keyboard both players follow the same instructions and when i use the left half its the same. Do you know any solution to the problem?

Thanks in advance!

Hi! I’ve attached a package with an Example of this script working correctly. If the example scene fails the same way, I can help you figure out what’s going on.

7002035–827603–Arugula_KeyboardSplitter_Example.unitypackage (15.6 KB)

I cant believe it :eyes: Your scene is perfectly working and i cant find anything that i did different. Maybe you could take a quick look at my scene, because i am not experienced enaugh to find the solution. Of course i understand if you dont want to, but it would be a huge help, because im struggling for weeks now. If not i can start a new project from the bottom with the new input system done first.

I see you’re using the Generate C# Class option. The Unity PlayerInputManager and PlayerInput class are not compatible with Generate C# Class.

See the example I posted and how its using the SendMessages option of PlayerInput to marshal the controls to the player’s instanced prefab.

Additionally I actually made a few tutorials on “How to get goin” with this stuff:

The local multiplayer one in particular is probably of interest to ya.

There are definitely more interesting ways to deal with local-multiplayer since I wrote that tutorial, but this should at least get ya started.

Ohhh. Thank you so much! I finally got it! I just assumed the Generate C# Class is needed after i saw it in another tutorial. Great tutorial and thanks again for your help!

You’re welcome! :slight_smile:

And yea… it would be nice if Unity shipped an Input System with 3 modes of use that were all compatible with eachother… but they didn’t, and its a sad state of affairs.

2 Likes

First up: great job, really appreciate your effort.

However, I’m currently running into a very odd bug that’s tricky to pin down, as I’m not getting any error messages.

Essentially the splitter works great… until it does not. It seems that it stops working after I have modified some code in my scripts and Unity has re-compiles. Not always, but if the issue occurs, it’s after re-compiling.

Likewise I can’t reliably get it get to work again. Dis/re-enabling the KeySplitter component does not seem to work. Again, letting C# re-compile after modifying anything in my project does sometimes seem to help, as does a restart of the entire project. As before, it’s not reliable solution.

As you can probably tell by that terrible bug report I’m completely stumped :slight_smile: Open to any ideas to help pin this one down.

Indeed horrible bug report! lol.

What version of Unity, Input System, and which path are you using? (Generate C# Class, PlayerInput, manually linking Actions, etc).

2020.3.1f1, Input System 1.0.2

I’ve got a fairly standard setup: Player Input Manager set to “join when button is pressed”, the PlayerInput invokes Unity Events, which are then intercepted by my PlayerController which sets the movement etc.

I’ll add more debug.logs to determine at what point the splitter fails (or if the issue occurs earlier, pointing towards another cuprit)

This script is exactly what I’ve needed for a long time! Unfortunately, I’m running into a weird issue where when attempting to join players by input the input system does not recognize the input until around 5 to 10 seconds have passed in the runtime, after which the system works flawlessly. If you have any ideas what could be causing it I’d appreciate the help.

This is just what I was looking for!