Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Join us on Thursday, June 8, for a Q&A with Unity's Content Pipeline group here on the forum, and on the Unity Discord, and discuss topics around Content Build, Import Workflows, Asset Database, and Addressables!
    Dismiss Notice

New Input System : How to use the "Hold" interaction.

Discussion in 'Input System' started by Xynhay, Dec 31, 2018.

  1. tclancey

    tclancey

    Joined:
    May 19, 2017
    Posts:
    143
    It's now August of 2020 and there still isn't a way to tell if my player is holding a button? At least not one I can find quickly or easily.

    For someone starting with Unity this input system is just tooooo much. It's going to put a lot of people off. This is the only engine I've ever tried to use where I need to put an hour and 30 lines of code into getting a key press. Come on, this is just nuts.
     
    nglasl, florianBrn, NotaNaN and 8 others like this.
  2. PixelLifetime

    PixelLifetime

    Joined:
    Mar 30, 2017
    Posts:
    90
    This system has a steep learning curve but it offers a lot more after you master it. It's new thus not many tutorials are available and I understand how you feel. But making it easier for someone to use is not always a good option when developing systems like this.
    If you dive deep and understand it, there are things like interfaces and code generation that let's you use input in 3 lines of code if you don't count `{}`.

    You must be looking for `InputAction.triggered` if you need a boolean that tells if your button is pressed or not. If you need holding for some amount of time then checkout `Interactions`.

    If you are starting with Unity I suggest to avoid using this system but instead use the old one. This one will take some time to understand, if you don't wish to put that time into this right now, learning the old way is not a bad thing, it's even better because you will be able to see differences and improvements at a later point.
     
    SomeGuy22 and MassimoFrancesco like this.
  3. MassimoFrancesco

    MassimoFrancesco

    Joined:
    Jul 6, 2019
    Posts:
    44
    I've implemented the new Input System already, but am still polling the old way in Update() for the key holding (movement buttons).
    You can workaround this by what PixelLifetime said, using a boolean. But I would recommend you not using the new input system, if you are just starting out.

    Don't worry, if you keep your ("old") input code in one place, you will be able to easily swap it out in a day of work, as soon as NewInputSystem is more fleshed out. It's not complicated.
     
    SomeGuy22 likes this.
  4. jackieucla

    jackieucla

    Joined:
    Mar 30, 2020
    Posts:
    3
    I have read through this thread about a half dozen times and trying hard to invest in figuring out how to make this input system work but it is definitely confusing..

    Short version of question: why is my bool isMoving never set to false after I release the key?


    Code (CSharp):
    1. private InputControls inputCtrls;
    2.         private bool isMoving = false;
    3.         private Vector2 moveDirection;
    4.  
    5.         private void Awake()
    6.         {
    7.             inputCtrls = new InputControls();
    8.             moveDirection = new Vector2(0,0);
    9.         }
    10.  
    11.         private void OnEnable()
    12.         {
    13.             inputCtrls.Player.Enable();
    14.             inputCtrls.Player.Movement.started += Movement_started;
    15.             inputCtrls.Player.Movement.performed += Movement_performed;
    16.             inputCtrls.Player.Movement.canceled += Movement_canceled;
    17.  
    18.             Debug.Log("Movements assigned");
    19.         }
    20.  
    21.         private void Movement_started(InputAction.CallbackContext obj)
    22.         {
    23.             moveDirection = obj.ReadValue<Vector2>();
    24.             Debug.Log("Movement started: " + moveDirection.ToString());
    25.             isMoving = true;
    26.         }
    27.         private void Movement_performed(InputAction.CallbackContext obj)
    28.         {
    29.             moveDirection = obj.ReadValue<Vector2>();
    30.             Debug.Log("Movement performed: " + moveDirection.ToString());
    31.             isMoving = true;
    32.         }
    33.         private void Movement_canceled(InputAction.CallbackContext obj)
    34.         {
    35.             moveDirection = Vector2.zero;
    36.             Debug.LogError("Movement stopped");
    37.             isMoving = false;
    38.         }
    39.  
    40.         private void OnDisable()
    41.         {
    42.             inputCtrls.Player.Movement.started -= Movement_started;
    43.             inputCtrls.Player.Movement.performed -= Movement_performed;
    44.             inputCtrls.Player.Movement.canceled -= Movement_canceled;
    45.             inputCtrls.Player.Disable();
    46.         }
    47.  
    48.         void Update()
    49.         {
    50.             if (isMoving)
    51.             {
    52.                 Debug.Log("Why does this message keep looping?");
    53.             }
    54.         }
    Long Version of Question:
    I am trying to get a correct hold down behavior for a binding to a Vector2 composite (using WASD keys) for player movement. When this script is attached to my game object, the "~looping" message just continues to display even after I let go of the keyboard. In addition, "Movement Started" never displays. I would want it to display "Movement Stopped" after button release but that does not work with this as well. Could someone explain how this behavior does not seem to work for Vector2 bindings but it does work fine if the Action type is assigned to Button? I need to be able to use Vector2 composite for proper movement. Is there a reason the Vector2 composite does not behave the way a Button does?
     
    Last edited: Aug 29, 2020
    zozazu likes this.
  5. NeatWolf

    NeatWolf

    Joined:
    Sep 27, 2013
    Posts:
    924
    Hi!

    I have 2 actions on the right stick click:

    One on press
    One on hold

    looks like everything works fine but... the "hold" InputAction only triggers once, even if you release it and press it again?

    I mean, when it reaches the state of Triggered, seems to be stuck in the canceled state.

    Does it need to be reset?

    is there any doc specifically about it?
     
  6. BigHandInSky

    BigHandInSky

    Joined:
    Apr 26, 2015
    Posts:
    5
    Hey, just jumping in to say that in 2020.1.5f1, InputSystem 1.0.0, I'm having the same issue as NeatWolf.

    I have a hacky fix for it - note this will call Cancelled immediately after you get performed, so you'll need to account for that.

    Code (CSharp):
    1.  
    2.         private void OnActionTriggered( InputAction.CallbackContext obj )
    3.         {
    4.             if ( obj.action == _skipAction)
    5.             {
    6.                 if ( obj.started )
    7.                 {
    8.                     Debug.Log( "hold started" );
    9.                 }
    10.  
    11.                 if ( obj.canceled )
    12.                 {
    13.                     Debug.Log( "hold cancelled" );
    14.                 }
    15.                
    16.                 if ( obj.performed )
    17.                 {
    18.                     Debug.Log( "hold performed" );
    19.                     if(isThisPlayerActive)
    20.                         CallExitMethod();
    21.  
    22.                     StartCoroutine( ResetControl() );
    23.                 }
    24.             }
    25.         }
    26.  
    27.         private IEnumerator ResetControl()
    28.         {
    29.             yield return new WaitForEndOfFrame();
    30.             _skipAction.Disable();
    31.             yield return new WaitForEndOfFrame();
    32.             _skipAction.Enable();
    33.         }
     
    Jericko likes this.
  7. OFG

    OFG

    Joined:
    Dec 6, 2017
    Posts:
    13
    We have the same freaking problem. When you disable a hold action in its performed callback it got stucks in that state and when you want to use same action the first time you pressed that action nothing happens. Its started callback does not get triggered. So second time you pressed is when the key is actually works.

    This creates very clunky controls. All we need to is release a action from its state and return to its default state.
    Maybe some simple state resetter function would help for either "Action" or whole "ActionMap".
     
  8. a_rabbi

    a_rabbi

    Joined:
    Jun 12, 2018
    Posts:
    1
    Reading this thread, it sounds like using the new input system to do character movement is going to require more LOC than the old input system would require. And on top of that, the new input system will require an additional asset. Is the new input system just not ready to be used yet?
     
    MrGreenish likes this.
  9. SomeGuy22

    SomeGuy22

    Joined:
    Jun 3, 2011
    Posts:
    717
    The Input System is more than production ready. Yes, it's a bit more complicated at first sight than the old way. But once you take the time to learn it and apply your own approaches then it's much more robust and feature-complete than how it used to be. If you want to switch over to relying on callbacks then it's a bit more of structural change you'll have to make to your code if you're used to the old method.

    However it is entirely possible to port over the old input functionality and accomplish exactly the same code pattern if you so desire. If you wrap/obscure some of the steps (by programmatically storing each Action into an easily accessible dictionary and building your own logic on top of it) you can easily replicate the same behavior in basically the same number of lines.

    Not sure what you mean by additional asset, nothing else beyond the Input System package is needed except for what you decide you want to write on top of it. Unless you mean the "Input Action Asset" which is just how you define what key presses/etc are mapped to what actions. It's exactly the same work as defining keybinds to "Buttons" in the old system, only here the UI is much cleaner, more organized, and includes more features, such as defining as many mappings as you want to the same action.
     
  10. felipemullen

    felipemullen

    Joined:
    Mar 4, 2017
    Posts:
    40
    I just got back to Unity after sleeping for a couple years. Decided to check out the new input system, and since this is a top hit on Google, I thought people should know:

    Yes, you can easily implement a hold-only action with the new input system

    Only took me about 30 minutes of derping around, and I was able to implement a mouse click (hold) to rotate the camera (only when hold mouse down).

    As mentioned in some comments, reading a
    boolean
    does appear tricky, but I easily created a value like this:

    Code (CSharp):
    1. _inputActions.Camera.InputHold.started += x => _inputIsDown = true;
    2. _inputActions.Camera.InputHold.canceled += x => _inputIsDown = false;
    I then use that value as a flag that decides whether or not I should update my rotation
    Vector2
    mouse delta.
    Update()
    performs the actual camera movement.

    The Input Actions look like the image attached. If anyone needs more info I can post some more code, but I am a lazy programmer
     

    Attached Files:

  11. zh4r0naX

    zh4r0naX

    Joined:
    Oct 30, 2016
    Posts:
    71
    Performed hold actions don’t reset after you release the button. Can you please fix this ? They stay pressed.
     
    zozazu and MrGreenish like this.
  12. BonitaPersona

    BonitaPersona

    Joined:
    Feb 20, 2014
    Posts:
    16
    +1 to the "hold interaction only triggers once" issue.

    It's been months, and there seems to be absolutely no official statement whatsoever.

    How are we supposed to use the "hold" interaction if it only triggers once per gameplay? It makes no sense. There's something missing somewhere.
     
    MrGreenish and zyndata like this.
  13. SomeGuy22

    SomeGuy22

    Joined:
    Jun 3, 2011
    Posts:
    717
    Please read the above thread before jumping into conclusions here. There's 3 pages of information to look into which explain a multitude of options for continuous input, granted none of them specifically use the hold interaction. But it was also discussed that the hold interaction is not meant and was never meant to be used the way you describe.

    Check out a snippet of this post from October 20th 2019, yes--almost exactly year ago:

    You can also read about this fact which is described very clearly on the Input System 1.0 API:

    "Performs the action if the control is pressed and held for at least the set duration (which defaults to defaultHoldTime)."

    The link is here. In regards to it being "performed", as explained this is no different than a default Action with no interactions--if you hold down a default Action it will remain "performed" (sending exactly 1 performed callback) until you release. So really it would seem there isn't anything "missing", the API docs explain exactly what it does.

    In that regard I wouldn't call it an "issue" either, that is the intended behavior of this interaction. And with a little experimentation and reading of the second page of this thread you'll find plenty of ways to detect continuous input.

    Actually Rene has weighed in a few times on this thread and others explaining ways to read inputs the way you describe. There has been no "statement" on changing the hold interaction because it isn't supposed to be used for continuous input. In fact Rene himself states this on Jan 2nd 2019:

    I should mention though, that just a few weeks ago Rene mentioned some plans for a new update which brings in easy-to-use functions that replace GetButtonDown(), GetButton() etc. that are called from an Action. You can read about that here. The new IsPressed() call is yet another way to get continuous input detected on whatever time-frame you specify in the input settings. I asked a few questions over on that thread and he clarified some details.

    Put simply, I find it odd that people are still treating this like its some huge ignored issue, coming to this thread and raising questions about something that has been answered on pages 1 and 2. But if you do a little research in the API docs and test the system for yourself you'd find that it has been accounted for the whole time. I don't mind if you're new to the Input System and need some things clarified, but before we demand changes to the package itself we should investigate what's available and see if our own use cases can't be fulfilled in other ways we just haven't encountered yet.
     
    Zelgadis87 likes this.
  14. BonitaPersona

    BonitaPersona

    Joined:
    Feb 20, 2014
    Posts:
    16
    I think you're misunderstanding me. I don't want anything to do with the "continuous" state, I'm just talking about there being no option to trigger the "cancel" once the input has been released after the "perform" trigger.

    I read the whole thread before posting, only superficially, and even after reading your post I keep thinking this is indeed an issue in the default "hold" interaction. It triggers only after the key press was held for a while, but it never implies that this can only happen ONCE per gameplay session, with absolutely no exceptions.

    Look it from the other side: what has more chances of having use cases:
    • that this held key press can be repeated more than once per gameplay session,
    • or it can only trigger once.
    I can think of plenty of examples for the first use case: simplified "are you sure prompts" in UI, activating modes or skills during gameplay,
    And actually, I can't think of a single use for the second case, which Rene indeed says the default intended use case.

    If so many people keep coming for this exact same behaviour as if it was an issue, I'm guessing that there is actually an issue. Maybe the issue in the intended behaviour for the default "hold" interaction, or maybe it is in the documentation. People will keep coming.

    Also, I'm not confused, offended, nor want part in any war. I'm extremely pleased and happy with the new Input System package, and keep advocating for it by word-of-mouth. And of course I will keep doing so! And that's exactly why I'm here, investing myself in giving feedback. Nothing personal here.
     
  15. SomeGuy22

    SomeGuy22

    Joined:
    Jun 3, 2011
    Posts:
    717
    My bad, I thought you were weighing in on what has been the majority topic on this discussion which is continuous input. When I read "only triggers once" I presumed you referred to the fact that the interaction doesn't cause multiple performed calls within the same actuation event. Really I would expect a new thread on this topic to really discuss it, because this thread has sort of drifted far beyond the original intent. I apologize for taking it in the wrong direction but the point still stands for anyone as a recap to the previous pages to help those looking for an answer.

    So actually, I dug into this myself and this turns out to be yet another thing which is explained explicitly in the docs that I just linked. This actually is the intended behavior, or rather, the intended consequence of interaction processing in the likely scenarios that the above posts are encountering. You can read what I'm about to explain here.

    Interactions can only "progress" (function properly) when the Process() method is called in response to an input. Take a look at this note from the docs:

    Sure enough, if I test the "Hold Interaction" on an Action which has more than one binding, I encountered the "triggers once per gameplay" issue you describe. But if I make the action have only one binding, then it behaves as expected, allowing me to retrigger the performed callback many times over gameplay.

    What does this mean? It means if the Action in question has multiple controls, this disambiguation system will possibly ignore a control and thus Process() is never called. Leaving you stuck in the performed state.

    The solution? As the docs mention, this control disambiguation occurs when Button or Value type is used, but not with Pass Through. Sure enough, if I set my Action (with multiple bindings) to the type Pass Through, control disambiguation does not occur and the interaction works as expected. Basically you want your action setup to look like this:



    Not sure if this is what was happening to you--if your Action was of the type Button and had multiple bindings. I'm only guessing because this seems to be the scenario posted by a user above and I was able to replicate what you describe under these conditions. If so, give it a try and see if it does the trick.

    You have a point there about "issues" being subjective, however I'd argue this is still not a bug, and would not require any change on the developer's part. Especially considering how simple it is to switch the Action Type and how it is clearly explained in the docs, though maybe hard to associate if you don't know what you're looking for. Therefore, I still don't think there needs to be any "official statement" because this is in fact the intended result, and has a realistic solution to try.

    The only drawback is if you really need your Action to be a Button and not Pass Through. But I'd imagine it doesn't matter for most cases. If you really were insistent on using a Button, at that point you could code your own "interaction" with a timer that just activates as long as the Action is performed. A bit more tedious I know, but this is assuming you really wanted to be strict about the state of this Action.

    Of course, it's not personal, I'm just trying to help and get everyone on the same page. I don't think this is a "war", and I certainly didn't think you were trying to tear down the input system or anything like that, just wanted to maybe provide some alternate solutions to an issue I thought you were bringing up, and now a proposed solution to the actual issue you're describing. I apologize if I was a bit blunt in my reply, I just don't think people should go straight to demanding changes/statements when there's plenty more to research and solve on your own. Especially here when it appears to be the actual intended behavior.
     
  16. FileThirteen

    FileThirteen

    Joined:
    Oct 23, 2012
    Posts:
    31
    I'm not sure where Rene said that it is intended, I scoured the thread but I didn't find it. But at least according to the documentation at: https://docs.unity3d.com/Packages/c...InputSystem.Interactions.HoldInteraction.html

    The action is started when the control is pressed. If the control is released before the set duration, the action is canceled. As soon as the hold time is reached, the action performs. The action then stays performed until the control is released, at which point the action cancels.

    Which means it is supposed to cancel. I did a bunch of testing a while ago and I just redid some of it because you brought this up and I find that yeah it never cancels until the game stops after it is performed. If you cancel before it is performed you can start it again over and over until it is performed then it stays performed forever.

    I see why Rene might say that it's intended behavior though because you can see here:
    https://github.com/Unity-Technologi...m/Actions/Interactions/HoldInteraction.cs#L70

    It literally says it Stays Performed, there does appear to be code to cancel it after it is performed but that doesn't seem to work properly. Most likely due to the transient nature of these context callbacks, but I'm not sure honestly.

    The solution is pretty simple and that's to copy the hold interaction, but customize it so it actually works the way your first use case expects it, which I completely agree with. Add this script, and then you can add the CustomHoldInteraction onto any Action which works the way you expect. Started when pressed, performed when held long enough, then it goes back to waiting, if you go through started then release before the timer then you get canceled. It doesn't ever cancel after it performs and it never performs if it cancels so it either goes started -> performed or started -> canceled:

    This is a slightly modified HoldInteraction, it doesn't use the InputActionPhase.PerformedAndStayPerformed() instead swapping for InputActionPhase.Performed().
    Code (CSharp):
    1. using UnityEditor;
    2. using UnityEngine.InputSystem;
    3. using UnityEngine;
    4.  
    5. #if UNITY_EDITOR
    6. [InitializeOnLoad]
    7. #endif
    8. public class CustomHoldInteraction : IInputInteraction {
    9.  
    10.     public float duration;
    11.  
    12.     public float pressPoint;
    13.  
    14.     private float durationOrDefault => duration > 0.0 ? duration : InputSystem.settings.defaultHoldTime;
    15.     private float pressPointOrDefault => pressPoint > 0.0 ? pressPoint : InputSystem.settings.defaultButtonPressPoint;
    16.  
    17.     private double m_TimePressed;
    18.  
    19.     public void Process(ref InputInteractionContext context) {
    20.         if (context.timerHasExpired) {
    21.             context.Performed();
    22.             return;
    23.         }
    24.  
    25.         switch (context.phase) {
    26.             case InputActionPhase.Waiting:
    27.                 if (context.ControlIsActuated(pressPointOrDefault)) {
    28.                     m_TimePressed = context.time;
    29.  
    30.                     context.Started();
    31.                     context.SetTimeout(durationOrDefault);
    32.                 }
    33.                 break;
    34.  
    35.             case InputActionPhase.Started:
    36.                 // If we've reached our hold time threshold, perform the hold.
    37.                 // We do this regardless of what state the control changed to.
    38.                 if (context.time - m_TimePressed >= durationOrDefault) {
    39.                     context.Performed();
    40.                 } else if (!context.ControlIsActuated()) {
    41.                     // Control is no longer actuated and we haven't performed a hold yet,
    42.                     // so cancel.
    43.                     context.Canceled();
    44.                 }
    45.                 break;
    46.  
    47.             case InputActionPhase.Performed:
    48.                 if (!context.ControlIsActuated(pressPointOrDefault))
    49.                     context.Canceled();
    50.                 break;
    51.         }
    52.     }
    53.  
    54.     public void Reset() {
    55.         m_TimePressed = 0;
    56.     }
    57.  
    58.     static CustomHoldInteraction() {
    59.         InputSystem.RegisterInteraction<CustomHoldInteraction>();
    60.     }
    61.  
    62.     [RuntimeInitializeOnLoadMethod]
    63.     private static void Initialize() {
    64.         // Will execute the static constructor as a side effect.
    65.     }
    66. }
    An example script for you:
    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.InputSystem;
    3.  
    4. public class TestCallbacks : MonoBehaviour
    5. {
    6.     DefaultInputActionAsset inputActions;
    7.  
    8.     private void OnEnable() {
    9.         inputActions.Enable();
    10.     }
    11.  
    12.     private void OnDisable() {
    13.         inputActions.Disable();
    14.     }
    15.  
    16.     private void Awake() {
    17.         inputActions = new DefaultInputActionAsset();
    18.         inputActions.Player.Jump.started += OnStarted;
    19.         inputActions.Player.Jump.performed += OnPerformed;
    20.         inputActions.Player.Jump.canceled += OnCanceled;
    21.     }
    22.  
    23.     private void OnStarted(InputAction.CallbackContext context) {
    24.         Debug.Log("Started");
    25.     }
    26.  
    27.     private void OnPerformed(InputAction.CallbackContext context) {
    28.         Debug.Log("Performed");
    29.         context.interaction.Reset();
    30.     }
    31.  
    32.     private void OnCanceled(InputAction.CallbackContext context) {
    33.         Debug.Log("Cancelled");
    34.     }
    35.  
    36. }
    37.  
    I couldn't get Editor Code to work because of protection levels of some of the classes in the InputSystem, so it is very basic. Default values should be 0.4 and 0.5 respectively, which you can look at the actual HoldInteraction for anyway.

    Also wanted to add what SomeGuy22 says I also tested and with a pass through any action, regular hold interaction it works as expected based on the docs. Cancelled happens upon key release. Dunno what if any side effects it might have using the Pass Through setting. It reminds me when I was doing my testing I discovered that MultiTap also doesn't work properly unless you use Pass Through Any, so this is very insightful, as that disambiguation stuff is most likely why that one also doesn't work.
     
    Last edited: Nov 6, 2020
    BonitaPersona likes this.
  17. SomeGuy22

    SomeGuy22

    Joined:
    Jun 3, 2011
    Posts:
    717
    Were your tests only on Actions with multiple bindings? I've tried HoldInteraction on an Action with a single binding, with type Button, and it worked as expected. So yes, it "supposed to cancel" when working properly, and it does. But because of Control Disambiguation it breaks. As I said, it is likely the intended consequence of this mechanic, while it is inconvenient there are solutions as you have pointed out. It is documented so it's not like we're totally in the dark about some major bug or anything. The reason it's documented makes me think this is intentional, see below:

    I would be more concerned about changing the context method to PerformedAndStayPerformed() having more dangerous side effects than switching to pass through. I'm no expert, don't really have the time to dig through the source files but I'm wondering if there was a specific reason for this to be used. Quickly looking through this file shows that PerformedAndStayPerformed() has no comments, but earlier up there is a note about using it to stop an Input from going back to the waiting phase after "it has been performed". I'm just spitballing here, maybe the way you wrote it is fine and works better, it's hard to say until a bug happens or a dev weighs in on it.

    My limited understanding of Pass Through is that it doesn't cull out other bindings like Button does. It just "passes them through" and any change of any binding results in a callback. You can read about it here. For example, if you're using a Button then I suspect moving the joystick constantly will "override" you pressing the keyboard as the latter will be ignored and one binding only will drive the action. However, with Pass Though both inputs are accepted at the same time you end up with perhaps a combined result or multiple callbacks depending on how you draw out the data. So that would be one consequence of using Pass Through instead of Button. For many situations I'd say it doesn't matter too much. But it all depends on the needs of your project and how carefully you want to measure input.
     
  18. FileThirteen

    FileThirteen

    Joined:
    Oct 23, 2012
    Posts:
    31
    Yes my tests were because I didn't realize it would act so differently because of the control disambiguation. At the time I was just testing setups where it's like you have space and A button on a controller for jump and didn't even realize it was going to be a problem. I'll be honest when I did the testing I thought it was working normally but I didn't even realize to test multiple times, I will just post the chart I made up, you can see the testing isn't perfect so I ended up with mixed results for some stuff like that, it's nice to know the cause finally. Yeah I mean I'm not sure if there would be any side effects of my custom Hold Interaction, as far as I can tell the only side effects would be if you were expecting that canceled callback after the performed on a hold if you were using it to reset something after you release the button for example. I guess Pass Through is the way to go, but it still seems hard for me to really understand. What you say makes some sense though. Seems to me that making Actions with single bindings isn't often an option if you want to support controllers and stuff.

    My testing was just console logs in the callback methods attached to each event firing, just manually going through each and trying to figure out when each event fired. I was a little confused at how the system worked so I just wanted to know and this is what I found. Obviously now it needs to be updated to include the fact about the pass through vs multiple bindings, and the fact that my hold technically didn't work more than once under certain circumstances was completely missed.

    Edit those results I had:

    Action Type Button
    Interaction None
    started, performed on button down | canceled on release

    Interaction Press And Release
    started, performed on button down | started, performed again on button up

    Interaction Press Only
    started, performed on button down

    Interaction Release Only
    started on button down | performed on button up

    Interaction Hold
    started on button down | performed once the button is held long enough | canceled when the button is released too early

    Interaction Multi Tap
    started on button down | canceled if button not pressed fast enough soon enough | performed if button pressed enough times fast enough
    note: multitap doesn't work

    Interaction Slow Tap
    started on button down | canceled if you release before min tap duration | performed as soon as you release if the alotted min tap duration has elapsed (happens when you release the button not when the time has elapsed)

    Interaction Tap
    started on button down | performed if you release before the Max Tap Duration | canceled if you hold down past the Max Tap Duration as soon as the duration passes(no event on button up)

    Action Type Value with a button
    Control Type Any, Analog, Axis, Bone, Digital, Double, Dpad, Eyes, Integer, Quaternion, Stick, Touch, Vector2, Vector3
    Interactions None
    started, performed on button down | canceled on button up

    Control Type Vector2 with a joystick
    Interactions None
    started on any joystick movement, performed while joystick is not centered over and over, canceled when release joystick

    ControlType Any, Analog (didn't test the rest but assume it is the same)
    Interactions Press And Release
    started, performed on button down | performed, canceled on button up

    Interactions Press Only
    started, performed on button down | performed, canceled on button up

    Interactions Release Only
    started on button down | performed, canceled on button up

    Interactions Hold
    started on button down | performed after hold time | canceled when stopping game
    note: this seems broken can't get any more actions, it's like it never releases

    Interactions Multi Tap
    started on button down | performed if button is pressed enough times fast enough | canceled if button is not pressed fast enough soon enough
    note: doesn't work it's broken, only get started and canceled no matter what

    Interactions Slow Tap
    started on button down | performed on release if button was held long enough | cancelled on release if button was not held long enough

    Interactions Tap
    started on button down | canceled as soon as Max Tap Duration elapsed | performed if released before Max Tap Duration elapsed

    Action Type Pass Through
    Interactions None
    performed on button down | performed on button up

    Interactions Press and Release
    started, performed on button down | canceled on button up

    Interactions Press Only
    started, performed on button down | canceled on button up

    Interactions Release Only
    started on button down | performed, canceled on button up

    Interactions Hold
    started on button down | performed as soon as hold time elapses | canceled on button up

    Interactions Multi Tap
    started on button down | performed if button pressed enough times fast enough | canceled if button is not pressed enough times fast enough
    note: This seems to be the only multi tap that is actually working

    Interactions Slow Tap
    started on button down | performed on button up if Min Tap Duration elapsed | canceled on button up if Min Tap Duration not elapsed

    Interactions Tap
    started on button down | performed on button up if release before Max Tap Duration | canceled as soon as Max Tap Duration elapsed (no event on button up after Max Tap Duration elapsed)
     
    SomeGuy22 likes this.
  19. schilbiz

    schilbiz

    Joined:
    Dec 16, 2016
    Posts:
    5
    I just started to work on a new project and wanted to use the new input system this time around. I ran into this exact problem and thought I was overlooking something with the Hold Interactions. It turns out that logic isn't in the new input system yet? I like the idea of not having to constantly check a boolean within and update loop, I came up with a solution using coroutines; it seems to work fine for what I need it for.

    Other than the code below you need to create an Action of Type Button for Horizontal and Vertical with a 1D Axis assigned to the keyboard pos/neg keys. It works for gamepad and others as well.
    upload_2020-11-13_22-41-47.png

    upload_2020-11-13_22-35-38.png

    This is more for new people just starting with the new input system and not sure how to get it to work. It assumes you have already created the inputsettings and assigned PlayerInput, if not read the manual on how to get it setup.

    If you want to modify the delay between the "triggers" (when holding the key down) just modify the wfs variable value. (currently set to .05f)

    Code (CSharp):
    1. private InputActions input;
    2. private bool horizontal;
    3. private bool vertical;
    4. private static WaitForSeconds wfs = new WaitForSeconds(.05f);
    5.  
    6. private void OnEnable() {
    7.     input = new InputActions();
    8.     input.Enable();
    9.     input.Player.Horizontal.started += InputHorizontalStart;
    10.     input.Player.Horizontal.canceled += InputHorizontalStop;
    11.     input.Player.Vertical.started += InputVerticalStart;
    12.     input.Player.Vertical.canceled += InputVerticalStop;
    13. }
    14.  
    15. private void OnDisable() {
    16.     input.Player.Horizontal.started -= InputHorizontalStart;
    17.     input.Player.Horizontal.canceled -= InputHorizontalStop;
    18.     input.Player.Vertical.started -= InputVerticalStart;
    19.     input.Player.Vertical.canceled -= InputVerticalStop;
    20.     input.Disable();
    21. }
    22.  
    23. public void InputHorizontalStart(InputAction.CallbackContext context) {
    24.     horizontal = true;
    25.     Debug.Log("Horizontal key down");
    26.     StartCoroutine("CoroHorizontal", context);
    27. }
    28.  
    29. public void InputHorizontalStop(InputAction.CallbackContext context) {
    30.     horizontal = false;
    31.     Debug.Log("Horizontal key up");
    32.     StopCoroutine("CoroHorizontal");
    33. }
    34.  
    35. IEnumerator CoroHorizontal(InputAction.CallbackContext context) {
    36.     while (horizontal) {
    37.         InputHorizontal(context);
    38.         yield return wfs;
    39.     }
    40. }
    41.  
    42. public void InputHorizontal(InputAction.CallbackContext context) {
    43.     if (context.ReadValue<float>() > 0) {
    44.         Debug.Log("Player move right method");
    45.     } else {
    46.         Debug.Log("Player move left method");
    47.     }
    48. }
    49.  
    50. public void InputVerticalStart(InputAction.CallbackContext context) {
    51.     vertical = true;
    52.     Debug.Log("Vertical key down");
    53.     StartCoroutine("CoroVertical", context);
    54. }
    55. public void InputVerticalStop(InputAction.CallbackContext context) {
    56.     vertical = false;
    57.     Debug.Log("Vertical key up");
    58.     StopCoroutine("CoroVertical");
    59. }
    60. IEnumerator CoroVertical(InputAction.CallbackContext context) {
    61.     while (vertical) {
    62.         InputVertical(context);
    63.         yield return wfs;
    64.     }
    65. }
    66. public void InputVertical(InputAction.CallbackContext context) {
    67.     if (context.ReadValue<float>() > 0) {
    68.         Debug.Log("Player move up method");
    69.     } else {
    70.         Debug.Log("Player move down method");
    71.     }
    72. }
    73.  
     
  20. Karsten

    Karsten

    Joined:
    Apr 8, 2012
    Posts:
    183
    This is really sad, the fact that there is no way to continous call an event on keydown on buttondown ect forces the developer to write code about what the event is meaning , this is similiar what we did with the old system when we tried to to do remapping what action is called with what keypress...
    hold, press,performed ,canceled all new terms to learn what they mean and their names are often misleading

    overall much much code needed to solve basic stuff like a key holded down calling a methood continious.
    When I see the Spagetthi codewalls in this thread trying to solve "how to interprete event xyz problems" I want to cry.
    I hope in the next refactoring run wonders happen.
    Edit: And the PlayerInput "Invoke Unity Events" Behaviour which would be good for prototyping is very unpredictable , after all for me it looks like the standard is just "call the event once a key is pressed and once a key is released" the rest is up to the developer
     
    Last edited: Nov 24, 2020
    chriseborn, lgmsantos and GrayedFox like this.
  21. SomeGuy22

    SomeGuy22

    Joined:
    Jun 3, 2011
    Posts:
    717
    Code (CSharp):
    1. void Update() {
    2.     MyContinuousFunction(myInputAction.ReadValue<Vector2>());
    3. }
    Not understanding why this is not satisfactory for what you might need, did you read the thread? Please check the InputAction documentation.

    They're not going to code your game for you; the Input System is meant to provide a way to package hardware inputs into easily understood Actions, a useful data class which can act on callbacks you provide. How you interpret those Actions and callbacks are up to you.
     
  22. Karsten

    Karsten

    Joined:
    Apr 8, 2012
    Posts:
    183
    @SomeGuy22 I wish I had as much time as you to write in forums and look detailed and indeep into every new thing, thanks for the tip how to use the new Input System similiar like the old one, thats exactly what I wanted , If you could please give me one more tip how to change the keybindings at runtime (please as easy as possible, not everyone is a prodegy) I would be really happy because then I dont need to read and study the whole huge documentation of the new Input System (dont get me wrong docs are IMPORTANT!!!).
     
    lgmsantos likes this.
  23. SomeGuy22

    SomeGuy22

    Joined:
    Jun 3, 2011
    Posts:
    717
    Part of being a game developer/app writer is being able to do your own research; you don't need to go digging in the forums to find these answers, you can just check the documentation. It won't take as long as you might think.

    Every Action in your InputActionAsset is made up of Bindings. To get the bindings array, use myInputAction.bindings. Each InputBinding is a representation of the exact hardware controls that will trigger that action. You'll notice the InputBinding has a property called "overridePath". This can be used to override the default hardware actuator being used to influence the Action. All you have to do is get the binding you want, and set its overridePath to a String that represents your hardware input, i.e. "<Gamepad>/leftStick/x". Check out the format for Paths here.
     
  24. zh4r0naX

    zh4r0naX

    Joined:
    Oct 30, 2016
    Posts:
    71
    This here shows exactly what is broken on the hold interaction.

    Interactions Hold
    started on button down | performed after hold time | canceled when stopping game
    note: this seems broken can't get any more actions, it's like it never releases

    You can cancel the hold interaction if you dont perform it. But when you performed it you cant start or cancel it again.

    EDIT:
    For example i got a beam creating gun. It charges up, upon fully charging up it releases a laserbeam until the player releases the firebutton again. This works perfectly but just for one time.

    If i cancel the hold action before the beam is created, it works fine, after that it wont even charge up anymore.

    EDIT2:

    In February Rene-Damm confirmed that this should be fixed with 0.5 preview version, now we are on higher versions and that issue still exists for me the same way it did before.
     
    Last edited: Dec 5, 2020
  25. SomeGuy22

    SomeGuy22

    Joined:
    Jun 3, 2011
    Posts:
    717
    Please read the post I made on Oct 23, 2020 in this thread.
     
    zh4r0naX likes this.
  26. zh4r0naX

    zh4r0naX

    Joined:
    Oct 30, 2016
    Posts:
    71
    Thank you! This really helped. English isnt my native language and while programming is something i just learn by watching tutorials and reading some stuff up, it was hard to follow.

    Thank you for pointing me into the right direction!
     
    SomeGuy22 likes this.
  27. DaveTheCoder

    DaveTheCoder

    Joined:
    Feb 26, 2020
    Posts:
    10
    Thanks for this thread!

    After studying it and the manual, and experimenting for a few hours, I was able to make a button continuously move a player. :D

    One question: What should the binding path be for an onscreen button?

    Using something like "<Gamepad>/dpad/down" works, but does that make sense for an arbitrary onscreen button? Is there a better choice?
     
  28. DaveTheCoder

    DaveTheCoder

    Joined:
    Feb 26, 2020
    Posts:
    10
  29. GrayedFox

    GrayedFox

    Joined:
    Jan 28, 2014
    Posts:
    70
    Hey, wanted to share a really quite simple bit of code here which mirrors the functionality of knowing when a button is held or not. Interestingly, you don't use a Hold interaction to achieve this functionality (derp?).

    Hopefully it helps some others. One advantage of this method is you can still use the simpler SendMessage or BroadcastMessage control systems if you don't want the overhead of using Unity or native C# events (which I did not).

    1. Open your input settings and define a "Press" interaction for the required binding
    2. Set the behaviour to "Press and Release"

    press-and-release-snip.png

    3. Toggle a persistent boolean variable inside the matching callback method

    Code (CSharp):
    1. // somewhere inside your character/player/unit controller
    2. private bool ButtonHeld = false;
    3.  
    4. // triggered on button press and release to allow for continuous logic
    5. public void OnAttack()
    6. {
    7.     ButtonHeld = !ButtonHeld;
    8.     SomeOtherMethod(ButtonHeld);
    9. }
    10.  
    Now this won't help if you really do need the callback context but if all you want to do is perform some task based on whether the button is held down or not, the above code is really all you need.

    As for mirroring a "hold delay", that's also relatively trivial: just keep track of when ButtonHeld becomes true and put that logic inside a coroutine that has a while loop that yields at whatever interval you desire. Interrupt the coroutine when ButtonHeld becomes false, otherwise, once the desired amount of time has passed and ButtonHeld is still true, do your thing.

    You can mirror the "held for" property of the Hold interaction this way. From my testing the PressAndRelease consistently fires on both the press and release of a mouse click every time, so I'm happy to trust that and build my own Hold behaviour instead of getting lost inside callback contexts which themselves can and do expire!
     
    Last edited: Dec 16, 2020
    Karsten likes this.
  30. coolblue2000

    coolblue2000

    Joined:
    May 7, 2015
    Posts:
    24

    I think you are being totally blind to the issue here. Yes there are ways to do what people are asking. However it is inconsistent with other input systems and even inconsistent with the Unity Input System behaviour!

    What people are asking for and expect from a modern input system is for there to be a hold button down call. So I can get a callback (or use the triggered property) so tell if a button has been activated. I do however also expect there to be a callback (or property called something like "held") to easily tell if the button is being held down or not...

    Telling people they are not proper programmers or that they are asking for unreasonable things is not a good way to handle this. The work arounds are a starting point but what we expect from Unity is to listen and say something more like "Yes we understand this is not working as people would expect and we are working on putting things right".
     
  31. SomeGuy22

    SomeGuy22

    Joined:
    Jun 3, 2011
    Posts:
    717
    What exactly is inconsistent? The fact that you have to poll the status of a button being "held" instead of there being a callback? Because that's exactly how it was done in the old Input class. And for Input System, that's how it has always been, I don't see how it can be inconsistent with itself. Events are meant to fire when the Action changes, that is the core idea behind them.

    If you're talking about getting a single callback when the button has been fired, that's exactly what the InputSystem is built upon. You can use the "performed" event found here to get a function call when the button has been activated.

    If you're talking about getting a series of callback events while the button is being held, I'm not understanding what this really gets you aside from the Callback Context the Action provides. The example I provided took just a single line in Update and most certainly handles the vast majority of cases for a continuous function. If you do need the Callback Context, you could always just have it catch the context from a Pass Through "on value change" event and when the value is not changing, just re-fire the event with the stored context. That's where it requires a few more lines, but even then: you'd probably have a complex multi-character system anyways if you needed the Callback Context and I don't think it would save you much time or effort.

    If you read page 2 of this thread, you'd find there are multiple ways to do exactly that. One of them is InputAction.phase, which lets you check the current status of the action. The other is InputAction.ReadValue, which returns >0 when the button is being "held".

    I don't think anyone said that, nor do I think it's unreasonable to ask for continuous callback behavior. However, I don't believe this is nearly as important as some have made it out to be, the "workarounds" are not a hassle at all and really I think it's better to do it the way I described because of at least one key advantage which I'll get to below. The reason I don't believe this requires an "urgent fix" is because nothing we've been talking about is "broken" to begin with. "Putting things right" might be your view if you can't live without continuous callbacks, but considering you can get around that with a few lines of code at most I'm not sure if it's worth the effort to adjust.

    Examples

    If you find yourself thinking "but I have to move this spaceship only when my axis is >0! That means my function should continuously run when the axis is being held down!" Then it's better to change your approach instead of getting stuck on this limitation. Rather than run the "move spaceship" function via callback, just call it from Update() all the time. Then with your "performed" callback, you can set the "move spaceship value" that is later used within the "move spaceship function". One extra function and one extra variable to store the data provided by the callback--that's all it takes.

    If you find yourself thinking "but I have to move this spaceship only if the spacebar is held down!" Then the fix is even more simple--call the "move spaceship" function in Update() only if the Action's ReadValue is >.5, that will ensure the function is called only when the button is held down.

    In my opinion, the reason this is an advantage over having a "continuous callback" that can be assigned to the InputAction itself is that I believe the Input System processes events on a single user-defined frame time. See this thread for the details. There's also an internal polling frequency which I believe runs at 60Htz by default, see here. If in our spaceship example we needed to move the spaceship in FixedUpdate, say because it was a physics object, then we would need our "continuous callback" to fire it's events in FixedUpdate so we could move it using physics calls. But in other parts of our game we might want events to fire on the frame time of Update() instead. Yet we can't have both using this method! Even if we did try to process events on both Fixed and regular Update, we'd end up with unnecessary performance issues and for each callback we'd need to know what time we were called from so we can process it/ignore it, which just makes the whole system needlessly complex. Instead of that, we could just poll the state of our action from the thread of our choice, and act accordingly since we defined when that function is called. This way, we could have continuous functions that run in Update(), FixedUpdate() or even 5 times a second using Coroutines without needing the InputSystem to do any extra work that could slow down processing.

    Am I missing something, or is this not what you were talking about? I'm truly trying to understand why this isn't satisfactory and what the core of the issue really is.
     
  32. Karsten

    Karsten

    Joined:
    Apr 8, 2012
    Posts:
    183
    What I objectively see is text walls whenever someone tries to explain the new input system(not only in this forum), this is at least from my point of view a proof that the system could be easier to use and understand because then you would not need text walls to explain very basic things .I personally think the "there are multible ways to do xyz" design is the problem.Why multible ways that lead to the same result ?
    However in the meanwhile I managed to get up the very steep learning curve doing at least what I need for my project with the new Input System , it was quite hard and I didn't yet dare to see how to work with the "processing" stuff like "tap" "hold" and that stuff... somewhat I'm happy I dont need it at the moment to be honest.
     
    Dmitresso and Shin_Toasty like this.
  33. Leslie-Young

    Leslie-Young

    Joined:
    Dec 24, 2008
    Posts:
    1,143
    @Karsten haha, ye. But from the docs it seems like this whole "continues movement" thing can be as easy as just reading the value in Update. If it is a Zero vector then no movement. I used this and it works fine for my little game where I need to move an RTS-style camera.

    https://docs.unity3d.com/Packages/c.../api/UnityEngine.InputSystem.PlayerInput.html

    Code snippet from above docs...
    Code (CSharp):
    1. [RequireComponent(typeof(PlayerInput))]
    2. public class MyPlayerLogic : MonoBehaviour
    3. {
    4.     public GameObject projectilePrefab;
    5.  
    6.     private PlayerInput m_PlayerInput;
    7.     private InputAction m_LookAction;
    8.     private InputAction m_MoveAction;
    9.     private InputAction m_FireAction;
    10.  
    11.     public void OnUpdate()
    12.     {
    13.         if (m_PlayerInput == null)
    14.         {
    15.             m_PlayerInput = GetComponent<PlayerInput>();
    16.             m_FireAction = m_PlayerInput.actions["fire"];
    17.             m_LookAction = m_PlayerInput.actions["look"];
    18.             m_MoveAction = m_PlayerInput.actions["move"];
    19.         }
    20.  
    21.         if (m_FireAction.triggered)
    22.             /* firing logic... */;
    23.  
    24.         var move = m_MoveAction.ReadValue<Vector2>();
    25.         var look = m_LookAction.ReadValue<Vector2>();
    26.         /* Update transform from move&look... */
    27.     }
    28. }
     
  34. Shin_Toasty

    Shin_Toasty

    Joined:
    Jun 15, 2017
    Posts:
    46
    Like they say, text walls everywhere. The new system can do a lot more but punishes beginners mightily. It's not hell for a PC game but I gave up trying to get it to work with hold or deltas on Android.
     
  35. SomeGuy22

    SomeGuy22

    Joined:
    Jun 3, 2011
    Posts:
    717
    There are beginner tutorials for Input System in other places online. This thread is not the way to go if you're just starting out.

    Aside from that, if you're not going to take the effort to read then I don't see the point of trying new tech in the first place. If a few paragraphs are stopping you from progressing your game then you're better off using what you already know instead of complaining here. If you have a specific question about the Input System then feel free to ask. But if you truly want to understand what you're working with and overcome the limitations of the old Input class, reading the relevant parts of the documentation and what is discussed online is the way to go.

    Nobody is forcing you to use Input System or to scour the forums for solutions, but if you want answers then you need to have the patience to at least look at what people are saying. That is where the explanations will be.
     
  36. Javier-Cabrera

    Javier-Cabrera

    Joined:
    Sep 30, 2013
    Posts:
    15
    Are you out of your mind? What is the point of having something like this system if it is not easy to use? I'm about to create a post myself because I've been struggling with this... input thing for the past three days with almost nothing to show for but false starts!

    There is no coherent logic behind the new input system API. None!

    Yes, if I follow a tutorial, I can get something moving on screen--but that is no way to understand what's happening code-wise. It should be natural. Many newcomers will ran away scared from Unity when trying to get the most basic character movement done.

    The Editor part is very good and it works as expected. But the API... oh man. After three days, I don't know even what I'm doing anymore.

    The old system was logic, this one feels unnecessarily hard to get into for newcomers. It makes me want to switch to Unreal.

    If the reasoning behind releasing this was "ok, let's make it incredibly hard because 'not everything needs to be easy'," then, friend, well done.

    It is not easy.

    It is hard. Damn hard.
     
  37. Roboserg

    Roboserg

    Joined:
    Jun 3, 2018
    Posts:
    83
    You define the actions and use them with events, it's very easy. Watching these vids helped me a lot:



    Also, watch official Unity vids, they are great, videos at the bottom
    https://unity.com/features/input-system
     
    SomeGuy22 likes this.
  38. Aksoq

    Aksoq

    Joined:
    Nov 11, 2019
    Posts:
    5
    I used this way to implement continious button interaction to shoot projectile in 1.0.2 new input system. Everything else works pretty good with SendMessage() notifications.

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.InputSystem;
    3.  
    4. public class ControlsExample : MonoBehaviour
    5. {
    6.     //Controls is your generated C# Input Actions script
    7.     public Controls controls;
    8.  
    9.     void Awake()
    10.     {
    11.         controls = new Controls();
    12.     }
    13.  
    14.     void OnEnable()
    15.     {
    16.         controls.Enable();
    17.     }
    18.  
    19.     void OnDisable()
    20.     {
    21.         controls.Disable();
    22.     }
    23.  
    24.     void Update()
    25.     {
    26.         //Button input uses float so we can read it
    27.         //and if it's not 0, then button is held this frame
    28.         //Player is your default Map in Player Input
    29.         //Fire is the name of your action in Player Input
    30.         if (controls.Player.Fire.ReadValue<float>() != 0)
    31.         {
    32.             LaunchProjectile();
    33.         }
    34.     }
    35. }
    You can also do it without generated C# script (because it doesn't work with InteractiveRebinding in my experience)

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.InputSystem;
    3.  
    4. public class ControlsExample : MonoBehaviour
    5. {
    6.     //Controls is your generated C# Input Actions script
    7.     public PlayerInput playerInput;
    8.     public InputActionMap actionMap;
    9.  
    10.     void Awake()
    11.     {
    12.        playerInput = GetComponent<PlayerInput>();
    13.        actionMap = playerInput.actions.FindActionMap("Player");
    14.        fireAction = actionMap.FindAction("Fire");
    15.     }
    16.  
    17.     void OnEnable()
    18.     {
    19.         actionMap.Enable();
    20.     }
    21.  
    22.     void OnDisable()
    23.     {
    24.         actionMap.Disable();
    25.     }
    26.  
    27.     void Update()
    28.     {
    29.         if (fireAction.ReadValue<float>() != 0)
    30.         {
    31.             LaunchProjectile();
    32.         }
    33.     }
    34. }
     
    Last edited: Feb 24, 2021
  39. MrGreenish

    MrGreenish

    Joined:
    Oct 20, 2019
    Posts:
    34
    Thanks!

    By the way, this is the solution in case someone gets stuck.
     
    SomeGuy22 likes this.
  40. vaughncrimson

    vaughncrimson

    Joined:
    Nov 14, 2016
    Posts:
    8
    I understand that you can check for performed and cancelled to do repeated actions.
    But how do you achieve this in consideration to UI, specifically with UI/Submit action?

    Let's say I extended a Button to listen for UI/Submit to repeatedly invoke its OnClick event.
    And I created 3 Button using the extended version.
    Holding the UI/Submit action will cause all 3 buttons to repeat its OnClick event.

    Is there a way to isolate the repetition to the currently selected button only?
     
  41. SomeGuy22

    SomeGuy22

    Joined:
    Jun 3, 2011
    Posts:
    717
    Check out EventSystem.current.currentSelectedGameObject. It tells you exactly what the event system considers to be selected, so you could compare it to the object associated with your button extension and isolate certain behaviors that way. Alternatively, you could subscribe every extended button to the OnSelect callback by interfacing ISelectHandler and manually track which ones are selected. See the answers to this question for a few examples.
     
  42. MysterieCatGames

    MysterieCatGames

    Joined:
    Oct 8, 2012
    Posts:
    5
    So basically, as of 2021, despite SomeGuy22 preaching as hard as possible, if you want to use the New Input System to *easily* do a 'while held down' type function you're better off just going back to the old input system until New is the defacto standard. Then hope either someone writes a wrapper or the Unity team figures out what the words 'Hold' and 'Press' mean.
     
    illinar likes this.
  43. Lurking-Ninja

    Lurking-Ninja

    Joined:
    Jan 20, 2015
    Posts:
    9,009
    You're a grown-up developer. You do whatever you want. The rest of us use the new system happily.
     
  44. illinar

    illinar

    Joined:
    Apr 6, 2011
    Posts:
    856
    As a grown up developer, could you please explain how you justify the S***ty API, or how you could possibly argue that it's not S***ty?
     
  45. SomeGuy22

    SomeGuy22

    Joined:
    Jun 3, 2011
    Posts:
    717
    I really don't understand what the problem is, I believe several times in this thread it's been stated that there's multiple ways to do this. Whether or not you find it "easy" well, that would be beside the point of understanding how to use it. All I can really do is explain how it works, I don't have any control over what Unity develops. I'd also note that not everything in this industry is going to be "easy", that's just a part of gamedev and software dev in general. There's always going to be complex systems and frustrating ways that things work. That doesn't mean you can't ask for improvements, but you could at least try to learn before you start demanding changes. I personally don't think it's that hard to use.

    In case it was missed I'll reiterate again the ways to do this in the simplest examples possible:
    • Access the Input Action you want and poll the .ReadValue<float>() value from Update() and call whatever function you want every frame where it's not == 0. This value tells you whether or not the Action is being held down. I think someone did this just a few posts up.
    • Access the Input Action you want and poll the .phase value. It tells you whether or not the action is held down. You can do the same step of calling your own function if the phase value is pressed.
    • Make a custom bool that stores the "state" of the button. On the .performed delegate callback, you can simply set it to true and then run your function from Update() or wherever when it's true. This is only necessary if you insist on using the callbacks, but the old system never relied on that so it's an odd stipulation to have if you just care about getting the old behavior back.
    The first two bullet points here are quite literally 2 lines of code. I'm not sure how much easier it could really be.

    Again, I think I've stated a few times in this thread that a wrapper exists which emulates all the old behaviors. I made it back in 2019 and posted it publicly on the forums. You can find it here.

    "Press" and "Hold" are just interactions, intended to modify the response time of the Action for delays, etc. All they do is adjust what qualifies as a press, they do not change the behavior of how many times the .performed callback is run. If you have any questions on that feel free to ask.

    I'm pretty sure all of this stuff was mentioned before, so I'd advise you to read pages 1 and 2 of this thread if you want more explanations.
     
    Lurking-Ninja likes this.
  46. Korindian

    Korindian

    Joined:
    Jun 25, 2013
    Posts:
    584
  47. Voronoi

    Voronoi

    Joined:
    Jul 2, 2012
    Posts:
    539
    I have been trying to work with the new Input system and every time I get back into it I feel like I'm in a fog trying to understand it. I am trying to implement a Zoom function, and have already hooked up an Input Action Asset so that the scroll wheel zooms more or less how I want.

    My next task seems so simple, I just can't believe I can't get my head around it! Here is what I want to do:
    1. When a UI Button on screen is held down, zoom in.
    2. Stop zooming when the button is released.
    I want this to work for desktop and mobile, so I'm trying to just use pointer. How do I hook up a button to do this? I can easily use the Editor and the buttons' OnClick() function, but I see no way to set up the started/canceled actions for an onscreen keyboard.

    The documentation is not great, and example switch between and Action Map Asset thing and specific actions. It's very confusing. Here's my code so far;

    Code (CSharp):
    1.    private void Awake()
    2.     {
    3.         controls = new CustomInputActions();
    4.         controls.UI.ScrollWheel.performed += context => SmoothZoom(context);
    5.         controls.UI.Zoom.performed += context => Zoom(context);
    6.  
    7.     }
    8.  
    9.     private void OnEnable()
    10.     {
    11.         controls.Enable();
    12.  
    13.     }
    14.  
    15.     private void OnDisable()
    16.     {
    17.         controls.Disable();
    18.  
    19.     }
    20.  
    21. public void Zoom(InputAction.CallbackContext context)
    22.     {
    23.         Debug.Log(context.ToString());
    24.  
    25.     }
    26.  
    Here is the Input Actions:

    Screen Shot 2021-05-16 at 4.19.52 PM.png

    I get the Debug messages when my mouse is down, but of course that happens if the mouse is pressed anywhere on the screen. I get that I'll use the .started/.canceled events, but how do I get this only when pressing the onscreen button?

    I agree with a lot of the previous posts, this just seems ridiculously complicated to set up!
     
  48. SomeGuy22

    SomeGuy22

    Joined:
    Jun 3, 2011
    Posts:
    717
    You don't need to "simulate" an action press to make a UI button do something, you can just hook up OnClick to your Zoom() function or some other function of your choice and handle the results from code. i.e. if you have other code that actually moves/zooms the camera you can structure it inside it's own method and call upon that from both Zoom() and some button-specific zoom function like "ButtonZoom()" with the appropriate params.

    Be aware that UI buttons offer only onClick which I believe is only on release. If you want control over both "press" and "release", the easiest way is probably to attach a script to your button object with OnMouseDown() and OnMouseUp() callbacks which interact with your Zoom() code to start and stop the zoom behavior. These callbacks come from MonoBehavior and should work on UI elements.

    This is for learning/reference only and I don't really recommend this... but if you want to completely insist on using the action performed event only then you could do some approach where you detect if the mouse cursor is over the UI element, then you accept the mouse click zoom actions. You can do this with similar MonoBehavior "Messages" called OnMouseEnter() and OnMouseExit(). Again, just attach a script with these methods in it and toggle a bool on or off somewhere in your zoom controller which tells you whether you should proceed with the zoom actions.

    Well now you're kind of delving into Unity UI and the problem you're trying to solve is not solely related to Input System. But if you have further UI questions feel free to ask in the appropriate forum categories.
     
    Last edited: May 17, 2021
  49. Voronoi

    Voronoi

    Joined:
    Jul 2, 2012
    Posts:
    539
    This is correct, OnClick only happens on release. Thank you! You did jog my memory and now I recall I did this before, finding out that the new Input system does not support OnMouseDown and the new method. The new system uses IPointerDownHandler instead as explained in the OnScreen controls section.

    They really need to clean up the docs though, it used to be a relatively simple copy/paste operation for simple UI functions and Input controls. Now that the new inputs are de-coupled and spread across different assets it's quite confusing. I am sure it's better and more flexible in the long run, so I'm glad they are doing it, just wish the docs were better!
     
  50. SomeGuy22

    SomeGuy22

    Joined:
    Jun 3, 2011
    Posts:
    717
    My bad, I assumed that OnMouseDown would rely on the EventSystem which normally is compatible with Input System when you use the "UI Input Module" they provide but I guess in the docs it says it's not supported. So I suppose if you want something like this to rely only on Input System you will need to use On-Screen Button or implement IPointerDownHandler, or do something like what I'm doing in my project which is sending a raycast from mouse position to check against UI elements that get hit.

    I think you're right about the docs, should probably have more links to the Input System API and really anywhere related to Input in the main API. Clear explanations/warnings of what works and what doesn't would probably help a lot of people. Though its tough to make that call when Input System currently is just another module and there's tons of packages now, so they'd ideally want to do that for all the other modules as well. But it may be worthwhile here if they are encouraging everyone to use it.