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