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.
5 #include "content/browser/renderer_host/ui_events_helper.h"
7 #include "third_party/WebKit/public/web/WebInputEvent.h"
8 #include "ui/events/event.h"
9 #include "ui/events/event_constants.h"
13 int WebModifiersToUIFlags(int modifiers
) {
14 int flags
= ui::EF_NONE
;
16 if (modifiers
& blink::WebInputEvent::ShiftKey
)
17 flags
|= ui::EF_SHIFT_DOWN
;
18 if (modifiers
& blink::WebInputEvent::ControlKey
)
19 flags
|= ui::EF_CONTROL_DOWN
;
20 if (modifiers
& blink::WebInputEvent::AltKey
)
21 flags
|= ui::EF_ALT_DOWN
;
23 if (modifiers
& blink::WebInputEvent::LeftButtonDown
)
24 flags
|= ui::EF_LEFT_MOUSE_BUTTON
;
25 if (modifiers
& blink::WebInputEvent::RightButtonDown
)
26 flags
|= ui::EF_RIGHT_MOUSE_BUTTON
;
27 if (modifiers
& blink::WebInputEvent::MiddleButtonDown
)
28 flags
|= ui::EF_MIDDLE_MOUSE_BUTTON
;
30 if (modifiers
& blink::WebInputEvent::CapsLockOn
)
31 flags
|= ui::EF_CAPS_LOCK_DOWN
;
36 ui::EventType
WebTouchPointStateToEventType(
37 blink::WebTouchPoint::State state
) {
39 case blink::WebTouchPoint::StateReleased
:
40 return ui::ET_TOUCH_RELEASED
;
42 case blink::WebTouchPoint::StatePressed
:
43 return ui::ET_TOUCH_PRESSED
;
45 case blink::WebTouchPoint::StateMoved
:
46 return ui::ET_TOUCH_MOVED
;
48 case blink::WebTouchPoint::StateCancelled
:
49 return ui::ET_TOUCH_CANCELLED
;
52 return ui::ET_UNKNOWN
;
56 blink::WebTouchPoint::State
TouchPointStateFromEvent(
57 const ui::TouchEvent
& event
) {
58 switch (event
.type()) {
59 case ui::ET_TOUCH_PRESSED
:
60 return blink::WebTouchPoint::StatePressed
;
61 case ui::ET_TOUCH_RELEASED
:
62 return blink::WebTouchPoint::StateReleased
;
63 case ui::ET_TOUCH_MOVED
:
64 return blink::WebTouchPoint::StateMoved
;
65 case ui::ET_TOUCH_CANCELLED
:
66 return blink::WebTouchPoint::StateCancelled
;
68 return blink::WebTouchPoint::StateUndefined
;
72 blink::WebInputEvent::Type
TouchEventTypeFromEvent(
73 const ui::TouchEvent
& event
) {
74 switch (event
.type()) {
75 case ui::ET_TOUCH_PRESSED
:
76 return blink::WebInputEvent::TouchStart
;
77 case ui::ET_TOUCH_RELEASED
:
78 return blink::WebInputEvent::TouchEnd
;
79 case ui::ET_TOUCH_MOVED
:
80 return blink::WebInputEvent::TouchMove
;
81 case ui::ET_TOUCH_CANCELLED
:
82 return blink::WebInputEvent::TouchCancel
;
84 return blink::WebInputEvent::Undefined
;
92 bool MakeUITouchEventsFromWebTouchEvents(
93 const TouchEventWithLatencyInfo
& touch_with_latency
,
94 ScopedVector
<ui::TouchEvent
>* list
,
95 TouchEventCoordinateSystem coordinate_system
) {
96 const blink::WebTouchEvent
& touch
= touch_with_latency
.event
;
97 ui::EventType type
= ui::ET_UNKNOWN
;
99 case blink::WebInputEvent::TouchStart
:
100 type
= ui::ET_TOUCH_PRESSED
;
102 case blink::WebInputEvent::TouchEnd
:
103 type
= ui::ET_TOUCH_RELEASED
;
105 case blink::WebInputEvent::TouchMove
:
106 type
= ui::ET_TOUCH_MOVED
;
108 case blink::WebInputEvent::TouchCancel
:
109 type
= ui::ET_TOUCH_CANCELLED
;
116 int flags
= WebModifiersToUIFlags(touch
.modifiers
);
117 base::TimeDelta timestamp
= base::TimeDelta::FromMicroseconds(
118 static_cast<int64
>(touch
.timeStampSeconds
* 1000000));
119 for (unsigned i
= 0; i
< touch
.touchesLength
; ++i
) {
120 const blink::WebTouchPoint
& point
= touch
.touches
[i
];
121 if (WebTouchPointStateToEventType(point
.state
) != type
)
123 // In aura, the touch-event needs to be in the screen coordinate, since the
124 // touch-event is routed to RootWindow first. In Windows, on the other hand,
125 // the touch-event is dispatched directly to the gesture-recognizer, so the
126 // location needs to be in the local coordinate space.
127 #if defined(USE_AURA)
129 if (coordinate_system
== LOCAL_COORDINATES
)
130 location
= gfx::Point(point
.position
.x
, point
.position
.y
);
132 location
= gfx::Point(point
.screenPosition
.x
, point
.screenPosition
.y
);
134 gfx::Point
location(point
.position
.x
, point
.position
.y
);
136 ui::TouchEvent
* uievent
= new ui::TouchEvent(type
,
145 uievent
->set_latency(touch_with_latency
.latency
);
146 list
->push_back(uievent
);
151 blink::WebGestureEvent
MakeWebGestureEventFromUIEvent(
152 const ui::GestureEvent
& event
) {
153 blink::WebGestureEvent gesture_event
;
155 switch (event
.type()) {
156 case ui::ET_GESTURE_TAP
:
157 gesture_event
.type
= blink::WebInputEvent::GestureTap
;
158 gesture_event
.data
.tap
.tapCount
= event
.details().tap_count();
159 gesture_event
.data
.tap
.width
= event
.details().bounding_box().width();
160 gesture_event
.data
.tap
.height
= event
.details().bounding_box().height();
162 case ui::ET_GESTURE_TAP_DOWN
:
163 gesture_event
.type
= blink::WebInputEvent::GestureTapDown
;
164 gesture_event
.data
.tapDown
.width
=
165 event
.details().bounding_box().width();
166 gesture_event
.data
.tapDown
.height
=
167 event
.details().bounding_box().height();
169 case ui::ET_GESTURE_SHOW_PRESS
:
170 gesture_event
.type
= blink::WebInputEvent::GestureShowPress
;
171 gesture_event
.data
.showPress
.width
=
172 event
.details().bounding_box().width();
173 gesture_event
.data
.showPress
.height
=
174 event
.details().bounding_box().height();
176 case ui::ET_GESTURE_TAP_CANCEL
:
177 gesture_event
.type
= blink::WebInputEvent::GestureTapCancel
;
179 case ui::ET_GESTURE_SCROLL_BEGIN
:
180 gesture_event
.type
= blink::WebInputEvent::GestureScrollBegin
;
181 gesture_event
.data
.scrollBegin
.deltaXHint
=
182 event
.details().scroll_x_hint();
183 gesture_event
.data
.scrollBegin
.deltaYHint
=
184 event
.details().scroll_y_hint();
186 case ui::ET_GESTURE_SCROLL_UPDATE
:
187 gesture_event
.type
= blink::WebInputEvent::GestureScrollUpdate
;
188 gesture_event
.data
.scrollUpdate
.deltaX
= event
.details().scroll_x();
189 gesture_event
.data
.scrollUpdate
.deltaY
= event
.details().scroll_y();
191 case ui::ET_GESTURE_SCROLL_END
:
192 gesture_event
.type
= blink::WebInputEvent::GestureScrollEnd
;
194 case ui::ET_GESTURE_PINCH_BEGIN
:
195 gesture_event
.type
= blink::WebInputEvent::GesturePinchBegin
;
197 case ui::ET_GESTURE_PINCH_UPDATE
:
198 gesture_event
.type
= blink::WebInputEvent::GesturePinchUpdate
;
199 gesture_event
.data
.pinchUpdate
.scale
= event
.details().scale();
201 case ui::ET_GESTURE_PINCH_END
:
202 gesture_event
.type
= blink::WebInputEvent::GesturePinchEnd
;
204 case ui::ET_SCROLL_FLING_START
:
205 gesture_event
.type
= blink::WebInputEvent::GestureFlingStart
;
206 gesture_event
.data
.flingStart
.velocityX
= event
.details().velocity_x();
207 gesture_event
.data
.flingStart
.velocityY
= event
.details().velocity_y();
209 case ui::ET_SCROLL_FLING_CANCEL
:
210 gesture_event
.type
= blink::WebInputEvent::GestureFlingCancel
;
212 case ui::ET_GESTURE_LONG_PRESS
:
213 gesture_event
.type
= blink::WebInputEvent::GestureLongPress
;
214 gesture_event
.data
.longPress
.width
=
215 event
.details().bounding_box().width();
216 gesture_event
.data
.longPress
.height
=
217 event
.details().bounding_box().height();
219 case ui::ET_GESTURE_LONG_TAP
:
220 gesture_event
.type
= blink::WebInputEvent::GestureLongTap
;
221 gesture_event
.data
.longPress
.width
=
222 event
.details().bounding_box().width();
223 gesture_event
.data
.longPress
.height
=
224 event
.details().bounding_box().height();
226 case ui::ET_GESTURE_TWO_FINGER_TAP
:
227 gesture_event
.type
= blink::WebInputEvent::GestureTwoFingerTap
;
228 gesture_event
.data
.twoFingerTap
.firstFingerWidth
=
229 event
.details().first_finger_width();
230 gesture_event
.data
.twoFingerTap
.firstFingerHeight
=
231 event
.details().first_finger_height();
233 case ui::ET_GESTURE_BEGIN
:
234 case ui::ET_GESTURE_END
:
235 case ui::ET_GESTURE_MULTIFINGER_SWIPE
:
236 gesture_event
.type
= blink::WebInputEvent::Undefined
;
239 NOTREACHED() << "Unknown gesture type: " << event
.type();
242 gesture_event
.sourceDevice
= blink::WebGestureEvent::Touchscreen
;
243 gesture_event
.modifiers
= EventFlagsToWebEventModifiers(event
.flags());
244 gesture_event
.timeStampSeconds
= event
.time_stamp().InSecondsF();
246 return gesture_event
;
249 int EventFlagsToWebEventModifiers(int flags
) {
252 if (flags
& ui::EF_SHIFT_DOWN
)
253 modifiers
|= blink::WebInputEvent::ShiftKey
;
254 if (flags
& ui::EF_CONTROL_DOWN
)
255 modifiers
|= blink::WebInputEvent::ControlKey
;
256 if (flags
& ui::EF_ALT_DOWN
)
257 modifiers
|= blink::WebInputEvent::AltKey
;
258 // TODO(beng): MetaKey/META_MASK
259 if (flags
& ui::EF_LEFT_MOUSE_BUTTON
)
260 modifiers
|= blink::WebInputEvent::LeftButtonDown
;
261 if (flags
& ui::EF_MIDDLE_MOUSE_BUTTON
)
262 modifiers
|= blink::WebInputEvent::MiddleButtonDown
;
263 if (flags
& ui::EF_RIGHT_MOUSE_BUTTON
)
264 modifiers
|= blink::WebInputEvent::RightButtonDown
;
265 if (flags
& ui::EF_CAPS_LOCK_DOWN
)
266 modifiers
|= blink::WebInputEvent::CapsLockOn
;
270 blink::WebTouchPoint
* UpdateWebTouchEventFromUIEvent(
271 const ui::TouchEvent
& event
,
272 blink::WebTouchEvent
* web_event
) {
273 blink::WebTouchPoint
* point
= NULL
;
274 switch (event
.type()) {
275 case ui::ET_TOUCH_PRESSED
:
276 // Add a new touch point.
277 if (web_event
->touchesLength
< blink::WebTouchEvent::touchesLengthCap
) {
278 point
= &web_event
->touches
[web_event
->touchesLength
++];
279 point
->id
= event
.touch_id();
282 case ui::ET_TOUCH_RELEASED
:
283 case ui::ET_TOUCH_CANCELLED
:
284 case ui::ET_TOUCH_MOVED
: {
285 // The touch point should have been added to the event from an earlier
286 // _PRESSED event. So find that.
287 // At the moment, only a maximum of 4 touch-points are allowed. So a
288 // simple loop should be sufficient.
289 for (unsigned i
= 0; i
< web_event
->touchesLength
; ++i
) {
290 point
= web_event
->touches
+ i
;
291 if (point
->id
== event
.touch_id())
298 DLOG(WARNING
) << "Unknown touch event " << event
.type();
305 // The spec requires the radii values to be positive (and 1 when unknown).
306 point
->radiusX
= std::max(1.f
, event
.radius_x());
307 point
->radiusY
= std::max(1.f
, event
.radius_y());
308 point
->rotationAngle
= event
.rotation_angle();
309 point
->force
= event
.force();
311 // Update the location and state of the point.
312 point
->state
= TouchPointStateFromEvent(event
);
313 if (point
->state
== blink::WebTouchPoint::StateMoved
) {
314 // It is possible for badly written touch drivers to emit Move events even
315 // when the touch location hasn't changed. In such cases, consume the event
316 // and pretend nothing happened.
317 if (point
->position
.x
== event
.x() && point
->position
.y
== event
.y())
320 point
->position
.x
= event
.x();
321 point
->position
.y
= event
.y();
323 const gfx::Point root_point
= event
.root_location();
324 point
->screenPosition
.x
= root_point
.x();
325 point
->screenPosition
.y
= root_point
.y();
327 // Mark the rest of the points as stationary.
328 for (unsigned i
= 0; i
< web_event
->touchesLength
; ++i
) {
329 blink::WebTouchPoint
* iter
= web_event
->touches
+ i
;
331 iter
->state
= blink::WebTouchPoint::StateStationary
;
334 // Update the type of the touch event.
335 web_event
->type
= TouchEventTypeFromEvent(event
);
336 web_event
->timeStampSeconds
= event
.time_stamp().InSecondsF();
337 web_event
->modifiers
= EventFlagsToWebEventModifiers(event
.flags());
342 } // namespace content