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