* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "nweb_event_handler.h"
#include <cmath>
#include <vector>
#include "cef/include/base/cef_logging.h"
#include "cef/include/base/cef_macros.h"
#include "cef/include/internal/cef_types.h"
#include "cef/include/internal/cef_types_wrappers.h"
#include "cef_delegate/nweb_delegate.h"
#include "base/trace_event/common/trace_event_common.h"
#include "base/trace_event/trace_event.h"
#include "ui/events/keycodes/keyboard_code_conversion_x.h"
#include "ui/events/keycodes/keysym_to_unicode.h"
namespace OHOS::NWeb {
std::shared_ptr<NWebEventHandler> NWebEventHandler::Create() {
auto event_handler = std::make_shared<NWebEventHandler>();
if (event_handler == nullptr) {
LOG(ERROR) << "fail to create NWebEventHandler instance";
return nullptr;
}
return event_handler;
}
NWebEventHandler::NWebEventHandler() {
#if defined(OHOS_INPUT_EVENTS)
mmi_adapter_ =
OHOS::NWeb::OhosAdapterHelper::GetInstance().CreateMMIAdapter();
if (mmi_adapter_ == nullptr) {
LOG(ERROR) << "display_manager_adapter is nullptr";
return;
}
#endif
}
void NWebEventHandler::OnDestroy() {
#if defined(OHOS_INPUT_EVENTS)
if (mmi_id_ > 0 && mmi_adapter_ != nullptr) {
mmi_adapter_->UnregisterMMIInputListener(mmi_id_);
}
#endif
browser_ = nullptr;
}
void NWebEventHandler::SetBrowser(CefRefPtr<CefBrowser> browser) {
browser_ = browser;
}
void NWebEventHandler::OnTouchPress(int32_t id,
double x,
double y,
bool from_overlay) {
#if defined(OHOS_SLIDE) || defined(OHOS_PER_DFX)
TRACE_EVENT0("input",
"NWebEventHandler::OnTouchPress sliding response begin");
LOG(DEBUG) << "NWebEventHandler::OnTouchPress sliding response begin. id = "
<< id << ", x = " << x << ", y = " << y
<< ", from_overlay = " << from_overlay;
#endif
CefTouchEvent touch_pressed;
touch_pressed.type = CEF_TET_PRESSED;
touch_pressed.pointer_type = CEF_POINTER_TYPE_TOUCH;
touch_pressed.id = id;
touch_pressed.x = x;
touch_pressed.y = y;
touch_pressed.modifiers = EVENTFLAG_NONE;
touch_pressed.from_overlay = from_overlay;
if (browser_ && browser_->GetHost()) {
browser_->GetHost()->SendTouchEvent(touch_pressed);
}
}
void NWebEventHandler::OnTouchMove(int32_t id,
double x,
double y,
bool from_overlay) {
LOG(DEBUG) << "NWebEventHandler::OnTouchMove id = " << id << ", x = " << x
<< ", y = " << y << ", from_overlay = " << from_overlay;
CefTouchEvent touch_move;
touch_move.type = CEF_TET_MOVED;
touch_move.pointer_type = CEF_POINTER_TYPE_TOUCH;
touch_move.id = id;
touch_move.x = x;
touch_move.y = y;
touch_move.modifiers = EVENTFLAG_NONE;
touch_move.from_overlay = from_overlay;
if (browser_ && browser_->GetHost()) {
browser_->GetHost()->SendTouchEvent(touch_move);
}
}
void NWebEventHandler::OnTouchMove(const std::vector<std::shared_ptr<NWebTouchPointInfo>> &touch_point_infos,
bool from_overlay, float virtual_pixel_ratio) {
std::vector<CefTouchEvent> event_list {};
std::string touch_point_info_str {"NWebEventHandler::OnTouchMove"};
for (const auto& touch_point : touch_point_infos) {
CefTouchEvent touch_move;
touch_move.type = CEF_TET_MOVED;
touch_move.pointer_type = CEF_POINTER_TYPE_TOUCH;
touch_move.id = touch_point->GetId();
touch_move.x = touch_point->GetX() / virtual_pixel_ratio;
touch_move.y = touch_point->GetY() / virtual_pixel_ratio;
touch_move.modifiers = EVENTFLAG_NONE;
touch_move.from_overlay = from_overlay;
touch_point_info_str += " id = " + std::to_string(touch_point->GetId()) + ", x = " +
std::to_string(touch_move.x) + ", y = " + std::to_string(touch_move.y);
event_list.emplace_back(touch_move);
}
LOG(DEBUG) << touch_point_info_str << ", from_overlay = " << from_overlay;
if (browser_ && browser_->GetHost()) {
browser_->GetHost()->SendTouchEventList(event_list);
}
}
void NWebEventHandler::OnTouchRelease(int32_t id,
double x,
double y,
bool from_overlay) {
LOG(DEBUG) << "NWebEventHandler::OnTouchRelease";
CefTouchEvent touch_end;
touch_end.type = CEF_TET_RELEASED;
touch_end.pointer_type = CEF_POINTER_TYPE_TOUCH;
touch_end.id = id;
touch_end.x = x;
touch_end.y = y;
touch_end.modifiers = EVENTFLAG_NONE;
touch_end.from_overlay = from_overlay;
if (browser_ && browser_->GetHost()) {
browser_->GetHost()->SendTouchEvent(touch_end);
}
}
void NWebEventHandler::OnTouchCancel() {
LOG(DEBUG) << "NWebEventHandler::OnTouchCancel";
CefTouchEvent touch_cancelled;
touch_cancelled.type = CEF_TET_CANCELLED;
if (browser_ && browser_->GetHost()) {
browser_->GetHost()->SendTouchEvent(touch_cancelled);
}
}
void NWebEventHandler::OnTouchCancelById(int32_t id,
double x,
double y,
bool from_overlay) {
(void)from_overlay;
CefTouchEvent touch_cancelled;
touch_cancelled.type = CEF_TET_CANCELLED;
touch_cancelled.pointer_type = CEF_POINTER_TYPE_TOUCH;
touch_cancelled.id = id;
touch_cancelled.x = x;
touch_cancelled.y = y;
if (browser_ && browser_->GetHost()) {
browser_->GetHost()->SendTouchEvent(touch_cancelled);
}
}
#if defined(OHOS_INPUT_EVENTS)
void NWebEventHandler::SendKeyEventFromMMI(int32_t keyCode, int32_t keyAction) {
if (!isFocus_ || !NWebInputDelegate::IsMMIKeyEvent(keyCode)) {
return;
}
LOG(DEBUG) << "SendKeyEventFromMMI keyCode = " << keyCode
<< " keyAction = " << keyAction;
SendKeyEvent(keyCode, keyAction);
}
bool NWebEventHandler::SendKeyEventFromAce(int32_t keyCode, int32_t keyAction) {
if (mmi_id_ >= 0 && NWebInputDelegate::IsMMIKeyEvent(keyCode)) {
return true;
}
LOG(DEBUG) << "SendKeyEventFromAce keyCode = " << keyCode
<< " keyAction = " << keyAction;
return SendKeyEvent(keyCode, keyAction);
}
bool NWebEventHandler::WebSendKeyEventFromAce(int32_t keyCode, int32_t keyAction,
const std::vector<int32_t>& pressedCodes) {
if (mmi_id_ >= 0 && NWebInputDelegate::IsMMIKeyEvent(keyCode)) {
return true;
}
LOG(DEBUG) << "WebSendKeyEventFromAce keyCode = " << keyCode
<< " keyAction = " << keyAction;
return WebSendKeyEvent(keyCode, keyAction, pressedCodes);
}
bool NWebEventHandler::CreateCefKeyEvent(CefKeyEvent& keyEvent,
int32_t keyCode,
int32_t keyAction,
int32_t modifiers) {
keyEvent.windows_key_code =
NWebInputDelegate::CefConverter("keycode", keyCode);
if (keyEvent.windows_key_code == -1) {
LOG(ERROR) << "WebSendKeyEvent keyCode conversion failed";
return false;
}
int type = NWebInputDelegate::CefConverter("keyaction", keyAction);
if (type == -1) {
LOG(ERROR) << "keyaction conversion failed, keyAction:" << keyAction;
return false;
}
keyEvent.type = static_cast<cef_key_event_type_t>(type);
keyEvent.modifiers = modifiers;
LOG(DEBUG) << "WebSendKeyEvent modifiers = " << keyEvent.modifiers;
keyEvent.is_system_key = false;
keyEvent.native_key_code =
NWebInputDelegate::CefConverter("keyscancode", keyCode);
ui::KeyboardCode key_code =
static_cast<ui::KeyboardCode>(keyEvent.windows_key_code);
int keysym = ui::XKeysymForWindowsKeyCode(
key_code, keyEvent.modifiers & EVENTFLAG_SHIFT_DOWN, keyEvent.modifiers & EVENTFLAG_CAPS_LOCK_ON);
char16_t character = ui::GetUnicodeCharacterFromXKeySym(keysym);
keyEvent.character = keyEvent.unmodified_character = character;
return true;
}
void NWebEventHandler::SendCefKeyEvent(CefKeyEvent& keyEvent) {
if (!browser_ || !browser_->GetHost()) {
LOG(ERROR) << "SendCefKeyEvent browser_ or Host is nullptr, browser_: " << !browser_;
return;
}
browser_->GetHost()->SendKeyEvent(keyEvent);
if (keyEvent.type == KEYEVENT_RAWKEYDOWN) {
keyEvent.type = KEYEVENT_CHAR;
browser_->GetHost()->SendKeyEvent(keyEvent);
}
}
bool NWebEventHandler::WebSendKeyEvent(int32_t keyCode, int32_t keyAction,
const std::vector<int32_t>& pressedCodes) {
LOG(DEBUG) << "WebSendKeyEvent keyCode = " << keyCode
<< " keyAction = " << keyAction;
if (keyCode < 0) {
LOG(ERROR) << "WebSendKeyEvent obtaining invalid keyCode";
return false;
}
CefKeyEvent keyEvent;
int32_t modifiers = NWebInputDelegate::GetWebModifiers(keyCode, keyAction, pressedCodes);
input_delegate_.SetModifiers(keyCode, keyAction);
if (!CreateCefKeyEvent(keyEvent, keyCode, keyAction, modifiers)) {
LOG(ERROR) << "WebSendKeyEvent create key event failed";
return false;
}
SendCefKeyEvent(keyEvent);
return true;
}
void NWebEventHandler::SendCefMouseWheelEvent(double x,
double y,
double deltaX,
double deltaY,
int32_t modifiers,
int32_t source) {
CefMouseEvent mouseEvent;
mouseEvent.x = x;
mouseEvent.y = y;
mouseEvent.modifiers = modifiers;
mouseEvent.source = source;
LOG(DEBUG) << "WebSendMouseWheelEvent modifiers = " << mouseEvent.modifiers;
LOG(DEBUG) << "WebSendMouseWheelEventV2 source = " << mouseEvent.source;
if (!browser_ || !browser_->GetHost()) {
LOG(ERROR) << "SendCefMouseWheelEvent browser_ or Host is nullptr, browser_: " << !browser_;
return;
}
double horizontalDelta;
double verticalDelta;
if (mmi_id_ > 0 && (mouseEvent.modifiers & EVENTFLAG_SHIFT_DOWN)) {
horizontalDelta = deltaY * input_delegate_.GetMouseWheelRatio();
verticalDelta = deltaX * input_delegate_.GetMouseWheelRatio();
} else {
horizontalDelta = deltaX * input_delegate_.GetMouseWheelRatio();
verticalDelta = deltaY * input_delegate_.GetMouseWheelRatio();
}
LOG(DEBUG) << "SendCefMouseWheelEvent Axis deltaX: " << horizontalDelta
<< " deltaY: " << verticalDelta;
browser_->GetHost()->SendMouseWheelEvent(mouseEvent, horizontalDelta,
verticalDelta);
}
void NWebEventHandler::WebSendMouseWheelEvent(double x,
double y,
double deltaX,
double deltaY,
const std::vector<int32_t>& pressedCodes) {
int32_t modifiers = NWebInputDelegate::GetWebModifiersByPressedCode(pressedCodes);
SendCefMouseWheelEvent(x, y, deltaX, deltaY, modifiers);
}
void NWebEventHandler::WebSendMouseWheelEventV2(double x,
double y,
double deltaX,
double deltaY,
const std::vector<int32_t>& pressedCodes,
int32_t source) {
int32_t modifiers = NWebInputDelegate::GetWebModifiersByPressedCode(pressedCodes);
SendCefMouseWheelEvent(x, y, deltaX, deltaY, modifiers, source);
}
void NWebEventHandler::WebSendTouchpadFlingEvent(double x,
double y,
double vx,
double vy,
const std::vector<int32_t>& pressedCodes) {
CefMouseEvent mouseEvent;
mouseEvent.x = x;
mouseEvent.y = y;
mouseEvent.modifiers = NWebInputDelegate::GetWebModifiersByPressedCode(pressedCodes);
LOG(DEBUG) << "WebSendTouchpadFlingEvent modifiers = " << mouseEvent.modifiers;
if (!browser_ || !browser_->GetHost()) {
LOG(ERROR) << "WebSendTouchpadFlingEvent browser_ or host is nullptr, browser_: " << !browser_;
return;
}
browser_->GetHost()->SendTouchpadFlingEvent(mouseEvent, vx, vy);
}
bool NWebEventHandler::SendKeyboardEvent(
const std::shared_ptr<OHOS::NWeb::NWebKeyboardEvent>& keyboardEvent) {
if (!keyboardEvent) {
return false;
}
if (keyboardEvent->GetKeyCode() < 0) {
LOG(ERROR) << "SendKeyboardEvent obtaining invalid keyCode";
return false;
}
CefKeyEvent keyEvent;
int32_t modifiers = NWebInputDelegate::GetModifiersByKeyEvent(keyboardEvent);
if (!CreateCefKeyEvent(keyEvent,
keyboardEvent->GetKeyCode(),
keyboardEvent->GetAction(),
modifiers)) {
return false;
}
SendCefKeyEvent(keyEvent);
return true;
}
#if defined(OHOS_INPUT_EVENTS)
void NWebEventHandler::WebUpdateModifiers(CefMouseEvent& mouseInfo, const cef_mouse_button_type_t& buttonType) {
if (NWebInputDelegate::IsMouseDown(previous_action_) && previous_button_ != buttonType) {
mouseInfo.modifiers |= NWebInputDelegate::GetMouseButtonModifiers(
static_cast<cef_mouse_button_type_t>(previous_action_));
}
}
#endif
void NWebEventHandler::WebSendMouseEvent(const std::shared_ptr<OHOS::NWeb::NWebMouseEvent>& mouseEvent,
float ratio) {
if (!mouseEvent) {
LOG(INFO) << "WebSendMouseEvent mouseEvent is NULL";
return;
}
CefMouseEvent mouseInfo;
mouseInfo.x = mouseEvent->GetX() / ratio;
mouseInfo.y = mouseEvent->GetY() / ratio;
mouseInfo.raw_x = mouseEvent->GetRawX();
mouseInfo.raw_y = mouseEvent->GetRawY();
#ifdef OHOS_EX_TOPCONTROLS
if (browser_ && browser_->GetHost()) {
mouseInfo.y -= browser_->GetHost()->GetShrinkViewportHeight();
}
#endif
cef_mouse_button_type_t buttonType = static_cast<cef_mouse_button_type_t>(
NWebInputDelegate::CefConverter("mousebutton", mouseEvent->GetButton()));
mouseInfo.modifiers = NWebInputDelegate::GetWebMouseModifiersByPressedCode(buttonType,
mouseEvent->GetPressKeyCodes());
LOG(INFO) << "WebSendMouseEvent x: " << mouseInfo.x << " y: " << mouseInfo.y
<< " modifiers: " << mouseInfo.modifiers;
if (NWebInputDelegate::IsMouseLeave(mouseEvent->GetAction())) {
is_in_web_ = false;
} else if (NWebInputDelegate::IsMouseEnter(mouseEvent->GetAction())) {
is_in_web_ = true;
}
if (browser_ && browser_->GetHost()) {
if (NWebInputDelegate::IsMouseDown(mouseEvent->GetAction())) {
previous_action_ = mouseEvent->GetAction();
previous_button_ = buttonType;
browser_->GetHost()->SendMouseClickEvent(mouseInfo, buttonType, false,
mouseEvent->GetClickNum());
} else if (NWebInputDelegate::IsMouseUp(mouseEvent->GetAction())) {
previous_action_ = mouseEvent->GetAction();
previous_button_ = buttonType;
browser_->GetHost()->SendMouseClickEvent(mouseInfo, buttonType, true, 1);
if (!is_in_web_) {
browser_->GetHost()->SendMouseMoveEvent(mouseInfo, true);
}
} else if (NWebInputDelegate::IsMouseMove(mouseEvent->GetAction())) {
if (last_mouse_x_ == mouseInfo.x && last_mouse_y_ == mouseInfo.y) {
LOG(INFO) << "no change in coordinates, cancel mouse move event";
return;
}
#if defined(OHOS_INPUT_EVENTS)
WebUpdateModifiers(mouseInfo, buttonType);
#endif
last_mouse_x_ = mouseInfo.x;
last_mouse_y_ = mouseInfo.y;
browser_->GetHost()->SendMouseMoveEvent(mouseInfo, false);
} else if (NWebInputDelegate::IsMouseLeave(mouseEvent->GetAction())) {
if (previous_button_ == MBT_LEFT || previous_button_ == MBT_RIGHT) {
browser_->GetHost()->SendMouseMoveEvent(mouseInfo, true);
}
} else {
previous_action_= mouseEvent->GetAction();
LOG(INFO) << "mouse event action: " << mouseEvent->GetAction();
}
}
}
#endif
bool NWebEventHandler::SendKeyEvent(int32_t keyCode, int32_t keyAction) {
LOG(DEBUG) << "SendKeyEvent keyCode = " << keyCode
<< " keyAction = " << keyAction;
if (keyCode < 0) {
LOG(ERROR) << "SendKeyEvent obtaining invalid keyCode";
return false;
}
CefKeyEvent keyEvent;
input_delegate_.SetModifiers(keyCode, keyAction);
int32_t modifiers = input_delegate_.GetModifiers();
if (!CreateCefKeyEvent(keyEvent, keyCode, keyAction, modifiers)) {
LOG(ERROR) << "SendKeyEvent create key event failed";
return false;
}
SendCefKeyEvent(keyEvent);
return true;
}
void NWebEventHandler::SendTouchpadFlingEvent(double x, double y, double vx, double vy) {
CefMouseEvent mouseEvent;
mouseEvent.x = x;
mouseEvent.y = y;
mouseEvent.modifiers = input_delegate_.GetModifiers();
#if defined(OHOS_INPUT_EVENTS)
if (!browser_ || !browser_->GetHost()) {
LOG(ERROR) << "SendTouchpadFlingEvent browser_ or host is nullptr, browser_: " << !browser_;
return;
}
browser_->GetHost()->SendTouchpadFlingEvent(mouseEvent, vx, vy);
#endif
}
void NWebEventHandler::SendMouseWheelEvent(double x,
double y,
double deltaX,
double deltaY) {
#if defined(OHOS_INPUT_EVENTS)
int32_t modifiers = input_delegate_.GetModifiers();
SendCefMouseWheelEvent(x, y, deltaX, deltaY, modifiers);
#endif
}
void NWebEventHandler::SendMouseEvent(int x,
int y,
int button,
int action,
int count) {
CefMouseEvent mouseEvent;
mouseEvent.x = x;
mouseEvent.y = y;
#ifdef OHOS_EX_TOPCONTROLS
if (browser_ && browser_->GetHost()) {
mouseEvent.y -= browser_->GetHost()->GetShrinkViewportHeight();
}
#endif
cef_mouse_button_type_t buttonType = static_cast<cef_mouse_button_type_t>(
NWebInputDelegate::CefConverter("mousebutton", button));
mouseEvent.modifiers = input_delegate_.GetModifiers(buttonType);
if (NWebInputDelegate::IsMouseLeave(action)) {
is_in_web_ = false;
} else if (NWebInputDelegate::IsMouseEnter(action)) {
is_in_web_ = true;
}
if (browser_ && browser_->GetHost()) {
if (NWebInputDelegate::IsMouseDown(action)) {
previous_action_ = action;
previous_button_ = buttonType;
#ifdef OHOS_CLIPBOARD
if (buttonType == MBT_LEFT) {
browser_->GetHost()->SetFocus(true);
}
#endif
browser_->GetHost()->SendMouseClickEvent(mouseEvent, buttonType, false,
count);
} else if (NWebInputDelegate::IsMouseUp(action)) {
previous_action_ = action;
previous_button_ = buttonType;
browser_->GetHost()->SendMouseClickEvent(mouseEvent, buttonType, true, 1);
if (!is_in_web_) {
browser_->GetHost()->SendMouseMoveEvent(mouseEvent, true);
}
} else if (NWebInputDelegate::IsMouseMove(action)) {
if (last_mouse_x_ == x && last_mouse_y_ == y) {
LOG(DEBUG) << "no change in coordinates, cancel mouse move event";
return;
}
last_mouse_x_ = x;
last_mouse_y_ = y;
browser_->GetHost()->SendMouseMoveEvent(mouseEvent, false);
} else if (NWebInputDelegate::IsMouseLeave(action)) {
browser_->GetHost()->SendMouseMoveEvent(mouseEvent, true);
} else {
LOG(DEBUG) << "mouse event action: " << action;
}
}
}
void NWebEventHandler::NotifyForNextTouchEvent() {
if (browser_ && browser_->GetHost()) {
browser_->GetHost()->NotifyForNextTouchEvent();
} else {
LOG(ERROR) << "NotifyForNextTouchEvent browser_ or host is nullptr, browser_: " << !browser_;
}
}
}