* 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_inputmethod_handler.h"
#include <codecvt>
#include "nweb_imf_cursor_info_adapter_impl.h"
#include "nweb_imf_input_attribute_adapter_impl.h"
#include "nweb_imf_selection_range_adapter_impl.h"
#include "nweb_imf_text_config_adapter_impl.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/functional/callback_helpers.h"
#include "base/logging.h"
#include "base/memory/raw_ptr.h"
#include "base/ohos/sys_info_utils.h"
#include "base/strings/utf_string_conversions.h"
#include "cef/include/cef_task.h"
#include "content/public/browser/browser_thread.h"
#include "libcef/browser/thread_util.h"
#include "ohos_glue/base/include/ark_web_errno.h"
#include "ohos_adapter_helper.h"
#include "res_sched_client_adapter.h"
#include "ui/events/keycodes/keyboard_codes_posix.h"
namespace OHOS::NWeb {
static constexpr char16_t DEL_CHAR = 127;
constexpr int32_t MAX_ENTERKEYTYPE = 8;
constexpr float AVOID_OFFSET = 24.0;
const std::string AUTO_FILL_CANCEL_PRIVATE_COMMAND = "autofill.cancel";
class OnTextChangedListenerImpl : public IMFTextListenerAdapter {
public:
OnTextChangedListenerImpl(NWebInputMethodHandler* handler)
: handler_(handler) {}
~OnTextChangedListenerImpl() = default;
void InsertText(const std::u16string& text) override {
if (text.size() == 1 && text.front() == '\n') {
return;
}
handler_->InsertText(text);
}
void DeleteForward(int32_t length) override {
handler_->DeleteForward(length);
}
void DeleteBackward(int32_t length) override {
handler_->DeleteBackward(length);
}
void SendKeyEventFromInputMethod() override {
LOG(INFO) << "NWebInputMethodHandler::SendKeyEventFromInputMethod";
}
void SendKeyboardStatus(const IMFAdapterKeyboardStatus& status) override {
if (status == IMFAdapterKeyboardStatus::SHOW) {
handler_->SetIMEStatus(true);
} else if (status == IMFAdapterKeyboardStatus::HIDE) {
handler_->SetIMEStatus(false);
}
}
void SendFunctionKey(
std::shared_ptr<IMFAdapterFunctionKeyAdapter> functionKey) override {
if (handler_ && functionKey) {
LOG(DEBUG) << "SendFunctionKey enterkeytype = "
<< static_cast<int32_t>(functionKey->GetEnterKeyType());
handler_->SendEnterKeyEvent(
static_cast<int32_t>(functionKey->GetEnterKeyType()));
}
}
void SetKeyboardStatus(bool status) override {
handler_->SetIMEStatus(status);
}
void KeyboardUpperRightCornerHide() override {
handler_->WebBlurKeyboardHide();
}
void MoveCursor(const IMFAdapterDirection direction) override {
if (direction == IMFAdapterDirection::NONE) {
LOG(ERROR) << "NWebInputMethodHandler::MoveCursor got none direction";
return;
}
handler_->MoveCursor(direction);
}
void HandleSetSelection(int32_t start, int32_t end) override {}
void HandleExtendAction(int32_t action) override {}
void HandleSelect(int32_t keyCode, int32_t cursorMoveSkip) override {}
int32_t GetTextIndexAtCursor() override {
return handler_->GetTextIndexAtCursor();
}
std::u16string GetLeftTextOfCursor(int32_t number) override {
return handler_->GetLeftTextOfCursor(number);
}
std::u16string GetRightTextOfCursor(int32_t number) override {
return handler_->GetRightTextOfCursor(number);
}
int32_t SetPreviewText(const std::u16string& text,
int32_t start,
int32_t end) override {
return handler_->SetPreviewText(text, start, end);
}
void FinishTextPreview() override { return handler_->FinishTextPreview(); }
void SetNeedUnderLine(bool is_need_underline) override {
handler_->SetNeedUnderLine(is_need_underline);
}
void AutoFillWithIMFEvent(bool is_username,
bool is_other_account,
bool is_new_password,
const std::string& content) override {
LOG(INFO) << "receive autofill event from IMF";
handler_->AutoFillWithIMFEvent(is_username, is_other_account,
is_new_password, content);
}
private:
raw_ptr<NWebInputMethodHandler> handler_;
};
class InputMethodTask : public CefTask {
public:
explicit InputMethodTask(base::OnceClosure closure)
: closure_(std::move(closure)) {}
InputMethodTask(const InputMethodTask&) = delete;
InputMethodTask& operator=(const InputMethodTask&) = delete;
virtual void Execute() override {
std::move(closure_).Run();
}
private:
base::OnceClosure closure_;
IMPLEMENT_REFCOUNTING(InputMethodTask);
};
NWebInputMethodHandler::NWebInputMethodHandler()
: selected_from_(0), selected_to_(0) {
inputmethod_adapter_ = OhosAdapterHelper::GetInstance().CreateIMFAdapter();
if (inputmethod_adapter_ == nullptr) {
LOG(ERROR) << "inputmethod_adapter_ create failed";
}
}
NWebInputMethodHandler::~NWebInputMethodHandler() {}
uint32_t NWebInputMethodHandler::lastAttachNWebId_ = 0;
IMFAdapterTextInputType NWebInputMethodHandler::lastInputMode_ =
IMFAdapterTextInputType::NONE;
std::shared_ptr<IMFCursorInfoAdapter> NWebInputMethodHandler::GetCursorInfo() {
std::shared_ptr<NWebIMFCursorInfoAdapterImpl> cursorInfo =
std::make_shared<NWebIMFCursorInfoAdapterImpl>();
double left =
(focus_rect_.x + focus_rect_.width) * device_pixel_ratio_ + offset_x_;
double top = focus_rect_.y * device_pixel_ratio_ + offset_y_;
double width = focus_rect_.width * device_pixel_ratio_;
double height = focus_rect_.height * device_pixel_ratio_;
cursorInfo->SetLeft(left);
cursorInfo->SetTop(top);
cursorInfo->SetWidth(width);
cursorInfo->SetHeight(height);
LOG(DEBUG) << "NWebInputMethodHandler::Attach cursorInfo.left = " << left
<< ", cursorInfo.top = " << top << ", cursorInfo.width = " << width
<< ", cursorInfo.height = " << height;
return cursorInfo;
}
IMFAdapterTextInputType NWebInputMethodHandler::TextInputModeToIMFAdapter(
cef_text_input_mode_t mode) {
switch (mode) {
case CEF_TEXT_INPUT_MODE_TEXT:
return IMFAdapterTextInputType::TEXT;
case CEF_TEXT_INPUT_MODE_TEL:
return IMFAdapterTextInputType::PHONE;
case CEF_TEXT_INPUT_MODE_URL:
return IMFAdapterTextInputType::URL;
case CEF_TEXT_INPUT_MODE_EMAIL:
return IMFAdapterTextInputType::EMAIL_ADDRESS;
case CEF_TEXT_INPUT_MODE_NUMERIC:
case CEF_TEXT_INPUT_MODE_DECIMAL:
return IMFAdapterTextInputType::NUMBER;
case CEF_TEXT_INPUT_MODE_SEARCH:
default:
type_text_flag_multi_line_ = true;
return IMFAdapterTextInputType::TEXT;
}
}
IMFAdapterTextInputType NWebInputMethodHandler::TextInputTypeToIMFAdapter(
cef_text_input_type_t type) {
switch (type) {
case CEF_TEXT_INPUT_TYPE_TEXT:
return IMFAdapterTextInputType::TEXT;
case CEF_TEXT_INPUT_TYPE_PASSWORD:
return IMFAdapterTextInputType::VISIBLE_PASSWORD;
case CEF_TEXT_INPUT_TYPE_EMAIL:
return IMFAdapterTextInputType::EMAIL_ADDRESS;
case CEF_TEXT_INPUT_TYPE_NUMBER:
return IMFAdapterTextInputType::NUMBER;
case CEF_TEXT_INPUT_TYPE_TELEPHONE:
return IMFAdapterTextInputType::PHONE;
case CEF_TEXT_INPUT_TYPE_URL:
return IMFAdapterTextInputType::URL;
case CEF_TEXT_INPUT_TYPE_TEXT_AREA:
case CEF_TEXT_INPUT_TYPE_CONTENT_EDITABLE:
type_text_flag_multi_line_ = true;
return IMFAdapterTextInputType::TEXT;
default:
return IMFAdapterTextInputType::TEXT;
}
}
IMFAdapterEnterKeyType NWebInputMethodHandler::TextInputActionToIMFAdapter(
InputInfo inputInfo) {
if (inputInfo.input_action == CEF_TEXT_INPUT_ACTION_DEFAULT) {
if (inputInfo.input_mode == CEF_TEXT_INPUT_MODE_DEFAULT &&
inputInfo.input_type == CEF_TEXT_INPUT_TYPE_SEARCH) {
LOG(DEBUG)
<< "The tag is not set with enterkeyhint. The type of the input box "
"is search, so the enterkeytype is set to SEARCH.";
return IMFAdapterEnterKeyType::SEARCH;
} else if (type_text_flag_multi_line_) {
LOG(DEBUG)
<< "The tag is not set with enterkeyhint. The input box supports "
"multiple lines of input, so the enterkeytype is set to NEW_LINE.";
return IMFAdapterEnterKeyType::NEW_LINE;
} else if (inputInfo.input_flags &
CEF_TEXT_INPUT_FLAG_HAVE_NEXT_FOCUSABLE_ELEMENT) {
LOG(DEBUG)
<< "The tag is not set with enterkeyhint. There is the next edit box "
"that can be focused on, so the enterkeytype is set to NEXT.";
if (!base::ohos::IsPcDevice()) {
return IMFAdapterEnterKeyType::NEXT;
}
return IMFAdapterEnterKeyType::GO;
} else {
LOG(DEBUG) << "The tag is not set with enterkeyhint. The above "
"situations are not met, so the enterkeytype is set to GO.";
return IMFAdapterEnterKeyType::GO;
}
} else {
switch (inputInfo.input_action) {
case CEF_TEXT_INPUT_ACTION_DEFAULT:
return IMFAdapterEnterKeyType::UNSPECIFIED;
case CEF_TEXT_INPUT_ACTION_ENTER:
LOG(DEBUG) << "Enterkeyhint is set to ENTER, therefore enterkeytype is "
"set to NEW_LINE.";
return IMFAdapterEnterKeyType::NEW_LINE;
case CEF_TEXT_INPUT_ACTION_DONE:
LOG(DEBUG) << "Enterkeyhint is set to DONE, therefore enterkeytype is "
"set to DONE.";
return IMFAdapterEnterKeyType::DONE;
case CEF_TEXT_INPUT_ACTION_GO:
LOG(DEBUG) << "Enterkeyhint is set to GO, therefore enterkeytype is "
"set to GO.";
return IMFAdapterEnterKeyType::GO;
case CEF_TEXT_INPUT_ACTION_NEXT:
LOG(DEBUG) << "Enterkeyhint is set to NEXT, therefore enterkeytype is "
"set to NEXT.";
return IMFAdapterEnterKeyType::NEXT;
case CEF_TEXT_INPUT_ACTION_PREVIOUS:
LOG(DEBUG) << "Enterkeyhint is set to PREVIOUS, therefore enterkeytype "
"is set to PREVIOUS.";
return IMFAdapterEnterKeyType::PREVIOUS;
case CEF_TEXT_INPUT_ACTION_SEARCH:
LOG(DEBUG) << "Enterkeyhint is set to SEARCH, therefore enterkeytype "
"is set to SEARCH.";
return IMFAdapterEnterKeyType::SEARCH;
case CEF_TEXT_INPUT_ACTION_SEND:
LOG(DEBUG) << "Enterkeyhint is set to SEND, therefore enterkeytype is "
"set to SEND.";
return IMFAdapterEnterKeyType::SEND;
default:
return IMFAdapterEnterKeyType::GO;
}
}
}
void NWebInputMethodHandler::ComputeEditorInfo(InputInfo inputInfo, int32_t customEnterKeyType) {
type_text_flag_multi_line_ = false;
show_keyboard_ = inputInfo.show_keyboard;
input_flags_ = inputInfo.input_flags;
input_node_id_ = inputInfo.node_id;
if (inputInfo.input_mode != CEF_TEXT_INPUT_MODE_DEFAULT &&
inputInfo.input_type != CEF_TEXT_INPUT_TYPE_PASSWORD) {
imf_input_mode_ = TextInputModeToIMFAdapter(inputInfo.input_mode);
} else {
imf_input_mode_ = TextInputTypeToIMFAdapter(inputInfo.input_type);
}
imf_input_action_ = static_cast<IMFAdapterEnterKeyType>(customEnterKeyType);
if (customEnterKeyType < 0 || customEnterKeyType > MAX_ENTERKEYTYPE) {
imf_input_action_ = TextInputActionToIMFAdapter(inputInfo);
}
}
bool NWebInputMethodHandler::AttachToSystemIME(bool is_need_reset_listener, int32_t requestKeyboardReason) {
if (inputmethod_adapter_ == nullptr) {
LOG(ERROR) << "inputmethod_adapter_ is nullptr";
return false;
}
if (!focus_status_) {
LOG(INFO) << "Do not attach the IME in the unfocused status, will reattach "
"after focused";
isNeedReattachOnfocus_ = true;
return false;
}
if (inputmethod_listener_ == nullptr) {
inputmethod_listener_ = std::make_shared<OnTextChangedListenerImpl>(this);
}
std::shared_ptr<NWebIMFInputAttributeAdapterImpl> inputAttribute =
std::make_shared<NWebIMFInputAttributeAdapterImpl>();
inputAttribute->SetInputPattern(static_cast<int32_t>(imf_input_mode_));
inputAttribute->SetEnterKeyType(static_cast<int32_t>(imf_input_action_));
std::shared_ptr<IMFCursorInfoAdapter> cursorInfo = GetCursorInfo();
std::shared_ptr<NWebIMFTextConfigAdapterImpl> textConfig =
std::make_shared<NWebIMFTextConfigAdapterImpl>();
textConfig->SetInputAttribute(inputAttribute);
textConfig->SetCursorInfo(cursorInfo);
textConfig->SetWindowId(windowId_);
textConfig->SetPositionY(offset_y_);
textConfig->SetHeight((focus_rect_.y + focus_rect_.height + AVOID_OFFSET) *
device_pixel_ratio_);
bool show_keyboard = show_keyboard_ && (!isManualCloseKeyboard_);
isAttachSuccess_ = inputmethod_adapter_->AttachWithRequestKeyboardReason(
inputmethod_listener_, show_keyboard, textConfig, is_need_reset_listener,
requestKeyboardReason);
if (ArkWebGetErrno() != ArkWebInterfaceResult::RESULT_OK) {
isAttachSuccess_ = inputmethod_adapter_->Attach(inputmethod_listener_, show_keyboard,
textConfig, is_need_reset_listener);
}
if (!isAttachSuccess_) {
LOG(ERROR) << "inputmethod_adapter_ attach failed";
return false;
}
#if defined(OHOS_PASSWORD_AUTOFILL)
if (!fill_content_.empty()) {
if (fill_content_node_id_ == input_node_id_) {
LOG(INFO) << "send autofill cancel fill content to IMF";
inputmethod_adapter_->SendPrivateCommand(AUTO_FILL_CANCEL_PRIVATE_COMMAND,
fill_content_);
}
fill_content_.clear();
}
#endif
return true;
}
void NWebInputMethodHandler::Attach(CefRefPtr<CefBrowser> browser,
InputInfo inputInfo,
bool is_need_reset_listener,
int32_t enterKeyType) {
LOG(INFO) << "NWebInputMethodHandler::Attach";
int32_t requestKeyboardReasonNone = 0;
Attach(browser, inputInfo, is_need_reset_listener, enterKeyType, requestKeyboardReasonNone);
}
void NWebInputMethodHandler::Attach(CefRefPtr<CefBrowser> browser,
InputInfo inputInfo,
bool is_need_reset_listener,
int32_t enterKeyType, int32_t requestKeyboardReason) {
LOG(INFO) << "NWebInputMethodHandler::Attach";
ComputeEditorInfo(inputInfo, enterKeyType);
composing_text_.clear();
browser_ = browser;
isManualCloseKeyboard_ = false;
if (!AttachToSystemIME(is_need_reset_listener, requestKeyboardReason)) {
return;
}
isAttached_ = true;
lastAttachNWebId_ = nweb_id_;
lastInputMode_ = imf_input_mode_;
if (focus_status_ && focus_rect_status_) {
if (inputmethod_adapter_) {
inputmethod_adapter_->OnCursorUpdate(GetCursorInfo());
}
}
}
bool NWebInputMethodHandler::Reattach(uint32_t nwebId, ReattachType type) {
nweb_id_ = nwebId;
if (type == ReattachType::FROM_CONTINUE) {
if (!isNeedReattachOncontinue_ || !is_editable_node_) {
LOG(INFO) << "don't need reattach input method";
return false;
}
isNeedReattachOncontinue_ = false;
}
if (type == ReattachType::FROM_ONFOCUS) {
if (!isNeedReattachOnfocus_ || !is_editable_node_) {
LOG(INFO) << "ReAttchOnfocus, don't need reattach input method";
return false;
}
isNeedReattachOnfocus_ = false;
}
LOG(INFO) << "Trigger reattach, nwebId=" << nwebId << ", source="
<< (type == ReattachType::FROM_ONFOCUS ? "focus" : "continue");
composing_text_.clear();
ClearComposingStatus();
if (!show_keyboard_ && isAttached_ && imf_input_mode_ != lastInputMode_) {
LOG(ERROR) << "do not need attach";
inputmethod_adapter_->Close();
}
if (!AttachToSystemIME(false)) {
return false;
}
isAttached_ = true;
lastAttachNWebId_ = nwebId;
lastInputMode_ = imf_input_mode_;
return show_keyboard_;
}
void NWebInputMethodHandler::ShowTextInput() {
LOG(INFO) << "NWebInputMethodHandler::ShowTextInput";
}
void NWebInputMethodHandler::SetNeedReattach(HideTextinputType hideType) {
if (hideType == HideTextinputType::FROM_ONPAUSE) {
isNeedReattachOncontinue_ = true;
}
if (hideType == HideTextinputType::FROM_ONBLUR) {
isNeedReattachOnfocus_ = true;
}
}
void NWebInputMethodHandler::HideTextInput(uint32_t nwebId,
HideTextinputType hideType,
bool noNeedKeyboardByInput) {
LOG(INFO) << "NWebInputMethodHandler::HideTextInput, isAttached_: " << isAttached_;
ClearComposingStatus();
if (inputmethod_adapter_ == nullptr) {
LOG(ERROR) << "inputmethod_adapter_ is nullptr";
return;
}
if (!isAttached_) {
if (!isAttachSuccess_) {
SetNeedReattach(hideType);
LOG(INFO) << "HideTextInput is triggered after an attach failure, "
"need to reattach next time.";
}
if (noNeedKeyboardByInput) {
LOG(INFO) << "inputMode is None, no need keyboard.";
inputmethod_adapter_->HideTextInput();
inputmethod_adapter_->Close();
return;
}
if (hideType != HideTextinputType::FROM_ONPAUSE) {
LOG(INFO) << "not from switch front and background, ingnore";
return;
}
auto nowTime = std::chrono::high_resolution_clock::now();
std::chrono::duration<double, std::milli> diff =
std::chrono::duration_cast<std::chrono::milliseconds>(
nowTime - lastCloseInputMethodTime_);
if (diff.count() < 100) {
isNeedReattachOncontinue_ = true;
LOG(INFO) << "set isNeedReattachOncontinue_ flag, diff = " << diff.count()
<< "ms";
}
return;
}
if (lastAttachNWebId_ == 0 || lastAttachNWebId_ == nwebId ||
hideType == HideTextinputType::FROM_KERNEL) {
LOG(INFO) << "need to hide text input, hidetype = "
<< static_cast<int>(hideType);
inputmethod_adapter_->HideTextInput();
inputmethod_adapter_->Close();
}
lastCloseInputMethodTime_ = std::chrono::high_resolution_clock::now();
isAttached_ = false;
SetNeedReattach(hideType);
}
void NWebInputMethodHandler::HideTextInputForce() {
LOG(INFO) << "NWebInputMethodHandler::HideTextInputForce";
if (inputmethod_adapter_ == nullptr) {
LOG(ERROR) << "inputmethod_adapter_ is nullptr";
return;
}
inputmethod_adapter_->HideTextInput();
inputmethod_adapter_->Close();
}
void NWebInputMethodHandler::OnTextSelectionChanged(
CefRefPtr<CefBrowser> browser,
const CefString& selected_text,
const CefRange& selected_range) {
selected_text_ = selected_text.ToString16();
}
void NWebInputMethodHandler::OnCursorUpdate(const CefRect& rect) {
focus_rect_ = rect;
focus_rect_status_ = true;
if (focus_status_) {
std::shared_ptr<NWebIMFCursorInfoAdapterImpl> cursorInfo =
std::make_shared<NWebIMFCursorInfoAdapterImpl>();
double left = (rect.x + rect.width) * device_pixel_ratio_ + offset_x_;
double top = rect.y * device_pixel_ratio_ + offset_y_;
double width = rect.width * device_pixel_ratio_;
double height = rect.height * device_pixel_ratio_;
cursorInfo->SetLeft(left);
cursorInfo->SetTop(top);
cursorInfo->SetWidth(width);
cursorInfo->SetHeight(height);
LOG(DEBUG) << "NWebInputMethodHandler::OnCursorUpdate cursorInfo.left = "
<< left << ", cursorInfo.top = " << top
<< ", cursorInfo.width = " << width
<< ", cursorInfo.height = " << height;
if (inputmethod_adapter_) {
inputmethod_adapter_->OnCursorUpdate(cursorInfo);
}
}
}
void NWebInputMethodHandler::OnSelectionChanged(
CefRefPtr<CefBrowser> browser,
const CefString& text,
const CefRange& selected_range) {
LOG(DEBUG) << "NWebInputMethodHandler::OnSelectionChanged";
}
void NWebInputMethodHandler::OnImeCompositionRangeChanged(
CefRefPtr<CefBrowser> browser,
const CefRange& selected_range) {
LOG(DEBUG) << "NWebInputMethodHandler::OnImeCompositionRangeChanged"
<< selected_range.from << ", to: " << selected_range.to;
}
bool NWebInputMethodHandler::IsTextInputStateChange(
const CefString& text,
const CefRange& selected_range,
const CefRange& compositon_range) {
if (whole_text_ != text) {
return true;
}
if ((selected_range.from != selected_from_) ||
(selected_range.to != selected_to_)) {
return true;
}
if ((compositon_range.from != composition_range_start_) ||
(compositon_range.to != composition_range_end_)) {
return true;
}
return false;
}
void NWebInputMethodHandler::OnUpdateTextInputStateCalled(
CefRefPtr<CefBrowser> browser,
const CefString& text,
const CefRange& selected_range,
const CefRange& compositon_range) {
bool is_state_change =
IsTextInputStateChange(text, selected_range, compositon_range);
if (!is_state_change) {
LOG(DEBUG) << "NWebInputMethodHandler::OnUpdateTextInputStateCalled state "
"is not changed";
return;
}
LOG(DEBUG)
<< "NWebInputMethodHandler::OnUpdateTextInputStateCalled text_length = "
<< text.ToString16().length()
<< ", selected_range start = " << selected_range.from
<< ", to = " << selected_range.to
<< ", compositon_range start = " << compositon_range.from
<< ", to = " << compositon_range.to;
if (compositon_range == CefRange::InvalidRange()) {
has_composition_ = false;
composition_range_start_ = 0;
composition_range_end_ = 0;
preview_text_cache_ = u"";
} else {
has_composition_ = true;
composition_range_start_ = compositon_range.from;
composition_range_end_ = compositon_range.to;
int32_t preview_length = composition_range_end_ - composition_range_start_;
if (!text.ToString16().empty() &&
(composition_range_end_ <= text.ToString16().length())) {
preview_text_cache_ =
text.ToString16().substr(composition_range_start_, preview_length);
}
}
LOG(DEBUG) << "NWebInputMethodHandler::OnUpdateTextInputStateCalled";
selected_from_ = selected_range.from;
selected_to_ = selected_range.to;
if (inputmethod_adapter_) {
inputmethod_adapter_->OnSelectionChange(text.ToString16(), selected_from_,
selected_to_);
}
{
std::unique_lock<std::mutex> lock(textCursorMutex_);
whole_text_ = text;
textCursorReady_ = 0;
textCursorCv_.notify_all();
}
}
void NWebInputMethodHandler::SetIMEStatus(bool status) {
if (browser_ != nullptr && browser_->GetHost() != nullptr) {
CefRefPtr<CefTask> insert_task = new InputMethodTask(base::BindOnce(
&NWebInputMethodHandler::SetIMEStatusOnUI, this, std::move(status)));
browser_->GetHost()->PostTaskToUIThread(insert_task);
}
}
void NWebInputMethodHandler::WebBlurKeyboardHide() {
if (browser_ != nullptr && browser_->GetHost() != nullptr) {
CefRefPtr<CefTask> task = new InputMethodTask(base::BindOnce(
&NWebInputMethodHandler::WebBlurKeyboardHideOnUI, this));
browser_->GetHost()->PostTaskToUIThread(task);
}
}
void NWebInputMethodHandler::InsertText(const std::u16string& text) {
if (text.empty()) {
LOG(ERROR) << "insert text empty!";
return;
}
if (browser_ != nullptr && browser_->GetHost() != nullptr) {
CefRefPtr<CefTask> insert_task = new InputMethodTask(base::BindOnce(
&NWebInputMethodHandler::InsertTextHandlerOnUI, this, std::move(text)));
browser_->GetHost()->PostTaskToUIThread(insert_task);
}
}
void NWebInputMethodHandler::DeleteBackward(int32_t length) {
if (browser_ != nullptr && browser_->GetHost() != nullptr) {
CefRefPtr<CefTask> delete_task = new InputMethodTask(base::BindOnce(
&NWebInputMethodHandler::DeleteBackwardHandlerOnUI, this, length));
browser_->GetHost()->PostTaskToUIThread(delete_task);
}
}
void NWebInputMethodHandler::DeleteForward(int32_t length) {
if (browser_ != nullptr && browser_->GetHost() != nullptr) {
CefRefPtr<CefTask> delete_task = new InputMethodTask(base::BindOnce(
&NWebInputMethodHandler::DeleteForwardHandlerOnUI, this, length));
browser_->GetHost()->PostTaskToUIThread(delete_task);
}
}
void NWebInputMethodHandler::SetIMEStatusOnUI(bool status) {
LOG(INFO) << "NWebInputMethodHandler::SetIMEStatusOnUI status:" << status;
if (!status && ime_text_composing_) {
browser_->GetHost()->ImeFinishComposingText(false);
ime_text_composing_ = false;
composing_text_.clear();
}
if (status) {
isManualCloseKeyboard_ = false;
}
ime_shown_ = status;
}
void NWebInputMethodHandler::WebBlurKeyboardHideOnUI() {
LOG(INFO) << "NWebInputMethodHandler::WebBlurKeyboardHideOnUI" ;
isManualCloseKeyboard_ = true;
browser_->GetHost()->SetFocusOnWeb();
}
void NWebInputMethodHandler::InsertTextHandlerOnUI(const std::u16string& text) {
LOG(INFO) << "NWebInputMethodHandler::InsertTextHandlerOnUI text length:" << text.length();
if (text.empty()) {
LOG(ERROR) << "insert text empty!";
return;
}
{
std::unique_lock<std::mutex> lock(textCursorMutex_);
textCursorReady_++;
}
CefKeyEvent keyEvent;
keyEvent.windows_key_code = ui::VKEY_PROCESSKEY;
if (base::ohos::IsPcDevice() && text.length() == 1) {
char16_t firstChar = text[0];
if (keycode_map.count(firstChar) > 0) {
keyEvent.windows_key_code = keycode_map[firstChar];
}
}
keyEvent.modifiers = 0;
keyEvent.is_system_key = false;
keyEvent.type = KEYEVENT_RAWKEYDOWN;
browser_->GetHost()->SendKeyEvent(keyEvent);
if (!ime_text_composing_) {
ime_text_composing_ = true;
composing_text_.clear();
}
composing_text_.append(text);
browser_->GetHost()->ImeCommitText(composing_text_,
CefRange(UINT32_MAX, UINT32_MAX), 0);
if (text.length() > 1) {
ResSchedClientAdapter::ReportScene(ResSchedStatusAdapter::WEB_SCENE_ENTER,
ResSchedSceneAdapter::CLICK);
}
ime_text_composing_ = false;
composing_text_.clear();
LOG(DEBUG) << "NWebInputMethodHandler::InsertTextHandlerOnUI selected_from_ "
<< selected_from_;
keyEvent.type = KEYEVENT_KEYUP;
browser_->GetHost()->SendKeyEvent(keyEvent);
ClearComposingStatus();
}
void NWebInputMethodHandler::ClearComposingStatus() {
has_composition_ = false;
preview_text_cache_ = u"";
composition_range_start_ = 0;
composition_range_end_ = 0;
}
void NWebInputMethodHandler::PreviewTextHandlerOnUI(const std::u16string& text,
int32_t start,
int32_t end) {
LOG(DEBUG) << "NWebInputMethodHandler start " << start << ", end " << end;
{
std::unique_lock<std::mutex> lock(textCursorMutex_);
textCursorReady_++;
}
LOG(DEBUG) << "NWebInputMethodHandler::preview_text_cache_ After composition_range_start_ "
<< composition_range_start_ << ", composition_range_end_ " << composition_range_end_;
std::vector<CefCompositionUnderline> underlines;
CefCompositionUnderline underline;
underline.range.from = 0;
underline.range.to = text.length();
if (is_need_underline_) {
underline.style = CEF_CUS_SOLID;
} else {
underline.style = CEF_CUS_NONE;
}
underlines.push_back(underline);
CefRange replace_range = CefRange::InvalidRange();
if (composition_type_ == COMPOSITION_REPLACE) {
replace_range.Set(start, end);
}
CefRange selection_range(composition_cursor_index_,
composition_cursor_index_);
LOG(DEBUG) << "NWebInputMethodHandler::underline style: " << underline.style
<< ", from: " << underline.range.from
<< ", to: " << underline.range.to;
LOG(DEBUG) << "NWebInputMethodHandler::replace_range from "
<< replace_range.from << ", to " << replace_range.to;
LOG(DEBUG) << "NWebInputMethodHandler::selection_range from "
<< selection_range.from << ", to " << selection_range.to;
browser_->GetHost()->ImeSetComposition(text, underlines, replace_range,
selection_range);
}
void NWebInputMethodHandler::CancelPreviewHandlerOnUI() {
if (browser_ != nullptr && browser_->GetHost() != nullptr) {
LOG(DEBUG) << "NWebInputMethodHandler::CancelPreviewHandlerOnUI";
browser_->GetHost()->ImeCancelComposition();
ClearComposingStatus();
}
}
void NWebInputMethodHandler::FinishPreviewTextOnUI() {
if (browser_ != nullptr && browser_->GetHost() != nullptr) {
LOG(DEBUG) << "NWebInputMethodHandler::FinishPreviewTextOnUI";
browser_->GetHost()->ImeFinishComposingText(false);
ClearComposingStatus();
}
}
void NWebInputMethodHandler::SetNeedUnderLineOnUI(bool is_need_underline) {
LOG(DEBUG) << "NWebInputMethodHandler::SetNeedUnderLine "
<< is_need_underline;
is_need_underline_ = is_need_underline;
}
void NWebInputMethodHandler::DeleteForwardHandlerOnUI(int32_t length) {
CefKeyEvent keyEvent;
keyEvent.windows_key_code = ui::VKEY_DELETE;
keyEvent.native_key_code = static_cast<int>(ScanKeyCode::DELETE_SCAN_CODE);
keyEvent.modifiers = 0;
keyEvent.is_system_key = false;
keyEvent.character = keyEvent.unmodified_character = DEL_CHAR;
LOG(INFO) << "NWebInputMethodHandler::DeleteForwardHandlerOnUI length=" << length;
if (!browser_ || !browser_->GetHost()) {
LOG(ERROR) << "delete backward browser get failed";
return;
}
is_need_notify_all_ = false;
text_cursor_length_ = length;
selected_from_ = selected_from_ >= whole_text_.size() ? whole_text_.size()
: selected_from_;
LOG(DEBUG)
<< "NWebInputMethodHandler::DeleteForwardHandlerOnUI selected_from_ "
<< selected_from_;
if (whole_text_.substr(selected_from_).size() <= length) {
text_cursor_length_ = whole_text_.substr(selected_from_).size();
if (selected_from_ == 0) {
is_need_notify_all_ = true;
}
} else {
std::unique_lock<std::mutex> lock(textCursorMutex_);
textCursorReady_ += text_cursor_length_;
}
for (int32_t i = 0; i < length; i++) {
keyEvent.type = KEYEVENT_RAWKEYDOWN;
browser_->GetHost()->SendKeyEvent(keyEvent);
keyEvent.type = KEYEVENT_CHAR;
browser_->GetHost()->SendKeyEvent(keyEvent);
}
keyEvent.type = KEYEVENT_KEYUP;
browser_->GetHost()->SendKeyEvent(keyEvent);
if (preview_text_cache_.length() == 1) {
ClearComposingStatus();
}
}
void NWebInputMethodHandler::DeleteBackwardHandlerOnUI(int32_t length) {
CefKeyEvent keyEvent;
keyEvent.windows_key_code = ui::VKEY_BACK;
keyEvent.native_key_code = static_cast<int>(ScanKeyCode::BACKSPACE_SCAN_CODE);
keyEvent.modifiers = 0;
keyEvent.is_system_key = false;
keyEvent.character = keyEvent.unmodified_character = DEL_CHAR;
LOG(INFO) << "NWebInputMethodHandler::DeleteBackwardHandlerOnUI length=" << length;
if (!browser_ || !browser_->GetHost()) {
LOG(ERROR) << "delete forward browser get failed";
return;
}
text_cursor_length_ = length;
if (selected_from_ <= length) {
text_cursor_length_ = selected_from_;
} else {
std::unique_lock<std::mutex> lock(textCursorMutex_);
textCursorReady_ += text_cursor_length_;
}
for (int32_t i = 0; i < length; i++) {
keyEvent.type = KEYEVENT_RAWKEYDOWN;
browser_->GetHost()->SendKeyEvent(keyEvent);
keyEvent.type = KEYEVENT_CHAR;
browser_->GetHost()->SendKeyEvent(keyEvent);
}
keyEvent.type = KEYEVENT_KEYUP;
browser_->GetHost()->SendKeyEvent(keyEvent);
if (preview_text_cache_.length() == 1) {
ClearComposingStatus();
}
}
void NWebInputMethodHandler::SendEnterKeyEvent(int32_t enterKeyType) {
if (browser_ != nullptr && browser_->GetHost() != nullptr) {
CefRefPtr<CefTask> sendEnterKeyEvent_task = new InputMethodTask(base::BindOnce(
&NWebInputMethodHandler::SendEnterKeyEventOnUI, this, std::move(enterKeyType)));
browser_->GetHost()->PostTaskToUIThread(sendEnterKeyEvent_task);
}
}
void NWebInputMethodHandler::SendEnterKeyEventOnUI(int32_t enterKeyType) {
if (!browser_ || !browser_->GetHost()) {
LOG(ERROR) << "NWebInputMethodHandler send enter key failed, browser_ is nullptr!";
return;
}
if (!base::ohos::IsPcDevice()) {
if (enterKeyType == static_cast<int32_t>(IMFAdapterEnterKeyType::NEXT) &&
input_flags_ & CEF_TEXT_INPUT_FLAG_HAVE_NEXT_FOCUSABLE_ELEMENT) {
LOG(DEBUG) << "NWebInputMethodHandler::SendEnterKeyEvent "
"IMFAdapterEnterKeyType::NEXT";
browser_->GetHost()->AdvanceFocusForIME(
static_cast<int>(FocusType::FORWARD));
return;
} else if (enterKeyType ==
static_cast<int32_t>(IMFAdapterEnterKeyType::PREVIOUS) &&
input_flags_ &
CEF_TEXT_INPUT_FLAG_HAVE_PREVIOUS_FOCUSABLE_ELEMENT) {
LOG(DEBUG) << "NWebInputMethodHandler::SendEnterKeyEvent "
"IMFAdapterEnterKeyType::PREVIOUS";
browser_->GetHost()->AdvanceFocusForIME(
static_cast<int>(FocusType::BACKWARD));
return;
}
}
CefKeyEvent keyEvent;
keyEvent.windows_key_code = ui::VKEY_RETURN;
keyEvent.native_key_code = static_cast<int>(ScanKeyCode::ENTER_SCAN_CODE);
LOG(DEBUG) << "NWebInputMethodHandler::SendEnterKeyEvent";
keyEvent.type = KEYEVENT_KEYDOWN;
keyEvent.character = '\r';
keyEvent.modifiers = 0;
keyEvent.is_system_key = false;
browser_->GetHost()->SendKeyEvent(keyEvent);
keyEvent.type = KEYEVENT_CHAR;
browser_->GetHost()->SendKeyEvent(keyEvent);
keyEvent.type = KEYEVENT_KEYUP;
browser_->GetHost()->SendKeyEvent(keyEvent);
}
void NWebInputMethodHandler::MoveCursor(const IMFAdapterDirection direction) {
LOG(INFO) << "NWebInputMethodHandler::MoveCursor called";
CefKeyEvent keyEvent;
switch (direction) {
case IMFAdapterDirection::UP: {
keyEvent.windows_key_code = ui::VKEY_UP;
keyEvent.native_key_code = static_cast<int>(ScanKeyCode::UP_SCAN_CODE);
break;
}
case IMFAdapterDirection::LEFT: {
keyEvent.windows_key_code = ui::VKEY_LEFT;
keyEvent.native_key_code = static_cast<int>(ScanKeyCode::LEFT_SCAN_CODE);
break;
}
case IMFAdapterDirection::RIGHT: {
keyEvent.windows_key_code = ui::VKEY_RIGHT;
keyEvent.native_key_code = static_cast<int>(ScanKeyCode::RIGHT_SCAN_CODE);
break;
}
case IMFAdapterDirection::DOWN: {
keyEvent.windows_key_code = ui::VKEY_DOWN;
keyEvent.native_key_code = static_cast<int>(ScanKeyCode::DOWN_SCAN_CODE);
break;
}
default: {
LOG(ERROR) << "invalid direction";
return;
}
}
{
std::unique_lock<std::mutex> lock(textCursorMutex_);
textCursorReady_++;
}
keyEvent.type = KEYEVENT_KEYDOWN;
keyEvent.modifiers = 0;
keyEvent.is_system_key = false;
if (browser_ && browser_->GetHost()) {
browser_->GetHost()->SendKeyEvent(keyEvent);
}
keyEvent.type = KEYEVENT_KEYUP;
if (browser_ && browser_->GetHost()) {
browser_->GetHost()->SendKeyEvent(keyEvent);
}
}
void NWebInputMethodHandler::SetScreenOffSet(double x, double y) {
if (focus_status_) {
if (focus_rect_status_ && (offset_x_ != x || offset_y_ != y)) {
std::shared_ptr<NWebIMFCursorInfoAdapterImpl> cursorInfo =
std::make_shared<NWebIMFCursorInfoAdapterImpl>();
double left =
(focus_rect_.x + focus_rect_.width) * device_pixel_ratio_ + x;
double top = focus_rect_.y * device_pixel_ratio_ + y;
double width = focus_rect_.width * device_pixel_ratio_;
double height = focus_rect_.height * device_pixel_ratio_;
cursorInfo->SetLeft(left);
cursorInfo->SetTop(top);
cursorInfo->SetWidth(width);
cursorInfo->SetHeight(height);
LOG(DEBUG) << "NWebInputMethodHandler::SetScreenOffSet cursorInfo.left = "
<< left << ", cursorInfo.top = " << top
<< ", cursorInfo.width = " << width
<< ", cursorInfo.height = " << height;
if (inputmethod_adapter_) {
inputmethod_adapter_->OnCursorUpdate(cursorInfo);
}
}
}
offset_x_ = x;
offset_y_ = y;
}
void NWebInputMethodHandler::SetVirtualDeviceRatio(float device_pixel_ratio) {
device_pixel_ratio_ = device_pixel_ratio;
}
void NWebInputMethodHandler::SetFocusStatus(bool focus_status) {
if (focus_status && focus_rect_status_) {
std::shared_ptr<NWebIMFCursorInfoAdapterImpl> cursorInfo =
std::make_shared<NWebIMFCursorInfoAdapterImpl>();
double left =
(focus_rect_.x + focus_rect_.width) * device_pixel_ratio_ + offset_x_;
double top = focus_rect_.y * device_pixel_ratio_ + offset_y_;
double width = focus_rect_.width * device_pixel_ratio_;
double height = focus_rect_.height * device_pixel_ratio_;
cursorInfo->SetLeft(left);
cursorInfo->SetTop(top);
cursorInfo->SetWidth(width);
cursorInfo->SetHeight(height);
LOG(DEBUG) << "NWebInputMethodHandler::SetFocusStatus cursorInfo.left = "
<< left << ", cursorInfo.top = " << top << ", width = " << width
<< ", height = " << height;
if (inputmethod_adapter_) {
inputmethod_adapter_->OnCursorUpdate(cursorInfo);
}
}
focus_status_ = focus_status;
}
void NWebInputMethodHandler::OnEditableChanged(CefRefPtr<CefBrowser> browser,
bool is_editable_node) {
is_editable_node_ = is_editable_node;
}
bool NWebInputMethodHandler::GetIsEditableNode() {
LOG(INFO) << "NWebInputMethodHandler is_editable_node_ = "
<< is_editable_node_;
return is_editable_node_;
}
bool NWebInputMethodHandler::HasComposition() {
LOG(INFO) << "NWebInputMethodHandler HasComposition = " << has_composition_;
return has_composition_;
}
int32_t NWebInputMethodHandler::GetTextIndexAtCursor() {
std::unique_lock<std::mutex> lock(textCursorMutex_);
bool istextCursorReady =
textCursorCv_.wait_for(lock, std::chrono::milliseconds(50),
[this] { return textCursorReady_ == 0; });
textCursorReady_ = 0;
if (!istextCursorReady) {
LOG(ERROR) << "GetTextIndexAtCursor wait_for timeout";
if (ResetTextSelectiondata()) {
return 0;
}
}
LOG(DEBUG) << "NWebInputMethodHandler::GetTextIndexAtCursor selected_to_ "
<< selected_to_;
return selected_to_;
}
std::u16string NWebInputMethodHandler::GetLeftTextOfCursor(int32_t number) {
std::unique_lock<std::mutex> lock(textCursorMutex_);
bool istextCursorReady =
textCursorCv_.wait_for(lock, std::chrono::milliseconds(50),
[this] { return textCursorReady_ == 0; });
textCursorReady_ = 0;
if (!istextCursorReady) {
LOG(ERROR) << "GetLeftTextOfCursor wait_for timeout";
if (ResetTextSelectiondata()) {
return u"";
}
}
int32_t selectBegin = selected_from_;
int32_t selectEnd = selected_to_;
if (!IsCorrectParam(number, selectBegin, selectEnd)) {
return u"";
}
int32_t startPos = (number <= selectBegin ? (selectBegin - number) : 0);
int32_t length = (number <= selectBegin ? number : selectBegin);
return whole_text_.substr(startPos, length);
}
std::u16string NWebInputMethodHandler::GetRightTextOfCursor(int32_t number) {
std::unique_lock<std::mutex> lock(textCursorMutex_);
bool istextCursorReady =
textCursorCv_.wait_for(lock, std::chrono::milliseconds(50),
[this] { return textCursorReady_ == 0; });
textCursorReady_ = 0;
if (!istextCursorReady) {
LOG(ERROR) << "GetRightTextOfCursor wait_for timeout";
if (ResetTextSelectiondata()) {
return u"";
}
}
int32_t selectBegin = selected_from_;
int32_t selectEnd = selected_to_;
if (!IsCorrectParam(number, selectBegin, selectEnd)) {
return u"";
}
return whole_text_.substr(selectEnd, number);
}
int32_t NWebInputMethodHandler::GetCompositionTypeAndCheckInput(
const std::u16string& text,
int32_t start,
int32_t end,
CompositionType& composition_type) {
bool is_empty = text.empty();
if (is_empty && !has_composition_) {
LOG(ERROR) << "set null preview text when has not composition";
composition_type = COMPOSITION_INVALID;
return ERROR;
}
CompositionType type;
if ((start == -1) && (end == -1)) {
if (is_empty) {
type = COMPOSITION_CANCEL;
} else {
type = COMPOSITION_CURRENT;
}
} else if (start == end) {
type = COMPOSITION_POSITION;
} else if (start < end) {
if (is_empty && (preview_text_cache_.length() == 1)) {
type = COMPOSITION_DELETE;
} else {
type = COMPOSITION_REPLACE;
}
} else {
type = COMPOSITION_INVALID;
}
composition_type = type;
switch (composition_type) {
case COMPOSITION_INVALID: {
LOG(ERROR) << "COMPOSITION_INVALID:";
return ERROR;
}
case COMPOSITION_POSITION:
case COMPOSITION_REPLACE: {
int32_t whole_text_length = whole_text_.length();
if (end > whole_text_length) {
LOG(ERROR) << "composition position is larger then current text length "
<< "end: " << end
<< ", whole_text_length: " << whole_text_length
<< ", preview_text_cache_ " << preview_text_cache_.length();
return ERROR;
}
if (has_composition_ && !((start >= composition_range_start_) &&
(end <= composition_range_end_))) {
LOG(ERROR)
<< "COMPOSITION_POSITION: start is invalid when has composition, "
<< "start: " << start << ", end: " << end
<< ", composition_range_start_: " << composition_range_start_
<< ", composition_range_end_: " << composition_range_end_;
return ERROR;
}
break;
}
default: {
LOG(INFO) << "no need check";
return OK;
}
}
return OK;
}
int32_t NWebInputMethodHandler::UpdateCompositionInfo(
const std::u16string& text,
int32_t start,
int32_t end) {
if (GetCompositionTypeAndCheckInput(text, start, end, composition_type_) !=
OK) {
LOG(ERROR) << "check in put failed";
return ERROR;
}
LOG(DEBUG) << "NWebInputMethodHandler::has_composition_ " << has_composition_;
LOG(DEBUG) << "NWebInputMethodHandler:: Before composition_range_start_ " << composition_range_start_
<< ", composition_range_end_ " << composition_range_end_;
switch (composition_type_) {
case COMPOSITION_INVALID: {
LOG(ERROR) << "COMPOSITION_INVALID:";
return ERROR;
}
case COMPOSITION_CANCEL:
case COMPOSITION_DELETE: {
LOG(ERROR) << "will handle later:";
break;
}
case COMPOSITION_CURRENT: {
preview_text_cache_ = text;
composition_cursor_index_ = text.length();
LOG(DEBUG) << "NWebInputMethodHandler::COMPOSITION_CURRENT: composition_range_start_ "
<< composition_range_start_ << ", composition_range_end_ " << composition_range_end_
<< ", composition_cursor_index_ " << composition_cursor_index_;
break;
}
case COMPOSITION_POSITION: {
int32_t insert_rel_position = 0;
if (has_composition_) {
insert_rel_position = start - composition_range_start_;
if (insert_rel_position < 0) {
LOG(ERROR) << "COMPOSITION_POSITION:insert_rel_position < 0";
return ERROR;
}
preview_text_cache_.insert(insert_rel_position, text);
composition_cursor_index_ = insert_rel_position + text.length();
LOG(DEBUG) << "NWebInputMethodHandler::COMPOSITION_POSITION: has_composition_ "
<< " composition_range_start_ " << composition_range_start_
<< ", composition_range_end_ " << composition_range_end_
<< ", composition_cursor_index_ " << composition_cursor_index_;
} else {
preview_text_cache_ = text;
composition_cursor_index_ = text.length();
LOG(DEBUG) << "NWebInputMethodHandler::COMPOSITION_POSITION: composition_range_start_ "
<< composition_range_start_ << ", composition_range_end_ " << composition_range_end_
<< ", composition_cursor_index_ " << composition_cursor_index_;
}
break;
}
case COMPOSITION_REPLACE: {
if (has_composition_) {
int replace_pos = start - composition_range_start_;
if (replace_pos < 0) {
LOG(ERROR) << "COMPOSITION_REPLACE:replace_pos < 0";
return ERROR;
}
int replace_length = end - start;
LOG(DEBUG) << "NWebInputMethodHandler::COMPOSITION_REPLACE "
<< ", replace_pos " << replace_pos << ", replace_length "
<< replace_length;
std::u16string replace_string =
preview_text_cache_.replace(replace_pos, replace_length, text);
preview_text_cache_ = replace_string;
composition_cursor_index_ = replace_pos + text.length();
} else {
preview_text_cache_ = text;
composition_cursor_index_ = text.length();
}
LOG(DEBUG)
<< "NWebInputMethodHandler::COMPOSITION_REPLACE: composition_range_start_ "
<< composition_range_start_ << ", composition_range_end_ "
<< composition_range_end_ << ", composition_cursor_index_ "
<< composition_cursor_index_;
break;
}
default: {
LOG(ERROR) << "invalid type:";
return ERROR;
}
}
has_composition_ = true;
return OK;
}
int32_t NWebInputMethodHandler::SetPreviewText(const std::u16string& text,
int32_t start,
int32_t end) {
LOG(DEBUG) << "NWebInputMethodHandler::SetPreviewText start: " << start << ", end: " << end;
if (UpdateCompositionInfo(std::move(text), start, end) != OK) {
LOG(ERROR) << "update composition info failed!";
return ERROR;
}
if (composition_type_ == COMPOSITION_CANCEL) {
LOG(DEBUG) << "NWebInputMethodHandler::COMPOSITION_CANCEL";
if (browser_ != nullptr && browser_->GetHost() != nullptr) {
CefRefPtr<CefTask> task = new InputMethodTask(base::BindOnce(
&NWebInputMethodHandler::CancelPreviewHandlerOnUI, this));
browser_->GetHost()->PostTaskToUIThread(task);
}
} else if (composition_type_ == COMPOSITION_DELETE) {
LOG(DEBUG) << "NWebInputMethodHandler::COMPOSITION_DELETE selected_from_ "
<< selected_from_;
if (start == selected_from_) {
DeleteForward(1);
}
else if (end == selected_from_) {
DeleteBackward(1);
}
} else {
if (browser_ != nullptr && browser_->GetHost() != nullptr) {
CefRefPtr<CefTask> task = new InputMethodTask(
base::BindOnce(&NWebInputMethodHandler::PreviewTextHandlerOnUI, this,
preview_text_cache_, start, end));
browser_->GetHost()->PostTaskToUIThread(task);
}
}
return OK;
}
void NWebInputMethodHandler::FinishTextPreview() {
if (browser_ != nullptr && browser_->GetHost() != nullptr) {
CefRefPtr<CefTask> task = new InputMethodTask(
base::BindOnce(&NWebInputMethodHandler::FinishPreviewTextOnUI, this));
browser_->GetHost()->PostTaskToUIThread(task);
}
}
void NWebInputMethodHandler::SetNeedUnderLine(bool is_need_underline) {
SetNeedUnderLineOnUI(is_need_underline);
}
#if defined(OHOS_PASSWORD_AUTOFILL)
void NWebInputMethodHandler::AutoFillWithIMFEvent(bool is_username,
bool is_other_account,
bool is_new_password,
const std::string& content) {
if (browser_ && browser_->GetHost()) {
CefRefPtr<CefTask> autofill_task = new InputMethodTask(base::BindOnce(
&NWebInputMethodHandler::AutoFillWithIMFEventOnUI, this, is_username,
is_other_account, is_new_password, std::move(content)));
browser_->GetHost()->PostTaskToUIThread(autofill_task);
}
}
void NWebInputMethodHandler::AutoFillWithIMFEventOnUI(
bool is_username,
bool is_other_account,
bool is_new_password,
const std::string& content) {
if (browser_ && browser_->GetHost()) {
browser_->GetHost()->AutoFillWithIMFEvent(is_username, is_other_account,
is_new_password, content);
}
}
#endif
#if defined(OHOS_CLIPBOARD)
std::string NWebInputMethodHandler::GetSelectInfo() {
std::string selected_str = base::UTF16ToUTF8(selected_text_);
return selected_str;
}
#endif
void NWebInputMethodHandler::SetWindowIdForIME(uint32_t windowId) {
LOG(INFO) << "NWebInputMethodHandler::SetWindowIdForIME windowId: "
<< windowId;
windowId_ = windowId;
}
bool NWebInputMethodHandler::IsCorrectParam(int32_t number,
int32_t& selectBegin,
int32_t& selectEnd) {
if (number < 0 || selectBegin < 0 || selectEnd < 0) {
LOG(ERROR) << "param error, number:" << number
<< ", selectBegin:" << selectBegin
<< ", selectEnd:" << selectEnd;
return false;
}
if (selectBegin > selectEnd) {
std::swap(selectBegin, selectEnd);
}
if (selectEnd > whole_text_.size()) {
LOG(ERROR) << "param error, end:" << selectEnd;
return false;
}
return true;
}
bool NWebInputMethodHandler::ResetTextSelectiondata() {
if (is_need_notify_all_) {
LOG(ERROR) << "NWebInputMethodHandler::ResetTextSelectiondata";
whole_text_ = u"";
selected_from_ = 0;
selected_to_ = 0;
textCursorReady_ = 0;
is_need_notify_all_ = false;
return true;
}
return false;
}
}