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