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
24using ppapi::EventTimeToPPTimeTicks;
25using ppapi::InputEventData;
26using ppapi::PPTimeTicksToEventTime;
27using blink::WebInputEvent;
28using blink::WebKeyboardEvent;
29using blink::WebMouseEvent;
30using blink::WebMouseWheelEvent;
31using blink::WebString;
32using blink::WebTouchEvent;
33using blink::WebTouchPoint;
34using blink::WebUChar;
35
36namespace content {
37
38namespace {
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).
43COMPILE_ASSERT(static_cast<int>(PP_INPUTEVENT_MODIFIER_SHIFTKEY) ==
44                   static_cast<int>(WebInputEvent::ShiftKey),
45               ShiftKeyMatches);
46COMPILE_ASSERT(static_cast<int>(PP_INPUTEVENT_MODIFIER_CONTROLKEY) ==
47                   static_cast<int>(WebInputEvent::ControlKey),
48               ControlKeyMatches);
49COMPILE_ASSERT(static_cast<int>(PP_INPUTEVENT_MODIFIER_ALTKEY) ==
50                   static_cast<int>(WebInputEvent::AltKey),
51               AltKeyMatches);
52COMPILE_ASSERT(static_cast<int>(PP_INPUTEVENT_MODIFIER_METAKEY) ==
53                   static_cast<int>(WebInputEvent::MetaKey),
54               MetaKeyMatches);
55COMPILE_ASSERT(static_cast<int>(PP_INPUTEVENT_MODIFIER_ISKEYPAD) ==
56                   static_cast<int>(WebInputEvent::IsKeyPad),
57               KeyPadMatches);
58COMPILE_ASSERT(static_cast<int>(PP_INPUTEVENT_MODIFIER_ISAUTOREPEAT) ==
59                   static_cast<int>(WebInputEvent::IsAutoRepeat),
60               AutoRepeatMatches);
61COMPILE_ASSERT(static_cast<int>(PP_INPUTEVENT_MODIFIER_LEFTBUTTONDOWN) ==
62                   static_cast<int>(WebInputEvent::LeftButtonDown),
63               LeftButtonMatches);
64COMPILE_ASSERT(static_cast<int>(PP_INPUTEVENT_MODIFIER_MIDDLEBUTTONDOWN) ==
65                   static_cast<int>(WebInputEvent::MiddleButtonDown),
66               MiddleButtonMatches);
67COMPILE_ASSERT(static_cast<int>(PP_INPUTEVENT_MODIFIER_RIGHTBUTTONDOWN) ==
68                   static_cast<int>(WebInputEvent::RightButtonDown),
69               RightButtonMatches);
70COMPILE_ASSERT(static_cast<int>(PP_INPUTEVENT_MODIFIER_CAPSLOCKKEY) ==
71                   static_cast<int>(WebInputEvent::CapsLockOn),
72               CapsLockMatches);
73COMPILE_ASSERT(static_cast<int>(PP_INPUTEVENT_MODIFIER_NUMLOCKKEY) ==
74                   static_cast<int>(WebInputEvent::NumLockOn),
75               NumLockMatches);
76COMPILE_ASSERT(static_cast<int>(PP_INPUTEVENT_MODIFIER_ISLEFT) ==
77                   static_cast<int>(WebInputEvent::IsLeft),
78               LeftMatches);
79COMPILE_ASSERT(static_cast<int>(PP_INPUTEVENT_MODIFIER_ISRIGHT) ==
80                   static_cast<int>(WebInputEvent::IsRight),
81               RightMatches);
82
83PP_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.
124InputEventData 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
131void 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
142void 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
170void 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
202void 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
216enum 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};
221void 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
249void 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
269WebTouchPoint 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
286bool 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
298void 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
320WebTouchEvent* 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
362WebKeyboardEvent* 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
384WebKeyboardEvent* 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
402WebMouseEvent* 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
446WebMouseWheelEvent* 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.
483void 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
548void 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
584WebInputEvent* 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.
629std::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
723PP_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