void MobileSimulator::MouseDownEvent(Vec2i screenCoordinates, MouseButtonInput button) { _mouseDown = true; TouchList* tl = &TouchListener::GetTouchList(); if (theInput.IsKeyDown(ANGEL_KEY_LEFTCONTROL) || theInput.IsKeyDown(ANGEL_KEY_RIGHTCONTROL)) { // add the two touches Touch* t = new Touch(); t->__platformTouch = NULL; t->StartingPoint = screenCoordinates; t->CurrentPoint = t->StartingPoint; tl->push_back(t); SendTouchNotifiers(t, TOUCH_START); t = new Touch(); t->__platformTouch = NULL; Vector2 pos2 = MathUtil::WorldToScreen(_fingerGhost2->GetPosition()); t->StartingPoint = Vec2i(pos2.X, pos2.Y); t->CurrentPoint = t->StartingPoint; tl->push_back(t); SendTouchNotifiers(t, TOUCH_START); } else { // just a single touch Touch* t = new Touch(); t->__platformTouch = NULL; t->StartingPoint = screenCoordinates; t->CurrentPoint = t->StartingPoint; tl->push_back(t); SendTouchNotifiers(t, TOUCH_START); } }
void PluginView::handleTouchEvent(TouchEvent* event) { if (!m_window->isAcceptingEvent(kTouch_ANPEventFlag)) return; if (!m_window->inFullScreen() && m_parentFrame->document()->focusedNode() != m_element) return; ANPEvent evt; SkANP::InitEvent(&evt, kMultiTouch_ANPEventType); const AtomicString& type = event->type(); if (eventNames().touchstartEvent == type) evt.data.multiTouch.action = kDown_ANPTouchAction; else if (eventNames().touchendEvent == type) evt.data.multiTouch.action = kUp_ANPTouchAction; else if (eventNames().touchmoveEvent == type) evt.data.multiTouch.action = kMove_ANPTouchAction; else if (eventNames().touchcancelEvent == type) evt.data.multiTouch.action = kCancel_ANPTouchAction; else if (eventNames().touchlongpressEvent == type) evt.data.multiTouch.action = kLongPress_ANPTouchAction; else if (eventNames().touchdoubletapEvent == type) evt.data.multiTouch.action = kDoubleTap_ANPTouchAction; else return; // set the id and timestamp evt.data.multiTouch.id = 0; // TODO evt.data.multiTouch.timestamp = 0; // TODO // In the event of a touchend (up) or touchcancel event, we must ask the changedTouch for the // co-ordinates as there is no touch in touches anymore. TouchList* touches = (evt.data.multiTouch.action == kUp_ANPTouchAction || evt.data.multiTouch.action == kCancel_ANPTouchAction) ? event->changedTouches() : event->touches(); // set each touchPoint int pointerCount = touches->length(); evt.data.multiTouch.pointerCount = pointerCount; evt.data.multiTouch.touchPoint = new TouchPoint[pointerCount]; for (int x = 0; x < evt.data.multiTouch.pointerCount; x++) { Touch* touch = touches->item(x); // Convert to coordinates that are relative to the plugin. IntPoint localPos = roundedIntPoint(m_element->renderer()->absoluteToLocal(IntPoint(touch->pageX(), touch->pageY()))); evt.data.multiTouch.touchPoint[x].id = touch->identifier(); evt.data.multiTouch.touchPoint[x].x = localPos.x(); evt.data.multiTouch.touchPoint[x].y = localPos.y(); evt.data.multiTouch.touchPoint[x].pressure = 1; // TODO evt.data.multiTouch.touchPoint[x].size = 1; // TODO } if (m_window->sendEvent(evt)) event->preventDefault(); // cleanup the touch points we allocated delete[] evt.data.multiTouch.touchPoint; }
JSValue jsTouchListLength(ExecState* exec, JSValue slotBase, const Identifier&) { JSTouchList* castedThis = static_cast<JSTouchList*>(asObject(slotBase)); UNUSED_PARAM(exec); TouchList* imp = static_cast<TouchList*>(castedThis->impl()); JSValue result = jsNumber(imp->length()); return result; }
void RangeInputType::handleTouchEvent(TouchEvent* event) { if (element().isDisabledOrReadOnly()) return; if (event->type() == EventTypeNames::touchend) { event->setDefaultHandled(); return; } TouchList* touches = event->targetTouches(); if (touches->length() == 1) { sliderThumbElement()->setPositionFromPoint(touches->item(0)->absoluteLocation()); event->setDefaultHandled(); } }
void SliderThumbElement::handleTouchStart(TouchEvent* touchEvent) { TouchList* targetTouches = touchEvent->targetTouches(); if (targetTouches->length() != 1) return; // Ignore the touch if it is not really inside the thumb. Touch* touch = targetTouches->item(0); IntRect boundingBox = renderer()->absoluteBoundingBoxRect(); if (!boundingBox.contains(touch->pageX(), touch->pageY())) return; setExclusiveTouchIdentifier(touch->identifier()); startDragging(); touchEvent->setDefaultHandled(); }
EncodedJSValue JSC_HOST_CALL jsTouchListPrototypeFunctionItem(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); if (!thisValue.inherits(&JSTouchList::s_info)) return throwVMTypeError(exec); JSTouchList* castedThis = static_cast<JSTouchList*>(asObject(thisValue)); ASSERT_GC_OBJECT_INHERITS(castedThis, &JSTouchList::s_info); TouchList* imp = static_cast<TouchList*>(castedThis->impl()); if (exec->argumentCount() < 1) return throwVMError(exec, createTypeError(exec, "Not enough arguments")); unsigned index(exec->argument(0).toUInt32(exec)); if (exec->hadException()) return JSValue::encode(jsUndefined()); JSC::JSValue result = toJS(exec, castedThis->globalObject(), WTF::getPtr(imp->item(index))); return JSValue::encode(result); }
void RangeInputType::handleTouchEvent(TouchEvent* event) { #if PLATFORM(IOS) typedSliderThumbElement().handleTouchEvent(event); #elif ENABLE(TOUCH_SLIDER) if (element().isDisabledOrReadOnly()) return; if (event->type() == eventNames().touchendEvent) { event->setDefaultHandled(); return; } TouchList* touches = event->targetTouches(); if (touches->length() == 1) { typedSliderThumbElement().setPositionFromPoint(touches->item(0)->absoluteLocation()); event->setDefaultHandled(); } #endif }
void PluginView::handleTouchEvent(TouchEvent* event) { if (!m_private) return; if (!m_private->m_isFocused) focusPluginElement(); NPTouchEvent npTouchEvent; if (event->isDoubleTap()) npTouchEvent.type = TOUCH_EVENT_DOUBLETAP; else if (event->isTouchHold()) npTouchEvent.type = TOUCH_EVENT_TOUCHHOLD; else if (event->type() == eventNames().touchcancelEvent) npTouchEvent.type = TOUCH_EVENT_CANCEL; else return; TouchList* touchList; // The touches list is empty if in a touch end event. // Since DoubleTap is ususally a TouchEnd Use changedTouches instead. if (npTouchEvent.type == TOUCH_EVENT_DOUBLETAP) touchList = event->changedTouches(); else touchList = event->touches(); npTouchEvent.points = 0; npTouchEvent.size = touchList->length(); OwnArrayPtr<NPTouchPoint> touchPoints; if (touchList->length()) { touchPoints = adoptArrayPtr(new NPTouchPoint[touchList->length()]); npTouchEvent.points = touchPoints.get(); for (unsigned i = 0; i < touchList->length(); i++) { Touch* touchItem = touchList->item(i); touchPoints[i].touchId = touchItem->identifier(); touchPoints[i].clientX = touchItem->pageX() - frameRect().x(); touchPoints[i].clientY = touchItem->pageY() - frameRect().y(); touchPoints[i].screenX = touchItem->screenX(); touchPoints[i].screenY = touchItem->screenY(); touchPoints[i].pageX = touchItem->pageX(); touchPoints[i].pageY = touchItem->pageY(); } } NPEvent npEvent; npEvent.type = NP_TouchEvent; npEvent.data = &npTouchEvent; if (dispatchNPEvent(npEvent)) event->setDefaultHandled(); }
void SliderContainerElement::handleTouchEvent(TouchEvent* event) { HTMLInputElement* input = hostInput(); if (input->isDisabledOrReadOnly()) return; if (event->type() == EventTypeNames::touchend) { input->dispatchFormControlChangeEvent(); event->setDefaultHandled(); m_slidingDirection = NoMove; m_touchStarted = false; return; } // The direction of this series of touch actions has been determined, which is // perpendicular to the slider, so no need to adjust the value. if (!canSlide()) { return; } TouchList* touches = event->targetTouches(); SliderThumbElement* thumb = toSliderThumbElement( treeScope().getElementById(ShadowElementNames::sliderThumb())); if (touches->length() == 1) { if (event->type() == EventTypeNames::touchstart) { m_startPoint = touches->item(0)->absoluteLocation(); m_slidingDirection = NoMove; m_touchStarted = true; thumb->setPositionFromPoint(touches->item(0)->absoluteLocation()); } else if (m_touchStarted) { LayoutPoint currentPoint = touches->item(0)->absoluteLocation(); if (m_slidingDirection == NoMove) { // Still needs to update the direction. m_slidingDirection = getDirection(currentPoint, m_startPoint); } // m_slidingDirection has been updated, so check whether it's okay to // slide again. if (canSlide()) { thumb->setPositionFromPoint(touches->item(0)->absoluteLocation()); event->setDefaultHandled(); } } } }
void EventPath::checkReachability(TreeScope& treeScope, TouchList& touchList) { for (size_t i = 0; i < touchList.length(); ++i) ASSERT(touchList.item(i)->target()->toNode()->treeScope().isInclusiveOlderSiblingShadowRootOrAncestorTreeScopeOf(treeScope)); }
void MobileSimulator::MouseMotionEvent(Vec2i screenCoordinates) { Vector2 pos = MathUtil::ScreenToWorld(screenCoordinates); _fingerGhost1->SetPosition(pos); _fingerGhost2->SetPosition(-pos); if (_mouseDown) { //move touch(es) TouchList *tl = &TouchListener::GetTouchList(); if (tl->size() > 0) { (*tl)[0]->CurrentPoint = screenCoordinates; if ( (*tl)[0]->MotionStartTime < 0.0f ) { (*tl)[0]->MotionStartTime = theWorld.GetCurrentTimeSeconds(); } } if (tl->size() > 1) { Vector2 negCoordsVec = MathUtil::WorldToScreen(-pos); Vec2i negCoords(negCoordsVec.X, negCoordsVec.Y); (*tl)[1]->CurrentPoint = negCoords; if ( (*tl)[1]->MotionStartTime < 0.0f ) { (*tl)[1]->MotionStartTime = theWorld.GetCurrentTimeSeconds(); } Touch* t1 = (*tl)[0]; Touch* t2 = (*tl)[1]; Vector2 start1(t1->StartingPoint); Vector2 current1(t1->CurrentPoint); Vector2 start2(t2->StartingPoint); Vector2 current2(t2->CurrentPoint); Vector2 initialVector = start2 - start1; Vector2 currentVector = current2 - current1; Vector2 initNorm = Vector2::Normalize(initialVector); Vector2 currentNorm = Vector2::Normalize(currentVector); float radiansRotated = acos(Vector2::Dot(initNorm, currentNorm)); if (!_multiGestureOngoing) { Vector2 motion = current1 - start1; if (motion.LengthSquared() >= (MULTI_MIN_DISTANCE * MULTI_MIN_DISTANCE) ) { _multiGestureOngoing = true; // figure out if it's a rotate or a pinch if (radiansRotated > MULTI_ROTATE_ANGLE) { _gestureType = ROTATE; } else { _gestureType = PINCH; } } } if (_multiGestureOngoing) { GestureData gd; gd.Velocity = 0.0f; // don't want to store all the extra datums // needed to actually calculate this if (_gestureType == ROTATE) { float cross = Vector2::Cross(initNorm, currentNorm); if (cross > 0.0f) { radiansRotated = -radiansRotated; } gd.GestureMagnitude = radiansRotated; theSwitchboard.Broadcast(new TypedMessage<GestureData>("MultiTouchRotate", gd)); } else if (_gestureType == PINCH) { gd.GestureMagnitude = currentVector.Length() / initialVector.Length(); theSwitchboard.Broadcast(new TypedMessage<GestureData>("MultiTouchPinch", gd)); } } } } }
void MobileSimulator::MouseUpEvent(Vec2i screenCoordinates, MouseButtonInput button) { _multiGestureOngoing = false; _gestureType = NONE; _mouseDown = false; TouchList* tl = &TouchListener::GetTouchList(); if (theInput.IsKeyDown(ANGEL_KEY_LEFTCONTROL) || theInput.IsKeyDown(ANGEL_KEY_RIGHTCONTROL)) { TouchList::iterator it = tl->begin(); while (it != tl->end()) { SendTouchNotifiers((*it), TOUCH_END); delete (*it); it = tl->erase(it); } } else { // just a single touch, but we'll iterate anyway TouchList::iterator it = tl->begin(); while (it != tl->end()) { if ( (theWorld.GetCurrentTimeSeconds() - (*it)->MotionStartTime) < SWIPE_MAX_DURATION) { Vector2 start((*it)->StartingPoint.X, (*it)->StartingPoint.Y); Vector2 end((*it)->CurrentPoint.X, (*it)->CurrentPoint.Y); Vector2 motion = end - start; if (motion.LengthSquared() >= (SWIPE_MIN_DISTANCE * SWIPE_MIN_DISTANCE)) { float angle = MathUtil::ToDegrees(acos(Vector2::Dot(Vector2::UnitX, Vector2::Normalize(motion)))); if (motion.Y > 0.0f) { angle = 360.0f - angle; } if ( (angle > 45.0f) && (angle <= 135.0f) ) { // swipe up theSwitchboard.Broadcast(new Message("MultiTouchSwipeUp")); } else if ( (angle > 135.0f) && (angle <= 225.0f) ) { // swipe left theSwitchboard.Broadcast(new Message("MultiTouchSwipeLeft")); } else if ( (angle > 225.0f) && (angle <= 315.0f) ) { // swipe down theSwitchboard.Broadcast(new Message("MultiTouchSwipeDown")); } else { // swipe right theSwitchboard.Broadcast(new Message("MultiTouchSwipeRight")); } } } SendTouchNotifiers((*it), TOUCH_END); delete (*it); it = tl->erase(it); } } }
WebInputEventResult TouchEventManager::dispatchTouchEvents( const PlatformTouchEvent& event, const HeapVector<TouchInfo>& touchInfos, bool allTouchesReleased) { bool touchStartOrFirstTouchMove = false; if (event.type() == PlatformEvent::TouchStart) { m_waitingForFirstTouchMove = true; touchStartOrFirstTouchMove = true; } else if (event.type() == PlatformEvent::TouchMove) { touchStartOrFirstTouchMove = m_waitingForFirstTouchMove; m_waitingForFirstTouchMove = false; } // Build up the lists to use for the |touches|, |targetTouches| and // |changedTouches| attributes in the JS event. See // http://www.w3.org/TR/touch-events/#touchevent-interface for how these // lists fit together. // Holds the complete set of touches on the screen. TouchList* touches = TouchList::create(); // A different view on the 'touches' list above, filtered and grouped by // event target. Used for the |targetTouches| list in the JS event. using TargetTouchesHeapMap = HeapHashMap<EventTarget*, Member<TouchList>>; TargetTouchesHeapMap touchesByTarget; // Array of touches per state, used to assemble the |changedTouches| list. ChangedTouches changedTouches[PlatformTouchPoint::TouchStateEnd]; for (unsigned i = 0; i < touchInfos.size(); ++i) { const TouchInfo& touchInfo = touchInfos[i]; const PlatformTouchPoint& point = touchInfo.point; PlatformTouchPoint::TouchState pointState = point.state(); if (touchInfo.consumed) continue; Touch* touch = Touch::create( touchInfo.targetFrame.get(), touchInfo.touchNode.get(), point.id(), point.screenPos(), touchInfo.contentPoint, touchInfo.adjustedRadius, point.rotationAngle(), point.force(), touchInfo.region); // Ensure this target's touch list exists, even if it ends up empty, so // it can always be passed to TouchEvent::Create below. TargetTouchesHeapMap::iterator targetTouchesIterator = touchesByTarget.find(touchInfo.touchNode.get()); if (targetTouchesIterator == touchesByTarget.end()) { touchesByTarget.set(touchInfo.touchNode.get(), TouchList::create()); targetTouchesIterator = touchesByTarget.find(touchInfo.touchNode.get()); } // |touches| and |targetTouches| should only contain information about // touches still on the screen, so if this point is released or // cancelled it will only appear in the |changedTouches| list. if (pointState != PlatformTouchPoint::TouchReleased && pointState != PlatformTouchPoint::TouchCancelled) { touches->append(touch); targetTouchesIterator->value->append(touch); } // Now build up the correct list for |changedTouches|. // Note that any touches that are in the TouchStationary state (e.g. if // the user had several points touched but did not move them all) should // never be in the |changedTouches| list so we do not handle them // explicitly here. See https://bugs.webkit.org/show_bug.cgi?id=37609 // for further discussion about the TouchStationary state. if (pointState != PlatformTouchPoint::TouchStationary && touchInfo.knownTarget) { ASSERT(pointState < PlatformTouchPoint::TouchStateEnd); if (!changedTouches[pointState].m_touches) changedTouches[pointState].m_touches = TouchList::create(); changedTouches[pointState].m_touches->append(touch); changedTouches[pointState].m_targets.add(touchInfo.touchNode); } } if (allTouchesReleased) { m_touchSequenceDocument.clear(); m_touchSequenceUserGestureToken.clear(); } WebInputEventResult eventResult = WebInputEventResult::NotHandled; // Now iterate through the |changedTouches| list and |m_targets| within it, // sending TouchEvents to the targets as required. for (unsigned state = 0; state != PlatformTouchPoint::TouchStateEnd; ++state) { if (!changedTouches[state].m_touches) continue; const AtomicString& eventName(touchEventNameForTouchPointState(static_cast<PlatformTouchPoint::TouchState>(state))); for (const auto& eventTarget : changedTouches[state].m_targets) { EventTarget* touchEventTarget = eventTarget; TouchEvent* touchEvent = TouchEvent::create( touches, touchesByTarget.get(touchEventTarget), changedTouches[state].m_touches.get(), eventName, touchEventTarget->toNode()->document().domWindow(), event.getModifiers(), event.cancelable(), event.causesScrollingIfUncanceled(), event.timestamp()); DispatchEventResult domDispatchResult = touchEventTarget->dispatchEvent(touchEvent); // Only report for top level documents with a single touch on // touch-start or the first touch-move. if (touchStartOrFirstTouchMove && touchInfos.size() == 1 && event.cancelable() && m_frame->isMainFrame()) { DEFINE_STATIC_LOCAL(EnumerationHistogram, rootDocumentListenerHistogram, ("Event.Touch.TargetAndDispatchResult", TouchTargetAndDispatchResultTypeMax)); rootDocumentListenerHistogram.count(toTouchTargetHistogramValue(eventTarget, domDispatchResult)); // Count the handled touch starts and first touch moves before and after the page is fully loaded respectively. if (m_frame->document()->isLoadCompleted()) { DEFINE_STATIC_LOCAL(EnumerationHistogram, touchDispositionsAfterPageLoadHistogram, ("Event.Touch.TouchDispositionsAfterPageLoad", TouchEventDispatchResultTypeMax)); touchDispositionsAfterPageLoadHistogram.count((domDispatchResult != DispatchEventResult::NotCanceled) ? HandledTouches : UnhandledTouches); } else { DEFINE_STATIC_LOCAL(EnumerationHistogram, touchDispositionsBeforePageLoadHistogram, ("Event.Touch.TouchDispositionsBeforePageLoad", TouchEventDispatchResultTypeMax)); touchDispositionsBeforePageLoadHistogram.count((domDispatchResult != DispatchEventResult::NotCanceled) ? HandledTouches : UnhandledTouches); } } eventResult = EventHandler::mergeEventResult(eventResult, EventHandler::toWebInputEventResult(domDispatchResult)); } } return eventResult; }