event_conversion.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
13c827367444ee418f129b2c238299f49d3264554Jarkko Poyry// Copyright (c) 2012 The Chromium Authors. All rights reserved.
23c827367444ee418f129b2c238299f49d3264554Jarkko Poyry// Use of this source code is governed by a BSD-style license that can be
33c827367444ee418f129b2c238299f49d3264554Jarkko Poyry// found in the LICENSE file.
43c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
53c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "content/renderer/pepper/event_conversion.h"
63c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
73c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include <map>
83c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
93c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "base/basictypes.h"
103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "base/i18n/char_iterator.h"
113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "base/logging.h"
123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "base/memory/scoped_ptr.h"
133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "base/strings/string_util.h"
143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "base/strings/stringprintf.h"
153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "base/strings/utf_string_conversion_utils.h"
163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "base/strings/utf_string_conversions.h"
173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "content/renderer/pepper/common.h"
183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "content/renderer/pepper/usb_key_code_conversion.h"
193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "ppapi/c/pp_input_event.h"
203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "ppapi/shared_impl/ppb_input_event_shared.h"
213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "ppapi/shared_impl/time_conversion.h"
223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "third_party/WebKit/public/platform/WebGamepads.h"
233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "third_party/WebKit/public/platform/WebString.h"
243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "third_party/WebKit/public/web/WebInputEvent.h"
253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
263c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing ppapi::EventTimeToPPTimeTicks;
273c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing ppapi::InputEventData;
283c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing ppapi::PPTimeTicksToEventTime;
293c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing blink::WebInputEvent;
303c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing blink::WebKeyboardEvent;
313c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing blink::WebMouseEvent;
323c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing blink::WebMouseWheelEvent;
333c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing blink::WebString;
343c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing blink::WebTouchEvent;
353c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing blink::WebTouchPoint;
363c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing blink::WebUChar;
373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
383c827367444ee418f129b2c238299f49d3264554Jarkko Poyrynamespace 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 =
188      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, 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(touch_event.touches, touch_event.touchesLength,
242                   &result.touches);
243  SetPPTouchPoints(touch_event.changedTouches, touch_event.changedTouchesLength,
244                   &result.changed_touches);
245  SetPPTouchPoints(touch_event.targetTouches, touch_event.targetTouchesLength,
246                   &result.target_touches);
247
248  result_events->push_back(result);
249}
250
251// Structure used to map touch point id's to touch states.  Since the pepper
252// touch event structure does not have states for individual touch points and
253// instead relies on the event type in combination with the set of touch lists,
254// we have to set the state for the changed touches to be the same as the event
255// type and all others to be 'stationary.'
256typedef std::map<uint32_t, WebTouchPoint::State> TouchStateMap;
257
258void SetWebTouchPoints(const std::vector<PP_TouchPoint>& pp_touches,
259                       const TouchStateMap& states_map,
260                       WebTouchPoint* web_touches,
261                       uint32_t* web_touches_length) {
262
263  for (uint32_t i = 0; i < pp_touches.size() &&
264       i < WebTouchEvent::touchesLengthCap; i++) {
265    WebTouchPoint pt;
266    const PP_TouchPoint& pp_pt = pp_touches[i];
267    pt.id = pp_pt.id;
268
269    if (states_map.find(pt.id) == states_map.end())
270      pt.state = WebTouchPoint::StateStationary;
271    else
272      pt.state = states_map.find(pt.id)->second;
273
274    pt.position.x = pp_pt.position.x;
275    pt.position.y = pp_pt.position.y;
276    // TODO bug:http://code.google.com/p/chromium/issues/detail?id=93902
277    pt.screenPosition.x = 0;
278    pt.screenPosition.y = 0;
279    pt.force = pp_pt.pressure;
280    pt.radiusX = pp_pt.radius.x;
281    pt.radiusY = pp_pt.radius.y;
282    pt.rotationAngle = pp_pt.rotation_angle;
283    web_touches[i] = pt;
284    (*web_touches_length)++;
285  }
286}
287
288WebTouchEvent* BuildTouchEvent(const InputEventData& event) {
289  WebTouchEvent* web_event = new WebTouchEvent();
290  WebTouchPoint::State state = WebTouchPoint::StateUndefined;
291  switch (event.event_type) {
292    case PP_INPUTEVENT_TYPE_TOUCHSTART:
293      web_event->type = WebInputEvent::TouchStart;
294      state = WebTouchPoint::StatePressed;
295      break;
296    case PP_INPUTEVENT_TYPE_TOUCHMOVE:
297      web_event->type = WebInputEvent::TouchMove;
298      state = WebTouchPoint::StateMoved;
299      break;
300    case PP_INPUTEVENT_TYPE_TOUCHEND:
301      web_event->type = WebInputEvent::TouchEnd;
302      state = WebTouchPoint::StateReleased;
303      break;
304    case PP_INPUTEVENT_TYPE_TOUCHCANCEL:
305      web_event->type = WebInputEvent::TouchCancel;
306      state = WebTouchPoint::StateCancelled;
307      break;
308    default:
309      NOTREACHED();
310  }
311
312  TouchStateMap states_map;
313  for (uint32_t i = 0; i < event.changed_touches.size(); i++)
314    states_map[event.changed_touches[i].id] = state;
315
316  web_event->timeStampSeconds = PPTimeTicksToEventTime(event.event_time_stamp);
317
318  SetWebTouchPoints(event.changed_touches, states_map,
319                    web_event->changedTouches,
320                    &web_event->changedTouchesLength);
321
322  SetWebTouchPoints(event.touches, states_map, web_event->touches,
323                    &web_event->touchesLength);
324
325  SetWebTouchPoints(event.target_touches, states_map, web_event->targetTouches,
326                    &web_event->targetTouchesLength);
327
328  if (web_event->type == WebInputEvent::TouchEnd ||
329      web_event->type == WebInputEvent::TouchCancel) {
330    SetWebTouchPoints(event.changed_touches, states_map,
331                      web_event->touches, &web_event->touchesLength);
332    SetWebTouchPoints(event.changed_touches, states_map,
333                      web_event->targetTouches,
334                      &web_event->targetTouchesLength);
335  }
336
337  return web_event;
338}
339
340WebKeyboardEvent* BuildKeyEvent(const InputEventData& event) {
341  WebKeyboardEvent* key_event = new WebKeyboardEvent();
342  switch (event.event_type) {
343    case PP_INPUTEVENT_TYPE_RAWKEYDOWN:
344      key_event->type = WebInputEvent::RawKeyDown;
345      break;
346    case PP_INPUTEVENT_TYPE_KEYDOWN:
347      key_event->type = WebInputEvent::KeyDown;
348      break;
349    case PP_INPUTEVENT_TYPE_KEYUP:
350      key_event->type = WebInputEvent::KeyUp;
351      break;
352    default:
353      NOTREACHED();
354  }
355  key_event->timeStampSeconds = PPTimeTicksToEventTime(event.event_time_stamp);
356  key_event->modifiers = event.event_modifiers;
357  key_event->windowsKeyCode = event.key_code;
358  key_event->setKeyIdentifierFromWindowsKeyCode();
359  return key_event;
360}
361
362WebKeyboardEvent* BuildCharEvent(const InputEventData& event) {
363  WebKeyboardEvent* key_event = new WebKeyboardEvent();
364  key_event->type = WebInputEvent::Char;
365  key_event->timeStampSeconds = PPTimeTicksToEventTime(event.event_time_stamp);
366  key_event->modifiers = event.event_modifiers;
367
368  // Make sure to not read beyond the buffer in case some bad code doesn't
369  // NULL-terminate it (this is called from plugins).
370  size_t text_length_cap = WebKeyboardEvent::textLengthCap;
371  base::string16 text16 = base::UTF8ToUTF16(event.character_text);
372
373  memset(key_event->text, 0, text_length_cap);
374  memset(key_event->unmodifiedText, 0, text_length_cap);
375  for (size_t i = 0;
376       i < std::min(text_length_cap, text16.size());
377       ++i)
378    key_event->text[i] = text16[i];
379  return key_event;
380}
381
382WebMouseEvent* BuildMouseEvent(const InputEventData& event) {
383  WebMouseEvent* mouse_event = new WebMouseEvent();
384  switch (event.event_type) {
385    case PP_INPUTEVENT_TYPE_MOUSEDOWN:
386      mouse_event->type = WebInputEvent::MouseDown;
387      break;
388    case PP_INPUTEVENT_TYPE_MOUSEUP:
389      mouse_event->type = WebInputEvent::MouseUp;
390      break;
391    case PP_INPUTEVENT_TYPE_MOUSEMOVE:
392      mouse_event->type = WebInputEvent::MouseMove;
393      break;
394    case PP_INPUTEVENT_TYPE_MOUSEENTER:
395      mouse_event->type = WebInputEvent::MouseEnter;
396      break;
397    case PP_INPUTEVENT_TYPE_MOUSELEAVE:
398      mouse_event->type = WebInputEvent::MouseLeave;
399      break;
400    case PP_INPUTEVENT_TYPE_CONTEXTMENU:
401      mouse_event->type = WebInputEvent::ContextMenu;
402      break;
403    default:
404      NOTREACHED();
405  }
406  mouse_event->timeStampSeconds =
407      PPTimeTicksToEventTime(event.event_time_stamp);
408  mouse_event->modifiers = event.event_modifiers;
409  mouse_event->button =
410      static_cast<WebMouseEvent::Button>(event.mouse_button);
411  if (mouse_event->type == WebInputEvent::MouseMove) {
412    if (mouse_event->modifiers & WebInputEvent::LeftButtonDown)
413      mouse_event->button = WebMouseEvent::ButtonLeft;
414    else if (mouse_event->modifiers & WebInputEvent::MiddleButtonDown)
415      mouse_event->button = WebMouseEvent::ButtonMiddle;
416    else if (mouse_event->modifiers & WebInputEvent::RightButtonDown)
417      mouse_event->button = WebMouseEvent::ButtonRight;
418  }
419  mouse_event->x = event.mouse_position.x;
420  mouse_event->y = event.mouse_position.y;
421  mouse_event->clickCount = event.mouse_click_count;
422  mouse_event->movementX = event.mouse_movement.x;
423  mouse_event->movementY = event.mouse_movement.y;
424  return mouse_event;
425}
426
427WebMouseWheelEvent* BuildMouseWheelEvent(const InputEventData& event) {
428  WebMouseWheelEvent* mouse_wheel_event = new WebMouseWheelEvent();
429  mouse_wheel_event->type = WebInputEvent::MouseWheel;
430  mouse_wheel_event->timeStampSeconds =
431      PPTimeTicksToEventTime(event.event_time_stamp);
432  mouse_wheel_event->modifiers = event.event_modifiers;
433  mouse_wheel_event->deltaX = event.wheel_delta.x;
434  mouse_wheel_event->deltaY = event.wheel_delta.y;
435  mouse_wheel_event->wheelTicksX = event.wheel_ticks.x;
436  mouse_wheel_event->wheelTicksY = event.wheel_ticks.y;
437  mouse_wheel_event->scrollByPage = event.wheel_scroll_by_page;
438  return mouse_wheel_event;
439}
440
441#if !defined(OS_WIN)
442#define VK_RETURN         0x0D
443
444#define VK_PRIOR          0x21
445#define VK_NEXT           0x22
446#define VK_END            0x23
447#define VK_HOME           0x24
448#define VK_LEFT           0x25
449#define VK_UP             0x26
450#define VK_RIGHT          0x27
451#define VK_DOWN           0x28
452#define VK_SNAPSHOT       0x2C
453#define VK_INSERT         0x2D
454#define VK_DELETE         0x2E
455
456#define VK_APPS           0x5D
457
458#define VK_F1             0x70
459#endif
460
461// Convert a character string to a Windows virtual key code. Adapted from
462// src/third_party/WebKit/Tools/DumpRenderTree/chromium/EventSender.cpp. This
463// is used by CreateSimulatedWebInputEvents to convert keyboard events.
464void GetKeyCode(const std::string& char_text,
465                WebUChar* code,
466                WebUChar* text,
467                bool* needs_shift_modifier,
468                bool* generate_char) {
469  WebUChar vk_code = 0;
470  WebUChar vk_text = 0;
471  *needs_shift_modifier = false;
472  *generate_char = false;
473  if ("\n" == char_text) {
474    vk_text = vk_code = VK_RETURN;
475    *generate_char = true;
476  } else if ("rightArrow" == char_text) {
477    vk_code = VK_RIGHT;
478  } else if ("downArrow" == char_text) {
479    vk_code = VK_DOWN;
480  } else if ("leftArrow" == char_text) {
481    vk_code = VK_LEFT;
482  } else if ("upArrow" == char_text) {
483    vk_code = VK_UP;
484  } else if ("insert" == char_text) {
485    vk_code = VK_INSERT;
486  } else if ("delete" == char_text) {
487    vk_code = VK_DELETE;
488  } else if ("pageUp" == char_text) {
489    vk_code = VK_PRIOR;
490  } else if ("pageDown" == char_text) {
491    vk_code = VK_NEXT;
492  } else if ("home" == char_text) {
493    vk_code = VK_HOME;
494  } else if ("end" == char_text) {
495    vk_code = VK_END;
496  } else if ("printScreen" == char_text) {
497    vk_code = VK_SNAPSHOT;
498  } else if ("menu" == char_text) {
499    vk_code = VK_APPS;
500  } else {
501    // Compare the input string with the function-key names defined by the
502    // DOM spec (i.e. "F1",...,"F24").
503    for (int i = 1; i <= 24; ++i) {
504      std::string functionKeyName = base::StringPrintf("F%d", i);
505      if (functionKeyName == char_text) {
506        vk_code = VK_F1 + (i - 1);
507        break;
508      }
509    }
510    if (!vk_code) {
511      WebString web_char_text =
512          WebString::fromUTF8(char_text.data(), char_text.size());
513      DCHECK_EQ(web_char_text.length(), 1U);
514      vk_text = vk_code = web_char_text.at(0);
515      *needs_shift_modifier =
516          (vk_code & 0xFF) >= 'A' && (vk_code & 0xFF) <= 'Z';
517      if ((vk_code & 0xFF) >= 'a' && (vk_code & 0xFF) <= 'z')
518          vk_code -= 'a' - 'A';
519      *generate_char = true;
520    }
521  }
522
523  *code = vk_code;
524  *text = vk_text;
525}
526
527}  // namespace
528
529void CreateInputEventData(const WebInputEvent& event,
530                          std::vector<InputEventData>* result) {
531  result->clear();
532
533  switch (event.type) {
534    case WebInputEvent::MouseDown:
535    case WebInputEvent::MouseUp:
536    case WebInputEvent::MouseMove:
537    case WebInputEvent::MouseEnter:
538    case WebInputEvent::MouseLeave:
539    case WebInputEvent::ContextMenu:
540      AppendMouseEvent(event, result);
541      break;
542    case WebInputEvent::MouseWheel:
543      AppendMouseWheelEvent(event, result);
544      break;
545    case WebInputEvent::RawKeyDown:
546    case WebInputEvent::KeyDown:
547    case WebInputEvent::KeyUp:
548      AppendKeyEvent(event, result);
549      break;
550    case WebInputEvent::Char:
551      AppendCharEvent(event, result);
552      break;
553    case WebInputEvent::TouchStart:
554    case WebInputEvent::TouchMove:
555    case WebInputEvent::TouchEnd:
556    case WebInputEvent::TouchCancel:
557      AppendTouchEvent(event, result);
558      break;
559    case WebInputEvent::Undefined:
560    default:
561      break;
562  }
563}
564
565WebInputEvent* CreateWebInputEvent(const InputEventData& event) {
566  scoped_ptr<WebInputEvent> web_input_event;
567  switch (event.event_type) {
568    case PP_INPUTEVENT_TYPE_UNDEFINED:
569      return NULL;
570    case PP_INPUTEVENT_TYPE_MOUSEDOWN:
571    case PP_INPUTEVENT_TYPE_MOUSEUP:
572    case PP_INPUTEVENT_TYPE_MOUSEMOVE:
573    case PP_INPUTEVENT_TYPE_MOUSEENTER:
574    case PP_INPUTEVENT_TYPE_MOUSELEAVE:
575    case PP_INPUTEVENT_TYPE_CONTEXTMENU:
576      web_input_event.reset(BuildMouseEvent(event));
577      break;
578    case PP_INPUTEVENT_TYPE_WHEEL:
579      web_input_event.reset(BuildMouseWheelEvent(event));
580      break;
581    case PP_INPUTEVENT_TYPE_RAWKEYDOWN:
582    case PP_INPUTEVENT_TYPE_KEYDOWN:
583    case PP_INPUTEVENT_TYPE_KEYUP:
584      web_input_event.reset(BuildKeyEvent(event));
585      break;
586    case PP_INPUTEVENT_TYPE_CHAR:
587      web_input_event.reset(BuildCharEvent(event));
588      break;
589    case PP_INPUTEVENT_TYPE_IME_COMPOSITION_START:
590    case PP_INPUTEVENT_TYPE_IME_COMPOSITION_UPDATE:
591    case PP_INPUTEVENT_TYPE_IME_COMPOSITION_END:
592    case PP_INPUTEVENT_TYPE_IME_TEXT:
593      // TODO(kinaba) implement in WebKit an event structure to handle
594      // composition events.
595      NOTREACHED();
596      break;
597    case PP_INPUTEVENT_TYPE_TOUCHSTART:
598    case PP_INPUTEVENT_TYPE_TOUCHMOVE:
599    case PP_INPUTEVENT_TYPE_TOUCHEND:
600    case PP_INPUTEVENT_TYPE_TOUCHCANCEL:
601      web_input_event.reset(BuildTouchEvent(event));
602      break;
603  }
604
605  return web_input_event.release();
606}
607
608// Generate a coherent sequence of input events to simulate a user event.
609// From src/third_party/WebKit/Tools/DumpRenderTree/chromium/EventSender.cpp.
610std::vector<linked_ptr<WebInputEvent> > CreateSimulatedWebInputEvents(
611    const ppapi::InputEventData& event,
612    int plugin_x,
613    int plugin_y) {
614  std::vector<linked_ptr<WebInputEvent> > events;
615  linked_ptr<WebInputEvent> original_event(CreateWebInputEvent(event));
616
617  switch (event.event_type) {
618    case PP_INPUTEVENT_TYPE_MOUSEDOWN:
619    case PP_INPUTEVENT_TYPE_MOUSEUP:
620    case PP_INPUTEVENT_TYPE_MOUSEMOVE:
621    case PP_INPUTEVENT_TYPE_MOUSEENTER:
622    case PP_INPUTEVENT_TYPE_MOUSELEAVE:
623    case PP_INPUTEVENT_TYPE_TOUCHSTART:
624    case PP_INPUTEVENT_TYPE_TOUCHMOVE:
625    case PP_INPUTEVENT_TYPE_TOUCHEND:
626    case PP_INPUTEVENT_TYPE_TOUCHCANCEL:
627      events.push_back(original_event);
628      break;
629
630    case PP_INPUTEVENT_TYPE_WHEEL: {
631      WebMouseWheelEvent* web_mouse_wheel_event =
632          static_cast<WebMouseWheelEvent*>(original_event.get());
633      web_mouse_wheel_event->x = plugin_x;
634      web_mouse_wheel_event->y = plugin_y;
635      events.push_back(original_event);
636      break;
637    }
638
639    case PP_INPUTEVENT_TYPE_RAWKEYDOWN:
640    case PP_INPUTEVENT_TYPE_KEYDOWN:
641    case PP_INPUTEVENT_TYPE_KEYUP: {
642      // Windows key down events should always be "raw" to avoid an ASSERT.
643#if defined(OS_WIN)
644      WebKeyboardEvent* web_keyboard_event =
645          static_cast<WebKeyboardEvent*>(original_event.get());
646      if (web_keyboard_event->type == WebInputEvent::KeyDown)
647        web_keyboard_event->type = WebInputEvent::RawKeyDown;
648#endif
649      events.push_back(original_event);
650      break;
651    }
652
653    case PP_INPUTEVENT_TYPE_CHAR: {
654      WebKeyboardEvent* web_char_event =
655          static_cast<WebKeyboardEvent*>(original_event.get());
656
657      WebUChar code = 0, text = 0;
658      bool needs_shift_modifier = false, generate_char = false;
659      GetKeyCode(event.character_text,
660                 &code,
661                 &text,
662                 &needs_shift_modifier,
663                 &generate_char);
664
665      // Synthesize key down and key up events in all cases.
666      scoped_ptr<WebKeyboardEvent> key_down_event(new WebKeyboardEvent());
667      scoped_ptr<WebKeyboardEvent> key_up_event(new WebKeyboardEvent());
668
669      key_down_event->type = WebInputEvent::RawKeyDown;
670      key_down_event->windowsKeyCode = code;
671      key_down_event->nativeKeyCode = code;
672      if (needs_shift_modifier)
673        key_down_event->modifiers |= WebInputEvent::ShiftKey;
674
675      // If a char event is needed, set the text fields.
676      if (generate_char) {
677        key_down_event->text[0] = text;
678        key_down_event->unmodifiedText[0] = text;
679      }
680      // Convert the key code to a string identifier.
681      key_down_event->setKeyIdentifierFromWindowsKeyCode();
682
683      *key_up_event = *web_char_event = *key_down_event;
684
685      events.push_back(linked_ptr<WebInputEvent>(key_down_event.release()));
686
687      if (generate_char) {
688        web_char_event->type = WebInputEvent::Char;
689        web_char_event->keyIdentifier[0] = '\0';
690        events.push_back(original_event);
691      }
692
693      key_up_event->type = WebInputEvent::KeyUp;
694      events.push_back(linked_ptr<WebInputEvent>(key_up_event.release()));
695      break;
696    }
697
698    default:
699      break;
700  }
701  return events;
702}
703
704PP_InputEvent_Class ClassifyInputEvent(WebInputEvent::Type type) {
705  switch (type) {
706    case WebInputEvent::MouseDown:
707    case WebInputEvent::MouseUp:
708    case WebInputEvent::MouseMove:
709    case WebInputEvent::MouseEnter:
710    case WebInputEvent::MouseLeave:
711    case WebInputEvent::ContextMenu:
712      return PP_INPUTEVENT_CLASS_MOUSE;
713    case WebInputEvent::MouseWheel:
714      return PP_INPUTEVENT_CLASS_WHEEL;
715    case WebInputEvent::RawKeyDown:
716    case WebInputEvent::KeyDown:
717    case WebInputEvent::KeyUp:
718    case WebInputEvent::Char:
719      return PP_INPUTEVENT_CLASS_KEYBOARD;
720    case WebInputEvent::TouchCancel:
721    case WebInputEvent::TouchEnd:
722    case WebInputEvent::TouchMove:
723    case WebInputEvent::TouchStart:
724      return PP_INPUTEVENT_CLASS_TOUCH;
725    case WebInputEvent::Undefined:
726    default:
727      NOTREACHED();
728      return PP_InputEvent_Class(0);
729  }
730}
731
732}  // namespace content
733