test
This commit is contained in:
@@ -0,0 +1,273 @@
|
||||
using System;
|
||||
using UnityEngine.InputSystem.Utilities;
|
||||
|
||||
////REVIEW: nuke this and force raw pointers on all code using events?
|
||||
|
||||
namespace UnityEngine.InputSystem.LowLevel
|
||||
{
|
||||
/// <summary>
|
||||
/// Pointer to an <see cref="InputEvent"/>. Makes it easier to work with InputEvents and hides
|
||||
/// the unsafe operations necessary to work with them.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Note that event pointers generally refer to event buffers that are continually reused. This means
|
||||
/// that event pointers should not be held on to. Instead, to hold onto event data, manually copy
|
||||
/// an event to a buffer.
|
||||
/// </remarks>
|
||||
public unsafe struct InputEventPtr : IEquatable<InputEventPtr>
|
||||
{
|
||||
// C# does not allow us to have pointers to structs that have managed data members. Since
|
||||
// this can't be guaranteed for generic type parameters, they can't be used with pointers.
|
||||
// This is why we cannot make InputEventPtr generic or have a generic method that returns
|
||||
// a pointer to a specific type of event.
|
||||
private readonly InputEvent* m_EventPtr;
|
||||
|
||||
/// <summary>
|
||||
/// Initialize the pointer to refer to the given event.
|
||||
/// </summary>
|
||||
/// <param name="eventPtr">Pointer to an event. Can be <c>null</c>.</param>
|
||||
public InputEventPtr(InputEvent* eventPtr)
|
||||
{
|
||||
m_EventPtr = eventPtr;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether the pointer is not <c>null</c>.
|
||||
/// </summary>
|
||||
/// <value>True if the struct refers to an event.</value>
|
||||
public bool valid => m_EventPtr != null;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the event is considered "handled" and should not be processed further.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is used in two ways. Setting it from inside <see cref="InputSystem.onEvent"/> will
|
||||
/// cause the event to not be processed further. If it is a <see cref="StateEvent"/> or
|
||||
/// <see cref="DeltaStateEvent"/>, the <see cref="InputDevice"/> targeted by the event will
|
||||
/// not receive the state change.
|
||||
///
|
||||
/// Setting this flag from inside a state change monitor (see <see cref="InputState.AddChangeMonitor(InputControl,IInputStateChangeMonitor,long,uint)"/>)
|
||||
/// will prevent other monitors on the same <see cref="IInputStateChangeMonitor"/> not receiving the state change.
|
||||
/// </remarks>
|
||||
/// <exception cref="InvalidOperationException">The event pointer instance is not <see cref="valid"/>.</exception>
|
||||
public bool handled
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!valid)
|
||||
return false;
|
||||
return m_EventPtr->handled;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (!valid)
|
||||
throw new InvalidOperationException("The InputEventPtr is not valid.");
|
||||
m_EventPtr->handled = value;
|
||||
}
|
||||
}
|
||||
|
||||
public int id
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!valid)
|
||||
return 0;
|
||||
return m_EventPtr->eventId;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (!valid)
|
||||
throw new InvalidOperationException("The InputEventPtr is not valid.");
|
||||
m_EventPtr->eventId = value;
|
||||
}
|
||||
}
|
||||
|
||||
public FourCC type
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!valid)
|
||||
return new FourCC();
|
||||
return m_EventPtr->type;
|
||||
}
|
||||
}
|
||||
|
||||
public uint sizeInBytes
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!valid)
|
||||
return 0;
|
||||
return m_EventPtr->sizeInBytes;
|
||||
}
|
||||
}
|
||||
|
||||
public int deviceId
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!valid)
|
||||
return InputDevice.InvalidDeviceId;
|
||||
return m_EventPtr->deviceId;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (!valid)
|
||||
throw new InvalidOperationException("The InputEventPtr is not valid.");
|
||||
m_EventPtr->deviceId = value;
|
||||
}
|
||||
}
|
||||
|
||||
public double time
|
||||
{
|
||||
get => valid ? m_EventPtr->time : 0.0;
|
||||
set
|
||||
{
|
||||
if (!valid)
|
||||
throw new InvalidOperationException("The InputEventPtr is not valid.");
|
||||
m_EventPtr->time = value;
|
||||
}
|
||||
}
|
||||
|
||||
internal double internalTime
|
||||
{
|
||||
get => valid ? m_EventPtr->internalTime : 0.0;
|
||||
set
|
||||
{
|
||||
if (!valid)
|
||||
throw new InvalidOperationException("The InputEventPtr is not valid.");
|
||||
m_EventPtr->internalTime = value;
|
||||
}
|
||||
}
|
||||
|
||||
public InputEvent* data => m_EventPtr;
|
||||
|
||||
// The stateFormat, stateSizeInBytes, and stateOffset properties are very
|
||||
// useful for debugging.
|
||||
|
||||
internal FourCC stateFormat
|
||||
{
|
||||
get
|
||||
{
|
||||
var eventType = type;
|
||||
if (eventType == StateEvent.Type)
|
||||
return StateEvent.FromUnchecked(this)->stateFormat;
|
||||
if (eventType == DeltaStateEvent.Type)
|
||||
return DeltaStateEvent.FromUnchecked(this)->stateFormat;
|
||||
throw new InvalidOperationException("Event must be a StateEvent or DeltaStateEvent but is " + this);
|
||||
}
|
||||
}
|
||||
|
||||
internal uint stateSizeInBytes
|
||||
{
|
||||
get
|
||||
{
|
||||
if (IsA<StateEvent>())
|
||||
return StateEvent.From(this)->stateSizeInBytes;
|
||||
if (IsA<DeltaStateEvent>())
|
||||
return DeltaStateEvent.From(this)->deltaStateSizeInBytes;
|
||||
throw new InvalidOperationException("Event must be a StateEvent or DeltaStateEvent but is " + this);
|
||||
}
|
||||
}
|
||||
|
||||
internal uint stateOffset
|
||||
{
|
||||
get
|
||||
{
|
||||
if (IsA<DeltaStateEvent>())
|
||||
return DeltaStateEvent.From(this)->stateOffset;
|
||||
throw new InvalidOperationException("Event must be a DeltaStateEvent but is " + this);
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsA<TOtherEvent>()
|
||||
where TOtherEvent : struct, IInputEventTypeInfo
|
||||
{
|
||||
if (m_EventPtr == null)
|
||||
return false;
|
||||
|
||||
// NOTE: Important to say `default` instead of `new TOtherEvent()` here. The latter will result in a call to
|
||||
// `Activator.CreateInstance` on Mono and thus allocate GC memory.
|
||||
TOtherEvent otherEvent = default;
|
||||
return m_EventPtr->type == otherEvent.typeStatic;
|
||||
}
|
||||
|
||||
// NOTE: It is your responsibility to know *if* there actually another event following this one in memory.
|
||||
public InputEventPtr Next()
|
||||
{
|
||||
if (!valid)
|
||||
return new InputEventPtr();
|
||||
|
||||
return new InputEventPtr(InputEvent.GetNextInMemory(m_EventPtr));
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
if (!valid)
|
||||
return "null";
|
||||
|
||||
// il2cpp has a bug which makes builds fail if this is written as 'return m_EventPtr->ToString()'.
|
||||
// Gives an error about "trying to constrain an invalid type".
|
||||
// Writing it as a two-step operation like here makes it build cleanly.
|
||||
var eventPtr = *m_EventPtr;
|
||||
return eventPtr.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the plain pointer wrapped around by the struct.
|
||||
/// </summary>
|
||||
/// <returns>A plain pointer. Can be <c>null</c>.</returns>
|
||||
public InputEvent* ToPointer()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
public bool Equals(InputEventPtr other)
|
||||
{
|
||||
return m_EventPtr == other.m_EventPtr || InputEvent.Equals(m_EventPtr, other.m_EventPtr);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (ReferenceEquals(null, obj))
|
||||
return false;
|
||||
return obj is InputEventPtr ptr && Equals(ptr);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return unchecked((int)(long)m_EventPtr);
|
||||
}
|
||||
|
||||
public static bool operator==(InputEventPtr left, InputEventPtr right)
|
||||
{
|
||||
return left.m_EventPtr == right.m_EventPtr;
|
||||
}
|
||||
|
||||
public static bool operator!=(InputEventPtr left, InputEventPtr right)
|
||||
{
|
||||
return left.m_EventPtr != right.m_EventPtr;
|
||||
}
|
||||
|
||||
public static implicit operator InputEventPtr(InputEvent* eventPtr)
|
||||
{
|
||||
return new InputEventPtr(eventPtr);
|
||||
}
|
||||
|
||||
public static InputEventPtr From(InputEvent* eventPtr)
|
||||
{
|
||||
return new InputEventPtr(eventPtr);
|
||||
}
|
||||
|
||||
public static implicit operator InputEvent*(InputEventPtr eventPtr)
|
||||
{
|
||||
return eventPtr.data;
|
||||
}
|
||||
|
||||
// Make annoying Microsoft code analyzer happy.
|
||||
public static InputEvent* FromInputEventPtr(InputEventPtr eventPtr)
|
||||
{
|
||||
return eventPtr.data;
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user