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
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  result.usb_key_code = 0;
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.usb_key_code = UsbKeyCodeForKeyboardEvent(key_event);
142  result.code = CodeForKeyboardEvent(key_event);
143  result_events->push_back(result);
144}
145
146void 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
174void 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
207void 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
221void 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
237void 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.'
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; 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
290WebTouchEvent* 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
342WebKeyboardEvent* 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
364WebKeyboardEvent* 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
384WebMouseEvent* 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
429WebMouseWheelEvent* 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.
466void 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
531void 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
567WebInputEvent* 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.
612std::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
706PP_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