Search Unity

Missing features: Sensitivity, Unity Action arguments

Discussion in 'Input System' started by illinar, Oct 15, 2019.

  1. illinar

    illinar

    Joined:
    Apr 6, 2011
    Posts:
    863
    Use case
    Rotating camera with gamepad or mouse.

    Approach
    Having Vector2 RotateCamera action with a binding for each control scheme. Sending UnityEvent in PlayerInput when action is triggerd. Reading the event and applying the given input value in camera control script.

    Missing Features
    I need to be able to send value in unity events in PlayerInput.
    I need sensitivity setting in binding properties so I can use this action's value directly no matter if its a mouse or a gamepad stick. Currently I would have to create additional layer for handling those events and set sensitivities there. Also I need that layer because Unity Actions are void for some reason instead of having the value type of the action (V2 in this case).

    With those features in place I could just directly use PlayerInput anywhere I want.
     
  2. Jichaels

    Jichaels

    Joined:
    Dec 27, 2018
    Posts:
    237
    If you have control schemes, then you can just do something simple like :

    Code (CSharp):
    1. switch (_playerInput.currentControlScheme)
    2. {
    3.     case "MouseKeyboard":
    4.         yourInput * MouseSensitivity;
    5.         break;
    6.     case "Gamepad":
    7.         yourInput * GamepadSensitivity;
    8.         break;
    9. }
     
  3. illinar

    illinar

    Joined:
    Apr 6, 2011
    Posts:
    863
    On closer inspection I can't make another generic "layer" for the input

    upload_2019-10-15_15-52-57.png

    because Player input doesn't send any data about the event.

    Instead it seems that my only option is to manually handle each Action.. I t could be so easy but now I need a class for each action.

    This could also could be solved by _playerInput having a .currenAction so when it's triggered I could go and get any additional data I want.
     
  4. Rene-Damm

    Rene-Damm

    Joined:
    Sep 15, 2012
    Posts:
    1,779
    The idea here is to put sensitivity scaling as processors on the bindings. E.g. have a scale processor on the gamepad left stick binding with one value and another scale processor with a different value on the mouse delta binding.

    One thing we're missing here is the ability to set parameters dynamically. ATM, if, for example, you want to have a mouse sensitivity setting in your game settings and want that to affect the mouse delta binding, the only way to do so currently is by writing a custom processor.

    Code (CSharp):
    1. #if UNITY_EDITOR
    2. [InitializeOnLoad]
    3. #endif
    4. public class MouseSensitivityProcessor : InputProcessor<Vector2>
    5. {
    6.     public override Vector2 Process(Vector2 value, InputControl control)
    7.     {
    8.         return value * MyGameSettings.mouseSensitivity;
    9.     }
    10.  
    11.     #if UNITY_EDITOR
    12.     static MouseSensitivityProcessor()
    13.     {
    14.         Register();
    15.     }
    16.     #endif
    17.  
    18.     private static void Register()
    19.     {
    20.         InputSystem.RegisterProcessor<MouseSensitivityProcessor>();
    21.     }
    22. }
    BTW, to find out where input is coming from, you can use InputAction.CallbackContext.control. This gives you the control that triggered the action. From it, you can also reach the device via InputControl.device.
     
  5. illinar

    illinar

    Joined:
    Apr 6, 2011
    Posts:
    863
    Thanks. Is there a way to get the current control scheme without strings and preferably without PlayerInput? Ideally subscribe via script to an event on control scheme change?
     
  6. Jichaels

    Jichaels

    Joined:
    Dec 27, 2018
    Posts:
    237
    Yeah, you can do :
    Code (CSharp):
    1.  
    2. InputUser.onChange += yourCallback;
    3.  
    4. private void yourCallback (InputUser user, InputUserChange change, InputDevice device)
    5. {
    6.     if (_playerInput.user != user) return;
    7.     if (change != InputUserChange.ControlSchemeChanged) return;
    8.  
    9.     yourLogic here
    10. }
    That's what I'm doing at least
     
  7. Rene-Damm

    Rene-Damm

    Joined:
    Sep 15, 2012
    Posts:
    1,779
    PlayerInput is built on InputUser which can be used directly to manage devices, actions, and control schemes. However, PlayerInput is currently the only way to get fully rigged support for automatic control scheme switching. It's on the TODO list to equip generated C# classes with equivalent means.

    Code (CSharp):
    1. // Start user out with keyboard&mouse.
    2. var user = InputUser.PerformPairingWithDevice(Keyboard.current);
    3. InutUser.PerformPairingWithDevice(Mouse.current, user: user);
    4.  
    5. // Pick keyboard&mouse control scheme
    6. user.ActivateControlScheme("Keyboard&Mouse");
    7.  
    8. // Associate actions with user.
    9. user.AssociateActionsWithUser(myActions);
    10.  
    11. // Listen for unpaired device activity to initiate control scheme switches.
    12. ++InputUser.listenForUnpairedDeviceActivity;
    13. InputUser.onUnpairedDeviceUsed +=
    14.     (control, eventPtr) =>
    15.     {
    16.         // Initiate control scheme switch. "control" is the control that the user actuated.
    17.         // Guaranteed to not be noise. "control.device" is the device that received input.
    18.         // Determine which control scheme to use and update device pairing accordingly.
    19.     };
    20.  
    21. xxx
     
  8. illinar

    illinar

    Joined:
    Apr 6, 2011
    Posts:
    863
    Thank you. I totally missed the processors.

    So what is the recommended way to read the event value? InputAction.CallbackContext.control I have no idea what that is..

    upload_2019-10-15_16-31-58.png

    I don't see InputUser class anywhere either..

    upload_2019-10-15_16-37-0.png

    UnityEngine.InputSystem is imported.
     
  9. Jichaels

    Jichaels

    Joined:
    Dec 27, 2018
    Posts:
    237
    I'm using Rider so all using are done automatically, but I think it's in this :

    using UnityEngine.InputSystem.Users;
     
  10. illinar

    illinar

    Joined:
    Apr 6, 2011
    Posts:
    863
    Just to be clear I would prefer to use just the PlayerInput, but I can't find a way to access the input value. This is the core issue.
     
  11. illinar

    illinar

    Joined:
    Apr 6, 2011
    Posts:
    863
    Right, makes sense. Thanks.
     
  12. Jichaels

    Jichaels

    Joined:
    Dec 27, 2018
    Posts:
    237
    Your callback using PlayerInput/Invoke Unity events should be

    public void YourCallback(InputAction.CallbackContext ctx)
    {
    ctx.ReadValue<theType>();
    }
     
  13. illinar

    illinar

    Joined:
    Apr 6, 2011
    Posts:
    863
    Yes, I just remembered how to use the context

    upload_2019-10-15_16-52-27.png

    Now gonna try in PlayerInput event callbacks.
     
  14. illinar

    illinar

    Joined:
    Apr 6, 2011
    Posts:
    863
    So, I thought you mean this:
    upload_2019-10-15_17-7-5.png
    But PlayerInput event can't see OnRotationInput();

    Here is the weird part for me. Out following three methods it can see only bool one... Why??
    upload_2019-10-15_17-12-49.png

    upload_2019-10-15_17-11-26.png
     
  15. illinar

    illinar

    Joined:
    Apr 6, 2011
    Posts:
    863
    I guess this is not bad at all: upload_2019-10-15_17-19-50.png

    But ideally I would avoid making these input scripts and would use PlayerInput instead.

    Another reason to have these input scripts is to handle global sensitivity later if it dynamic sensitivity is not supported. Or is there dynamic global sensitivity built into the input system?
     
  16. Sorry for the offtopic, but please use the CODE tags on the forums. It is very hard to follow your code in dark, unreadable screenshots. You can find info how to paste code in the forums here.
     
  17. illinar

    illinar

    Joined:
    Apr 6, 2011
    Posts:
    863
    Okay. I thought it's much more readable than the style in which code is presented here with tags.
     
  18. Deozaan

    Deozaan

    Joined:
    Oct 27, 2010
    Posts:
    707
    For what it's worth, I didn't have a problem reading your code. And I much prefer the darker theme. :D:cool:

    That said, it is better to use actual text rather than screenshots, for accessibility purposes.
     
  19. Tony_Klink

    Tony_Klink

    Joined:
    Jul 16, 2015
    Posts:
    1

    I have an issue working with custom processors. I've copied your code, changed MyGameSettings.mouseSensitivity to my value.
    Everything works fine in the editor. When I hit play - mouse is working properly.
    But when I do Build & Run - code that didn't use processors, and code that uses default ones like 'Scale Vector2' works, and code that uses this 'MouseSensitivityProcessor' seems not working and affected input completely lost.

    On a side note I have Cursor.lockState = CursorLockMode.Locked in my application
     
  20. Cissi

    Cissi

    Joined:
    Jun 12, 2020
    Posts:
    1
    I had the same problem when copying this code. Everything worked in the editor, but when I made a build, the actions using my custom processor was not working, as if the input was lost/didn't happen.

    I solved it by adding [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] to the Register-method.

    Code (CSharp):
    1. #if UNITY_EDITOR
    2. [InitializeOnLoad]
    3. #endif
    4. public class MouseSensitivityProcessor : InputProcessor<Vector2>
    5. {
    6.     public override Vector2 Process(Vector2 value, InputControl control)
    7.     {
    8.         return value * MyGameSettings.mouseSensitivity;
    9.     }
    10.     #if UNITY_EDITOR
    11.     static MouseSensitivityProcessor()
    12.     {
    13.         Register();
    14.     }
    15.     #endif
    16.  
    17.     [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
    18.     private static void Register()
    19.     {
    20.         InputSystem.RegisterProcessor<MouseSensitivityProcessor>();
    21.     }
    22. }
    I can't say I completely understand why it works. I found this thread with a different issue with custom processors, that's why I tried it. Possibly a bad solution but seems to work the way I want it to now.

    If anyone come across this and know why this worked or if there is a better way to solve it I would love to know.

    (The actions I use the custom processor for is used only with the CinemachineInputProvider-script, if that is relevant.)
     
    Last edited: Apr 30, 2021