diff --git a/bundle.json b/bundle.json index f01a865e71e7e5a0b1162f94c96e2d6742fc2feb..ede373559f79ca2abfcba950e74d2a24cf5872cd 100644 --- a/bundle.json +++ b/bundle.json @@ -125,6 +125,15 @@ }, { "name": "//base/inputmethod/imf/frameworks/kits/extension_cj:cj_inputmethod_extension_ffi" + }, + { + "name": "//base/inputmethod/imf/interfaces/kits/js:extra_config_napi", + "header": { + "header_files": [ + "extra_config_napi.h" + ], + "header_base": "//base/inputmethod/imf/interfaces/kits/js/" + } } ], "test": [ diff --git a/frameworks/js/napi/inputmethodability/BUILD.gn b/frameworks/js/napi/inputmethodability/BUILD.gn index 31622c658b02128d970608bff9b98849bddbc0a7..afac975543d7d21bcf4e3f7376bb14e249b1c97c 100644 --- a/frameworks/js/napi/inputmethodability/BUILD.gn +++ b/frameworks/js/napi/inputmethodability/BUILD.gn @@ -23,6 +23,7 @@ config("inputmethodengine_native_config") { "${inputmethod_path}/frameworks/native/inputmethod_ability/include", "${inputmethod_path}/frameworks/native/inputmethod_controller/include", "${inputmethod_path}/interfaces/inner_api/inputmethod_controller/include", + "${inputmethod_path}/interfaces/kits/js", ] ldflags = [ "-Wl,--exclude-libs=ALL" ] cflags_cc = [ @@ -76,6 +77,7 @@ ohos_shared_library("inputmethodengine") { "${inputmethod_path}/interfaces/inner_api/inputmethod_ability:input_control_channel_proxy", "${inputmethod_path}/interfaces/inner_api/inputmethod_ability:inputmethod_ability", "${inputmethod_path}/services/json:imf_json_static", + "${inputmethod_path}/interfaces/kits/js:extra_config_napi", ] external_deps = [ diff --git a/frameworks/js/napi/inputmethodability/js_text_input_client_engine.cpp b/frameworks/js/napi/inputmethodability/js_text_input_client_engine.cpp index 0bac05f5aae9f57aa2947b1c1b06f5de1dd05c03..5d193c4441d39afc2051659ce6e1fad6db4e447d 100644 --- a/frameworks/js/napi/inputmethodability/js_text_input_client_engine.cpp +++ b/frameworks/js/napi/inputmethodability/js_text_input_client_engine.cpp @@ -16,6 +16,7 @@ #include "js_text_input_client_engine.h" #include "event_checker.h" +#include "extra_config_napi.h" #include "input_method_ability.h" #include "inputmethod_trace.h" #include "js_callback_handler.h" @@ -1164,6 +1165,36 @@ bool JsRange::Read(napi_env env, napi_value jsObject, Range &nativeObject) return ret; } +bool JsExtraConfigInfo::Write(napi_env env, napi_value &jsObject, const ExtraConfig &nativeObject) +{ + napi_value jsExtraConfig = nullptr; + auto status = napi_create_object(env, &jsExtraConfig); + if (status != napi_ok) { + return false; + } + status = JsExtraConfig::GetJsExtraConfig(env, nativeObject, jsExtraConfig); + if (status != napi_ok) { + return false; + } + std::string name = "extraConfig"; + return napi_set_named_property(env, jsObject, name.c_str(), jsExtraConfig) == napi_ok; +} + +bool JsExtraConfigInfo::Read(napi_env env, napi_value jsObject, ExtraConfig &nativeObject) +{ + napi_valuetype valueType = napi_undefined; + napi_status status = napi_typeof(env, jsObject, &valueType); + CHECK_RETURN(valueType != napi_undefined, "napi_typeof error", false); + + napi_value value = nullptr; + std::string name = "extraConfig"; + status = napi_get_named_property(env, jsObject, name.c_str(), &value); + CHECK_RETURN(status == napi_ok, "ExtraConfig get_named_property", false); + status = JsExtraConfig::GetValue(env, value, nativeObject); + CHECK_RETURN(status == napi_ok, "ExtraConfig covert failed", false); + return true; +} + napi_value JsInputAttribute::Write(napi_env env, const InputAttribute &nativeObject) { napi_value jsObject = nullptr; @@ -1186,6 +1217,7 @@ napi_value JsInputAttribute::Write(napi_env env, const InputAttribute &nativeObj if (InputMethodAbility::GetInstance().IsSystemApp()) { ret = ret && JsUtil::Object::WriteProperty(env, jsObject, "fluidLightMode", nativeObject.fluidLightMode); } + ret = ret && JsExtraConfigInfo::Write(env, jsObject, nativeObject.extraConfig); return ret ? jsObject : JsUtil::Const::Null(env); } @@ -1212,6 +1244,7 @@ bool JsInputAttribute::Read(napi_env env, napi_value jsObject, InputAttribute &n if (InputMethodAbility::GetInstance().IsSystemApp()) { ret = ret && JsUtil::Object::ReadProperty(env, jsObject, "fluidLightMode", nativeObject.fluidLightMode); } + ret = ret && JsExtraConfigInfo::Read(env, jsObject, nativeObject.extraConfig); return ret; } diff --git a/frameworks/js/napi/inputmethodability/js_text_input_client_engine.h b/frameworks/js/napi/inputmethodability/js_text_input_client_engine.h index 2cbefdba6264a2e8a4013ad9c10d013d43a2b7bc..2f6ab8b9b8e5e8441511d2848eab409f7b03df54 100644 --- a/frameworks/js/napi/inputmethodability/js_text_input_client_engine.h +++ b/frameworks/js/napi/inputmethodability/js_text_input_client_engine.h @@ -58,6 +58,11 @@ struct JsRange { static bool Read(napi_env env, napi_value jsObject, Range &nativeObject); }; +struct JsExtraConfigInfo { + static bool Write(napi_env env, napi_value &jsObject, const ExtraConfig &nativeObject); + static bool Read(napi_env env, napi_value jsObject, ExtraConfig &nativeObject); +}; + struct JsInputAttribute { static napi_value Write(napi_env env, const InputAttribute &nativeObject); static bool Read(napi_env env, napi_value jsObject, InputAttribute &nativeObject); diff --git a/frameworks/js/napi/inputmethodclient/js_utils.h b/frameworks/js/napi/inputmethodclient/js_utils.h index 71797468f739718b8eeefa501cfaece793387c98..4de5a3b10daad4fea4f43fa74b9b76cbf1866f56 100644 --- a/frameworks/js/napi/inputmethodclient/js_utils.h +++ b/frameworks/js/napi/inputmethodclient/js_utils.h @@ -19,6 +19,7 @@ #include #include "ability.h" +#include "extra_config.h" #include "global.h" #include "input_method_panel.h" #include "input_method_utils.h" diff --git a/frameworks/kits/extra_config/extra_config_napi.cpp b/frameworks/kits/extra_config/extra_config_napi.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e5d10f7e8a0c3133944f84bfbd531c1af0c39fc9 --- /dev/null +++ b/frameworks/kits/extra_config/extra_config_napi.cpp @@ -0,0 +1,154 @@ +/* + * 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 "extra_config_napi.h" +#include "js_utils.h" + +namespace OHOS { +namespace MiscServices { +napi_status JsExtraConfig::GetValue(napi_env env, napi_value in, ExtraConfig &out, uint32_t maxLen) +{ + if (maxLen > MAX_EXTRA_CONFIG_SIZE) { + return napi_generic_failure; + } + napi_valuetype type = napi_undefined; + napi_status status = napi_typeof(env, in, &type); + CHECK_RETURN(type != napi_undefined, "param is undefined.", napi_generic_failure); + + napi_value propType = nullptr; + status = napi_get_named_property(env, in, "customSettings", &propType); + CHECK_RETURN((status == napi_ok), "no property customSettings ", status); + return GetValue(env, propType, out.customSettings, maxLen); +} + +napi_status JsExtraConfig::GetValue(napi_env env, napi_value in, CustomSettings &out, uint32_t maxLen) +{ + napi_valuetype type = napi_undefined; + napi_status status = napi_typeof(env, in, &type); + CHECK_RETURN(type != napi_undefined, "param is undefined.", napi_generic_failure); + + napi_value keys = nullptr; + napi_get_property_names(env, in, &keys); + uint32_t arrLen = 0; + status = napi_get_array_length(env, keys, &arrLen); + if (status != napi_ok) { + IMSA_HILOGE("napi_get_array_length error"); + return status; + } + IMSA_HILOGD("length : %{public}u", arrLen); + uint32_t totalSize = 0; + for (size_t iter = 0; iter < arrLen; ++iter) { + napi_value key = nullptr; + status = napi_get_element(env, keys, iter, &key); + CHECK_RETURN(status == napi_ok, "napi_get_element error", status); + + napi_value value = nullptr; + status = napi_get_property(env, in, key, &value); + CHECK_RETURN(status == napi_ok, "napi_get_property error", status); + + std::string keyStr; + status = JsUtils::GetValue(env, key, keyStr); + CHECK_RETURN(status == napi_ok, "GetValue keyStr error", status); + uint32_t keySize = keyStr.size(); + + CustomValueType customSettingData; + uint32_t valueSize = 0; + status = GetValue(env, value, customSettingData, valueSize); + CHECK_RETURN(status == napi_ok, "GetValue customSettingData error", status); + totalSize = totalSize + keySize + valueSize; + out.emplace(keyStr, customSettingData); + } + if (totalSize > maxLen) { + out.clear(); + IMSA_HILOGE("totalSize : %{public}d", totalSize); + return napi_generic_failure; + } + return status; +} + +napi_status JsExtraConfig::GetValue(napi_env env, napi_value in, CustomValueType &out, uint32_t &valueSize) +{ + napi_valuetype valueType = napi_undefined; + napi_status status = napi_typeof(env, in, &valueType); + CHECK_RETURN(status == napi_ok, "napi_typeof error", napi_generic_failure); + if (valueType == napi_string) { + std::string customSettingStr; + status = JsUtils::GetValue(env, in, customSettingStr); + CHECK_RETURN(status == napi_ok, "GetValue napi_string error", napi_generic_failure); + valueSize = customSettingStr.size(); + out.emplace(customSettingStr); + } else if (valueType == napi_boolean) { + bool customSettingBool = false; + status = JsUtils::GetValue(env, in, customSettingBool); + CHECK_RETURN(status == napi_ok, "GetValue napi_boolean error", napi_generic_failure); + valueSize = sizeof(bool); + out.emplace(customSettingBool); + } else if (valueType == napi_number) { + int32_t customSettingInt = 0; + status = JsUtils::GetValue(env, in, customSettingInt); + CHECK_RETURN(status == napi_ok, "GetValue napi_number error", napi_generic_failure); + valueSize = sizeof(int32_t); + out.emplace(customSettingInt); + } else { + CHECK_RETURN(false, "value type must be string | boolean | number", napi_generic_failure); + } + return status; +} + +napi_status JsExtraConfig::GetJsExtraConfig(napi_env env, const ExtraConfig &in, napi_value &out) +{ + napi_value jsObject = nullptr; + CHECK_RETURN(napi_create_object(env, &jsObject) == napi_ok, "create_object error", napi_generic_failure); + for (const auto &iter : in.customSettings) { + size_t idx = iter.second.index(); + napi_value value = nullptr; + if (idx == static_cast(CustomValueTypeValue::CUSTOM_VALUE_TYPE_STRING)) { + auto stringValue = std::get_if(&iter.second); + CHECK_RETURN(stringValue != nullptr, "stringValue is nullptr", napi_generic_failure); + CHECK_RETURN(napi_create_string_utf8(env, (*stringValue).c_str(), (*stringValue).size(), &value) + == napi_ok, "create_string_utf8 error", napi_generic_failure); + } else if (idx == static_cast(CustomValueTypeValue::CUSTOM_VALUE_TYPE_BOOL)) { + auto boolValue = std::get_if(&iter.second); + CHECK_RETURN(boolValue != nullptr, "boolValue is nullptr", napi_generic_failure); + CHECK_RETURN(napi_get_boolean(env, *boolValue, &value) == napi_ok, "get_boolean error", + napi_generic_failure); + } else if (idx == static_cast(CustomValueTypeValue::CUSTOM_VALUE_TYPE_NUMBER)) { + auto numberValue = std::get_if(&iter.second); + CHECK_RETURN(numberValue != nullptr, "numberValue is nullptr", napi_generic_failure); + CHECK_RETURN(napi_create_int32(env, *numberValue, &value) == napi_ok, "create_int32 error", + napi_generic_failure); + } + CHECK_RETURN(napi_set_named_property(env, jsObject, iter.first.c_str(), value) == napi_ok, + "set_named_property error", napi_generic_failure); + } + std::string name = "customSettings"; + CHECK_RETURN(napi_set_named_property(env, out, name.c_str(), jsObject) == napi_ok, "set_named_property error", + napi_generic_failure); + return napi_ok; +} + +napi_status JsExtraConfig::CreateExtraConfig(napi_env env, const ExtraConfig &in, napi_value &out) +{ + return GetJsExtraConfig(env, in, out); +} + +napi_status JsExtraConfig::GetExtraConfig(napi_env env, napi_value in, ExtraConfig &out, uint32_t maxLen) +{ + auto status = GetValue(env, in, out, maxLen); + CHECK_RETURN(status == napi_ok, "ExtraConfig convert failed", status); + return napi_ok; +} +} // namespace MiscServices +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/native/inputmethod_controller/include/extra_config.h b/frameworks/native/inputmethod_controller/include/extra_config.h new file mode 100644 index 0000000000000000000000000000000000000000..3d47f0f01fd6ebeaf6ce6599c8ec342d97a30284 --- /dev/null +++ b/frameworks/native/inputmethod_controller/include/extra_config.h @@ -0,0 +1,44 @@ +/* + * 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. + */ + +#ifndef INPUTMETHOD_EXTRA_CONFIG_H +#define INPUTMETHOD_EXTRA_CONFIG_H + +#include +#include +#include +#include + +namespace OHOS { +namespace MiscServices { + +enum CustomValueTypeValue : int32_t { + CUSTOM_VALUE_TYPE_STRING = 0, + CUSTOM_VALUE_TYPE_NUMBER, + CUSTOM_VALUE_TYPE_BOOL +}; +using CustomValueType = std::variant; +using CustomSettings = std::unordered_map; +struct ExtraConfig { + CustomSettings customSettings = {}; + bool operator==(const ExtraConfig &info) const + { + return customSettings == info.customSettings; + } +}; +} // namespace MiscServices +} // namespace OHOS + +#endif // INPUTMETHOD_EXTRA_CONFIG_H \ No newline at end of file diff --git a/frameworks/native/inputmethod_controller/include/input_attribute.h b/frameworks/native/inputmethod_controller/include/input_attribute.h index 8b1e6151b1a19a3fdc95f0f60492861a6164e56e..653ef16c612700959b220803d9856ebf4ec1dad6 100644 --- a/frameworks/native/inputmethod_controller/include/input_attribute.h +++ b/frameworks/native/inputmethod_controller/include/input_attribute.h @@ -19,6 +19,7 @@ #include #include +#include "extra_config.h" #include "parcel.h" namespace OHOS { @@ -30,6 +31,91 @@ enum class CapitalizeMode : int32_t { CHARACTERS }; +struct ExtraConfigInner : public Parcelable { + CustomSettings customSettings = {}; + bool ReadFromParcel(Parcel &in) + { + uint32_t size = in.ReadUint32(); + if (size == 0) { + return true; + } + customSettings.clear(); + + for (uint32_t index = 0; index < size; index++) { + std::string key = in.ReadString(); + int32_t valueType = in.ReadInt32(); + if (valueType == static_cast(CustomValueTypeValue::CUSTOM_VALUE_TYPE_STRING)) { + std::string strValue = in.ReadString(); + customSettings.insert(std::make_pair(key, strValue)); + } else if (valueType == static_cast(CustomValueTypeValue::CUSTOM_VALUE_TYPE_BOOL)) { + bool boolValue = false; + boolValue = in.ReadBool(); + customSettings.insert(std::make_pair(key, boolValue)); + } else if (valueType == static_cast(CustomValueTypeValue::CUSTOM_VALUE_TYPE_NUMBER)) { + int32_t intValue = 0; + intValue = in.ReadInt32(); + customSettings.insert(std::make_pair(key, intValue)); + } + } + return true; + } + + bool Marshalling(Parcel &out) const + { + if (!out.WriteUint32(customSettings.size())) { + return false; + } + if (customSettings.size() == 0) { + return true; + } + for (auto &it : customSettings) { + std::string key = it.first; + if (!out.WriteString(key)) { + return false; + } + auto value = it.second; + bool ret = false; + int32_t valueType = static_cast(value.index()); + if (!out.WriteInt32(valueType)) { + return false; + } + if (valueType == static_cast(CustomValueTypeValue::CUSTOM_VALUE_TYPE_STRING)) { + auto stringValue = std::get_if(&value); + if (stringValue != nullptr) { + ret = out.WriteString(*stringValue); + } + } else if (valueType == static_cast(CustomValueTypeValue::CUSTOM_VALUE_TYPE_BOOL)) { + auto boolValue = std::get_if(&value); + if (boolValue != nullptr) { + ret = out.WriteBool(*boolValue); + } + } else if (valueType == static_cast(CustomValueTypeValue::CUSTOM_VALUE_TYPE_NUMBER)) { + auto numberValue = std::get_if(&value); + if (numberValue != nullptr) { + ret = out.WriteInt32(*numberValue); + } + } + if (ret == false) { + return ret; + } + } + return true; + } + static ExtraConfigInner *Unmarshalling(Parcel &in) + { + ExtraConfigInner *data = new (std::nothrow) ExtraConfigInner(); + if (data && !data->ReadFromParcel(in)) { + delete data; + data = nullptr; + } + return data; + } + bool operator==(const ExtraConfigInner &info) const + { + return customSettings == info.customSettings; + } +}; + struct InputAttribute { static const int32_t PATTERN_TEXT = 0x00000001; static const int32_t PATTERN_PASSWORD = 0x00000007; @@ -51,6 +137,7 @@ struct InputAttribute { std::u16string abilityName { u"" }; CapitalizeMode capitalizeMode = CapitalizeMode::NONE; bool needAutoInputNumkey { false }; // number keys need to be automatically handled by imf + ExtraConfig extraConfig = {}; bool GetSecurityFlag() const { @@ -83,6 +170,7 @@ struct InputAttribute { << "immersiveMode:" << immersiveMode << "windowId:" << windowId << "callingDisplayId:" << callingDisplayId << "needNumInput: " << needAutoInputNumkey + << "extraConfig.customSettings.size: " << extraConfig.customSettings.size() << "]"; return ss.str(); } @@ -108,6 +196,7 @@ struct InputAttributeInner : public Parcelable { std::u16string abilityName { u"" }; CapitalizeMode capitalizeMode = CapitalizeMode::NONE; bool needAutoInputNumkey { false }; // number keys need to be automatically handled by imf + ExtraConfigInner extraConfig; bool ReadFromParcel(Parcel &in) { @@ -130,6 +219,11 @@ struct InputAttributeInner : public Parcelable { needAutoInputNumkey = in.ReadBool(); gradientMode = in.ReadInt32(); fluidLightMode = in.ReadInt32(); + std::unique_ptr extraConfigInfo(in.ReadParcelable()); + if (extraConfigInfo == nullptr) { + return false; + } + extraConfig = *extraConfigInfo; return true; } @@ -164,6 +258,9 @@ struct InputAttributeInner : public Parcelable { ret = ret && out.WriteBool(needAutoInputNumkey); ret = ret && out.WriteInt32(gradientMode); ret = ret && out.WriteInt32(fluidLightMode); + if (!out.WriteParcelable(&extraConfig)) { + return false; + } return ret; } @@ -177,7 +274,7 @@ struct InputAttributeInner : public Parcelable { return data; } - bool operator==(const InputAttribute &info) const + bool operator==(const InputAttributeInner &info) const { return inputPattern == info.inputPattern && enterKeyType == info.enterKeyType && inputOption == info.inputOption && isTextPreviewSupported == info.isTextPreviewSupported; diff --git a/frameworks/native/inputmethod_controller/include/input_method_tools.h b/frameworks/native/inputmethod_controller/include/input_method_tools.h index 43efedeccb9564f193ae042b8b8baf8f74413760..33d02f1c895d81d9ffa7827f43bc51fb356b21ab 100644 --- a/frameworks/native/inputmethod_controller/include/input_method_tools.h +++ b/frameworks/native/inputmethod_controller/include/input_method_tools.h @@ -27,6 +27,8 @@ class InputMethodTools { public: static InputMethodTools &GetInstance(); ~InputMethodTools() = default; + ExtraConfigInner ExtraConfigToInner(const ExtraConfig &extraConfig); + ExtraConfig InnerToExtraConfig(const ExtraConfigInner &inner); InputAttributeInner AttributeToInner(const InputAttribute &attribute); InputAttribute InnerToAttribute(const InputAttributeInner &inner); CursorInfoInner CursorInfoToInner(const CursorInfo &cursorInfo); diff --git a/frameworks/native/inputmethod_controller/src/input_method_tools.cpp b/frameworks/native/inputmethod_controller/src/input_method_tools.cpp index 814e638ba573531c71da7b0f024cd0cbf5b27af8..b5277e64ef2f306551cd3a6b4cc0ce17874d86cf 100644 --- a/frameworks/native/inputmethod_controller/src/input_method_tools.cpp +++ b/frameworks/native/inputmethod_controller/src/input_method_tools.cpp @@ -24,6 +24,20 @@ InputMethodTools &InputMethodTools::GetInstance() return instance; } +ExtraConfigInner InputMethodTools::ExtraConfigToInner(const ExtraConfig &extraConfig) +{ + ExtraConfigInner inner; + inner.customSettings = extraConfig.customSettings; + return inner; +} + +ExtraConfig InputMethodTools::InnerToExtraConfig(const ExtraConfigInner &inner) +{ + ExtraConfig extraConfig; + extraConfig.customSettings = inner.customSettings; + return extraConfig; +} + InputAttributeInner InputMethodTools::AttributeToInner(const InputAttribute &attribute) { InputAttributeInner inner; @@ -41,6 +55,7 @@ InputAttributeInner InputMethodTools::AttributeToInner(const InputAttribute &att inner.abilityName = attribute.abilityName; inner.capitalizeMode = attribute.capitalizeMode; inner.needAutoInputNumkey = attribute.needAutoInputNumkey; + inner.extraConfig = ExtraConfigToInner(attribute.extraConfig); return inner; } @@ -61,6 +76,7 @@ InputAttribute InputMethodTools::InnerToAttribute(const InputAttributeInner &inn inputAttribute.abilityName = inner.abilityName; inputAttribute.capitalizeMode = inner.capitalizeMode; inputAttribute.needAutoInputNumkey = inner.needAutoInputNumkey; + inputAttribute.extraConfig = InnerToExtraConfig(inner.extraConfig); return inputAttribute; } diff --git a/interfaces/kits/js/BUILD.gn b/interfaces/kits/js/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..3531f5acdb7ed45349f9f1261269f32bc093c7f8 --- /dev/null +++ b/interfaces/kits/js/BUILD.gn @@ -0,0 +1,60 @@ +# 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. + +import("//base/inputmethod/imf/inputmethod.gni") +import("//build/ohos.gni") + +config("extra_config") { + visibility = [ ":*" ] + include_dirs = [ + "include", + "${inputmethod_path}/frameworks/native/inputmethod_controller/include", + "${inputmethod_path}/frameworks/js/napi/inputmethodclient", + "${inputmethod_path}/interfaces/kits/js", + ] +} + +ohos_shared_library("extra_config_napi") { + branch_protector_ret = "pac_ret" + sanitize = { + boundary_sanitize = true + cfi = true + cfi_cross_dso = true + debug = false + integer_overflow = true + ubsan = true + } + sources = [ + "${inputmethod_path}/frameworks/js/napi/inputmethodclient/js_utils.cpp", + "${inputmethod_path}/frameworks/kits/extra_config/extra_config_napi.cpp", + ] + + configs = [ ":extra_config" ] + + deps = [ + "${inputmethod_path}/common:inputmethod_common", + "${inputmethod_path}/frameworks/js/napi/common:inputmethod_js_common", + ] + + external_deps = [ + "ability_runtime:abilitykit_native", + "c_utils:utils", + "hilog:libhilog", + ] + + public_configs = [ ":extra_config" ] + + innerapi_tags = [ "platformsdk" ] + subsystem_name = "inputmethod" + part_name = "imf" +} diff --git a/interfaces/kits/js/extra_config_napi.h b/interfaces/kits/js/extra_config_napi.h new file mode 100644 index 0000000000000000000000000000000000000000..cd6064802bfd8be81292fb12da36e2d3370472d4 --- /dev/null +++ b/interfaces/kits/js/extra_config_napi.h @@ -0,0 +1,42 @@ +/* + * 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. + */ + +#ifndef INTERFACE_JS_EXTRA_CONFIG +#define INTERFACE_JS_EXTRA_CONFIG + +#include "extra_config.h" +#include "napi/native_api.h" + +namespace OHOS { +namespace MiscServices { +constexpr uint32_t DEFAULT_MAX_EXTRA_CONFIG_SIZE = 128 * 1024; // 128K +constexpr uint32_t MAX_EXTRA_CONFIG_SIZE = 1024 * 1024; // 1M + +class JsExtraConfig { +public: + JsExtraConfig() = default; + ~JsExtraConfig() = default; + static napi_status GetValue(napi_env env, napi_value in, ExtraConfig &out, uint32_t maxLen = MAX_EXTRA_CONFIG_SIZE); + static napi_status GetValue(napi_env env, napi_value in, CustomSettings &out, + uint32_t maxLen = MAX_EXTRA_CONFIG_SIZE); + static napi_status GetValue(napi_env env, napi_value in, CustomValueType &out, uint32_t &valueSize); + static napi_status GetJsExtraConfig(napi_env env, const ExtraConfig &in, napi_value &out); + static napi_status CreateExtraConfig(napi_env env, const ExtraConfig &in, napi_value &out); + static napi_status GetExtraConfig(napi_env env, napi_value in, ExtraConfig &out, + uint32_t maxLen = DEFAULT_MAX_EXTRA_CONFIG_SIZE); +}; +} // namespace MiscServices +} // namespace OHOS +#endif // INTERFACE_JS_EXTRA_CONFIG \ No newline at end of file diff --git a/test/unittest/cpp_test/src/input_method_ability_test.cpp b/test/unittest/cpp_test/src/input_method_ability_test.cpp index 6e80860706953d1c7fc233aa44ccaaedc52283f4..8267a15d5c3fc6bd169daf2b1dffa73c1a7d8eff 100644 --- a/test/unittest/cpp_test/src/input_method_ability_test.cpp +++ b/test/unittest/cpp_test/src/input_method_ability_test.cpp @@ -364,6 +364,22 @@ HWTEST_F(InputMethodAbilityTest, testSerializedInputAttribute_WithSpecificBundle EXPECT_EQ(inAttribute.bundleName, ret->bundleName); } +/** + * @tc.name: testSerializedInputAttribute + * @tc.desc: Checkout the serialization of InputAttribute. + * @tc.type: FUNC + */ +HWTEST_F(InputMethodAbilityTest, testSerializedExtraConfig, TestSize.Level0) +{ + ExtraConfigInner extraConfig; + extraConfig.customSettings.emplace("key", true); + MessageParcel data; + EXPECT_TRUE(extraConfig.Marshalling(data)); + auto ret = ExtraConfigInner::Unmarshalling(data); + EXPECT_NE(ret, nullptr); + EXPECT_EQ(extraConfig.customSettings["key"], ret->customSettings["key"]); +} + /** * @tc.name: testShowKeyboardInputMethodCoreProxy * @tc.desc: Test InputMethodCoreProxy ShowKeyboard diff --git a/test/unittest/cpp_test/src/input_method_controller_test.cpp b/test/unittest/cpp_test/src/input_method_controller_test.cpp index 5df383aabf210c2a5a2902c97bf091a4e65881a2..bb733df1c0d8fbec371e07357faaf0d5ae3ec770 100644 --- a/test/unittest/cpp_test/src/input_method_controller_test.cpp +++ b/test/unittest/cpp_test/src/input_method_controller_test.cpp @@ -1126,6 +1126,7 @@ HWTEST_F(InputMethodControllerTest, testOnEditorAttributeChanged02, TestSize.Lev InputAttribute attribute = { .inputPattern = static_cast(TextInputType::DATETIME), .enterKeyType = static_cast(EnterKeyType::GO), .isTextPreviewSupported = true }; + attribute.extraConfig.customSettings.emplace("key", "test"); auto ret = inputMethodController_->Attach(textListener_, false, attribute); EXPECT_EQ(ret, ErrorCode::NO_ERROR); Configuration info; @@ -1136,6 +1137,7 @@ HWTEST_F(InputMethodControllerTest, testOnEditorAttributeChanged02, TestSize.Lev EXPECT_EQ(InputMethodControllerTest::inputAttribute_.inputPattern, static_cast(info.GetTextInputType())); EXPECT_EQ(InputMethodControllerTest::inputAttribute_.enterKeyType, static_cast(info.GetEnterKeyType())); EXPECT_EQ(InputMethodControllerTest::inputAttribute_.isTextPreviewSupported, attribute.isTextPreviewSupported); + EXPECT_EQ(InputMethodControllerTest::inputAttribute_.extraConfig, attribute.extraConfig); } /** @@ -2020,6 +2022,7 @@ HWTEST_F(InputMethodControllerTest, testUpdateTextPreviewState, TestSize.Level0) IMSA_HILOGI("IMC testUpdateTextPreviewState Test START"); ASSERT_NE(inputMethodController_, nullptr); inputMethodController_->textConfig_.inputAttribute.isTextPreviewSupported = false; + inputMethodController_->textConfig_.inputAttribute.extraConfig.customSettings.emplace("key", "test"); inputMethodController_->UpdateTextPreviewState(true); EXPECT_TRUE(inputMethodController_->textConfig_.inputAttribute.isTextPreviewSupported); inputMethodController_->UpdateTextPreviewState(true);