/* * Copyright (C) 2021-2023 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 "input_method_controller.h" #include #include #include "securec.h" #include "block_data.h" #include "global.h" #include "imc_hisysevent_reporter.h" #include "ime_event_monitor_manager_impl.h" #include "input_client_service_impl.h" #include "input_data_channel_service_impl.h" #include "input_method_agent_proxy.h" #include "input_method_property.h" #include "input_method_status.h" #include "input_method_system_ability_proxy.h" #include "inputmethod_sysevent.h" #include "inputmethod_trace.h" #include "iservice_registry.h" #include "keyevent_consumer_service_impl.h" #include "on_demand_start_stop_sa.h" #include "string_ex.h" #include "string_utils.h" #include "sys/prctl.h" #include "system_ability_definition.h" #include "system_cmd_channel_stub.h" #include "input_method_tools.h" #include "notify_service_impl.h" #include "on_input_stop_notify_proxy.h" namespace OHOS { namespace MiscServices { using namespace MessageID; using namespace std::chrono; sptr InputMethodController::instance_; std::shared_ptr InputMethodController::handler_ { nullptr }; std::mutex InputMethodController::instanceLock_; std::mutex InputMethodController::logLock_; int InputMethodController::keyEventCountInPeriod_ = 0; std::chrono::system_clock::time_point InputMethodController::startLogTime_ = system_clock::now(); constexpr int32_t LOOP_COUNT = 5; constexpr int32_t LOG_MAX_TIME = 20; constexpr int64_t DELAY_TIME = 100; constexpr int32_t ACE_DEAL_TIME_OUT = 200; constexpr int32_t MAX_PLACEHOLDER_SIZE = 255; // 256 utf16 char constexpr int32_t MAX_ABILITY_NAME_SIZE = 127; // 127 utf16 char static constexpr int32_t MAX_TIMEOUT = 2500; constexpr size_t MAX_AGENT_NUMBER = 2; const std::string IME_MIRROR_NAME = "proxyIme_IME_MIRROR"; InputMethodController::InputMethodController() { IMSA_HILOGD("IMC structure."); } InputMethodController::~InputMethodController() { } #ifdef OHOS_IMF_TEST void InputMethodController::SetImsaProxyForTest(sptr proxy) { std::lock_guard autoLock(abilityLock_); abilityManager_ = proxy; } #endif // OHOS_IMF_TEST sptr InputMethodController::GetInstance() { if (instance_ == nullptr) { std::lock_guard autoLock(instanceLock_); if (instance_ == nullptr) { IMSA_HILOGD("instance_ is nullptr."); instance_ = new (std::nothrow) InputMethodController(); if (instance_ == nullptr) { IMSA_HILOGE("failed to create InputMethodController!"); return instance_; } int32_t ret = instance_->Initialize(); if (ret != ErrorCode::NO_ERROR) { InputMethodSysEvent::GetInstance().InputmethodFaultReporter(ret, "", "IMC initialize failed!"); } } } return instance_; } int32_t InputMethodController::RestoreListenEventFlag() { auto proxy = GetSystemAbilityProxy(); if (proxy == nullptr) { IMSA_HILOGE("proxy is nullptr!"); return ErrorCode::ERROR_SERVICE_START_FAILED; } // 0 represent no need to check permission InputClientInfoInner infoInner = InputMethodTools::GetInstance().InputClientInfoToInner(clientInfo_); return proxy->UpdateListenEventFlag(infoInner, 0); } int32_t InputMethodController::UpdateListenEventFlag(uint32_t finalEventFlag, uint32_t eventFlag, bool isOn) { auto oldEventFlag = clientInfo_.eventFlag; clientInfo_.eventFlag = finalEventFlag; auto proxy = GetSystemAbilityProxy(); if (proxy == nullptr) { IMSA_HILOGE("proxy is nullptr!"); if (isOn) { clientInfo_.eventFlag = oldEventFlag; } return ErrorCode::ERROR_SERVICE_START_FAILED; } InputClientInfoInner infoInner = InputMethodTools::GetInstance().InputClientInfoToInner(clientInfo_); auto ret = proxy->UpdateListenEventFlag(infoInner, eventFlag); if (ret != ErrorCode::NO_ERROR && isOn) { clientInfo_.eventFlag = oldEventFlag; } return ret; } void InputMethodController::SetControllerListener(std::shared_ptr controllerListener) { IMSA_HILOGD("InputMethodController run in"); controllerListener_ = std::move(controllerListener); } int32_t InputMethodController::Initialize() { sptr client = new (std::nothrow) InputClientServiceImpl(); if (client == nullptr) { IMSA_HILOGE("failed to create client!"); return ErrorCode::ERROR_NULL_POINTER; } sptr channel = new (std::nothrow) InputDataChannelServiceImpl(); if (channel == nullptr) { IMSA_HILOGE("failed to new channel!"); return ErrorCode::ERROR_NULL_POINTER; } InputAttribute attribute; attribute.inputPattern = InputAttribute::PATTERN_TEXT; clientInfo_.attribute = attribute; clientInfo_.client = client, clientInfo_.channel = channel->AsObject(); // make AppExecFwk::EventHandler handler handler_ = std::make_shared(AppExecFwk::EventRunner::GetMainEventRunner()); return ErrorCode::NO_ERROR; } sptr InputMethodController::TryGetSystemAbilityProxy() { return GetSystemAbilityProxy(false); } sptr InputMethodController::GetSystemAbilityProxy(bool ifRetry) { std::lock_guard lock(abilityLock_); if (abilityManager_ != nullptr) { return abilityManager_; } IMSA_HILOGD("get input method service proxy."); auto systemAbility = OnDemandStartStopSa::GetInputMethodSystemAbility(ifRetry); if (systemAbility == nullptr) { IMSA_HILOGE("systemAbility is nullptr!"); return nullptr; } if (deathRecipient_ == nullptr) { deathRecipient_ = new (std::nothrow) InputDeathRecipient(); if (deathRecipient_ == nullptr) { IMSA_HILOGE("create death recipient failed!"); return nullptr; } } deathRecipient_->SetDeathRecipient([this](const wptr &remote) { OnRemoteSaDied(remote); }); if ((systemAbility->IsProxyObject()) && (!systemAbility->AddDeathRecipient(deathRecipient_))) { IMSA_HILOGE("failed to add death recipient!"); return nullptr; } abilityManager_ = iface_cast(systemAbility); return abilityManager_; } void InputMethodController::RemoveDeathRecipient() { std::lock_guard lock(abilityLock_); if (abilityManager_ != nullptr && abilityManager_->AsObject() != nullptr && deathRecipient_ != nullptr) { abilityManager_->AsObject()->RemoveDeathRecipient(deathRecipient_); } deathRecipient_ = nullptr; abilityManager_ = nullptr; } void InputMethodController::DeactivateClient() { { std::lock_guard lock(clientInfoLock_); clientInfo_.state = ClientState::INACTIVE; } SendKeyboardStatus(KeyboardStatus::NONE); } void InputMethodController::CalibrateImmersiveParam(InputAttribute &inputAttribute) { // 1.The gradient mode and the fluid light mode can only be used when the immersive mode is enabled. if (inputAttribute.immersiveMode == 0) { if (inputAttribute.gradientMode != 0 || inputAttribute.fluidLightMode != 0) { IMSA_HILOGW("immersiveMode is NONE, but gradientMode=%{public}d, fluidLightMode=%{public}d", inputAttribute.gradientMode, inputAttribute.fluidLightMode); inputAttribute.gradientMode = 0; inputAttribute.fluidLightMode = 0; } return; } // 2.The fluid light mode can only be used when the gradient mode is enabled. if (inputAttribute.gradientMode == 0 && inputAttribute.fluidLightMode != 0) { IMSA_HILOGW("gradientMode is NONE, but fluidLightMode=%{public}d", inputAttribute.fluidLightMode); inputAttribute.fluidLightMode = 0; return; } } void InputMethodController::SaveTextConfig(const TextConfig &textConfig) { IMSA_HILOGD("textConfig: %{public}s.", textConfig.ToString().c_str()); CursorInfo cursorInfo = textConfig.cursorInfo; uint32_t windowId = textConfig.windowId; GetWindowScaleCoordinate(windowId, cursorInfo); { std::lock_guard lock(textConfigLock_); textConfig_ = textConfig; CalibrateImmersiveParam(textConfig_.inputAttribute); textConfig_.cursorInfo = cursorInfo; StringUtils::TruncateUtf16String(textConfig_.inputAttribute.placeholder, MAX_PLACEHOLDER_SIZE); StringUtils::TruncateUtf16String(textConfig_.inputAttribute.abilityName, MAX_ABILITY_NAME_SIZE); } if (textConfig.range.start != INVALID_VALUE) { std::lock_guard lock(editorContentLock_); selectOldBegin_ = selectNewBegin_; selectOldEnd_ = selectNewEnd_; selectNewBegin_ = textConfig.range.start; selectNewEnd_ = textConfig.range.end; } } int32_t InputMethodController::Attach(sptr listener, ClientType type) { return Attach(listener, true, type); } int32_t InputMethodController::Attach(sptr listener, bool isShowKeyboard, ClientType type) { InputAttribute attribute; attribute.inputPattern = InputAttribute::PATTERN_TEXT; return Attach(listener, isShowKeyboard, attribute, type); } int32_t InputMethodController::Attach( sptr listener, bool isShowKeyboard, const InputAttribute &attribute, ClientType type) { InputMethodSyncTrace tracer("InputMethodController Attach trace."); TextConfig textConfig; textConfig.inputAttribute = attribute; return Attach(listener, isShowKeyboard, textConfig, type); } int32_t InputMethodController::Attach( sptr listener, bool isShowKeyboard, const TextConfig &textConfig, ClientType type) { AttachOptions attachOptions; attachOptions.isShowKeyboard = isShowKeyboard; attachOptions.requestKeyboardReason = RequestKeyboardReason::NONE; return Attach(listener, attachOptions, textConfig, type); } int32_t InputMethodController::IsValidTextConfig(const TextConfig &textConfig) { if (textConfig.inputAttribute.immersiveMode < static_cast(ImmersiveMode::NONE_IMMERSIVE) || textConfig.inputAttribute.immersiveMode >= static_cast(ImmersiveMode::END)) { IMSA_HILOGE("invalid immersiveMode: %{public}d", textConfig.inputAttribute.immersiveMode); return ErrorCode::ERROR_PARAMETER_CHECK_FAILED; } if (textConfig.inputAttribute.gradientMode < static_cast(GradientMode::NONE) || textConfig.inputAttribute.gradientMode >= static_cast(GradientMode::END)) { IMSA_HILOGW("invalid gradientMode: %{public}d", textConfig.inputAttribute.gradientMode); } if (textConfig.inputAttribute.fluidLightMode < static_cast(FluidLightMode::NONE) || textConfig.inputAttribute.fluidLightMode >= static_cast(FluidLightMode::END)) { IMSA_HILOGW("invalid fluidLightMode: %{public}d", textConfig.inputAttribute.fluidLightMode); } return ErrorCode::NO_ERROR; } int32_t InputMethodController::Attach(sptr listener, const AttachOptions &attachOptions, const TextConfig &textConfig, ClientType type) { IMSA_HILOGI("isShowKeyboard %{public}d.", attachOptions.isShowKeyboard); InputMethodSyncTrace tracer("InputMethodController Attach with textConfig trace."); if (IsValidTextConfig(textConfig) != ErrorCode::NO_ERROR) { IMSA_HILOGE("invalid textConfig."); return ErrorCode::ERROR_PARAMETER_CHECK_FAILED; } auto lastListener = GetTextListener(); clientInfo_.isNotifyInputStart = lastListener != listener; if (clientInfo_.isNotifyInputStart) { sessionId_++; } IMSA_HILOGD("sessionId_ %{public}u", sessionId_.load()); if (clientInfo_.isNotifyInputStart && lastListener != nullptr) { lastListener->OnDetachV2(); } ClearEditorCache(clientInfo_.isNotifyInputStart, lastListener); SetTextListener(listener); { std::lock_guard lock(clientInfoLock_); clientInfo_.isShowKeyboard = attachOptions.isShowKeyboard; } SaveTextConfig(textConfig); GetTextConfig(clientInfo_.config); clientInfo_.requestKeyboardReason = attachOptions.requestKeyboardReason; clientInfo_.type = type; std::vector> agents; std::vector imeInfos; int32_t ret = StartInput(clientInfo_, agents, imeInfos); if (ret != ErrorCode::NO_ERROR) { auto evenInfo = HiSysOriginalInfo::Builder() .SetErrCode(ret) .SetInputPattern(textConfig.inputAttribute.inputPattern) .SetIsShowKeyboard(attachOptions.isShowKeyboard) .SetClientType(type) .Build(); ImcHiSysEventReporter::GetInstance().ReportEvent(ImfEventType::CLIENT_ATTACH, *evenInfo); SetTextListener(nullptr); return ret; } clientInfo_.state = ClientState::ACTIVE; SetInputReady(agents, imeInfos); if (attachOptions.isShowKeyboard) { InputMethodSysEvent::GetInstance().OperateSoftkeyboardBehaviour(OperateIMEInfoCode::IME_SHOW_ATTACH); } IMSA_HILOGI("bind imf successfully."); return ErrorCode::NO_ERROR; } int32_t InputMethodController::ShowTextInputInner(const AttachOptions &attachOptions, ClientType type) { InputMethodSyncTrace tracer("IMC_ShowTextInput"); if (!IsBound()) { IMSA_HILOGE("not bound!"); return ErrorCode::ERROR_CLIENT_NOT_BOUND; } IMSA_HILOGI("start."); { std::lock_guard lock(clientInfoLock_); clientInfo_.isShowKeyboard = true; } InputMethodSysEvent::GetInstance().OperateSoftkeyboardBehaviour(OperateIMEInfoCode::IME_SHOW_ENEDITABLE); int32_t ret = ShowInput(clientInfo_.client, type, static_cast(attachOptions.requestKeyboardReason)); if (ret != ErrorCode::NO_ERROR) { IMSA_HILOGE("failed to start input: %{public}d", ret); return ret; } isEditable_.store(true); IMSA_HILOGI("enter editable state."); return ret; } int32_t InputMethodController::HideTextInput() { InputMethodSyncTrace tracer("IMC_HideTextInput"); if (!IsBound()) { IMSA_HILOGE("not bound!"); return ErrorCode::ERROR_CLIENT_NOT_BOUND; } IMSA_HILOGI("start."); isEditable_.store(false); InputMethodSysEvent::GetInstance().OperateSoftkeyboardBehaviour(OperateIMEInfoCode::IME_HIDE_UNEDITABLE); return HideInput(clientInfo_.client); } int32_t InputMethodController::HideCurrentInput() { InputMethodSyncTrace tracer("IMC_HideCurrentInput"); IMSA_HILOGD("InputMethodController::HideCurrentInput"); if (!IsEditable()) { IMSA_HILOGD("not editable."); return ErrorCode::ERROR_CLIENT_NOT_EDITABLE; } auto proxy = GetSystemAbilityProxy(); if (proxy == nullptr) { IMSA_HILOGE("proxy is nullptr!"); return ErrorCode::ERROR_EX_NULL_POINTER; } { std::lock_guard lock(clientInfoLock_); clientInfo_.isShowKeyboard = false; } InputMethodSysEvent::GetInstance().OperateSoftkeyboardBehaviour(OperateIMEInfoCode::IME_HIDE_NORMAL); return proxy->HideCurrentInputDeprecated(); } int32_t InputMethodController::ShowCurrentInput() { InputMethodSyncTrace tracer("IMC_ShowCurrentInput"); if (!IsEditable()) { IMSA_HILOGD("not editable."); return ErrorCode::ERROR_CLIENT_NOT_EDITABLE; } auto proxy = GetSystemAbilityProxy(); if (proxy == nullptr) { IMSA_HILOGE("proxy is nullptr!"); return ErrorCode::ERROR_EX_NULL_POINTER; } IMSA_HILOGI("start."); { std::lock_guard lock(clientInfoLock_); clientInfo_.isShowKeyboard = true; } InputMethodSysEvent::GetInstance().OperateSoftkeyboardBehaviour(OperateIMEInfoCode::IME_SHOW_NORMAL); return proxy->ShowCurrentInputDeprecated(); } int32_t InputMethodController::Close() { if (IsBound()) { IMSA_HILOGI("start."); } auto listener = GetTextListener(); if (listener != nullptr) { listener->OnDetachV2(); } OperateIMEInfoCode infoCode = OperateIMEInfoCode::IME_UNBIND; { std::lock_guard lock(clientInfoLock_); if (clientInfo_.isShowKeyboard) { infoCode = OperateIMEInfoCode::IME_HIDE_UNBIND; } } InputMethodSyncTrace tracer("InputMethodController Close trace."); InputMethodSysEvent::GetInstance().OperateSoftkeyboardBehaviour(infoCode); return ReleaseInput(clientInfo_.client); } void InputMethodController::Reset() { Close(); RemoveDeathRecipient(); } int32_t InputMethodController::RequestShowInput() { auto proxy = GetSystemAbilityProxy(); if (proxy == nullptr) { IMSA_HILOGE("proxy is nullptr!"); return ErrorCode::ERROR_SERVICE_START_FAILED; // ERROR_EX_NULL_POINTER } IMSA_HILOGD("InputMethodController start."); return proxy->RequestShowInput(); } int32_t InputMethodController::RequestHideInput(bool isFocusTriggered) { auto proxy = TryGetSystemAbilityProxy(); if (proxy == nullptr) { IMSA_HILOGE("proxy is nullptr!"); return ErrorCode::ERROR_EX_NULL_POINTER; } IMSA_HILOGD("InputMethodController start."); return proxy->RequestHideInput(isFocusTriggered); } int32_t InputMethodController::DisplayOptionalInputMethod() { IMSA_HILOGD("InputMethodController::DisplayOptionalInputMethod start."); auto proxy = GetSystemAbilityProxy(); if (proxy == nullptr) { IMSA_HILOGE("proxy is nullptr!"); return ErrorCode::ERROR_EX_NULL_POINTER; } return proxy->DisplayOptionalInputMethod(); } bool InputMethodController::WasAttached() { return isBound_.load(); } int32_t InputMethodController::GetInputStartInfo(bool &isInputStart, uint32_t &callingWndId, int32_t &requestKeyboardReason) { auto proxy = GetSystemAbilityProxy(); if (proxy == nullptr) { IMSA_HILOGE("proxy is nullptr!"); return false; } return proxy->GetInputStartInfo(isInputStart, callingWndId, requestKeyboardReason); } int32_t InputMethodController::ListInputMethodCommon(InputMethodStatus status, std::vector &props) { IMSA_HILOGD("InputMethodController::ListInputMethodCommon start."); auto proxy = GetSystemAbilityProxy(); if (proxy == nullptr) { IMSA_HILOGE("proxy is nullptr!"); return ErrorCode::ERROR_EX_NULL_POINTER; } return proxy->ListInputMethod(status, props); } int32_t InputMethodController::ListInputMethod(std::vector &props) { IMSA_HILOGD("InputMethodController::listInputMethod start."); return ListInputMethodCommon(ALL, props); } int32_t InputMethodController::ListInputMethod(bool enable, std::vector &props) { IMSA_HILOGI("enable: %{public}s.", enable ? "ENABLE" : "DISABLE"); return ListInputMethodCommon(enable ? ENABLE : DISABLE, props); } int32_t InputMethodController::GetDefaultInputMethod(std::shared_ptr &property) { InputMethodSyncTrace tracer("IMC_GetDefaultInputMethod"); IMSA_HILOGD("InputMethodController::GetDefaultInputMethod start."); auto proxy = GetSystemAbilityProxy(); if (proxy == nullptr) { IMSA_HILOGE("proxy is nullptr!"); return ErrorCode::ERROR_SERVICE_START_FAILED; } Property prop; auto ret = proxy->GetDefaultInputMethod(prop, false); if (ret != ErrorCode::NO_ERROR) { return ret; } property = std::make_shared(prop); return ret; } int32_t InputMethodController::GetInputMethodConfig(OHOS::AppExecFwk::ElementName &inputMethodConfig) { InputMethodSyncTrace tracer("IMC_GetInputMethodConfig"); IMSA_HILOGD("InputMethodController::inputMethodConfig start."); auto proxy = GetSystemAbilityProxy(); if (proxy == nullptr) { IMSA_HILOGE("proxy is nullptr!"); return ErrorCode::ERROR_SERVICE_START_FAILED; } return proxy->GetInputMethodConfig(inputMethodConfig); } std::shared_ptr InputMethodController::GetCurrentInputMethod() { InputMethodSyncTrace tracer("IMC_GetCurrentInputMethod"); IMSA_HILOGD("InputMethodController::GetCurrentInputMethod start."); auto proxy = GetSystemAbilityProxy(); if (proxy == nullptr) { IMSA_HILOGE("proxy is nullptr!"); return nullptr; } Property propertyData; proxy->GetCurrentInputMethod(propertyData); auto property = std::make_shared(propertyData); return property; } std::shared_ptr InputMethodController::GetCurrentInputMethodSubtype() { InputMethodSyncTrace tracer("IMC_GetCurrentInputMethodSubtype"); IMSA_HILOGD("InputMethodController::GetCurrentInputMethodSubtype start."); auto proxy = GetSystemAbilityProxy(); if (proxy == nullptr) { IMSA_HILOGE("proxy is nullptr!"); return nullptr; } SubProperty subPropertyData; proxy->GetCurrentInputMethodSubtype(subPropertyData); auto subProperty = std::make_shared(subPropertyData); return subProperty; } bool InputMethodController::IsDefaultImeSet() { IMSA_HILOGI("enter."); auto proxy = GetSystemAbilityProxy(); if (proxy == nullptr) { IMSA_HILOGE("proxy is nullptr!"); return false; } bool ret = false; proxy->IsDefaultImeSet(ret); return ret; } int32_t InputMethodController::EnableIme( const std::string &bundleName, const std::string &extensionName, EnabledStatus status) { IMSA_HILOGI("enter."); auto proxy = GetSystemAbilityProxy(); if (proxy == nullptr) { IMSA_HILOGE("proxy is nullptr!"); return false; } return proxy->EnableIme(bundleName, extensionName, static_cast(status)); } int32_t InputMethodController::StartInput( InputClientInfo &inputClientInfo, std::vector> &agents, std::vector &imeInfos) { IMSA_HILOGD("InputMethodController::StartInput start."); auto proxy = GetSystemAbilityProxy(); if (proxy == nullptr) { IMSA_HILOGE("proxy is nullptr!"); return ErrorCode::ERROR_SERVICE_START_FAILED; } InputClientInfoInner inner = InputMethodTools::GetInstance().InputClientInfoToInner(inputClientInfo); int32_t ret = proxy->StartInput(inner, agents, imeInfos); return ret; } int32_t InputMethodController::ReleaseInput(sptr &client) { IMSA_HILOGD("InputMethodController::ReleaseInput start."); auto proxy = TryGetSystemAbilityProxy(); if (proxy == nullptr) { IMSA_HILOGE("proxy is nullptr!"); return ErrorCode::ERROR_SERVICE_START_FAILED; } int32_t ret = proxy->ReleaseInput(client, sessionId_.load()); if (ret == ErrorCode::NO_ERROR) { OnInputStop(); } SetTextListener(nullptr); return ret; } int32_t InputMethodController::ShowInput(sptr &client, ClientType type, int32_t requestKeyboardReason) { IMSA_HILOGD("InputMethodController::ShowInput start."); auto proxy = GetSystemAbilityProxy(); if (proxy == nullptr) { IMSA_HILOGE("proxy is nullptr!"); return ErrorCode::ERROR_SERVICE_START_FAILED; } return proxy->ShowInput(client, type, requestKeyboardReason); } int32_t InputMethodController::HideInput(sptr &client) { IMSA_HILOGD("InputMethodController::HideInput start."); auto proxy = GetSystemAbilityProxy(); if (proxy == nullptr) { IMSA_HILOGE("proxy is nullptr!"); return ErrorCode::ERROR_SERVICE_START_FAILED; } return proxy->HideInput(client); } void InputMethodController::OnRemoteSaDied(const wptr &remote) { IMSA_HILOGI("input method service death."); // imf sa died, current client callback inputStop ImeEventMonitorManagerImpl::GetInstance().OnInputStop(); auto textListener = GetTextListener(); if (textListener != nullptr && textConfig_.inputAttribute.isTextPreviewSupported) { IMSA_HILOGD("finish text preview."); textListener->FinishTextPreviewV2(); } { std::lock_guard lock(abilityLock_); abilityManager_ = nullptr; } ClearAgentInfo(); if (handler_ == nullptr) { IMSA_HILOGE("handler_ is nullptr!"); return; } RestoreClientInfoInSaDied(); } void InputMethodController::RestoreListenInfoInSaDied() { { std::lock_guard lock(clientInfoLock_); if (clientInfo_.eventFlag == NO_EVENT_ON) { return; } } isDiedRestoreListen_.store(false); auto restoreListenTask = [=]() { if (isDiedRestoreListen_.load()) { return; } auto ret = RestoreListenEventFlag(); if (ret == ErrorCode::NO_ERROR) { isDiedRestoreListen_.store(true); IMSA_HILOGI("try to RestoreListen success."); } }; for (int i = 0; i < LOOP_COUNT; i++) { handler_->PostTask(restoreListenTask, "OnRemoteSaDied", DELAY_TIME * (i + 1), AppExecFwk::EventQueue::Priority::VIP); } } void InputMethodController::RestoreClientInfoInSaDied() { if (!IsEditable()) { IMSA_HILOGD("not editable."); RestoreListenInfoInSaDied(); return; } auto attach = [=]() -> bool { TextConfig tempConfig {}; { std::lock_guard lock(textConfigLock_); tempConfig = textConfig_; tempConfig.range.start = selectNewBegin_; tempConfig.range.end = selectNewEnd_; } { std::lock_guard lock(cursorInfoMutex_); tempConfig.cursorInfo = cursorInfo_; } auto listener = GetTextListener(); bool isShowKeyboard = false; { std::lock_guard lock(clientInfoLock_); isShowKeyboard = clientInfo_.isShowKeyboard; } auto errCode = Attach(listener, isShowKeyboard, tempConfig); IMSA_HILOGI("attach end, errCode: %{public}d", errCode); return errCode == ErrorCode::NO_ERROR; }; if (attach()) { return; } isDiedAttached_.store(false); auto attachTask = [this, attach]() { if (isDiedAttached_.load()) { return; } attach(); }; for (int i = 0; i < LOOP_COUNT; i++) { handler_->PostTask(attachTask, "OnRemoteSaDied", DELAY_TIME * (i + 1), AppExecFwk::EventQueue::Priority::VIP); } } int32_t InputMethodController::DiscardTypingText() { if (!IsBound()) { IMSA_HILOGE("not bound."); return ErrorCode::ERROR_CLIENT_NOT_BOUND; } return SendRequestToAllAgents([](std::shared_ptr agent) -> int32_t { return agent->DiscardTypingText(); }); } int32_t InputMethodController::OnCursorUpdate(CursorInfo cursorInfo) { if (!IsBound()) { IMSA_HILOGD("not bound."); return ErrorCode::ERROR_CLIENT_NOT_BOUND; } if (!IsEditable()) { IMSA_HILOGD("not editable."); return ErrorCode::ERROR_CLIENT_NOT_EDITABLE; } uint32_t windowId = 0; { std::lock_guard lock(textConfigLock_); windowId = textConfig_.windowId; } GetWindowScaleCoordinate(windowId, cursorInfo); { std::lock_guard lock(textConfigLock_); textConfig_.cursorInfo = cursorInfo; } { std::lock_guard lk(cursorInfoMutex_); if (cursorInfo_ == cursorInfo) { IMSA_HILOGD("same to last update."); return ErrorCode::NO_ERROR; } cursorInfo_ = cursorInfo; } IMSA_HILOGI("left: %{public}d, top: %{public}d, height: %{public}d.", static_cast(cursorInfo.left), static_cast(cursorInfo.top), static_cast(cursorInfo.height)); return SendRequestToAllAgents([cursorInfo](std::shared_ptr agent) -> int32_t { agent->OnCursorUpdate(cursorInfo.left, cursorInfo.top, cursorInfo.height); return ErrorCode::NO_ERROR; }); } int32_t InputMethodController::OnSelectionChange(std::u16string text, int start, int end) { if (!IsBound()) { IMSA_HILOGD("not bound."); return ErrorCode::ERROR_CLIENT_NOT_BOUND; } if (!IsEditable()) { IMSA_HILOGD("not editable."); return ErrorCode::ERROR_CLIENT_NOT_EDITABLE; } { std::lock_guard lock(textConfigLock_); textConfig_.range.start = start; textConfig_.range.end = end; } { std::lock_guard lock(editorContentLock_); if (isTextNotified_.exchange(true) && textString_ == text && selectNewBegin_ == start && selectNewEnd_ == end) { IMSA_HILOGD("same to last update."); return ErrorCode::NO_ERROR; } textString_ = text; selectOldBegin_ = selectNewBegin_; selectOldEnd_ = selectNewEnd_; selectNewBegin_ = start; selectNewEnd_ = end; } IMSA_HILOGI("IMC size: %{public}zu, range: %{public}d/%{public}d/%{public}d/%{public}d.", text.size(), selectOldBegin_, selectOldEnd_, start, end); std::string testString = Str16ToStr8(text); return SendRequestToAllAgents( [testString, selectOldBegin = selectOldBegin_, selectOldEnd = selectOldEnd_, selectNewBegin = selectNewBegin_, selectNewEnd = selectNewEnd_](std::shared_ptr agent) -> int32_t { agent->OnSelectionChange(testString, selectOldBegin, selectOldEnd, selectNewBegin, selectNewEnd); return ErrorCode::NO_ERROR; }); } int32_t InputMethodController::OnConfigurationChange(Configuration info) { if (!IsBound()) { IMSA_HILOGD("not bound."); return ErrorCode::ERROR_CLIENT_NOT_BOUND; } bool oldSecurityFlag = textConfig_.inputAttribute.GetSecurityFlag(); InputAttribute attribute; { std::lock_guard lock(textConfigLock_); textConfig_.inputAttribute.enterKeyType = static_cast(info.GetEnterKeyType()); textConfig_.inputAttribute.inputPattern = static_cast(info.GetTextInputType()); attribute = textConfig_.inputAttribute; } if (!IsEditable()) { IMSA_HILOGD("not editable."); return ErrorCode::ERROR_CLIENT_NOT_EDITABLE; } IMSA_HILOGI( "IMC enterKeyType: %{public}d, textInputType: %{public}d.", attribute.enterKeyType, attribute.inputPattern); if (oldSecurityFlag != attribute.GetSecurityFlag()) { GetTextConfig(clientInfo_.config); std::vector> agents; std::vector imeInfos; int32_t ret = StartInput(clientInfo_, agents, imeInfos); if (ret != ErrorCode::NO_ERROR) { return ret; } SetInputReady(agents, imeInfos); } auto agent = GetAgent(); if (agent == nullptr) { IMSA_HILOGE("agent is nullptr!"); return ErrorCode::ERROR_IME_NOT_STARTED; } InputAttributeInner inner = InputMethodTools::GetInstance().AttributeToInner(attribute); agent->OnAttributeChange(inner); return ErrorCode::NO_ERROR; } int32_t InputMethodController::GetLeft(int32_t length, std::u16string &text) { InputMethodSyncTrace tracer("IMC_GetForward"); IMSA_HILOGD("start, length: %{public}d", length); auto listener = GetTextListener(); if (!IsEditable() || listener == nullptr) { IMSA_HILOGE("not editable or listener is nullptr!"); ReportBaseTextOperation(static_cast(IInputDataChannelIpcCode::COMMAND_GET_TEXT_BEFORE_CURSOR), ErrorCode::ERROR_CLIENT_NOT_EDITABLE); return ErrorCode::ERROR_CLIENT_NOT_EDITABLE; } int64_t start = duration_cast(system_clock::now().time_since_epoch()).count(); { InputMethodSyncTrace aceTracer("ACE_GetForward"); text = listener->GetLeftTextOfCursorV2(length); } PrintLogIfAceTimeout(start); return ErrorCode::NO_ERROR; } int32_t InputMethodController::GetRight(int32_t length, std::u16string &text) { IMSA_HILOGD("start, length: %{public}d", length); auto listener = GetTextListener(); if (!IsEditable() || listener == nullptr) { IMSA_HILOGE("not editable or textListener_ is nullptr!"); ReportBaseTextOperation(static_cast(IInputDataChannelIpcCode::COMMAND_GET_TEXT_AFTER_CURSOR), ErrorCode::ERROR_CLIENT_NOT_EDITABLE); return ErrorCode::ERROR_CLIENT_NOT_EDITABLE; } text = listener->GetRightTextOfCursorV2(length); return ErrorCode::NO_ERROR; } int32_t InputMethodController::GetTextIndexAtCursor(int32_t &index) { IMSA_HILOGD("start."); auto listener = GetTextListener(); if (!IsEditable() || listener == nullptr) { IMSA_HILOGE("not editable or textListener_ is nullptr!"); ReportBaseTextOperation(static_cast(IInputDataChannelIpcCode::COMMAND_GET_TEXT_INDEX_AT_CURSOR), ErrorCode::ERROR_CLIENT_NOT_EDITABLE); return ErrorCode::ERROR_CLIENT_NOT_EDITABLE; } index = listener->GetTextIndexAtCursorV2(); return ErrorCode::NO_ERROR; } void InputMethodController::PrintKeyEventLog() { std::lock_guard lock(logLock_); auto now = system_clock::now(); if (keyEventCountInPeriod_ == 0) { startLogTime_ = now; } keyEventCountInPeriod_++; if (std::chrono::duration_cast(now - startLogTime_).count() >= LOG_MAX_TIME) { auto start = std::chrono::duration_cast(startLogTime_.time_since_epoch()).count(); auto end = std::chrono::duration_cast(now.time_since_epoch()).count(); IMSA_HILOGI("KeyEventCountInPeriod: %{public}d, startTime: %{public}lld, endTime: %{public}lld", keyEventCountInPeriod_, start, end); keyEventCountInPeriod_ = 0; } } int32_t InputMethodController::DispatchKeyEvent(std::shared_ptr keyEvent, KeyEventCallback callback) { PrintKeyEventLog(); KeyEventInfo keyEventInfo = { std::chrono::system_clock::now(), keyEvent }; keyEventQueue_.Push(keyEventInfo); InputMethodSyncTrace tracer("DispatchKeyEvent trace"); keyEventQueue_.Wait(keyEventInfo); if (!IsEditable()) { IMSA_HILOGD("not editable."); keyEventQueue_.Pop(); return ErrorCode::ERROR_CLIENT_NOT_EDITABLE; } if (keyEvent == nullptr) { IMSA_HILOGE("keyEvent is nullptr!"); keyEventQueue_.Pop(); return ErrorCode::ERROR_EX_NULL_POINTER; } auto agent = GetAgent(); if (agent == nullptr) { IMSA_HILOGE("agent is nullptr!"); keyEventQueue_.Pop(); return ErrorCode::ERROR_IME_NOT_STARTED; } IMSA_HILOGD("start."); sptr channelObject = nullptr; { std::lock_guard lock(clientInfoLock_); channelObject = clientInfo_.channel; } if (channelObject == nullptr) { IMSA_HILOGE("channelObject is nullptr!"); keyEventQueue_.Pop(); return ErrorCode::ERROR_EX_NULL_POINTER; } auto cbId = keyEventRetHandler_.AddKeyEventCbInfo({ keyEvent, callback }); KeyEventValue keyEventValue; keyEventValue.event = keyEvent; auto ret = agent->DispatchKeyEvent(keyEventValue, cbId, channelObject); if (ret != ErrorCode::NO_ERROR) { IMSA_HILOGE("failed to DispatchKeyEvent: %{public}d", ret); keyEventRetHandler_.RemoveKeyEventCbInfo(cbId); } keyEventQueue_.Pop(); return ret; } void InputMethodController::HandleKeyEventResult(uint64_t cbId, bool consumeResult) { keyEventRetHandler_.HandleKeyEventResult(cbId, consumeResult); } int32_t InputMethodController::GetEnterKeyType(int32_t &keyType) { IMSA_HILOGD("InputMethodController::GetEnterKeyType start."); std::lock_guard lock(textConfigLock_); keyType = textConfig_.inputAttribute.enterKeyType; return ErrorCode::NO_ERROR; } int32_t InputMethodController::GetInputPattern(int32_t &inputpattern) { IMSA_HILOGD("InputMethodController::GetInputPattern start."); std::lock_guard lock(textConfigLock_); inputpattern = textConfig_.inputAttribute.inputPattern; return ErrorCode::NO_ERROR; } int32_t InputMethodController::GetTextConfig(TextTotalConfig &config) { std::lock_guard lock(textConfigLock_); config.inputAttribute = textConfig_.inputAttribute; config.cursorInfo = textConfig_.cursorInfo; config.windowId = textConfig_.windowId; config.positionY = textConfig_.positionY; config.height = textConfig_.height; config.privateCommand = textConfig_.privateCommand; config.abilityToken = textConfig_.abilityToken; if (textConfig_.range.start == INVALID_VALUE) { IMSA_HILOGD("SelectionRange is invalid."); } else { { std::lock_guard editorLock(editorContentLock_); config.textSelection.oldBegin = selectOldBegin_; config.textSelection.oldEnd = selectOldEnd_; } config.textSelection.newBegin = textConfig_.range.start; config.textSelection.newEnd = textConfig_.range.end; } IMSA_HILOGD("textConfig: %{public}s.", config.ToString().c_str()); return ErrorCode::NO_ERROR; } int32_t InputMethodController::SetCallingWindow(uint32_t windowId) { if (!IsBound()) { IMSA_HILOGD("not bound."); return ErrorCode::ERROR_CLIENT_NOT_BOUND; } if (!IsEditable()) { IMSA_HILOGD("not editable."); return ErrorCode::ERROR_CLIENT_NOT_EDITABLE; } { std::lock_guard lock(textConfigLock_); textConfig_.windowId = windowId; } auto agent = GetAgent(); if (agent == nullptr) { IMSA_HILOGE("agent is nullptr!"); return ErrorCode::ERROR_IME_NOT_STARTED; } IMSA_HILOGI("windowId: %{public}d.", windowId); agent->SetCallingWindow(windowId); auto proxy = GetSystemAbilityProxy(); if (proxy != nullptr) { proxy->SetCallingWindow(windowId, clientInfo_.client); } return ErrorCode::NO_ERROR; } int32_t InputMethodController::ShowSoftKeyboardInner(ClientType type) { auto proxy = GetSystemAbilityProxy(); if (proxy == nullptr) { IMSA_HILOGE("proxy is nullptr!"); return ErrorCode::ERROR_SERVICE_START_FAILED; } IMSA_HILOGI("start."); { std::lock_guard lock(clientInfoLock_); clientInfo_.isShowKeyboard = true; } InputMethodSysEvent::GetInstance().OperateSoftkeyboardBehaviour(OperateIMEInfoCode::IME_SHOW_NORMAL); return proxy->ShowCurrentInput(type); } int32_t InputMethodController::HideSoftKeyboard() { auto proxy = GetSystemAbilityProxy(); if (proxy == nullptr) { IMSA_HILOGE("proxy is nullptr!"); return ErrorCode::ERROR_EX_NULL_POINTER; } IMSA_HILOGI("start."); { std::lock_guard lock(clientInfoLock_); clientInfo_.isShowKeyboard = false; } InputMethodSysEvent::GetInstance().OperateSoftkeyboardBehaviour(OperateIMEInfoCode::IME_HIDE_NORMAL); return proxy->HideCurrentInput(); } int32_t InputMethodController::StopInputSession() { IMSA_HILOGI("start."); isEditable_.store(false); auto proxy = GetSystemAbilityProxy(); if (proxy == nullptr) { IMSA_HILOGE("proxy is nullptr!"); return ErrorCode::ERROR_EX_NULL_POINTER; } return proxy->StopInputSession(); } int32_t InputMethodController::ShowOptionalInputMethod() { auto proxy = GetSystemAbilityProxy(); if (proxy == nullptr) { IMSA_HILOGE("proxy is nullptr!"); return ErrorCode::ERROR_EX_NULL_POINTER; } IMSA_HILOGI("IMC start."); return proxy->DisplayOptionalInputMethod(); } int32_t InputMethodController::ListInputMethodSubtype(const Property &property, std::vector &subProps) { auto proxy = GetSystemAbilityProxy(); if (proxy == nullptr) { IMSA_HILOGE("proxy is nullptr!"); return ErrorCode::ERROR_EX_NULL_POINTER; } IMSA_HILOGD("ime bundleName: %{public}s.", property.name.c_str()); return proxy->ListInputMethodSubtype(property.name, subProps); } int32_t InputMethodController::ListCurrentInputMethodSubtype(std::vector &subProps) { auto proxy = GetSystemAbilityProxy(); if (proxy == nullptr) { IMSA_HILOGE("proxy is nullptr!"); return ErrorCode::ERROR_EX_NULL_POINTER; } IMSA_HILOGD("start."); return proxy->ListCurrentInputMethodSubtype(subProps); } int32_t InputMethodController::SwitchInputMethod( SwitchTrigger trigger, const std::string &name, const std::string &subName) { InputMethodSyncTrace tracer("IMC_SwitchInputMethod"); auto proxy = GetSystemAbilityProxy(); if (proxy == nullptr) { IMSA_HILOGE("proxy is nullptr!"); return ErrorCode::ERROR_EX_NULL_POINTER; } IMSA_HILOGI("name: %{public}s, subName: %{public}s, trigger: %{public}d.", name.c_str(), subName.c_str(), static_cast(trigger)); return proxy->SwitchInputMethod(name, subName, static_cast(trigger)); } int32_t InputMethodController::SetSimpleKeyboardEnabled(bool enable) { InputMethodSyncTrace tracer("IMC_SetSimpleKeyboardEnabled"); std::lock_guard lock(clientInfoLock_); clientInfo_.config.isSimpleKeyboardEnabled = enable; return ErrorCode::NO_ERROR; } void InputMethodController::OnInputReady(sptr agentObject, const BindImeInfo &imeInfo) { IMSA_HILOGI("InputMethodController start."); if (imeInfo.bundleName != IME_MIRROR_NAME) { SetBindImeInfo(std::make_pair(imeInfo.pid, imeInfo.bundleName)); isBound_.store(true); isEditable_.store(true); } else { IMSA_HILOGI("[ImeMirrorTag] proxyIme_IME_MIRROR no need to set bindImeInfo"); } if (agentObject == nullptr) { IMSA_HILOGE("agentObject is nullptr!"); return; } SetAgent(agentObject, imeInfo.bundleName); } void InputMethodController::SetInputReady( const std::vector> &agentObjects, const std::vector &imeInfos) { if (agentObjects.size() != imeInfos.size()) { IMSA_HILOGE("[ImeMirrorTag]agentObjects.size() != imeInfos.size()!"); return; } for (size_t i = 0; i < agentObjects.size(); i++) { OnInputReady(agentObjects[i], imeInfos[i]); } } void InputMethodController::OnInputStop(bool isStopInactiveClient, sptr proxy) { ClearAgentInfo(); auto listener = GetTextListener(); if (listener != nullptr) { IMSA_HILOGD("listener is not nullptr!"); if (textConfig_.inputAttribute.isTextPreviewSupported) { IMSA_HILOGD("finish text preview."); listener->FinishTextPreviewV2(); } if (!isStopInactiveClient || !listener->IsFromTs()) { listener->SendKeyboardStatusV2(KeyboardStatus::HIDE); } } isBound_.store(false); isEditable_.store(false); isTextNotified_.store(false); keyEventRetHandler_.ClearKeyEventCbInfo(); { std::lock_guard lock(editorContentLock_); textString_ = Str8ToStr16(""); selectOldBegin_ = INVALID_VALUE; selectOldEnd_ = INVALID_VALUE; selectNewBegin_ = INVALID_VALUE; selectNewEnd_ = INVALID_VALUE; } if (proxy == nullptr) { IMSA_HILOGD("proxy is nullptr."); return; } auto channelProxy = std::make_shared(proxy); channelProxy->NotifyOnInputStopFinished(); } void InputMethodController::OnImeMirrorStop(sptr object) { std::lock_guard guard(agentLock_); auto pos = find_if(agentInfoList_.begin(), agentInfoList_.end(), [object](const AgentInfo &agentInfo) { return agentInfo.agentObject == object; }); if (pos == agentInfoList_.end()) { IMSA_HILOGE("[ImeMirrorTag] object is not in agentInfoList."); return; } pos->agentObject = nullptr; pos->agent = nullptr; agentInfoList_.erase(pos); IMSA_HILOGI("[ImeMirrorTag]remove agent"); } void InputMethodController::ClearEditorCache(bool isNewEditor, sptr lastListener) { IMSA_HILOGD("isNewEditor: %{public}d.", isNewEditor); if (isNewEditor && isBound_.load() && lastListener != nullptr && textConfig_.inputAttribute.isTextPreviewSupported) { IMSA_HILOGD("last editor FinishTextPreview"); lastListener->FinishTextPreviewV2(); } { std::lock_guard lock(editorContentLock_); // reset old range when editor changes or first attach if (isNewEditor || !isBound_.load()) { isTextNotified_.store(false); textString_ = Str8ToStr16(""); selectOldBegin_ = INVALID_VALUE; selectOldEnd_ = INVALID_VALUE; selectNewBegin_ = INVALID_VALUE; selectNewEnd_ = INVALID_VALUE; } } { std::lock_guard lock(textConfigLock_); textConfig_ = {}; } { std::lock_guard lock(cursorInfoMutex_); cursorInfo_ = {}; } { std::lock_guard lock(clientInfoLock_); auto isSimpleKeyboardEnabled = clientInfo_.config.isSimpleKeyboardEnabled; clientInfo_.config = {}; clientInfo_.config.isSimpleKeyboardEnabled = isSimpleKeyboardEnabled; // global scope } } void InputMethodController::SelectByRange(int32_t start, int32_t end) { IMSA_HILOGD("InputMethodController start: %{public}d, end: %{public}d.", start, end); auto listener = GetTextListener(); if (IsEditable() && listener != nullptr) { listener->HandleSetSelectionV2(start, end); } else { IMSA_HILOGE("not editable or textListener_ is nullptr!"); } if (controllerListener_ != nullptr) { controllerListener_->OnSelectByRange(start, end); } else { IMSA_HILOGE("controllerListener_ is nullptr!"); } } void InputMethodController::SelectByMovement(int32_t direction, int32_t cursorMoveSkip) { IMSA_HILOGD( "InputMethodController start, direction: %{public}d, cursorMoveSkip: %{public}d", direction, cursorMoveSkip); auto listener = GetTextListener(); if (IsEditable() && listener != nullptr) { listener->HandleSelectV2(CURSOR_DIRECTION_BASE_VALUE + direction, cursorMoveSkip); } else { IMSA_HILOGE("not editable or textListener_ is nullptr!"); } if (controllerListener_ != nullptr) { controllerListener_->OnSelectByMovement(direction); } else { IMSA_HILOGE("controllerListener_ is nullptr!"); } } int32_t InputMethodController::HandleExtendAction(int32_t action) { IMSA_HILOGD("InputMethodController start, action: %{public}d.", action); auto listener = GetTextListener(); if (!IsEditable() || listener == nullptr) { IMSA_HILOGE("not editable or textListener is nullptr!"); return ErrorCode::ERROR_CLIENT_NOT_EDITABLE; } listener->HandleExtendActionV2(action); return ErrorCode::NO_ERROR; } sptr InputMethodController::GetTextListener() { std::lock_guard lock(textListenerLock_); return textListener_; } void InputMethodController::SetTextListener(sptr listener) { std::lock_guard lock(textListenerLock_); textListener_ = listener; } bool InputMethodController::IsEditable() { std::lock_guard lock(clientInfoLock_); if (clientInfo_.state != ClientState::ACTIVE) { IMSA_HILOGD("client is not active."); return false; } if (!isEditable_.load()) { IMSA_HILOGD("not in editable state."); return false; } return true; } bool InputMethodController::IsBound() { std::lock_guard lock(clientInfoLock_); if (clientInfo_.state != ClientState::ACTIVE) { IMSA_HILOGD("client is not active."); return false; } if (!isBound_.load()) { IMSA_HILOGD("not bound."); return false; } return true; } int32_t InputMethodController::InsertText(const std::u16string &text) { InputMethodSyncTrace tracer("IMC_InsertText"); IMSA_HILOGD("start."); auto listener = GetTextListener(); if (!IsEditable() || listener == nullptr) { IMSA_HILOGE("not editable or textListener is nullptr!"); ReportBaseTextOperation(static_cast(IInputDataChannelIpcCode::COMMAND_INSERT_TEXT), ErrorCode::ERROR_CLIENT_NOT_EDITABLE); return ErrorCode::ERROR_CLIENT_NOT_EDITABLE; } int64_t start = duration_cast(system_clock::now().time_since_epoch()).count(); { InputMethodSyncTrace aceTracer("ACE_InsertText"); IMSA_HILOGD("ACE InsertText."); listener->InsertTextV2(text); } PrintLogIfAceTimeout(start); return ErrorCode::NO_ERROR; } int32_t InputMethodController::DeleteForward(int32_t length) { InputMethodSyncTrace tracer("IMC_DeleteForward"); IMSA_HILOGD("start, length: %{public}d.", length); auto listener = GetTextListener(); if (!IsEditable() || listener == nullptr) { IMSA_HILOGE("not editable or textListener is nullptr!"); ReportBaseTextOperation(static_cast(IInputDataChannelIpcCode::COMMAND_DELETE_FORWARD), ErrorCode::ERROR_CLIENT_NOT_EDITABLE); return ErrorCode::ERROR_CLIENT_NOT_EDITABLE; } int64_t start = duration_cast(system_clock::now().time_since_epoch()).count(); { InputMethodSyncTrace aceTracer("ACE_DeleteForward"); // reverse for compatibility listener->DeleteBackwardV2(length); } PrintLogIfAceTimeout(start); return ErrorCode::NO_ERROR; } int32_t InputMethodController::DeleteBackward(int32_t length) { IMSA_HILOGD("InputMethodController start, length: %{public}d.", length); auto listener = GetTextListener(); if (!IsEditable() || listener == nullptr) { IMSA_HILOGE("not editable or textListener is nullptr!"); ReportBaseTextOperation(static_cast(IInputDataChannelIpcCode::COMMAND_DELETE_BACKWARD), ErrorCode::ERROR_CLIENT_NOT_EDITABLE); return ErrorCode::ERROR_CLIENT_NOT_EDITABLE; } // reverse for compatibility listener->DeleteForwardV2(length); return ErrorCode::NO_ERROR; } int32_t InputMethodController::MoveCursor(Direction direction) { IMSA_HILOGD("InputMethodController start, direction: %{public}d.", static_cast(direction)); auto listener = GetTextListener(); if (!IsEditable() || listener == nullptr) { IMSA_HILOGE("not editable or textListener_ is nullptr!"); return ErrorCode::ERROR_CLIENT_NOT_EDITABLE; } listener->MoveCursorV2(direction); return ErrorCode::NO_ERROR; } void InputMethodController::SendKeyboardStatus(KeyboardStatus status) { IMSA_HILOGD("InputMethodController status: %{public}d.", static_cast(status)); auto listener = GetTextListener(); if (listener == nullptr) { IMSA_HILOGE("listener is nullptr!"); return; } listener->SendKeyboardStatusV2(status); if (status == KeyboardStatus::HIDE) { std::lock_guard lock(clientInfoLock_); clientInfo_.isShowKeyboard = false; } } void InputMethodController::NotifyPanelStatusInfo(const PanelStatusInfo &info) { IMSA_HILOGD("InputMethodController start, type: %{public}d, flag: %{public}d, visible: %{public}d, trigger: " "%{public}d, sessionId: %{public}u.", static_cast(info.panelInfo.panelType), static_cast(info.panelInfo.panelFlag), info.visible, static_cast(info.trigger), info.sessionId); auto listener = GetTextListener(); if (listener == nullptr) { IMSA_HILOGE("listener is nullptr!"); return; } if (info.panelInfo.panelType == PanelType::SOFT_KEYBOARD) { info.visible ? SendKeyboardStatus(KeyboardStatus::SHOW) : SendKeyboardStatus(KeyboardStatus::HIDE); } if (info.visible || info.sessionId == 0 || info.sessionId == sessionId_) { listener->NotifyPanelStatusInfoV2(info); } if (info.panelInfo.panelType == PanelType::SOFT_KEYBOARD && info.panelInfo.panelFlag != PanelFlag::FLG_CANDIDATE_COLUMN && !info.visible) { std::lock_guard lock(clientInfoLock_); clientInfo_.isShowKeyboard = false; } } void InputMethodController::NotifyKeyboardHeight(uint32_t height) { IMSA_HILOGD("InputMethodController start, height: %{public}u.", height); auto listener = GetTextListener(); if (listener == nullptr) { IMSA_HILOGE("listener is nullptr!"); return; } listener->NotifyKeyboardHeightV2(height); } int32_t InputMethodController::SendFunctionKey(int32_t functionKey) { IMSA_HILOGD("InputMethodController start, functionKey: %{public}d", static_cast(functionKey)); auto listener = GetTextListener(); if (!IsEditable() || listener == nullptr) { IMSA_HILOGE("not editable or listener is nullptr!"); return ErrorCode::ERROR_CLIENT_NOT_EDITABLE; } FunctionKey funcKey; funcKey.SetEnterKeyType(static_cast(functionKey)); listener->SendFunctionKeyV2(funcKey); SendRequestToImeMirrorAgent([&functionKey](std::shared_ptr agent) -> int32_t { return agent->OnFunctionKey(functionKey); }); return ErrorCode::NO_ERROR; } bool InputMethodController::IsInputTypeSupported(InputType type) { auto proxy = GetSystemAbilityProxy(); if (proxy == nullptr) { IMSA_HILOGE("proxy is nullptr!"); return ErrorCode::ERROR_NULL_POINTER; } IMSA_HILOGI("type: %{public}d.", static_cast(type)); bool ret = false; proxy->IsInputTypeSupported(static_cast(type), ret); return ret; } bool InputMethodController::IsCurrentImeByPid(int32_t pid) { auto proxy = GetSystemAbilityProxy(); if (proxy == nullptr) { IMSA_HILOGE("proxy is nullptr!"); return false; } bool ret = false; proxy->IsCurrentImeByPid(pid, ret); return ret; } int32_t InputMethodController::StartInputType(InputType type) { auto proxy = GetSystemAbilityProxy(); if (proxy == nullptr) { IMSA_HILOGE("proxy is nullptr!"); return ErrorCode::ERROR_NULL_POINTER; } IMSA_HILOGI("type: %{public}d.", static_cast(type)); return proxy->StartInputType(static_cast(type)); } int32_t InputMethodController::StartInputTypeAsync(InputType type) { auto proxy = GetSystemAbilityProxy(); if (proxy == nullptr) { IMSA_HILOGE("proxy is nullptr!"); return ErrorCode::ERROR_NULL_POINTER; } IMSA_HILOGI("type: %{public}d.", static_cast(type)); return proxy->StartInputTypeAsync(static_cast(type)); } int32_t InputMethodController::IsPanelShown(const PanelInfo &panelInfo, bool &isShown) { auto proxy = GetSystemAbilityProxy(); if (proxy == nullptr) { IMSA_HILOGE("proxy is nullptr!"); return ErrorCode::ERROR_NULL_POINTER; } IMSA_HILOGD("type: %{public}d, flag: %{public}d.", static_cast(panelInfo.panelType), static_cast(panelInfo.panelFlag)); return proxy->IsPanelShown(panelInfo, isShown); } void InputMethodController::SetAgent(const sptr &agentObject, const std::string &bundleName) { std::lock_guard autoLock(agentLock_); for (auto &agentInfo : agentInfoList_) { if (agentInfo.agent != nullptr && agentInfo.agentObject.GetRefPtr() == agentObject.GetRefPtr()) { IMSA_HILOGD("[ImeMirrorTag]agent has already been set."); return; } } if (agentInfoList_.size() >= MAX_AGENT_NUMBER) { IMSA_HILOGW("[ImeMirrorTag]agent num is too many"); } AgentInfo agentInfo; agentInfo.agent = std::make_shared(agentObject); agentInfo.agentObject = agentObject; agentInfo.imeType = (bundleName == IME_MIRROR_NAME) ? ImeType::IME_MIRROR : ImeType::NONE; agentInfoList_.push_back(agentInfo); } std::shared_ptr InputMethodController::GetAgent() { std::lock_guard autoLock(agentLock_); for (auto &agentInfo : agentInfoList_) { if (agentInfo.agent != nullptr && agentInfo.imeType != ImeType::IME_MIRROR) { return agentInfo.agent; } } IMSA_HILOGE("no agent found!"); return nullptr; } void InputMethodController::PrintLogIfAceTimeout(int64_t start) { int64_t end = duration_cast(system_clock::now().time_since_epoch()).count(); if (end < start || start < 0) { return; } if (end - start > ACE_DEAL_TIME_OUT) { IMSA_HILOGW("timeout: [%{public}" PRId64 ", %{public}" PRId64 "].", start, end); } } int32_t InputMethodController::ReceivePrivateCommand( const std::unordered_map &privateCommand) { auto listener = GetTextListener(); if (listener == nullptr) { IMSA_HILOGE("listener is nullptr!"); return ErrorCode::ERROR_EX_NULL_POINTER; } IMSA_HILOGD("IMC in."); auto ret = listener->ReceivePrivateCommandV2(privateCommand); if (ret != ErrorCode::NO_ERROR) { IMSA_HILOGE("ReceivePrivateCommand err, ret: %{public}d!", ret); return ErrorCode::ERROR_TEXT_LISTENER_ERROR; } return ErrorCode::NO_ERROR; } int32_t InputMethodController::SendPrivateCommand( const std::unordered_map &privateCommand) { if (!IsBound()) { IMSA_HILOGD("not bound."); return ErrorCode::ERROR_CLIENT_NOT_BOUND; } if (!IsEditable()) { IMSA_HILOGD("not editable."); return ErrorCode::ERROR_CLIENT_NOT_EDITABLE; } if (!TextConfig::IsPrivateCommandValid(privateCommand)) { IMSA_HILOGE("invalid private command size!"); return ErrorCode::ERROR_INVALID_PRIVATE_COMMAND_SIZE; } auto agent = GetAgent(); if (agent == nullptr) { IMSA_HILOGE("agent is nullptr!"); return ErrorCode::ERROR_IME_NOT_STARTED; } IMSA_HILOGD("IMC start."); Value value(privateCommand); return agent->SendPrivateCommand(value); } void InputMethodController::SetBindImeInfo(const std::pair &imeInfo) { std::lock_guard lock(bindImeInfoLock_); bindImeInfo_ = imeInfo; } std::pair InputMethodController::GetBindImeInfo() { std::lock_guard lock(bindImeInfoLock_); return bindImeInfo_; } int32_t InputMethodController::SetPreviewTextInner(const std::string &text, const Range &range) { InputMethodSyncTrace tracer("IMC_SetPreviewText"); IMSA_HILOGD("IMC start."); if (!textConfig_.inputAttribute.isTextPreviewSupported) { IMSA_HILOGE("text preview do not supported!"); return ErrorCode::ERROR_TEXT_PREVIEW_NOT_SUPPORTED; } auto listener = GetTextListener(); if (!IsEditable() || listener == nullptr) { IMSA_HILOGE("not editable or listener is nullptr!"); return ErrorCode::ERROR_CLIENT_NOT_EDITABLE; } int32_t ret = 0; int64_t start = duration_cast(system_clock::now().time_since_epoch()).count(); { InputMethodSyncTrace aceTracer("ACE_SetPreviewText"); ret = listener->SetPreviewTextV2(Str8ToStr16(text), range); } PrintLogIfAceTimeout(start); if (ret != ErrorCode::NO_ERROR) { IMSA_HILOGE("failed to SetPreviewText: %{public}d!", ret); return ret == -1 ? ErrorCode::ERROR_INVALID_RANGE : ErrorCode::ERROR_TEXT_LISTENER_ERROR; } return ErrorCode::NO_ERROR; } int32_t InputMethodController::FinishTextPreview() { InputMethodSyncTrace tracer("IMC_FinishTextPreview"); IMSA_HILOGD("IMC start."); if (!textConfig_.inputAttribute.isTextPreviewSupported) { IMSA_HILOGD("text preview do not supported!"); ReportBaseTextOperation(static_cast(IInputDataChannelIpcCode::COMMAND_FINISH_TEXT_PREVIEW), ErrorCode::ERROR_TEXT_PREVIEW_NOT_SUPPORTED); return ErrorCode::ERROR_TEXT_PREVIEW_NOT_SUPPORTED; } auto listener = GetTextListener(); if (!isBound_.load() || listener == nullptr) { IMSA_HILOGW("not bound or listener is nullptr!"); ReportBaseTextOperation(static_cast(IInputDataChannelIpcCode::COMMAND_FINISH_TEXT_PREVIEW), ErrorCode::ERROR_CLIENT_NOT_EDITABLE); return ErrorCode::ERROR_CLIENT_NOT_EDITABLE; } { InputMethodSyncTrace aceTracer("ACE_FinishTextPreview"); listener->FinishTextPreviewV2(); } return ErrorCode::NO_ERROR; } int32_t InputMethodController::SendMessage(const ArrayBuffer &arrayBuffer) { if (!IsBound()) { IMSA_HILOGE("not bound."); return ErrorCode::ERROR_CLIENT_NOT_BOUND; } if (!IsEditable()) { IMSA_HILOGE("not editable."); return ErrorCode::ERROR_CLIENT_NOT_EDITABLE; } if (!ArrayBuffer::IsSizeValid(arrayBuffer)) { IMSA_HILOGE("arrayBuffer size is invalid!"); return ErrorCode::ERROR_INVALID_ARRAY_BUFFER_SIZE; } auto agent = GetAgent(); if (agent == nullptr) { IMSA_HILOGE("agent is nullptr!"); return ErrorCode::ERROR_CLIENT_NULL_POINTER; } return agent->SendMessage(arrayBuffer); } int32_t InputMethodController::RecvMessage(const ArrayBuffer &arrayBuffer) { if (!IsBound()) { IMSA_HILOGE("not bound."); return ErrorCode::ERROR_CLIENT_NOT_BOUND; } if (!IsEditable()) { IMSA_HILOGE("not editable."); return ErrorCode::ERROR_CLIENT_NOT_EDITABLE; } auto msgHandlerCallback = GetMsgHandlerCallback(); if (msgHandlerCallback == nullptr) { IMSA_HILOGW("Message handler was not regist!"); return ErrorCode::ERROR_MSG_HANDLER_NOT_REGIST; } return msgHandlerCallback->OnMessage(arrayBuffer); } int32_t InputMethodController::RegisterMsgHandler(const std::shared_ptr &msgHandler) { IMSA_HILOGI("isRegist: %{public}d", msgHandler != nullptr); std::shared_ptr exMsgHandler = nullptr; { std::lock_guard lock(msgHandlerMutex_); exMsgHandler = msgHandler_; msgHandler_ = msgHandler; } if (exMsgHandler != nullptr) { IMSA_HILOGI("Trigger exMessageHandler OnTerminated."); exMsgHandler->OnTerminated(); } return ErrorCode::NO_ERROR; } std::shared_ptr InputMethodController::GetMsgHandlerCallback() { std::lock_guard lock(msgHandlerMutex_); return msgHandler_; } int32_t InputMethodController::GetInputMethodState(EnabledStatus &state) { auto proxy = GetSystemAbilityProxy(); if (proxy == nullptr) { IMSA_HILOGE("proxy is nullptr!"); return ErrorCode::ERROR_NULL_POINTER; } int32_t stateData = 0; int32_t ret = proxy->GetInputMethodState(stateData); state = static_cast(stateData); return ret; } int32_t InputMethodController::SetPreviewText(const std::string &text, const Range &range) { auto ret = SetPreviewTextInner(text, range); ReportBaseTextOperation(static_cast(IInputDataChannelIpcCode::COMMAND_SET_PREVIEW_TEXT), ret); return ret; } int32_t InputMethodController::ShowTextInput(ClientType type) { AttachOptions attachOptions; return ShowTextInput(attachOptions, type); } int32_t InputMethodController::ShowTextInput(const AttachOptions &attachOptions, ClientType type) { auto ret = ShowTextInputInner(attachOptions, type); ReportClientShow(static_cast(IInputMethodSystemAbilityIpcCode::COMMAND_SHOW_INPUT), ret, type); return ret; } int32_t InputMethodController::ShowSoftKeyboard(ClientType type) { auto ret = ShowSoftKeyboardInner(type); ReportClientShow(static_cast(IInputMethodSystemAbilityIpcCode::COMMAND_SHOW_CURRENT_INPUT), ret, type); return ret; } void InputMethodController::ReportClientShow(int32_t eventCode, int32_t errCode, ClientType type) { auto evenInfo = HiSysOriginalInfo::Builder().SetClientType(type).SetEventCode(eventCode).SetErrCode(errCode).Build(); ImcHiSysEventReporter::GetInstance().ReportEvent(ImfEventType::CLIENT_SHOW, *evenInfo); } void InputMethodController::ReportBaseTextOperation(int32_t eventCode, int32_t errCode) { auto imeInfo = GetBindImeInfo(); auto evenInfo = HiSysOriginalInfo::Builder() .SetEventCode(eventCode) .SetErrCode(errCode) .SetPeerName(imeInfo.second) .SetPeerPid(imeInfo.first) .SetClientType(clientInfo_.type) .Build(); ImcHiSysEventReporter::GetInstance().ReportEvent(ImfEventType::BASE_TEXT_OPERATOR, *evenInfo); } void InputMethodController::UpdateTextPreviewState(bool isSupport) { if (textConfig_.inputAttribute.isTextPreviewSupported == isSupport) { return; } textConfig_.inputAttribute.isTextPreviewSupported = isSupport; auto agent = GetAgent(); if (agent == nullptr) { IMSA_HILOGE("agent is nullptr!"); return; } InputAttributeInner inner = InputMethodTools::GetInstance().AttributeToInner(textConfig_.inputAttribute); agent->OnAttributeChange(inner); } int32_t InputMethodController::SendPrivateData(const std::unordered_map &privateCommand) { auto proxy = GetSystemAbilityProxy(); if (proxy == nullptr) { IMSA_HILOGE("proxy is nullptr!"); return ErrorCode::ERROR_NULL_POINTER; } Value value(privateCommand); return proxy->SendPrivateData(value); } int32_t InputMethodController::RegisterWindowScaleCallbackHandler(WindowScaleCallback&& callback) { IMSA_HILOGD("isRegister: %{public}d", callback != nullptr); std::lock_guard lock(windowScaleCallbackMutex_); windowScaleCallback_ = std::move(callback); return static_cast(ErrorCode::NO_ERROR); } void InputMethodController::GetWindowScaleCoordinate(uint32_t windowId, CursorInfo &cursorInfo) { WindowScaleCallback handler = nullptr; { std::lock_guard lock(windowScaleCallbackMutex_); handler = windowScaleCallback_; } if (handler == nullptr) { IMSA_HILOGD("handler is nullptr"); return; } handler(windowId, cursorInfo); } int32_t InputMethodController::ResponseDataChannel( const sptr &agentObject, uint64_t msgId, int32_t code, const ResponseData &data) { if (agentObject == nullptr) { IMSA_HILOGE("agentObject is nullptr!"); return ErrorCode::ERROR_IME_NOT_STARTED; } auto agent = std::make_shared(agentObject); ResponseDataInner inner; inner.rspData = data; return agent->ResponseDataChannel(msgId, code, inner); } void InputMethodController::ClearAgentInfo() { std::lock_guard guard(agentLock_); for (auto &agentInfo : agentInfoList_) { agentInfo.agent = nullptr; agentInfo.agentObject = nullptr; } IMSA_HILOGD("Clear all agent info"); agentInfoList_.clear(); } int32_t InputMethodController::SendRequestToAllAgents(std::function)> task) { std::lock_guard guard(agentLock_); int32_t finalRet = ErrorCode::NO_ERROR; for (auto &agentInfo : agentInfoList_) { if (agentInfo.imeType == ImeType::IME_MIRROR && textConfig_.inputAttribute.IsSecurityImeFlag()) { IMSA_HILOGW("password not allow send to ime mirror"); continue; } if (agentInfo.agent == nullptr) { if (agentInfo.imeType == ImeType::IME_MIRROR) { IMSA_HILOGW("ime mirror agent is null"); continue; } IMSA_HILOGE("agent is null"); if (agentInfo.imeType == ImeType::IME_MIRROR) { continue; } return ErrorCode::ERROR_CLIENT_NULL_POINTER; } auto ret = task(agentInfo.agent); if (ret != ErrorCode::NO_ERROR) { IMSA_HILOGE("failed, ret = %{public}d", ret); } // Only update final return code for non-imeMirror IMEs // ImeMirror IME errors don't affect the overall result if (agentInfo.imeType != ImeType::IME_MIRROR) { finalRet = ret; } } IMSA_HILOGD("end, finalRet = %{public}d", finalRet); return finalRet; } int32_t InputMethodController::SendRequestToImeMirrorAgent( std::function)> task) { std::lock_guard guard(agentLock_); auto itr = std::find_if(agentInfoList_.begin(), agentInfoList_.end(), [](const AgentInfo &info) { return info.imeType == ImeType::IME_MIRROR; }); if (itr == agentInfoList_.end()) { IMSA_HILOGD("ime mirror agent is not exist"); return ErrorCode::ERROR_IME_NOT_FOUND; } if (textConfig_.inputAttribute.IsSecurityImeFlag()) { IMSA_HILOGE("text type is security, can not send function key"); return ErrorCode::ERROR_STATUS_PERMISSION_DENIED; } return task(itr->agent); } void OnTextChangedListener::InsertTextV2(const std::u16string &text) { auto eventHandler = GetEventHandler(); if (eventHandler == nullptr) { InsertText(text); return; } auto weakPtr = wptr(this); auto task = [weakPtr, text]() { auto listener = weakPtr.promote(); if (listener == nullptr) { IMSA_HILOGE("InsertTextV2 listener is nullptr."); return; } listener->InsertText(text); }; eventHandler->PostTask(task, "InsertTextV2", 0, AppExecFwk::EventQueue::Priority::VIP); } void OnTextChangedListener::DeleteForwardV2(int32_t length) { auto eventHandler = GetEventHandler(); if (eventHandler == nullptr) { DeleteForward(length); return; } auto weakPtr = wptr(this); auto task = [weakPtr, length]() { auto listener = weakPtr.promote(); if (listener == nullptr) { IMSA_HILOGE("DeleteForwardV2 listener is nullptr."); return; } listener->DeleteForward(length); }; eventHandler->PostTask(task, "DeleteForwardV2", 0, AppExecFwk::EventQueue::Priority::VIP); } void OnTextChangedListener::DeleteBackwardV2(int32_t length) { auto eventHandler = GetEventHandler(); if (eventHandler == nullptr) { DeleteBackward(length); return; } auto weakPtr = wptr(this); auto task = [weakPtr, length]() { auto listener = weakPtr.promote(); if (listener == nullptr) { IMSA_HILOGE("DeleteBackwardV2 listener is nullptr."); return; } listener->DeleteBackward(length); }; eventHandler->PostTask(task, "DeleteBackwardV2", 0, AppExecFwk::EventQueue::Priority::VIP); } void OnTextChangedListener::SendKeyboardStatusV2(const KeyboardStatus &keyboardStatus) { auto eventHandler = GetEventHandler(); if (eventHandler == nullptr) { SendKeyboardStatus(keyboardStatus); return; } auto weakPtr = wptr(this); auto task = [weakPtr, keyboardStatus]() { auto listener = weakPtr.promote(); if (listener == nullptr) { IMSA_HILOGE("SendKeyboardStatusV2 listener is nullptr."); return; } listener->SendKeyboardStatus(keyboardStatus); }; eventHandler->PostTask(task, "SendKeyboardStatusV2", 0, AppExecFwk::EventQueue::Priority::VIP); } void OnTextChangedListener::SendFunctionKeyV2(const FunctionKey &functionKey) { auto eventHandler = GetEventHandler(); if (eventHandler == nullptr) { SendFunctionKey(functionKey); return; } auto weakPtr = wptr(this); auto task = [weakPtr, functionKey]() { auto listener = weakPtr.promote(); if (listener == nullptr) { IMSA_HILOGE("SendFunctionKeyV2 listener is nullptr."); return; } listener->SendFunctionKey(functionKey); }; eventHandler->PostTask(task, "SendFunctionKeyV2", 0, AppExecFwk::EventQueue::Priority::VIP); } void OnTextChangedListener::MoveCursorV2(const Direction &direction) { auto eventHandler = GetEventHandler(); if (eventHandler == nullptr) { MoveCursor(direction); return; } auto weakPtr = wptr(this); auto task = [weakPtr, direction]() { auto listener = weakPtr.promote(); if (listener == nullptr) { IMSA_HILOGE("MoveCursorV2 listener is nullptr."); return; } listener->MoveCursor(direction); }; eventHandler->PostTask(task, "MoveCursorV2", 0, AppExecFwk::EventQueue::Priority::VIP); } void OnTextChangedListener::HandleExtendActionV2(int32_t action) { auto eventHandler = GetEventHandler(); if (eventHandler == nullptr) { HandleExtendAction(action); return; } auto weakPtr = wptr(this); auto task = [weakPtr, action]() { auto listener = weakPtr.promote(); if (listener == nullptr) { IMSA_HILOGE("HandleExtendActionV2 listener is nullptr."); return; } listener->HandleExtendAction(action); }; eventHandler->PostTask(task, "HandleExtendActionV2", 0, AppExecFwk::EventQueue::Priority::VIP); } std::u16string OnTextChangedListener::GetLeftTextOfCursorV2(int32_t number) { auto eventHandler = GetEventHandler(); if (eventHandler == nullptr) { return GetLeftTextOfCursor(number); } auto textResultHandler = std::make_shared>(MAX_TIMEOUT); auto weakPtr = wptr(this); auto task = [weakPtr, textResultHandler, number]() { std::u16string text; auto listener = weakPtr.promote(); if (listener == nullptr) { IMSA_HILOGE("GetLeftTextOfCursorV2 listener is nullptr."); } else { text = listener->GetLeftTextOfCursor(number); } if (textResultHandler != nullptr) { textResultHandler->SetValue(text); } }; eventHandler->PostTask(task, "GetLeftTextOfCursorV2", 0, AppExecFwk::EventQueue::Priority::VIP); std::u16string text; if (!textResultHandler->GetValue(text)) { IMSA_HILOGW("GetLeftTextOfCursorV2 timeout"); } return text; } std::u16string OnTextChangedListener::GetRightTextOfCursorV2(int32_t number) { auto eventHandler = GetEventHandler(); if (eventHandler == nullptr) { return GetRightTextOfCursor(number); } auto textResultHandler = std::make_shared>(MAX_TIMEOUT); auto weakPtr = wptr(this); auto task = [weakPtr, textResultHandler, number]() { std::u16string text; auto listener = weakPtr.promote(); if (listener == nullptr) { IMSA_HILOGE("GetRightTextOfCursorV2 listener is nullptr."); } else { text = listener->GetRightTextOfCursor(number); } if (textResultHandler != nullptr) { textResultHandler->SetValue(text); } }; eventHandler->PostTask(task, "GetRightTextOfCursorV2", 0, AppExecFwk::EventQueue::Priority::VIP); std::u16string text; if (!textResultHandler->GetValue(text)) { IMSA_HILOGW("GetRightTextOfCursorV2 timeout"); } return text; } int32_t OnTextChangedListener::GetTextIndexAtCursorV2() { auto eventHandler = GetEventHandler(); if (eventHandler == nullptr) { return GetTextIndexAtCursor(); } auto textResultHandler = std::make_shared>(MAX_TIMEOUT, -1); auto weakPtr = wptr(this); auto task = [weakPtr, textResultHandler]() { int32_t index = -1; auto listener = weakPtr.promote(); if (listener == nullptr) { IMSA_HILOGE("GetTextIndexAtCursorV2 listener is nullptr."); } else { index = listener->GetTextIndexAtCursor(); } if (textResultHandler != nullptr) { textResultHandler->SetValue(index); } }; eventHandler->PostTask(task, "GetTextIndexAtCursorV2", 0, AppExecFwk::EventQueue::Priority::VIP); int32_t index = -1; if (!textResultHandler->GetValue(index)) { IMSA_HILOGW("GetTextIndexAtCursorV2 timeout"); } return index; } void OnTextChangedListener::SendKeyEventFromInputMethodV2(const KeyEvent &event) { auto eventHandler = GetEventHandler(); if (eventHandler == nullptr) { SendKeyEventFromInputMethod(event); return; } auto weakPtr = wptr(this); auto task = [weakPtr, event]() { auto listener = weakPtr.promote(); if (listener == nullptr) { IMSA_HILOGE("SendKeyEventFromInputMethodV2 listener is nullptr."); return; } listener->SendKeyEventFromInputMethod(event); }; eventHandler->PostTask(task, "SendKeyEventFromInputMethodV2", 0, AppExecFwk::EventQueue::Priority::VIP); } void OnTextChangedListener::NotifyPanelStatusInfoV2(const PanelStatusInfo &info) { auto eventHandler = GetEventHandler(); if (eventHandler == nullptr) { NotifyPanelStatusInfo(info); return; } auto weakPtr = wptr(this); auto task = [weakPtr, info]() { auto listener = weakPtr.promote(); if (listener == nullptr) { IMSA_HILOGE("NotifyPanelStatusInfoV2 listener is nullptr."); return; } listener->NotifyPanelStatusInfo(info); }; eventHandler->PostTask(task, "NotifyPanelStatusInfoV2", 0, AppExecFwk::EventQueue::Priority::VIP); } void OnTextChangedListener::NotifyKeyboardHeightV2(uint32_t height) { auto eventHandler = GetEventHandler(); if (eventHandler == nullptr) { NotifyKeyboardHeight(height); return; } auto weakPtr = wptr(this); auto task = [weakPtr, height]() { auto listener = weakPtr.promote(); if (listener == nullptr) { IMSA_HILOGE("NotifyKeyboardHeightV2 listener is nullptr."); return; } listener->NotifyKeyboardHeight(height); }; eventHandler->PostTask(task, "NotifyKeyboardHeightV2", 0, AppExecFwk::EventQueue::Priority::VIP); } void OnTextChangedListener::SetKeyboardStatusV2(bool status) { auto eventHandler = GetEventHandler(); if (eventHandler == nullptr) { SetKeyboardStatus(status); return; } auto weakPtr = wptr(this); auto task = [weakPtr, status]() { auto listener = weakPtr.promote(); if (listener == nullptr) { IMSA_HILOGE("SetKeyboardStatusV2 listener is nullptr."); return; } listener->SetKeyboardStatus(status); }; eventHandler->PostTask(task, "SetKeyboardStatusV2", 0, AppExecFwk::EventQueue::Priority::VIP); } void OnTextChangedListener::HandleSetSelectionV2(int32_t start, int32_t end) { auto eventHandler = GetEventHandler(); if (eventHandler == nullptr) { HandleSetSelection(start, end); return; } auto weakPtr = wptr(this); auto task = [weakPtr, start, end]() { auto listener = weakPtr.promote(); if (listener == nullptr) { IMSA_HILOGE("HandleSetSelectionV2 listener is nullptr."); return; } listener->HandleSetSelection(start, end); }; eventHandler->PostTask(task, "HandleSetSelectionV2", 0, AppExecFwk::EventQueue::Priority::VIP); } void OnTextChangedListener::HandleSelectV2(int32_t keyCode, int32_t cursorMoveSkip) { auto eventHandler = GetEventHandler(); if (eventHandler == nullptr) { HandleSelect(keyCode, cursorMoveSkip); return; } auto weakPtr = wptr(this); auto task = [weakPtr, keyCode, cursorMoveSkip]() { auto listener = weakPtr.promote(); if (listener == nullptr) { IMSA_HILOGE("HandleSelectV2 listener is nullptr."); return; } listener->HandleSelect(keyCode, cursorMoveSkip); }; eventHandler->PostTask(task, "HandleSelectV2", 0, AppExecFwk::EventQueue::Priority::VIP); } int32_t OnTextChangedListener::ReceivePrivateCommandV2( const std::unordered_map &privateCommand) { auto eventHandler = GetEventHandler(); if (eventHandler == nullptr) { return ReceivePrivateCommand(privateCommand); } auto weakPtr = wptr(this); auto task = [weakPtr, privateCommand]() { auto listener = weakPtr.promote(); if (listener == nullptr) { IMSA_HILOGE("ReceivePrivateCommandV2 listener is nullptr."); return; } listener->ReceivePrivateCommand(privateCommand); }; eventHandler->PostTask(task, "ReceivePrivateCommandV2", 0, AppExecFwk::EventQueue::Priority::VIP); return ErrorCode::NO_ERROR; } int32_t OnTextChangedListener::SetPreviewTextV2(const std::u16string &text, const Range &range) { auto eventHandler = GetEventHandler(); if (eventHandler == nullptr) { return SetPreviewText(text, range); } auto weakPtr = wptr(this); auto task = [weakPtr, text, range]() { auto listener = weakPtr.promote(); if (listener == nullptr) { IMSA_HILOGE("SetPreviewTextV2 listener is nullptr."); return; } listener->SetPreviewText(text, range); }; eventHandler->PostTask(task, "SetPreviewTextV2", 0, AppExecFwk::EventQueue::Priority::VIP); return ErrorCode::NO_ERROR; } void OnTextChangedListener::FinishTextPreviewV2() { auto eventHandler = GetEventHandler(); if (eventHandler == nullptr) { FinishTextPreview(); return; } auto weakPtr = wptr(this); auto task = [weakPtr]() { auto listener = weakPtr.promote(); if (listener == nullptr) { IMSA_HILOGE("FinishTextPreviewV2 listener is nullptr."); return; } listener->FinishTextPreview(); }; eventHandler->PostTask(task, "FinishTextPreviewV2", 0, AppExecFwk::EventQueue::Priority::VIP); } void OnTextChangedListener::OnDetachV2() { auto eventHandler = GetEventHandler(); if (eventHandler == nullptr) { OnDetach(); return; } auto weakPtr = wptr(this); auto task = [weakPtr]() { auto listener = weakPtr.promote(); if (listener == nullptr) { IMSA_HILOGE("OnDetachV2 listener is nullptr."); return; } listener->OnDetach(); }; eventHandler->PostTask(task, "OnDetachV2", 0, AppExecFwk::EventQueue::Priority::VIP); } } // namespace MiscServices } // namespace OHOS