using System;
using System.Diagnostics;
using UnityEngine.InputSystem.LowLevel;
#if UNITY_EDITOR
using UnityEditor;
#endif
////REVIEW: this *really* should be renamed to TouchPolling or something like that
////REVIEW: Should this auto-enable itself when the API is used? Problem with this is that it means the first touch inputs will get missed
//// as by the time the API is polled, we're already into the first frame.
////TODO: gesture support
////TODO: high-frequency touch support
////REVIEW: have TouchTap, TouchSwipe, etc. wrapper MonoBehaviours like LeanTouch?
////TODO: as soon as we can break the API, remove the EnhancedTouchSupport class altogether and rename UnityEngine.InputSystem.EnhancedTouch to TouchPolling
////FIXME: does not survive domain reloads
namespace UnityEngine.InputSystem.EnhancedTouch
{
///
/// API to control enhanced touch facilities like that are not
/// enabled by default.
///
///
/// Enhanced touch support provides automatic finger tracking and touch history recording.
/// It is an API designed for polling, i.e. for querying touch state directly in methods
/// such as MonoBehaviour.Update. Enhanced touch support cannot be used in combination
/// with s though both can be used side-by-side.
///
///
///
/// public class MyBehavior : MonoBehaviour
/// {
/// protected void OnEnable()
/// {
/// EnhancedTouchSupport.Enable();
/// }
///
/// protected void OnDisable()
/// {
/// EnhancedTouchSupport.Disable();
/// }
///
/// protected void Update()
/// {
/// var activeTouches = Touch.activeTouches;
/// for (var i = 0; i < activeTouches.Count; ++i)
/// Debug.Log("Active touch: " + activeTouches[i]);
/// }
/// }
///
///
///
///
///
public static class EnhancedTouchSupport
{
///
/// Whether enhanced touch support is currently enabled.
///
/// True if EnhancedTouch support has been enabled.
public static bool enabled => s_Enabled > 0;
private static int s_Enabled;
private static InputSettings.UpdateMode s_UpdateMode;
///
/// Enable enhanced touch support.
///
///
/// Calling this method is necessary to enable the functionality provided
/// by and . These APIs add extra
/// processing to touches and are thus disabled by default.
///
/// Calls to Enable and balance each other out.
/// If Enable is called repeatedly, it will take as many calls to
/// to disable the system again.
///
public static void Enable()
{
++s_Enabled;
if (s_Enabled > 1)
return;
InputSystem.onDeviceChange += OnDeviceChange;
InputSystem.onBeforeUpdate += Touch.BeginUpdate;
InputSystem.onSettingsChange += OnSettingsChange;
#if UNITY_EDITOR
AssemblyReloadEvents.beforeAssemblyReload += OnBeforeDomainReload;
#endif
SetUpState();
}
///
/// Disable enhanced touch support.
///
///
/// This method only undoes a single call to .
///
public static void Disable()
{
if (!enabled)
return;
--s_Enabled;
if (s_Enabled > 0)
return;
InputSystem.onDeviceChange -= OnDeviceChange;
InputSystem.onBeforeUpdate -= Touch.BeginUpdate;
InputSystem.onSettingsChange -= OnSettingsChange;
#if UNITY_EDITOR
AssemblyReloadEvents.beforeAssemblyReload -= OnBeforeDomainReload;
#endif
TearDownState();
}
internal static void Reset()
{
Touch.s_GlobalState.touchscreens = default;
Touch.s_GlobalState.playerState.Destroy();
Touch.s_GlobalState.playerState = default;
#if UNITY_EDITOR
Touch.s_GlobalState.editorState.Destroy();
Touch.s_GlobalState.editorState = default;
#endif
s_Enabled = 0;
}
private static void SetUpState()
{
Touch.s_GlobalState.playerState.updateMask = InputUpdateType.Dynamic | InputUpdateType.Manual | InputUpdateType.Fixed;
#if UNITY_EDITOR
Touch.s_GlobalState.editorState.updateMask = InputUpdateType.Editor;
#endif
s_UpdateMode = InputSystem.settings.updateMode;
foreach (var device in InputSystem.devices)
OnDeviceChange(device, InputDeviceChange.Added);
}
internal static void TearDownState()
{
foreach (var device in InputSystem.devices)
OnDeviceChange(device, InputDeviceChange.Removed);
Touch.s_GlobalState.playerState.Destroy();
#if UNITY_EDITOR
Touch.s_GlobalState.editorState.Destroy();
#endif
Touch.s_GlobalState.playerState = default;
#if UNITY_EDITOR
Touch.s_GlobalState.editorState = default;
#endif
}
private static void OnDeviceChange(InputDevice device, InputDeviceChange change)
{
switch (change)
{
case InputDeviceChange.Added:
{
if (device is Touchscreen touchscreen)
Touch.AddTouchscreen(touchscreen);
break;
}
case InputDeviceChange.Removed:
{
if (device is Touchscreen touchscreen)
Touch.RemoveTouchscreen(touchscreen);
break;
}
}
}
private static void OnSettingsChange()
{
var currentUpdateMode = InputSystem.settings.updateMode;
if (s_UpdateMode == currentUpdateMode)
return;
TearDownState();
SetUpState();
}
#if UNITY_EDITOR
private static void OnBeforeDomainReload()
{
// We need to release NativeArrays we're holding before losing track of them during domain reloads.
Touch.s_GlobalState.playerState.Destroy();
Touch.s_GlobalState.editorState.Destroy();
}
#endif
[Conditional("DEVELOPMENT_BUILD")]
[Conditional("UNITY_EDITOR")]
internal static void CheckEnabled()
{
if (!enabled)
throw new InvalidOperationException("EnhancedTouch API is not enabled; call EnhancedTouchSupport.Enable()");
}
}
}