# 2. Enhanced Touch Polling Part of [[Mobile Input and Touch]]. Prev: [[1. Touch Schemes on the Existing Input System]]. Next: [[3. On-Screen Stick and Isolated Actions]]. On-screen sticks (part 3) are the right tool when you want a virtual gamepad. When you want to **inspect contacts** - a drag-to-pan surface, a debug overlay, a "how many fingers are down" test - use the official **Enhanced Touch** polling API. This is not a second player controller. Do not drive `Move` from both a stick and `Touch.activeTouches` at once. ## 2.1 Enable it explicitly Official 1.20.1 [touch polling](https://docs.unity3d.com/Packages/[email protected]/manual/touch-polling.html) manual: Enhanced Touch records contacts as they happen and has a cost, so it is **off** until you call `EnhancedTouchSupport.Enable()`. You do **not** need to enable it to use `Touchscreen` as a device, or to use Actions. You **do** need it to use `UnityEngine.InputSystem.EnhancedTouch.Touch`. `Enable()` / `Disable()` balance: if `Enable` is called twice, it takes two `Disable` calls to turn the system off. Pair them with a component's `OnEnable` / `OnDisable` so a disabled debug overlay does not leave the extra work running. Official warning, same page, easy to ignore: **do not poll `Touchscreen` state directly inside `Update` or `FixedUpdate` if you meant this API.** You can miss short-lived contacts that begin and end inside one Input System update. That is why Enhanced Touch exists. ```csharp using UnityEngine; using UnityEngine.InputSystem.EnhancedTouch; using Touch = UnityEngine.InputSystem.EnhancedTouch.Touch; using TouchPhase = UnityEngine.InputSystem.TouchPhase; /// <summary> /// Debug overlay for active touches. NOT compiled in Unity; not play-tested on a device. /// </summary> public sealed class TouchDebugOverlay : MonoBehaviour { void OnEnable() => EnhancedTouchSupport.Enable(); void OnDisable() => EnhancedTouchSupport.Disable(); void Update() { foreach (var touch in Touch.activeTouches) { switch (touch.phase) { case TouchPhase.Began: Debug.Log(quot;Touch {touch.touchId} began at {touch.screenPosition}"); break; case TouchPhase.Moved: case TouchPhase.Stationary: break; case TouchPhase.Ended: case TouchPhase.Canceled: Debug.Log(quot;Touch {touch.touchId} ended phase={touch.phase}"); break; } } } } ``` The alias `using Touch = UnityEngine.InputSystem.EnhancedTouch.Touch` is the official sample's habit, so this struct does not collide with `UnityEngine.Touch`. ## 2.2 Touches vs fingers vs actions Official `Touch` remarks (1.20.1): a **touch** is one contact-state change (Began / Moved / Ended / Canceled). A **finger** is the Nth contact on the screen and stays that slot as the contact moves. `Touch.activeTouches` is every touch that is ongoing **or ended this frame**. A contact that begins and ends in the same hardware update can surface as Began this frame and Ended next - so the count can exceed the number of physical fingers for a moment. Useful official properties, once support is enabled (accessing them otherwise throws `InvalidOperationException`): | Member | Role | |---|---| | `Touch.activeTouches` | Poll this in `Update` | | `touch.touchId`, `touch.phase`, `touch.screenPosition` | Identity, phase, position | | `touch.startScreenPosition`, `touch.delta`, `touch.startTime`, `touch.time` | Gesture math | | `touch.finger` | The `Finger` for this contact | | `Touch.activeFingers` / `Touch.fingers` | Active only, or all slots | | `Touch.onFingerDown` / `onFingerMove` / `onFingerUp` | Event alternative to polling | | `touch.pressure`, `touch.radius` | **Device-dependent**; pressure may be 0 if unsupported | | `touch.history` | History for this contact; official default history length can be **zero** until you opt into keeping it (`maxHistoryLengthPerFinger`) | Confirm `maxHistoryLengthPerFinger` in 1.20.1 IntelliSense if you need a swipe history; do not assume history is already recording. Enhanced Touch and `InputAction` can run **side by side**, but Enhanced Touch is a polling API - official remarks say it is not itself the Actions system. Prefer Actions + on-screen controls for player Move. Prefer Enhanced Touch for debug and custom gestures you are prepared to write tests for. ## 2.3 Where the Simulator will lie to you The Device Simulator (part 4) can only inject **one** finger. A two-finger gesture written against `Touch.activeTouches` will look "broken" in the Simulator even when the code is fine. Test multitouch on a phone, or with whatever **Input System** touch-simulation option your 1.20.x Input Debugger actually exposes (confirm in the installed package; do not copy a flag name from a different Input System major version). ## 2.4 Exercise Add `TouchDebugOverlay` to an empty scene, enable Enhanced Touch, enter Play Mode, and drag in the Game view or Device Simulator. Log `touchId` and `phase`. Then comment out `Enable()` and confirm you get the official `InvalidOperationException` (or enable-required behavior) when polling `activeTouches` - so you remember the switch. ## Sources - Touch polling (1.20.1): https://docs.unity3d.com/Packages/[email protected]/manual/touch-polling.html - `EnhancedTouchSupport` (1.20.1): https://docs.unity3d.com/Packages/[email protected]/api/UnityEngine.InputSystem.EnhancedTouch.EnhancedTouchSupport.html - `Touch` (1.20.1): https://docs.unity3d.com/Packages/[email protected]/api/UnityEngine.InputSystem.EnhancedTouch.Touch.html