// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "content/renderer/pepper/event_conversion.h" #include #include #include #include #include #include "base/feature_list.h" #include "base/i18n/char_iterator.h" #include "base/logging.h" #include "base/strings/string16.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversion_utils.h" #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" #include "content/common/input/web_touch_event_traits.h" #include "content/public/common/content_features.h" #include "device/gamepad/public/cpp/gamepads.h" #include "ppapi/c/pp_input_event.h" #include "ppapi/shared_impl/ppb_input_event_shared.h" #include "third_party/blink/public/common/input/web_input_event.h" #include "third_party/blink/public/common/input/web_keyboard_event.h" #include "third_party/blink/public/common/input/web_mouse_wheel_event.h" #include "third_party/blink/public/common/input/web_pointer_event.h" #include "third_party/blink/public/common/input/web_touch_event.h" #include "ui/events/keycodes/dom/keycode_converter.h" #if defined(OS_WIN) #include #endif using ppapi::InputEventData; using ppapi::TouchPointWithTilt; using blink::WebInputEvent; using blink::WebKeyboardEvent; using blink::WebMouseEvent; using blink::WebMouseWheelEvent; using blink::WebPointerEvent; using blink::WebTouchEvent; using blink::WebTouchPoint; namespace content { namespace { // Verify the modifier flags WebKit uses match the Pepper ones. If these start // not matching, we'll need to write conversion code to preserve the Pepper // values (since plugins will be depending on them). static_assert(static_cast(PP_INPUTEVENT_MODIFIER_SHIFTKEY) == static_cast(WebInputEvent::kShiftKey), "ShiftKey should match"); static_assert(static_cast(PP_INPUTEVENT_MODIFIER_CONTROLKEY) == static_cast(WebInputEvent::kControlKey), "ControlKey should match"); static_assert(static_cast(PP_INPUTEVENT_MODIFIER_ALTKEY) == static_cast(WebInputEvent::kAltKey), "AltKey should match"); static_assert(static_cast(PP_INPUTEVENT_MODIFIER_METAKEY) == static_cast(WebInputEvent::kMetaKey), "MetaKey should match"); static_assert(static_cast(PP_INPUTEVENT_MODIFIER_ISKEYPAD) == static_cast(WebInputEvent::kIsKeyPad), "KeyPad should match"); static_assert(static_cast(PP_INPUTEVENT_MODIFIER_ISAUTOREPEAT) == static_cast(WebInputEvent::kIsAutoRepeat), "AutoRepeat should match"); static_assert(static_cast(PP_INPUTEVENT_MODIFIER_LEFTBUTTONDOWN) == static_cast(WebInputEvent::kLeftButtonDown), "LeftButton should match"); static_assert(static_cast(PP_INPUTEVENT_MODIFIER_MIDDLEBUTTONDOWN) == static_cast(WebInputEvent::kMiddleButtonDown), "MiddleButton should match"); static_assert(static_cast(PP_INPUTEVENT_MODIFIER_RIGHTBUTTONDOWN) == static_cast(WebInputEvent::kRightButtonDown), "RightButton should match"); static_assert(static_cast(PP_INPUTEVENT_MODIFIER_CAPSLOCKKEY) == static_cast(WebInputEvent::kCapsLockOn), "CapsLock should match"); static_assert(static_cast(PP_INPUTEVENT_MODIFIER_NUMLOCKKEY) == static_cast(WebInputEvent::kNumLockOn), "NumLock should match"); static_assert(static_cast(PP_INPUTEVENT_MODIFIER_ISLEFT) == static_cast(WebInputEvent::kIsLeft), "IsLeft should match"); static_assert(static_cast(PP_INPUTEVENT_MODIFIER_ISRIGHT) == static_cast(WebInputEvent::kIsRight), "IsRight should match"); PP_InputEvent_Type ConvertEventTypes(const WebInputEvent& event) { switch (event.GetType()) { case WebInputEvent::kMouseDown: return PP_INPUTEVENT_TYPE_MOUSEDOWN; case WebInputEvent::kMouseUp: return PP_INPUTEVENT_TYPE_MOUSEUP; case WebInputEvent::kMouseMove: return PP_INPUTEVENT_TYPE_MOUSEMOVE; case WebInputEvent::kMouseEnter: return PP_INPUTEVENT_TYPE_MOUSEENTER; case WebInputEvent::kMouseLeave: return PP_INPUTEVENT_TYPE_MOUSELEAVE; case WebInputEvent::kContextMenu: return PP_INPUTEVENT_TYPE_CONTEXTMENU; case WebInputEvent::kMouseWheel: return PP_INPUTEVENT_TYPE_WHEEL; case WebInputEvent::kRawKeyDown: // In the past blink has always returned kKeyDown passed into plugins // although PPAPI had a RAWKEYDOWN definition. However implementations are // broken now that blink passes kRawKeyDown so convert it to a keydown. return PP_INPUTEVENT_TYPE_KEYDOWN; case WebInputEvent::kKeyDown: return PP_INPUTEVENT_TYPE_KEYDOWN; case WebInputEvent::kKeyUp: return PP_INPUTEVENT_TYPE_KEYUP; case WebInputEvent::kChar: return PP_INPUTEVENT_TYPE_CHAR; case WebInputEvent::kTouchStart: return PP_INPUTEVENT_TYPE_TOUCHSTART; case WebInputEvent::kTouchMove: return PP_INPUTEVENT_TYPE_TOUCHMOVE; case WebInputEvent::kTouchEnd: return PP_INPUTEVENT_TYPE_TOUCHEND; case WebInputEvent::kTouchCancel: return PP_INPUTEVENT_TYPE_TOUCHCANCEL; case WebInputEvent::kUndefined: default: return PP_INPUTEVENT_TYPE_UNDEFINED; } } // Converts WebInputEvent::Modifiers flags to PP_InputEvent_Modifier. int ConvertEventModifiers(int modifiers) { return modifiers & (PP_INPUTEVENT_MODIFIER_SHIFTKEY | PP_INPUTEVENT_MODIFIER_CONTROLKEY | PP_INPUTEVENT_MODIFIER_ALTKEY | PP_INPUTEVENT_MODIFIER_METAKEY | PP_INPUTEVENT_MODIFIER_ISKEYPAD | PP_INPUTEVENT_MODIFIER_ISAUTOREPEAT | PP_INPUTEVENT_MODIFIER_LEFTBUTTONDOWN | PP_INPUTEVENT_MODIFIER_MIDDLEBUTTONDOWN | PP_INPUTEVENT_MODIFIER_RIGHTBUTTONDOWN | PP_INPUTEVENT_MODIFIER_CAPSLOCKKEY | PP_INPUTEVENT_MODIFIER_NUMLOCKKEY | PP_INPUTEVENT_MODIFIER_ISLEFT | PP_INPUTEVENT_MODIFIER_ISRIGHT); } // Generates a PP_InputEvent with the fields common to all events, as well as // the event type from the given web event. Event-specific fields will be zero // initialized. InputEventData GetEventWithCommonFieldsAndType(const WebInputEvent& web_event) { InputEventData result; result.event_type = ConvertEventTypes(web_event); result.event_time_stamp = web_event.TimeStamp().since_origin().InSecondsF(); return result; } void AppendKeyEvent(const WebInputEvent& event, std::vector* result_events) { const WebKeyboardEvent& key_event = static_cast(event); InputEventData result = GetEventWithCommonFieldsAndType(event); result.event_modifiers = ConvertEventModifiers(key_event.GetModifiers()); result.key_code = key_event.windows_key_code; result.code = ui::KeycodeConverter::DomCodeToCodeString( static_cast(key_event.dom_code)); result_events->push_back(result); } void AppendCharEvent(const WebInputEvent& event, std::vector* result_events) { const WebKeyboardEvent& key_event = static_cast(event); // This is a bit complex, the input event will normally just have one 16-bit // character in it, but may be zero or more than one. The text array is // just padded with 0 values for the unused ones, but is not necessarily // null-terminated. // // Here we see how many UTF-16 characters we have. size_t utf16_char_count = 0; while (utf16_char_count < WebKeyboardEvent::kTextLengthCap && key_event.text[utf16_char_count]) utf16_char_count++; // Make a separate InputEventData for each Unicode character in the input. base::i18n::UTF16CharIterator iter(key_event.text, utf16_char_count); while (!iter.end()) { InputEventData result = GetEventWithCommonFieldsAndType(event); result.event_modifiers = ConvertEventModifiers(key_event.GetModifiers()); base::WriteUnicodeCharacter(iter.get(), &result.character_text); result_events->push_back(result); iter.Advance(); } } void AppendMouseEvent(const WebInputEvent& event, std::unique_ptr* in_out_last_mouse_position, std::vector* result_events) { static_assert(static_cast(WebMouseEvent::Button::kNoButton) == static_cast(PP_INPUTEVENT_MOUSEBUTTON_NONE), "MouseNone should match"); static_assert(static_cast(WebMouseEvent::Button::kLeft) == static_cast(PP_INPUTEVENT_MOUSEBUTTON_LEFT), "MouseLeft should match"); static_assert(static_cast(WebMouseEvent::Button::kRight) == static_cast(PP_INPUTEVENT_MOUSEBUTTON_RIGHT), "MouseRight should match"); static_assert(static_cast(WebMouseEvent::Button::kMiddle) == static_cast(PP_INPUTEVENT_MOUSEBUTTON_MIDDLE), "MouseMiddle should match"); const WebMouseEvent& mouse_event = static_cast(event); InputEventData result = GetEventWithCommonFieldsAndType(event); result.event_modifiers = ConvertEventModifiers(mouse_event.GetModifiers()); if (mouse_event.GetType() == WebInputEvent::kMouseDown || mouse_event.GetType() == WebInputEvent::kMouseMove || mouse_event.GetType() == WebInputEvent::kMouseUp) { switch (mouse_event.button) { case WebMouseEvent::Button::kNoButton: case WebMouseEvent::Button::kLeft: case WebMouseEvent::Button::kRight: case WebMouseEvent::Button::kMiddle: result.mouse_button = static_cast(mouse_event.button); break; default: return; } } result.mouse_position.x = mouse_event.PositionInWidget().x(); result.mouse_position.y = mouse_event.PositionInWidget().y(); result.mouse_click_count = mouse_event.click_count; if (base::FeatureList::IsEnabled(features::kConsolidatedMovementXY)) { if (mouse_event.GetType() == WebInputEvent::kMouseMove && *in_out_last_mouse_position) { result.mouse_movement.x = mouse_event.PositionInScreen().x() - (*in_out_last_mouse_position)->x(); result.mouse_movement.y = mouse_event.PositionInScreen().y() - (*in_out_last_mouse_position)->y(); } *in_out_last_mouse_position = std::make_unique(mouse_event.PositionInScreen()); // Filter out event generated by recentering the cursor when mouse locked. // See |RenderWidgetHostViewEventHandler::HandleMouseEventWhileLocked|. if ((mouse_event.GetModifiers() & WebInputEvent::Modifiers::kRelativeMotionEvent)) { return; } } else { result.mouse_movement.x = mouse_event.movement_x; result.mouse_movement.y = mouse_event.movement_y; } result_events->push_back(result); } void AppendMouseWheelEvent(const WebInputEvent& event, std::vector* result_events) { const WebMouseWheelEvent& mouse_wheel_event = static_cast(event); InputEventData result = GetEventWithCommonFieldsAndType(event); result.event_modifiers = ConvertEventModifiers(mouse_wheel_event.GetModifiers()); result.wheel_delta.x = mouse_wheel_event.delta_x; result.wheel_delta.y = mouse_wheel_event.delta_y; result.wheel_ticks.x = mouse_wheel_event.wheel_ticks_x; result.wheel_ticks.y = mouse_wheel_event.wheel_ticks_y; result.wheel_scroll_by_page = (mouse_wheel_event.delta_units == ui::ScrollGranularity::kScrollByPage); result_events->push_back(result); } enum IncludedTouchPointTypes { ALL, // All pointers targetting the plugin. ACTIVE, // Only pointers that are currently down. CHANGED // Only pointers that have changed since the previous event. }; void SetPPTouchPoints(const WebTouchPoint* touches, uint32_t touches_length, IncludedTouchPointTypes included_types, std::vector* result) { for (uint32_t i = 0; i < touches_length; i++) { const WebTouchPoint& touch_point = touches[i]; if (included_types == ACTIVE && (touch_point.state == WebTouchPoint::kStateReleased || touch_point.state == WebTouchPoint::kStateCancelled)) { continue; } if (included_types == CHANGED && (touch_point.state == WebTouchPoint::kStateUndefined || touch_point.state == WebTouchPoint::kStateStationary)) { continue; } PP_TouchPoint pp_pt; pp_pt.id = touch_point.id; pp_pt.position.x = touch_point.PositionInWidget().x(); pp_pt.position.y = touch_point.PositionInWidget().y(); pp_pt.radius.x = touch_point.radius_x; pp_pt.radius.y = touch_point.radius_y; pp_pt.rotation_angle = touch_point.rotation_angle; pp_pt.pressure = touch_point.force; PP_FloatPoint pp_ft; pp_ft.x = touch_point.tilt_x; pp_ft.y = touch_point.tilt_y; TouchPointWithTilt touch_with_tilt{pp_pt, pp_ft}; result->push_back(touch_with_tilt); } } void AppendTouchEvent(const WebInputEvent& event, std::vector* result_events) { const WebTouchEvent& touch_event = reinterpret_cast(event); InputEventData result = GetEventWithCommonFieldsAndType(event); if (touch_event.touches_length == 1) { if (touch_event.touches[0].pointer_type == blink::WebPointerProperties::PointerType::kPen) { result.event_modifiers |= PP_INPUTEVENT_MODIFIER_ISPEN; } else if (touch_event.touches[0].pointer_type == blink::WebPointerProperties::PointerType::kEraser) { result.event_modifiers |= PP_INPUTEVENT_MODIFIER_ISERASER; } } SetPPTouchPoints(touch_event.touches, touch_event.touches_length, ACTIVE, &result.touches); SetPPTouchPoints(touch_event.touches, touch_event.touches_length, CHANGED, &result.changed_touches); SetPPTouchPoints(touch_event.touches, touch_event.touches_length, ALL, &result.target_touches); result_events->push_back(result); } WebTouchPoint CreateWebTouchPoint(const PP_TouchPoint& pp_pt, WebTouchPoint::State state) { WebTouchPoint pt; pt.pointer_type = blink::WebPointerProperties::PointerType::kTouch; pt.id = pp_pt.id; pt.SetPositionInWidget(pp_pt.position.x, pp_pt.position.y); // TODO(crbug.com/93902): Add screen coordinate calculation. pt.SetPositionInScreen(0, 0); pt.force = pp_pt.pressure; pt.radius_x = pp_pt.radius.x; pt.radius_y = pp_pt.radius.y; pt.rotation_angle = pp_pt.rotation_angle; pt.state = state; return pt; } bool HasTouchPointWithId(const WebTouchPoint* web_touches, uint32_t web_touches_length, uint32_t id) { // Note: A brute force search to find the (potentially) existing touch point // is cheap given the small bound on |WebTouchEvent::kTouchesLengthCap|. for (uint32_t i = 0; i < web_touches_length; ++i) { if (web_touches[i].id == static_cast(id)) return true; } return false; } void SetWebTouchPointsIfNotYetSet( const std::vector& pp_touches, WebTouchPoint::State state, WebTouchPoint* web_touches, uint32_t* web_touches_length) { const uint32_t initial_web_touches_length = *web_touches_length; const uint32_t touches_length = std::min(static_cast(pp_touches.size()), static_cast(WebTouchEvent::kTouchesLengthCap)); for (uint32_t i = 0; i < touches_length; ++i) { const uint32_t touch_index = *web_touches_length; if (touch_index >= static_cast(WebTouchEvent::kTouchesLengthCap)) return; const PP_TouchPoint& pp_pt = pp_touches[i].touch; if (HasTouchPointWithId(web_touches, initial_web_touches_length, pp_pt.id)) continue; web_touches[touch_index] = CreateWebTouchPoint(pp_pt, state); ++(*web_touches_length); } } WebTouchEvent* BuildTouchEvent(const InputEventData& event) { WebTouchEvent* web_event = new WebTouchEvent(); WebTouchPoint::State state = WebTouchPoint::kStateUndefined; WebInputEvent::Type type = WebInputEvent::kUndefined; switch (event.event_type) { case PP_INPUTEVENT_TYPE_TOUCHSTART: type = WebInputEvent::kTouchStart; state = WebTouchPoint::kStatePressed; break; case PP_INPUTEVENT_TYPE_TOUCHMOVE: type = WebInputEvent::kTouchMove; state = WebTouchPoint::kStateMoved; break; case PP_INPUTEVENT_TYPE_TOUCHEND: type = WebInputEvent::kTouchEnd; state = WebTouchPoint::kStateReleased; break; case PP_INPUTEVENT_TYPE_TOUCHCANCEL: type = WebInputEvent::kTouchCancel; state = WebTouchPoint::kStateCancelled; break; default: NOTREACHED(); } WebTouchEventTraits::ResetType( type, base::TimeTicks() + base::TimeDelta::FromSecondsD(event.event_time_stamp), web_event); web_event->touches_length = 0; // First add all changed touches, then add only the remaining unset // (stationary) touches. SetWebTouchPointsIfNotYetSet(event.changed_touches, state, web_event->touches, &web_event->touches_length); SetWebTouchPointsIfNotYetSet(event.touches, WebTouchPoint::kStateStationary, web_event->touches, &web_event->touches_length); return web_event; } WebKeyboardEvent* BuildKeyEvent(const InputEventData& event) { WebInputEvent::Type type = WebInputEvent::Type::kUndefined; switch (event.event_type) { case PP_INPUTEVENT_TYPE_RAWKEYDOWN: type = WebInputEvent::kRawKeyDown; break; case PP_INPUTEVENT_TYPE_KEYDOWN: type = WebInputEvent::kKeyDown; break; case PP_INPUTEVENT_TYPE_KEYUP: type = WebInputEvent::kKeyUp; break; default: NOTREACHED(); } WebKeyboardEvent* key_event = new WebKeyboardEvent( type, event.event_modifiers, base::TimeTicks() + base::TimeDelta::FromSecondsD(event.event_time_stamp)); key_event->windows_key_code = event.key_code; return key_event; } WebKeyboardEvent* BuildCharEvent(const InputEventData& event) { WebKeyboardEvent* key_event = new WebKeyboardEvent( WebInputEvent::kChar, event.event_modifiers, base::TimeTicks() + base::TimeDelta::FromSecondsD(event.event_time_stamp)); // Make sure to not read beyond the buffer in case some bad code doesn't // NULL-terminate it (this is called from plugins). size_t text_length_cap = WebKeyboardEvent::kTextLengthCap; base::string16 text16 = base::UTF8ToUTF16(event.character_text); std::fill_n(key_event->text, text_length_cap, 0); std::fill_n(key_event->unmodified_text, text_length_cap, 0); for (size_t i = 0; i < std::min(text_length_cap, text16.size()); ++i) key_event->text[i] = text16[i]; return key_event; } WebMouseEvent* BuildMouseEvent(const InputEventData& event) { WebInputEvent::Type type = WebInputEvent::kUndefined; switch (event.event_type) { case PP_INPUTEVENT_TYPE_MOUSEDOWN: type = WebInputEvent::kMouseDown; break; case PP_INPUTEVENT_TYPE_MOUSEUP: type = WebInputEvent::kMouseUp; break; case PP_INPUTEVENT_TYPE_MOUSEMOVE: type = WebInputEvent::kMouseMove; break; case PP_INPUTEVENT_TYPE_MOUSEENTER: type = WebInputEvent::kMouseEnter; break; case PP_INPUTEVENT_TYPE_MOUSELEAVE: type = WebInputEvent::kMouseLeave; break; case PP_INPUTEVENT_TYPE_CONTEXTMENU: type = WebInputEvent::kContextMenu; break; default: NOTREACHED(); } WebMouseEvent* mouse_event = new WebMouseEvent( type, event.event_modifiers, base::TimeTicks() + base::TimeDelta::FromSecondsD(event.event_time_stamp)); mouse_event->pointer_type = blink::WebPointerProperties::PointerType::kMouse; mouse_event->button = static_cast(event.mouse_button); if (mouse_event->GetType() == WebInputEvent::kMouseMove) { if (mouse_event->GetModifiers() & WebInputEvent::kLeftButtonDown) mouse_event->button = WebMouseEvent::Button::kLeft; else if (mouse_event->GetModifiers() & WebInputEvent::kMiddleButtonDown) mouse_event->button = WebMouseEvent::Button::kMiddle; else if (mouse_event->GetModifiers() & WebInputEvent::kRightButtonDown) mouse_event->button = WebMouseEvent::Button::kRight; } mouse_event->SetPositionInWidget(event.mouse_position.x, event.mouse_position.y); mouse_event->click_count = event.mouse_click_count; mouse_event->movement_x = event.mouse_movement.x; mouse_event->movement_y = event.mouse_movement.y; return mouse_event; } WebMouseWheelEvent* BuildMouseWheelEvent(const InputEventData& event) { WebMouseWheelEvent* mouse_wheel_event = new WebMouseWheelEvent( WebInputEvent::kMouseWheel, event.event_modifiers, base::TimeTicks() + base::TimeDelta::FromSecondsD(event.event_time_stamp)); mouse_wheel_event->delta_x = event.wheel_delta.x; mouse_wheel_event->delta_y = event.wheel_delta.y; mouse_wheel_event->wheel_ticks_x = event.wheel_ticks.x; mouse_wheel_event->wheel_ticks_y = event.wheel_ticks.y; mouse_wheel_event->delta_units = event.wheel_scroll_by_page ? ui::ScrollGranularity::kScrollByPage : ui::ScrollGranularity::kScrollByPixel; return mouse_wheel_event; } #if !defined(OS_WIN) #define VK_RETURN 0x0D #define VK_PRIOR 0x21 #define VK_NEXT 0x22 #define VK_END 0x23 #define VK_HOME 0x24 #define VK_LEFT 0x25 #define VK_UP 0x26 #define VK_RIGHT 0x27 #define VK_DOWN 0x28 #define VK_SNAPSHOT 0x2C #define VK_INSERT 0x2D #define VK_DELETE 0x2E #define VK_APPS 0x5D #define VK_F1 0x70 #endif // Convert a character string to a Windows virtual key code. Adapted from // src/content/shell/test_runner/event_sender.cc. This // is used by CreateSimulatedWebInputEvents to convert keyboard events. void GetKeyCode(const std::string& char_text, uint16_t* code, uint16_t* text, bool* needs_shift_modifier, bool* generate_char) { uint16_t vk_code = 0; uint16_t vk_text = 0; *needs_shift_modifier = false; *generate_char = false; if ("\n" == char_text) { vk_text = vk_code = VK_RETURN; *generate_char = true; } else if ("rightArrow" == char_text) { vk_code = VK_RIGHT; } else if ("downArrow" == char_text) { vk_code = VK_DOWN; } else if ("leftArrow" == char_text) { vk_code = VK_LEFT; } else if ("upArrow" == char_text) { vk_code = VK_UP; } else if ("insert" == char_text) { vk_code = VK_INSERT; } else if ("delete" == char_text) { vk_code = VK_DELETE; } else if ("pageUp" == char_text) { vk_code = VK_PRIOR; } else if ("pageDown" == char_text) { vk_code = VK_NEXT; } else if ("home" == char_text) { vk_code = VK_HOME; } else if ("end" == char_text) { vk_code = VK_END; } else if ("printScreen" == char_text) { vk_code = VK_SNAPSHOT; } else if ("menu" == char_text) { vk_code = VK_APPS; } else { // Compare the input string with the function-key names defined by the // DOM spec (i.e. "F1",...,"F24"). for (int i = 1; i <= 24; ++i) { std::string functionKeyName = base::StringPrintf("F%d", i); if (functionKeyName == char_text) { vk_code = VK_F1 + (i - 1); break; } } if (!vk_code) { base::string16 char_text16 = base::UTF8ToUTF16(char_text); DCHECK_EQ(char_text16.size(), 1U); vk_text = vk_code = char_text16[0]; *needs_shift_modifier = base::IsAsciiUpper(vk_code & 0xFF); if (base::IsAsciiLower(vk_code & 0xFF)) vk_code -= 'a' - 'A'; *generate_char = true; } } *code = vk_code; *text = vk_text; } } // namespace void CreateInputEventData( const WebInputEvent& event, std::unique_ptr* in_out_last_mouse_position, std::vector* result) { result->clear(); switch (event.GetType()) { case WebInputEvent::kMouseDown: case WebInputEvent::kMouseUp: case WebInputEvent::kMouseMove: case WebInputEvent::kMouseEnter: case WebInputEvent::kMouseLeave: case WebInputEvent::kContextMenu: AppendMouseEvent(event, in_out_last_mouse_position, result); break; case WebInputEvent::kMouseWheel: AppendMouseWheelEvent(event, result); break; case WebInputEvent::kRawKeyDown: case WebInputEvent::kKeyDown: case WebInputEvent::kKeyUp: AppendKeyEvent(event, result); break; case WebInputEvent::kChar: AppendCharEvent(event, result); break; case WebInputEvent::kTouchStart: case WebInputEvent::kTouchMove: case WebInputEvent::kTouchEnd: case WebInputEvent::kTouchCancel: AppendTouchEvent(event, result); break; case WebInputEvent::kUndefined: default: break; } } WebInputEvent* CreateWebInputEvent(const InputEventData& event) { std::unique_ptr web_input_event; switch (event.event_type) { case PP_INPUTEVENT_TYPE_UNDEFINED: return nullptr; case PP_INPUTEVENT_TYPE_MOUSEDOWN: case PP_INPUTEVENT_TYPE_MOUSEUP: case PP_INPUTEVENT_TYPE_MOUSEMOVE: case PP_INPUTEVENT_TYPE_MOUSEENTER: case PP_INPUTEVENT_TYPE_MOUSELEAVE: case PP_INPUTEVENT_TYPE_CONTEXTMENU: web_input_event.reset(BuildMouseEvent(event)); break; case PP_INPUTEVENT_TYPE_WHEEL: web_input_event.reset(BuildMouseWheelEvent(event)); break; case PP_INPUTEVENT_TYPE_RAWKEYDOWN: case PP_INPUTEVENT_TYPE_KEYDOWN: case PP_INPUTEVENT_TYPE_KEYUP: web_input_event.reset(BuildKeyEvent(event)); break; case PP_INPUTEVENT_TYPE_CHAR: web_input_event.reset(BuildCharEvent(event)); break; case PP_INPUTEVENT_TYPE_IME_COMPOSITION_START: case PP_INPUTEVENT_TYPE_IME_COMPOSITION_UPDATE: case PP_INPUTEVENT_TYPE_IME_COMPOSITION_END: case PP_INPUTEVENT_TYPE_IME_TEXT: // TODO(kinaba) implement in WebKit an event structure to handle // composition events. NOTREACHED(); break; case PP_INPUTEVENT_TYPE_TOUCHSTART: case PP_INPUTEVENT_TYPE_TOUCHMOVE: case PP_INPUTEVENT_TYPE_TOUCHEND: case PP_INPUTEVENT_TYPE_TOUCHCANCEL: web_input_event.reset(BuildTouchEvent(event)); break; } return web_input_event.release(); } // Generate a coherent sequence of input events to simulate a user event. // From src/content/shell/test_runner/event_sender.cc. std::vector> CreateSimulatedWebInputEvents( const ppapi::InputEventData& event, int plugin_x, int plugin_y) { std::vector> events; std::unique_ptr original_event(CreateWebInputEvent(event)); switch (event.event_type) { case PP_INPUTEVENT_TYPE_MOUSEDOWN: case PP_INPUTEVENT_TYPE_MOUSEUP: case PP_INPUTEVENT_TYPE_MOUSEMOVE: case PP_INPUTEVENT_TYPE_MOUSEENTER: case PP_INPUTEVENT_TYPE_MOUSELEAVE: events.push_back(std::move(original_event)); break; case PP_INPUTEVENT_TYPE_TOUCHSTART: case PP_INPUTEVENT_TYPE_TOUCHMOVE: case PP_INPUTEVENT_TYPE_TOUCHEND: case PP_INPUTEVENT_TYPE_TOUCHCANCEL: { blink::WebTouchEvent* touch_event = static_cast(original_event.get()); for (unsigned i = 0; i < touch_event->touches_length; ++i) { const blink::WebTouchPoint& touch_point = touch_event->touches[i]; if (touch_point.state != blink::WebTouchPoint::kStateStationary) { events.push_back( std::make_unique(*touch_event, touch_point)); } } } break; case PP_INPUTEVENT_TYPE_WHEEL: { WebMouseWheelEvent* web_mouse_wheel_event = static_cast(original_event.get()); web_mouse_wheel_event->SetPositionInWidget(plugin_x, plugin_y); events.push_back(std::move(original_event)); break; } case PP_INPUTEVENT_TYPE_RAWKEYDOWN: case PP_INPUTEVENT_TYPE_KEYDOWN: case PP_INPUTEVENT_TYPE_KEYUP: { // Windows key down events should always be "raw" to avoid an ASSERT. #if defined(OS_WIN) WebKeyboardEvent* web_keyboard_event = static_cast(original_event.get()); if (web_keyboard_event->GetType() == WebInputEvent::kKeyDown) web_keyboard_event->SetType(WebInputEvent::kRawKeyDown); #endif events.push_back(std::move(original_event)); break; } case PP_INPUTEVENT_TYPE_CHAR: { WebKeyboardEvent* web_char_event = static_cast(original_event.get()); uint16_t code = 0, text = 0; bool needs_shift_modifier = false, generate_char = false; GetKeyCode(event.character_text, &code, &text, &needs_shift_modifier, &generate_char); // Synthesize key down and key up events in all cases. std::unique_ptr key_down_event(new WebKeyboardEvent( WebInputEvent::kRawKeyDown, needs_shift_modifier ? WebInputEvent::kShiftKey : WebInputEvent::kNoModifiers, web_char_event->TimeStamp())); std::unique_ptr key_up_event(new WebKeyboardEvent()); key_down_event->windows_key_code = code; key_down_event->native_key_code = code; // If a char event is needed, set the text fields. if (generate_char) { key_down_event->text[0] = text; key_down_event->unmodified_text[0] = text; } *key_up_event = *web_char_event = *key_down_event; events.push_back(std::move(key_down_event)); if (generate_char) { web_char_event->SetType(WebInputEvent::kChar); events.push_back(std::move(original_event)); } key_up_event->SetType(WebInputEvent::kKeyUp); events.push_back(std::move(key_up_event)); break; } default: break; } return events; } PP_InputEvent_Class ClassifyInputEvent(const WebInputEvent& event) { switch (event.GetType()) { case WebInputEvent::kMouseDown: case WebInputEvent::kMouseUp: case WebInputEvent::kMouseMove: case WebInputEvent::kMouseEnter: case WebInputEvent::kMouseLeave: case WebInputEvent::kContextMenu: return PP_INPUTEVENT_CLASS_MOUSE; case WebInputEvent::kMouseWheel: return PP_INPUTEVENT_CLASS_WHEEL; case WebInputEvent::kRawKeyDown: case WebInputEvent::kKeyDown: case WebInputEvent::kKeyUp: case WebInputEvent::kChar: return PP_INPUTEVENT_CLASS_KEYBOARD; case WebInputEvent::kTouchCancel: case WebInputEvent::kTouchEnd: case WebInputEvent::kTouchMove: case WebInputEvent::kTouchStart: return PP_INPUTEVENT_CLASS_TOUCH; case WebInputEvent::kTouchScrollStarted: return PP_InputEvent_Class(0); default: CHECK(WebInputEvent::IsGestureEventType(event.GetType())); return PP_InputEvent_Class(0); } } } // namespace content