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 "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"
14 int WebModifiersToUIFlags(int modifiers
) {
15 int flags
= ui::EF_NONE
;
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
;
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
;
31 if (modifiers
& blink::WebInputEvent::CapsLockOn
)
32 flags
|= ui::EF_CAPS_LOCK_DOWN
;
37 ui::EventType
WebTouchPointStateToEventType(
38 blink::WebTouchPoint::State state
) {
40 case blink::WebTouchPoint::StateReleased
:
41 return ui::ET_TOUCH_RELEASED
;
43 case blink::WebTouchPoint::StatePressed
:
44 return ui::ET_TOUCH_PRESSED
;
46 case blink::WebTouchPoint::StateMoved
:
47 return ui::ET_TOUCH_MOVED
;
49 case blink::WebTouchPoint::StateCancelled
:
50 return ui::ET_TOUCH_CANCELLED
;
53 return ui::ET_UNKNOWN
;
57 blink::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
;
69 return blink::WebTouchPoint::StateUndefined
;
73 blink::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
;
85 return blink::WebInputEvent::Undefined
;
93 bool 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
;
100 case blink::WebInputEvent::TouchStart
:
101 type
= ui::ET_TOUCH_PRESSED
;
103 case blink::WebInputEvent::TouchEnd
:
104 type
= ui::ET_TOUCH_RELEASED
;
106 case blink::WebInputEvent::TouchMove
:
107 type
= ui::ET_TOUCH_MOVED
;
109 case blink::WebInputEvent::TouchCancel
:
110 type
= ui::ET_TOUCH_CANCELLED
;
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
)
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
;
129 location
= point
.screenPosition
;
130 ui::TouchEvent
* uievent
= new ui::TouchEvent(type
,
139 uievent
->set_latency(touch_with_latency
.latency
);
140 list
->push_back(uievent
);
145 blink::WebGestureEvent
MakeWebGestureEventFromUIEvent(
146 const ui::GestureEvent
& event
) {
147 blink::WebGestureEvent gesture_event
;
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();
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();
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();
170 case ui::ET_GESTURE_TAP_CANCEL
:
171 gesture_event
.type
= blink::WebInputEvent::GestureTapCancel
;
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();
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();
185 case ui::ET_GESTURE_SCROLL_END
:
186 gesture_event
.type
= blink::WebInputEvent::GestureScrollEnd
;
188 case ui::ET_GESTURE_PINCH_BEGIN
:
189 gesture_event
.type
= blink::WebInputEvent::GesturePinchBegin
;
191 case ui::ET_GESTURE_PINCH_UPDATE
:
192 gesture_event
.type
= blink::WebInputEvent::GesturePinchUpdate
;
193 gesture_event
.data
.pinchUpdate
.scale
= event
.details().scale();
195 case ui::ET_GESTURE_PINCH_END
:
196 gesture_event
.type
= blink::WebInputEvent::GesturePinchEnd
;
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();
203 case ui::ET_SCROLL_FLING_CANCEL
:
204 gesture_event
.type
= blink::WebInputEvent::GestureFlingCancel
;
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();
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();
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();
227 case ui::ET_GESTURE_BEGIN
:
228 case ui::ET_GESTURE_END
:
229 case ui::ET_GESTURE_MULTIFINGER_SWIPE
:
230 gesture_event
.type
= blink::WebInputEvent::Undefined
;
233 NOTREACHED() << "Unknown gesture type: " << event
.type();
236 gesture_event
.sourceDevice
= blink::WebGestureEvent::Touchscreen
;
237 gesture_event
.modifiers
= EventFlagsToWebEventModifiers(event
.flags());
238 gesture_event
.timeStampSeconds
= event
.time_stamp().InSecondsF();
240 return gesture_event
;
243 int EventFlagsToWebEventModifiers(int flags
) {
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
;
264 blink::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();
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())
292 DLOG(WARNING
) << "Unknown touch event " << event
.type();
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();
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())
314 point
->position
.x
= event
.x();
315 point
->position
.y
= event
.y();
317 const gfx::Point root_point
= event
.root_location();
318 point
->screenPosition
.x
= root_point
.x();
319 point
->screenPosition
.y
= root_point
.y();
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
;
325 iter
->state
= blink::WebTouchPoint::StateStationary
;
328 // Update the type of the touch event.
329 WebTouchEventTraits::ResetType(TouchEventTypeFromEvent(event
),
330 event
.time_stamp().InSecondsF(),
332 web_event
->modifiers
= EventFlagsToWebEventModifiers(event
.flags());
337 } // namespace content