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