Gesture utilities
164510
function startHoldGesture(sense) {
        sense.triggerEvent(GST_HOLD_START, {
            clientX: sense.finger1.clientX,
            clientY: sense.finger1.clientY,
            pageX: sense.finger1.pageX,
            pageY: sense.finger1.pageY,
            nbFinger: sense.fingers.length
        });
    }
1276853
function SingleTouchInput() {
    this.evTarget = SINGLE_TOUCH_TARGET_EVENTS;
    this.evWin = SINGLE_TOUCH_WINDOW_EVENTS;
    this.started = false;

    Input.apply(this, arguments);
}
565164
function createTouchList(mouseEv) {
        var touchList = new TouchList();

        if (isMultiTouch) {
            var f = TouchEmulator.multiTouchOffset;
            var deltaX = multiTouchStartPos.pageX - mouseEv.pageX;
            var deltaY = multiTouchStartPos.pageY - mouseEv.pageY;

            touchList.push(new Touch(eventTarget, 1, multiTouchStartPos, (deltaX*-1) - f, (deltaY*-1) + f));
            touchList.push(new Touch(eventTarget, 2, multiTouchStartPos, deltaX+f, deltaY-f));
        } else {
            touchList.push(new Touch(eventTarget, 1, mouseEv, 0, 0));
        }

        return touchList;
    }
1040065
function(e) {
    this.touch.cur = 'shifting';
    var factor = 5e-3;
    var delta = 0;

    if (this.touch.lastY && (e.gesture.direction == 'up' || e.gesture.direction == 'down')) {
      this.touch.shiftControl
          .removeClass('shift-horizontal')
          .addClass('shift-vertical')
          .css('top', e.gesture.center.pageY + 'px');
      delta = e.gesture.deltaY - this.touch.lastY;
      this.viewpointY -= factor * delta * this.viewpointZ;
      this.angleX += delta;
    }
    if (this.touch.lastX && (e.gesture.direction == 'left' || e.gesture.direction == 'right')) {
      this.touch.shiftControl
          .removeClass('shift-vertical')
          .addClass('shift-horizontal')
          .css('left', e.gesture.center.pageX + 'px');
      delta = e.gesture.deltaX - this.touch.lastX;
      this.viewpointX += factor * delta * this.viewpointZ;
      this.angleZ += delta;
    }
    if (delta)
      this.onDraw();
    this.touch.lastX = e.gesture.deltaX;
    this.touch.lastY = e.gesture.deltaY;
  }
798235
async function wheelTimedOut(element) {

  // Snap to the closest item.
  const swipeFraction = element.state.swipeFraction;
  let gesture;
  if (swipeFraction <= -0.5) {
    gesture = symbols.swipeLeft;
  } else if (swipeFraction >= 0.5) {
    gesture = symbols.swipeRight;
  }

  // TODO: Listen for the transition to complete, and then restore
  // dragging to false (or the previous value).
  resetWheelTracking(element);
  element.setState({ swipeFraction: null });

  if (gesture && element[gesture]) {
    await element[gesture]();
  }
}
165376
function onEvent(gesture, handler) {
    var gestures = gesture.split(' ');
    Hammer.utils.each(gestures, function(gesture) {
      this.element.addEventListener(gesture, handler, false);
    }, this);
    return this;
  }
1294491
function triggerGesture(elements, startTouches, options, done) {
        var interval = 10,
            loops = Math.ceil(options.duration / interval),
            loop = 1;

        elements = ensureAnArray(elements);

        options = merge(options, {
            pos: [10, 10],
            duration: 250,
            touches: 1,
            deltaX: 0,
            deltaY: 0,
            radius: 100,
            scale: 1,
            rotation: 0,
            easing: 'swing'
        });

        function gestureLoop() {
            // calculate the radius
            // this is for scaling and multiple touches
            var radius = options.radius;
            if (options.scale !== 1) {
                radius = options.radius - (options.radius * (1 - options.scale) * (1 / loops * loop));
            }

            // calculate new position/rotation
            var easing = Simulator.easings[options.easing](1 / loops * loop),
                posX = options.pos[0] + (options.deltaX / loops * loop) * easing,
                posY = options.pos[1] + (options.deltaY / loops * loop) * easing,
                rotation = options.rotation / loops * loop,
                touches = getTouches([posX, posY], elements, startTouches.length, radius, rotation),
                isFirst = (loop == 1),
                isLast = (loop == loops);

            for (var t = touches.length - 1; t >= 0; t--) {
                if (isFirst) {
                    trigger(touches, touches[t].target, 'start');
                } else if (isLast) {
                    trigger(touches, touches[t].target, 'end');

                    // Remove processed touch
                    touches.pop()

                    if (touches.length === 0) {
                        return done();
                    }
                } else {
                    trigger(touches, touches[t].target, 'move');
                }
            }

            setTimeout(gestureLoop, interval);
            loop++;
        }
        gestureLoop();
    }
