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