1 /* 2 * Copyright (C) 2009 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include "config.h" 32 #include "web/WebInputEventConversion.h" 33 34 #include "core/dom/Touch.h" 35 #include "core/dom/TouchList.h" 36 #include "core/events/GestureEvent.h" 37 #include "core/events/KeyboardEvent.h" 38 #include "core/events/MouseEvent.h" 39 #include "core/events/TouchEvent.h" 40 #include "core/events/WheelEvent.h" 41 #include "core/frame/FrameHost.h" 42 #include "core/frame/FrameView.h" 43 #include "core/frame/PinchViewport.h" 44 #include "core/page/Page.h" 45 #include "core/rendering/RenderObject.h" 46 #include "platform/KeyboardCodes.h" 47 #include "platform/Widget.h" 48 #include "platform/scroll/ScrollView.h" 49 50 namespace blink { 51 52 static const double millisPerSecond = 1000.0; 53 54 static float widgetInputEventsScaleFactor(const Widget* widget) 55 { 56 if (!widget) 57 return 1; 58 59 ScrollView* rootView = toScrollView(widget->root()); 60 if (!rootView) 61 return 1; 62 63 return rootView->inputEventsScaleFactor(); 64 } 65 66 static IntSize widgetInputEventsOffset(const Widget* widget) 67 { 68 if (!widget) 69 return IntSize(); 70 ScrollView* rootView = toScrollView(widget->root()); 71 if (!rootView) 72 return IntSize(); 73 74 return rootView->inputEventsOffsetForEmulation(); 75 } 76 77 static IntPoint pinchViewportOffset(const Widget* widget) 78 { 79 // Event position needs to be adjusted by the pinch viewport's offset within the 80 // main frame before being passed into the widget's convertFromContainingWindow. 81 FrameView* rootView = toFrameView(widget->root()); 82 if (!rootView) 83 return IntPoint(); 84 85 return flooredIntPoint(rootView->page()->frameHost().pinchViewport().visibleRect().location()); 86 } 87 88 // MakePlatformMouseEvent ----------------------------------------------------- 89 90 PlatformMouseEventBuilder::PlatformMouseEventBuilder(Widget* widget, const WebMouseEvent& e) 91 { 92 float scale = widgetInputEventsScaleFactor(widget); 93 IntSize offset = widgetInputEventsOffset(widget); 94 IntPoint pinchViewport = pinchViewportOffset(widget); 95 96 // FIXME: Widget is always toplevel, unless it's a popup. We may be able 97 // to get rid of this once we abstract popups into a WebKit API. 98 m_position = widget->convertFromContainingWindow( 99 IntPoint((e.x - offset.width()) / scale + pinchViewport.x(), (e.y - offset.height()) / scale + pinchViewport.y())); 100 m_globalPosition = IntPoint(e.globalX, e.globalY); 101 m_movementDelta = IntPoint(e.movementX / scale, e.movementY / scale); 102 m_button = static_cast<MouseButton>(e.button); 103 104 m_modifiers = 0; 105 if (e.modifiers & WebInputEvent::ShiftKey) 106 m_modifiers |= PlatformEvent::ShiftKey; 107 if (e.modifiers & WebInputEvent::ControlKey) 108 m_modifiers |= PlatformEvent::CtrlKey; 109 if (e.modifiers & WebInputEvent::AltKey) 110 m_modifiers |= PlatformEvent::AltKey; 111 if (e.modifiers & WebInputEvent::MetaKey) 112 m_modifiers |= PlatformEvent::MetaKey; 113 114 m_modifierFlags = e.modifiers; 115 m_timestamp = e.timeStampSeconds; 116 m_clickCount = e.clickCount; 117 118 switch (e.type) { 119 case WebInputEvent::MouseMove: 120 case WebInputEvent::MouseLeave: // synthesize a move event 121 m_type = PlatformEvent::MouseMoved; 122 break; 123 124 case WebInputEvent::MouseDown: 125 m_type = PlatformEvent::MousePressed; 126 break; 127 128 case WebInputEvent::MouseUp: 129 m_type = PlatformEvent::MouseReleased; 130 break; 131 132 default: 133 ASSERT_NOT_REACHED(); 134 } 135 } 136 137 // PlatformWheelEventBuilder -------------------------------------------------- 138 139 PlatformWheelEventBuilder::PlatformWheelEventBuilder(Widget* widget, const WebMouseWheelEvent& e) 140 { 141 float scale = widgetInputEventsScaleFactor(widget); 142 IntSize offset = widgetInputEventsOffset(widget); 143 IntPoint pinchViewport = pinchViewportOffset(widget); 144 145 m_position = widget->convertFromContainingWindow( 146 IntPoint((e.x - offset.width()) / scale + pinchViewport.x(), (e.y - offset.height()) / scale + pinchViewport.y())); 147 m_globalPosition = IntPoint(e.globalX, e.globalY); 148 m_deltaX = e.deltaX; 149 m_deltaY = e.deltaY; 150 m_wheelTicksX = e.wheelTicksX; 151 m_wheelTicksY = e.wheelTicksY; 152 m_granularity = e.scrollByPage ? 153 ScrollByPageWheelEvent : ScrollByPixelWheelEvent; 154 155 m_type = PlatformEvent::Wheel; 156 157 m_modifiers = 0; 158 if (e.modifiers & WebInputEvent::ShiftKey) 159 m_modifiers |= PlatformEvent::ShiftKey; 160 if (e.modifiers & WebInputEvent::ControlKey) 161 m_modifiers |= PlatformEvent::CtrlKey; 162 if (e.modifiers & WebInputEvent::AltKey) 163 m_modifiers |= PlatformEvent::AltKey; 164 if (e.modifiers & WebInputEvent::MetaKey) 165 m_modifiers |= PlatformEvent::MetaKey; 166 167 m_hasPreciseScrollingDeltas = e.hasPreciseScrollingDeltas; 168 #if OS(MACOSX) 169 m_phase = static_cast<PlatformWheelEventPhase>(e.phase); 170 m_momentumPhase = static_cast<PlatformWheelEventPhase>(e.momentumPhase); 171 m_timestamp = e.timeStampSeconds; 172 m_scrollCount = 0; 173 m_unacceleratedScrollingDeltaX = e.deltaX; 174 m_unacceleratedScrollingDeltaY = e.deltaY; 175 m_canRubberbandLeft = e.canRubberbandLeft; 176 m_canRubberbandRight = e.canRubberbandRight; 177 #endif 178 } 179 180 // PlatformGestureEventBuilder -------------------------------------------------- 181 182 PlatformGestureEventBuilder::PlatformGestureEventBuilder(Widget* widget, const WebGestureEvent& e) 183 { 184 float scale = widgetInputEventsScaleFactor(widget); 185 IntSize offset = widgetInputEventsOffset(widget); 186 IntPoint pinchViewport = pinchViewportOffset(widget); 187 188 switch (e.type) { 189 case WebInputEvent::GestureScrollBegin: 190 m_type = PlatformEvent::GestureScrollBegin; 191 break; 192 case WebInputEvent::GestureScrollEnd: 193 m_type = PlatformEvent::GestureScrollEnd; 194 break; 195 case WebInputEvent::GestureFlingStart: 196 m_type = PlatformEvent::GestureFlingStart; 197 break; 198 case WebInputEvent::GestureScrollUpdate: 199 m_type = PlatformEvent::GestureScrollUpdate; 200 m_data.m_scrollUpdate.m_deltaX = e.data.scrollUpdate.deltaX / scale; 201 m_data.m_scrollUpdate.m_deltaY = e.data.scrollUpdate.deltaY / scale; 202 m_data.m_scrollUpdate.m_velocityX = e.data.scrollUpdate.velocityX; 203 m_data.m_scrollUpdate.m_velocityY = e.data.scrollUpdate.velocityY; 204 break; 205 case WebInputEvent::GestureScrollUpdateWithoutPropagation: 206 m_type = PlatformEvent::GestureScrollUpdateWithoutPropagation; 207 m_data.m_scrollUpdate.m_deltaX = e.data.scrollUpdate.deltaX / scale; 208 m_data.m_scrollUpdate.m_deltaY = e.data.scrollUpdate.deltaY / scale; 209 m_data.m_scrollUpdate.m_velocityX = e.data.scrollUpdate.velocityX; 210 m_data.m_scrollUpdate.m_velocityY = e.data.scrollUpdate.velocityY; 211 break; 212 case WebInputEvent::GestureTap: 213 m_type = PlatformEvent::GestureTap; 214 m_area = expandedIntSize(FloatSize(e.data.tap.width / scale, e.data.tap.height / scale)); 215 m_data.m_tap.m_tapCount = e.data.tap.tapCount; 216 break; 217 case WebInputEvent::GestureTapUnconfirmed: 218 m_type = PlatformEvent::GestureTapUnconfirmed; 219 m_area = expandedIntSize(FloatSize(e.data.tap.width / scale, e.data.tap.height / scale)); 220 break; 221 case WebInputEvent::GestureTapDown: 222 m_type = PlatformEvent::GestureTapDown; 223 m_area = expandedIntSize(FloatSize(e.data.tapDown.width / scale, e.data.tapDown.height / scale)); 224 break; 225 case WebInputEvent::GestureShowPress: 226 m_type = PlatformEvent::GestureShowPress; 227 m_area = expandedIntSize(FloatSize(e.data.showPress.width / scale, e.data.showPress.height / scale)); 228 break; 229 case WebInputEvent::GestureTapCancel: 230 m_type = PlatformEvent::GestureTapDownCancel; 231 break; 232 case WebInputEvent::GestureDoubleTap: 233 // DoubleTap gesture is now handled as PlatformEvent::GestureTap with tap_count = 2. So no 234 // need to convert to a Platfrom DoubleTap gesture. But in WebViewImpl::handleGestureEvent 235 // all WebGestureEvent are converted to PlatformGestureEvent, for completeness and not reach 236 // the ASSERT_NOT_REACHED() at the end, convert the DoubleTap to a NoType. 237 m_type = PlatformEvent::NoType; 238 break; 239 case WebInputEvent::GestureTwoFingerTap: 240 m_type = PlatformEvent::GestureTwoFingerTap; 241 m_area = expandedIntSize(FloatSize(e.data.twoFingerTap.firstFingerWidth / scale, e.data.twoFingerTap.firstFingerHeight / scale)); 242 break; 243 case WebInputEvent::GestureLongPress: 244 m_type = PlatformEvent::GestureLongPress; 245 m_area = expandedIntSize(FloatSize(e.data.longPress.width / scale, e.data.longPress.height / scale)); 246 break; 247 case WebInputEvent::GestureLongTap: 248 m_type = PlatformEvent::GestureLongTap; 249 m_area = expandedIntSize(FloatSize(e.data.longPress.width / scale, e.data.longPress.height / scale)); 250 break; 251 case WebInputEvent::GesturePinchBegin: 252 m_type = PlatformEvent::GesturePinchBegin; 253 break; 254 case WebInputEvent::GesturePinchEnd: 255 m_type = PlatformEvent::GesturePinchEnd; 256 break; 257 case WebInputEvent::GesturePinchUpdate: 258 m_type = PlatformEvent::GesturePinchUpdate; 259 m_data.m_pinchUpdate.m_scale = e.data.pinchUpdate.scale; 260 break; 261 default: 262 ASSERT_NOT_REACHED(); 263 } 264 m_position = widget->convertFromContainingWindow( 265 IntPoint((e.x - offset.width()) / scale + pinchViewport.x(), (e.y - offset.height()) / scale + pinchViewport.y())); 266 m_globalPosition = IntPoint(e.globalX, e.globalY); 267 m_timestamp = e.timeStampSeconds; 268 269 m_modifiers = 0; 270 if (e.modifiers & WebInputEvent::ShiftKey) 271 m_modifiers |= PlatformEvent::ShiftKey; 272 if (e.modifiers & WebInputEvent::ControlKey) 273 m_modifiers |= PlatformEvent::CtrlKey; 274 if (e.modifiers & WebInputEvent::AltKey) 275 m_modifiers |= PlatformEvent::AltKey; 276 if (e.modifiers & WebInputEvent::MetaKey) 277 m_modifiers |= PlatformEvent::MetaKey; 278 } 279 280 // MakePlatformKeyboardEvent -------------------------------------------------- 281 282 inline PlatformEvent::Type toPlatformKeyboardEventType(WebInputEvent::Type type) 283 { 284 switch (type) { 285 case WebInputEvent::KeyUp: 286 return PlatformEvent::KeyUp; 287 case WebInputEvent::KeyDown: 288 return PlatformEvent::KeyDown; 289 case WebInputEvent::RawKeyDown: 290 return PlatformEvent::RawKeyDown; 291 case WebInputEvent::Char: 292 return PlatformEvent::Char; 293 default: 294 ASSERT_NOT_REACHED(); 295 } 296 return PlatformEvent::KeyDown; 297 } 298 299 PlatformKeyboardEventBuilder::PlatformKeyboardEventBuilder(const WebKeyboardEvent& e) 300 { 301 m_type = toPlatformKeyboardEventType(e.type); 302 m_text = String(e.text); 303 m_unmodifiedText = String(e.unmodifiedText); 304 m_keyIdentifier = String(e.keyIdentifier); 305 m_autoRepeat = (e.modifiers & WebInputEvent::IsAutoRepeat); 306 m_nativeVirtualKeyCode = e.nativeKeyCode; 307 m_isKeypad = (e.modifiers & WebInputEvent::IsKeyPad); 308 m_isSystemKey = e.isSystemKey; 309 310 m_modifiers = 0; 311 if (e.modifiers & WebInputEvent::ShiftKey) 312 m_modifiers |= PlatformEvent::ShiftKey; 313 if (e.modifiers & WebInputEvent::ControlKey) 314 m_modifiers |= PlatformEvent::CtrlKey; 315 if (e.modifiers & WebInputEvent::AltKey) 316 m_modifiers |= PlatformEvent::AltKey; 317 if (e.modifiers & WebInputEvent::MetaKey) 318 m_modifiers |= PlatformEvent::MetaKey; 319 320 // FIXME: PlatformKeyboardEvents expect a locational version of the keycode (e.g. VK_LSHIFT 321 // instead of VK_SHIFT). This should be changed so the location/keycode are stored separately, 322 // as in other places in the code. 323 m_windowsVirtualKeyCode = e.windowsKeyCode; 324 if (e.windowsKeyCode == VK_SHIFT) { 325 if (e.modifiers & WebInputEvent::IsLeft) 326 m_windowsVirtualKeyCode = VK_LSHIFT; 327 else if (e.modifiers & WebInputEvent::IsRight) 328 m_windowsVirtualKeyCode = VK_RSHIFT; 329 } else if (e.windowsKeyCode == VK_CONTROL) { 330 if (e.modifiers & WebInputEvent::IsLeft) 331 m_windowsVirtualKeyCode = VK_LCONTROL; 332 else if (e.modifiers & WebInputEvent::IsRight) 333 m_windowsVirtualKeyCode = VK_RCONTROL; 334 } else if (e.windowsKeyCode == VK_MENU) { 335 if (e.modifiers & WebInputEvent::IsLeft) 336 m_windowsVirtualKeyCode = VK_LMENU; 337 else if (e.modifiers & WebInputEvent::IsRight) 338 m_windowsVirtualKeyCode = VK_RMENU; 339 } 340 341 } 342 343 void PlatformKeyboardEventBuilder::setKeyType(Type type) 344 { 345 // According to the behavior of Webkit in Windows platform, 346 // we need to convert KeyDown to RawKeydown and Char events 347 // See WebKit/WebKit/Win/WebView.cpp 348 ASSERT(m_type == KeyDown); 349 ASSERT(type == RawKeyDown || type == Char); 350 m_type = type; 351 352 if (type == RawKeyDown) { 353 m_text = String(); 354 m_unmodifiedText = String(); 355 } else { 356 m_keyIdentifier = String(); 357 m_windowsVirtualKeyCode = 0; 358 } 359 } 360 361 // Please refer to bug http://b/issue?id=961192, which talks about Webkit 362 // keyboard event handling changes. It also mentions the list of keys 363 // which don't have associated character events. 364 bool PlatformKeyboardEventBuilder::isCharacterKey() const 365 { 366 switch (windowsVirtualKeyCode()) { 367 case VKEY_BACK: 368 case VKEY_ESCAPE: 369 return false; 370 } 371 return true; 372 } 373 374 inline PlatformEvent::Type toPlatformTouchEventType(const WebInputEvent::Type type) 375 { 376 switch (type) { 377 case WebInputEvent::TouchStart: 378 return PlatformEvent::TouchStart; 379 case WebInputEvent::TouchMove: 380 return PlatformEvent::TouchMove; 381 case WebInputEvent::TouchEnd: 382 return PlatformEvent::TouchEnd; 383 case WebInputEvent::TouchCancel: 384 return PlatformEvent::TouchCancel; 385 default: 386 ASSERT_NOT_REACHED(); 387 } 388 return PlatformEvent::TouchStart; 389 } 390 391 inline PlatformTouchPoint::State toPlatformTouchPointState(const WebTouchPoint::State state) 392 { 393 switch (state) { 394 case WebTouchPoint::StateReleased: 395 return PlatformTouchPoint::TouchReleased; 396 case WebTouchPoint::StatePressed: 397 return PlatformTouchPoint::TouchPressed; 398 case WebTouchPoint::StateMoved: 399 return PlatformTouchPoint::TouchMoved; 400 case WebTouchPoint::StateStationary: 401 return PlatformTouchPoint::TouchStationary; 402 case WebTouchPoint::StateCancelled: 403 return PlatformTouchPoint::TouchCancelled; 404 case WebTouchPoint::StateUndefined: 405 ASSERT_NOT_REACHED(); 406 } 407 return PlatformTouchPoint::TouchReleased; 408 } 409 410 inline WebTouchPoint::State toWebTouchPointState(const AtomicString& type) 411 { 412 if (type == EventTypeNames::touchend) 413 return WebTouchPoint::StateReleased; 414 if (type == EventTypeNames::touchcancel) 415 return WebTouchPoint::StateCancelled; 416 if (type == EventTypeNames::touchstart) 417 return WebTouchPoint::StatePressed; 418 if (type == EventTypeNames::touchmove) 419 return WebTouchPoint::StateMoved; 420 return WebTouchPoint::StateUndefined; 421 } 422 423 PlatformTouchPointBuilder::PlatformTouchPointBuilder(Widget* widget, const WebTouchPoint& point) 424 { 425 float scale = 1.0f / widgetInputEventsScaleFactor(widget); 426 IntSize offset = widgetInputEventsOffset(widget); 427 IntPoint pinchViewport = pinchViewportOffset(widget); 428 m_id = point.id; 429 m_state = toPlatformTouchPointState(point.state); 430 FloatPoint pos = (point.position - offset).scaledBy(scale); 431 pos.moveBy(pinchViewport); 432 IntPoint flooredPoint = flooredIntPoint(pos); 433 // This assumes convertFromContainingWindow does only translations, not scales. 434 m_pos = widget->convertFromContainingWindow(flooredPoint) + (pos - flooredPoint); 435 m_screenPos = FloatPoint(point.screenPosition.x, point.screenPosition.y); 436 m_radius = FloatSize(point.radiusX, point.radiusY).scaledBy(scale); 437 m_rotationAngle = point.rotationAngle; 438 m_force = point.force; 439 } 440 441 PlatformTouchEventBuilder::PlatformTouchEventBuilder(Widget* widget, const WebTouchEvent& event) 442 { 443 m_type = toPlatformTouchEventType(event.type); 444 445 m_modifiers = 0; 446 if (event.modifiers & WebInputEvent::ShiftKey) 447 m_modifiers |= PlatformEvent::ShiftKey; 448 if (event.modifiers & WebInputEvent::ControlKey) 449 m_modifiers |= PlatformEvent::CtrlKey; 450 if (event.modifiers & WebInputEvent::AltKey) 451 m_modifiers |= PlatformEvent::AltKey; 452 if (event.modifiers & WebInputEvent::MetaKey) 453 m_modifiers |= PlatformEvent::MetaKey; 454 455 m_timestamp = event.timeStampSeconds; 456 457 for (unsigned i = 0; i < event.touchesLength; ++i) 458 m_touchPoints.append(PlatformTouchPointBuilder(widget, event.touches[i])); 459 460 m_cancelable = event.cancelable; 461 } 462 463 static int getWebInputModifiers(const UIEventWithKeyState& event) 464 { 465 int modifiers = 0; 466 if (event.ctrlKey()) 467 modifiers |= WebInputEvent::ControlKey; 468 if (event.shiftKey()) 469 modifiers |= WebInputEvent::ShiftKey; 470 if (event.altKey()) 471 modifiers |= WebInputEvent::AltKey; 472 if (event.metaKey()) 473 modifiers |= WebInputEvent::MetaKey; 474 return modifiers; 475 } 476 477 static FloatPoint convertAbsoluteLocationForRenderObjectFloat(const LayoutPoint& location, const RenderObject& renderObject) 478 { 479 return renderObject.absoluteToLocal(location, UseTransforms); 480 } 481 482 static IntPoint convertAbsoluteLocationForRenderObject(const LayoutPoint& location, const RenderObject& renderObject) 483 { 484 return roundedIntPoint(convertAbsoluteLocationForRenderObjectFloat(location, renderObject)); 485 } 486 487 static void updateWebMouseEventFromCoreMouseEvent(const MouseRelatedEvent& event, const Widget& widget, const RenderObject& renderObject, WebMouseEvent& webEvent) 488 { 489 webEvent.timeStampSeconds = event.timeStamp() / millisPerSecond; 490 webEvent.modifiers = getWebInputModifiers(event); 491 492 ScrollView* view = toScrollView(widget.parent()); 493 IntPoint windowPoint = IntPoint(event.absoluteLocation().x(), event.absoluteLocation().y()); 494 if (view) 495 windowPoint = view->contentsToWindow(windowPoint); 496 webEvent.globalX = event.screenX(); 497 webEvent.globalY = event.screenY(); 498 webEvent.windowX = windowPoint.x(); 499 webEvent.windowY = windowPoint.y(); 500 IntPoint localPoint = convertAbsoluteLocationForRenderObject(event.absoluteLocation(), renderObject); 501 webEvent.x = localPoint.x(); 502 webEvent.y = localPoint.y(); 503 } 504 505 WebMouseEventBuilder::WebMouseEventBuilder(const Widget* widget, const RenderObject* renderObject, const MouseEvent& event) 506 { 507 if (event.type() == EventTypeNames::mousemove) 508 type = WebInputEvent::MouseMove; 509 else if (event.type() == EventTypeNames::mouseout) 510 type = WebInputEvent::MouseLeave; 511 else if (event.type() == EventTypeNames::mouseover) 512 type = WebInputEvent::MouseEnter; 513 else if (event.type() == EventTypeNames::mousedown) 514 type = WebInputEvent::MouseDown; 515 else if (event.type() == EventTypeNames::mouseup) 516 type = WebInputEvent::MouseUp; 517 else if (event.type() == EventTypeNames::contextmenu) 518 type = WebInputEvent::ContextMenu; 519 else 520 return; // Skip all other mouse events. 521 522 updateWebMouseEventFromCoreMouseEvent(event, *widget, *renderObject, *this); 523 524 switch (event.button()) { 525 case LeftButton: 526 button = WebMouseEvent::ButtonLeft; 527 break; 528 case MiddleButton: 529 button = WebMouseEvent::ButtonMiddle; 530 break; 531 case RightButton: 532 button = WebMouseEvent::ButtonRight; 533 break; 534 } 535 if (event.buttonDown()) { 536 switch (event.button()) { 537 case LeftButton: 538 modifiers |= WebInputEvent::LeftButtonDown; 539 break; 540 case MiddleButton: 541 modifiers |= WebInputEvent::MiddleButtonDown; 542 break; 543 case RightButton: 544 modifiers |= WebInputEvent::RightButtonDown; 545 break; 546 } 547 } else 548 button = WebMouseEvent::ButtonNone; 549 movementX = event.movementX(); 550 movementY = event.movementY(); 551 clickCount = event.detail(); 552 } 553 554 // Generate a synthetic WebMouseEvent given a TouchEvent (eg. for emulating a mouse 555 // with touch input for plugins that don't support touch input). 556 WebMouseEventBuilder::WebMouseEventBuilder(const Widget* widget, const RenderObject* renderObject, const TouchEvent& event) 557 { 558 if (!event.touches()) 559 return; 560 if (event.touches()->length() != 1) { 561 if (event.touches()->length() || event.type() != EventTypeNames::touchend || !event.changedTouches() || event.changedTouches()->length() != 1) 562 return; 563 } 564 565 const Touch* touch = event.touches()->length() == 1 ? event.touches()->item(0) : event.changedTouches()->item(0); 566 if (touch->identifier()) 567 return; 568 569 if (event.type() == EventTypeNames::touchstart) 570 type = MouseDown; 571 else if (event.type() == EventTypeNames::touchmove) 572 type = MouseMove; 573 else if (event.type() == EventTypeNames::touchend) 574 type = MouseUp; 575 else 576 return; 577 578 timeStampSeconds = event.timeStamp() / millisPerSecond; 579 modifiers = getWebInputModifiers(event); 580 581 // The mouse event co-ordinates should be generated from the co-ordinates of the touch point. 582 ScrollView* view = toScrollView(widget->parent()); 583 IntPoint windowPoint = roundedIntPoint(touch->absoluteLocation()); 584 if (view) 585 windowPoint = view->contentsToWindow(windowPoint); 586 IntPoint screenPoint = roundedIntPoint(touch->screenLocation()); 587 globalX = screenPoint.x(); 588 globalY = screenPoint.y(); 589 windowX = windowPoint.x(); 590 windowY = windowPoint.y(); 591 592 button = WebMouseEvent::ButtonLeft; 593 modifiers |= WebInputEvent::LeftButtonDown; 594 clickCount = (type == MouseDown || type == MouseUp); 595 596 IntPoint localPoint = convertAbsoluteLocationForRenderObject(touch->absoluteLocation(), *renderObject); 597 x = localPoint.x(); 598 y = localPoint.y(); 599 } 600 601 WebMouseEventBuilder::WebMouseEventBuilder(const Widget* widget, const PlatformMouseEvent& event) 602 { 603 switch (event.type()) { 604 case PlatformEvent::MouseMoved: 605 type = MouseMove; 606 break; 607 case PlatformEvent::MousePressed: 608 type = MouseDown; 609 break; 610 case PlatformEvent::MouseReleased: 611 type = MouseUp; 612 break; 613 default: 614 ASSERT_NOT_REACHED(); 615 type = Undefined; 616 return; 617 } 618 619 modifiers = 0; 620 if (event.modifiers() & PlatformEvent::ShiftKey) 621 modifiers |= ShiftKey; 622 if (event.modifiers() & PlatformEvent::CtrlKey) 623 modifiers |= ControlKey; 624 if (event.modifiers() & PlatformEvent::AltKey) 625 modifiers |= AltKey; 626 if (event.modifiers() & PlatformEvent::MetaKey) 627 modifiers |= MetaKey; 628 629 timeStampSeconds = event.timestamp(); 630 631 // FIXME: Widget is always toplevel, unless it's a popup. We may be able 632 // to get rid of this once we abstract popups into a WebKit API. 633 IntPoint position = widget->convertToContainingWindow(event.position()); 634 float scale = widgetInputEventsScaleFactor(widget); 635 position.scale(scale, scale); 636 x = position.x(); 637 y = position.y(); 638 globalX = event.globalPosition().x(); 639 globalY = event.globalPosition().y(); 640 movementX = event.movementDelta().x() * scale; 641 movementY = event.movementDelta().y() * scale; 642 643 button = static_cast<Button>(event.button()); 644 clickCount = event.clickCount(); 645 } 646 647 WebMouseWheelEventBuilder::WebMouseWheelEventBuilder(const Widget* widget, const RenderObject* renderObject, const WheelEvent& event) 648 { 649 if (event.type() != EventTypeNames::wheel && event.type() != EventTypeNames::mousewheel) 650 return; 651 type = WebInputEvent::MouseWheel; 652 updateWebMouseEventFromCoreMouseEvent(event, *widget, *renderObject, *this); 653 deltaX = -event.deltaX(); 654 deltaY = -event.deltaY(); 655 wheelTicksX = event.ticksX(); 656 wheelTicksY = event.ticksY(); 657 scrollByPage = event.deltaMode() == WheelEvent::DOM_DELTA_PAGE; 658 } 659 660 WebKeyboardEventBuilder::WebKeyboardEventBuilder(const KeyboardEvent& event) 661 { 662 if (event.type() == EventTypeNames::keydown) 663 type = KeyDown; 664 else if (event.type() == EventTypeNames::keyup) 665 type = WebInputEvent::KeyUp; 666 else if (event.type() == EventTypeNames::keypress) 667 type = WebInputEvent::Char; 668 else 669 return; // Skip all other keyboard events. 670 671 modifiers = getWebInputModifiers(event); 672 if (event.location() == KeyboardEvent::DOM_KEY_LOCATION_NUMPAD) 673 modifiers |= WebInputEvent::IsKeyPad; 674 else if (event.location() == KeyboardEvent::DOM_KEY_LOCATION_LEFT) 675 modifiers |= WebInputEvent::IsLeft; 676 else if (event.location() == KeyboardEvent::DOM_KEY_LOCATION_RIGHT) 677 modifiers |= WebInputEvent::IsRight; 678 679 timeStampSeconds = event.timeStamp() / millisPerSecond; 680 windowsKeyCode = event.keyCode(); 681 682 // The platform keyevent does not exist if the event was created using 683 // initKeyboardEvent. 684 if (!event.keyEvent()) 685 return; 686 nativeKeyCode = event.keyEvent()->nativeVirtualKeyCode(); 687 unsigned numberOfCharacters = std::min(event.keyEvent()->text().length(), static_cast<unsigned>(textLengthCap)); 688 for (unsigned i = 0; i < numberOfCharacters; ++i) { 689 text[i] = event.keyEvent()->text()[i]; 690 unmodifiedText[i] = event.keyEvent()->unmodifiedText()[i]; 691 } 692 memcpy(keyIdentifier, event.keyIdentifier().ascii().data(), event.keyIdentifier().length()); 693 } 694 695 WebInputEvent::Type toWebKeyboardEventType(PlatformEvent::Type type) 696 { 697 switch (type) { 698 case PlatformEvent::KeyUp: 699 return WebInputEvent::KeyUp; 700 case PlatformEvent::KeyDown: 701 return WebInputEvent::KeyDown; 702 case PlatformEvent::RawKeyDown: 703 return WebInputEvent::RawKeyDown; 704 case PlatformEvent::Char: 705 return WebInputEvent::Char; 706 default: 707 return WebInputEvent::Undefined; 708 } 709 } 710 711 int toWebKeyboardEventModifiers(int modifiers) 712 { 713 int newModifiers = 0; 714 if (modifiers & PlatformEvent::ShiftKey) 715 newModifiers |= WebInputEvent::ShiftKey; 716 if (modifiers & PlatformEvent::CtrlKey) 717 newModifiers |= WebInputEvent::ControlKey; 718 if (modifiers & PlatformEvent::AltKey) 719 newModifiers |= WebInputEvent::AltKey; 720 if (modifiers & PlatformEvent::MetaKey) 721 newModifiers |= WebInputEvent::MetaKey; 722 return newModifiers; 723 } 724 725 WebKeyboardEventBuilder::WebKeyboardEventBuilder(const PlatformKeyboardEvent& event) 726 { 727 type = toWebKeyboardEventType(event.type()); 728 modifiers = toWebKeyboardEventModifiers(event.modifiers()); 729 if (event.isAutoRepeat()) 730 modifiers |= WebInputEvent::IsAutoRepeat; 731 if (event.isKeypad()) 732 modifiers |= WebInputEvent::IsKeyPad; 733 isSystemKey = event.isSystemKey(); 734 nativeKeyCode = event.nativeVirtualKeyCode(); 735 736 windowsKeyCode = windowsKeyCodeWithoutLocation(event.windowsVirtualKeyCode()); 737 modifiers |= locationModifiersFromWindowsKeyCode(event.windowsVirtualKeyCode()); 738 739 event.text().copyTo(text, 0, textLengthCap); 740 event.unmodifiedText().copyTo(unmodifiedText, 0, textLengthCap); 741 memcpy(keyIdentifier, event.keyIdentifier().ascii().data(), std::min(static_cast<unsigned>(keyIdentifierLengthCap), event.keyIdentifier().length())); 742 } 743 744 static WebTouchPoint toWebTouchPoint(const Touch* touch, const RenderObject* renderObject, WebTouchPoint::State state) 745 { 746 WebTouchPoint point; 747 point.id = touch->identifier(); 748 point.screenPosition = touch->screenLocation(); 749 point.position = convertAbsoluteLocationForRenderObjectFloat(touch->absoluteLocation(), *renderObject); 750 point.radiusX = touch->radiusX(); 751 point.radiusY = touch->radiusY(); 752 point.rotationAngle = touch->webkitRotationAngle(); 753 point.force = touch->force(); 754 point.state = state; 755 return point; 756 } 757 758 static bool hasTouchPointWithId(const WebTouchPoint* touchPoints, unsigned touchPointsLength, unsigned id) 759 { 760 for (unsigned i = 0; i < touchPointsLength; ++i) { 761 if (touchPoints[i].id == static_cast<int>(id)) 762 return true; 763 } 764 return false; 765 } 766 767 static void addTouchPointsIfNotYetAdded(const Widget* widget, WebTouchPoint::State state, TouchList* touches, WebTouchPoint* touchPoints, unsigned* touchPointsLength, const RenderObject* renderObject) 768 { 769 unsigned initialTouchPointsLength = *touchPointsLength; 770 for (unsigned i = 0; i < touches->length(); ++i) { 771 const unsigned pointIndex = *touchPointsLength; 772 if (pointIndex >= static_cast<unsigned>(WebTouchEvent::touchesLengthCap)) 773 return; 774 775 const Touch* touch = touches->item(i); 776 if (hasTouchPointWithId(touchPoints, initialTouchPointsLength, touch->identifier())) 777 continue; 778 779 touchPoints[pointIndex] = toWebTouchPoint(touch, renderObject, state); 780 ++(*touchPointsLength); 781 } 782 } 783 784 WebTouchEventBuilder::WebTouchEventBuilder(const Widget* widget, const RenderObject* renderObject, const TouchEvent& event) 785 { 786 if (event.type() == EventTypeNames::touchstart) 787 type = TouchStart; 788 else if (event.type() == EventTypeNames::touchmove) 789 type = TouchMove; 790 else if (event.type() == EventTypeNames::touchend) 791 type = TouchEnd; 792 else if (event.type() == EventTypeNames::touchcancel) 793 type = TouchCancel; 794 else { 795 ASSERT_NOT_REACHED(); 796 type = Undefined; 797 return; 798 } 799 800 modifiers = getWebInputModifiers(event); 801 timeStampSeconds = event.timeStamp() / millisPerSecond; 802 cancelable = event.cancelable(); 803 804 addTouchPointsIfNotYetAdded(widget, toWebTouchPointState(event.type()), event.changedTouches(), touches, &touchesLength, renderObject); 805 addTouchPointsIfNotYetAdded(widget, WebTouchPoint::StateStationary, event.touches(), touches, &touchesLength, renderObject); 806 } 807 808 WebGestureEventBuilder::WebGestureEventBuilder(const Widget* widget, const RenderObject* renderObject, const GestureEvent& event) 809 { 810 if (event.type() == EventTypeNames::gestureshowpress) 811 type = GestureShowPress; 812 else if (event.type() == EventTypeNames::gesturetapdown) 813 type = GestureTapDown; 814 else if (event.type() == EventTypeNames::gesturescrollstart) 815 type = GestureScrollBegin; 816 else if (event.type() == EventTypeNames::gesturescrollend) 817 type = GestureScrollEnd; 818 else if (event.type() == EventTypeNames::gesturescrollupdate) { 819 type = GestureScrollUpdate; 820 data.scrollUpdate.deltaX = event.deltaX(); 821 data.scrollUpdate.deltaY = event.deltaY(); 822 } else if (event.type() == EventTypeNames::gesturetap) { 823 type = GestureTap; 824 data.tap.tapCount = 1; 825 } 826 827 timeStampSeconds = event.timeStamp() / millisPerSecond; 828 modifiers = getWebInputModifiers(event); 829 830 globalX = event.screenX(); 831 globalY = event.screenY(); 832 IntPoint localPoint = convertAbsoluteLocationForRenderObject(event.absoluteLocation(), *renderObject); 833 x = localPoint.x(); 834 y = localPoint.y(); 835 } 836 837 } // namespace blink 838