using System.ComponentModel;
using UnityEngine.InputSystem.Controls;
using UnityEngine.Scripting;
#if UNITY_EDITOR
using UnityEditor;
using UnityEngine.InputSystem.Editor;
#endif
////TODO: protect against the control *hovering* around the press point; this should not fire the press repeatedly; probably need a zone around the press point
////TODO: also, for analog controls, we probably want a deadzone that gives just a tiny little buffer at the low end before the action starts
////REVIEW: shouldn't it use Canceled for release on PressAndRelease instead of triggering Performed again?
namespace UnityEngine.InputSystem.Interactions
{
///
/// Performs the action at specific points in a button press-and-release sequence according top .
///
///
/// By default, uses which performs the action as soon as the control crosses the
/// button press threshold defined by . The action then will not trigger again until the control
/// is first released.
///
/// Can be set to instead trigger on release (that is, when the control goes back below the button press threshold) using
/// or can be set to trigger on both press and release using ).
///
/// Note that using an explicit press interaction is only necessary if the goal is to either customize the press behavior
/// of a button or when binding to controls that are not buttons as such (the press interaction compares magnitudes to
/// and thus any type of control that can deliver a magnitude can act as a button). The default
/// behavior available out of the box when binding type actions to button-type controls
/// () corresponds to using a press modifier with
/// set to and left at default.
///
[DisplayName("Press")]
public class PressInteraction : IInputInteraction
{
///
/// Amount of actuation required before a control is considered pressed.
///
///
/// If zero (default), defaults to .
///
[Tooltip("The amount of actuation a control requires before being considered pressed. If not set, default to "
+ "'Default Press Point' in the global input settings.")]
public float pressPoint;
////REVIEW: this should really be named "pressBehavior"
///
/// Determines how button presses trigger the action.
///
///
/// By default (PressOnly), the action is performed on press.
/// With ReleaseOnly, the action is performed on release. With PressAndRelease, the action is
/// performed on press and on release.
///
[Tooltip("Determines how button presses trigger the action. By default (PressOnly), the action is performed on press. "
+ "With ReleaseOnly, the action is performed on release. With PressAndRelease, the action is performed on press and release.")]
public PressBehavior behavior;
private float pressPointOrDefault => pressPoint > 0 ? pressPoint : ButtonControl.s_GlobalDefaultButtonPressPoint;
private float releasePointOrDefault => pressPointOrDefault * ButtonControl.s_GlobalDefaultButtonReleaseThreshold;
private bool m_WaitingForRelease;
public void Process(ref InputInteractionContext context)
{
var actuation = context.ComputeMagnitude();
switch (behavior)
{
case PressBehavior.PressOnly:
if (m_WaitingForRelease)
{
if (actuation <= releasePointOrDefault)
{
m_WaitingForRelease = false;
if (Mathf.Approximately(0f, actuation))
context.Canceled();
else
context.Started();
}
}
else if (actuation >= pressPointOrDefault)
{
m_WaitingForRelease = true;
// Stay performed until release.
context.PerformedAndStayPerformed();
}
else if (actuation > 0 && !context.isStarted)
{
context.Started();
}
else if (Mathf.Approximately(0f, actuation) && context.isStarted)
{
context.Canceled();
}
break;
case PressBehavior.ReleaseOnly:
if (m_WaitingForRelease)
{
if (actuation <= releasePointOrDefault)
{
m_WaitingForRelease = false;
context.Performed();
context.Canceled();
}
}
else if (actuation >= pressPointOrDefault)
{
m_WaitingForRelease = true;
if (!context.isStarted)
context.Started();
}
else
{
var started = context.isStarted;
if (actuation > 0 && !started)
context.Started();
else if (Mathf.Approximately(0, actuation) && started)
context.Canceled();
}
break;
case PressBehavior.PressAndRelease:
if (m_WaitingForRelease)
{
if (actuation <= releasePointOrDefault)
{
m_WaitingForRelease = false;
context.Performed();
if (Mathf.Approximately(0, actuation))
context.Canceled();
}
}
else if (actuation >= pressPointOrDefault)
{
m_WaitingForRelease = true;
context.PerformedAndStayPerformed();
}
else
{
var started = context.isStarted;
if (actuation > 0 && !started)
context.Started();
else if (Mathf.Approximately(0, actuation) && started)
context.Canceled();
}
break;
}
}
public void Reset()
{
m_WaitingForRelease = false;
}
}
///
/// Determines how to trigger an action based on button presses.
///
///
public enum PressBehavior
{
///
/// Perform the action when the button is pressed.
///
///
/// Triggers when a control crosses the button press threshold.
///
// ReSharper disable once UnusedMember.Global
PressOnly = 0,
///
/// Perform the action when the button is released.
///
///
/// Triggers when a control crosses the button press threshold and
/// when the control goes back below the button press threshold.
///
// ReSharper disable once UnusedMember.Global
ReleaseOnly = 1,
///
/// Perform the action when the button is pressed and when the button is released.
///
///
/// Triggers when a control crosses the button press threshold
/// and triggers again when it goes back below the button press
/// threshold.
///
// ReSharper disable once UnusedMember.Global
PressAndRelease = 2,
}
#if UNITY_EDITOR
///
/// UI that is displayed when editing in the editor.
///
// ReSharper disable once UnusedMember.Global
internal class PressInteractionEditor : InputParameterEditor
{
protected override void OnEnable()
{
m_PressPointSetting.Initialize("Press Point",
"The amount of actuation a control requires before being considered pressed. If not set, default to "
+ "'Default Button Press Point' in the global input settings.",
"Default Button Press Point",
() => target.pressPoint, v => target.pressPoint = v,
() => InputSystem.settings.defaultButtonPressPoint);
}
public override void OnGUI()
{
EditorGUILayout.HelpBox(s_HelpBoxText);
target.behavior = (PressBehavior)EditorGUILayout.EnumPopup(s_PressBehaviorLabel, target.behavior);
m_PressPointSetting.OnGUI();
}
private CustomOrDefaultSetting m_PressPointSetting;
private static readonly GUIContent s_HelpBoxText = EditorGUIUtility.TrTextContent("Note that the 'Press' interaction is only "
+ "necessary when wanting to customize button press behavior. For default press behavior, simply set the action type to 'Button' "
+ "and use the action without interactions added to it.");
private static readonly GUIContent s_PressBehaviorLabel = EditorGUIUtility.TrTextContent("Trigger Behavior",
"Determines how button presses trigger the action. By default (PressOnly), the action is performed on press. "
+ "With ReleaseOnly, the action is performed on release. With PressAndRelease, the action is performed on press and "
+ "canceled on release.");
}
#endif
}