How to call Actions from code in new input system

Hi, I have created a kind of custom joystick that works with touch. I want a specific behavior for it, but I don’t know how to communicate it with the input system.

I would like to be able to call the action directly or otherwise pass the value to the input system and have it handle the call to action. Here is an example of the code:

        private void HandleFingerMove(Finger obj)
        {
            if (obj != _currentFinger) return;

            Vector3 handlerPosition = Vector3.zero;
            handlerPosition.x = Mathf.Clamp(obj.screenPosition.x - _originTouchPoint.x, -sliderSize, sliderSize);
            handler.transform.localPosition = handlerPosition;
            
            float axisValue = handlerPosition.x / sliderSize;
            // Send axisValue to Input System
        }

Thanks :slight_smile:

The Input System provides its own set of scripts for this:
https://docs.unity3d.com/Packages/com.unity.inputsystem@1.10/manual/OnScreen.html#writing-custom-on-screen-controls

You could extend those or look at the source to see how it’s implemented. Basically, you create a virtual device and then implement controls that match the ones you’re trying to simulate.

Thank you for your response. It would seem the solution, inherit “OnScreenControl” and call SendValueToControl() having set the m_controlPath. But it doesn’t seem to work. Maybe I’m setting the m_controlPath wrong.

        [InputControl]
        [SerializeField]
        private string mControlPath;

        protected override string controlPathInternal
        {
            get => mControlPath;
            set => mControlPath = value;
        }

        private void HandleFingerDown(Finger obj)
        {
            if (_currentFinger != null) return;
            SendValueToControl(1);

            // More code here
        }

The input is never transmitted by code through the action. However, it does arrive if I am using a gamepad.

It doesn’t seem to make sense unless I’m doing something wrong.

Haven’t tried a custom subclass but at least OnScreenButton works fine for me.

Do you only ever send 1 to the control? It might only work properly when transitioning form 0 to 1, so you might have to send it 0 at the beginning.

Also check there’s not something else preventing the input, like some code disabling actions or ignoring input when using touch/mouse instead of gamepad.

Looks like I found the problem :slight_smile: I was using the OnEnable and OnDisable methods in my class, this override those of the OnScreenControl class. Once the methods are removed everything seems to work, unfortunately they are private and cannot be called from child :frowning:

My problem now is that I input to make them call since it is a -1 to 1 slider and none of the unity inputs expect that in general. Using some input from a device I don’t support would seem really strange and not appropriate :thinking:

image

Which version of the Input System package are you using?

OnEnable and OnDisable haven’t been private since version 1.1.0, they are now properly protected virtual. The currently recommended version is 1.7.0 and the latest is 1.10.0, if you’re working with such an old version you should update.

Depending on what you use it for, you could send your -1..1 value:

  • To a stick control and use only one axis
  • To a trigger control and remap it to 0..1 range
  • Split it between two triggers, so <0 goes to one and >0 to the other trigger

I am using input system version 1.7.0 and Unity version 2022.3.11f1. OnEnable and OnDisable are private per Unity framework and have nothing to do with InputSystem.

I will probably use the X value of a joystick, thanks for the suggestions.

Those are what Unity calls “messages” and which are called from native code using reflection. Messages completely ignore normal C# conventions and are based on implementing a method with a specific name in a specific subclass.

Unlike regular C# inheritance, the class implementing a message can freely choose the protection level, you can have private void OnEnable(), protected virtual void OnEnable() or public void OnEnable() – all of those are valid implementations of the Unity OnEnable message.

However, Unity doesn’t handle subclasses, it will call the first OnEnable it finds in the class hierarchy, which is why your OnEnable was called but the base class OnEnable was ignored (you should have gotten a warning, though). That’s why it’s important that base classes implement messages as virtual, so that subclasses can override and use them as well.

If you check the implementation of OnScreenControl, you can see that OnEnable is implemented as protected virtual. All you need to do is override it and call the base implementation:
https://docs.unity3d.com/Packages/com.unity.inputsystem@1.7/api/UnityEngine.InputSystem.OnScreen.OnScreenControl.html#UnityEngine_InputSystem_OnScreen_OnScreenControl_OnEnable

oh, I see, very useful this information, indeed they are protected in version 1.7.0 and I can call the base, thank you very much :slight_smile:

However I’m getting some strange behaviors, I thought it could be because of the simulator so I created a build of the game for Android but it behaves the same. When calling SendValueToControl it seems to transmit the value, however it immediately receives a value of 0 that I am not sending.

image