using System;
using UnityEngine.InputSystem.LowLevel;
////REVIEW: should timer expiration be a separate method on IInputInteraction?
namespace UnityEngine.InputSystem
{
///
/// Information passed to interactions
/// when their associated controls trigger.
///
///
public struct InputInteractionContext
{
///
/// The action associated with the binding.
///
///
/// If the binding is not associated with an action, this is null.
///
///
public InputAction action => m_State.GetActionOrNull(ref m_TriggerState);
///
/// The bound control that changed its state to trigger the binding associated
/// with the interaction.
///
///
/// In case the binding associated with the interaction is a composite, this is
/// one of the controls that are part of the composite.
///
///
public InputControl control => m_State.GetControl(ref m_TriggerState);
public InputActionPhase phase => m_TriggerState.phase;
///
/// Time stamp of the input event that caused to trigger a change in the
/// state of .
///
///
public double time => m_TriggerState.time;
public double startTime => m_TriggerState.startTime;
public bool timerHasExpired
{
get => (m_Flags & Flags.TimerHasExpired) != 0;
internal set
{
if (value)
m_Flags |= Flags.TimerHasExpired;
else
m_Flags &= ~Flags.TimerHasExpired;
}
}
///
/// True if the interaction is waiting for input
///
///
/// By default, an interaction will return this this phase after every time it has been performed
/// (). This can be changed by using
/// or .
///
///
public bool isWaiting => phase == InputActionPhase.Waiting;
///
/// True if the interaction has been started.
///
///
///
public bool isStarted => phase == InputActionPhase.Started;
///
/// Return true if the control that triggered the interaction has been actuated beyond the given threshold.
///
/// Threshold that must be reached for the control to be considered actuated. If this is zero,
/// the threshold must be exceeded. If it is any positive value, the value must be at least matched.
/// True if the trigger control is actuated.
///
public bool ControlIsActuated(float threshold = 0)
{
return m_State.IsActuated(ref m_TriggerState, threshold);
}
///
/// Mark the interaction has having begun.
///
///
/// Note that this affects the current interaction only. There may be multiple interactions on a binding
/// and arbitrary many interactions may concurrently be in started state. However, only one interaction
/// (usually the one that starts first) is allowed to drive the action's state as a whole. If an interaction
/// that is currently driving an action is canceled, however, the next interaction in the list that has
/// been started will take over and continue driving the action.
///
///
///
/// public class MyInteraction : IInputInteraction<float>
/// {
/// public void Process(ref IInputInteractionContext context)
/// {
/// if (context.isWaiting && context.ControlIsActuated())
/// {
/// // We've waited for input and got it. Start the interaction.
/// context.Started();
/// }
/// else if (context.isStarted && !context.ControlIsActuated())
/// {
/// // Interaction has been completed.
/// context.Performed();
/// }
/// }
///
/// public void Reset()
/// {
/// // No reset code needed. We're not keeping any state locally in the interaction.
/// }
/// }
///
///
///
public void Started()
{
m_TriggerState.startTime = time;
m_State.ChangePhaseOfInteraction(InputActionPhase.Started, ref m_TriggerState);
}
public void Performed()
{
if (m_TriggerState.phase == InputActionPhase.Waiting)
m_TriggerState.startTime = time;
m_State.ChangePhaseOfInteraction(InputActionPhase.Performed, ref m_TriggerState);
}
public void PerformedAndStayStarted()
{
if (m_TriggerState.phase == InputActionPhase.Waiting)
m_TriggerState.startTime = time;
m_State.ChangePhaseOfInteraction(InputActionPhase.Performed, ref m_TriggerState,
phaseAfterPerformed: InputActionPhase.Started);
}
public void PerformedAndStayPerformed()
{
if (m_TriggerState.phase == InputActionPhase.Waiting)
m_TriggerState.startTime = time;
m_State.ChangePhaseOfInteraction(InputActionPhase.Performed, ref m_TriggerState,
phaseAfterPerformed: InputActionPhase.Performed);
}
public void Canceled()
{
if (m_TriggerState.phase != InputActionPhase.Canceled)
m_State.ChangePhaseOfInteraction(InputActionPhase.Canceled, ref m_TriggerState);
}
public void Waiting()
{
if (m_TriggerState.phase != InputActionPhase.Waiting)
m_State.ChangePhaseOfInteraction(InputActionPhase.Waiting, ref m_TriggerState);
}
public void SetTimeout(float seconds)
{
m_State.StartTimeout(seconds, ref m_TriggerState);
}
public TValue ReadValue()
where TValue : struct
{
return m_State.ReadValue(m_TriggerState.bindingIndex, m_TriggerState.controlIndex);
}
internal InputActionState m_State;
internal Flags m_Flags;
internal InputActionState.TriggerState m_TriggerState;
internal int mapIndex => m_TriggerState.mapIndex;
internal int controlIndex => m_TriggerState.controlIndex;
internal int bindingIndex => m_TriggerState.bindingIndex;
internal int interactionIndex => m_TriggerState.interactionIndex;
[Flags]
internal enum Flags
{
TimerHasExpired = 1 << 1
}
}
}