ui_events_helper.cc revision cedac228d2dd51db4b79ea1e72c7f249408ee061
1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "content/browser/renderer_host/ui_events_helper.h" 6 7#include "content/common/input/web_touch_event_traits.h" 8#include "third_party/WebKit/public/web/WebInputEvent.h" 9#include "ui/events/event.h" 10#include "ui/events/event_constants.h" 11 12namespace { 13 14int WebModifiersToUIFlags(int modifiers) { 15 int flags = ui::EF_NONE; 16 17 if (modifiers & blink::WebInputEvent::ShiftKey) 18 flags |= ui::EF_SHIFT_DOWN; 19 if (modifiers & blink::WebInputEvent::ControlKey) 20 flags |= ui::EF_CONTROL_DOWN; 21 if (modifiers & blink::WebInputEvent::AltKey) 22 flags |= ui::EF_ALT_DOWN; 23 24 if (modifiers & blink::WebInputEvent::LeftButtonDown) 25 flags |= ui::EF_LEFT_MOUSE_BUTTON; 26 if (modifiers & blink::WebInputEvent::RightButtonDown) 27 flags |= ui::EF_RIGHT_MOUSE_BUTTON; 28 if (modifiers & blink::WebInputEvent::MiddleButtonDown) 29 flags |= ui::EF_MIDDLE_MOUSE_BUTTON; 30 31 if (modifiers & blink::WebInputEvent::CapsLockOn) 32 flags |= ui::EF_CAPS_LOCK_DOWN; 33 34 return flags; 35} 36 37ui::EventType WebTouchPointStateToEventType( 38 blink::WebTouchPoint::State state) { 39 switch (state) { 40 case blink::WebTouchPoint::StateReleased: 41 return ui::ET_TOUCH_RELEASED; 42 43 case blink::WebTouchPoint::StatePressed: 44 return ui::ET_TOUCH_PRESSED; 45 46 case blink::WebTouchPoint::StateMoved: 47 return ui::ET_TOUCH_MOVED; 48 49 case blink::WebTouchPoint::StateCancelled: 50 return ui::ET_TOUCH_CANCELLED; 51 52 default: 53 return ui::ET_UNKNOWN; 54 } 55} 56 57blink::WebTouchPoint::State TouchPointStateFromEvent( 58 const ui::TouchEvent& event) { 59 switch (event.type()) { 60 case ui::ET_TOUCH_PRESSED: 61 return blink::WebTouchPoint::StatePressed; 62 case ui::ET_TOUCH_RELEASED: 63 return blink::WebTouchPoint::StateReleased; 64 case ui::ET_TOUCH_MOVED: 65 return blink::WebTouchPoint::StateMoved; 66 case ui::ET_TOUCH_CANCELLED: 67 return blink::WebTouchPoint::StateCancelled; 68 default: 69 return blink::WebTouchPoint::StateUndefined; 70 } 71} 72 73blink::WebInputEvent::Type TouchEventTypeFromEvent( 74 const ui::TouchEvent& event) { 75 switch (event.type()) { 76 case ui::ET_TOUCH_PRESSED: 77 return blink::WebInputEvent::TouchStart; 78 case ui::ET_TOUCH_RELEASED: 79 return blink::WebInputEvent::TouchEnd; 80 case ui::ET_TOUCH_MOVED: 81 return blink::WebInputEvent::TouchMove; 82 case ui::ET_TOUCH_CANCELLED: 83 return blink::WebInputEvent::TouchCancel; 84 default: 85 return blink::WebInputEvent::Undefined; 86 } 87} 88 89} // namespace 90 91namespace content { 92 93bool MakeUITouchEventsFromWebTouchEvents( 94 const TouchEventWithLatencyInfo& touch_with_latency, 95 ScopedVector<ui::TouchEvent>* list, 96 TouchEventCoordinateSystem coordinate_system) { 97 const blink::WebTouchEvent& touch = touch_with_latency.event; 98 ui::EventType type = ui::ET_UNKNOWN; 99 switch (touch.type) { 100 case blink::WebInputEvent::TouchStart: 101 type = ui::ET_TOUCH_PRESSED; 102 break; 103 case blink::WebInputEvent::TouchEnd: 104 type = ui::ET_TOUCH_RELEASED; 105 break; 106 case blink::WebInputEvent::TouchMove: 107 type = ui::ET_TOUCH_MOVED; 108 break; 109 case blink::WebInputEvent::TouchCancel: 110 type = ui::ET_TOUCH_CANCELLED; 111 break; 112 default: 113 NOTREACHED(); 114 return false; 115 } 116 117 int flags = WebModifiersToUIFlags(touch.modifiers); 118 base::TimeDelta timestamp = base::TimeDelta::FromMicroseconds( 119 static_cast<int64>(touch.timeStampSeconds * 1000000)); 120 for (unsigned i = 0; i < touch.touchesLength; ++i) { 121 const blink::WebTouchPoint& point = touch.touches[i]; 122 if (WebTouchPointStateToEventType(point.state) != type) 123 continue; 124 // ui events start in the co-ordinate space of the EventDispatcher. 125 gfx::PointF location; 126 if (coordinate_system == LOCAL_COORDINATES) 127 location = point.position; 128 else 129 location = point.screenPosition; 130 ui::TouchEvent* uievent = new ui::TouchEvent(type, 131 location, 132 flags, 133 point.id, 134 timestamp, 135 point.radiusX, 136 point.radiusY, 137 point.rotationAngle, 138 point.force); 139 uievent->set_latency(touch_with_latency.latency); 140 list->push_back(uievent); 141 } 142 return true; 143} 144 145blink::WebGestureEvent MakeWebGestureEventFromUIEvent( 146 const ui::GestureEvent& event) { 147 blink::WebGestureEvent gesture_event; 148 149 switch (event.type()) { 150 case ui::ET_GESTURE_TAP: 151 gesture_event.type = blink::WebInputEvent::GestureTap; 152 gesture_event.data.tap.tapCount = event.details().tap_count(); 153 gesture_event.data.tap.width = event.details().bounding_box().width(); 154 gesture_event.data.tap.height = event.details().bounding_box().height(); 155 break; 156 case ui::ET_GESTURE_TAP_DOWN: 157 gesture_event.type = blink::WebInputEvent::GestureTapDown; 158 gesture_event.data.tapDown.width = 159 event.details().bounding_box().width(); 160 gesture_event.data.tapDown.height = 161 event.details().bounding_box().height(); 162 break; 163 case ui::ET_GESTURE_SHOW_PRESS: 164 gesture_event.type = blink::WebInputEvent::GestureShowPress; 165 gesture_event.data.showPress.width = 166 event.details().bounding_box().width(); 167 gesture_event.data.showPress.height = 168 event.details().bounding_box().height(); 169 break; 170 case ui::ET_GESTURE_TAP_CANCEL: 171 gesture_event.type = blink::WebInputEvent::GestureTapCancel; 172 break; 173 case ui::ET_GESTURE_SCROLL_BEGIN: 174 gesture_event.type = blink::WebInputEvent::GestureScrollBegin; 175 gesture_event.data.scrollBegin.deltaXHint = 176 event.details().scroll_x_hint(); 177 gesture_event.data.scrollBegin.deltaYHint = 178 event.details().scroll_y_hint(); 179 break; 180 case ui::ET_GESTURE_SCROLL_UPDATE: 181 gesture_event.type = blink::WebInputEvent::GestureScrollUpdate; 182 gesture_event.data.scrollUpdate.deltaX = event.details().scroll_x(); 183 gesture_event.data.scrollUpdate.deltaY = event.details().scroll_y(); 184 break; 185 case ui::ET_GESTURE_SCROLL_END: 186 gesture_event.type = blink::WebInputEvent::GestureScrollEnd; 187 break; 188 case ui::ET_GESTURE_PINCH_BEGIN: 189 gesture_event.type = blink::WebInputEvent::GesturePinchBegin; 190 break; 191 case ui::ET_GESTURE_PINCH_UPDATE: 192 gesture_event.type = blink::WebInputEvent::GesturePinchUpdate; 193 gesture_event.data.pinchUpdate.scale = event.details().scale(); 194 break; 195 case ui::ET_GESTURE_PINCH_END: 196 gesture_event.type = blink::WebInputEvent::GesturePinchEnd; 197 break; 198 case ui::ET_SCROLL_FLING_START: 199 gesture_event.type = blink::WebInputEvent::GestureFlingStart; 200 gesture_event.data.flingStart.velocityX = event.details().velocity_x(); 201 gesture_event.data.flingStart.velocityY = event.details().velocity_y(); 202 break; 203 case ui::ET_SCROLL_FLING_CANCEL: 204 gesture_event.type = blink::WebInputEvent::GestureFlingCancel; 205 break; 206 case ui::ET_GESTURE_LONG_PRESS: 207 gesture_event.type = blink::WebInputEvent::GestureLongPress; 208 gesture_event.data.longPress.width = 209 event.details().bounding_box().width(); 210 gesture_event.data.longPress.height = 211 event.details().bounding_box().height(); 212 break; 213 case ui::ET_GESTURE_LONG_TAP: 214 gesture_event.type = blink::WebInputEvent::GestureLongTap; 215 gesture_event.data.longPress.width = 216 event.details().bounding_box().width(); 217 gesture_event.data.longPress.height = 218 event.details().bounding_box().height(); 219 break; 220 case ui::ET_GESTURE_TWO_FINGER_TAP: 221 gesture_event.type = blink::WebInputEvent::GestureTwoFingerTap; 222 gesture_event.data.twoFingerTap.firstFingerWidth = 223 event.details().first_finger_width(); 224 gesture_event.data.twoFingerTap.firstFingerHeight = 225 event.details().first_finger_height(); 226 break; 227 case ui::ET_GESTURE_BEGIN: 228 case ui::ET_GESTURE_END: 229 case ui::ET_GESTURE_SWIPE: 230 gesture_event.type = blink::WebInputEvent::Undefined; 231 break; 232 default: 233 NOTREACHED() << "Unknown gesture type: " << event.type(); 234 } 235 236 gesture_event.sourceDevice = blink::WebGestureEvent::Touchscreen; 237 gesture_event.modifiers = EventFlagsToWebEventModifiers(event.flags()); 238 gesture_event.timeStampSeconds = event.time_stamp().InSecondsF(); 239 240 return gesture_event; 241} 242 243int EventFlagsToWebEventModifiers(int flags) { 244 int modifiers = 0; 245 246 if (flags & ui::EF_SHIFT_DOWN) 247 modifiers |= blink::WebInputEvent::ShiftKey; 248 if (flags & ui::EF_CONTROL_DOWN) 249 modifiers |= blink::WebInputEvent::ControlKey; 250 if (flags & ui::EF_ALT_DOWN) 251 modifiers |= blink::WebInputEvent::AltKey; 252 // TODO(beng): MetaKey/META_MASK 253 if (flags & ui::EF_LEFT_MOUSE_BUTTON) 254 modifiers |= blink::WebInputEvent::LeftButtonDown; 255 if (flags & ui::EF_MIDDLE_MOUSE_BUTTON) 256 modifiers |= blink::WebInputEvent::MiddleButtonDown; 257 if (flags & ui::EF_RIGHT_MOUSE_BUTTON) 258 modifiers |= blink::WebInputEvent::RightButtonDown; 259 if (flags & ui::EF_CAPS_LOCK_DOWN) 260 modifiers |= blink::WebInputEvent::CapsLockOn; 261 return modifiers; 262} 263 264blink::WebTouchPoint* UpdateWebTouchEventFromUIEvent( 265 const ui::TouchEvent& event, 266 blink::WebTouchEvent* web_event) { 267 blink::WebTouchPoint* point = NULL; 268 switch (event.type()) { 269 case ui::ET_TOUCH_PRESSED: 270 // Add a new touch point. 271 if (web_event->touchesLength < blink::WebTouchEvent::touchesLengthCap) { 272 point = &web_event->touches[web_event->touchesLength++]; 273 point->id = event.touch_id(); 274 } 275 break; 276 case ui::ET_TOUCH_RELEASED: 277 case ui::ET_TOUCH_CANCELLED: 278 case ui::ET_TOUCH_MOVED: { 279 // The touch point should have been added to the event from an earlier 280 // _PRESSED event. So find that. 281 // At the moment, only a maximum of 4 touch-points are allowed. So a 282 // simple loop should be sufficient. 283 for (unsigned i = 0; i < web_event->touchesLength; ++i) { 284 point = web_event->touches + i; 285 if (point->id == event.touch_id()) 286 break; 287 point = NULL; 288 } 289 break; 290 } 291 default: 292 DLOG(WARNING) << "Unknown touch event " << event.type(); 293 break; 294 } 295 296 if (!point) 297 return NULL; 298 299 // The spec requires the radii values to be positive (and 1 when unknown). 300 point->radiusX = std::max(1.f, event.radius_x()); 301 point->radiusY = std::max(1.f, event.radius_y()); 302 point->rotationAngle = event.rotation_angle(); 303 point->force = event.force(); 304 305 // Update the location and state of the point. 306 point->state = TouchPointStateFromEvent(event); 307 if (point->state == blink::WebTouchPoint::StateMoved) { 308 // It is possible for badly written touch drivers to emit Move events even 309 // when the touch location hasn't changed. In such cases, consume the event 310 // and pretend nothing happened. 311 if (point->position.x == event.x() && point->position.y == event.y()) 312 return NULL; 313 } 314 point->position.x = event.x(); 315 point->position.y = event.y(); 316 317 const gfx::Point root_point = event.root_location(); 318 point->screenPosition.x = root_point.x(); 319 point->screenPosition.y = root_point.y(); 320 321 // Mark the rest of the points as stationary. 322 for (unsigned i = 0; i < web_event->touchesLength; ++i) { 323 blink::WebTouchPoint* iter = web_event->touches + i; 324 if (iter != point) 325 iter->state = blink::WebTouchPoint::StateStationary; 326 } 327 328 // Update the type of the touch event. 329 WebTouchEventTraits::ResetType(TouchEventTypeFromEvent(event), 330 event.time_stamp().InSecondsF(), 331 web_event); 332 web_event->modifiers = EventFlagsToWebEventModifiers(event.flags()); 333 334 return point; 335} 336 337} // namespace content 338