/* * @author Valentin Simonov / http://va.lent.in/ */ using System; using System.Collections.Generic; using TouchScript.Core; using TouchScript.Devices.Display; using TouchScript.Layers; using TouchScript.Pointers; using TouchScript.Utils.Attributes; using UnityEngine; using UnityEngine.Events; using Object = UnityEngine.Object; namespace TouchScript { /// /// A facade object to configure and hold parameters for an instance of . Contains constants used throughout the library. /// /// /// /// An instance of may be added to a Unity scene to hold (i.e. serialize them to the scene) parameters needed to configure an instance of used in application. Which can be accessed via static property. /// Though it's not required it is a convenient way to configure TouchScript for your scene. You can use different configuration options for different scenes. /// [AddComponentMenu("TouchScript/Touch Manager")] [HelpURL("http://touchscript.github.io/docs/html/T_TouchScript_TouchManager.htm")] public sealed class TouchManager : DebuggableMonoBehaviour { #region Constants #if TOUCHSCRIPT_DEBUG public const int DEBUG_GL_START = int.MinValue; public const int DEBUG_GL_TOUCH = DEBUG_GL_START; #endif /// /// Event implementation in Unity EventSystem for pointer events. /// [Serializable] public class PointerEvent : UnityEvent> {} /// /// Event implementation in Unity EventSystem for frame events. /// /// [Serializable] public class FrameEvent : UnityEvent {} /// /// Values of a bit-mask representing which Unity messages an instance of will dispatch. /// [Flags] public enum MessageType { /// /// Pointer frame started. /// FrameStarted = 1 << 0, /// /// Pointer frame finished. /// FrameFinished = 1 << 1, /// /// Some pointers were added during the frame. /// PointersAdded = 1 << 2, /// /// Some pointers were updated during the frame. /// PointersUpdated = 1 << 3, /// /// Some pointers have touched the surface during the frame. /// PointersPressed = 1 << 4, /// /// Some pointers were released during the frame. /// PointersReleased = 1 << 5, /// /// Some pointers were removed during the frame. /// PointersRemoved = 1 << 6, /// /// Some pointers were cancelled during the frame. /// PointersCancelled = 1 << 7 } /// /// Names of dispatched Unity messages. /// public enum MessageName { /// /// Pointer frame started. /// OnFrameStart = MessageType.FrameStarted, /// /// Pointer frame finished. /// OnFrameFinish = MessageType.FrameFinished, /// /// Some pointers were added during the frame. /// OnPointersAdd = MessageType.PointersAdded, /// /// Some pointers have updated during the frame. /// OnPointersUpdate = MessageType.PointersUpdated, /// /// Some pointers have touched the surface during the frame. /// OnPointersPress = MessageType.PointersPressed, /// /// Some pointers were released during the frame. /// OnPointersRelease = MessageType.PointersReleased, /// /// Some pointers were removed during the frame. /// OnPointersRemove = MessageType.PointersRemoved, /// /// Some pointers were cancelled during the frame. /// OnPointersCancel = MessageType.PointersCancelled } /// /// Centimeter to inch ratio to be used in DPI calculations. /// public const float CM_TO_INCH = 0.393700787f; /// /// Inch to centimeter ratio to be used in DPI calculations. /// public const float INCH_TO_CM = 1 / CM_TO_INCH; /// /// The value used to represent an unknown state of a screen position. Use to check if a point has unknown value. /// public static readonly Vector2 INVALID_POSITION = new Vector2(float.NaN, float.NaN); /// /// TouchScript version. /// public static readonly Version VERSION = new Version(9, 0); /// /// TouchScript version suffix. /// public static readonly string VERSION_SUFFIX = ""; #endregion #region Events /// /// Occurs when a new frame is started before all other events. /// public FrameEvent OnFrameStart = new FrameEvent(); /// /// Occurs when a frame is finished. After all other events. /// [SerializeField] public FrameEvent OnFrameFinish = new FrameEvent(); /// /// Occurs when new hovering pointers are added. /// [SerializeField] public PointerEvent OnPointersAdd = new PointerEvent(); /// /// Occurs when pointers are updated. /// [SerializeField] public PointerEvent OnPointersUpdate = new PointerEvent(); /// /// Occurs when pointers touch the surface. /// [SerializeField] public PointerEvent OnPointersPress = new PointerEvent(); /// /// Occurs when pointers are released. /// [SerializeField] public PointerEvent OnPointersRelease = new PointerEvent(); /// /// Occurs when pointers are removed from the system. /// [SerializeField] public PointerEvent OnPointersRemove = new PointerEvent(); /// /// Occurs when pointers are cancelled. /// [SerializeField] public PointerEvent OnPointersCancel = new PointerEvent(); #endregion #region Public properties /// /// Gets the instance of implementation used in the application. /// /// An instance of which is in charge of global pointer input control in the application. public static ITouchManager Instance { get { return TouchManagerInstance.Instance; } } /// /// Gets or sets current display device. /// /// Object which holds properties of current display device, like DPI and others. /// A shortcut for which is also serialized into scene. public IDisplayDevice DisplayDevice { get { if (Instance == null) return displayDevice as IDisplayDevice; return Instance.DisplayDevice; } set { if (Instance == null) { displayDevice = value as Object; return; } Instance.DisplayDevice = value; } } /// /// Indicates if TouchScript should create a CameraLayer for you if no layers present in a scene. /// /// true if a CameraLayer should be created on startup; otherwise, false. /// This is usually a desired behavior but sometimes you would want to turn this off if you are using TouchScript only to get pointer input from some device. public bool ShouldCreateCameraLayer { get { return shouldCreateCameraLayer; } set { shouldCreateCameraLayer = value; } } /// /// Gets or sets a value indicating whether a should be created in scene if no inputs present. /// /// true if StandardInput should be created; otherwise, false. /// This is usually a desired behavior but sometimes you would want to turn this off. public bool ShouldCreateStandardInput { get { return shouldCreateStandardInput; } set { shouldCreateStandardInput = value; } } /// /// Gets or sets a value indicating whether Unity messages are sent when dispatches events. /// /// true if Unity messages are used; otherwise, false. /// If Unity messages are used they are sent to an object set as a value of property or to TouchManager's GameObject if it's null. public bool UseSendMessage { get { return useSendMessage; } set { if (value == useSendMessage) return; useSendMessage = value; updateSendMessageSubscription(); } } /// /// Gets or sets the bit-mask which indicates which events from an instance of are sent as Unity messages. /// /// Bit-mask with corresponding bits for used events. public MessageType SendMessageEvents { get { return sendMessageEvents; } set { if (sendMessageEvents == value) return; sendMessageEvents = value; updateSendMessageSubscription(); } } /// /// Gets or sets the SendMessage target GameObject. /// /// Which GameObject to use to dispatch Unity messages. If null, TouchManager's GameObject is used. public GameObject SendMessageTarget { get { return sendMessageTarget; } set { sendMessageTarget = value; if (value == null) sendMessageTarget = gameObject; } } /// /// Gets or sets a value indicating whether Unity Events should be used. /// /// /// true if TouchManager should use Unity Events; otherwise, false. /// public bool UseUnityEvents { get { return useUnityEvents; } set { if (useUnityEvents == value) return; useUnityEvents = value; updateUnityEventsSubscription(); } } #if TOUCHSCRIPT_DEBUG /// public override bool DebugMode { get { return base.DebugMode; } set { base.DebugMode = value; if (Application.isPlaying) (Instance as TouchManagerInstance).DebugMode = value; } } #endif #endregion #region Public methods /// /// Determines whether a Vector2 represents an invalid position, i.e. if it is equal to . /// /// Screen position. /// true if position is invalid; otherwise, false. public static bool IsInvalidPosition(Vector2 position) { return position.x == INVALID_POSITION.x && position.y == INVALID_POSITION.y; } #endregion #region Private variables #pragma warning disable CS0414 [SerializeField] [HideInInspector] private bool basicEditor = true; #pragma warning restore CS0414 [SerializeField] private Object displayDevice; [SerializeField] [ToggleLeft] private bool shouldCreateCameraLayer = true; [SerializeField] [ToggleLeft] private bool shouldCreateStandardInput = true; [SerializeField] [ToggleLeft] private bool useSendMessage = false; [SerializeField] private MessageType sendMessageEvents = MessageType.PointersPressed | MessageType.PointersCancelled | MessageType.PointersReleased | MessageType.PointersUpdated | MessageType.PointersAdded | MessageType.PointersRemoved; [SerializeField] private GameObject sendMessageTarget; [SerializeField] private bool useUnityEvents = false; [SerializeField] private List layers = new List(); #endregion #region Unity private void Awake() { if (Instance == null) return; #if TOUCHSCRIPT_DEBUG if (DebugMode) (Instance as TouchManagerInstance).DebugMode = true; #endif Instance.DisplayDevice = displayDevice as IDisplayDevice; Instance.ShouldCreateCameraLayer = ShouldCreateCameraLayer; Instance.ShouldCreateStandardInput = ShouldCreateStandardInput; for (var i = 0; i < layers.Count; i++) { var layer = layers[i]; if (layer != null) LayerManager.Instance.AddLayer(layer, i); } } private void OnEnable() { updateSendMessageSubscription(); updateUnityEventsSubscription(); } private void OnDisable() { removeSendMessageSubscriptions(); removeUnityEventsSubscriptions(); } [ContextMenu("Basic Editor")] private void switchToBasicEditor() { basicEditor = true; } #endregion #region Private functions private void updateSendMessageSubscription() { if (!Application.isPlaying) return; if (Instance == null) return; if (sendMessageTarget == null) sendMessageTarget = gameObject; removeSendMessageSubscriptions(); if (!useSendMessage) return; if ((SendMessageEvents & MessageType.FrameStarted) != 0) Instance.FrameStarted += frameStartedSendMessageHandler; if ((SendMessageEvents & MessageType.FrameFinished) != 0) Instance.FrameFinished += frameFinishedSendMessageHandler; if ((SendMessageEvents & MessageType.PointersAdded) != 0) Instance.PointersAdded += pointersAddedSendMessageHandler; if ((SendMessageEvents & MessageType.PointersUpdated) != 0) Instance.PointersUpdated += pointersUpdatedSendMessageHandler; if ((SendMessageEvents & MessageType.PointersPressed) != 0) Instance.PointersPressed += pointersPressedSendMessageHandler; if ((SendMessageEvents & MessageType.PointersReleased) != 0) Instance.PointersReleased += pointersReleasedSendMessageHandler; if ((SendMessageEvents & MessageType.PointersRemoved) != 0) Instance.PointersRemoved += pointersRemovedSendMessageHandler; if ((SendMessageEvents & MessageType.PointersCancelled) != 0) Instance.PointersCancelled += pointersCancelledSendMessageHandler; } private void removeSendMessageSubscriptions() { if (!Application.isPlaying) return; if (Instance == null) return; Instance.FrameStarted -= frameStartedSendMessageHandler; Instance.FrameFinished -= frameFinishedSendMessageHandler; Instance.PointersAdded -= pointersAddedSendMessageHandler; Instance.PointersUpdated -= pointersUpdatedSendMessageHandler; Instance.PointersPressed -= pointersPressedSendMessageHandler; Instance.PointersReleased -= pointersReleasedSendMessageHandler; Instance.PointersRemoved -= pointersRemovedSendMessageHandler; Instance.PointersCancelled -= pointersCancelledSendMessageHandler; } private void pointersAddedSendMessageHandler(object sender, PointerEventArgs e) { sendMessageTarget.SendMessage(MessageName.OnPointersAdd.ToString(), e.Pointers, SendMessageOptions.DontRequireReceiver); } private void pointersUpdatedSendMessageHandler(object sender, PointerEventArgs e) { sendMessageTarget.SendMessage(MessageName.OnPointersUpdate.ToString(), e.Pointers, SendMessageOptions.DontRequireReceiver); } private void pointersPressedSendMessageHandler(object sender, PointerEventArgs e) { sendMessageTarget.SendMessage(MessageName.OnPointersPress.ToString(), e.Pointers, SendMessageOptions.DontRequireReceiver); } private void pointersReleasedSendMessageHandler(object sender, PointerEventArgs e) { sendMessageTarget.SendMessage(MessageName.OnPointersRelease.ToString(), e.Pointers, SendMessageOptions.DontRequireReceiver); } private void pointersRemovedSendMessageHandler(object sender, PointerEventArgs e) { sendMessageTarget.SendMessage(MessageName.OnPointersRemove.ToString(), e.Pointers, SendMessageOptions.DontRequireReceiver); } private void pointersCancelledSendMessageHandler(object sender, PointerEventArgs e) { sendMessageTarget.SendMessage(MessageName.OnPointersCancel.ToString(), e.Pointers, SendMessageOptions.DontRequireReceiver); } private void frameStartedSendMessageHandler(object sender, EventArgs e) { sendMessageTarget.SendMessage(MessageName.OnFrameStart.ToString(), SendMessageOptions.DontRequireReceiver); } private void frameFinishedSendMessageHandler(object sender, EventArgs e) { sendMessageTarget.SendMessage(MessageName.OnFrameFinish.ToString(), SendMessageOptions.DontRequireReceiver); } private void updateUnityEventsSubscription() { if (!Application.isPlaying) return; if (Instance == null) return; removeUnityEventsSubscriptions(); if (!useUnityEvents) return; Instance.FrameStarted += frameStartedUnityEventsHandler; Instance.FrameFinished += frameFinishedUnityEventsHandler; Instance.PointersAdded += pointersAddedUnityEventsHandler; Instance.PointersUpdated += pointersUpdatedUnityEventsHandler; Instance.PointersPressed += pointersPressedUnityEventsHandler; Instance.PointersReleased += pointersReleasedUnityEventsHandler; Instance.PointersRemoved += pointersRemovedUnityEventsHandler; Instance.PointersCancelled += pointersCancelledUnityEventsHandler; } private void removeUnityEventsSubscriptions() { if (!Application.isPlaying) return; if (Instance == null) return; Instance.FrameStarted -= frameStartedUnityEventsHandler; Instance.FrameFinished -= frameFinishedUnityEventsHandler; Instance.PointersAdded -= pointersAddedUnityEventsHandler; Instance.PointersUpdated -= pointersUpdatedUnityEventsHandler; Instance.PointersPressed -= pointersPressedUnityEventsHandler; Instance.PointersReleased -= pointersReleasedUnityEventsHandler; Instance.PointersRemoved -= pointersRemovedUnityEventsHandler; Instance.PointersCancelled -= pointersCancelledUnityEventsHandler; } private void pointersAddedUnityEventsHandler(object sender, PointerEventArgs e) { OnPointersAdd.Invoke(e.Pointers); } private void pointersUpdatedUnityEventsHandler(object sender, PointerEventArgs e) { OnPointersUpdate.Invoke(e.Pointers); } private void pointersPressedUnityEventsHandler(object sender, PointerEventArgs e) { OnPointersPress.Invoke(e.Pointers); } private void pointersReleasedUnityEventsHandler(object sender, PointerEventArgs e) { OnPointersRelease.Invoke(e.Pointers); } private void pointersRemovedUnityEventsHandler(object sender, PointerEventArgs e) { OnPointersRemove.Invoke(e.Pointers); } private void pointersCancelledUnityEventsHandler(object sender, PointerEventArgs e) { OnPointersCancel.Invoke(e.Pointers); } private void frameStartedUnityEventsHandler(object sender, EventArgs e) { OnFrameStart.Invoke(); } private void frameFinishedUnityEventsHandler(object sender, EventArgs e) { OnFrameFinish.Invoke(); } #endregion } }