/* * Copyright (C) 2010 Apple Inc. All rights reserved. * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include "WebEventFactory.h" #include #include #include #include #include #include #include #include #include using namespace WebCore; namespace WebKit { static inline double currentTimeForEvent(const QInputEvent* event) { ASSERT(event); // Use the input event timestamps if they are available. // These timestamps are in milliseconds, thus convert them to seconds. if (event->timestamp()) return static_cast(event->timestamp()) / 1000; return WTF::currentTime(); } static WebMouseEvent::Button mouseButtonForEvent(QMouseEvent *event) { if (event->button() == Qt::LeftButton || (event->buttons() & Qt::LeftButton)) return WebMouseEvent::LeftButton; else if (event->button() == Qt::RightButton || (event->buttons() & Qt::RightButton)) return WebMouseEvent::RightButton; else if (event->button() == Qt::MidButton || (event->buttons() & Qt::MidButton)) return WebMouseEvent::MiddleButton; return WebMouseEvent::NoButton; } static WebEvent::Type webEventTypeForEvent(const QEvent* event) { switch (event->type()) { case QEvent::MouseButtonPress: return WebEvent::MouseDown; case QEvent::MouseButtonRelease: return WebEvent::MouseUp; case QEvent::MouseMove: return WebEvent::MouseMove; case QEvent::Wheel: return WebEvent::Wheel; case QEvent::KeyPress: return WebEvent::KeyDown; case QEvent::KeyRelease: return WebEvent::KeyUp; #if ENABLE(TOUCH_EVENTS) case QEvent::TouchBegin: return WebEvent::TouchStart; case QEvent::TouchUpdate: return WebEvent::TouchMove; case QEvent::TouchEnd: return WebEvent::TouchEnd; case QEvent::TouchCancel: return WebEvent::TouchCancel; #endif case QEvent::MouseButtonDblClick: ASSERT_NOT_REACHED(); return WebEvent::NoType; default: // assert return WebEvent::MouseMove; } } static inline WebEvent::Modifiers modifiersForEvent(Qt::KeyboardModifiers modifiers) { unsigned result = 0; if (modifiers & Qt::ShiftModifier) result |= WebEvent::ShiftKey; if (modifiers & Qt::ControlModifier) result |= WebEvent::ControlKey; if (modifiers & Qt::AltModifier) result |= WebEvent::AltKey; if (modifiers & Qt::MetaModifier) result |= WebEvent::MetaKey; return (WebEvent::Modifiers)result; } WebMouseEvent WebEventFactory::createWebMouseEvent(QMouseEvent* event, const QTransform& fromItemTransform, int eventClickCount) { static FloatPoint lastPos = FloatPoint(0, 0); WebEvent::Type type = webEventTypeForEvent(event); WebMouseEvent::Button button = mouseButtonForEvent(event); float deltaX = event->pos().x() - lastPos.x(); float deltaY = event->pos().y() - lastPos.y(); int clickCount = eventClickCount; WebEvent::Modifiers modifiers = modifiersForEvent(event->modifiers()); double timestamp = currentTimeForEvent(event); lastPos.set(event->localPos().x(), event->localPos().y()); return WebMouseEvent(type, button, fromItemTransform.map(event->localPos()).toPoint(), event->screenPos().toPoint(), deltaX, deltaY, 0.0f, clickCount, modifiers, timestamp); } WebWheelEvent WebEventFactory::createWebWheelEvent(QWheelEvent* e, const QTransform& fromItemTransform) { float deltaX = 0; float deltaY = 0; float wheelTicksX = 0; float wheelTicksY = 0; WebWheelEvent::Granularity granularity = WebWheelEvent::ScrollByPixelWheelEvent; WebEvent::Modifiers modifiers = modifiersForEvent(e->modifiers()); double timestamp = currentTimeForEvent(e); if (e->orientation() == Qt::Horizontal) { deltaX = e->delta(); wheelTicksX = deltaX / 120.0f; } else { deltaY = e->delta(); wheelTicksY = deltaY / 120.0f; } // Since we report the scroll by the pixel, convert the delta to pixel distance using standard scroll step. // Use the same single scroll step as QTextEdit (in QTextEditPrivate::init [h,v]bar->setSingleStep) static const float cDefaultQtScrollStep = 20.f; // ### FIXME: Default from QtGui. Should use Qt platform theme API once configurable. const int wheelScrollLines = 3; deltaX = wheelTicksX * wheelScrollLines * cDefaultQtScrollStep; deltaY = wheelTicksY * wheelScrollLines * cDefaultQtScrollStep; // Transform the position and the pixel scrolling distance. QLineF transformedScroll = fromItemTransform.map(QLineF(e->posF(), e->posF() + QPointF(deltaX, deltaY))); IntPoint transformedPoint = transformedScroll.p1().toPoint(); IntPoint globalPoint = e->globalPosF().toPoint(); FloatSize transformedDelta(transformedScroll.dx(), transformedScroll.dy()); FloatSize wheelTicks(wheelTicksX, wheelTicksY); return WebWheelEvent(WebEvent::Wheel, transformedPoint, globalPoint, transformedDelta, wheelTicks, granularity, modifiers, timestamp); } WebKeyboardEvent WebEventFactory::createWebKeyboardEvent(QKeyEvent* event) { const int state = event->modifiers(); WebEvent::Type type = webEventTypeForEvent(event); const String text = event->text(); const String unmodifiedText = event->text(); bool isAutoRepeat = event->isAutoRepeat(); bool isSystemKey = false; // FIXME: No idea what that is. bool isKeypad = (state & Qt::KeypadModifier); const String keyIdentifier = keyIdentifierForQtKeyCode(event->key()); int windowsVirtualKeyCode = windowsKeyCodeForKeyEvent(event->key(), isKeypad); int nativeVirtualKeyCode = event->nativeVirtualKey(); int macCharCode = 0; WebEvent::Modifiers modifiers = modifiersForEvent(event->modifiers()); double timestamp = currentTimeForEvent(event); return WebKeyboardEvent(type, text, unmodifiedText, keyIdentifier, windowsVirtualKeyCode, nativeVirtualKeyCode, macCharCode, isAutoRepeat, isKeypad, isSystemKey, modifiers, timestamp); } #if ENABLE(TOUCH_EVENTS) WebTouchEvent WebEventFactory::createWebTouchEvent(const QTouchEvent* event, const QTransform& fromItemTransform) { WebEvent::Type type = webEventTypeForEvent(event); WebPlatformTouchPoint::TouchPointState state = static_cast(0); unsigned id; WebEvent::Modifiers modifiers = modifiersForEvent(event->modifiers()); double timestamp = currentTimeForEvent(event); const QList& points = event->touchPoints(); Vector touchPoints; for (int i = 0; i < points.count(); ++i) { const QTouchEvent::TouchPoint& touchPoint = points.at(i); id = static_cast(touchPoint.id()); switch (touchPoint.state()) { case Qt::TouchPointReleased: state = WebPlatformTouchPoint::TouchReleased; break; case Qt::TouchPointMoved: state = WebPlatformTouchPoint::TouchMoved; break; case Qt::TouchPointPressed: state = WebPlatformTouchPoint::TouchPressed; break; case Qt::TouchPointStationary: state = WebPlatformTouchPoint::TouchStationary; break; default: ASSERT_NOT_REACHED(); break; } // Qt does not have a Qt::TouchPointCancelled point state, so if we receive a touch cancel event, // simply cancel all touch points here. if (type == WebEvent::TouchCancel) state = WebPlatformTouchPoint::TouchCancelled; IntSize radius(touchPoint.rect().width()/ 2, touchPoint.rect().height() / 2); touchPoints.append(WebPlatformTouchPoint(id, state, touchPoint.screenPos().toPoint(), fromItemTransform.map(touchPoint.pos()).toPoint(), radius, 0.0, touchPoint.pressure())); } return WebTouchEvent(type, WTFMove(touchPoints), modifiers, timestamp); } #endif } // namespace WebKit