314887
def on_touch(self, view, event):
        
        d = self.declaration
        r = {'event': event, 'result': False}
        d.touch_event(r)
        return r['result']
1246038
function logHammerEvent(ev) {
		if(!ev.gesture) {
			return;
		}

		// store last event, that should might match the gremlin
		if(ev.gesture.eventType == 'end') {
			testLogger.lastEvent = ev;
		}

		// highlight gesture
		var event_el = getLogElement('gesture', ev.type);
		event_el.className = 'active';

		for(var i = 0, len = hammerProps.length; i < len; i++) {
			var prop = hammerProps[i];
			var value = ev.gesture[prop];
			switch(prop) {
				case 'center':
					value = value.pageX + 'x' + value.pageY;
					break;
				case 'gesture':
					value = ev.type;
					break;
				case 'target':
					value = ev.gesture.target.tagName;
					break;
				case 'touches':
					value = ev.gesture.touches.length;
					break;
			}
			getLogElement('prop', prop).innerHTML = value;
		}
	}
1095730
function startHandler(evt) {
        startHandlerOriginal.call(this, evt);
        // must be a picture, only one picture!!
        var node = this.els[1].querySelector('img:first-child');
        var device = this.deviceEvents;
        if (device.hasTouch && node !== null) {
            IN_SCALE_MODE = true;
            var transform = getComputedTranslate(node);
            startTouches = getTouches(evt.targetTouches);
            startX = transform.translateX - 0;
            startY = transform.translateY - 0;
            currentScale = transform.scaleX;
            zoomNode = node;
            var pos = getPosition(node);
            if (evt.targetTouches.length == 2) {
                lastTouchStart = null;
                var touches = evt.touches;
                var touchCenter = getCenter({
                    x: touches[0].pageX,
                    y: touches[0].pageY
                }, {
                    x: touches[1].pageX,
                    y: touches[1].pageY
                });
                node.style.webkitTransformOrigin = generateTransformOrigin(touchCenter.x - pos.left, touchCenter.y - pos.top);
            } else if (evt.targetTouches.length === 1) {
                var time = (new Date()).getTime();
                gesture = 0;
                if (time - lastTouchStart < 300) {
                    evt.preventDefault();
                    gesture = 3;
                }
                lastTouchStart = time;
            }
        }
    }
607697
function (gesture, lastGesture, reverse) {
    var clip;
    var fromAction;
    var mesh = this.el.getObject3D('mesh');
    var toAction;

    if (!mesh) { return; }

    // Stop all current animations.
    mesh.mixer.stopAllAction();

    // Grab clip action.
    clip = this.getClip(gesture);
    toAction = mesh.mixer.clipAction(clip);
    toAction.clampWhenFinished = true;
    toAction.loop = THREE.LoopRepeat;
    toAction.repetitions = 0;
    toAction.timeScale = reverse ? -1 : 1;
    toAction.time = reverse ? clip.duration : 0;
    toAction.weight = 1;

    // No gesture to gesture or gesture to no gesture.
    if (!lastGesture || gesture === lastGesture) {
      // Stop all current animations.
      mesh.mixer.stopAllAction();
      // Play animation.
      toAction.play();
      return;
    }

    // Animate or crossfade from gesture to gesture.
    clip = this.getClip(lastGesture);
    fromAction = mesh.mixer.clipAction(clip);
    fromAction.weight = 0.15;
    fromAction.play();
    toAction.play();
    fromAction.crossFadeTo(toAction, 0.15, true);
  }
