event_conversion.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
13c827367444ee418f129b2c238299f49d3264554Jarkko Poyry// Copyright (c) 2012 The Chromium Authors. All rights reserved. 23c827367444ee418f129b2c238299f49d3264554Jarkko Poyry// Use of this source code is governed by a BSD-style license that can be 33c827367444ee418f129b2c238299f49d3264554Jarkko Poyry// found in the LICENSE file. 43c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 53c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "content/renderer/pepper/event_conversion.h" 63c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 73c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include <map> 83c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 93c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "base/basictypes.h" 103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "base/i18n/char_iterator.h" 113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "base/logging.h" 123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "base/memory/scoped_ptr.h" 133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "base/strings/string_util.h" 143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "base/strings/stringprintf.h" 153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "base/strings/utf_string_conversion_utils.h" 163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "base/strings/utf_string_conversions.h" 173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "content/renderer/pepper/common.h" 183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "content/renderer/pepper/usb_key_code_conversion.h" 193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "ppapi/c/pp_input_event.h" 203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "ppapi/shared_impl/ppb_input_event_shared.h" 213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "ppapi/shared_impl/time_conversion.h" 223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "third_party/WebKit/public/platform/WebGamepads.h" 233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "third_party/WebKit/public/platform/WebString.h" 243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "third_party/WebKit/public/web/WebInputEvent.h" 253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 263c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing ppapi::EventTimeToPPTimeTicks; 273c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing ppapi::InputEventData; 283c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing ppapi::PPTimeTicksToEventTime; 293c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing blink::WebInputEvent; 303c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing blink::WebKeyboardEvent; 313c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing blink::WebMouseEvent; 323c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing blink::WebMouseWheelEvent; 333c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing blink::WebString; 343c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing blink::WebTouchEvent; 353c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing blink::WebTouchPoint; 363c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing blink::WebUChar; 373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 383c827367444ee418f129b2c238299f49d3264554Jarkko Poyrynamespace content { 39 40namespace { 41 42// Verify the modifier flags WebKit uses match the Pepper ones. If these start 43// not matching, we'll need to write conversion code to preserve the Pepper 44// values (since plugins will be depending on them). 45COMPILE_ASSERT(static_cast<int>(PP_INPUTEVENT_MODIFIER_SHIFTKEY) == 46 static_cast<int>(WebInputEvent::ShiftKey), 47 ShiftKeyMatches); 48COMPILE_ASSERT(static_cast<int>(PP_INPUTEVENT_MODIFIER_CONTROLKEY) == 49 static_cast<int>(WebInputEvent::ControlKey), 50 ControlKeyMatches); 51COMPILE_ASSERT(static_cast<int>(PP_INPUTEVENT_MODIFIER_ALTKEY) == 52 static_cast<int>(WebInputEvent::AltKey), 53 AltKeyMatches); 54COMPILE_ASSERT(static_cast<int>(PP_INPUTEVENT_MODIFIER_METAKEY) == 55 static_cast<int>(WebInputEvent::MetaKey), 56 MetaKeyMatches); 57COMPILE_ASSERT(static_cast<int>(PP_INPUTEVENT_MODIFIER_ISKEYPAD) == 58 static_cast<int>(WebInputEvent::IsKeyPad), 59 KeyPadMatches); 60COMPILE_ASSERT(static_cast<int>(PP_INPUTEVENT_MODIFIER_ISAUTOREPEAT) == 61 static_cast<int>(WebInputEvent::IsAutoRepeat), 62 AutoRepeatMatches); 63COMPILE_ASSERT(static_cast<int>(PP_INPUTEVENT_MODIFIER_LEFTBUTTONDOWN) == 64 static_cast<int>(WebInputEvent::LeftButtonDown), 65 LeftButtonMatches); 66COMPILE_ASSERT(static_cast<int>(PP_INPUTEVENT_MODIFIER_MIDDLEBUTTONDOWN) == 67 static_cast<int>(WebInputEvent::MiddleButtonDown), 68 MiddleButtonMatches); 69COMPILE_ASSERT(static_cast<int>(PP_INPUTEVENT_MODIFIER_RIGHTBUTTONDOWN) == 70 static_cast<int>(WebInputEvent::RightButtonDown), 71 RightButtonMatches); 72COMPILE_ASSERT(static_cast<int>(PP_INPUTEVENT_MODIFIER_CAPSLOCKKEY) == 73 static_cast<int>(WebInputEvent::CapsLockOn), 74 CapsLockMatches); 75COMPILE_ASSERT(static_cast<int>(PP_INPUTEVENT_MODIFIER_NUMLOCKKEY) == 76 static_cast<int>(WebInputEvent::NumLockOn), 77 NumLockMatches); 78COMPILE_ASSERT(static_cast<int>(PP_INPUTEVENT_MODIFIER_ISLEFT) == 79 static_cast<int>(WebInputEvent::IsLeft), 80 LeftMatches); 81COMPILE_ASSERT(static_cast<int>(PP_INPUTEVENT_MODIFIER_ISRIGHT) == 82 static_cast<int>(WebInputEvent::IsRight), 83 RightMatches); 84 85PP_InputEvent_Type ConvertEventTypes(WebInputEvent::Type wetype) { 86 switch (wetype) { 87 case WebInputEvent::MouseDown: 88 return PP_INPUTEVENT_TYPE_MOUSEDOWN; 89 case WebInputEvent::MouseUp: 90 return PP_INPUTEVENT_TYPE_MOUSEUP; 91 case WebInputEvent::MouseMove: 92 return PP_INPUTEVENT_TYPE_MOUSEMOVE; 93 case WebInputEvent::MouseEnter: 94 return PP_INPUTEVENT_TYPE_MOUSEENTER; 95 case WebInputEvent::MouseLeave: 96 return PP_INPUTEVENT_TYPE_MOUSELEAVE; 97 case WebInputEvent::ContextMenu: 98 return PP_INPUTEVENT_TYPE_CONTEXTMENU; 99 case WebInputEvent::MouseWheel: 100 return PP_INPUTEVENT_TYPE_WHEEL; 101 case WebInputEvent::RawKeyDown: 102 return PP_INPUTEVENT_TYPE_RAWKEYDOWN; 103 case WebInputEvent::KeyDown: 104 return PP_INPUTEVENT_TYPE_KEYDOWN; 105 case WebInputEvent::KeyUp: 106 return PP_INPUTEVENT_TYPE_KEYUP; 107 case WebInputEvent::Char: 108 return PP_INPUTEVENT_TYPE_CHAR; 109 case WebInputEvent::TouchStart: 110 return PP_INPUTEVENT_TYPE_TOUCHSTART; 111 case WebInputEvent::TouchMove: 112 return PP_INPUTEVENT_TYPE_TOUCHMOVE; 113 case WebInputEvent::TouchEnd: 114 return PP_INPUTEVENT_TYPE_TOUCHEND; 115 case WebInputEvent::TouchCancel: 116 return PP_INPUTEVENT_TYPE_TOUCHCANCEL; 117 case WebInputEvent::Undefined: 118 default: 119 return PP_INPUTEVENT_TYPE_UNDEFINED; 120 } 121} 122 123// Generates a PP_InputEvent with the fields common to all events, as well as 124// the event type from the given web event. Event-specific fields will be zero 125// initialized. 126InputEventData GetEventWithCommonFieldsAndType(const WebInputEvent& web_event) { 127 InputEventData result; 128 result.event_type = ConvertEventTypes(web_event.type); 129 result.event_time_stamp = EventTimeToPPTimeTicks(web_event.timeStampSeconds); 130 return result; 131} 132 133void AppendKeyEvent(const WebInputEvent& event, 134 std::vector<InputEventData>* result_events) { 135 const WebKeyboardEvent& key_event = 136 static_cast<const WebKeyboardEvent&>(event); 137 InputEventData result = GetEventWithCommonFieldsAndType(event); 138 result.event_modifiers = key_event.modifiers; 139 result.key_code = key_event.windowsKeyCode; 140 result.code = CodeForKeyboardEvent(key_event); 141 result_events->push_back(result); 142} 143 144void AppendCharEvent(const WebInputEvent& event, 145 std::vector<InputEventData>* result_events) { 146 const WebKeyboardEvent& key_event = 147 static_cast<const WebKeyboardEvent&>(event); 148 149 // This is a bit complex, the input event will normally just have one 16-bit 150 // character in it, but may be zero or more than one. The text array is 151 // just padded with 0 values for the unused ones, but is not necessarily 152 // null-terminated. 153 // 154 // Here we see how many UTF-16 characters we have. 155 size_t utf16_char_count = 0; 156 while (utf16_char_count < WebKeyboardEvent::textLengthCap && 157 key_event.text[utf16_char_count]) 158 utf16_char_count++; 159 160 // Make a separate InputEventData for each Unicode character in the input. 161 base::i18n::UTF16CharIterator iter(key_event.text, utf16_char_count); 162 while (!iter.end()) { 163 InputEventData result = GetEventWithCommonFieldsAndType(event); 164 result.event_modifiers = key_event.modifiers; 165 base::WriteUnicodeCharacter(iter.get(), &result.character_text); 166 167 result_events->push_back(result); 168 iter.Advance(); 169 } 170} 171 172void AppendMouseEvent(const WebInputEvent& event, 173 std::vector<InputEventData>* result_events) { 174 COMPILE_ASSERT(static_cast<int>(WebMouseEvent::ButtonNone) == 175 static_cast<int>(PP_INPUTEVENT_MOUSEBUTTON_NONE), 176 MouseNone); 177 COMPILE_ASSERT(static_cast<int>(WebMouseEvent::ButtonLeft) == 178 static_cast<int>(PP_INPUTEVENT_MOUSEBUTTON_LEFT), 179 MouseLeft); 180 COMPILE_ASSERT(static_cast<int>(WebMouseEvent::ButtonRight) == 181 static_cast<int>(PP_INPUTEVENT_MOUSEBUTTON_RIGHT), 182 MouseRight); 183 COMPILE_ASSERT(static_cast<int>(WebMouseEvent::ButtonMiddle) == 184 static_cast<int>(PP_INPUTEVENT_MOUSEBUTTON_MIDDLE), 185 MouseMiddle); 186 187 const WebMouseEvent& mouse_event = 188 static_cast<const WebMouseEvent&>(event); 189 InputEventData result = GetEventWithCommonFieldsAndType(event); 190 result.event_modifiers = mouse_event.modifiers; 191 if (mouse_event.type == WebInputEvent::MouseDown || 192 mouse_event.type == WebInputEvent::MouseMove || 193 mouse_event.type == WebInputEvent::MouseUp) { 194 result.mouse_button = 195 static_cast<PP_InputEvent_MouseButton>(mouse_event.button); 196 } 197 result.mouse_position.x = mouse_event.x; 198 result.mouse_position.y = mouse_event.y; 199 result.mouse_click_count = mouse_event.clickCount; 200 result.mouse_movement.x = mouse_event.movementX; 201 result.mouse_movement.y = mouse_event.movementY; 202 result_events->push_back(result); 203} 204 205void AppendMouseWheelEvent(const WebInputEvent& event, 206 std::vector<InputEventData>* result_events) { 207 const WebMouseWheelEvent& mouse_wheel_event = 208 static_cast<const WebMouseWheelEvent&>(event); 209 InputEventData result = GetEventWithCommonFieldsAndType(event); 210 result.event_modifiers = mouse_wheel_event.modifiers; 211 result.wheel_delta.x = mouse_wheel_event.deltaX; 212 result.wheel_delta.y = mouse_wheel_event.deltaY; 213 result.wheel_ticks.x = mouse_wheel_event.wheelTicksX; 214 result.wheel_ticks.y = mouse_wheel_event.wheelTicksY; 215 result.wheel_scroll_by_page = !!mouse_wheel_event.scrollByPage; 216 result_events->push_back(result); 217} 218 219void SetPPTouchPoints(const WebTouchPoint* touches, uint32_t touches_length, 220 std::vector<PP_TouchPoint>* result) { 221 for (uint32_t i = 0; i < touches_length; i++) { 222 const WebTouchPoint& touch_point = touches[i]; 223 PP_TouchPoint pp_pt; 224 pp_pt.id = touch_point.id; 225 pp_pt.position.x = touch_point.position.x; 226 pp_pt.position.y = touch_point.position.y; 227 pp_pt.radius.x = touch_point.radiusX; 228 pp_pt.radius.y = touch_point.radiusY; 229 pp_pt.rotation_angle = touch_point.rotationAngle; 230 pp_pt.pressure = touch_point.force; 231 result->push_back(pp_pt); 232 } 233} 234 235void AppendTouchEvent(const WebInputEvent& event, 236 std::vector<InputEventData>* result_events) { 237 const WebTouchEvent& touch_event = 238 reinterpret_cast<const WebTouchEvent&>(event); 239 240 InputEventData result = GetEventWithCommonFieldsAndType(event); 241 SetPPTouchPoints(touch_event.touches, touch_event.touchesLength, 242 &result.touches); 243 SetPPTouchPoints(touch_event.changedTouches, touch_event.changedTouchesLength, 244 &result.changed_touches); 245 SetPPTouchPoints(touch_event.targetTouches, touch_event.targetTouchesLength, 246 &result.target_touches); 247 248 result_events->push_back(result); 249} 250 251// Structure used to map touch point id's to touch states. Since the pepper 252// touch event structure does not have states for individual touch points and 253// instead relies on the event type in combination with the set of touch lists, 254// we have to set the state for the changed touches to be the same as the event 255// type and all others to be 'stationary.' 256typedef std::map<uint32_t, WebTouchPoint::State> TouchStateMap; 257 258void SetWebTouchPoints(const std::vector<PP_TouchPoint>& pp_touches, 259 const TouchStateMap& states_map, 260 WebTouchPoint* web_touches, 261 uint32_t* web_touches_length) { 262 263 for (uint32_t i = 0; i < pp_touches.size() && 264 i < WebTouchEvent::touchesLengthCap; i++) { 265 WebTouchPoint pt; 266 const PP_TouchPoint& pp_pt = pp_touches[i]; 267 pt.id = pp_pt.id; 268 269 if (states_map.find(pt.id) == states_map.end()) 270 pt.state = WebTouchPoint::StateStationary; 271 else 272 pt.state = states_map.find(pt.id)->second; 273 274 pt.position.x = pp_pt.position.x; 275 pt.position.y = pp_pt.position.y; 276 // TODO bug:http://code.google.com/p/chromium/issues/detail?id=93902 277 pt.screenPosition.x = 0; 278 pt.screenPosition.y = 0; 279 pt.force = pp_pt.pressure; 280 pt.radiusX = pp_pt.radius.x; 281 pt.radiusY = pp_pt.radius.y; 282 pt.rotationAngle = pp_pt.rotation_angle; 283 web_touches[i] = pt; 284 (*web_touches_length)++; 285 } 286} 287 288WebTouchEvent* BuildTouchEvent(const InputEventData& event) { 289 WebTouchEvent* web_event = new WebTouchEvent(); 290 WebTouchPoint::State state = WebTouchPoint::StateUndefined; 291 switch (event.event_type) { 292 case PP_INPUTEVENT_TYPE_TOUCHSTART: 293 web_event->type = WebInputEvent::TouchStart; 294 state = WebTouchPoint::StatePressed; 295 break; 296 case PP_INPUTEVENT_TYPE_TOUCHMOVE: 297 web_event->type = WebInputEvent::TouchMove; 298 state = WebTouchPoint::StateMoved; 299 break; 300 case PP_INPUTEVENT_TYPE_TOUCHEND: 301 web_event->type = WebInputEvent::TouchEnd; 302 state = WebTouchPoint::StateReleased; 303 break; 304 case PP_INPUTEVENT_TYPE_TOUCHCANCEL: 305 web_event->type = WebInputEvent::TouchCancel; 306 state = WebTouchPoint::StateCancelled; 307 break; 308 default: 309 NOTREACHED(); 310 } 311 312 TouchStateMap states_map; 313 for (uint32_t i = 0; i < event.changed_touches.size(); i++) 314 states_map[event.changed_touches[i].id] = state; 315 316 web_event->timeStampSeconds = PPTimeTicksToEventTime(event.event_time_stamp); 317 318 SetWebTouchPoints(event.changed_touches, states_map, 319 web_event->changedTouches, 320 &web_event->changedTouchesLength); 321 322 SetWebTouchPoints(event.touches, states_map, web_event->touches, 323 &web_event->touchesLength); 324 325 SetWebTouchPoints(event.target_touches, states_map, web_event->targetTouches, 326 &web_event->targetTouchesLength); 327 328 if (web_event->type == WebInputEvent::TouchEnd || 329 web_event->type == WebInputEvent::TouchCancel) { 330 SetWebTouchPoints(event.changed_touches, states_map, 331 web_event->touches, &web_event->touchesLength); 332 SetWebTouchPoints(event.changed_touches, states_map, 333 web_event->targetTouches, 334 &web_event->targetTouchesLength); 335 } 336 337 return web_event; 338} 339 340WebKeyboardEvent* BuildKeyEvent(const InputEventData& event) { 341 WebKeyboardEvent* key_event = new WebKeyboardEvent(); 342 switch (event.event_type) { 343 case PP_INPUTEVENT_TYPE_RAWKEYDOWN: 344 key_event->type = WebInputEvent::RawKeyDown; 345 break; 346 case PP_INPUTEVENT_TYPE_KEYDOWN: 347 key_event->type = WebInputEvent::KeyDown; 348 break; 349 case PP_INPUTEVENT_TYPE_KEYUP: 350 key_event->type = WebInputEvent::KeyUp; 351 break; 352 default: 353 NOTREACHED(); 354 } 355 key_event->timeStampSeconds = PPTimeTicksToEventTime(event.event_time_stamp); 356 key_event->modifiers = event.event_modifiers; 357 key_event->windowsKeyCode = event.key_code; 358 key_event->setKeyIdentifierFromWindowsKeyCode(); 359 return key_event; 360} 361 362WebKeyboardEvent* BuildCharEvent(const InputEventData& event) { 363 WebKeyboardEvent* key_event = new WebKeyboardEvent(); 364 key_event->type = WebInputEvent::Char; 365 key_event->timeStampSeconds = PPTimeTicksToEventTime(event.event_time_stamp); 366 key_event->modifiers = event.event_modifiers; 367 368 // Make sure to not read beyond the buffer in case some bad code doesn't 369 // NULL-terminate it (this is called from plugins). 370 size_t text_length_cap = WebKeyboardEvent::textLengthCap; 371 base::string16 text16 = base::UTF8ToUTF16(event.character_text); 372 373 memset(key_event->text, 0, text_length_cap); 374 memset(key_event->unmodifiedText, 0, text_length_cap); 375 for (size_t i = 0; 376 i < std::min(text_length_cap, text16.size()); 377 ++i) 378 key_event->text[i] = text16[i]; 379 return key_event; 380} 381 382WebMouseEvent* BuildMouseEvent(const InputEventData& event) { 383 WebMouseEvent* mouse_event = new WebMouseEvent(); 384 switch (event.event_type) { 385 case PP_INPUTEVENT_TYPE_MOUSEDOWN: 386 mouse_event->type = WebInputEvent::MouseDown; 387 break; 388 case PP_INPUTEVENT_TYPE_MOUSEUP: 389 mouse_event->type = WebInputEvent::MouseUp; 390 break; 391 case PP_INPUTEVENT_TYPE_MOUSEMOVE: 392 mouse_event->type = WebInputEvent::MouseMove; 393 break; 394 case PP_INPUTEVENT_TYPE_MOUSEENTER: 395 mouse_event->type = WebInputEvent::MouseEnter; 396 break; 397 case PP_INPUTEVENT_TYPE_MOUSELEAVE: 398 mouse_event->type = WebInputEvent::MouseLeave; 399 break; 400 case PP_INPUTEVENT_TYPE_CONTEXTMENU: 401 mouse_event->type = WebInputEvent::ContextMenu; 402 break; 403 default: 404 NOTREACHED(); 405 } 406 mouse_event->timeStampSeconds = 407 PPTimeTicksToEventTime(event.event_time_stamp); 408 mouse_event->modifiers = event.event_modifiers; 409 mouse_event->button = 410 static_cast<WebMouseEvent::Button>(event.mouse_button); 411 if (mouse_event->type == WebInputEvent::MouseMove) { 412 if (mouse_event->modifiers & WebInputEvent::LeftButtonDown) 413 mouse_event->button = WebMouseEvent::ButtonLeft; 414 else if (mouse_event->modifiers & WebInputEvent::MiddleButtonDown) 415 mouse_event->button = WebMouseEvent::ButtonMiddle; 416 else if (mouse_event->modifiers & WebInputEvent::RightButtonDown) 417 mouse_event->button = WebMouseEvent::ButtonRight; 418 } 419 mouse_event->x = event.mouse_position.x; 420 mouse_event->y = event.mouse_position.y; 421 mouse_event->clickCount = event.mouse_click_count; 422 mouse_event->movementX = event.mouse_movement.x; 423 mouse_event->movementY = event.mouse_movement.y; 424 return mouse_event; 425} 426 427WebMouseWheelEvent* BuildMouseWheelEvent(const InputEventData& event) { 428 WebMouseWheelEvent* mouse_wheel_event = new WebMouseWheelEvent(); 429 mouse_wheel_event->type = WebInputEvent::MouseWheel; 430 mouse_wheel_event->timeStampSeconds = 431 PPTimeTicksToEventTime(event.event_time_stamp); 432 mouse_wheel_event->modifiers = event.event_modifiers; 433 mouse_wheel_event->deltaX = event.wheel_delta.x; 434 mouse_wheel_event->deltaY = event.wheel_delta.y; 435 mouse_wheel_event->wheelTicksX = event.wheel_ticks.x; 436 mouse_wheel_event->wheelTicksY = event.wheel_ticks.y; 437 mouse_wheel_event->scrollByPage = event.wheel_scroll_by_page; 438 return mouse_wheel_event; 439} 440 441#if !defined(OS_WIN) 442#define VK_RETURN 0x0D 443 444#define VK_PRIOR 0x21 445#define VK_NEXT 0x22 446#define VK_END 0x23 447#define VK_HOME 0x24 448#define VK_LEFT 0x25 449#define VK_UP 0x26 450#define VK_RIGHT 0x27 451#define VK_DOWN 0x28 452#define VK_SNAPSHOT 0x2C 453#define VK_INSERT 0x2D 454#define VK_DELETE 0x2E 455 456#define VK_APPS 0x5D 457 458#define VK_F1 0x70 459#endif 460 461// Convert a character string to a Windows virtual key code. Adapted from 462// src/third_party/WebKit/Tools/DumpRenderTree/chromium/EventSender.cpp. This 463// is used by CreateSimulatedWebInputEvents to convert keyboard events. 464void GetKeyCode(const std::string& char_text, 465 WebUChar* code, 466 WebUChar* text, 467 bool* needs_shift_modifier, 468 bool* generate_char) { 469 WebUChar vk_code = 0; 470 WebUChar vk_text = 0; 471 *needs_shift_modifier = false; 472 *generate_char = false; 473 if ("\n" == char_text) { 474 vk_text = vk_code = VK_RETURN; 475 *generate_char = true; 476 } else if ("rightArrow" == char_text) { 477 vk_code = VK_RIGHT; 478 } else if ("downArrow" == char_text) { 479 vk_code = VK_DOWN; 480 } else if ("leftArrow" == char_text) { 481 vk_code = VK_LEFT; 482 } else if ("upArrow" == char_text) { 483 vk_code = VK_UP; 484 } else if ("insert" == char_text) { 485 vk_code = VK_INSERT; 486 } else if ("delete" == char_text) { 487 vk_code = VK_DELETE; 488 } else if ("pageUp" == char_text) { 489 vk_code = VK_PRIOR; 490 } else if ("pageDown" == char_text) { 491 vk_code = VK_NEXT; 492 } else if ("home" == char_text) { 493 vk_code = VK_HOME; 494 } else if ("end" == char_text) { 495 vk_code = VK_END; 496 } else if ("printScreen" == char_text) { 497 vk_code = VK_SNAPSHOT; 498 } else if ("menu" == char_text) { 499 vk_code = VK_APPS; 500 } else { 501 // Compare the input string with the function-key names defined by the 502 // DOM spec (i.e. "F1",...,"F24"). 503 for (int i = 1; i <= 24; ++i) { 504 std::string functionKeyName = base::StringPrintf("F%d", i); 505 if (functionKeyName == char_text) { 506 vk_code = VK_F1 + (i - 1); 507 break; 508 } 509 } 510 if (!vk_code) { 511 WebString web_char_text = 512 WebString::fromUTF8(char_text.data(), char_text.size()); 513 DCHECK_EQ(web_char_text.length(), 1U); 514 vk_text = vk_code = web_char_text.at(0); 515 *needs_shift_modifier = 516 (vk_code & 0xFF) >= 'A' && (vk_code & 0xFF) <= 'Z'; 517 if ((vk_code & 0xFF) >= 'a' && (vk_code & 0xFF) <= 'z') 518 vk_code -= 'a' - 'A'; 519 *generate_char = true; 520 } 521 } 522 523 *code = vk_code; 524 *text = vk_text; 525} 526 527} // namespace 528 529void CreateInputEventData(const WebInputEvent& event, 530 std::vector<InputEventData>* result) { 531 result->clear(); 532 533 switch (event.type) { 534 case WebInputEvent::MouseDown: 535 case WebInputEvent::MouseUp: 536 case WebInputEvent::MouseMove: 537 case WebInputEvent::MouseEnter: 538 case WebInputEvent::MouseLeave: 539 case WebInputEvent::ContextMenu: 540 AppendMouseEvent(event, result); 541 break; 542 case WebInputEvent::MouseWheel: 543 AppendMouseWheelEvent(event, result); 544 break; 545 case WebInputEvent::RawKeyDown: 546 case WebInputEvent::KeyDown: 547 case WebInputEvent::KeyUp: 548 AppendKeyEvent(event, result); 549 break; 550 case WebInputEvent::Char: 551 AppendCharEvent(event, result); 552 break; 553 case WebInputEvent::TouchStart: 554 case WebInputEvent::TouchMove: 555 case WebInputEvent::TouchEnd: 556 case WebInputEvent::TouchCancel: 557 AppendTouchEvent(event, result); 558 break; 559 case WebInputEvent::Undefined: 560 default: 561 break; 562 } 563} 564 565WebInputEvent* CreateWebInputEvent(const InputEventData& event) { 566 scoped_ptr<WebInputEvent> web_input_event; 567 switch (event.event_type) { 568 case PP_INPUTEVENT_TYPE_UNDEFINED: 569 return NULL; 570 case PP_INPUTEVENT_TYPE_MOUSEDOWN: 571 case PP_INPUTEVENT_TYPE_MOUSEUP: 572 case PP_INPUTEVENT_TYPE_MOUSEMOVE: 573 case PP_INPUTEVENT_TYPE_MOUSEENTER: 574 case PP_INPUTEVENT_TYPE_MOUSELEAVE: 575 case PP_INPUTEVENT_TYPE_CONTEXTMENU: 576 web_input_event.reset(BuildMouseEvent(event)); 577 break; 578 case PP_INPUTEVENT_TYPE_WHEEL: 579 web_input_event.reset(BuildMouseWheelEvent(event)); 580 break; 581 case PP_INPUTEVENT_TYPE_RAWKEYDOWN: 582 case PP_INPUTEVENT_TYPE_KEYDOWN: 583 case PP_INPUTEVENT_TYPE_KEYUP: 584 web_input_event.reset(BuildKeyEvent(event)); 585 break; 586 case PP_INPUTEVENT_TYPE_CHAR: 587 web_input_event.reset(BuildCharEvent(event)); 588 break; 589 case PP_INPUTEVENT_TYPE_IME_COMPOSITION_START: 590 case PP_INPUTEVENT_TYPE_IME_COMPOSITION_UPDATE: 591 case PP_INPUTEVENT_TYPE_IME_COMPOSITION_END: 592 case PP_INPUTEVENT_TYPE_IME_TEXT: 593 // TODO(kinaba) implement in WebKit an event structure to handle 594 // composition events. 595 NOTREACHED(); 596 break; 597 case PP_INPUTEVENT_TYPE_TOUCHSTART: 598 case PP_INPUTEVENT_TYPE_TOUCHMOVE: 599 case PP_INPUTEVENT_TYPE_TOUCHEND: 600 case PP_INPUTEVENT_TYPE_TOUCHCANCEL: 601 web_input_event.reset(BuildTouchEvent(event)); 602 break; 603 } 604 605 return web_input_event.release(); 606} 607 608// Generate a coherent sequence of input events to simulate a user event. 609// From src/third_party/WebKit/Tools/DumpRenderTree/chromium/EventSender.cpp. 610std::vector<linked_ptr<WebInputEvent> > CreateSimulatedWebInputEvents( 611 const ppapi::InputEventData& event, 612 int plugin_x, 613 int plugin_y) { 614 std::vector<linked_ptr<WebInputEvent> > events; 615 linked_ptr<WebInputEvent> original_event(CreateWebInputEvent(event)); 616 617 switch (event.event_type) { 618 case PP_INPUTEVENT_TYPE_MOUSEDOWN: 619 case PP_INPUTEVENT_TYPE_MOUSEUP: 620 case PP_INPUTEVENT_TYPE_MOUSEMOVE: 621 case PP_INPUTEVENT_TYPE_MOUSEENTER: 622 case PP_INPUTEVENT_TYPE_MOUSELEAVE: 623 case PP_INPUTEVENT_TYPE_TOUCHSTART: 624 case PP_INPUTEVENT_TYPE_TOUCHMOVE: 625 case PP_INPUTEVENT_TYPE_TOUCHEND: 626 case PP_INPUTEVENT_TYPE_TOUCHCANCEL: 627 events.push_back(original_event); 628 break; 629 630 case PP_INPUTEVENT_TYPE_WHEEL: { 631 WebMouseWheelEvent* web_mouse_wheel_event = 632 static_cast<WebMouseWheelEvent*>(original_event.get()); 633 web_mouse_wheel_event->x = plugin_x; 634 web_mouse_wheel_event->y = plugin_y; 635 events.push_back(original_event); 636 break; 637 } 638 639 case PP_INPUTEVENT_TYPE_RAWKEYDOWN: 640 case PP_INPUTEVENT_TYPE_KEYDOWN: 641 case PP_INPUTEVENT_TYPE_KEYUP: { 642 // Windows key down events should always be "raw" to avoid an ASSERT. 643#if defined(OS_WIN) 644 WebKeyboardEvent* web_keyboard_event = 645 static_cast<WebKeyboardEvent*>(original_event.get()); 646 if (web_keyboard_event->type == WebInputEvent::KeyDown) 647 web_keyboard_event->type = WebInputEvent::RawKeyDown; 648#endif 649 events.push_back(original_event); 650 break; 651 } 652 653 case PP_INPUTEVENT_TYPE_CHAR: { 654 WebKeyboardEvent* web_char_event = 655 static_cast<WebKeyboardEvent*>(original_event.get()); 656 657 WebUChar code = 0, text = 0; 658 bool needs_shift_modifier = false, generate_char = false; 659 GetKeyCode(event.character_text, 660 &code, 661 &text, 662 &needs_shift_modifier, 663 &generate_char); 664 665 // Synthesize key down and key up events in all cases. 666 scoped_ptr<WebKeyboardEvent> key_down_event(new WebKeyboardEvent()); 667 scoped_ptr<WebKeyboardEvent> key_up_event(new WebKeyboardEvent()); 668 669 key_down_event->type = WebInputEvent::RawKeyDown; 670 key_down_event->windowsKeyCode = code; 671 key_down_event->nativeKeyCode = code; 672 if (needs_shift_modifier) 673 key_down_event->modifiers |= WebInputEvent::ShiftKey; 674 675 // If a char event is needed, set the text fields. 676 if (generate_char) { 677 key_down_event->text[0] = text; 678 key_down_event->unmodifiedText[0] = text; 679 } 680 // Convert the key code to a string identifier. 681 key_down_event->setKeyIdentifierFromWindowsKeyCode(); 682 683 *key_up_event = *web_char_event = *key_down_event; 684 685 events.push_back(linked_ptr<WebInputEvent>(key_down_event.release())); 686 687 if (generate_char) { 688 web_char_event->type = WebInputEvent::Char; 689 web_char_event->keyIdentifier[0] = '\0'; 690 events.push_back(original_event); 691 } 692 693 key_up_event->type = WebInputEvent::KeyUp; 694 events.push_back(linked_ptr<WebInputEvent>(key_up_event.release())); 695 break; 696 } 697 698 default: 699 break; 700 } 701 return events; 702} 703 704PP_InputEvent_Class ClassifyInputEvent(WebInputEvent::Type type) { 705 switch (type) { 706 case WebInputEvent::MouseDown: 707 case WebInputEvent::MouseUp: 708 case WebInputEvent::MouseMove: 709 case WebInputEvent::MouseEnter: 710 case WebInputEvent::MouseLeave: 711 case WebInputEvent::ContextMenu: 712 return PP_INPUTEVENT_CLASS_MOUSE; 713 case WebInputEvent::MouseWheel: 714 return PP_INPUTEVENT_CLASS_WHEEL; 715 case WebInputEvent::RawKeyDown: 716 case WebInputEvent::KeyDown: 717 case WebInputEvent::KeyUp: 718 case WebInputEvent::Char: 719 return PP_INPUTEVENT_CLASS_KEYBOARD; 720 case WebInputEvent::TouchCancel: 721 case WebInputEvent::TouchEnd: 722 case WebInputEvent::TouchMove: 723 case WebInputEvent::TouchStart: 724 return PP_INPUTEVENT_CLASS_TOUCH; 725 case WebInputEvent::Undefined: 726 default: 727 NOTREACHED(); 728 return PP_InputEvent_Class(0); 729 } 730} 731 732} // namespace content 733