OLD | NEW |
| (Empty) |
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 <map> | |
6 | |
7 #include "webkit/plugins/ppapi/event_conversion.h" | |
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 "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 #include "webkit/plugins/ppapi/common.h" | |
24 #include "webkit/plugins/ppapi/usb_key_code_conversion.h" | |
25 | |
26 using ppapi::EventTimeToPPTimeTicks; | |
27 using ppapi::InputEventData; | |
28 using ppapi::PPTimeTicksToEventTime; | |
29 using WebKit::WebInputEvent; | |
30 using WebKit::WebKeyboardEvent; | |
31 using WebKit::WebMouseEvent; | |
32 using WebKit::WebMouseWheelEvent; | |
33 using WebKit::WebString; | |
34 using WebKit::WebTouchEvent; | |
35 using WebKit::WebTouchPoint; | |
36 using WebKit::WebUChar; | |
37 | |
38 namespace webkit { | |
39 namespace ppapi { | |
40 | |
41 namespace { | |
42 | |
43 // Verify the modifier flags WebKit uses match the Pepper ones. If these start | |
44 // not matching, we'll need to write conversion code to preserve the Pepper | |
45 // values (since plugins will be depending on them). | |
46 COMPILE_ASSERT(static_cast<int>(PP_INPUTEVENT_MODIFIER_SHIFTKEY) == | |
47 static_cast<int>(WebInputEvent::ShiftKey), | |
48 ShiftKeyMatches); | |
49 COMPILE_ASSERT(static_cast<int>(PP_INPUTEVENT_MODIFIER_CONTROLKEY) == | |
50 static_cast<int>(WebInputEvent::ControlKey), | |
51 ControlKeyMatches); | |
52 COMPILE_ASSERT(static_cast<int>(PP_INPUTEVENT_MODIFIER_ALTKEY) == | |
53 static_cast<int>(WebInputEvent::AltKey), | |
54 AltKeyMatches); | |
55 COMPILE_ASSERT(static_cast<int>(PP_INPUTEVENT_MODIFIER_METAKEY) == | |
56 static_cast<int>(WebInputEvent::MetaKey), | |
57 MetaKeyMatches); | |
58 COMPILE_ASSERT(static_cast<int>(PP_INPUTEVENT_MODIFIER_ISKEYPAD) == | |
59 static_cast<int>(WebInputEvent::IsKeyPad), | |
60 KeyPadMatches); | |
61 COMPILE_ASSERT(static_cast<int>(PP_INPUTEVENT_MODIFIER_ISAUTOREPEAT) == | |
62 static_cast<int>(WebInputEvent::IsAutoRepeat), | |
63 AutoRepeatMatches); | |
64 COMPILE_ASSERT(static_cast<int>(PP_INPUTEVENT_MODIFIER_LEFTBUTTONDOWN) == | |
65 static_cast<int>(WebInputEvent::LeftButtonDown), | |
66 LeftButtonMatches); | |
67 COMPILE_ASSERT(static_cast<int>(PP_INPUTEVENT_MODIFIER_MIDDLEBUTTONDOWN) == | |
68 static_cast<int>(WebInputEvent::MiddleButtonDown), | |
69 MiddleButtonMatches); | |
70 COMPILE_ASSERT(static_cast<int>(PP_INPUTEVENT_MODIFIER_RIGHTBUTTONDOWN) == | |
71 static_cast<int>(WebInputEvent::RightButtonDown), | |
72 RightButtonMatches); | |
73 COMPILE_ASSERT(static_cast<int>(PP_INPUTEVENT_MODIFIER_CAPSLOCKKEY) == | |
74 static_cast<int>(WebInputEvent::CapsLockOn), | |
75 CapsLockMatches); | |
76 COMPILE_ASSERT(static_cast<int>(PP_INPUTEVENT_MODIFIER_NUMLOCKKEY) == | |
77 static_cast<int>(WebInputEvent::NumLockOn), | |
78 NumLockMatches); | |
79 COMPILE_ASSERT(static_cast<int>(PP_INPUTEVENT_MODIFIER_ISLEFT) == | |
80 static_cast<int>(WebInputEvent::IsLeft), | |
81 LeftMatches); | |
82 COMPILE_ASSERT(static_cast<int>(PP_INPUTEVENT_MODIFIER_ISRIGHT) == | |
83 static_cast<int>(WebInputEvent::IsRight), | |
84 RightMatches); | |
85 | |
86 PP_InputEvent_Type ConvertEventTypes(WebInputEvent::Type wetype) { | |
87 switch (wetype) { | |
88 case WebInputEvent::MouseDown: | |
89 return PP_INPUTEVENT_TYPE_MOUSEDOWN; | |
90 case WebInputEvent::MouseUp: | |
91 return PP_INPUTEVENT_TYPE_MOUSEUP; | |
92 case WebInputEvent::MouseMove: | |
93 return PP_INPUTEVENT_TYPE_MOUSEMOVE; | |
94 case WebInputEvent::MouseEnter: | |
95 return PP_INPUTEVENT_TYPE_MOUSEENTER; | |
96 case WebInputEvent::MouseLeave: | |
97 return PP_INPUTEVENT_TYPE_MOUSELEAVE; | |
98 case WebInputEvent::ContextMenu: | |
99 return PP_INPUTEVENT_TYPE_CONTEXTMENU; | |
100 case WebInputEvent::MouseWheel: | |
101 return PP_INPUTEVENT_TYPE_WHEEL; | |
102 case WebInputEvent::RawKeyDown: | |
103 return PP_INPUTEVENT_TYPE_RAWKEYDOWN; | |
104 case WebInputEvent::KeyDown: | |
105 return PP_INPUTEVENT_TYPE_KEYDOWN; | |
106 case WebInputEvent::KeyUp: | |
107 return PP_INPUTEVENT_TYPE_KEYUP; | |
108 case WebInputEvent::Char: | |
109 return PP_INPUTEVENT_TYPE_CHAR; | |
110 case WebInputEvent::TouchStart: | |
111 return PP_INPUTEVENT_TYPE_TOUCHSTART; | |
112 case WebInputEvent::TouchMove: | |
113 return PP_INPUTEVENT_TYPE_TOUCHMOVE; | |
114 case WebInputEvent::TouchEnd: | |
115 return PP_INPUTEVENT_TYPE_TOUCHEND; | |
116 case WebInputEvent::TouchCancel: | |
117 return PP_INPUTEVENT_TYPE_TOUCHCANCEL; | |
118 case WebInputEvent::Undefined: | |
119 default: | |
120 return PP_INPUTEVENT_TYPE_UNDEFINED; | |
121 } | |
122 } | |
123 | |
124 // Generates a PP_InputEvent with the fields common to all events, as well as | |
125 // the event type from the given web event. Event-specific fields will be zero | |
126 // initialized. | |
127 InputEventData GetEventWithCommonFieldsAndType(const WebInputEvent& web_event) { | |
128 InputEventData result; | |
129 result.event_type = ConvertEventTypes(web_event.type); | |
130 result.event_time_stamp = EventTimeToPPTimeTicks(web_event.timeStampSeconds); | |
131 result.usb_key_code = 0; | |
132 return result; | |
133 } | |
134 | |
135 void AppendKeyEvent(const WebInputEvent& event, | |
136 std::vector<InputEventData>* result_events) { | |
137 const WebKeyboardEvent& key_event = | |
138 static_cast<const WebKeyboardEvent&>(event); | |
139 InputEventData result = GetEventWithCommonFieldsAndType(event); | |
140 result.event_modifiers = key_event.modifiers; | |
141 result.key_code = key_event.windowsKeyCode; | |
142 result.usb_key_code = UsbKeyCodeForKeyboardEvent(key_event); | |
143 result_events->push_back(result); | |
144 } | |
145 | |
146 void 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 | |
174 void 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 | |
207 void 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 | |
221 void 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 | |
237 void 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.' | |
258 typedef std::map<uint32_t, WebTouchPoint::State> TouchStateMap; | |
259 | |
260 void 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 | |
290 WebTouchEvent* 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 | |
342 WebKeyboardEvent* 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 | |
364 WebKeyboardEvent* 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 | |
384 WebMouseEvent* 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 | |
429 WebMouseWheelEvent* 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. | |
466 void 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 | |
531 void 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 | |
567 WebInputEvent* 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. | |
612 std::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 | |
706 PP_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 ppapi | |
735 } // namespace webkit | |
OLD | NEW |