650771
function w3cTouchConvert(touchList) {
      var canvasOffset = display._getCanvasOffset();
      var tList = [];
      for (var i = 0; i < touchList.length; i++) {
         var touchEvent = touchList.item(i);
         tList.push({
            identifier: touchEvent.identifier,
            pos: [touchEvent.clientX - canvasOffset[0], touchEvent.clientY - canvasOffset[1]]
         });
      }
      return tList;
   }
637759
function getTouchList(ev/*, eventType*/) {
    // get the fake pointerEvent touchlist
    if(Hammer.HAS_POINTEREVENTS) {
      return Hammer.PointerEvent.getTouchList();
    }
    // get the touchlist
    else if(ev.touches) {
      return ev.touches;
    }
    // make fake touchlist from mouse position
    else {
      ev.identifier = 1;
      return [ev];
    }
  }
263581
def long_press(query, options={})
      ensure_query_class_or_nil(query)

      gesture_options = options.dup
      gesture_options[:at] ||= {}
      gesture_options[:at][:x] ||= 50
      gesture_options[:at][:y] ||= 50
      gesture_options[:timeout] ||= Calabash::Gestures::DEFAULT_GESTURE_WAIT_TIMEOUT
      gesture_options[:duration] ||= 1

      _long_press(query, gesture_options)
    end
778137
def gesture(self, start1, start2, *args, **kwargs):
        '''
        
        '''
        def to(obj_self, end1, end2, steps=100):
            ctp = lambda pt: point(*pt) if type(pt) == tuple else pt  # convert tuple to point
            s1, s2, e1, e2 = ctp(start1), ctp(start2), ctp(end1), ctp(end2)
            return self.jsonrpc.gesture(self.selector, s1, s2, e1, e2, steps)
        obj = type("Gesture", (object,), {"to": to})()
        return obj if len(args) == 0 else to(None, *args, **kwargs)
259116
function (el) {
            $el = $(el);
            $el.on('scroll', handleScroll);
            $el.on('touchstart', handleTouchstart);
            $el.on('touchmove', handleTouchmove);
            $el.on('touchend', handleTouchend);
        }
776473
function gestureContinue(element, clientX, clientY) {

  // Calculate and save the velocity since the last event. If this is the last
  // movement of the gesture, this velocity will be used to determine whether
  // the user is trying to flick.
  const deltaX = clientX - element[previousXKey];
  const deltaY = clientY - element[previousYKey];
  const now = Date.now();
  const deltaTime = now - element[previousTimeKey];
  const velocity = deltaX / deltaTime * 1000;

  element[previousXKey] = clientX;
  element[previousYKey] = clientY;
  element[previousTimeKey] = now;
  element[previousVelocityKey] = velocity;

  const verticalSwipe = Math.abs(deltaY) > Math.abs(deltaX);
  const vertical = element.state.swipeAxis === 'vertical';
  const swipeAlongAxis = vertical === verticalSwipe;

  if (!swipeAlongAxis) {
    // Move was mostly along the other axis.
    return false;
  }

  // Move was mostly along desired axis.

  if (vertical && isAnyAncestorScrolled(element[symbols.swipeTarget])) {
    // Don't interfere with scrolling.
    return false;
  }

  const swipeFraction = getSwipeFraction(element, clientX, clientY);

  if (swipeFraction < 0 && !element.state.enableNegativeSwipe ||
      swipeFraction > 0 && !element.state.enablePositiveSwipe) {
    // Swipe was in a direction that's not explicitly enabled.
    return false;
  }

  element.setState({ swipeFraction });
  
  // Indicate that the event was handled. It'd be nicer if we didn't have
  // to do this so that, e.g., a user could be swiping left and right
  // while simultaneously scrolling up and down. (Native touch apps can do
  // that.) However, Mobile Safari wants to handle swipe events near the
  // page and interpret them as navigations. To avoid having a horiziontal
  // swipe misintepreted as a navigation, we indicate that we've handled
  // the event, and prevent default behavior.
  return true;
}