handoff: Fix the origin so that it correctly reflects the sender.
[chromium-blink-merge.git] / content / browser / renderer_host / input / web_input_event_util.cc
blob150d83e8ee55a5024ce24dfefe0bba853db8207c
1 // Copyright 2013 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 // MSVC++ requires this to be set before any other includes to get M_PI.
6 #define _USE_MATH_DEFINES
8 #include "content/browser/renderer_host/input/web_input_event_util.h"
10 #include <cmath>
12 #include "base/strings/string_util.h"
13 #include "content/common/input/web_touch_event_traits.h"
14 #include "ui/events/event_constants.h"
15 #include "ui/events/gesture_detection/gesture_event_data.h"
16 #include "ui/events/gesture_detection/motion_event.h"
17 #include "ui/gfx/geometry/safe_integer_conversions.h"
19 using blink::WebGestureEvent;
20 using blink::WebInputEvent;
21 using blink::WebTouchEvent;
22 using blink::WebTouchPoint;
23 using ui::MotionEvent;
25 namespace {
27 const char* GetKeyIdentifier(ui::KeyboardCode key_code) {
28 switch (key_code) {
29 case ui::VKEY_MENU:
30 return "Alt";
31 case ui::VKEY_CONTROL:
32 return "Control";
33 case ui::VKEY_SHIFT:
34 return "Shift";
35 case ui::VKEY_CAPITAL:
36 return "CapsLock";
37 case ui::VKEY_LWIN:
38 case ui::VKEY_RWIN:
39 return "Win";
40 case ui::VKEY_CLEAR:
41 return "Clear";
42 case ui::VKEY_DOWN:
43 return "Down";
44 case ui::VKEY_END:
45 return "End";
46 case ui::VKEY_RETURN:
47 return "Enter";
48 case ui::VKEY_EXECUTE:
49 return "Execute";
50 case ui::VKEY_F1:
51 return "F1";
52 case ui::VKEY_F2:
53 return "F2";
54 case ui::VKEY_F3:
55 return "F3";
56 case ui::VKEY_F4:
57 return "F4";
58 case ui::VKEY_F5:
59 return "F5";
60 case ui::VKEY_F6:
61 return "F6";
62 case ui::VKEY_F7:
63 return "F7";
64 case ui::VKEY_F8:
65 return "F8";
66 case ui::VKEY_F9:
67 return "F9";
68 case ui::VKEY_F10:
69 return "F10";
70 case ui::VKEY_F11:
71 return "F11";
72 case ui::VKEY_F12:
73 return "F12";
74 case ui::VKEY_F13:
75 return "F13";
76 case ui::VKEY_F14:
77 return "F14";
78 case ui::VKEY_F15:
79 return "F15";
80 case ui::VKEY_F16:
81 return "F16";
82 case ui::VKEY_F17:
83 return "F17";
84 case ui::VKEY_F18:
85 return "F18";
86 case ui::VKEY_F19:
87 return "F19";
88 case ui::VKEY_F20:
89 return "F20";
90 case ui::VKEY_F21:
91 return "F21";
92 case ui::VKEY_F22:
93 return "F22";
94 case ui::VKEY_F23:
95 return "F23";
96 case ui::VKEY_F24:
97 return "F24";
98 case ui::VKEY_HELP:
99 return "Help";
100 case ui::VKEY_HOME:
101 return "Home";
102 case ui::VKEY_INSERT:
103 return "Insert";
104 case ui::VKEY_LEFT:
105 return "Left";
106 case ui::VKEY_NEXT:
107 return "PageDown";
108 case ui::VKEY_PRIOR:
109 return "PageUp";
110 case ui::VKEY_PAUSE:
111 return "Pause";
112 case ui::VKEY_SNAPSHOT:
113 return "PrintScreen";
114 case ui::VKEY_RIGHT:
115 return "Right";
116 case ui::VKEY_SCROLL:
117 return "Scroll";
118 case ui::VKEY_SELECT:
119 return "Select";
120 case ui::VKEY_UP:
121 return "Up";
122 case ui::VKEY_DELETE:
123 return "U+007F"; // Standard says that DEL becomes U+007F.
124 case ui::VKEY_MEDIA_NEXT_TRACK:
125 return "MediaNextTrack";
126 case ui::VKEY_MEDIA_PREV_TRACK:
127 return "MediaPreviousTrack";
128 case ui::VKEY_MEDIA_STOP:
129 return "MediaStop";
130 case ui::VKEY_MEDIA_PLAY_PAUSE:
131 return "MediaPlayPause";
132 case ui::VKEY_VOLUME_MUTE:
133 return "VolumeMute";
134 case ui::VKEY_VOLUME_DOWN:
135 return "VolumeDown";
136 case ui::VKEY_VOLUME_UP:
137 return "VolumeUp";
138 default:
139 return NULL;
143 WebInputEvent::Type ToWebInputEventType(MotionEvent::Action action) {
144 switch (action) {
145 case MotionEvent::ACTION_DOWN:
146 return WebInputEvent::TouchStart;
147 case MotionEvent::ACTION_MOVE:
148 return WebInputEvent::TouchMove;
149 case MotionEvent::ACTION_UP:
150 return WebInputEvent::TouchEnd;
151 case MotionEvent::ACTION_CANCEL:
152 return WebInputEvent::TouchCancel;
153 case MotionEvent::ACTION_POINTER_DOWN:
154 return WebInputEvent::TouchStart;
155 case MotionEvent::ACTION_POINTER_UP:
156 return WebInputEvent::TouchEnd;
158 NOTREACHED() << "Invalid MotionEvent::Action.";
159 return WebInputEvent::Undefined;
162 // Note that |is_action_pointer| is meaningful only in the context of
163 // |ACTION_POINTER_UP| and |ACTION_POINTER_DOWN|; other actions map directly to
164 // WebTouchPoint::State.
165 WebTouchPoint::State ToWebTouchPointState(const MotionEvent& event,
166 size_t pointer_index) {
167 switch (event.GetAction()) {
168 case MotionEvent::ACTION_DOWN:
169 return WebTouchPoint::StatePressed;
170 case MotionEvent::ACTION_MOVE:
171 return WebTouchPoint::StateMoved;
172 case MotionEvent::ACTION_UP:
173 return WebTouchPoint::StateReleased;
174 case MotionEvent::ACTION_CANCEL:
175 return WebTouchPoint::StateCancelled;
176 case MotionEvent::ACTION_POINTER_DOWN:
177 return static_cast<int>(pointer_index) == event.GetActionIndex()
178 ? WebTouchPoint::StatePressed
179 : WebTouchPoint::StateStationary;
180 case MotionEvent::ACTION_POINTER_UP:
181 return static_cast<int>(pointer_index) == event.GetActionIndex()
182 ? WebTouchPoint::StateReleased
183 : WebTouchPoint::StateStationary;
185 NOTREACHED() << "Invalid MotionEvent::Action.";
186 return WebTouchPoint::StateUndefined;
189 WebTouchPoint CreateWebTouchPoint(const MotionEvent& event,
190 size_t pointer_index) {
191 WebTouchPoint touch;
192 touch.id = event.GetPointerId(pointer_index);
193 touch.state = ToWebTouchPointState(event, pointer_index);
194 touch.position.x = event.GetX(pointer_index);
195 touch.position.y = event.GetY(pointer_index);
196 touch.screenPosition.x = event.GetRawX(pointer_index);
197 touch.screenPosition.y = event.GetRawY(pointer_index);
199 // A note on touch ellipse specifications:
201 // Android MotionEvent provides the major and minor axes of the touch ellipse,
202 // as well as the orientation of the major axis clockwise from vertical, in
203 // radians. See:
204 // http://developer.android.com/reference/android/view/MotionEvent.html
206 // The proposed extension to W3C Touch Events specifies the touch ellipse
207 // using two radii along x- & y-axes and a positive acute rotation angle in
208 // degrees. See:
209 // http://dvcs.w3.org/hg/webevents/raw-file/default/touchevents.html
211 float major_radius = event.GetTouchMajor(pointer_index) / 2.f;
212 float minor_radius = event.GetTouchMinor(pointer_index) / 2.f;
214 DCHECK_LE(minor_radius, major_radius);
215 DCHECK_IMPLIES(major_radius, minor_radius);
217 float orientation_deg = event.GetOrientation(pointer_index) * 180.f / M_PI;
218 DCHECK_GE(major_radius, 0);
219 DCHECK_GE(minor_radius, 0);
220 DCHECK_GE(major_radius, minor_radius);
221 // Allow a small bound tolerance to account for floating point conversion.
222 DCHECK_GT(orientation_deg, -90.01f);
223 DCHECK_LT(orientation_deg, 90.01f);
224 if (orientation_deg >= 0) {
225 // The case orientation_deg == 0 is handled here on purpose: although the
226 // 'else' block is equivalent in this case, we want to pass the 0 value
227 // unchanged (and 0 is the default value for many devices that don't
228 // report elliptical touches).
229 touch.radiusX = minor_radius;
230 touch.radiusY = major_radius;
231 touch.rotationAngle = orientation_deg;
232 } else {
233 touch.radiusX = major_radius;
234 touch.radiusY = minor_radius;
235 touch.rotationAngle = orientation_deg + 90;
238 touch.force = event.GetPressure(pointer_index);
240 return touch;
243 } // namespace
245 namespace content {
247 void UpdateWindowsKeyCodeAndKeyIdentifier(blink::WebKeyboardEvent* event,
248 ui::KeyboardCode windows_key_code) {
249 event->windowsKeyCode = windows_key_code;
251 const char* id = GetKeyIdentifier(windows_key_code);
252 if (id) {
253 base::strlcpy(event->keyIdentifier, id, sizeof(event->keyIdentifier) - 1);
254 } else {
255 base::snprintf(event->keyIdentifier,
256 sizeof(event->keyIdentifier),
257 "U+%04X",
258 base::ToUpperASCII(static_cast<int>(windows_key_code)));
262 blink::WebTouchEvent CreateWebTouchEventFromMotionEvent(
263 const ui::MotionEvent& event,
264 bool may_cause_scrolling) {
265 static_assert(static_cast<int>(MotionEvent::MAX_TOUCH_POINT_COUNT) ==
266 static_cast<int>(blink::WebTouchEvent::touchesLengthCap),
267 "inconsistent maximum number of active touch points");
269 blink::WebTouchEvent result;
271 WebTouchEventTraits::ResetType(
272 ToWebInputEventType(event.GetAction()),
273 (event.GetEventTime() - base::TimeTicks()).InSecondsF(),
274 &result);
275 result.causesScrollingIfUncanceled = may_cause_scrolling;
277 result.modifiers = EventFlagsToWebEventModifiers(event.GetFlags());
278 result.touchesLength =
279 std::min(event.GetPointerCount(),
280 static_cast<size_t>(WebTouchEvent::touchesLengthCap));
281 DCHECK_GT(result.touchesLength, 0U);
283 for (size_t i = 0; i < result.touchesLength; ++i)
284 result.touches[i] = CreateWebTouchPoint(event, i);
286 return result;
289 WebGestureEvent CreateWebGestureEvent(const ui::GestureEventDetails& details,
290 base::TimeDelta timestamp,
291 const gfx::PointF& location,
292 const gfx::PointF& raw_location,
293 int flags) {
294 WebGestureEvent gesture;
295 gesture.timeStampSeconds = timestamp.InSecondsF();
296 gesture.x = gfx::ToFlooredInt(location.x());
297 gesture.y = gfx::ToFlooredInt(location.y());
298 gesture.globalX = gfx::ToFlooredInt(raw_location.x());
299 gesture.globalY = gfx::ToFlooredInt(raw_location.y());
300 gesture.modifiers = EventFlagsToWebEventModifiers(flags);
301 gesture.sourceDevice = blink::WebGestureDeviceTouchscreen;
303 switch (details.type()) {
304 case ui::ET_GESTURE_SHOW_PRESS:
305 gesture.type = WebInputEvent::GestureShowPress;
306 gesture.data.showPress.width = details.bounding_box_f().width();
307 gesture.data.showPress.height = details.bounding_box_f().height();
308 break;
309 case ui::ET_GESTURE_DOUBLE_TAP:
310 gesture.type = WebInputEvent::GestureDoubleTap;
311 DCHECK_EQ(1, details.tap_count());
312 gesture.data.tap.tapCount = details.tap_count();
313 gesture.data.tap.width = details.bounding_box_f().width();
314 gesture.data.tap.height = details.bounding_box_f().height();
315 break;
316 case ui::ET_GESTURE_TAP:
317 gesture.type = WebInputEvent::GestureTap;
318 DCHECK_GE(details.tap_count(), 1);
319 gesture.data.tap.tapCount = details.tap_count();
320 gesture.data.tap.width = details.bounding_box_f().width();
321 gesture.data.tap.height = details.bounding_box_f().height();
322 break;
323 case ui::ET_GESTURE_TAP_UNCONFIRMED:
324 gesture.type = WebInputEvent::GestureTapUnconfirmed;
325 DCHECK_EQ(1, details.tap_count());
326 gesture.data.tap.tapCount = details.tap_count();
327 gesture.data.tap.width = details.bounding_box_f().width();
328 gesture.data.tap.height = details.bounding_box_f().height();
329 break;
330 case ui::ET_GESTURE_LONG_PRESS:
331 gesture.type = WebInputEvent::GestureLongPress;
332 gesture.data.longPress.width = details.bounding_box_f().width();
333 gesture.data.longPress.height = details.bounding_box_f().height();
334 break;
335 case ui::ET_GESTURE_LONG_TAP:
336 gesture.type = WebInputEvent::GestureLongTap;
337 gesture.data.longPress.width = details.bounding_box_f().width();
338 gesture.data.longPress.height = details.bounding_box_f().height();
339 break;
340 case ui::ET_GESTURE_TWO_FINGER_TAP:
341 gesture.type = blink::WebInputEvent::GestureTwoFingerTap;
342 gesture.data.twoFingerTap.firstFingerWidth = details.first_finger_width();
343 gesture.data.twoFingerTap.firstFingerHeight =
344 details.first_finger_height();
345 break;
346 case ui::ET_GESTURE_SCROLL_BEGIN:
347 gesture.type = WebInputEvent::GestureScrollBegin;
348 gesture.data.scrollBegin.deltaXHint = details.scroll_x_hint();
349 gesture.data.scrollBegin.deltaYHint = details.scroll_y_hint();
350 break;
351 case ui::ET_GESTURE_SCROLL_UPDATE:
352 gesture.type = WebInputEvent::GestureScrollUpdate;
353 gesture.data.scrollUpdate.deltaX = details.scroll_x();
354 gesture.data.scrollUpdate.deltaY = details.scroll_y();
355 gesture.data.scrollUpdate.previousUpdateInSequencePrevented =
356 details.previous_scroll_update_in_sequence_prevented();
357 break;
358 case ui::ET_GESTURE_SCROLL_END:
359 gesture.type = WebInputEvent::GestureScrollEnd;
360 break;
361 case ui::ET_SCROLL_FLING_START:
362 gesture.type = WebInputEvent::GestureFlingStart;
363 gesture.data.flingStart.velocityX = details.velocity_x();
364 gesture.data.flingStart.velocityY = details.velocity_y();
365 break;
366 case ui::ET_SCROLL_FLING_CANCEL:
367 gesture.type = WebInputEvent::GestureFlingCancel;
368 break;
369 case ui::ET_GESTURE_PINCH_BEGIN:
370 gesture.type = WebInputEvent::GesturePinchBegin;
371 break;
372 case ui::ET_GESTURE_PINCH_UPDATE:
373 gesture.type = WebInputEvent::GesturePinchUpdate;
374 gesture.data.pinchUpdate.scale = details.scale();
375 break;
376 case ui::ET_GESTURE_PINCH_END:
377 gesture.type = WebInputEvent::GesturePinchEnd;
378 break;
379 case ui::ET_GESTURE_TAP_CANCEL:
380 gesture.type = WebInputEvent::GestureTapCancel;
381 break;
382 case ui::ET_GESTURE_TAP_DOWN:
383 gesture.type = WebInputEvent::GestureTapDown;
384 gesture.data.tapDown.width = details.bounding_box_f().width();
385 gesture.data.tapDown.height = details.bounding_box_f().height();
386 break;
387 case ui::ET_GESTURE_BEGIN:
388 case ui::ET_GESTURE_END:
389 case ui::ET_GESTURE_SWIPE:
390 // The caller is responsible for discarding these gestures appropriately.
391 gesture.type = WebInputEvent::Undefined;
392 break;
393 default:
394 NOTREACHED() << "ui::EventType provided wasn't a valid gesture event: "
395 << details.type();
398 return gesture;
401 WebGestureEvent CreateWebGestureEventFromGestureEventData(
402 const ui::GestureEventData& data) {
403 return CreateWebGestureEvent(data.details,
404 data.time - base::TimeTicks(),
405 gfx::PointF(data.x, data.y),
406 gfx::PointF(data.raw_x, data.raw_y),
407 data.flags);
410 int EventFlagsToWebEventModifiers(int flags) {
411 int modifiers = 0;
413 if (flags & ui::EF_SHIFT_DOWN)
414 modifiers |= blink::WebInputEvent::ShiftKey;
415 if (flags & ui::EF_CONTROL_DOWN)
416 modifiers |= blink::WebInputEvent::ControlKey;
417 if (flags & ui::EF_ALT_DOWN)
418 modifiers |= blink::WebInputEvent::AltKey;
419 if (flags & ui::EF_COMMAND_DOWN)
420 modifiers |= blink::WebInputEvent::MetaKey;
422 if (flags & ui::EF_LEFT_MOUSE_BUTTON)
423 modifiers |= blink::WebInputEvent::LeftButtonDown;
424 if (flags & ui::EF_MIDDLE_MOUSE_BUTTON)
425 modifiers |= blink::WebInputEvent::MiddleButtonDown;
426 if (flags & ui::EF_RIGHT_MOUSE_BUTTON)
427 modifiers |= blink::WebInputEvent::RightButtonDown;
428 if (flags & ui::EF_CAPS_LOCK_DOWN)
429 modifiers |= blink::WebInputEvent::CapsLockOn;
430 if (flags & ui::EF_IS_REPEAT)
431 modifiers |= blink::WebInputEvent::IsAutoRepeat;
432 if (flags & ui::EF_NUMPAD_KEY)
433 modifiers |= blink::WebInputEvent::IsKeyPad;
435 return modifiers;
438 int WebEventModifiersToEventFlags(int modifiers) {
439 int flags = 0;
441 if (modifiers & blink::WebInputEvent::ShiftKey)
442 flags |= ui::EF_SHIFT_DOWN;
443 if (modifiers & blink::WebInputEvent::ControlKey)
444 flags |= ui::EF_CONTROL_DOWN;
445 if (modifiers & blink::WebInputEvent::AltKey)
446 flags |= ui::EF_ALT_DOWN;
447 if (modifiers & blink::WebInputEvent::MetaKey)
448 flags |= ui::EF_COMMAND_DOWN;
450 if (modifiers & blink::WebInputEvent::LeftButtonDown)
451 flags |= ui::EF_LEFT_MOUSE_BUTTON;
452 if (modifiers & blink::WebInputEvent::MiddleButtonDown)
453 flags |= ui::EF_MIDDLE_MOUSE_BUTTON;
454 if (modifiers & blink::WebInputEvent::RightButtonDown)
455 flags |= ui::EF_RIGHT_MOUSE_BUTTON;
456 if (modifiers & blink::WebInputEvent::CapsLockOn)
457 flags |= ui::EF_CAPS_LOCK_DOWN;
458 if (modifiers & blink::WebInputEvent::IsAutoRepeat)
459 flags |= ui::EF_IS_REPEAT;
460 if (modifiers & blink::WebInputEvent::IsKeyPad)
461 flags |= ui::EF_NUMPAD_KEY;
463 return flags;
466 } // namespace content