Basically I want to know how do you check to see if a button is being held down durring a frame. Instead of just being pressed. I’m not sure how to check for this.
I have figured out how to do what I needed done. I didn’t realize you could have to actions binded to the same button. So all I had to do was add a binding for pressing a button and another for releasing the same button.
There’s some other ways you can go about it.
If all you’re interested in is getting one call on press and one on release, hook into started and cancelled.
myAction.started += /* button was pressed */;
myAction.cancelled += /* button was released */;
If you want to continuously be notified for as long as the button is held, check the “Continuous” box on the action and use performed and cancelled.
myAction.performed += /* button was pressed or is held */;
myAction.cancelled += /* button was released */;
Came across this thread, and this solution doesn’t work for me. GetButtonDown would be true if it had been pressed in that frame, and false otherwise, and there’s no simple and clean way to do this in the new system. this would work however if Started and cancelled got called when using the ‘Press’ interaction, but they don’t for some reason.
Performed no longer gets called when you release either so you can’t use the ctx.ReadValue<float>()
anymore either.
Either I am doing something wrong here or this needs to be fixed.
Using “Press” and setting it to “Press and Release”, you should see “performed” when the button is pressed and “cancelled” when the button is released. In most cases, though, the explicit “Press” interaction shouldn’t be necessary. It gives control over press points and such but even without any interaction on a binding to a button, you should “performed” getting called when the button is pressed and “cancelled” when the button is released. At least that’s the expected behavior. If that doesn’t happen, there’s probably a bug.
Hi,
I try to check the phase but in both cases (press/release) it returns “Performed”.
Then in debug mode I saw that the Button Control has the members “wasPressedThisFrame” and “wasReleasedThisFrame”, but I have another issue which is that when:
-
“Continuous” is unchecked, the event is not send when holding so the flag “wasPressedThisFrame” is not updated
-
“Continuous” is checked, the behaviour is … the same, events are only raised on press and release action. Is there a point I missed on continuous feature? Do I need to add another interaction? Hold?
My action config:
- 'Continuous" checked/unchecked according to the test case
- Interaction: Press - Press and Release
I could update the flag “manually” after a Time.deltaTime delay but it seems not the most efficient way to achieve it.
Thanks for your help
Hi, I just wanted to jump in on this thread as well with a note that Press and Release is 100% always giving “performed” for both events, making it quite difficult to differentiate between the two events. Looking at the code in Github seems to confirm this behavior:
case PressBehavior.PressAndRelease:
if (m_WaitingForRelease)
{
if (!isActuated)
context.PerformedAndGoBackToWaiting();
// No support for continuous mode.
m_WaitingForRelease = isActuated;
}
else if (isActuated)
{
context.PerformedAndGoBackToWaiting();
// No support for continuous mode.
m_WaitingForRelease = true;
}
break;
I’ve also noticed that quick taps seem to give only the press “performed” without the release “performed”. Is that intentional, and if so, is there a correct way to resolve it?
I also can’t find a way to trigger a button release. Tried every solution mentionned here.
EDIT: Finally figured it out. The release is also triggered in .performed, NOT .canceled.
I’m currently trying to integrate the new input system in my project and I also ran into the problem how to implement Input.GetButtonDown() and Input.GetButtonUp() in the new input system.
I’m able to detect button down/up only, when I subscribe to the started/performed and canceled events of an action. In this case, when I press the button associated to the action, it triggers the following events:
started (frame:678)
performed (frame:678)
canceled (frame:684)
“started” and “performed” happen during the same frame. “started” corresponds to “GetButtonDown” and “canceled” to “GetButtonUp” I would say. That’s what I expected.
However, I would like to poll the state, rather than subscribing to different events. So I was just dumping the phase of an action to see how it changes as I press and release a button (left ctrl key):
var fire = m_Controls.Player.Fire;
Debug.LogFormat("phase: {0}, triggered: {1}, value: {2}", fire.phase, fire.triggered, fire.ReadValue<float>());
But phase never contains performed and canceled. The test outputs:
phase: Waiting, triggered: False, value: 0 (frame:74)
phase: Started, triggered: True, value: 1 (frame:75)
phase: Started, triggered: False, value: 1 (frame:76) // many of these
...
phase: Started, triggered: False, value: 1 (frame:93)
phase: Waiting, triggered: False, value: 0 (frame:94)
So how can I poll an action whether it has been “canceled” to emulate Input.GetButtonUp()? With the current phases, it seems I can only emulate GetButtonDown().
Test code
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
public class GetButtonDownTest : MonoBehaviour
{
MyInputControls m_Controls;
void Awake()
{
m_Controls = new MyInputControls();
m_Controls.Enable();
//m_Controls.Player.Fire.started += Fire_started;
//m_Controls.Player.Fire.performed += Fire_performed;
//m_Controls.Player.Fire.canceled += Fire_canceled;
}
void Fire_canceled(InputAction.CallbackContext obj)
{
Debug.LogFormat("canceled (frame:{0})", Time.frameCount);
}
void Fire_performed(InputAction.CallbackContext obj)
{
Debug.LogFormat("performed (frame:{0})", Time.frameCount);
}
void Fire_started(InputAction.CallbackContext obj)
{
Debug.LogFormat("started (frame:{0})", Time.frameCount);
}
void Update()
{
var fire = m_Controls.Player.Fire;
Debug.LogFormat("phase: {0}, triggered: {1}, value: {2} (frame:{3})", fire.phase, fire.triggered, fire.ReadValue<float>(), Time.frameCount);
}
}
I’m using the preview-1.0.0 package and Unity 2019.3.0b4.
@Peter77 Polling an action like that will indeed not observe performed or canceled. The reason is that these simply happen instantaneously and the action then immediately goes back to waiting. I.e. event comes in, action performs, calls its callback, then goes back to waiting. All this happens in the input update and by the time the Update/FixedUpdate code runs, it’s history.
There is no equivalent for polling for an action a la GetButtonUp. GetButtonDown corresponds to InputAction.triggered.
To observe both press and release requires using callbacks.
private void bool m_Pressed;
private void bool m_Released;
protected void OnEnable()
{
m_Controls.Player.Fire.performed += ctx => m_Pressed = true;
m_Controls.Player.Fire.canceled += ctx => m_Released = true;
}
protected void Update()
{
if (m_Pressed)
/* button down */;
if (m_Released)
/* button released */;
m_Pressed = false;
m_Released = false;
}
Thanks for the reply.
Is there a way to attach some sort of “Component” to an Action?
My preferred way to implement these callbacks would be to put the code in a Component and expose hold, pressed, released properties. So I have this code in a single place only. The game code would then get that “action component” to read the state, rather than having to implement the same “subscribe to callback, capture state in three fields, etc” over and over again across the code base?
I’ve looked at Interactions and Processors if I could abuse them for my purpose, but I can’t see how I would iterate over the Interactions or Processors list. Action.interactions just returns a string, rather than a collection of Interactions.
Not 100% sure what you’re looking for but could be that the interface generated as part of the C# class is coming close. E.g. if you have a MyGameActions.inputactions file and have “Generate C# Class” on, there’s an interface generated as part of it which you can implement on components.
public class MyComponent : IMyGameActions
{
public void OnFire(InputAction.CallbackContext context)
{
if (context.performed)
/* pressed */;
else if (context.canceled)
/* released */;
}
}
The generated SetCallbacks method can be used to automatically hook in the callbacks from an implementation of the interface.
I was looking for a way to attach custom data and logic to an InputAction. Like attaching a custom Processor to an InputAction.
My hope was I could implement the callback handling in a single place only, something like a “MonoBehaviour” for InputAction’s, which I could then attach to an InputAction through the Input Editor, like it’s possible with Processors and Interactions.
I’ll find another way to avoid having to write the same callback handling code for a gazillion InputAction’s.
Thanks again for the help.
You can alternatively listen to InputActionMap.actionTriggered or even InputSystem.onActionChange. These route callbacks from several actions into one funnel.
Yep, these make the code a little less verbose. Thanks!
Here is what I came up with. I’m surprised how much code is involved for something that seemed to simple initially. Is this how you imagine the system should be used if GetButton/Down/Up-like methods are needed?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
public class GetButtonDownTest : MonoBehaviour
{
MyInputControls m_Controls;
List<ActionState> m_States = new List<ActionState>();
class ActionState
{
public InputAction action;
public int downFrame;
public bool hold;
public int upFrame;
public InputAction.CallbackContext context;
public bool down
{
get
{
return downFrame == Time.frameCount;
}
}
public bool up
{
get
{
return upFrame == Time.frameCount;
}
}
}
void Awake()
{
m_Controls = new MyInputControls();
m_Controls.Enable();
}
void OnEnable()
{
m_Controls.Player.Get().actionTriggered += OnActionTriggered;
}
void OnDisable()
{
m_Controls.Player.Get().actionTriggered -= OnActionTriggered;
}
void Update()
{
var fire = m_Controls.Player.Fire;
if (GetButtonDown(fire))
Debug.LogFormat("down (frame:{0})", Time.frameCount);
if (GetButtonUp(fire))
Debug.LogFormat("up (frame:{0})", Time.frameCount);
//Debug.LogFormat("hold: {0}, down: {1}, up: {2} (frame:{3})",
// GetButton(fire),
// GetButtonDown(fire),
// GetButtonUp(fire),
// Time.frameCount);
}
ActionState FindOrCreateState(InputAction action)
{
for (var n = 0; n < m_States.Count; ++n)
{
if (m_States[n].action == action)
return m_States[n];
}
var entry = new ActionState();
entry.action = action;
m_States.Add(entry);
return entry;
}
void OnActionTriggered(InputAction.CallbackContext obj)
{
var state = FindOrCreateState(obj.action);
state.context = obj;
if (obj.started)
{
state.hold = true;
state.downFrame = obj.duration == 0.0f ? Time.frameCount : -1;
}
if (obj.canceled)
{
state.hold = false;
state.upFrame = Time.frameCount;
}
}
bool GetButton(InputAction action)
{
if (action == null)
return false;
var state = FindOrCreateState(action);
return state.hold;
}
bool GetButtonDown(InputAction action)
{
if (action == null)
return false;
var state = FindOrCreateState(action);
return state.down;
}
bool GetButtonUp(InputAction action)
{
if (action == null)
return false;
var state = FindOrCreateState(action);
return state.up;
}
}
Sadly context.performed isn’t called continuously here. How can I use the generated interface and have a “OnLeftMouseButtonHeld” or “GetMouseButton(0)” functionality.
Use the Press and Release interaction, set a flag to true when you get press, then false on release, and use it accordingly
Hey, probably a lot of you wonder how to do bind press and release LMB with the new Unity Input System, and well none of sugestions here seems to work…
I recommend to read this article first: Interactions | Input System | 1.0.2
There you’ll find how interactions on buttons work, and what values you get from specific input types ‘ReadValues<>()’
First of all - performed and canceled works only with “Hold” interaction - canceled is called if we press, hold and release the button before the “Press Point” value (in secounds). If we releas the button after that time, “canceled” won’t trigger any action.
The best way is to choose “Press” Interaction and choose “Press and Release” Trigger Behavior:
Then, when we press and release, the “performed” function is called for each of the actions (for press and for release), and we also get the float value from the context, if we bind the button to it.
So:
private Controls controls = null;
private bool LMB;
private void Awake() {
controls.Player.Interact.performed += ctx => ClickAction(ctx.ReadValue<float>());
}
private void OnEnable() => controls.Player.Enable();
private void OnDisable() => controls.Player.Disable();
void ClickAction(float b) {
if(b > 0)
LMB = true;
else
LMB = false;
}
you can also convert float to bool, becausein every programming language 0 = false and any other number = true:
void ClickAction(float b) {
LMB = System.Convert.ToBoolean(b);
}
or not even retrive the float value, because “performed” calls the action when you click and another time when you release, so in the function you just need to invert the LMB boolion, like this:
private bool LMB = false;
private void Awake() {
controls.Player.Interact.performed += ctx => ClickAction();
}
void ClickAction() {
LMB = !LMB;
}
Hi,
I can’t find this continous checkbox that you where talking about. I want an event to trigger every frame a specific button is held down.
It would be verry nice if you could explain where to find it
Continuous was removed in 0.9.0, I think.
Check here for some discussion and alternatives: