1/* 2 Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies) 3 Copyright (C) 2006 Zack Rusin <zack@kde.org> 4 Copyright (C) 2011 Research In Motion Limited. 5 6 This library is free software; you can redistribute it and/or 7 modify it under the terms of the GNU Library General Public 8 License as published by the Free Software Foundation; either 9 version 2 of the License, or (at your option) any later version. 10 11 This library is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 Library General Public License for more details. 15 16 You should have received a copy of the GNU Library General Public License 17 along with this library; see the file COPYING.LIB. If not, write to 18 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 Boston, MA 02110-1301, USA. 20*/ 21 22#include "config.h" 23#include "WebEventConversion.h" 24 25#include "PlatformGestureEvent.h" 26#include "PlatformMouseEvent.h" 27#include "PlatformTouchEvent.h" 28#include "PlatformTouchPoint.h" 29#include "PlatformWheelEvent.h" 30#include <QTouchEvent> 31#include <QWheelEvent> 32#include <wtf/CurrentTime.h> 33 34namespace WebCore { 35 36static void mouseEventModifiersFromQtKeyboardModifiers(Qt::KeyboardModifiers keyboardModifiers, unsigned& modifiers) 37{ 38 modifiers = 0; 39 if (keyboardModifiers & Qt::ShiftModifier) 40 modifiers |= PlatformEvent::ShiftKey; 41 if (keyboardModifiers & Qt::ControlModifier) 42 modifiers |= PlatformEvent::CtrlKey; 43 if (keyboardModifiers & Qt::AltModifier) 44 modifiers |= PlatformEvent::AltKey; 45 if (keyboardModifiers & Qt::MetaModifier) 46 modifiers |= PlatformEvent::MetaKey; 47} 48 49static void mouseEventTypeAndMouseButtonFromQEvent(const QEvent* event, PlatformEvent::Type& mouseEventType, MouseButton& mouseButton) 50{ 51 switch (event->type()) { 52 case QEvent::MouseButtonDblClick: 53 case QEvent::MouseButtonPress: 54 mouseEventType = PlatformEvent::MousePressed; 55 break; 56 case QEvent::MouseButtonRelease: 57 mouseEventType = PlatformEvent::MouseReleased; 58 break; 59 case QEvent::MouseMove: 60 mouseEventType = PlatformEvent::MouseMoved; 61 break; 62 default: 63 ASSERT_NOT_REACHED(); 64 mouseEventType = PlatformEvent::MouseMoved; 65 break; 66 } 67 68 Qt::MouseButtons mouseButtons; 69 70 const QMouseEvent* mouseEvent = static_cast<const QMouseEvent*>(event); 71 mouseButtons = mouseEventType == PlatformEvent::MouseMoved ? mouseEvent->buttons() : mouseEvent->button(); 72 73 74 if (mouseButtons & Qt::LeftButton) 75 mouseButton = LeftButton; 76 else if (mouseButtons & Qt::RightButton) 77 mouseButton = RightButton; 78 else if (mouseButtons & Qt::MidButton) 79 mouseButton = MiddleButton; 80 else 81 mouseButton = NoButton; 82} 83 84class WebKitPlatformMouseEvent : public PlatformMouseEvent { 85public: 86 WebKitPlatformMouseEvent(QInputEvent*, int clickCount); 87}; 88 89WebKitPlatformMouseEvent::WebKitPlatformMouseEvent(QInputEvent* event, int clickCount) 90{ 91 m_timestamp = WTF::currentTime(); 92 93 bool isContextMenuEvent = false; 94#ifndef QT_NO_CONTEXTMENU 95 if (event->type() == QEvent::ContextMenu) { 96 isContextMenuEvent = true; 97 m_type = PlatformEvent::MousePressed; 98 QContextMenuEvent* ce = static_cast<QContextMenuEvent*>(event); 99 m_position = IntPoint(ce->pos()); 100 m_globalPosition = IntPoint(ce->globalPos()); 101 m_button = RightButton; 102 } 103#endif 104 if (!isContextMenuEvent) { 105 PlatformEvent::Type type; 106 mouseEventTypeAndMouseButtonFromQEvent(event, type, m_button); 107 QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event); 108 109 m_type = type; 110 m_position = IntPoint(mouseEvent->pos()); 111 m_globalPosition = IntPoint(mouseEvent->globalPos()); 112 } 113 114 m_clickCount = clickCount; 115 mouseEventModifiersFromQtKeyboardModifiers(event->modifiers(), m_modifiers); 116} 117 118PlatformMouseEvent convertMouseEvent(QInputEvent* event, int clickCount) 119{ 120 return WebKitPlatformMouseEvent(event, clickCount); 121} 122 123class WebKitPlatformWheelEvent : public PlatformWheelEvent { 124public: 125 WebKitPlatformWheelEvent(QWheelEvent*, int wheelScrollLines); 126 127private: 128 void applyDelta(int delta, Qt::Orientation, int wheelScrollLines); 129}; 130 131void WebKitPlatformWheelEvent::applyDelta(int delta, Qt::Orientation orientation, int wheelScrollLines) 132{ 133 if (orientation == Qt::Horizontal) { 134 m_deltaX = delta; 135 m_deltaY = 0; 136 } else { 137 m_deltaX = 0; 138 m_deltaY = delta; 139 } 140 m_wheelTicksX = m_deltaX / 120.0f; 141 m_wheelTicksY = m_deltaY / 120.0f; 142 143 // Since we request the scroll delta by the pixel, convert the wheel delta to pixel delta using the standard scroll step. 144 // Use the same single scroll step as QTextEdit (in QTextEditPrivate::init [h,v]bar->setSingleStep) 145 static const float cDefaultQtScrollStep = 20.f; 146 m_deltaX = m_wheelTicksX * wheelScrollLines * cDefaultQtScrollStep; 147 m_deltaY = m_wheelTicksY * wheelScrollLines * cDefaultQtScrollStep; 148} 149 150WebKitPlatformWheelEvent::WebKitPlatformWheelEvent(QWheelEvent* e, int wheelScrollLines) 151{ 152 m_timestamp = WTF::currentTime(); 153 mouseEventModifiersFromQtKeyboardModifiers(e->modifiers(), m_modifiers); 154 m_position = e->pos(); 155 m_globalPosition = e->globalPos(); 156 m_granularity = ScrollByPixelWheelEvent; 157 m_directionInvertedFromDevice = false; 158 applyDelta(e->delta(), e->orientation(), wheelScrollLines); 159} 160 161#if ENABLE(TOUCH_EVENTS) 162class WebKitPlatformTouchEvent : public PlatformTouchEvent { 163public: 164 WebKitPlatformTouchEvent(QTouchEvent*); 165}; 166 167class WebKitPlatformTouchPoint : public PlatformTouchPoint { 168public: 169 WebKitPlatformTouchPoint(const QTouchEvent::TouchPoint&, State); 170}; 171 172WebKitPlatformTouchEvent::WebKitPlatformTouchEvent(QTouchEvent* event) 173{ 174 switch (event->type()) { 175 case QEvent::TouchBegin: 176 m_type = PlatformEvent::TouchStart; 177 break; 178 case QEvent::TouchUpdate: 179 m_type = PlatformEvent::TouchMove; 180 break; 181 case QEvent::TouchEnd: 182 m_type = PlatformEvent::TouchEnd; 183 break; 184 case QEvent::TouchCancel: 185 m_type = PlatformEvent::TouchCancel; 186 break; 187 } 188 189 const QList<QTouchEvent::TouchPoint>& points = event->touchPoints(); 190 for (int i = 0; i < points.count(); ++i) { 191 PlatformTouchPoint::State state = PlatformTouchPoint::TouchStateEnd; 192 193 switch (points.at(i).state()) { 194 case Qt::TouchPointReleased: 195 state = PlatformTouchPoint::TouchReleased; 196 break; 197 case Qt::TouchPointMoved: 198 state = PlatformTouchPoint::TouchMoved; 199 break; 200 case Qt::TouchPointPressed: 201 state = PlatformTouchPoint::TouchPressed; 202 break; 203 case Qt::TouchPointStationary: 204 state = PlatformTouchPoint::TouchStationary; 205 break; 206 } 207 208 // Qt does not have a Qt::TouchPointCancelled point state, so if we receive a touch cancel event, 209 // simply cancel all touch points here. 210 if (m_type == PlatformEvent::TouchCancel) 211 state = PlatformTouchPoint::TouchCancelled; 212 213 m_touchPoints.append(WebKitPlatformTouchPoint(points.at(i), state)); 214 } 215 216 mouseEventModifiersFromQtKeyboardModifiers(event->modifiers(), m_modifiers); 217 218 m_timestamp = WTF::currentTime(); 219} 220 221WebKitPlatformTouchPoint::WebKitPlatformTouchPoint(const QTouchEvent::TouchPoint& point, State state) 222{ 223 // The QTouchEvent::TouchPoint API states that ids will be >= 0. 224 m_id = point.id(); 225 m_state = state; 226 m_screenPos = point.screenPos().toPoint(); 227 m_pos = point.pos().toPoint(); 228 // Qt reports touch point size as rectangles, but we will pretend it is an oval. 229 QRect touchRect = point.rect().toAlignedRect(); 230 if (touchRect.isValid()) { 231 m_radiusX = point.rect().width() / 2; 232 m_radiusY = point.rect().height() / 2; 233 } else { 234 // http://www.w3.org/TR/2011/WD-touch-events-20110505: 1 if no value is known. 235 m_radiusX = 1; 236 m_radiusY = 1; 237 } 238 m_force = point.pressure(); 239 // FIXME: Support m_rotationAngle if QTouchEvent at some point supports it. 240} 241#endif 242 243#if ENABLE(GESTURE_EVENTS) 244class WebKitPlatformGestureEvent : public PlatformGestureEvent { 245public: 246 WebKitPlatformGestureEvent(QGestureEventFacade*); 247}; 248 249static inline PlatformEvent::Type toPlatformEventType(Qt::GestureType type) 250{ 251 switch (type) { 252 case Qt::TapGesture: 253 return PlatformEvent::GestureTap; 254 case Qt::TapAndHoldGesture: 255 return PlatformEvent::GestureLongPress; 256 default: 257 ASSERT_NOT_REACHED(); 258 return PlatformEvent::NoType; 259 } 260} 261 262WebKitPlatformGestureEvent::WebKitPlatformGestureEvent(QGestureEventFacade* event) 263{ 264 m_type = toPlatformEventType(event->type); 265 m_globalPosition = event->globalPos; 266 m_position = event->pos; 267 m_timestamp = WTF::currentTime(); 268} 269 270#endif 271 272PlatformWheelEvent convertWheelEvent(QWheelEvent* event, int wheelScrollLines) 273{ 274 return WebKitPlatformWheelEvent(event, wheelScrollLines); 275} 276 277#if ENABLE(TOUCH_EVENTS) 278PlatformTouchEvent convertTouchEvent(QTouchEvent* event) 279{ 280 return WebKitPlatformTouchEvent(event); 281} 282#endif 283 284#if ENABLE(GESTURE_EVENTS) 285PlatformGestureEvent convertGesture(QGestureEventFacade* event) 286{ 287 return WebKitPlatformGestureEvent(event); 288} 289#endif 290} 291