* Copyright (c) 2025 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 "ohos.inputMethod.impl.hpp"
#include "ani_common.h"
#include "common_fun_ani.h"
#include "input_method_controller.h"
#include "input_method_controller_impl.h"
#include "input_method_setting_impl.h"
#include "js_utils.h"
#include "ohos.inputMethod.proj.hpp"
#include "stdexcept"
#include "taihe/runtime.hpp"
#include "input_method_impl.h"
using namespace taihe;
using namespace ohos::inputMethod;
using namespace ohos::InputMethodSubtype;
using namespace OHOS::MiscServices;
namespace {
InputMethodSetting GetSetting()
{
return make_holder<IMFSettingImpl, InputMethodSetting>();
}
ohos::inputMethod::InputMethodController GetController()
{
return make_holder<IMFControllerImpl, ohos::inputMethod::InputMethodController>();
}
InputMethodProperty GetDefaultInputMethod()
{
InputMethodProperty inputMethodProperty{};
std::shared_ptr<Property> property;
int32_t ret = OHOS::MiscServices::InputMethodController::GetInstance()->GetDefaultInputMethod(property);
if (ret != ErrorCode::NO_ERROR) {
taihe::set_business_error(JsUtils::Convert(ret), "failed to get default input method!");
IMSA_HILOGE("failed to get default input method!");
return inputMethodProperty;
}
inputMethodProperty = PropertyConverter::ConvertProperty(property);
return inputMethodProperty;
}
InputMethodProperty GetDefaultInputMethodByUserId(optional_view<int32_t> userId)
{
InputMethodProperty inputMethodProperty{};
int32_t nativeUserId = -1;
if (userId.has_value()) {
nativeUserId = userId.value();
if (nativeUserId < 0) {
int32_t errCode = ErrorCode::ERROR_PARAMETER_CHECK_FAILED;
set_business_error(JsUtils::Convert(errCode), "userId must greater than 0");
return inputMethodProperty;
}
}
std::shared_ptr<Property> property;
int32_t ret = OHOS::MiscServices::InputMethodController::GetInstance()->GetDefaultInputMethod(
property, nativeUserId);
if (ret != ErrorCode::NO_ERROR) {
taihe::set_business_error(JsUtils::Convert(ret), "failed to get default input method!");
IMSA_HILOGE("failed to get default input method!");
return inputMethodProperty;
}
inputMethodProperty = PropertyConverter::ConvertProperty(property);
return inputMethodProperty;
}
InputMethodProperty GetCurrentInputMethod()
{
InputMethodProperty inputMethodProperty{};
std::shared_ptr<Property> property =
OHOS::MiscServices::InputMethodController::GetInstance()->GetCurrentInputMethod();
if (property == nullptr) {
IMSA_HILOGE("current input method is nullptr!");
return inputMethodProperty;
}
inputMethodProperty = PropertyConverter::ConvertProperty(property);
return inputMethodProperty;
}
InputMethodProperty GetCurrentInputMethodByUserId(optional_view<int32_t> userId)
{
InputMethodProperty inputMethodProperty{};
int32_t nativeUserId = -1;
if (userId.has_value()) {
nativeUserId = userId.value();
if (nativeUserId < 0) {
int32_t errCode = ErrorCode::ERROR_PARAMETER_CHECK_FAILED;
set_business_error(JsUtils::Convert(errCode), "userId must greater than 0");
return inputMethodProperty;
}
}
std::shared_ptr<Property> property =
OHOS::MiscServices::InputMethodController::GetInstance()->GetCurrentInputMethod(nativeUserId);
if (property == nullptr) {
IMSA_HILOGE("current input method is nullptr!");
return inputMethodProperty;
}
inputMethodProperty = PropertyConverter::ConvertProperty(property);
return inputMethodProperty;
}
InputMethodSubtype GetCurrentInputMethodSubtype()
{
InputMethodSubtype inputMethodSubtype{};
std::shared_ptr<SubProperty> subProperty =
OHOS::MiscServices::InputMethodController::GetInstance()->GetCurrentInputMethodSubtype();
if (subProperty == nullptr) {
IMSA_HILOGE("current input method subtype is nullptr!");
return inputMethodSubtype;
}
inputMethodSubtype = PropertyConverter::ConvertSubProperty(subProperty);
return inputMethodSubtype;
}
InputMethodSubtype GetCurrentInputMethodSubtypeByUserId(optional_view<int32_t> userId)
{
InputMethodSubtype inputMethodSubtype{};
int32_t nativeUserId = -1;
if (userId.has_value()) {
nativeUserId = userId.value();
if (nativeUserId < 0) {
int32_t errCode = ErrorCode::ERROR_PARAMETER_CHECK_FAILED;
set_business_error(JsUtils::Convert(errCode), "userId must greater than 0");
return inputMethodSubtype;
}
}
std::shared_ptr<SubProperty> subProperty =
OHOS::MiscServices::InputMethodController::GetInstance()->GetCurrentInputMethodSubtype(nativeUserId);
if (subProperty == nullptr) {
IMSA_HILOGE("current input method subtype is nullptr!");
return inputMethodSubtype;
}
inputMethodSubtype = PropertyConverter::ConvertSubProperty(subProperty);
return inputMethodSubtype;
}
uintptr_t GetSystemInputMethodConfigAbility()
{
OHOS::AppExecFwk::ElementName elementName;
int32_t ret = OHOS::MiscServices::InputMethodController::GetInstance()->GetInputMethodConfig(elementName);
if (ret != ErrorCode::NO_ERROR) {
taihe::set_business_error(JsUtils::Convert(ret), "failed to get input method config ability!");
IMSA_HILOGE("failed to get input method config ability!");
return reinterpret_cast<uintptr_t>(nullptr);
}
ani_object obj = OHOS::AppExecFwk::CommonFunAni::ConvertElementName(taihe::get_env(), elementName);
return reinterpret_cast<uintptr_t>(obj);
}
uintptr_t GetSystemInputMethodConfigAbilityByUserId(optional_view<int32_t> userId)
{
int32_t nativeUserId = -1;
if (userId.has_value()) {
nativeUserId = userId.value();
if (nativeUserId < 0) {
int32_t errCode = ErrorCode::ERROR_PARAMETER_CHECK_FAILED;
set_business_error(JsUtils::Convert(errCode), "userId must greater than 0");
return reinterpret_cast<uintptr_t>(nullptr);
}
}
OHOS::AppExecFwk::ElementName elementName;
int32_t ret =
OHOS::MiscServices::InputMethodController::GetInstance()->GetInputMethodConfig(elementName, nativeUserId);
if (ret != ErrorCode::NO_ERROR) {
taihe::set_business_error(JsUtils::Convert(ret), "failed to get input method config ability!");
IMSA_HILOGE("failed to get input method config ability!");
return reinterpret_cast<uintptr_t>(nullptr);
}
ani_object obj = OHOS::AppExecFwk::CommonFunAni::ConvertElementName(taihe::get_env(), elementName);
return reinterpret_cast<uintptr_t>(obj);
}
bool SwitchInputMethodWithTarget(InputMethodProperty const &target)
{
std::string packageName(target.name);
std::string id(target.id);
if (packageName.empty() || id.empty()) {
taihe::set_business_error(IMFErrorCode::EXCEPTION_PARAMCHECK, "packageName and methodId is empty");
IMSA_HILOGE("failed to switch input method, packageName or id is empty!");
return false;
}
int32_t errCode =
OHOS::MiscServices::InputMethodController::GetInstance()->SwitchInputMethod(SwitchTrigger::CURRENT_IME,
packageName, "");
if (errCode != ErrorCode::NO_ERROR) {
int32_t code = JsUtils::Convert(errCode);
std::string message = JsUtils::ToMessage(code);
taihe::set_business_error(code, message);
IMSA_HILOGE("failed to switch input method, code:%{public}d message: %{public}s", code, message.c_str());
return false;
}
IMSA_HILOGI("SwitchInputMethodWithTarget success.");
return true;
}
void SwitchInputMethodSync(string_view bundleName, optional_view<string> subtypeId)
{
std::string id;
if (subtypeId.has_value()) {
id = subtypeId.value();
}
int32_t errCode =
OHOS::MiscServices::InputMethodController::GetInstance()->SwitchInputMethod(SwitchTrigger::SYSTEM_APP,
std::string(bundleName), id);
if (errCode != ErrorCode::NO_ERROR) {
int32_t code = JsUtils::Convert(errCode);
std::string message = JsUtils::ToMessage(code);
taihe::set_business_error(code, message);
IMSA_HILOGE("failed to switch input method, code:%{public}d message: %{public}s", code, message.c_str());
return;
}
IMSA_HILOGI("SwitchInputMethodSync success.");
}
bool SwitchCurrentInputMethodSubtypeSync(InputMethodSubtype const &target)
{
std::string name(target.name);
std::string id(target.id);
int32_t errCode =
OHOS::MiscServices::InputMethodController::GetInstance()->SwitchInputMethod(SwitchTrigger::CURRENT_IME, name,
id);
if (errCode != ErrorCode::NO_ERROR) {
int32_t code = JsUtils::Convert(errCode);
std::string message = JsUtils::ToMessage(code);
taihe::set_business_error(code, message);
IMSA_HILOGE("failed to switch Current input method subtype, code:%{public}d message: %{public}s", code,
message.c_str());
return false;
}
IMSA_HILOGI("SwitchCurrentInputMethodSubtypeSync success.");
return true;
}
void SwitchInputMethodByUserId(string_view bundleName, optional_view<string> subtypeId, optional_view<int32_t> userId)
{
std::string id;
if (subtypeId.has_value()) {
id = subtypeId.value();
}
int32_t nativeUserId = -1;
if (userId.has_value()) {
nativeUserId = userId.value();
if (nativeUserId < 0) {
int32_t errCode = ErrorCode::ERROR_PARAMETER_CHECK_FAILED;
set_business_error(JsUtils::Convert(errCode), "userId must greater than 0");
return;
}
}
int32_t errCode = OHOS::MiscServices::InputMethodController::GetInstance()->SwitchInputMethod(
SwitchTrigger::SYSTEM_APP, std::string(bundleName), id, nativeUserId);
if (errCode != ErrorCode::NO_ERROR) {
int32_t code = JsUtils::Convert(errCode);
std::string message = JsUtils::ToMessage(code);
taihe::set_business_error(code, message);
IMSA_HILOGE("failed to switch input method, code:%{public}d message: %{public}s", code, message.c_str());
return;
}
IMSA_HILOGI("SwitchInputMethodByUserId success.");
}
void SetSimpleKeyboardEnabled(bool enable)
{
auto controller = OHOS::MiscServices::InputMethodController::GetInstance();
if (controller != nullptr) {
auto ret = controller->SetSimpleKeyboardEnabled(enable);
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("SetSimpleKeyboardEnabled failed:%{public}d.", ret);
return;
}
IMSA_HILOGI("SetSimpleKeyboardEnabled success.");
return;
}
IMSA_HILOGE("SetSimpleKeyboardEnabled failed, InputMethodController GetInstance failed");
}
bool SwitchCurrentInputMethodAndSubtypeSync(::ohos::inputMethod::InputMethodProperty const& inputMethodProperty,
::ohos::InputMethodSubtype::InputMethodSubtype const& inputMethodSubtype)
{
std::string name(inputMethodSubtype.name);
std::string id(inputMethodSubtype.id);
int32_t errCode = OHOS::MiscServices::InputMethodController::GetInstance()->SwitchInputMethod(
SwitchTrigger::CURRENT_IME, name, id);
if (errCode != ErrorCode::NO_ERROR) {
int32_t code = JsUtils::Convert(errCode);
std::string message = JsUtils::ToMessage(code);
taihe::set_business_error(code, message);
IMSA_HILOGE("failed to switch Current input method subtype, code:%{public}d message: %{public}s", code,
message.c_str());
return false;
}
IMSA_HILOGI("SwitchCurrentInputMethodAndSubtype success.");
return true;
}
void OnAttachmentDidFail(taihe::callback_view<void(AttachFailureReason_t data)> callback)
{
InputMethodImpl::GetInstance()->RegisterListener("attachmentDidFail", callback);
}
void OffAttachmentDidFail(taihe::optional_view<taihe::callback<void(AttachFailureReason_t data)>> callback)
{
InputMethodImpl::GetInstance()->UnRegisterListener("attachmentDidFail", callback);
}
}
TH_EXPORT_CPP_API_GetSetting(GetSetting);
TH_EXPORT_CPP_API_GetController(GetController);
TH_EXPORT_CPP_API_GetDefaultInputMethod(GetDefaultInputMethod);
TH_EXPORT_CPP_API_GetDefaultInputMethodByUserId(GetDefaultInputMethodByUserId);
TH_EXPORT_CPP_API_GetCurrentInputMethod(GetCurrentInputMethod);
TH_EXPORT_CPP_API_GetCurrentInputMethodByUserId(GetCurrentInputMethodByUserId);
TH_EXPORT_CPP_API_GetCurrentInputMethodSubtype(GetCurrentInputMethodSubtype);
TH_EXPORT_CPP_API_GetCurrentInputMethodSubtypeByUserId(GetCurrentInputMethodSubtypeByUserId);
TH_EXPORT_CPP_API_GetSystemInputMethodConfigAbility(GetSystemInputMethodConfigAbility);
TH_EXPORT_CPP_API_GetSystemInputMethodConfigAbilityByUserId(GetSystemInputMethodConfigAbilityByUserId);
TH_EXPORT_CPP_API_SwitchInputMethodWithTarget(SwitchInputMethodWithTarget);
TH_EXPORT_CPP_API_SwitchInputMethodSync(SwitchInputMethodSync);
TH_EXPORT_CPP_API_SwitchCurrentInputMethodSubtypeSync(SwitchCurrentInputMethodSubtypeSync);
TH_EXPORT_CPP_API_SwitchInputMethodByUserId(SwitchInputMethodByUserId);
TH_EXPORT_CPP_API_SetSimpleKeyboardEnabled(SetSimpleKeyboardEnabled);
TH_EXPORT_CPP_API_SwitchCurrentInputMethodAndSubtypeSync(SwitchCurrentInputMethodAndSubtypeSync);
TH_EXPORT_CPP_API_OnAttachmentDidFail(OnAttachmentDidFail);
TH_EXPORT_CPP_API_OffAttachmentDidFail(OffAttachmentDidFail);