#include "ui/events/blink/web_input_event.h"
#include "base/feature_list.h"
#include "base/notimplemented.h"
#include "base/types/cxx23_to_underlying.h"
#include "build/build_config.h"
#include "third_party/blink/public/common/features.h"
#include "ui/base/ui_base_features.h"
#include "ui/events/blink/blink_event_util.h"
#include "ui/events/blink/blink_features.h"
#include "ui/events/event.h"
#include "ui/events/event_target.h"
#include "ui/events/event_utils.h"
#include "ui/events/keycodes/dom/keycode_converter.h"
#if BUILDFLAG(IS_WIN)
#include "ui/events/blink/web_input_event_builders_win.h"
#endif
namespace ui {
namespace {
using WebInputEvent = blink::WebInputEvent;
gfx::PointF GetScreenLocationFromEvent(const LocatedEvent& event) {
return event.target() ? event.target()->GetScreenLocationF(event)
: event.root_location_f();
}
blink::WebGestureEvent MakeWebGestureEventFromUIEvent(
const GestureEvent& event) {
return CreateWebGestureEvent(event.details(), event.time_stamp(),
event.location_f(), event.root_location_f(),
event.flags(), event.unique_touch_event_id());
}
}
#if BUILDFLAG(IS_WIN)
blink::WebMouseEvent MakeUntranslatedWebMouseEventFromNativeEvent(
const PlatformEvent& native_event,
const base::TimeTicks& time_stamp,
blink::WebPointerProperties::PointerType pointer_type) {
return WebMouseEventBuilder::Build(native_event.hwnd, native_event.message,
native_event.wParam, native_event.lParam,
time_stamp, pointer_type);
}
blink::WebMouseWheelEvent MakeUntranslatedWebMouseWheelEventFromNativeEvent(
const PlatformEvent& native_event,
const base::TimeTicks& time_stamp,
blink::WebPointerProperties::PointerType pointer_type) {
return WebMouseWheelEventBuilder::Build(
native_event.hwnd, native_event.message, native_event.wParam,
native_event.lParam, time_stamp, pointer_type);
}
#endif
blink::WebKeyboardEvent MakeWebKeyboardEventFromUiEvent(const KeyEvent& event) {
WebInputEvent::Type type = WebInputEvent::Type::kUndefined;
switch (event.type()) {
case EventType::kKeyPressed:
type = event.is_char() ? WebInputEvent::Type::kChar
: WebInputEvent::Type::kRawKeyDown;
break;
case EventType::kKeyReleased:
type = WebInputEvent::Type::kKeyUp;
break;
default:
NOTREACHED();
}
blink::WebKeyboardEvent webkit_event(
type,
EventFlagsToWebEventModifiers(event.flags()) |
DomCodeToWebInputEventModifiers(event.code()),
event.time_stamp());
if (webkit_event.GetModifiers() & WebInputEvent::kAltKey) {
webkit_event.is_system_key = true;
}
webkit_event.windows_key_code = event.key_code();
webkit_event.native_key_code =
KeycodeConverter::DomCodeToNativeKeycode(event.code());
webkit_event.dom_code = static_cast<int>(event.code());
webkit_event.dom_key = static_cast<int>(event.GetDomKey());
webkit_event.unmodified_text[0] = event.GetUnmodifiedText();
webkit_event.text[0] = event.GetText();
return webkit_event;
}
blink::WebMouseWheelEvent MakeWebMouseWheelEventFromUiEvent(
const ScrollEvent& event) {
blink::WebMouseWheelEvent webkit_event(
WebInputEvent::Type::kMouseWheel,
EventFlagsToWebEventModifiers(event.flags()), event.time_stamp());
webkit_event.button = blink::WebPointerProperties::Button::kNoButton;
webkit_event.delta_units = ui::ScrollGranularity::kScrollByPrecisePixel;
float offset_ordinal_x = event.x_offset_ordinal();
float offset_ordinal_y = event.y_offset_ordinal();
webkit_event.delta_x = event.x_offset();
webkit_event.delta_y = event.y_offset();
if (offset_ordinal_x != 0.f && webkit_event.delta_x != 0.f)
webkit_event.acceleration_ratio_x = offset_ordinal_x / webkit_event.delta_x;
webkit_event.wheel_ticks_x =
webkit_event.delta_x / MouseWheelEvent::kWheelDelta;
webkit_event.wheel_ticks_y =
webkit_event.delta_y / MouseWheelEvent::kWheelDelta;
if (offset_ordinal_y != 0.f && webkit_event.delta_y != 0.f)
webkit_event.acceleration_ratio_y = offset_ordinal_y / webkit_event.delta_y;
webkit_event.pointer_type = event.pointer_details().pointer_type;
switch (event.scroll_event_phase()) {
case ui::ScrollEventPhase::kNone:
webkit_event.phase = blink::WebMouseWheelEvent::kPhaseNone;
break;
case ui::ScrollEventPhase::kBegan:
webkit_event.phase = blink::WebMouseWheelEvent::kPhaseBegan;
break;
case ui::ScrollEventPhase::kUpdate:
webkit_event.phase = blink::WebMouseWheelEvent::kPhaseChanged;
break;
case ui::ScrollEventPhase::kEnd:
webkit_event.phase = blink::WebMouseWheelEvent::kPhaseEnded;
break;
default:
NOTREACHED();
}
switch (event.momentum_phase()) {
case ui::EventMomentumPhase::NONE:
webkit_event.momentum_phase = blink::WebMouseWheelEvent::kPhaseNone;
break;
case ui::EventMomentumPhase::BEGAN:
webkit_event.momentum_phase = blink::WebMouseWheelEvent::kPhaseBegan;
break;
case ui::EventMomentumPhase::MAY_BEGIN:
webkit_event.momentum_phase = blink::WebMouseWheelEvent::kPhaseMayBegin;
break;
case ui::EventMomentumPhase::INERTIAL_UPDATE:
webkit_event.momentum_phase = blink::WebMouseWheelEvent::kPhaseChanged;
break;
case ui::EventMomentumPhase::END:
webkit_event.momentum_phase = blink::WebMouseWheelEvent::kPhaseEnded;
break;
case ui::EventMomentumPhase::BLOCKED:
webkit_event.momentum_phase = blink::WebMouseWheelEvent::kPhaseBlocked;
break;
default:
NOTREACHED();
}
return webkit_event;
}
blink::WebGestureEvent MakeWebGestureEventFromUiEvent(
const ScrollEvent& event) {
WebInputEvent::Type type = WebInputEvent::Type::kUndefined;
switch (event.type()) {
case EventType::kScrollFlingStart:
type = WebInputEvent::Type::kGestureFlingStart;
break;
case EventType::kScrollFlingCancel:
type = WebInputEvent::Type::kGestureFlingCancel;
break;
case EventType::kScroll:
NOTREACHED() << "Invalid gesture type: "
<< base::to_underlying(event.type());
default:
NOTREACHED() << "Unknown gesture type: "
<< base::to_underlying(event.type());
}
blink::WebGestureEvent webkit_event(
type, EventFlagsToWebEventModifiers(event.flags()), event.time_stamp(),
blink::WebGestureDevice::kTouchpad);
if (event.type() == EventType::kScrollFlingStart) {
webkit_event.data.fling_start.velocity_x = event.x_offset();
webkit_event.data.fling_start.velocity_y = event.y_offset();
}
return webkit_event;
}
blink::WebMouseEvent MakeWebMouseEventFromUiEvent(const MouseEvent& event);
blink::WebMouseWheelEvent MakeWebMouseWheelEventFromUiEvent(
const MouseWheelEvent& event);
blink::WebMouseEvent MakeWebMouseEvent(const MouseEvent& event) {
blink::WebMouseEvent webkit_event =
#if BUILDFLAG(IS_WIN)
event.native_event().message && (event.type() != EventType::kMouseExited)
? MakeUntranslatedWebMouseEventFromNativeEvent(
event.native_event(), event.time_stamp(),
event.pointer_details().pointer_type)
: MakeWebMouseEventFromUiEvent(event);
#else
MakeWebMouseEventFromUiEvent(event);
#endif
webkit_event.UpdateEventModifiersToMatchButton();
webkit_event.SetPositionInWidget(event.x(), event.y());
if (event.flags() & ui::EF_UNADJUSTED_MOUSE) {
webkit_event.movement_x = event.movement().x();
webkit_event.movement_y = event.movement().y();
webkit_event.is_raw_movement_event = true;
}
#if BUILDFLAG(IS_WIN)
if (event.native_event().message && event.type() != EventType::kMouseExited) {
return webkit_event;
}
#endif
const gfx::PointF screen_point = GetScreenLocationFromEvent(event);
webkit_event.SetPositionInScreen(screen_point.x(), screen_point.y());
return webkit_event;
}
blink::WebMouseWheelEvent MakeWebMouseWheelEvent(const MouseWheelEvent& event) {
#if BUILDFLAG(IS_WIN)
blink::WebMouseWheelEvent webkit_event =
event.native_event().message
? MakeUntranslatedWebMouseWheelEventFromNativeEvent(
event.native_event(), event.time_stamp(),
event.pointer_details().pointer_type)
: MakeWebMouseWheelEventFromUiEvent(event);
#else
blink::WebMouseWheelEvent webkit_event =
MakeWebMouseWheelEventFromUiEvent(event);
#endif
webkit_event.SetPositionInWidget(event.x(), event.y());
const gfx::PointF screen_point = GetScreenLocationFromEvent(event);
webkit_event.SetPositionInScreen(screen_point.x(), screen_point.y());
return webkit_event;
}
blink::WebMouseWheelEvent MakeWebMouseWheelEvent(const ScrollEvent& event) {
#if BUILDFLAG(IS_WIN)
blink::WebMouseWheelEvent webkit_event =
event.native_event().message
? MakeUntranslatedWebMouseWheelEventFromNativeEvent(
event.native_event(), event.time_stamp(),
event.pointer_details().pointer_type)
: MakeWebMouseWheelEventFromUiEvent(event);
#else
blink::WebMouseWheelEvent webkit_event =
MakeWebMouseWheelEventFromUiEvent(event);
#endif
webkit_event.SetPositionInWidget(event.x(), event.y());
const gfx::PointF screen_point = GetScreenLocationFromEvent(event);
webkit_event.SetPositionInScreen(screen_point.x(), screen_point.y());
return webkit_event;
}
blink::WebKeyboardEvent MakeWebKeyboardEvent(const KeyEvent& event) {
blink::WebKeyboardEvent webkit_event = MakeWebKeyboardEventFromUiEvent(event);
#if BUILDFLAG(IS_WIN)
if (event.HasNativeEvent()) {
const PlatformEvent& native_event = event.native_event();
webkit_event.is_system_key = native_event.message == WM_SYSCHAR ||
native_event.message == WM_SYSKEYDOWN ||
native_event.message == WM_SYSKEYUP;
webkit_event.native_key_code = static_cast<int>(native_event.lParam);
}
#endif
return webkit_event;
}
blink::WebGestureEvent MakeWebGestureEvent(const GestureEvent& event) {
blink::WebGestureEvent gesture_event = MakeWebGestureEventFromUIEvent(event);
gesture_event.SetPositionInWidget(event.location_f());
const gfx::PointF screen_point = GetScreenLocationFromEvent(event);
gesture_event.SetPositionInScreen(screen_point);
return gesture_event;
}
blink::WebGestureEvent MakeWebGestureEvent(const ScrollEvent& event) {
blink::WebGestureEvent gesture_event = MakeWebGestureEventFromUiEvent(event);
gesture_event.SetPositionInWidget(event.location_f());
const gfx::PointF screen_point = GetScreenLocationFromEvent(event);
gesture_event.SetPositionInScreen(screen_point);
return gesture_event;
}
blink::WebGestureEvent MakeWebGestureEventFlingCancel(
const blink::WebMouseWheelEvent& wheel_event) {
blink::WebGestureEvent gesture_event(
WebInputEvent::Type::kGestureFlingCancel, WebInputEvent::kNoModifiers,
wheel_event.TimeStamp(), blink::WebGestureDevice::kTouchpad);
gesture_event.SetPositionInWidget(wheel_event.PositionInWidget());
gesture_event.SetPositionInScreen(wheel_event.PositionInScreen());
return gesture_event;
}
blink::WebMouseEvent MakeWebMouseEventFromUiEvent(const MouseEvent& event) {
WebInputEvent::Type type = WebInputEvent::Type::kUndefined;
int click_count = 0;
switch (event.type()) {
case EventType::kMousePressed:
type = WebInputEvent::Type::kMouseDown;
click_count = event.GetClickCount();
break;
case EventType::kMouseReleased:
type = WebInputEvent::Type::kMouseUp;
click_count = event.GetClickCount();
break;
case EventType::kMouseExited: {
const Event::Properties* props = event.properties();
if (props && props->contains(kPropertyMouseCrossedIntermediateWindow)) {
type = WebInputEvent::Type::kMouseMove;
} else {
type = WebInputEvent::Type::kMouseLeave;
}
break;
}
case EventType::kMouseEntered:
case EventType::kMouseMoved:
case EventType::kMouseDragged:
type = WebInputEvent::Type::kMouseMove;
break;
default:
NOTIMPLEMENTED() << "Received unexpected event: "
<< base::to_underlying(event.type());
break;
}
blink::WebMouseEvent webkit_event(
type, EventFlagsToWebEventModifiers(event.flags()), event.time_stamp(),
event.pointer_details().id);
webkit_event.button = blink::WebPointerProperties::Button::kNoButton;
int button_flags = event.flags();
if (event.type() == EventType::kMousePressed ||
event.type() == EventType::kMouseReleased) {
if (event.changed_button_flags())
button_flags = event.changed_button_flags();
}
if (button_flags & EF_BACK_MOUSE_BUTTON) {
webkit_event.button = blink::WebPointerProperties::Button::kBack;
}
if (button_flags & EF_FORWARD_MOUSE_BUTTON) {
webkit_event.button = blink::WebPointerProperties::Button::kForward;
}
if (button_flags & EF_LEFT_MOUSE_BUTTON) {
webkit_event.button = blink::WebPointerProperties::Button::kLeft;
}
if (button_flags & EF_MIDDLE_MOUSE_BUTTON) {
webkit_event.button = blink::WebPointerProperties::Button::kMiddle;
}
if (button_flags & EF_RIGHT_MOUSE_BUTTON) {
webkit_event.button = blink::WebPointerProperties::Button::kRight;
}
webkit_event.click_count = click_count;
webkit_event.tilt_x = event.pointer_details().tilt_x;
webkit_event.tilt_y = event.pointer_details().tilt_y;
webkit_event.force = event.pointer_details().force;
webkit_event.tangential_pressure =
event.pointer_details().tangential_pressure;
webkit_event.twist = event.pointer_details().twist;
webkit_event.id = event.pointer_details().id;
webkit_event.pointer_type = event.pointer_details().pointer_type;
webkit_event.device_id = event.source_device_id();
return webkit_event;
}
blink::WebMouseWheelEvent MakeWebMouseWheelEventFromUiEvent(
const MouseWheelEvent& event) {
blink::WebMouseWheelEvent webkit_event(
WebInputEvent::Type::kMouseWheel,
EventFlagsToWebEventModifiers(event.flags()), event.time_stamp());
webkit_event.button = blink::WebPointerProperties::Button::kNoButton;
webkit_event.delta_x = event.x_offset();
webkit_event.delta_y = event.y_offset();
DCHECK(!(event.flags() & ui::EF_PRECISION_SCROLLING_DELTA &&
event.flags() & ui::EF_SCROLL_BY_PAGE));
if (event.flags() & ui::EF_PRECISION_SCROLLING_DELTA) {
webkit_event.delta_units = ui::ScrollGranularity::kScrollByPrecisePixel;
} else if (event.flags() & ui::EF_SCROLL_BY_PAGE) {
webkit_event.delta_units = ui::ScrollGranularity::kScrollByPage;
}
webkit_event.wheel_ticks_x =
webkit_event.delta_x / MouseWheelEvent::kWheelDelta;
webkit_event.wheel_ticks_y =
webkit_event.delta_y / MouseWheelEvent::kWheelDelta;
webkit_event.tilt_x = event.pointer_details().tilt_x;
webkit_event.tilt_y = event.pointer_details().tilt_y;
webkit_event.force = event.pointer_details().force;
webkit_event.pointer_type = event.pointer_details().pointer_type;
return webkit_event;
}
}