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