| // Copyright 2016 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 "ui/events/mojo/event_struct_traits.h" |
| |
| #include "mojo/common/time_struct_traits.h" |
| #include "ui/events/event.h" |
| #include "ui/events/gesture_event_details.h" |
| #include "ui/events/keycodes/dom/keycode_converter.h" |
| #include "ui/events/mojo/event_constants.mojom.h" |
| #include "ui/latency/mojo/latency_info_struct_traits.h" |
| |
| namespace mojo { |
| namespace { |
| |
| ui::mojom::EventType UIEventTypeToMojo(ui::EventType type) { |
| switch (type) { |
| case ui::ET_KEY_PRESSED: |
| return ui::mojom::EventType::KEY_PRESSED; |
| |
| case ui::ET_KEY_RELEASED: |
| return ui::mojom::EventType::KEY_RELEASED; |
| |
| case ui::ET_POINTER_DOWN: |
| return ui::mojom::EventType::POINTER_DOWN; |
| |
| case ui::ET_POINTER_MOVED: |
| return ui::mojom::EventType::POINTER_MOVE; |
| |
| case ui::ET_POINTER_EXITED: |
| return ui::mojom::EventType::MOUSE_EXIT; |
| |
| case ui::ET_POINTER_UP: |
| return ui::mojom::EventType::POINTER_UP; |
| |
| case ui::ET_POINTER_CANCELLED: |
| return ui::mojom::EventType::POINTER_CANCEL; |
| |
| case ui::ET_POINTER_WHEEL_CHANGED: |
| return ui::mojom::EventType::POINTER_WHEEL_CHANGED; |
| |
| case ui::ET_GESTURE_TAP: |
| return ui::mojom::EventType::GESTURE_TAP; |
| |
| default: |
| NOTREACHED() << "This unsupported event type will close the connection"; |
| break; |
| } |
| return ui::mojom::EventType::UNKNOWN; |
| } |
| |
| ui::EventType MojoPointerEventTypeToUIEvent(ui::mojom::EventType action) { |
| switch (action) { |
| case ui::mojom::EventType::POINTER_DOWN: |
| return ui::ET_POINTER_DOWN; |
| |
| case ui::mojom::EventType::POINTER_UP: |
| return ui::ET_POINTER_UP; |
| |
| case ui::mojom::EventType::POINTER_MOVE: |
| return ui::ET_POINTER_MOVED; |
| |
| case ui::mojom::EventType::POINTER_CANCEL: |
| return ui::ET_POINTER_CANCELLED; |
| |
| case ui::mojom::EventType::MOUSE_EXIT: |
| return ui::ET_POINTER_EXITED; |
| |
| case ui::mojom::EventType::POINTER_WHEEL_CHANGED: |
| return ui::ET_POINTER_WHEEL_CHANGED; |
| |
| default: |
| NOTREACHED(); |
| } |
| |
| return ui::ET_UNKNOWN; |
| } |
| |
| ui::mojom::LocationDataPtr GetLocationData(ui::LocatedEvent* event) { |
| ui::mojom::LocationDataPtr location_data(ui::mojom::LocationData::New()); |
| location_data->x = event->location_f().x(); |
| location_data->y = event->location_f().y(); |
| location_data->screen_x = event->root_location_f().x(); |
| location_data->screen_y = event->root_location_f().y(); |
| return location_data; |
| } |
| |
| ui::EventPointerType PointerTypeFromPointerKind(ui::mojom::PointerKind kind) { |
| switch (kind) { |
| case ui::mojom::PointerKind::MOUSE: |
| return ui::EventPointerType::POINTER_TYPE_MOUSE; |
| case ui::mojom::PointerKind::TOUCH: |
| return ui::EventPointerType::POINTER_TYPE_TOUCH; |
| case ui::mojom::PointerKind::PEN: |
| return ui::EventPointerType::POINTER_TYPE_PEN; |
| case ui::mojom::PointerKind::ERASER: |
| return ui::EventPointerType::POINTER_TYPE_ERASER; |
| } |
| NOTREACHED(); |
| return ui::EventPointerType::POINTER_TYPE_UNKNOWN; |
| } |
| |
| bool ReadPointerDetails(ui::mojom::EventType event_type, |
| const ui::mojom::PointerData& pointer_data, |
| ui::PointerDetails* out) { |
| switch (pointer_data.kind) { |
| case ui::mojom::PointerKind::MOUSE: { |
| if (event_type == ui::mojom::EventType::POINTER_WHEEL_CHANGED) { |
| *out = ui::PointerDetails( |
| ui::EventPointerType::POINTER_TYPE_MOUSE, |
| gfx::Vector2d(static_cast<int>(pointer_data.wheel_data->delta_x), |
| static_cast<int>(pointer_data.wheel_data->delta_y)), |
| ui::MouseEvent::kMousePointerId); |
| } else { |
| *out = ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_MOUSE, |
| ui::MouseEvent::kMousePointerId); |
| } |
| return true; |
| } |
| case ui::mojom::PointerKind::TOUCH: |
| case ui::mojom::PointerKind::PEN: { |
| const ui::mojom::BrushData& brush_data = *pointer_data.brush_data; |
| *out = ui::PointerDetails( |
| PointerTypeFromPointerKind(pointer_data.kind), |
| pointer_data.pointer_id, brush_data.width, brush_data.height, |
| brush_data.pressure, brush_data.twist, brush_data.tilt_x, |
| brush_data.tilt_y, brush_data.tangential_pressure); |
| return true; |
| } |
| case ui::mojom::PointerKind::ERASER: |
| // TODO(jamescook): Eraser support. |
| NOTIMPLEMENTED(); |
| return false; |
| } |
| NOTREACHED(); |
| return false; |
| } |
| |
| } // namespace |
| |
| static_assert(ui::mojom::kEventFlagNone == static_cast<int32_t>(ui::EF_NONE), |
| "EVENT_FLAGS must match"); |
| static_assert(ui::mojom::kEventFlagIsSynthesized == |
| static_cast<int32_t>(ui::EF_IS_SYNTHESIZED), |
| "EVENT_FLAGS must match"); |
| static_assert(ui::mojom::kEventFlagShiftDown == |
| static_cast<int32_t>(ui::EF_SHIFT_DOWN), |
| "EVENT_FLAGS must match"); |
| static_assert(ui::mojom::kEventFlagControlDown == |
| static_cast<int32_t>(ui::EF_CONTROL_DOWN), |
| "EVENT_FLAGS must match"); |
| static_assert(ui::mojom::kEventFlagAltDown == |
| static_cast<int32_t>(ui::EF_ALT_DOWN), |
| "EVENT_FLAGS must match"); |
| static_assert(ui::mojom::kEventFlagCommandDown == |
| static_cast<int32_t>(ui::EF_COMMAND_DOWN), |
| "EVENT_FLAGS must match"); |
| static_assert(ui::mojom::kEventFlagAltgrDown == |
| static_cast<int32_t>(ui::EF_ALTGR_DOWN), |
| "EVENT_FLAGS must match"); |
| static_assert(ui::mojom::kEventFlagMod3Down == |
| static_cast<int32_t>(ui::EF_MOD3_DOWN), |
| "EVENT_FLAGS must match"); |
| static_assert(ui::mojom::kEventFlagNumLockOn == |
| static_cast<int32_t>(ui::EF_NUM_LOCK_ON), |
| "EVENT_FLAGS must match"); |
| static_assert(ui::mojom::kEventFlagCapsLockOn == |
| static_cast<int32_t>(ui::EF_CAPS_LOCK_ON), |
| "EVENT_FLAGS must match"); |
| static_assert(ui::mojom::kEventFlagScrollLockOn == |
| static_cast<int32_t>(ui::EF_SCROLL_LOCK_ON), |
| "EVENT_FLAGS must match"); |
| static_assert(ui::mojom::kEventFlagLeftMouseButton == |
| static_cast<int32_t>(ui::EF_LEFT_MOUSE_BUTTON), |
| "EVENT_FLAGS must match"); |
| static_assert(ui::mojom::kEventFlagMiddleMouseButton == |
| static_cast<int32_t>(ui::EF_MIDDLE_MOUSE_BUTTON), |
| "EVENT_FLAGS must match"); |
| static_assert(ui::mojom::kEventFlagRightMouseButton == |
| static_cast<int32_t>(ui::EF_RIGHT_MOUSE_BUTTON), |
| "EVENT_FLAGS must match"); |
| static_assert(ui::mojom::kEventFlagBackMouseButton == |
| static_cast<int32_t>(ui::EF_BACK_MOUSE_BUTTON), |
| "EVENT_FLAGS must match"); |
| static_assert(ui::mojom::kEventFlagForwardMouseButton == |
| static_cast<int32_t>(ui::EF_FORWARD_MOUSE_BUTTON), |
| "EVENT_FLAGS must match"); |
| |
| ui::mojom::EventType |
| StructTraits<ui::mojom::EventDataView, EventUniquePtr>::action( |
| const EventUniquePtr& event) { |
| return UIEventTypeToMojo(event->type()); |
| } |
| |
| int32_t StructTraits<ui::mojom::EventDataView, EventUniquePtr>::flags( |
| const EventUniquePtr& event) { |
| return event->flags(); |
| } |
| |
| base::TimeTicks |
| StructTraits<ui::mojom::EventDataView, EventUniquePtr>::time_stamp( |
| const EventUniquePtr& event) { |
| return event->time_stamp(); |
| } |
| |
| const ui::LatencyInfo& |
| StructTraits<ui::mojom::EventDataView, EventUniquePtr>::latency( |
| const EventUniquePtr& event) { |
| return *event->latency(); |
| } |
| |
| ui::mojom::KeyDataPtr |
| StructTraits<ui::mojom::EventDataView, EventUniquePtr>::key_data( |
| const EventUniquePtr& event) { |
| if (!event->IsKeyEvent()) |
| return nullptr; |
| |
| const ui::KeyEvent* key_event = event->AsKeyEvent(); |
| ui::mojom::KeyDataPtr key_data(ui::mojom::KeyData::New()); |
| key_data->key_code = key_event->GetConflatedWindowsKeyCode(); |
| key_data->native_key_code = |
| ui::KeycodeConverter::DomCodeToNativeKeycode(key_event->code()); |
| key_data->is_char = key_event->is_char(); |
| key_data->character = key_event->GetCharacter(); |
| key_data->windows_key_code = static_cast<ui::mojom::KeyboardCode>( |
| key_event->GetLocatedWindowsKeyboardCode()); |
| key_data->text = key_event->GetText(); |
| key_data->unmodified_text = key_event->GetUnmodifiedText(); |
| if (key_event->properties()) |
| key_data->properties = *(key_event->properties()); |
| |
| return key_data; |
| } |
| |
| ui::mojom::PointerDataPtr |
| StructTraits<ui::mojom::EventDataView, EventUniquePtr>::pointer_data( |
| const EventUniquePtr& event) { |
| if (!event->IsPointerEvent()) |
| return nullptr; |
| |
| const ui::PointerEvent* pointer_event = event->AsPointerEvent(); |
| ui::mojom::PointerDataPtr pointer_data(ui::mojom::PointerData::New()); |
| pointer_data->pointer_id = pointer_event->pointer_details().id; |
| pointer_data->changed_button_flags = pointer_event->changed_button_flags(); |
| const ui::PointerDetails* pointer_details = &pointer_event->pointer_details(); |
| ui::EventPointerType pointer_type = pointer_details->pointer_type; |
| |
| switch (pointer_type) { |
| case ui::EventPointerType::POINTER_TYPE_MOUSE: |
| pointer_data->kind = ui::mojom::PointerKind::MOUSE; |
| break; |
| case ui::EventPointerType::POINTER_TYPE_TOUCH: |
| pointer_data->kind = ui::mojom::PointerKind::TOUCH; |
| break; |
| case ui::EventPointerType::POINTER_TYPE_PEN: |
| pointer_data->kind = ui::mojom::PointerKind::PEN; |
| break; |
| case ui::EventPointerType::POINTER_TYPE_ERASER: |
| pointer_data->kind = ui::mojom::PointerKind::ERASER; |
| break; |
| case ui::EventPointerType::POINTER_TYPE_UNKNOWN: |
| NOTREACHED(); |
| } |
| |
| ui::mojom::BrushDataPtr brush_data(ui::mojom::BrushData::New()); |
| // TODO(rjk): this is in the wrong coordinate system |
| brush_data->width = pointer_details->radius_x; |
| brush_data->height = pointer_details->radius_y; |
| brush_data->pressure = pointer_details->force; |
| // In theory only pen events should have tilt, tangential_pressure and twist. |
| // In practive a JavaScript PointerEvent could have type touch and still have |
| // data in those fields. |
| brush_data->tilt_x = pointer_details->tilt_x; |
| brush_data->tilt_y = pointer_details->tilt_y; |
| brush_data->tangential_pressure = pointer_details->tangential_pressure; |
| brush_data->twist = pointer_details->twist; |
| pointer_data->brush_data = std::move(brush_data); |
| |
| // TODO(rjkroege): Plumb raw pointer events on windows. |
| // TODO(rjkroege): Handle force-touch on MacOS |
| // TODO(rjkroege): Adjust brush data appropriately for Android. |
| |
| pointer_data->location = GetLocationData(event->AsLocatedEvent()); |
| |
| if (event->type() == ui::ET_POINTER_WHEEL_CHANGED) { |
| ui::mojom::WheelDataPtr wheel_data(ui::mojom::WheelData::New()); |
| |
| // TODO(rjkroege): Support page scrolling on windows by directly |
| // cracking into a mojo event when the native event is available. |
| wheel_data->mode = ui::mojom::WheelMode::LINE; |
| // TODO(rjkroege): Support precise scrolling deltas. |
| |
| if ((event->flags() & ui::EF_SHIFT_DOWN) != 0 && |
| pointer_details->offset.x() == 0) { |
| wheel_data->delta_x = pointer_details->offset.y(); |
| wheel_data->delta_y = 0; |
| wheel_data->delta_z = 0; |
| } else { |
| // TODO(rjkroege): support z in ui::Events. |
| wheel_data->delta_x = pointer_details->offset.x(); |
| wheel_data->delta_y = pointer_details->offset.y(); |
| wheel_data->delta_z = 0; |
| } |
| pointer_data->wheel_data = std::move(wheel_data); |
| } |
| |
| return pointer_data; |
| } |
| |
| ui::mojom::GestureDataPtr |
| StructTraits<ui::mojom::EventDataView, EventUniquePtr>::gesture_data( |
| const EventUniquePtr& event) { |
| if (!event->IsGestureEvent()) |
| return nullptr; |
| |
| ui::mojom::GestureDataPtr gesture_data(ui::mojom::GestureData::New()); |
| gesture_data->location = GetLocationData(event->AsLocatedEvent()); |
| return gesture_data; |
| } |
| |
| bool StructTraits<ui::mojom::EventDataView, EventUniquePtr>::Read( |
| ui::mojom::EventDataView event, |
| EventUniquePtr* out) { |
| DCHECK(!out->get()); |
| |
| base::TimeTicks time_stamp; |
| if (!event.ReadTimeStamp(&time_stamp)) |
| return false; |
| |
| switch (event.action()) { |
| case ui::mojom::EventType::KEY_PRESSED: |
| case ui::mojom::EventType::KEY_RELEASED: { |
| ui::mojom::KeyDataPtr key_data; |
| if (!event.ReadKeyData<ui::mojom::KeyDataPtr>(&key_data)) |
| return false; |
| |
| if (key_data->is_char) { |
| *out = std::make_unique<ui::KeyEvent>( |
| static_cast<base::char16>(key_data->character), |
| static_cast<ui::KeyboardCode>(key_data->key_code), event.flags(), |
| time_stamp); |
| } else { |
| *out = std::make_unique<ui::KeyEvent>( |
| event.action() == ui::mojom::EventType::KEY_PRESSED |
| ? ui::ET_KEY_PRESSED |
| : ui::ET_KEY_RELEASED, |
| static_cast<ui::KeyboardCode>(key_data->key_code), event.flags(), |
| time_stamp); |
| } |
| if (key_data->properties) |
| (*out)->AsKeyEvent()->SetProperties(*key_data->properties); |
| break; |
| } |
| case ui::mojom::EventType::POINTER_DOWN: |
| case ui::mojom::EventType::POINTER_UP: |
| case ui::mojom::EventType::POINTER_MOVE: |
| case ui::mojom::EventType::POINTER_CANCEL: |
| case ui::mojom::EventType::MOUSE_EXIT: |
| case ui::mojom::EventType::POINTER_WHEEL_CHANGED: { |
| ui::mojom::PointerDataPtr pointer_data; |
| if (!event.ReadPointerData<ui::mojom::PointerDataPtr>(&pointer_data)) |
| return false; |
| |
| ui::PointerDetails pointer_details; |
| if (!ReadPointerDetails(event.action(), *pointer_data, &pointer_details)) |
| return false; |
| |
| const gfx::Point location(pointer_data->location->x, |
| pointer_data->location->y); |
| const gfx::Point screen_location(pointer_data->location->screen_x, |
| pointer_data->location->screen_y); |
| *out = std::make_unique<ui::PointerEvent>( |
| MojoPointerEventTypeToUIEvent(event.action()), location, |
| screen_location, event.flags(), pointer_data->changed_button_flags, |
| pointer_details, time_stamp); |
| break; |
| } |
| case ui::mojom::EventType::GESTURE_TAP: { |
| ui::mojom::GestureDataPtr gesture_data; |
| if (!event.ReadGestureData<ui::mojom::GestureDataPtr>(&gesture_data)) |
| return false; |
| |
| *out = std::make_unique<ui::GestureEvent>( |
| gesture_data->location->x, gesture_data->location->y, event.flags(), |
| time_stamp, ui::GestureEventDetails(ui::ET_GESTURE_TAP)); |
| break; |
| } |
| case ui::mojom::EventType::UNKNOWN: |
| NOTREACHED() << "This unsupported event type will close the connection"; |
| return false; |
| } |
| |
| if (!out->get()) |
| return false; |
| |
| return event.ReadLatency((*out)->latency()); |
| } |
| |
| } // namespace mojo |