// Add gesture source to gesture source dictionary when detected.
        public void OnSourceDetected(SourceStateEventData eventData)
        {
            IInputSource inputSource = eventData.InputSource;

            // If dictionary already contains source with this id, return.
            if (_gestureSources.ContainsKey(eventData.SourceId))
            {
                return;
            }

            var gestureSource = new GestureSource(inputSource, eventData.SourceId);

            _gestureSources.Add(eventData.SourceId, gestureSource);
        }
        // Remove gesture source from gesture source dictionary when lost.
        public void OnSourceLost(SourceStateEventData eventData)
        {
            // If dictionary contains no source with this id, return.
            if (!_gestureSources.ContainsKey(eventData.SourceId))
            {
                return;
            }

            // If the lost gesture source was currently manipulating invoke a
            // ManipulationEnd event.
            if (_gestureSources[eventData.SourceId].IsManipulating)
            {
                GestureSource[] gestureSources = new GestureSource[_gestureSources.Count];
                _gestureSources.Values.CopyTo(gestureSources, 0);

                var eventArgs = new GestureInputEventArgs(gestureSources);
                ManipulationEnd(eventArgs);
            }

            _gestureSources.Remove(eventData.SourceId);
        }
        // This coroutine is invoked anytime an InputUp or InputDown event is received.
        // After it has been invoked, it waits for the duration set as InputTimeout until
        // evaluating the input. During this time, additional InputUp and InputDown events
        // can be received and accumulated. For example, two InputDown and two InputUp
        // events received for one gesture source during the timeout period will be evaluated
        // to a OneHandDoubleTap event.
        private IEnumerator ProcessInput(InputEventData eventData)
        {
            IsProcessing = true;

            // Wait and accumulate additional InputDown and InputUp events.
            yield return(new WaitForSeconds(InputTimeout));

            // Get all present gesture sources.
            GestureSource[] gestureSources = new GestureSource[_gestureSources.Count];
            _gestureSources.Values.CopyTo(gestureSources, 0);

            // Evaluate the InputUp and InputDown count for each gesture source and
            // encode the input data into a short. Afterwards, reset input sources.
            short inputData = 0;

            for (int i = 0; i < gestureSources.Length; i++)
            {
                inputData += (short)(gestureSources[i].Evaluate() << i * 8);
                gestureSources[i].ResetInputData();
            }

            // Unset the timer, so the GestureInputListener can process new input events.
            _timerSet = false;
            GestureType gestureType;

            // Check whether the encoded input data corresponds to a gesture. If so, retrieve
            // the corresponding Action delegate from the gesture event table and pass it to
            // the input handler for invocation.
            if (_gestureTypeTable.TryGetValue(inputData, out gestureType))
            {
                GestureInputEventArgs          eventArgs = new GestureInputEventArgs(gestureSources);
                Action <GestureInputEventArgs> action    = _gestureEventTable[gestureType];
                InputHandler.Instance.InvokeGestureInputEvent(action, eventArgs);
            }

            IsProcessing = false;
        }
        private void Update()
        {
            int sourcesManipulating = 0;

            // Check whether any sources are currently in a manipulating state.
            foreach (GestureSource source in _gestureSources.Values)
            {
                if (source.IsManipulating && !source.IsEvaluating)
                {
                    sourcesManipulating++;
                }
            }

            // If there is any gesture source currently manipulating, invoke a
            // ManipulationUpdate event.
            if (sourcesManipulating != 0)
            {
                GestureSource[] gestureSources = new GestureSource[_gestureSources.Count];
                _gestureSources.Values.CopyTo(gestureSources, 0);

                var eventArgs = new GestureInputEventArgs(gestureSources);
                ManipulationUpdate(eventArgs);
            }
        }