using UnityEngine.InputSystem.Utilities; using Unity.Collections.LowLevel.Unsafe; using UnityEngine.InputSystem.Layouts; using UnityEngine.InputSystem.LowLevel; using UnityEngine.Scripting; ////TODO: enforce memory layout of TouchControl to be that of TouchState (build that into the layout system? "freeze"/final layout?) namespace UnityEngine.InputSystem.Controls { /// /// A control representing a touch contact. /// /// /// Note that unlike most other control types, TouchControls do not have /// a flexible memory layout. They are hardwired to and /// will not work correctly with a different memory layouts. Additional fields may /// be appended to the struct but what's there in the struct has to be located /// at exactly those memory addresses. /// [InputControlLayout(stateType = typeof(TouchState))] public class TouchControl : InputControl { /// /// Button that indicates whether there is currently an ongoing touch /// contact on the control. When touch is ongoing, button will be 1, /// otherwise button will be 0. /// /// Control representing an ongoing touch contact. /// /// This control simply monitors and will read as 1 whenever /// the phase is , , /// or . /// /// public TouchPressControl press { get; set; } /// /// The ID of the touch contact as reported by the underlying system. /// /// Control reading out the ID of the touch. /// /// Each touch contact that is made with the screen receives its own unique ID which is /// normally assigned by the underlying platform. /// /// Note a platform may reuse touch IDs after their respective touches have finished. /// This means that the guarantee of uniqueness is only made with respect to currently /// ongoing touches. /// /// public IntegerControl touchId { get; set; } /// /// Absolute screen-space position on the touch surface. /// /// Control representing the screen-space of the touch. /// public Vector2Control position { get; set; } /// /// Screen-space motion delta of the touch. /// /// Control representing the screen-space motion delta of the touch. /// /// This is either supplied directly by the underlying platform or computed on the /// fly by from the last known position of the touch. /// /// Note that deltas have behaviors attached to them different from most other /// controls. See for details. /// /// public DeltaControl delta { get; set; } /// /// Normalized pressure of the touch against the touch surface. /// /// Control representing the pressure level of the touch. /// /// Not all touchscreens are pressure-sensitive. If unsupported, this control will remain /// at default value. /// /// In general, touch pressure is supported on mobile platforms only. /// /// Note that it is possible for the value to go above 1 even though it is considered normalized. The reason is /// that calibration on the system can put the maximum pressure point below the physically supported maximum value. /// /// /// public AxisControl pressure { get; set; } /// /// Screen-space radius of the touch. /// /// Control representing the horizontal and vertical extents of the touch contact. /// /// If supported by the device, this reports the size of the touch contact based on its /// center point. If not supported, this will be default(Vector2). /// /// public Vector2Control radius { get; set; } /// /// Current phase of the touch. /// /// Control representing the current phase of the touch. /// /// This will be if no touch has been registered on the control /// yet or if the control has been reset to its default state. /// /// public TouchPhaseControl phase { get; set; } /// /// Whether the touch comes from a source other than direct contact with the touch surface. /// /// Control indicating whether the touch was generated indirectly. /// /// Indirect touches can be generated with a stylus, for example. /// public ButtonControl indirectTouch { get; set; } /// /// Whether the touch has performed a tap. /// /// Control that indicates whether the touch has tapped the screen. /// /// A tap is defined as a touch that begins and ends within and /// stays within of its . If this /// is the case for a touch, this button is set to 1 at the time the touch goes to /// . /// /// The button resets to 0 only when another touch is started on the control or when the control /// is reset. /// /// /// public ButtonControl tap { get; set; } /// /// Number of times that the touch has been tapped in succession. /// /// Control that indicates how many taps have been performed one after the other. /// /// Successive taps have to come within for them /// to increase the tap count. I.e. if a new tap finishes within that time after /// of the previous touch, the tap count is increased by one. If more than /// passes after a tap with no successive tap, the tap count is reset to zero. /// public IntegerControl tapCount { get; set; } /// /// Time in seconds on the same timeline as Time.realTimeSinceStartup when the touch began. /// /// Control representing the start time of the touch. /// /// This is the value of when the touch starts with /// . /// /// public DoubleControl startTime { get; set; } /// /// Screen-space position where the touch started. /// /// Control representing the start position of the touch. /// public Vector2Control startPosition { get; set; } /// /// Whether a touch on the control is currently is progress. /// /// If true, a touch is in progress, i.e. has a of /// , , or . public bool isInProgress { get { switch (phase.ReadValue()) { case TouchPhase.Began: case TouchPhase.Moved: case TouchPhase.Stationary: return true; } return false; } } /// /// Default-initialize the touch control. /// /// /// Sets the to "TOUC". /// public TouchControl() { m_StateBlock.format = new FourCC('T', 'O', 'U', 'C'); } /// protected override void FinishSetup() { press = GetChildControl("press"); touchId = GetChildControl("touchId"); position = GetChildControl("position"); delta = GetChildControl("delta"); pressure = GetChildControl("pressure"); radius = GetChildControl("radius"); phase = GetChildControl("phase"); indirectTouch = GetChildControl("indirectTouch"); tap = GetChildControl("tap"); tapCount = GetChildControl("tapCount"); startTime = GetChildControl("startTime"); startPosition = GetChildControl("startPosition"); ////TODO: throw if state layouts of the controls doesn't match TouchState base.FinishSetup(); } /// public override unsafe TouchState ReadUnprocessedValueFromState(void* statePtr) { var valuePtr = (TouchState*)((byte*)statePtr + (int)m_StateBlock.byteOffset); return *valuePtr; } /// public override unsafe void WriteValueIntoState(TouchState value, void* statePtr) { var valuePtr = (TouchState*)((byte*)statePtr + (int)m_StateBlock.byteOffset); UnsafeUtility.MemCpy(valuePtr, UnsafeUtility.AddressOf(ref value), UnsafeUtility.SizeOf()); } } }