Merge branch 'master' of gitee.com:openharmony/inputmethod_imf into master

Signed-off-by: 赵凌岚 <zhaolinglan@huawei.com>
This commit is contained in:
赵凌岚 2023-04-02 06:56:54 +00:00 committed by Gitee
commit 52672a1c30
35 changed files with 2201 additions and 724 deletions

View File

@ -0,0 +1,286 @@
/*
* Copyright (c) 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.
*/
#ifndef OHOS_INPUTMETHOD_IMF_FRAMEWORKS_COMMON_CONCURRENT_MAP_H
#define OHOS_INPUTMETHOD_IMF_FRAMEWORKS_COMMON_CONCURRENT_MAP_H
#include <functional>
#include <map>
#include <mutex>
namespace OHOS {
template<typename _Key, typename _Tp>
class ConcurrentMap {
template<typename _First, typename... _Rest>
static _First First();
public:
using map_type = typename std::map<_Key, _Tp>;
using filter_type = typename std::function<bool(map_type &)>;
using key_type = typename std::map<_Key, _Tp>::key_type;
using mapped_type = typename std::map<_Key, _Tp>::mapped_type;
using value_type = typename std::map<_Key, _Tp>::value_type;
using size_type = typename std::map<_Key, _Tp>::size_type;
using reference = typename std::map<_Key, _Tp>::reference;
using const_reference = typename std::map<_Key, _Tp>::const_reference;
ConcurrentMap() = default;
~ConcurrentMap()
{
Clear();
}
ConcurrentMap(const ConcurrentMap &other)
{
operator=(std::move(other));
}
ConcurrentMap &operator=(const ConcurrentMap &other) noexcept
{
if (this == &other) {
return *this;
}
auto tmp = other.Clone();
std::lock_guard<decltype(mutex_)> lock(mutex_);
entries_ = std::move(tmp);
return *this;
}
ConcurrentMap(ConcurrentMap &&other) noexcept
{
operator=(std::move(other));
}
ConcurrentMap &operator=(ConcurrentMap &&other) noexcept
{
if (this == &other) {
return *this;
}
auto tmp = other.Steal();
std::lock_guard<decltype(mutex_)> lock(mutex_);
entries_ = std::move(tmp);
return *this;
}
bool Emplace() noexcept
{
std::lock_guard<decltype(mutex_)> lock(mutex_);
auto it = entries_.emplace();
return it.second;
}
template<typename... _Args>
typename std::enable_if<!std::is_convertible_v<decltype(First<_Args...>()), filter_type>, bool>::type
Emplace(_Args &&...__args) noexcept
{
std::lock_guard<decltype(mutex_)> lock(mutex_);
auto it = entries_.emplace(std::forward<_Args>(__args)...);
return it.second;
}
template<typename _Filter, typename... _Args>
typename std::enable_if<std::is_convertible_v<_Filter, filter_type>, bool>::type
Emplace(const _Filter &filter, _Args &&...__args) noexcept
{
std::lock_guard<decltype(mutex_)> lock(mutex_);
if (!filter(entries_)) {
return false;
}
auto it = entries_.emplace(std::forward<_Args>(__args)...);
return it.second;
}
std::pair<bool, mapped_type> Find(const key_type &key) const noexcept
{
std::lock_guard<decltype(mutex_)> lock(mutex_);
auto it = entries_.find(key);
if (it == entries_.end()) {
return std::pair { false, mapped_type() };
}
return std::pair { true, it->second };
}
bool Contains(const key_type &key) const noexcept
{
std::lock_guard<decltype(mutex_)> lock(mutex_);
return (entries_.find(key) != entries_.end());
}
template <typename _Obj>
bool InsertOrAssign(const key_type &key, _Obj &&obj) noexcept
{
std::lock_guard<decltype(mutex_)> lock(mutex_);
auto it = entries_.insert_or_assign(key, std::forward<_Obj>(obj));
return it.second;
}
bool Insert(const key_type &key, const mapped_type &value) noexcept
{
std::lock_guard<decltype(mutex_)> lock(mutex_);
auto it = entries_.insert(value_type { key, value });
return it.second;
}
size_type Erase(const key_type &key) noexcept
{
std::lock_guard<decltype(mutex_)> lock(mutex_);
return entries_.erase(key);
}
void Clear() noexcept
{
std::lock_guard<decltype(mutex_)> lock(mutex_);
return entries_.clear();
}
bool Empty() const noexcept
{
std::lock_guard<decltype(mutex_)> lock(mutex_);
return entries_.empty();
}
size_type Size() const noexcept
{
std::lock_guard<decltype(mutex_)> lock(mutex_);
return entries_.size();
}
// The action`s return true means meeting the erase condition
// The action`s return false means not meeting the erase condition
size_type EraseIf(const std::function<bool(const key_type &key, mapped_type &value)> &action) noexcept
{
if (action == nullptr) {
return 0;
}
std::lock_guard<decltype(mutex_)> lock(mutex_);
#if __cplusplus > 201703L
auto count = std::erase_if(entries_,
[&action](value_type &value) -> bool { return action(value.first, value.second); });
#else
auto count = entries_.size();
for (auto it = entries_.begin(); it != entries_.end();) {
if (action((*it).first, (*it).second)) {
it = entries_.erase(it);
} else {
++it;
}
}
count -= entries_.size();
#endif
return count;
}
mapped_type &operator[](const key_type &key) noexcept
{
std::lock_guard<decltype(mutex_)> lock(mutex_);
return entries_[key];
}
void ForEach(const std::function<bool(const key_type &, mapped_type &)> &action)
{
if (action == nullptr) {
return;
}
std::lock_guard<decltype(mutex_)> lock(mutex_);
for (auto &[key, value] : entries_) {
if (action(key, value)) {
break;
}
}
}
void ForEachCopies(const std::function<bool(const key_type &, mapped_type &)> &action)
{
if (action == nullptr) {
return;
}
auto entries = Clone();
for (auto &[key, value] : entries) {
if (action(key, value)) {
break;
}
}
}
// The action's return value means that the element is keep in map or not; true means keeping, false means removing.
bool Compute(const key_type &key, const std::function<bool(const key_type &, mapped_type &)> &action)
{
if (action == nullptr) {
return false;
}
std::lock_guard<decltype(mutex_)> lock(mutex_);
auto it = entries_.find(key);
if (it == entries_.end()) {
auto result = entries_.emplace(key, mapped_type());
it = result.second ? result.first : entries_.end();
}
if (it == entries_.end()) {
return false;
}
if (!action(it->first, it->second)) {
entries_.erase(key);
}
return true;
}
// The action's return value means that the element is keep in map or not; true means keeping, false means removing.
bool ComputeIfPresent(const key_type &key, const std::function<bool(const key_type &, mapped_type &)> &action)
{
if (action == nullptr) {
return false;
}
std::lock_guard<decltype(mutex_)> lock(mutex_);
auto it = entries_.find(key);
if (it == entries_.end()) {
return false;
}
if (!action(key, it->second)) {
entries_.erase(key);
}
return true;
}
bool ComputeIfAbsent(const key_type &key, const std::function<mapped_type(const key_type &)> &action)
{
if (action == nullptr) {
return false;
}
std::lock_guard<decltype(mutex_)> lock(mutex_);
auto it = entries_.find(key);
if (it != entries_.end()) {
return false;
}
entries_.emplace(key, action(key));
return true;
}
private:
std::map<_Key, _Tp> Steal() noexcept
{
std::lock_guard<decltype(mutex_)> lock(mutex_);
return std::move(entries_);
}
std::map<_Key, _Tp> Clone() const noexcept
{
std::lock_guard<decltype(mutex_)> lock(mutex_);
return entries_;
}
private:
mutable std::recursive_mutex mutex_;
std::map<_Key, _Tp> entries_;
};
} // namespace OHOS
#endif // OHOS_INPUTMETHOD_IMF_FRAMEWORKS_COMMON_CONCURRENT_MAP_H

View File

@ -18,6 +18,7 @@ config("inputmethodengine_native_config") {
visibility = [ ":*" ]
include_dirs = [
"include",
"${inputmethod_path}/frameworks/common",
"${inputmethod_path}/frameworks/native/inputmethod_ability/include",
"${inputmethod_path}/frameworks/native/inputmethod_controller/include",
"${inputmethod_path}/interfaces/inner_api/inputmethod_controller/include",
@ -34,6 +35,7 @@ config("inputmethodengine_native_public_config") {
visibility = []
include_dirs = [
"include",
"${inputmethod_path}/frameworks/common",
"${inputmethod_path}/frameworks/js/napi/inputmethodclient",
"${inputmethod_path}/frameworks/js/napi/inputmethodability",
]
@ -49,7 +51,9 @@ ohos_shared_library("inputmethodengine") {
"js_input_method_engine_setting.cpp",
"js_keyboard_controller_engine.cpp",
"js_keyboard_delegate_setting.cpp",
"js_panel.cpp",
"js_text_input_client_engine.cpp",
"panel_listener_impl.cpp",
]
configs = [ ":inputmethodengine_native_config" ]
@ -62,6 +66,7 @@ ohos_shared_library("inputmethodengine") {
"hiviewdfx_hilog_native:libhilog",
"input:libmmi-client",
"ipc:ipc_core",
"napi:ace_napi",
]
public_configs = [ ":inputmethodengine_native_public_config" ]

View File

@ -21,8 +21,8 @@
#include "input_method_property.h"
#include "input_method_utils.h"
#include "js_keyboard_controller_engine.h"
#include "js_runtime_utils.h"
#include "js_text_input_client_engine.h"
#include "js_utils.h"
#include "napi/native_api.h"
#include "napi/native_node_api.h"
@ -79,6 +79,8 @@ napi_value JsInputMethodEngineSetting::Init(napi_env env, napi_value exports)
napi_property_descriptor properties[] = {
DECLARE_NAPI_FUNCTION("on", Subscribe),
DECLARE_NAPI_FUNCTION("off", UnSubscribe),
DECLARE_NAPI_FUNCTION("createPanel", CreatePanel),
DECLARE_NAPI_FUNCTION("destroyPanel", DestroyPanel),
};
napi_value cons = nullptr;
NAPI_CALL(env, napi_define_class(env, IMES_CLASS_NAME.c_str(), IMES_CLASS_NAME.size(), JsConstructor, nullptr,
@ -165,11 +167,6 @@ napi_value JsInputMethodEngineSetting::GetIMEInstance(napi_env env, napi_callbac
napi_value argv[ARGC_MAX] = { nullptr };
NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
if (argc != ARGC_ZERO) {
JsUtils::ThrowException(
env, IMFErrorCode::EXCEPTION_PARAMCHECK, "Wrong number of arguments, requires 0", TypeCode::TYPE_NONE);
return nullptr;
}
}
if (napi_get_reference_value(env, IMESRef_, &cons) != napi_ok) {
@ -190,13 +187,9 @@ napi_value JsInputMethodEngineSetting::MoveCursor(napi_env env, napi_callback_in
NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
NAPI_ASSERT(env, argc == 1, "Wrong number of arguments, requires 1");
napi_valuetype valuetype;
NAPI_CALL(env, napi_typeof(env, argv[ARGC_ZERO], &valuetype));
NAPI_ASSERT(env, valuetype == napi_number, "type is not a number");
int32_t number;
if (napi_get_value_int32(env, argv[ARGC_ZERO], &number) != napi_ok) {
IMSA_HILOGE("GetNumberProperty error");
int32_t number = 0;
if (JsUtils::GetValue(env, argv[ARGC_ZERO], number) != napi_ok) {
IMSA_HILOGE("Get number error");
}
InputMethodAbility::GetInstance()->MoveCursor(number);
@ -206,17 +199,6 @@ napi_value JsInputMethodEngineSetting::MoveCursor(napi_env env, napi_callback_in
return result;
}
std::string JsInputMethodEngineSetting::GetStringProperty(napi_env env, napi_value jsString)
{
char propValue[MAX_VALUE_LEN] = { 0 };
size_t propLen;
if (napi_get_value_string_utf8(env, jsString, propValue, MAX_VALUE_LEN, &propLen) != napi_ok) {
IMSA_HILOGE("GetStringProperty error");
return "";
}
return std::string(propValue);
}
void JsInputMethodEngineSetting::RegisterListener(
napi_value callback, std::string type, std::shared_ptr<JSCallbackObject> callbackObj)
{
@ -227,7 +209,7 @@ void JsInputMethodEngineSetting::RegisterListener(
}
auto callbacks = jsCbMap_[type];
bool ret = std::any_of(callbacks.begin(), callbacks.end(), [&callback](std::shared_ptr<JSCallbackObject> cb) {
return Equals(cb->env_, callback, cb->callback_, cb->threadId_);
return JsUtils::Equals(cb->env_, callback, cb->callback_, cb->threadId_);
});
if (ret) {
IMSA_HILOGE("JsInputMethodEngineListener::RegisterListener callback already registered!");
@ -254,7 +236,7 @@ void JsInputMethodEngineSetting::UnRegisterListener(napi_value callback, std::st
}
for (auto item = jsCbMap_[type].begin(); item != jsCbMap_[type].end(); item++) {
if (Equals((*item)->env_, callback, (*item)->callback_, (*item)->threadId_)) {
if (JsUtils::Equals((*item)->env_, callback, (*item)->callback_, (*item)->threadId_)) {
jsCbMap_[type].erase(item);
break;
}
@ -265,24 +247,6 @@ void JsInputMethodEngineSetting::UnRegisterListener(napi_value callback, std::st
}
}
JsInputMethodEngineSetting *JsInputMethodEngineSetting::GetNative(napi_env env, napi_callback_info info)
{
size_t argc = ARGC_MAX;
void *native = nullptr;
napi_value self = nullptr;
napi_value argv[ARGC_MAX] = { nullptr };
napi_status status = napi_invalid_arg;
NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &self, nullptr));
if (self == nullptr && argc >= ARGC_MAX) {
IMSA_HILOGE("napi_get_cb_info failed");
return nullptr;
}
status = napi_unwrap(env, self, &native);
NAPI_ASSERT(env, (status == napi_ok && native != nullptr), "napi_unwrap failed!");
return reinterpret_cast<JsInputMethodEngineSetting *>(native);
}
napi_value JsInputMethodEngineSetting::Subscribe(napi_env env, napi_callback_info info)
{
size_t argc = ARGC_TWO;
@ -290,29 +254,18 @@ napi_value JsInputMethodEngineSetting::Subscribe(napi_env env, napi_callback_inf
napi_value thisVar = nullptr;
void *data = nullptr;
NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, &data));
if (argc != ARGC_TWO) {
JsUtils::ThrowException(
env, IMFErrorCode::EXCEPTION_PARAMCHECK, "Wrong number of arguments, requires 2", TypeCode::TYPE_NONE);
return nullptr;
}
PARAM_CHECK_RETURN(env, argc >= ARGC_TWO, "Wrong number of arguments, requires 2", TYPE_NONE, nullptr);
napi_valuetype valuetype;
NAPI_CALL(env, napi_typeof(env, argv[ARGC_ZERO], &valuetype));
if (valuetype != napi_string) {
JsUtils::ThrowException(env, IMFErrorCode::EXCEPTION_PARAMCHECK, "'type'", TypeCode::TYPE_STRING);
return nullptr;
}
std::string type = GetStringProperty(env, argv[ARGC_ZERO]);
std::string type = "";
napi_status status = JsUtils::GetValue(env, argv[ARGC_ZERO], type);
NAPI_ASSERT_BASE(env, status == napi_ok, "get type failed!", nullptr);
IMSA_HILOGE("event type is: %{public}s", type.c_str());
valuetype = napi_undefined;
napi_typeof(env, argv[ARGC_ONE], &valuetype);
if (valuetype != napi_function) {
JsUtils::ThrowException(env, IMFErrorCode::EXCEPTION_PARAMCHECK, "'callback'", TypeCode::TYPE_FUNCTION);
return nullptr;
}
napi_valuetype valueType = napi_undefined;
napi_typeof(env, argv[ARGC_ONE], &valueType);
PARAM_CHECK_RETURN(env, valueType == napi_function, "'callback'", TYPE_FUNCTION, nullptr);
auto engine = GetNative(env, info);
auto engine = reinterpret_cast<JsInputMethodEngineSetting *>(JsUtils::GetNativeSelf(env, info));
if (engine == nullptr) {
return nullptr;
}
@ -325,6 +278,117 @@ napi_value JsInputMethodEngineSetting::Subscribe(napi_env env, napi_callback_inf
return result;
}
napi_value JsInputMethodEngineSetting::CreatePanel(napi_env env, napi_callback_info info)
{
auto ctxt = std::make_shared<PanelContext>();
auto input = [ctxt](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
PARAM_CHECK_RETURN(env, argc >= 2, "should has 2 or 3 parameters!", TYPE_NONE, napi_invalid_arg);
napi_valuetype valueType = napi_undefined;
napi_typeof(env, argv[ARGC_ZERO], &valueType);
PARAM_CHECK_RETURN(env, valueType == napi_object, " ctx: ", TYPE_OBJECT, napi_invalid_arg);
void *contextPtr = nullptr;
NativeValue *value = reinterpret_cast<NativeValue *>(argv[ARGC_ZERO]);
GetNativeContext(env, value, contextPtr);
ctxt->contextPtr = contextPtr;
napi_typeof(env, argv[ARGC_ONE], &valueType);
PARAM_CHECK_RETURN(env, valueType == napi_object, " panelInfo: ", TYPE_OBJECT, napi_invalid_arg);
napi_value napiValue = nullptr;
napi_status status = napi_get_named_property(env, argv[ARGC_ONE], "type", &napiValue);
PARAM_CHECK_RETURN(env, status == napi_ok, " missing info parameter.", TYPE_NONE, status);
status = JsUtils::GetValue(env, napiValue, ctxt->panelType);
NAPI_ASSERT_BASE(env, status == napi_ok, "Get panelType error!", status);
status = napi_get_named_property(env, argv[ARGC_ONE], "flag", &napiValue);
PARAM_CHECK_RETURN(env, status == napi_ok, " missing info parameter.", TYPE_NONE, status);
status = JsUtils::GetValue(env, napiValue, ctxt->panelFlag);
NAPI_ASSERT_BASE(env, status == napi_ok, "Get panelFlag error!", status);
ctxt->ref = NewWithRef(env, 0, nullptr, reinterpret_cast<void **>(&ctxt->jsPanel), JsPanel::Constructor(env));
return status;
};
auto exec = [ctxt](AsyncCall::Context *ctx) {
std::shared_ptr<InputMethodPanel> panel = nullptr;
PanelInfo panelInfo = { .panelType = PanelType(ctxt->panelType), .panelFlag = PanelFlag(ctxt->panelFlag) };
auto context = static_cast<std::weak_ptr<AbilityRuntime::Context> *>(ctxt->contextPtr);
CHECK_RETURN_VOID(ctxt->jsPanel != nullptr, "napi_create_reference failed");
auto ret = InputMethodAbility::GetInstance()->CreatePanel(context->lock(), panelInfo, panel);
ctxt->SetErrorCode(ret);
CHECK_RETURN_VOID(ret == ErrorCode::NO_ERROR, "JsInputMethodEngineSetting CreatePanel failed!");
ctxt->jsPanel->SetNative(panel);
ctxt->SetState(napi_ok);
};
auto output = [ctxt](napi_env env, napi_value *result) -> napi_status {
NAPI_ASSERT_BASE(env, ctxt->ref != nullptr, "ctxt->ref == nullptr!", napi_generic_failure);
auto status = napi_get_reference_value(env, ctxt->ref, result);
NAPI_ASSERT_BASE(env, (status == napi_ok || result != nullptr), "Get ref error!", napi_generic_failure);
napi_delete_reference(env, ctxt->ref);
return napi_ok;
};
ctxt->SetAction(std::move(input), std::move(output));
AsyncCall asyncCall(env, info, ctxt, ARGC_TWO);
return asyncCall.Call(env, exec);
}
void JsInputMethodEngineSetting::GetNativeContext(napi_env env, NativeValue *nativeContext, void *&contextPtr)
{
if (nativeContext != nullptr) {
auto objContext = AbilityRuntime::ConvertNativeValueTo<NativeObject>(nativeContext);
if (objContext == nullptr) {
IMSA_HILOGE("Get context object failed.");
return;
}
contextPtr = objContext->GetNativePointer();
}
}
napi_value JsInputMethodEngineSetting::DestroyPanel(napi_env env, napi_callback_info info)
{
auto ctxt = std::make_shared<PanelContext>();
auto input = [ctxt](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
PARAM_CHECK_RETURN(env, argc >= 1, "should has 1 parameters!", TYPE_NONE, napi_invalid_arg);
napi_valuetype valueType = napi_undefined;
napi_typeof(env, argv[0], &valueType);
PARAM_CHECK_RETURN(env, valueType == napi_object, " target: ", TYPE_OBJECT, napi_invalid_arg);
bool result = false;
napi_status status = napi_instanceof(env, argv[0], JsPanel::Constructor(env), &result);
NAPI_ASSERT_BASE(env, status == napi_ok, "run napi_instanceof failed!", status);
JsPanel *panel = nullptr;
status = napi_unwrap(env, argv[0], (void **)(&panel));
NAPI_ASSERT_BASE(env, (status == napi_ok) && (panel != nullptr), "can not unwrap to JsPanel!", status);
ctxt->jsPanel = panel;
return status;
};
auto exec = [ctxt](AsyncCall::Context *ctx) {
CHECK_RETURN_VOID(ctxt->jsPanel != nullptr, "JsPanel is nullptr!");
auto status = InputMethodAbility::GetInstance()->DestroyPanel(ctxt->jsPanel->GetNative());
ctxt->SetErrorCode(status);
CHECK_RETURN_VOID(status == ErrorCode::NO_ERROR, "DestroyPanel return error!");
ctxt->SetState(napi_ok);
};
ctxt->SetAction(std::move(input));
AsyncCall asyncCall(env, info, ctxt, 1);
return asyncCall.Call(env, exec);
}
napi_ref JsInputMethodEngineSetting::NewWithRef(
napi_env env, size_t argc, napi_value *argv, void **out, napi_value constructor)
{
napi_value object = nullptr;
napi_status status = napi_new_instance(env, constructor, argc, argv, &object);
NAPI_ASSERT(env, (status == napi_ok) && (object != nullptr), "napi_new_instance failed!");
status = napi_unwrap(env, object, out);
NAPI_ASSERT(env, (status == napi_ok) && (out != nullptr), "napi_unwrap failed");
napi_ref ref = nullptr;
status = napi_create_reference(env, object, 1, &ref);
NAPI_ASSERT(env, (status == napi_ok) && (ref != nullptr), "napi_create_reference failed");
return ref;
}
napi_value JsInputMethodEngineSetting::UnSubscribe(napi_env env, napi_callback_info info)
{
size_t argc = ARGC_TWO;
@ -332,60 +396,26 @@ napi_value JsInputMethodEngineSetting::UnSubscribe(napi_env env, napi_callback_i
napi_value thisVar = nullptr;
void *data = nullptr;
NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, &data));
if (argc != ARGC_ONE && argc != ARGC_TWO) {
JsUtils::ThrowException(env, IMFErrorCode::EXCEPTION_PARAMCHECK, "Wrong number of arguments, requires 1 or 2",
TypeCode::TYPE_NONE);
return nullptr;
}
napi_valuetype valuetype;
NAPI_CALL(env, napi_typeof(env, argv[ARGC_ZERO], &valuetype));
if (valuetype != napi_string) {
JsUtils::ThrowException(env, IMFErrorCode::EXCEPTION_PARAMCHECK, "'type'", TypeCode::TYPE_STRING);
return nullptr;
}
std::string type = GetStringProperty(env, argv[ARGC_ZERO]);
IMSA_HILOGE("event type is: %{public}s", type.c_str());
auto engine = GetNative(env, info);
if (engine == nullptr) {
PARAM_CHECK_RETURN(env, argc >= 1, "Wrong number of arguments, requires 1 or 2", TYPE_NONE, nullptr);
std::string type = "";
JsUtils::GetValue(env, argv[ARGC_ZERO], type);
IMSA_HILOGD("event type is: %{public}s", type.c_str());
auto setting = reinterpret_cast<JsInputMethodEngineSetting *>(JsUtils::GetNativeSelf(env, info));
if (setting == nullptr) {
return nullptr;
}
if (argc == ARGC_TWO) {
valuetype = napi_undefined;
napi_typeof(env, argv[ARGC_ONE], &valuetype);
if (valuetype != napi_function) {
JsUtils::ThrowException(env, IMFErrorCode::EXCEPTION_PARAMCHECK, "'callback'", TypeCode::TYPE_FUNCTION);
return nullptr;
}
napi_valuetype valueType = napi_undefined;
napi_typeof(env, argv[ARGC_ONE], &valueType);
PARAM_CHECK_RETURN(env, valueType == napi_function, " 'callback' ", TYPE_FUNCTION, nullptr);
}
engine->UnRegisterListener(argv[ARGC_ONE], type);
setting->UnRegisterListener(argv[ARGC_ONE], type);
napi_value result = nullptr;
napi_get_null(env, &result);
return result;
}
bool JsInputMethodEngineSetting::Equals(napi_env env, napi_value value, napi_ref copy, std::thread::id threadId)
{
if (copy == nullptr) {
return (value == nullptr);
}
if (threadId != std::this_thread::get_id()) {
IMSA_HILOGD("napi_value can not be compared");
return false;
}
napi_value copyValue = nullptr;
napi_get_reference_value(env, copy, &copyValue);
bool isEquals = false;
napi_strict_equals(env, value, copyValue, &isEquals);
IMSA_HILOGD("value compare result: %{public}d", isEquals);
return isEquals;
}
napi_value JsInputMethodEngineSetting::GetResultOnSetSubtype(napi_env env, const SubProperty &property)
{
napi_value subType = nullptr;

View File

@ -27,7 +27,9 @@
#include "input_method_engine_listener.h"
#include "input_method_property.h"
#include "js_callback_object.h"
#include "js_panel.h"
#include "napi/native_api.h"
#include "input_method_panel.h"
namespace OHOS {
namespace MiscServices {
@ -41,6 +43,8 @@ public:
static napi_value Subscribe(napi_env env, napi_callback_info info);
static napi_value UnSubscribe(napi_env env, napi_callback_info info);
static napi_value MoveCursor(napi_env env, napi_callback_info info);
static napi_value CreatePanel(napi_env env, napi_callback_info info);
static napi_value DestroyPanel(napi_env env, napi_callback_info info);
void OnInputStart() override;
void OnKeyboardStatus(bool isShow) override;
void OnInputStop(const std::string &imeId) override;
@ -48,18 +52,40 @@ public:
void OnSetSubtype(const SubProperty &property) override;
private:
struct PanelContext : public AsyncCall::Context {
int32_t panelType = -1;
int32_t panelFlag = 0;
JsPanel *jsPanel = nullptr;
void *contextPtr = nullptr;
napi_ref ref = nullptr;
PanelContext() : Context(nullptr, nullptr){};
PanelContext(InputAction input, OutputAction output) : Context(std::move(input), std::move(output)){};
napi_status operator()(napi_env env, size_t argc, napi_value *argv, napi_value self) override
{
NAPI_ASSERT_BASE(env, self != nullptr, "self is nullptr", napi_invalid_arg);
return Context::operator()(env, argc, argv, self);
}
napi_status operator()(napi_env env, napi_value *result) override
{
if (status_ != napi_ok) {
output_ = nullptr;
return status_;
}
return Context::operator()(env, result);
}
};
static napi_value JsConstructor(napi_env env, napi_callback_info cbinfo);
static JsInputMethodEngineSetting *GetNative(napi_env env, napi_callback_info info);
static std::shared_ptr<JsInputMethodEngineSetting> GetInputMethodEngineSetting();
static bool Equals(napi_env env, napi_value value, napi_ref copy, std::thread::id threadId);
static napi_value GetJsConstProperty(napi_env env, uint32_t num);
static napi_value GetIntJsConstProperty(napi_env env, int32_t num);
static napi_value GetIMEInstance(napi_env env, napi_callback_info info, int flag);
void RegisterListener(napi_value callback, std::string type, std::shared_ptr<JSCallbackObject> callbackObj);
void UnRegisterListener(napi_value callback, std::string type);
static napi_value GetResultOnSetSubtype(napi_env env, const SubProperty &property);
static std::string GetStringProperty(napi_env env, napi_value jsString);
static constexpr int32_t MAX_VALUE_LEN = 1024;
static napi_ref NewWithRef(napi_env env, size_t argc, napi_value *argv, void **out, napi_value constructor);
static void GetNativeContext(napi_env env, NativeValue *nativeContext, void *&contextPtr);
static const std::string IMES_CLASS_NAME;
static thread_local napi_ref IMESRef_;
struct UvEntry {

View File

@ -16,7 +16,6 @@
#include "js_keyboard_controller_engine.h"
#include "input_method_ability.h"
#include "js_utils.h"
#include "napi/native_api.h"
#include "napi/native_node_api.h"

View File

@ -31,6 +31,7 @@ constexpr size_t ARGC_THREE = 3;
constexpr size_t ARGC_FOUR = 4;
constexpr int32_t V9_FLAG = 1;
constexpr int32_t ORIGINAL_FLAG = 2;
constexpr size_t ARGC_MAX = 6;
const std::string JsKeyboardDelegateSetting::KDS_CLASS_NAME = "KeyboardDelegate";
thread_local napi_ref JsKeyboardDelegateSetting::KDSRef_ = nullptr;
@ -140,14 +141,10 @@ napi_value JsKeyboardDelegateSetting::GetKDInstance(napi_env env, napi_callback_
napi_value instance = nullptr;
napi_value cons = nullptr;
if (flag == V9_FLAG) {
size_t argc = AsyncCall::ARGC_MAX;
napi_value argv[AsyncCall::ARGC_MAX] = { nullptr };
size_t argc = ARGC_MAX;
napi_value argv[ARGC_MAX] = { nullptr };
NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
if (argc != ARGC_ZERO) {
JsUtils::ThrowException(
env, IMFErrorCode::EXCEPTION_PARAMCHECK, "Wrong number of arguments, requires 0", TypeCode::TYPE_NONE);
}
}
if (napi_get_reference_value(env, KDSRef_, &cons) != napi_ok) {
@ -162,17 +159,6 @@ napi_value JsKeyboardDelegateSetting::GetKDInstance(napi_env env, napi_callback_
return instance;
}
std::string JsKeyboardDelegateSetting::GetStringProperty(napi_env env, napi_value jsString)
{
char propValue[MAX_VALUE_LEN] = { 0 };
size_t propLen;
if (napi_get_value_string_utf8(env, jsString, propValue, MAX_VALUE_LEN, &propLen) != napi_ok) {
IMSA_HILOGE("GetStringProperty error");
return "";
}
return std::string(propValue);
}
void JsKeyboardDelegateSetting::RegisterListener(
napi_value callback, std::string type, std::shared_ptr<JSCallbackObject> callbackObj)
{
@ -183,7 +169,7 @@ void JsKeyboardDelegateSetting::RegisterListener(
}
auto callbacks = jsCbMap_[type];
bool ret = std::any_of(callbacks.begin(), callbacks.end(), [&callback](std::shared_ptr<JSCallbackObject> cb) {
return Equals(cb->env_, callback, cb->callback_, cb->threadId_);
return JsUtils::Equals(cb->env_, callback, cb->callback_, cb->threadId_);
});
if (ret) {
IMSA_HILOGE("JsKeyboardDelegateSetting::RegisterListener callback already registered!");
@ -210,7 +196,8 @@ void JsKeyboardDelegateSetting::UnRegisterListener(napi_value callback, std::str
}
for (auto item = jsCbMap_[type].begin(); item != jsCbMap_[type].end(); item++) {
if ((callback != nullptr) && (Equals((*item)->env_, callback, (*item)->callback_, (*item)->threadId_))) {
if ((callback != nullptr) &&
(JsUtils::Equals((*item)->env_, callback, (*item)->callback_, (*item)->threadId_))) {
jsCbMap_[type].erase(item);
break;
}
@ -220,24 +207,6 @@ void JsKeyboardDelegateSetting::UnRegisterListener(napi_value callback, std::str
}
}
JsKeyboardDelegateSetting *JsKeyboardDelegateSetting::GetNative(napi_env env, napi_callback_info info)
{
size_t argc = AsyncCall::ARGC_MAX;
void *native = nullptr;
napi_value self = nullptr;
napi_value argv[AsyncCall::ARGC_MAX] = { nullptr };
napi_status status = napi_invalid_arg;
NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &self, nullptr));
if (self == nullptr && argc >= AsyncCall::ARGC_MAX) {
IMSA_HILOGE("napi_get_cb_info failed");
return nullptr;
}
status = napi_unwrap(env, self, &native);
NAPI_ASSERT(env, (status == napi_ok && native != nullptr), "napi_unwrap failed!");
return reinterpret_cast<JsKeyboardDelegateSetting *>(native);
}
napi_value JsKeyboardDelegateSetting::Subscribe(napi_env env, napi_callback_info info)
{
size_t argc = ARGC_TWO;
@ -245,28 +214,16 @@ napi_value JsKeyboardDelegateSetting::Subscribe(napi_env env, napi_callback_info
napi_value thisVar = nullptr;
void *data = nullptr;
NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, &data));
if (argc != ARGC_TWO) {
JsUtils::ThrowException(
env, IMFErrorCode::EXCEPTION_PARAMCHECK, "Wrong number of arguments, requires 2", TypeCode::TYPE_NONE);
}
napi_valuetype valuetype;
NAPI_CALL(env, napi_typeof(env, argv[ARGC_ZERO], &valuetype));
if (valuetype != napi_string) {
JsUtils::ThrowException(env, IMFErrorCode::EXCEPTION_PARAMCHECK, "'type'", TypeCode::TYPE_STRING);
return nullptr;
}
std::string type = GetStringProperty(env, argv[ARGC_ZERO]);
PARAM_CHECK_RETURN(env, argc >= ARGC_TWO, "Wrong number of arguments, requires 2", TYPE_NONE, nullptr);
std::string type = "";
JsUtils::GetValue(env, argv[ARGC_ZERO], type);
IMSA_HILOGE("event type is: %{public}s", type.c_str());
valuetype = napi_undefined;
napi_typeof(env, argv[ARGC_ONE], &valuetype);
if (valuetype != napi_function) {
JsUtils::ThrowException(env, IMFErrorCode::EXCEPTION_PARAMCHECK, "'callback'", TypeCode::TYPE_FUNCTION);
return nullptr;
}
napi_valuetype valueType = napi_undefined;
napi_typeof(env, argv[ARGC_ONE], &valueType);
PARAM_CHECK_RETURN(env, valueType == napi_function, "callback", TYPE_FUNCTION, nullptr);
auto engine = GetNative(env, info);
auto engine = reinterpret_cast<JsKeyboardDelegateSetting *>(JsUtils::GetNativeSelf(env, info));
if (engine == nullptr) {
return nullptr;
}
@ -286,32 +243,20 @@ napi_value JsKeyboardDelegateSetting::UnSubscribe(napi_env env, napi_callback_in
napi_value thisVar = nullptr;
void *data = nullptr;
NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, &data));
if (argc != ARGC_ONE && argc != ARGC_TWO) {
JsUtils::ThrowException(env, IMFErrorCode::EXCEPTION_PARAMCHECK, "Wrong number of arguments, requires 1 or 2",
TypeCode::TYPE_NONE);
return nullptr;
}
PARAM_CHECK_RETURN(env, argc > 0, "should 1 or 2 parameters!", TYPE_NONE, nullptr);
napi_valuetype valuetype;
NAPI_CALL(env, napi_typeof(env, argv[ARGC_ZERO], &valuetype));
if (valuetype != napi_string) {
JsUtils::ThrowException(env, IMFErrorCode::EXCEPTION_PARAMCHECK, "'type'", TypeCode::TYPE_STRING);
return nullptr;
}
std::string type = GetStringProperty(env, argv[ARGC_ZERO]);
std::string type = "";
JsUtils::GetValue(env, argv[ARGC_ZERO], type);
auto delegate = GetNative(env, info);
auto delegate = reinterpret_cast<JsKeyboardDelegateSetting *>(JsUtils::GetNativeSelf(env, info));
if (delegate == nullptr) {
return nullptr;
}
if (argc == ARGC_TWO) {
valuetype = napi_undefined;
napi_typeof(env, argv[ARGC_ONE], &valuetype);
if (valuetype != napi_function) {
JsUtils::ThrowException(env, IMFErrorCode::EXCEPTION_PARAMCHECK, "'callback'", TypeCode::TYPE_FUNCTION);
return nullptr;
}
napi_valuetype valueType = napi_undefined;
napi_typeof(env, argv[ARGC_ONE], &valueType);
PARAM_CHECK_RETURN(env, valueType == napi_function, "callback", TYPE_FUNCTION, nullptr);
}
delegate->UnRegisterListener(argv[ARGC_ONE], type);
napi_value result = nullptr;
@ -319,26 +264,6 @@ napi_value JsKeyboardDelegateSetting::UnSubscribe(napi_env env, napi_callback_in
return result;
}
bool JsKeyboardDelegateSetting::Equals(napi_env env, napi_value value, napi_ref copy, std::thread::id threadId)
{
if (copy == nullptr) {
return (value == nullptr);
}
if (threadId != std::this_thread::get_id()) {
IMSA_HILOGD("napi_value can not be compared");
return false;
}
napi_value copyValue = nullptr;
napi_get_reference_value(env, copy, &copyValue);
bool isEquals = false;
napi_strict_equals(env, value, copyValue, &isEquals);
IMSA_HILOGD("value compare result: %{public}d", isEquals);
return isEquals;
}
napi_value JsKeyboardDelegateSetting::GetResultOnKeyEvent(napi_env env, int32_t keyCode, int32_t keyStatus)
{
napi_value KeyboardDelegate = nullptr;

View File

@ -92,14 +92,9 @@ private:
static napi_value GetKDInstance(napi_env env, napi_callback_info info, int flag);
static std::shared_ptr<JsKeyboardDelegateSetting> GetKeyboardDelegateSetting();
static napi_value JsConstructor(napi_env env, napi_callback_info cbinfo);
static JsKeyboardDelegateSetting *GetNative(napi_env env, napi_callback_info info);
static bool Equals(napi_env env, napi_value value, napi_ref copy, std::thread::id threadId);
void RegisterListener(napi_value callback, std::string type, std::shared_ptr<JSCallbackObject> callbackObj);
void UnRegisterListener(napi_value callback, std::string type);
static std::string GetStringProperty(napi_env env, napi_value jsString);
static constexpr int32_t MAX_VALUE_LEN = 1024;
static constexpr int32_t MAX_TIMEOUT = 100;
static constexpr int32_t MAX_TIMEOUT = 5;
static const std::string KDS_CLASS_NAME;
static thread_local napi_ref KDSRef_;
struct CursorPara {

View File

@ -0,0 +1,292 @@
/*
* Copyright (c) 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 "js_panel.h"
#include "input_method_ability.h"
#include "js_utils.h"
#include "napi/native_common.h"
#include "panel_listener_impl.h"
namespace OHOS {
namespace MiscServices {
constexpr size_t ARGC_ZERO = 0;
constexpr size_t ARGC_ONE = 1;
constexpr size_t ARGC_TWO = 2;
const std::string JsPanel::CLASS_NAME = "Panel";
napi_value JsPanel::Constructor(napi_env env)
{
IMSA_HILOGI("JsPanel in.");
const napi_property_descriptor properties[] = {
DECLARE_NAPI_FUNCTION("setUiContent", SetUiContent),
DECLARE_NAPI_FUNCTION("resize", Resize),
DECLARE_NAPI_FUNCTION("moveTo", MoveTo),
DECLARE_NAPI_FUNCTION("show", Show),
DECLARE_NAPI_FUNCTION("hide", Hide),
DECLARE_NAPI_FUNCTION("changeFlag", ChangeFlag),
DECLARE_NAPI_FUNCTION("on", Subscribe),
DECLARE_NAPI_FUNCTION("off", UnSubscribe),
};
napi_value constructor = nullptr;
NAPI_CALL(env, napi_define_class(env, CLASS_NAME.c_str(), CLASS_NAME.size(), JsNew, nullptr,
sizeof(properties) / sizeof(napi_property_descriptor), properties, &constructor));
NAPI_ASSERT(env, constructor != nullptr, "napi_define_class failed!");
return constructor;
}
napi_value JsPanel::JsNew(napi_env env, napi_callback_info info)
{
IMSA_HILOGD("JsPanel, create panel instance in.");
JsPanel *panel = new (std::nothrow) JsPanel();
NAPI_ASSERT(env, panel != nullptr, "no memory for JsPanel");
auto finalize = [](napi_env env, void *data, void *hint) {
IMSA_HILOGI("jsPanel finalize.");
auto *jsPanel = reinterpret_cast<JsPanel *>(data);
NAPI_ASSERT_RETURN_VOID(env, jsPanel != nullptr, "finalize null!");
delete jsPanel;
};
napi_value thisVar = nullptr;
NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr));
napi_status status = napi_wrap(env, thisVar, panel, finalize, nullptr, nullptr);
if (status != napi_ok) {
IMSA_HILOGE("JsPanel napi_wrap failed: %{public}d", status);
return nullptr;
}
return thisVar;
}
JsPanel::~JsPanel()
{
inputMethodPanel_ = nullptr;
}
void JsPanel::SetNative(const std::shared_ptr<InputMethodPanel> &panel)
{
inputMethodPanel_ = panel;
}
std::shared_ptr<InputMethodPanel> &JsPanel::GetNative()
{
return inputMethodPanel_;
}
napi_value JsPanel::SetUiContent(napi_env env, napi_callback_info info)
{
IMSA_HILOGI("JsPanel in.");
auto ctxt = std::make_shared<PanelContentContext>(env, info);
auto input = [ctxt](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
napi_status status = napi_generic_failure;
PARAM_CHECK_RETURN(env, argc >= 1, "should 1 or 2 parameters!", TYPE_NONE, status);
status = JsUtils::GetValue(env, argv[ARGC_ZERO], ctxt->path);
NAPI_ASSERT_BASE(env, status == napi_ok, "get path failed!", status);
// if type of argv[1] is object, we will get value of 'storage' from it.
if (argc >= 2) {
napi_valuetype valueType = napi_undefined;
napi_status status = napi_typeof(env, argv[1], &valueType);
NAPI_ASSERT_BASE(env, status == napi_ok, "get valueType failed!", status);
if (valueType == napi_object) {
NativeValue *storage = nullptr;
storage = reinterpret_cast<NativeValue *>(argv[1]);
auto contentStorage = (storage == nullptr)
? nullptr
: std::shared_ptr<NativeReference>(
reinterpret_cast<NativeEngine *>(env)->CreateReference(storage, 1));
ctxt->contentStorage = contentStorage;
}
}
return napi_ok;
};
auto exec = [ctxt, env](AsyncCall::Context *ctx) {
auto &inputMethodPanel = reinterpret_cast<JsPanel *>(ctxt->native)->GetNative();
CHECK_RETURN_VOID(inputMethodPanel != nullptr, "inputMethodPanel_ is nullptr.");
NativeValue *nativeStorage = (ctxt->contentStorage == nullptr) ? nullptr : ctxt->contentStorage->Get();
auto code = inputMethodPanel->SetUiContent(ctxt->path, reinterpret_cast<NativeEngine *>(env), nativeStorage);
if (code == ErrorCode::NO_ERROR) {
ctxt->SetState(napi_ok);
return;
}
ctxt->SetErrorCode(code);
};
ctxt->SetAction(std::move(input));
AsyncCall asyncCall(env, info, ctxt, 1);
return asyncCall.Call(env, exec);
}
napi_value JsPanel::Resize(napi_env env, napi_callback_info info)
{
auto ctxt = std::make_shared<PanelContentContext>(env, info);
auto input = [ctxt](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
napi_status status = napi_generic_failure;
PARAM_CHECK_RETURN(env, argc > 1, "should 2 or 3 parameters!", TYPE_NONE, status);
status = JsUtils::GetValue(env, argv[ARGC_ZERO], ctxt->width);
NAPI_ASSERT_BASE(env, status == napi_ok, "get width failed!", status);
status = JsUtils::GetValue(env, argv[ARGC_ONE], ctxt->height);
NAPI_ASSERT_BASE(env, status == napi_ok, "get height failed!", status);
return napi_ok;
};
auto exec = [ctxt](AsyncCall::Context *ctx) {
auto &inputMethodPanel = reinterpret_cast<JsPanel *>(ctxt->native)->GetNative();
CHECK_RETURN_VOID(inputMethodPanel != nullptr, "inputMethodPanel_ is nullptr.");
auto code = inputMethodPanel->Resize(ctxt->width, ctxt->height);
if (code == ErrorCode::NO_ERROR) {
ctxt->SetState(napi_ok);
return;
}
ctxt->SetErrorCode(code);
};
ctxt->SetAction(std::move(input));
AsyncCall asyncCall(env, info, ctxt, ARGC_TWO);
return asyncCall.Call(env, exec);
}
napi_value JsPanel::MoveTo(napi_env env, napi_callback_info info)
{
auto ctxt = std::make_shared<PanelContentContext>(env, info);
auto input = [ctxt](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
napi_status status = napi_generic_failure;
PARAM_CHECK_RETURN(env, argc > 1, " should 2 or 3 parameters! ", TYPE_NONE, status);
status = JsUtils::GetValue(env, argv[ARGC_ZERO], ctxt->width);
NAPI_ASSERT_BASE(env, status == napi_ok, "get width failed!", status);
status = JsUtils::GetValue(env, argv[ARGC_ONE], ctxt->height);
NAPI_ASSERT_BASE(env, status == napi_ok, "get height failed!", status);
return napi_ok;
};
auto exec = [ctxt](AsyncCall::Context *ctx) {
auto &inputMethodPanel = reinterpret_cast<JsPanel *>(ctxt->native)->GetNative();
CHECK_RETURN_VOID(inputMethodPanel != nullptr, "inputMethodPanel_ is nullptr.");
auto code = inputMethodPanel->MoveTo(ctxt->width, ctxt->height);
if (code == ErrorCode::NO_ERROR) {
ctxt->SetState(napi_ok);
return;
}
ctxt->SetErrorCode(code);
};
ctxt->SetAction(std::move(input));
AsyncCall asyncCall(env, info, ctxt, ARGC_TWO);
return asyncCall.Call(env, exec);
}
napi_value JsPanel::Show(napi_env env, napi_callback_info info)
{
auto ctxt = std::make_shared<PanelContentContext>(env, info);
auto exec = [ctxt](AsyncCall::Context *ctx) {
auto &inputMethodPanel = reinterpret_cast<JsPanel *>(ctxt->native)->GetNative();
CHECK_RETURN_VOID(inputMethodPanel != nullptr, "inputMethodPanel_ is nullptr.");
auto code = inputMethodPanel->ShowPanel();
if (code == ErrorCode::NO_ERROR) {
ctxt->SetState(napi_ok);
return;
}
ctxt->SetErrorCode(code);
};
AsyncCall asyncCall(env, info, ctxt, 0);
return asyncCall.Call(env, exec);
}
napi_value JsPanel::Hide(napi_env env, napi_callback_info info)
{
auto ctxt = std::make_shared<PanelContentContext>(env, info);
auto exec = [ctxt](AsyncCall::Context *ctx) {
auto &inputMethodPanel = reinterpret_cast<JsPanel *>(ctxt->native)->GetNative();
CHECK_RETURN_VOID(inputMethodPanel != nullptr, "inputMethodPanel_ is nullptr.");
auto code = inputMethodPanel->HidePanel();
if (code == ErrorCode::NO_ERROR) {
ctxt->SetState(napi_ok);
return;
}
ctxt->SetErrorCode(code);
};
AsyncCall asyncCall(env, info, ctxt, 0);
return asyncCall.Call(env, exec);
}
napi_value JsPanel::ChangeFlag(napi_env env, napi_callback_info info)
{
size_t argc = ARGC_MAX;
napi_value argv[ARGC_MAX] = { nullptr };
napi_value thisVar = nullptr;
NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
PARAM_CHECK_RETURN(env, argc > 0, " should 1 parameter! ", TYPE_NONE, nullptr);
int32_t panelFlag = 0;
napi_status status = JsUtils::GetValue(env, argv[ARGC_ZERO], panelFlag);
NAPI_ASSERT(env, status == napi_ok, "get panelFlag failed!");
auto inputMethodPanel = UnwrapPanel(env, thisVar);
auto ret = inputMethodPanel->ChangePanelFlag(PanelFlag(panelFlag));
NAPI_ASSERT(env, ret == ErrorCode::NO_ERROR, "ChangePanelFlag failed!");
return nullptr;
}
napi_value JsPanel::Subscribe(napi_env env, napi_callback_info info)
{
IMSA_HILOGD("JsPanel in");
size_t argc = ARGC_MAX;
napi_value argv[ARGC_MAX] = { nullptr };
napi_value thisVar = nullptr;
NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
NAPI_ASSERT(env, (argc >= ARGC_ONE) && (argc <= ARGC_MAX), "err number of argument!");
std::string type = "";
JsUtils::GetValue(env, argv[ARGC_ZERO], type);
IMSA_HILOGD("on event type is: %{public}s", type.c_str());
napi_valuetype valuetype = napi_undefined;
napi_typeof(env, argv[1], &valuetype);
NAPI_ASSERT(env, valuetype == napi_function, "callback is not a function");
std::shared_ptr<PanelListenerImpl> observer = PanelListenerImpl::GetInstance();
auto inputMethodPanel = UnwrapPanel(env, thisVar);
observer->SaveInfo(env, type, argv[ARGC_ONE], inputMethodPanel->windowId_);
inputMethodPanel->SetPanelStatusListener(observer);
napi_value result = nullptr;
napi_get_undefined(env, &result);
return result;
}
napi_value JsPanel::UnSubscribe(napi_env env, napi_callback_info info)
{
size_t argc = ARGC_MAX;
napi_value argv[ARGC_MAX] = { nullptr };
napi_value thisVar = nullptr;
NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
NAPI_ASSERT(env, argc >= 1, "Wrong number of arguments, requires 1 or 2");
std::string type = "";
JsUtils::GetValue(env, argv[ARGC_ZERO], type);
IMSA_HILOGI("event type is: %{public}s", type.c_str());
std::shared_ptr<PanelListenerImpl> observer = PanelListenerImpl::GetInstance();
auto inputMethodPanel = UnwrapPanel(env, thisVar);
observer->RemoveInfo(type, inputMethodPanel->windowId_);
inputMethodPanel->RemovePanelListener(type);
napi_value result = nullptr;
napi_get_null(env, &result);
return result;
}
std::shared_ptr<InputMethodPanel> JsPanel::UnwrapPanel(napi_env env, napi_value thisVar)
{
void *native = nullptr;
napi_status status = napi_unwrap(env, thisVar, &native);
NAPI_ASSERT_BASE(env, (status == napi_ok && native != nullptr), "napi_unwrap failed!", nullptr);
auto jsPanel = reinterpret_cast<JsPanel *>(native);
if (jsPanel == nullptr) {
return nullptr;
}
auto &inputMethodPanel = jsPanel->GetNative();
NAPI_ASSERT_BASE(env, inputMethodPanel != nullptr, "inputMethodPanel is nullptr", nullptr);
return inputMethodPanel;
}
} // namespace MiscServices
} // namespace OHOS

View File

@ -0,0 +1,84 @@
/*
* Copyright (c) 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.
*/
#ifndef INPUTMETHOD_IMF_JSPANEL_H
#define INPUTMETHOD_IMF_JSPANEL_H
#include <uv.h>
#include "async_call.h"
#include "input_method_panel.h"
#include "js_callback_object.h"
#include "napi/native_api.h"
#include "napi/native_common.h"
#include "napi/native_node_api.h"
#include "native_engine/native_engine.h"
#include "native_engine/native_value.h"
namespace OHOS {
namespace MiscServices {
class JsPanel {
public:
JsPanel() = default;
~JsPanel();
static napi_value Constructor(napi_env env);
static napi_value SetUiContent(napi_env env, napi_callback_info info);
static napi_value Resize(napi_env env, napi_callback_info info);
static napi_value MoveTo(napi_env env, napi_callback_info info);
static napi_value Show(napi_env env, napi_callback_info info);
static napi_value Hide(napi_env env, napi_callback_info info);
static napi_value ChangeFlag(napi_env env, napi_callback_info info);
static napi_value Subscribe(napi_env env, napi_callback_info info);
static napi_value UnSubscribe(napi_env env, napi_callback_info info);
void SetNative(const std::shared_ptr<InputMethodPanel> &panel);
std::shared_ptr<InputMethodPanel> &GetNative();
private:
struct PanelContentContext : public AsyncCall::Context {
std::string path = "";
uint32_t width = 0;
uint32_t height = 0;
void *native = nullptr;
std::shared_ptr<NativeReference> contentStorage = nullptr;
PanelContentContext(napi_env env, napi_callback_info info) : Context(nullptr, nullptr)
{
napi_value self = nullptr;
napi_status status = napi_get_cb_info(env, info, 0, nullptr, &self, nullptr);
status = napi_unwrap(env, self, &native);
};
PanelContentContext(InputAction input, OutputAction output) : Context(std::move(input), std::move(output)){};
napi_status operator()(napi_env env, size_t argc, napi_value *argv, napi_value self) override
{
NAPI_ASSERT_BASE(env, self != nullptr, "self is nullptr", napi_invalid_arg);
return Context::operator()(env, argc, argv, self);
}
napi_status operator()(napi_env env, napi_value *result) override
{
if (status_ != napi_ok) {
output_ = nullptr;
return status_;
}
return Context::operator()(env, result);
}
};
static napi_value JsNew(napi_env env, napi_callback_info info);
static std::shared_ptr<InputMethodPanel> UnwrapPanel(napi_env env, napi_value thisVar);
static const std::string CLASS_NAME;
static constexpr size_t ARGC_MAX = 6;
std::shared_ptr<InputMethodPanel> inputMethodPanel_ = nullptr;
};
} // namespace MiscServices
} // namespace OHOS
#endif //INPUTMETHOD_IMF_JSPANEL_H

View File

@ -55,20 +55,8 @@ napi_value JsTextInputClientEngine::MoveCursor(napi_env env, napi_callback_info
{
auto ctxt = std::make_shared<MoveCursorContext>();
auto input = [ctxt](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
napi_status status = napi_generic_failure;
napi_valuetype valueType = napi_undefined;
napi_typeof(env, argv[0], &valueType);
if (argc < 1) {
JsUtils::ThrowException(
env, IMFErrorCode::EXCEPTION_PARAMCHECK, " should 1 or 2 parameters!", TypeCode::TYPE_NONE);
return status;
}
if (valueType != napi_number) {
JsUtils::ThrowException(env, IMFErrorCode::EXCEPTION_PARAMCHECK, " direction", TypeCode::TYPE_NUMBER);
return status;
}
status = GetMoveCursorParam(env, argv[0], ctxt);
return status;
PARAM_CHECK_RETURN(env, argc > 0, " should 1 or 2 parameters! ", TYPE_NONE, napi_generic_failure);
return JsUtils::GetValue(env, argv[0], ctxt->num);
};
auto exec = [ctxt](AsyncCall::Context *ctx) {
int32_t code = InputMethodAbility::GetInstance()->MoveCursor(ctxt->num);
@ -127,26 +115,6 @@ napi_value JsTextInputClientEngine::GetTextInputClientInstance(napi_env env)
return instance;
}
int32_t JsTextInputClientEngine::GetNumberProperty(napi_env env, napi_value jsNumber)
{
int32_t number;
if (napi_get_value_int32(env, jsNumber, &number) != napi_ok) {
IMSA_HILOGE("GetNumberProperty error");
}
return number;
}
std::string JsTextInputClientEngine::GetStringProperty(napi_env env, napi_value jsString)
{
char propValue[MAX_VALUE_LEN] = { 0 };
size_t propLen;
if (napi_get_value_string_utf8(env, jsString, propValue, MAX_VALUE_LEN, &propLen) != napi_ok) {
IMSA_HILOGE("GetStringProperty error");
return "";
}
return std::string(propValue);
}
napi_value JsTextInputClientEngine::GetResult(napi_env env, std::string &text)
{
napi_value jsText = nullptr;
@ -171,112 +139,18 @@ napi_value JsTextInputClientEngine::GetResultEditorAttribute(
return editorAttribute;
}
napi_status JsTextInputClientEngine::GetAction(
napi_env env, napi_value argv, std::shared_ptr<SendKeyFunctionContext> ctxt)
{
napi_valuetype valueType = napi_undefined;
napi_status status = napi_generic_failure;
status = napi_typeof(env, argv, &valueType);
if (valueType == napi_number) {
ctxt->action = GetNumberProperty(env, argv);
}
return status;
}
napi_status JsTextInputClientEngine::GetDeleteForwardLength(
napi_env env, napi_value argv, std::shared_ptr<DeleteForwardContext> ctxt)
{
napi_valuetype valueType = napi_undefined;
napi_status status = napi_generic_failure;
status = napi_typeof(env, argv, &valueType);
if (valueType == napi_number) {
ctxt->length = GetNumberProperty(env, argv);
}
return status;
}
napi_status JsTextInputClientEngine::GetMoveCursorParam(
napi_env env, napi_value argv, std::shared_ptr<MoveCursorContext> ctxt)
{
napi_valuetype valueType = napi_undefined;
napi_status status = napi_generic_failure;
status = napi_typeof(env, argv, &valueType);
if (valueType == napi_number) {
ctxt->num = GetNumberProperty(env, argv);
}
return status;
}
napi_status JsTextInputClientEngine::GetDeleteBackwardLength(
napi_env env, napi_value argv, std::shared_ptr<DeleteBackwardContext> ctxt)
{
napi_valuetype valueType = napi_undefined;
napi_status status = napi_generic_failure;
status = napi_typeof(env, argv, &valueType);
if (valueType == napi_number) {
ctxt->length = GetNumberProperty(env, argv);
}
return status;
}
napi_status JsTextInputClientEngine::GetInsertText(
napi_env env, napi_value argv, std::shared_ptr<InsertTextContext> ctxt)
{
napi_valuetype valueType = napi_undefined;
napi_status status = napi_generic_failure;
status = napi_typeof(env, argv, &valueType);
if (valueType == napi_string) {
ctxt->text = GetStringProperty(env, argv);
}
return status;
}
napi_status JsTextInputClientEngine::GetForwardLength(
napi_env env, napi_value argv, std::shared_ptr<GetForwardContext> ctxt)
{
napi_valuetype valueType = napi_undefined;
napi_status status = napi_generic_failure;
status = napi_typeof(env, argv, &valueType);
if (valueType == napi_number) {
ctxt->length = GetNumberProperty(env, argv);
}
return status;
}
napi_status JsTextInputClientEngine::GetBackwardLength(
napi_env env, napi_value argv, std::shared_ptr<GetBackwardContext> ctxt)
{
napi_valuetype valueType = napi_undefined;
napi_status status = napi_generic_failure;
status = napi_typeof(env, argv, &valueType);
if (valueType == napi_number) {
ctxt->length = GetNumberProperty(env, argv);
}
return status;
}
napi_status JsTextInputClientEngine::GetSelectRange(napi_env env, napi_value argv, std::shared_ptr<SelectContext> ctxt)
{
napi_status status = napi_generic_failure;
napi_value napiValue = nullptr;
status = napi_get_named_property(env, argv, "start", &napiValue);
if (status != napi_ok) {
JsUtils::ThrowException(
env, IMFErrorCode::EXCEPTION_PARAMCHECK, "missing start parameter.", TypeCode::TYPE_NONE);
return status;
}
status = napi_get_value_int32(env, napiValue, &ctxt->start);
if (status != napi_ok) {
IMSA_HILOGE("failed to get start value");
return status;
}
PARAM_CHECK_RETURN(env, status == napi_ok, "missing start parameter.", TYPE_NONE, status);
status = JsUtils::GetValue(env, napiValue, ctxt->start);
NAPI_ASSERT_BASE(env, status == napi_ok, "failed to get start value", status);
status = napi_get_named_property(env, argv, "end", &napiValue);
if (status != napi_ok) {
JsUtils::ThrowException(env, IMFErrorCode::EXCEPTION_PARAMCHECK, "missing end parameter.", TypeCode::TYPE_NONE);
return status;
}
status = napi_get_value_int32(env, napiValue, &ctxt->end);
PARAM_CHECK_RETURN(env, status == napi_ok, "missing end parameter.", TYPE_NONE, status);
status = JsUtils::GetValue(env, napiValue, ctxt->end);
if (status != napi_ok) {
IMSA_HILOGE("failed to get end value");
}
@ -289,12 +163,8 @@ napi_status JsTextInputClientEngine::GetSelectMovement(
napi_status status = napi_generic_failure;
napi_value napiValue = nullptr;
status = napi_get_named_property(env, argv, "direction", &napiValue);
if (status != napi_ok) {
JsUtils::ThrowException(
env, IMFErrorCode::EXCEPTION_PARAMCHECK, "missing direction parameter.", TypeCode::TYPE_NONE);
return status;
}
status = napi_get_value_int32(env, napiValue, &ctxt->direction);
PARAM_CHECK_RETURN(env, status == napi_ok, "missing direction parameter.", TYPE_NONE, status);
status = JsUtils::GetValue(env, napiValue, ctxt->direction);
if (status != napi_ok) {
IMSA_HILOGE("failed to get direction value");
}
@ -305,20 +175,8 @@ napi_value JsTextInputClientEngine::SendKeyFunction(napi_env env, napi_callback_
{
auto ctxt = std::make_shared<SendKeyFunctionContext>();
auto input = [ctxt](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
napi_status status = napi_generic_failure;
napi_valuetype valueType = napi_undefined;
napi_typeof(env, argv[0], &valueType);
if (argc < 1) {
JsUtils::ThrowException(
env, IMFErrorCode::EXCEPTION_PARAMCHECK, " should 1 or 2 parameters!", TypeCode::TYPE_NONE);
return status;
}
if (valueType != napi_number) {
JsUtils::ThrowException(env, IMFErrorCode::EXCEPTION_PARAMCHECK, " 'action'", TypeCode::TYPE_NUMBER);
return status;
}
status = GetAction(env, argv[0], ctxt);
return status;
PARAM_CHECK_RETURN(env, argc > 0, "should 1 or 2 parameters!", TYPE_NONE, napi_generic_failure);
return JsUtils::GetValue(env, argv[0], ctxt->action);
};
auto output = [ctxt](napi_env env, napi_value *result) -> napi_status {
napi_status status = napi_get_boolean(env, ctxt->isSendKeyFunction, result);
@ -343,20 +201,8 @@ napi_value JsTextInputClientEngine::DeleteForward(napi_env env, napi_callback_in
{
auto ctxt = std::make_shared<DeleteForwardContext>();
auto input = [ctxt](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
napi_status status = napi_generic_failure;
napi_valuetype valueType = napi_undefined;
napi_typeof(env, argv[0], &valueType);
if (argc < 1) {
JsUtils::ThrowException(
env, IMFErrorCode::EXCEPTION_PARAMCHECK, " should 1 or 2 parameters!", TypeCode::TYPE_NONE);
return status;
}
if (valueType != napi_number) {
JsUtils::ThrowException(env, IMFErrorCode::EXCEPTION_PARAMCHECK, " 'length'", TypeCode::TYPE_NUMBER);
return status;
}
status = GetDeleteForwardLength(env, argv[0], ctxt);
return status;
PARAM_CHECK_RETURN(env, argc > 0, "should 1 or 2 parameters!", TYPE_NONE, napi_generic_failure);
return JsUtils::GetValue(env, argv[0], ctxt->length);
};
auto output = [ctxt](napi_env env, napi_value *result) -> napi_status {
napi_status status = napi_get_boolean(env, ctxt->isDeleteForward, result);
@ -381,20 +227,8 @@ napi_value JsTextInputClientEngine::DeleteBackward(napi_env env, napi_callback_i
{
auto ctxt = std::make_shared<DeleteBackwardContext>();
auto input = [ctxt](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
napi_status status = napi_generic_failure;
napi_valuetype valueType = napi_undefined;
napi_typeof(env, argv[0], &valueType);
if (argc < 1) {
JsUtils::ThrowException(
env, IMFErrorCode::EXCEPTION_PARAMCHECK, " should 1 or 2 parameters!", TypeCode::TYPE_NONE);
return status;
}
if (valueType != napi_number) {
JsUtils::ThrowException(env, IMFErrorCode::EXCEPTION_PARAMCHECK, " 'length", TypeCode::TYPE_NUMBER);
return status;
}
status = GetDeleteBackwardLength(env, argv[0], ctxt);
return status;
PARAM_CHECK_RETURN(env, argc > 0, "should 1 or 2 parameters!", TYPE_NONE, napi_generic_failure);
return JsUtils::GetValue(env, argv[0], ctxt->length);
};
auto output = [ctxt](napi_env env, napi_value *result) -> napi_status {
napi_status status = napi_get_boolean(env, ctxt->isDeleteBackward, result);
@ -419,20 +253,8 @@ napi_value JsTextInputClientEngine::InsertText(napi_env env, napi_callback_info
{
auto ctxt = std::make_shared<InsertTextContext>();
auto input = [ctxt](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
napi_status status = napi_generic_failure;
napi_valuetype valueType = napi_undefined;
napi_typeof(env, argv[0], &valueType);
if (argc < 1) {
JsUtils::ThrowException(
env, IMFErrorCode::EXCEPTION_PARAMCHECK, " should 1 or 2 parameters!", TypeCode::TYPE_NONE);
return status;
}
if (valueType != napi_string) {
JsUtils::ThrowException(env, IMFErrorCode::EXCEPTION_PARAMCHECK, " 'text'", TypeCode::TYPE_STRING);
return status;
}
status = GetInsertText(env, argv[0], ctxt);
return status;
PARAM_CHECK_RETURN(env, argc > 0, "should 1 or 2 parameters!", TYPE_NONE, napi_generic_failure);
return JsUtils::GetValue(env, argv[0], ctxt->text);
};
auto output = [ctxt](napi_env env, napi_value *result) -> napi_status {
napi_status status = napi_get_boolean(env, ctxt->isInsertText, result);
@ -457,20 +279,8 @@ napi_value JsTextInputClientEngine::GetForward(napi_env env, napi_callback_info
{
auto ctxt = std::make_shared<GetForwardContext>();
auto input = [ctxt](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
napi_status status = napi_generic_failure;
napi_valuetype valueType = napi_undefined;
napi_typeof(env, argv[0], &valueType);
if (argc < 1) {
JsUtils::ThrowException(
env, IMFErrorCode::EXCEPTION_PARAMCHECK, " should 1 or 2 parameters!", TypeCode::TYPE_NONE);
return status;
}
if (valueType != napi_number) {
JsUtils::ThrowException(env, IMFErrorCode::EXCEPTION_PARAMCHECK, " 'length'", TypeCode::TYPE_NUMBER);
return status;
}
status = GetForwardLength(env, argv[0], ctxt);
return status;
PARAM_CHECK_RETURN(env, argc > 0, "should 1 or 2 parameters!", TYPE_NONE, napi_generic_failure);
return JsUtils::GetValue(env, argv[0], ctxt->length);
};
auto output = [ctxt](napi_env env, napi_value *result) -> napi_status {
napi_value data = GetResult(env, ctxt->text);
@ -497,20 +307,8 @@ napi_value JsTextInputClientEngine::GetBackward(napi_env env, napi_callback_info
{
auto ctxt = std::make_shared<GetBackwardContext>();
auto input = [ctxt](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
napi_status status = napi_generic_failure;
napi_valuetype valueType = napi_undefined;
if (argc < 1) {
JsUtils::ThrowException(
env, IMFErrorCode::EXCEPTION_PARAMCHECK, " should 1 or 2 parameters!", TypeCode::TYPE_NONE);
return status;
}
napi_typeof(env, argv[0], &valueType);
if (valueType != napi_number) {
JsUtils::ThrowException(env, IMFErrorCode::EXCEPTION_PARAMCHECK, " 'length'", TypeCode::TYPE_NUMBER);
return status;
}
status = GetBackwardLength(env, argv[0], ctxt);
return status;
PARAM_CHECK_RETURN(env, argc > 0, "should 1 or 2 parameters!", TYPE_NONE, napi_generic_failure);
return JsUtils::GetValue(env, argv[0], ctxt->length);
};
auto output = [ctxt](napi_env env, napi_value *result) -> napi_status {
napi_value data = GetResult(env, ctxt->text);
@ -563,17 +361,10 @@ napi_value JsTextInputClientEngine::SelectByRange(napi_env env, napi_callback_in
IMSA_HILOGD("run in");
auto ctxt = std::make_shared<SelectContext>();
auto input = [ctxt](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
if (argc < 1) {
JsUtils::ThrowException(
env, IMFErrorCode::EXCEPTION_PARAMCHECK, " should 1 or 2 parameters!", TypeCode::TYPE_NONE);
return napi_generic_failure;
}
PARAM_CHECK_RETURN(env, argc > 0, "should 1 or 2 parameters!", TYPE_NONE, napi_generic_failure);
napi_valuetype valueType = napi_undefined;
napi_typeof(env, argv[0], &valueType);
if (valueType != napi_object) {
JsUtils::ThrowException(env, IMFErrorCode::EXCEPTION_PARAMCHECK, "range", TypeCode::TYPE_OBJECT);
return napi_generic_failure;
}
PARAM_CHECK_RETURN(env, valueType == napi_object, "range", TYPE_OBJECT, napi_generic_failure);
return GetSelectRange(env, argv[0], ctxt);
};
auto output = [ctxt](napi_env env, napi_value *result) -> napi_status { return napi_ok; };
@ -596,17 +387,10 @@ napi_value JsTextInputClientEngine::SelectByMovement(napi_env env, napi_callback
IMSA_HILOGD("run in");
auto ctxt = std::make_shared<SelectContext>();
auto input = [ctxt](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
if (argc < 1) {
JsUtils::ThrowException(
env, IMFErrorCode::EXCEPTION_PARAMCHECK, " should 1 or 2 parameters!", TypeCode::TYPE_NONE);
return napi_generic_failure;
}
PARAM_CHECK_RETURN(env, argc > 0, "should 1 or 2 parameters!", TYPE_NONE, napi_generic_failure);
napi_valuetype valueType = napi_undefined;
napi_typeof(env, argv[0], &valueType);
if (valueType != napi_object) {
JsUtils::ThrowException(env, IMFErrorCode::EXCEPTION_PARAMCHECK, "movement", TypeCode::TYPE_OBJECT);
return napi_generic_failure;
}
PARAM_CHECK_RETURN(env, valueType == napi_object, "movement", TYPE_NUMBER, napi_generic_failure);
return GetSelectMovement(env, argv[0], ctxt);
};
auto output = [ctxt](napi_env env, napi_value *result) -> napi_status { return napi_ok; };

View File

@ -253,21 +253,10 @@ public:
static napi_value SelectByMovement(napi_env env, napi_callback_info info);
private:
static napi_status GetAction(napi_env env, napi_value argv, std::shared_ptr<SendKeyFunctionContext> ctxt);
static napi_status GetDeleteForwardLength(
napi_env env, napi_value argv, std::shared_ptr<DeleteForwardContext> ctxt);
static napi_status GetDeleteBackwardLength(
napi_env env, napi_value argv, std::shared_ptr<DeleteBackwardContext> ctxt);
static napi_status GetMoveCursorParam(napi_env env, napi_value argv, std::shared_ptr<MoveCursorContext> ctxt);
static napi_status GetInsertText(napi_env env, napi_value argv, std::shared_ptr<InsertTextContext> ctxt);
static napi_status GetForwardLength(napi_env env, napi_value argv, std::shared_ptr<GetForwardContext> ctxt);
static napi_status GetBackwardLength(napi_env env, napi_value argv, std::shared_ptr<GetBackwardContext> ctxt);
static napi_status GetSelectRange(napi_env env, napi_value argv, std::shared_ptr<SelectContext> ctxt);
static napi_status GetSelectMovement(napi_env env, napi_value argv, std::shared_ptr<SelectContext> ctxt);
static napi_value JsConstructor(napi_env env, napi_callback_info cbinfo);
static int32_t GetNumberProperty(napi_env env, napi_value jsNumber);
static std::string GetStringProperty(napi_env env, napi_value jsString);
static napi_value GetResult(napi_env env, std::string &text);
static napi_value GetResultEditorAttribute(
napi_env env, std::shared_ptr<GetEditorAttributeContext> getEditorAttribute);

View File

@ -0,0 +1,121 @@
/*
* Copyright (c) 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 "panel_listener_impl.h"
#include "js_utils.h"
namespace OHOS {
namespace MiscServices {
std::shared_ptr<PanelListenerImpl> PanelListenerImpl::instance_{ nullptr };
std::mutex PanelListenerImpl::listenerMutex_;
std::shared_ptr<PanelListenerImpl> PanelListenerImpl::GetInstance()
{
if (instance_ == nullptr) {
std::lock_guard<std::mutex> lock(listenerMutex_);
if (instance_ == nullptr) {
auto engine = std::make_shared<PanelListenerImpl>();
if (engine == nullptr) {
IMSA_HILOGE("input method engine nullptr");
return nullptr;
}
instance_ = engine;
}
}
return instance_;
}
PanelListenerImpl::~PanelListenerImpl()
{
env_ = nullptr;
}
void PanelListenerImpl::SaveInfo(napi_env env, const std::string &type, napi_value callback, uint32_t windowId)
{
env_ = env;
std::shared_ptr<JSCallbackObject> cbObject =
std::make_shared<JSCallbackObject>(env, callback, std::this_thread::get_id());
auto result = callbacks_.Find(windowId);
if (!result.first) {
ConcurrentMap<std::string, std::shared_ptr<JSCallbackObject>> cbs{};
cbs.Insert(type, cbObject);
callbacks_.Insert(windowId, cbs);
} else {
auto res = result.second.Find(type);
if (!res.first) {
result.second.Insert(type, cbObject);
}
}
}
void PanelListenerImpl::RemoveInfo(const std::string &type, uint32_t windowId)
{
auto result = callbacks_.Find(windowId);
if (result.first) {
result.second.Erase(type);
if (result.second.Empty()) {
callbacks_.Erase(windowId);
}
}
}
void PanelListenerImpl::OnPanelStatus(uint32_t windowId, bool isShow)
{
IMSA_HILOGI("PanelListenerImpl, run in");
std::string type = isShow ? "show" : "hide";
uv_work_t *work = new (std::nothrow) uv_work_t;
if (work == nullptr) {
IMSA_HILOGE("uv_work_t is nullptr!");
return;
}
auto result = callbacks_.Find(windowId);
if (!result.first) {
IMSA_HILOGE("no callback of windowId = %{public}d!", windowId);
return;
}
auto callback = result.second.Find(type);
if (!callback.first) {
IMSA_HILOGE("no callback in map!");
return;
}
work->data = new (std::nothrow) UvEntry(callback.second);
uv_loop_s *loop = nullptr;
napi_get_uv_event_loop(env_, &loop);
uv_queue_work(
loop, work, [](uv_work_t *work) {},
[](uv_work_t *work, int status) {
napi_value callback = nullptr;
std::shared_ptr<UvEntry> entry(static_cast<UvEntry *>(work->data), [work](UvEntry *data) {
delete data;
delete work;
});
CHECK_RETURN_VOID(entry != nullptr, "OnInputStart:: entry is null.");
napi_handle_scope scope = nullptr;
napi_open_handle_scope(entry->cbCopy->env_, &scope);
napi_get_reference_value(entry->cbCopy->env_, entry->cbCopy->callback_, &callback);
if (callback != nullptr) {
napi_value global = nullptr;
napi_get_global(entry->cbCopy->env_, &global);
napi_value result = nullptr;
napi_status callStatus = napi_call_function(entry->cbCopy->env_, global, callback, 0, nullptr, &result);
if (callStatus != napi_ok) {
IMSA_HILOGE("notify data change failed callStatus:%{public}d", callStatus);
}
}
napi_close_handle_scope(entry->cbCopy->env_, scope);
});
}
} // namespace MiscServices
} // namespace OHOS

View File

@ -0,0 +1,51 @@
/*
* Copyright (c) 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.
*/
#ifndef INPUTMETHOD_IMF_PANEL_LISTENER_IMPL_H
#define INPUTMETHOD_IMF_PANEL_LISTENER_IMPL_H
#include <mutex>
#include <thread>
#include <uv.h>
#include "concurrent_map.h"
#include "js_callback_object.h"
#include "panel_status_listener.h"
#include "napi/native_api.h"
#include "napi/native_node_api.h"
namespace OHOS {
namespace MiscServices {
class PanelListenerImpl : public PanelStatusListener {
public:
static std::shared_ptr<PanelListenerImpl> GetInstance();
~PanelListenerImpl();
void OnPanelStatus(uint32_t windowId, bool isShow) override;
void SaveInfo(napi_env env, const std::string &type, napi_value callback, uint32_t windowId);
void RemoveInfo(const std::string &type, uint32_t windowId);
struct UvEntry {
std::shared_ptr<JSCallbackObject> cbCopy;
explicit UvEntry(const std::shared_ptr<JSCallbackObject> &cb) : cbCopy(cb) {}
};
napi_env env_ = nullptr;
ConcurrentMap<uint32_t, ConcurrentMap<std::string, std::shared_ptr<JSCallbackObject>>> callbacks_;
static std::mutex listenerMutex_;
static std::shared_ptr<PanelListenerImpl> instance_;
};
} // namespace MiscServices
} // namespace OHOS
#endif //INPUTMETHOD_IMF_PANEL_LISTENER_IMPL_H

View File

@ -20,6 +20,7 @@
namespace OHOS {
namespace MiscServices {
constexpr size_t ARGC_MAX = 6;
AsyncCall::AsyncCall(napi_env env, napi_callback_info info, std::shared_ptr<Context> context, size_t pos) : env_(env)
{
context_ = new AsyncContext();
@ -111,10 +112,10 @@ void AsyncCall::OnComplete(napi_env env, napi_status status, void *data)
if (status == napi_ok && runStatus == napi_ok) {
napi_get_undefined(env, &result[ARG_ERROR]);
if (output != nullptr) {
IMSA_HILOGE("AsyncCall::OnComplete output != nullptr");
IMSA_HILOGI("AsyncCall::OnComplete output != nullptr");
result[ARG_DATA] = output;
} else {
IMSA_HILOGE("AsyncCall::OnComplete output == nullptr");
IMSA_HILOGI("AsyncCall::OnComplete output == nullptr");
napi_get_undefined(env, &result[ARG_DATA]);
}
} else {

View File

@ -16,6 +16,7 @@
#define ASYN_CALL_H
#include "input_method_info.h"
#include "global.h"
#include "js_utils.h"
#include "napi/native_api.h"
#include "napi/native_common.h"
@ -91,7 +92,6 @@ public:
napi_status status_ = napi_generic_failure;
int32_t errorCode_ = 0;
};
static constexpr size_t ARGC_MAX = 6;
static constexpr size_t ASYNC_DEFAULT_POS = -1;
AsyncCall(napi_env env, napi_callback_info info, std::shared_ptr<Context> context, size_t pos = ASYNC_DEFAULT_POS);
~AsyncCall();

View File

@ -26,7 +26,6 @@ namespace MiscServices {
constexpr size_t ARGC_ZERO = 0;
constexpr size_t ARGC_ONE = 1;
constexpr size_t ARGC_TWO = 2;
constexpr size_t ARGC_MAX = 6;
const std::set<std::string> EVENT_TYPE{
"selectByRange",
"selectByMovement",
@ -132,44 +131,6 @@ std::shared_ptr<JsGetInputMethodController> JsGetInputMethodController::GetInsta
return controller_;
}
JsGetInputMethodController *JsGetInputMethodController::GetNative(napi_env env, napi_callback_info info)
{
size_t argc = ARGC_MAX;
void *native = nullptr;
napi_value self = nullptr;
napi_value argv[ARGC_MAX] = { nullptr };
napi_status status = napi_invalid_arg;
napi_get_cb_info(env, info, &argc, argv, &self, nullptr);
if (self == nullptr && argc >= ARGC_MAX) {
IMSA_HILOGE("napi_get_cb_info failed");
return nullptr;
}
status = napi_unwrap(env, self, &native);
NAPI_ASSERT(env, (status == napi_ok && native != nullptr), "napi_unwrap failed!");
return reinterpret_cast<JsGetInputMethodController *>(native);
}
bool JsGetInputMethodController::Equals(napi_env env, napi_value value, napi_ref copy, std::thread::id threadId)
{
if (copy == nullptr) {
return (value == nullptr);
}
if (threadId != std::this_thread::get_id()) {
IMSA_HILOGD("napi_value can not be compared");
return false;
}
napi_value copyValue = nullptr;
napi_get_reference_value(env, copy, &copyValue);
bool isEquals = false;
napi_strict_equals(env, value, copyValue, &isEquals);
IMSA_HILOGD("value compare result: %{public}d", isEquals);
return isEquals;
}
void JsGetInputMethodController::RegisterListener(
napi_value callback, std::string type, std::shared_ptr<JSCallbackObject> callbackObj)
{
@ -181,7 +142,7 @@ void JsGetInputMethodController::RegisterListener(
auto callbacks = jsCbMap_[type];
bool ret = std::any_of(callbacks.begin(), callbacks.end(), [&callback](std::shared_ptr<JSCallbackObject> cb) {
return Equals(cb->env_, callback, cb->callback_, cb->threadId_);
return JsUtils::Equals(cb->env_, callback, cb->callback_, cb->threadId_);
});
if (ret) {
IMSA_HILOGE("JsGetInputMethodController callback already registered!");
@ -210,31 +171,13 @@ napi_value JsGetInputMethodController::Subscribe(napi_env env, napi_callback_inf
napi_value thisVar = nullptr;
void *data = nullptr;
NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, &data));
if (argc < ARGC_TWO) {
JsUtils::ThrowException(env, IMFErrorCode::EXCEPTION_PARAMCHECK, " should 2 parameters!", TypeCode::TYPE_NONE);
return nullptr;
}
PARAM_CHECK_RETURN(env, argc > 1, "should 2 parameters!", TYPE_NONE, nullptr);
napi_valuetype valuetype = napi_undefined;
napi_typeof(env, argv[ARGC_ZERO], &valuetype);
if (valuetype != napi_string) {
JsUtils::ThrowException(env, IMFErrorCode::EXCEPTION_PARAMCHECK, "type", TypeCode::TYPE_STRING);
return nullptr;
}
std::string type = "";
napi_status status = JsUtils::GetValue(env, argv[ARGC_ZERO], type);
PARAM_CHECK_RETURN(env, status == napi_ok, "callback", TYPE_FUNCTION, nullptr);
std::string type = JsInputMethod::GetStringProperty(env, argv[ARGC_ZERO]);
if (EVENT_TYPE.find(type) == EVENT_TYPE.end()) {
JsUtils::ThrowException(env, IMFErrorCode::EXCEPTION_PARAMCHECK, "unkown type", TypeCode::TYPE_NONE);
return nullptr;
}
napi_typeof(env, argv[ARGC_ONE], &valuetype);
if (valuetype != napi_function) {
JsUtils::ThrowException(env, IMFErrorCode::EXCEPTION_PARAMCHECK, "callback", TypeCode::TYPE_FUNCTION);
return nullptr;
}
auto engine = GetNative(env, info);
auto engine = reinterpret_cast<JsGetInputMethodController *>(JsUtils::GetNativeSelf(env, info));
if (engine == nullptr) {
return nullptr;
}
@ -254,25 +197,12 @@ napi_value JsGetInputMethodController::UnSubscribe(napi_env env, napi_callback_i
napi_value thisVar = nullptr;
void *data = nullptr;
NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, &data));
if (argc < ARGC_ONE) {
JsUtils::ThrowException(env, IMFErrorCode::EXCEPTION_PARAMCHECK, " should 1 parameters!", TypeCode::TYPE_NONE);
return nullptr;
}
PARAM_CHECK_RETURN(env, argc > 0, "should 1 parameters!", TYPE_NONE, nullptr);
napi_valuetype valuetype = napi_undefined;
napi_typeof(env, argv[ARGC_ZERO], &valuetype);
if (valuetype != napi_string) {
JsUtils::ThrowException(env, IMFErrorCode::EXCEPTION_PARAMCHECK, "type", TypeCode::TYPE_STRING);
return nullptr;
}
std::string type = JsInputMethod::GetStringProperty(env, argv[ARGC_ZERO]);
if (EVENT_TYPE.find(type) == EVENT_TYPE.end()) {
JsUtils::ThrowException(env, IMFErrorCode::EXCEPTION_PARAMCHECK, "unkown type", TypeCode::TYPE_NONE);
return nullptr;
}
auto engine = GetNative(env, info);
std::string type = "";
JsUtils::GetValue(env, argv[ARGC_ZERO], type);
PARAM_CHECK_RETURN(env, EVENT_TYPE.find(type) != EVENT_TYPE.end(), "unkown type", TYPE_NONE, nullptr);
auto engine = reinterpret_cast<JsGetInputMethodController *>(JsUtils::GetNativeSelf(env, info));
if (engine == nullptr) {
return nullptr;
}

View File

@ -68,8 +68,6 @@ private:
static napi_value GetIMController(napi_env env, napi_callback_info cbInfo, bool needThrowException);
static napi_value CreateSelectRange(napi_env env, int32_t start, int32_t end);
static napi_value CreateSelectMovement(napi_env env, int32_t direction);
static JsGetInputMethodController *GetNative(napi_env env, napi_callback_info info);
static bool Equals(napi_env env, napi_value value, napi_ref copy, std::thread::id threadId);
void RegisterListener(napi_value callback, std::string type, std::shared_ptr<JSCallbackObject> callbackObj);
void UnRegisterListener(std::string type);
struct UvEntry {

View File

@ -29,7 +29,6 @@ int32_t MAX_TYPE_NUM = 128;
constexpr size_t ARGC_ZERO = 0;
constexpr size_t ARGC_ONE = 1;
constexpr size_t ARGC_TWO = 2;
constexpr size_t ARGC_MAX = 6;
thread_local napi_ref JsGetInputMethodSetting::IMSRef_ = nullptr;
const std::string JsGetInputMethodSetting::IMS_CLASS_NAME = "InputMethodSetting";
@ -150,44 +149,41 @@ napi_status JsGetInputMethodSetting::GetInputMethodProperty(
napi_env env, napi_value argv, std::shared_ptr<ListInputContext> ctxt)
{
napi_valuetype valueType = napi_undefined;
napi_status status = napi_generic_failure;
status = napi_typeof(env, argv, &valueType);
napi_status status = napi_typeof(env, argv, &valueType);
if (valueType == napi_object) {
napi_value result = nullptr;
napi_get_named_property(env, argv, "name", &result);
ctxt->property.name = JsInputMethod::GetStringProperty(env, result);
JsUtils::GetValue(env, result, ctxt->property.name);
result = nullptr;
napi_get_named_property(env, argv, "id", &result);
ctxt->property.id = JsInputMethod::GetStringProperty(env, result);
JsUtils::GetValue(env, result, ctxt->property.id);
if (ctxt->property.name.empty() || ctxt->property.id.empty()) {
result = nullptr;
napi_get_named_property(env, argv, "packageName", &result);
ctxt->property.name = JsInputMethod::GetStringProperty(env, result);
JsUtils::GetValue(env, result, ctxt->property.name);
result = nullptr;
napi_get_named_property(env, argv, "methodId", &result);
ctxt->property.id = JsInputMethod::GetStringProperty(env, result);
}
if (ctxt->property.name.empty() || ctxt->property.id.empty()) {
JsUtils::ThrowException(env, IMFErrorCode::EXCEPTION_PARAMCHECK, "Parameter error.", TYPE_NONE);
return napi_invalid_arg;
JsUtils::GetValue(env, result, ctxt->property.id);
}
PARAM_CHECK_RETURN(env, (!ctxt->property.name.empty() && !ctxt->property.id.empty()), "Parameter error.",
TYPE_NONE, napi_invalid_arg);
result = nullptr;
napi_get_named_property(env, argv, "label", &result);
ctxt->property.label = JsInputMethod::GetStringProperty(env, result);
JsUtils::GetValue(env, result, ctxt->property.label);
result = nullptr;
napi_get_named_property(env, argv, "icon", &result);
ctxt->property.icon = JsInputMethod::GetStringProperty(env, result);
JsUtils::GetValue(env, result, ctxt->property.icon);
result = nullptr;
napi_get_named_property(env, argv, "iconId", &result);
ctxt->property.iconId = JsInputMethod::GetNumberProperty(env, result);
IMSA_HILOGD("methodId:%{public}s, packageName:%{public}s", ctxt->property.id.c_str(),
ctxt->property.name.c_str());
status = JsUtils::GetValue(env, result, ctxt->property.iconId);
IMSA_HILOGD(
"methodId:%{public}s, packageName:%{public}s", ctxt->property.id.c_str(), ctxt->property.name.c_str());
}
return status;
}
@ -224,20 +220,12 @@ napi_value JsGetInputMethodSetting::GetInputMethods(napi_env env, napi_callback_
IMSA_HILOGI("run in GetInputMethods");
auto ctxt = std::make_shared<ListInputContext>();
auto input = [ctxt](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
if (argc < 1) {
JsUtils::ThrowException(env, IMFErrorCode::EXCEPTION_PARAMCHECK, "should has one parameter.", TYPE_NONE);
return napi_invalid_arg;
}
napi_valuetype valueType = napi_undefined;
napi_typeof(env, argv[0], &valueType);
if (valueType == napi_boolean) {
bool enable = false;
napi_get_value_bool(env, argv[0], &enable);
ctxt->inputMethodStatus = enable ? InputMethodStatus::ENABLE : InputMethodStatus::DISABLE;
return napi_ok;
}
JsUtils::ThrowException(env, IMFErrorCode::EXCEPTION_PARAMCHECK, " parameter's type is wrong.", TYPE_BOOLEAN);
return napi_generic_failure;
PARAM_CHECK_RETURN(env, argc > 0, "should has one parameter.", TYPE_NONE, napi_invalid_arg);
bool enable = false;
napi_status status = JsUtils::GetValue(env, argv[ARGC_ZERO], enable);
PARAM_CHECK_RETURN(env, status == napi_ok, "enable.", TYPE_NUMBER, napi_invalid_arg);
ctxt->inputMethodStatus = enable ? InputMethodStatus::ENABLE : InputMethodStatus::DISABLE;
return napi_ok;
};
auto output = [ctxt](napi_env env, napi_value *result) -> napi_status {
*result = JsInputMethod::GetJSInputMethodProperties(env, ctxt->properties);
@ -312,16 +300,10 @@ napi_value JsGetInputMethodSetting::ListInputMethodSubtype(napi_env env, napi_ca
IMSA_HILOGI("run in ListInputMethodSubtype");
auto ctxt = std::make_shared<ListInputContext>();
auto input = [ctxt](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
if (argc < 1) {
JsUtils::ThrowException(env, IMFErrorCode::EXCEPTION_PARAMCHECK, "should has one parameter.", TYPE_NONE);
return napi_invalid_arg;
}
PARAM_CHECK_RETURN(env, argc > 0, "should has one parameter.", TYPE_NONE, napi_invalid_arg);
napi_valuetype valueType = napi_undefined;
napi_typeof(env, argv[0], &valueType);
if (valueType != napi_object) {
JsUtils::ThrowException(env, IMFErrorCode::EXCEPTION_PARAMCHECK, " inputMethodProperty: ", TYPE_OBJECT);
return napi_object_expected;
}
PARAM_CHECK_RETURN(env, valueType == napi_object, "inputMethodProperty", TYPE_OBJECT, napi_invalid_arg);
napi_status status = JsGetInputMethodSetting::GetInputMethodProperty(env, argv[0], ctxt);
return status;
};
@ -370,44 +352,6 @@ napi_value JsGetInputMethodSetting::ListCurrentInputMethodSubtype(napi_env env,
return asyncCall.Call(env, exec);
}
JsGetInputMethodSetting *JsGetInputMethodSetting::GetNative(napi_env env, napi_callback_info info)
{
size_t argc = ARGC_MAX;
void *native = nullptr;
napi_value self = nullptr;
napi_value argv[ARGC_MAX] = { nullptr };
napi_status status = napi_invalid_arg;
napi_get_cb_info(env, info, &argc, argv, &self, nullptr);
if (self == nullptr && argc >= ARGC_MAX) {
IMSA_HILOGE("napi_get_cb_info failed");
return nullptr;
}
status = napi_unwrap(env, self, &native);
NAPI_ASSERT(env, (status == napi_ok && native != nullptr), "napi_unwrap failed!");
return reinterpret_cast<JsGetInputMethodSetting *>(native);
}
bool JsGetInputMethodSetting::Equals(napi_env env, napi_value value, napi_ref copy, std::thread::id threadId)
{
if (copy == nullptr) {
return (value == nullptr);
}
if (threadId != std::this_thread::get_id()) {
IMSA_HILOGD("napi_value can not be compared");
return false;
}
napi_value copyValue = nullptr;
napi_get_reference_value(env, copy, &copyValue);
bool isEquals = false;
napi_strict_equals(env, value, copyValue, &isEquals);
IMSA_HILOGD("value compare result: %{public}d", isEquals);
return isEquals;
}
void JsGetInputMethodSetting::RegisterListener(
napi_value callback, std::string type, std::shared_ptr<JSCallbackObject> callbackObj)
{
@ -419,7 +363,7 @@ void JsGetInputMethodSetting::RegisterListener(
auto callbacks = jsCbMap_[type];
bool ret = std::any_of(callbacks.begin(), callbacks.end(), [&callback](std::shared_ptr<JSCallbackObject> cb) {
return Equals(cb->env_, callback, cb->callback_, cb->threadId_);
return JsUtils::Equals(cb->env_, callback, cb->callback_, cb->threadId_);
});
if (ret) {
IMSA_HILOGE("JsGetInputMethodSetting::RegisterListener callback already registered!");
@ -439,17 +383,15 @@ napi_value JsGetInputMethodSetting::Subscribe(napi_env env, napi_callback_info i
NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, &data));
NAPI_ASSERT(env, argc == ARGC_TWO, "Wrong number of arguments, requires 2");
napi_valuetype valuetype;
NAPI_CALL(env, napi_typeof(env, argv[ARGC_ZERO], &valuetype));
NAPI_ASSERT(env, valuetype == napi_string, "type is not a string");
std::string type = JsInputMethod::GetStringProperty(env, argv[ARGC_ZERO]);
std::string type = "";
JsUtils::GetValue(env, argv[ARGC_ZERO], type);
IMSA_HILOGE("event type is: %{public}s", type.c_str());
valuetype = napi_undefined;
napi_valuetype valuetype = napi_undefined;
napi_typeof(env, argv[ARGC_ONE], &valuetype);
NAPI_ASSERT(env, valuetype == napi_function, "callback is not a function");
auto engine = GetNative(env, info);
auto engine = reinterpret_cast<JsGetInputMethodSetting *>(JsUtils::GetNativeSelf(env, info));
if (engine == nullptr) {
return nullptr;
}
@ -478,7 +420,7 @@ void JsGetInputMethodSetting::UnRegisterListener(napi_value callback, std::strin
}
for (auto item = jsCbMap_[type].begin(); item != jsCbMap_[type].end(); item++) {
if (Equals((*item)->env_, callback, (*item)->callback_, (*item)->threadId_)) {
if (JsUtils::Equals((*item)->env_, callback, (*item)->callback_, (*item)->threadId_)) {
jsCbMap_[type].erase(item);
break;
}
@ -498,19 +440,16 @@ napi_value JsGetInputMethodSetting::UnSubscribe(napi_env env, napi_callback_info
NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, &data));
NAPI_ASSERT(env, argc == ARGC_ONE || argc == ARGC_TWO, "Wrong number of arguments, requires 1 or 2");
napi_valuetype valuetype;
NAPI_CALL(env, napi_typeof(env, argv[ARGC_ZERO], &valuetype));
NAPI_ASSERT(env, valuetype == napi_string, "type is not a string");
std::string type = JsInputMethod::GetStringProperty(env, argv[ARGC_ZERO]);
std::string type = "";
JsUtils::GetValue(env, argv[ARGC_ZERO], type);
IMSA_HILOGE("event type is: %{public}s", type.c_str());
auto engine = GetNative(env, info);
auto engine = reinterpret_cast<JsGetInputMethodSetting *>(JsUtils::GetNativeSelf(env, info));
if (engine == nullptr) {
return nullptr;
}
if (argc == ARGC_TWO) {
valuetype = napi_undefined;
napi_valuetype valuetype = napi_undefined;
napi_typeof(env, argv[ARGC_ONE], &valuetype);
NAPI_ASSERT(env, valuetype == napi_function, "callback is not a function");
}

View File

@ -113,11 +113,9 @@ public:
private:
static napi_status GetInputMethodProperty(napi_env env, napi_value argv, std::shared_ptr<ListInputContext> ctxt);
static JsGetInputMethodSetting *GetNative(napi_env env, napi_callback_info info);
static napi_value JsConstructor(napi_env env, napi_callback_info cbinfo);
static napi_value GetJsConstProperty(napi_env env, uint32_t num);
static napi_value GetIMSetting(napi_env env, napi_callback_info info, bool needThrowException);
static bool Equals(napi_env env, napi_value value, napi_ref copy, std::thread::id threadId);
void RegisterListener(napi_value callback, std::string type, std::shared_ptr<JSCallbackObject> callbackObj);
void UnRegisterListener(napi_value callback, std::string type);
struct UvEntry {

View File

@ -39,25 +39,6 @@ napi_value JsInputMethod::Init(napi_env env, napi_value exports)
return exports;
};
std::string JsInputMethod::GetStringProperty(napi_env env, napi_value obj)
{
char propValue[MAX_VALUE_LEN] = { 0 };
size_t propLen;
if (napi_get_value_string_utf8(env, obj, propValue, MAX_VALUE_LEN, &propLen) != napi_ok) {
IMSA_HILOGE("GetStringProperty error");
}
return std::string(propValue);
}
int32_t JsInputMethod::GetNumberProperty(napi_env env, napi_value obj)
{
int32_t out;
if (napi_get_value_int32(env, obj, &out) != napi_ok) {
IMSA_HILOGE("GetInt32Property error");
}
return out;
}
napi_status JsInputMethod::GetInputMethodProperty(
napi_env env, napi_value argv, std::shared_ptr<SwitchInputMethodContext> ctxt)
{
@ -70,23 +51,25 @@ napi_status JsInputMethod::GetInputMethodProperty(
}
napi_value result = nullptr;
napi_get_named_property(env, argv, "name", &result);
ctxt->packageName = JsInputMethod::GetStringProperty(env, result);
status = JsUtils::GetValue(env, result, ctxt->packageName);
NAPI_ASSERT_BASE(env, status == napi_ok, "get ctxt->packageName failed!", status);
result = nullptr;
napi_get_named_property(env, argv, "id", &result);
ctxt->methodId = JsInputMethod::GetStringProperty(env, result);
status = JsUtils::GetValue(env, result, ctxt->methodId);
NAPI_ASSERT_BASE(env, status == napi_ok, "get ctxt->methodId failed!", status);
if (ctxt->packageName.empty() || ctxt->methodId.empty()) {
result = nullptr;
napi_get_named_property(env, argv, "packageName", &result);
ctxt->packageName = JsInputMethod::GetStringProperty(env, result);
status = JsUtils::GetValue(env, result, ctxt->packageName);
NAPI_ASSERT_BASE(env, status == napi_ok, "get ctxt->packageName failed!", status);
result = nullptr;
napi_get_named_property(env, argv, "methodId", &result);
ctxt->methodId = JsInputMethod::GetStringProperty(env, result);
}
if (ctxt->packageName.empty() || ctxt->methodId.empty()) {
JsUtils::ThrowException(env, IMFErrorCode::EXCEPTION_PARAMCHECK, "Parameter error.", TYPE_NONE);
return status;
status = JsUtils::GetValue(env, result, ctxt->methodId);
NAPI_ASSERT_BASE(env, status == napi_ok, "get ctxt->methodId failed!", status);
}
PARAM_CHECK_RETURN(env, (!ctxt->packageName.empty() && !ctxt->methodId.empty()), "JsInputMethod, Parameter error.",
TYPE_NONE, napi_invalid_arg);
IMSA_HILOGI("methodId:%{public}s and packageName:%{public}s", ctxt->methodId.c_str(), ctxt->packageName.c_str());
return napi_ok;
}
@ -100,18 +83,14 @@ napi_status JsInputMethod::GetInputMethodSubProperty(
if (valueType == napi_object) {
napi_value result = nullptr;
status = napi_get_named_property(env, argv, "name", &result);
if (status != napi_ok) {
JsUtils::ThrowException(env, IMFErrorCode::EXCEPTION_PARAMCHECK, "missing name parameter.", TYPE_STRING);
return status;
}
ctxt->name = GetStringProperty(env, result);
PARAM_CHECK_RETURN(env, status == napi_ok, " name ", TYPE_STRING, status);
status = JsUtils::GetValue(env, result, ctxt->name);
NAPI_ASSERT_BASE(env, status == napi_ok, "get ctxt->name failed!", status);
result = nullptr;
status = napi_get_named_property(env, argv, "id", &result);
if (status != napi_ok) {
JsUtils::ThrowException(env, IMFErrorCode::EXCEPTION_PARAMCHECK, "missing id parameter.", TYPE_STRING);
return status;
}
ctxt->id = GetStringProperty(env, result);
PARAM_CHECK_RETURN(env, status == napi_ok, " id ", TYPE_STRING, status);
status = JsUtils::GetValue(env, result, ctxt->id);
NAPI_ASSERT_BASE(env, status == napi_ok, "get ctxt->id failed!", status);
IMSA_HILOGI("name:%{public}s and id:%{public}s", ctxt->name.c_str(), ctxt->id.c_str());
}
return status;
@ -125,16 +104,12 @@ napi_value JsInputMethod::GetJsInputMethodProperty(napi_env env, const Property
napi_value packageName = nullptr;
napi_create_string_utf8(env, property.name.c_str(), NAPI_AUTO_LENGTH, &packageName);
napi_set_named_property(env, prop, "packageName", packageName);
if (packageName == nullptr) {
napi_set_named_property(env, prop, "name", packageName);
}
napi_set_named_property(env, prop, "name", packageName);
napi_value methodId = nullptr;
napi_create_string_utf8(env, property.id.c_str(), NAPI_AUTO_LENGTH, &methodId);
napi_set_named_property(env, prop, "methodId", methodId);
if (methodId == nullptr) {
napi_set_named_property(env, prop, "id", methodId);
}
napi_set_named_property(env, prop, "id", methodId);
return prop;
}
@ -216,16 +191,10 @@ napi_value JsInputMethod::SwitchInputMethod(napi_env env, napi_callback_info inf
{
auto ctxt = std::make_shared<SwitchInputMethodContext>();
auto input = [ctxt](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
if (argc < 1) {
JsUtils::ThrowException(env, IMFErrorCode::EXCEPTION_PARAMCHECK, "should has 1 parameters!", TYPE_NONE);
return napi_invalid_arg;
}
PARAM_CHECK_RETURN(env, argc > 0, "should has 1 parameters!", TYPE_NONE, napi_invalid_arg);
napi_valuetype valueType = napi_undefined;
napi_typeof(env, argv[0], &valueType);
if (valueType != napi_object) {
JsUtils::ThrowException(env, IMFErrorCode::EXCEPTION_PARAMCHECK, " target: ", TYPE_OBJECT);
return napi_ok;
}
PARAM_CHECK_RETURN(env, valueType == napi_object, " target: ", TYPE_OBJECT, napi_invalid_arg);
napi_status status = GetInputMethodProperty(env, argv[0], ctxt);
return status;
};
@ -283,16 +252,10 @@ napi_value JsInputMethod::SwitchCurrentInputMethodSubtype(napi_env env, napi_cal
{
auto ctxt = std::make_shared<SwitchInputMethodContext>();
auto input = [ctxt](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
if (argc < 1) {
JsUtils::ThrowException(env, IMFErrorCode::EXCEPTION_PARAMCHECK, "should has one parameter.", TYPE_NONE);
return napi_invalid_arg;
}
PARAM_CHECK_RETURN(env, argc > 0, "should has one parameter. ", TYPE_NONE, napi_invalid_arg);
napi_valuetype valueType = napi_undefined;
napi_typeof(env, argv[0], &valueType);
if (valueType != napi_object) {
JsUtils::ThrowException(env, IMFErrorCode::EXCEPTION_PARAMCHECK, " inputMethodSubtype: ", TYPE_OBJECT);
return napi_object_expected;
}
PARAM_CHECK_RETURN(env, valueType == napi_object, "inputMethodSubtype: ", TYPE_OBJECT, napi_object_expected);
napi_status status = GetInputMethodSubProperty(env, argv[0], ctxt);
return status;
};
@ -326,21 +289,12 @@ napi_value JsInputMethod::SwitchCurrentInputMethodAndSubtype(napi_env env, napi_
{
auto ctxt = std::make_shared<SwitchInputMethodContext>();
auto input = [ctxt](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
if (argc < 2) {
JsUtils::ThrowException(env, IMFErrorCode::EXCEPTION_PARAMCHECK, "should has two parameter.", TYPE_NONE);
return napi_invalid_arg;
}
PARAM_CHECK_RETURN(env, argc > 1, "should has two parameter.", TYPE_NONE, napi_invalid_arg);
napi_valuetype valueType = napi_undefined;
napi_typeof(env, argv[0], &valueType);
if (valueType != napi_object) {
JsUtils::ThrowException(env, IMFErrorCode::EXCEPTION_PARAMCHECK, " inputMethodProperty: ", TYPE_OBJECT);
return napi_object_expected;
}
PARAM_CHECK_RETURN(env, valueType == napi_object, "inputMethodProperty: ", TYPE_OBJECT, napi_object_expected);
napi_typeof(env, argv[1], &valueType);
if (valueType != napi_object) {
JsUtils::ThrowException(env, IMFErrorCode::EXCEPTION_PARAMCHECK, " inputMethodSubtype: ", TYPE_OBJECT);
return napi_object_expected;
}
PARAM_CHECK_RETURN(env, valueType == napi_object, "inputMethodSubtype: ", TYPE_OBJECT, napi_object_expected);
napi_status status = GetInputMethodSubProperty(env, argv[1], ctxt);
return status;
};

View File

@ -58,11 +58,9 @@ public:
static napi_value SwitchCurrentInputMethodAndSubtype(napi_env env, napi_callback_info info);
static napi_value GetCurrentInputMethodSubtype(napi_env env, napi_callback_info info);
static napi_value GetCurrentInputMethod(napi_env env, napi_callback_info info);
static int32_t GetNumberProperty(napi_env env, napi_value obj);
static napi_value GetJsInputMethodProperty(napi_env env, const Property &property);
static napi_value GetJSInputMethodSubProperties(napi_env env, const std::vector<SubProperty> &subProperties);
static napi_value GetJSInputMethodProperties(napi_env env, const std::vector<Property> &properties);
static std::string GetStringProperty(napi_env env, napi_value obj);
static napi_value GetJsInputMethodSubProperty(napi_env env, const SubProperty &subProperty);
private:

View File

@ -17,8 +17,11 @@
namespace OHOS {
namespace MiscServices {
constexpr int32_t STR_MAX_LENGTH = 4096;
constexpr size_t STR_TAIL_LENGTH = 1;
constexpr size_t ARGC_MAX = 6;
const std::map<int32_t, int32_t> JsUtils::ERROR_CODE_MAP = {
{ ErrorCode::ERROR_CONTROLLER_INVOKING_FAILED, EXCEPTION_CONTROLLER},
{ ErrorCode::ERROR_CONTROLLER_INVOKING_FAILED, EXCEPTION_CONTROLLER },
{ ErrorCode::ERROR_STATUS_PERMISSION_DENIED, EXCEPTION_PERMISSION },
{ ErrorCode::ERROR_REMOTE_CLIENT_DIED, EXCEPTION_IMCLIENT },
{ ErrorCode::ERROR_CLIENT_NOT_FOUND, EXCEPTION_IMCLIENT },
@ -128,8 +131,8 @@ const std::string JsUtils::ToMessage(int32_t code)
return "error is out of definition.";
}
bool JsUtils::TraverseCallback(const std::vector<std::shared_ptr<JSCallbackObject>> &vecCopy, size_t paramNum,
ArgsProvider argsProvider)
bool JsUtils::TraverseCallback(
const std::vector<std::shared_ptr<JSCallbackObject>> &vecCopy, size_t paramNum, ArgsProvider argsProvider)
{
bool isResult = false;
bool isOnKeyEvent = false;
@ -164,7 +167,7 @@ bool JsUtils::TraverseCallback(const std::vector<std::shared_ptr<JSCallbackObjec
if (valueType != napi_boolean) {
continue;
}
napi_get_value_bool(item->env_, result, &isResult);
GetValue(item->env_, result, isResult);
if (isResult) {
isOnKeyEvent = true;
}
@ -173,5 +176,94 @@ bool JsUtils::TraverseCallback(const std::vector<std::shared_ptr<JSCallbackObjec
}
return isOnKeyEvent;
}
bool JsUtils::Equals(napi_env env, napi_value value, napi_ref copy, std::thread::id threadId)
{
if (copy == nullptr) {
return value == nullptr;
}
if (threadId != std::this_thread::get_id()) {
IMSA_HILOGD("napi_value can not be compared");
return false;
}
napi_value copyValue = nullptr;
napi_get_reference_value(env, copy, &copyValue);
bool isEquals = false;
napi_strict_equals(env, value, copyValue, &isEquals);
IMSA_HILOGD("value compare result: %{public}d", isEquals);
return isEquals;
}
void *JsUtils::GetNativeSelf(napi_env env, napi_callback_info info)
{
size_t argc = ARGC_MAX;
void *native = nullptr;
napi_value self = nullptr;
napi_value argv[ARGC_MAX] = { nullptr };
napi_status status = napi_invalid_arg;
napi_get_cb_info(env, info, &argc, argv, &self, nullptr);
NAPI_ASSERT(env, (self != nullptr && argc <= ARGC_MAX), "napi_get_cb_info failed!");
status = napi_unwrap(env, self, &native);
NAPI_ASSERT(env, (status == napi_ok && native != nullptr), "napi_unwrap failed!");
return native;
}
napi_status JsUtils::GetValue(napi_env env, napi_value in, int32_t &out)
{
napi_valuetype type = napi_undefined;
napi_status status = napi_typeof(env, in, &type);
NAPI_ASSERT_BASE(env, (status == napi_ok) && (type == napi_number), "invalid type", status);
return napi_get_value_int32(env, in, &out);
}
/* napi_value <-> uint32_t */
napi_status JsUtils::GetValue(napi_env env, napi_value in, uint32_t &out)
{
napi_valuetype type = napi_undefined;
napi_status status = napi_typeof(env, in, &type);
NAPI_ASSERT_BASE(env, (status == napi_ok) && (type == napi_number), "invalid type", status);
return napi_get_value_uint32(env, in, &out);
}
napi_status JsUtils::GetValue(napi_env env, napi_value in, bool &out)
{
napi_valuetype type = napi_undefined;
napi_status status = napi_typeof(env, in, &type);
NAPI_ASSERT_BASE(env, (status == napi_ok) && (type == napi_boolean), "invalid type", status);
return napi_get_value_bool(env, in, &out);
}
/* napi_value <-> std::string */
napi_status JsUtils::GetValue(napi_env env, napi_value in, std::string &out)
{
IMSA_HILOGD("JsUtils get string value in.");
napi_valuetype type = napi_undefined;
napi_status status = napi_typeof(env, in, &type);
NAPI_ASSERT_BASE(env, (status == napi_ok) && (type == napi_string), "invalid type", status);
size_t maxLen = STR_MAX_LENGTH;
status = napi_get_value_string_utf8(env, in, NULL, 0, &maxLen);
if (maxLen <= 0) {
return status;
}
IMSA_HILOGD("napi_value -> std::string get length %{public}d", maxLen);
char *buf = new (std::nothrow) char[maxLen + STR_TAIL_LENGTH];
if (buf != nullptr) {
size_t len = 0;
status = napi_get_value_string_utf8(env, in, buf, maxLen + STR_TAIL_LENGTH, &len);
if (status == napi_ok) {
buf[len] = 0;
out = std::string(buf);
}
delete[] buf;
} else {
status = napi_generic_failure;
}
return status;
}
} // namespace MiscServices
} // namespace OHOS

View File

@ -24,7 +24,9 @@
#include "napi/native_node_api.h"
#include "string_ex.h"
#include "js_callback_object.h"
#include "ability.h"
using Ability = OHOS::AppExecFwk::Ability;
namespace OHOS {
namespace MiscServices {
enum IMFErrorCode : int32_t {
@ -55,6 +57,24 @@ enum TypeCode : int32_t {
TYPE_BIGINT,
};
/* check condition, return and logging if condition not true. */
#define PARAM_CHECK_RETURN(env, condition, message, typeCode, retVal) \
do { \
if (!(condition)) { \
JsUtils::ThrowException(env, IMFErrorCode::EXCEPTION_PARAMCHECK, message, typeCode); \
return retVal; \
} \
} while (0)
/* check condition, return and logging. */
#define CHECK_RETURN_VOID(condition, message) \
do { \
if (!(condition)) { \
IMSA_HILOGE("test (" #condition ") failed: " message); \
return; \
} \
} while (0)
class JsUtils {
public:
using ArgsProvider = std::function<bool(napi_value args[], uint8_t argc, std::shared_ptr<JSCallbackObject>)>;
@ -64,8 +84,16 @@ public:
static napi_value ToError(napi_env env, int32_t code);
static bool TraverseCallback(const std::vector<std::shared_ptr<JSCallbackObject>> &vecCopy, size_t paramNum,
ArgsProvider argsProvider);
ArgsProvider argsProvider);
static bool Equals(napi_env env, napi_value value, napi_ref copy, std::thread::id threadId);
static void *GetNativeSelf(napi_env env, napi_callback_info info);
static napi_status GetValue(napi_env env, napi_value in, int32_t &out);
static napi_status GetValue(napi_env env, napi_value in, uint32_t &out);
static napi_status GetValue(napi_env env, napi_value in, bool &out);
static napi_status GetValue(napi_env env, napi_value in, std::string &out);
private:
static int32_t Convert(int32_t code);

View File

@ -19,14 +19,20 @@ config("inputmethod_ability_native_config") {
include_dirs = [
"include",
"${inputmethod_path}/frameworks/native/inputmethod_controller/include",
"${inputmethod_path}/frameworks/common",
"${inputmethod_path}/services/include",
"${windowmanager_path}/interfaces/innerkits/dm",
"${windowmanager_path}/interfaces/innerkits/wm",
]
}
config("inputmethod_ability_native_public_config") {
visibility = []
include_dirs = [
"include",
"${inputmethod_path}/frameworks/common",
"${inputmethod_path}/services/include",
"${windowmanager_path}/interfaces/innerkits/dm",
"${windowmanager_path}/interfaces/innerkits/wm",
]
}
@ -45,17 +51,23 @@ ohos_shared_library("inputmethod_ability") {
"src/input_method_agent_stub.cpp",
"src/input_method_core_proxy.cpp",
"src/input_method_core_stub.cpp",
"src/input_method_panel.cpp",
]
configs = [ ":inputmethod_ability_native_config" ]
external_deps = [
"ability_runtime:ability_context_native",
"c_utils:utils",
"hiviewdfx_hilog_native:libhilog",
"ipc:ipc_single",
"samgr:samgr_proxy",
"window_manager:libdm",
"window_manager:libwm",
]
deps = [ "${graphic_path}/render_service_client:librender_service_client" ]
public_configs = [ ":inputmethod_ability_native_public_config" ]
subsystem_name = "inputmethod"

View File

@ -18,6 +18,7 @@
#include <thread>
#include "concurrent_map.h"
#include "i_input_control_channel.h"
#include "i_input_data_channel.h"
#include "i_input_method_agent.h"
@ -28,6 +29,7 @@
#include "input_data_channel_proxy.h"
#include "input_method_core_stub.h"
#include "input_method_engine_listener.h"
#include "input_method_panel.h"
#include "input_method_system_ability_proxy.h"
#include "iremote_object.h"
#include "keyboard_listener.h"
@ -35,6 +37,10 @@
#include "message_handler.h"
#include "utils.h"
namespace OHOS::AbilityRuntime {
class Context;
}
namespace OHOS {
namespace MiscServices {
struct InputStartNotifier {
@ -66,6 +72,9 @@ public:
int32_t GetInputPattern(int32_t &inputPattern);
int32_t GetTextIndexAtCursor(int32_t &index);
void OnImeReady();
int32_t CreatePanel(const std::shared_ptr<AbilityRuntime::Context> &context, const PanelInfo &panelInfo,
std::shared_ptr<InputMethodPanel> &inputMethodPanel);
int32_t DestroyPanel(const std::shared_ptr<InputMethodPanel> &inputMethodPanel);
private:
std::thread workThreadHandler;
@ -117,6 +126,7 @@ private:
void DismissInputWindow();
bool isImeReady_{ false };
InputStartNotifier notifier_;
ConcurrentMap<PanelType, std::shared_ptr<InputMethodPanel>> panels_{};
};
} // namespace MiscServices
} // namespace OHOS

View File

@ -0,0 +1,85 @@
/*
* Copyright (c) 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.
*/
#ifndef INPUT_METHOD_PANEL_H
#define INPUT_METHOD_PANEL_H
#include <cstdint>
#include <map>
#include <string>
#include "panel_status_listener.h"
#include "window.h"
#include "window_option.h"
#include "wm_common.h"
class NativeValue;
class NativeEngine;
namespace OHOS {
using namespace OHOS::Rosen;
namespace MiscServices {
enum PanelType {
SOFT_KEYBOARD = 0,
STATUS_BAR,
};
enum PanelFlag {
FLG_FIXED = 0,
FLG_FLOATING,
};
struct PanelInfo {
PanelType panelType = SOFT_KEYBOARD;
PanelFlag panelFlag = FLG_FIXED;
};
class InputMethodPanel {
public:
InputMethodPanel() = default;
~InputMethodPanel();
int32_t SetUiContent(const std::string& contentInfo, NativeEngine* engine, NativeValue* storage);
int32_t CreatePanel(const std::shared_ptr<AbilityRuntime::Context> &context, const PanelInfo &panelInfo);
int32_t DestroyPanel();
int32_t Resize(uint32_t width, uint32_t height);
int32_t MoveTo(int32_t x, int32_t y);
int32_t ChangePanelFlag(PanelFlag panelFlag);
PanelType GetPanelType();
int32_t ShowPanel();
int32_t HidePanel();
void SetPanelStatusListener(std::shared_ptr<PanelStatusListener> statusListener);
void RemovePanelListener(const std::string &type);
uint32_t windowId_ = 0;
private:
bool IsShowing();
bool IsHidden();
static uint32_t GenerateSequenceId();
sptr<Window> window_ = nullptr;
sptr<WindowOption> winOption_ = nullptr;
PanelType panelType_ = PanelType::SOFT_KEYBOARD;
PanelFlag panelFlag_ = PanelFlag::FLG_FIXED;
bool showRegistered_ = true;
bool hideRegistered_ = true;
uint32_t invalidGravityPercent = 0;
std::shared_ptr<PanelStatusListener> panelStatusListener_ = nullptr;
static std::atomic<uint32_t> sequenceId_;
};
}
}
#endif //INPUT_METHOD_PANEL_H

View File

@ -0,0 +1,29 @@
/*
* Copyright (c) 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.
*/
#ifndef INPUTMETHOD_IMF_PANEL_STATUS_LISTENER_H
#define INPUTMETHOD_IMF_PANEL_STATUS_LISTENER_H
namespace OHOS {
namespace MiscServices {
class PanelStatusListener {
public:
virtual ~PanelStatusListener(){};
virtual void OnPanelStatus(uint32_t windowId, bool isShow) = 0;
};
} // namespace MiscServices
} // namespace OHOS
#endif //INPUTMETHOD_IMF_PANEL_STATUS_LISTENER_H

View File

@ -27,8 +27,8 @@
#include "itypes_util.h"
#include "message_parcel.h"
#include "string_ex.h"
#include "system_ability_definition.h"
#include "sys/prctl.h"
#include "system_ability_definition.h"
namespace OHOS {
namespace MiscServices {
@ -359,6 +359,16 @@ void InputMethodAbility::ShowInputWindow(bool isShowKeyboard, const SubProperty
return;
}
channel->SendKeyboardStatus(KEYBOARD_SHOW);
auto result = panels_.Find(SOFT_KEYBOARD);
if (!result.first) {
IMSA_HILOGE("Not find SOFT_KEYBOARD panel.");
return;
}
auto ret = result.second->ShowPanel();
if (ret != NO_ERROR) {
IMSA_HILOGE("Show panel failed, ret = %{public}d.", ret);
return;
}
}
void InputMethodAbility::DismissInputWindow()
@ -375,6 +385,16 @@ void InputMethodAbility::DismissInputWindow()
return;
}
channel->SendKeyboardStatus(KEYBOARD_HIDE);
auto result = panels_.Find(SOFT_KEYBOARD);
if (!result.first) {
IMSA_HILOGE("Not find SOFT_KEYBOARD panel.");
return;
}
auto ret = result.second->HidePanel();
if (ret != NO_ERROR) {
IMSA_HILOGE("Show panel failed, ret = %{public}d.", ret);
return;
}
}
int32_t InputMethodAbility::InsertText(const std::string text)
@ -566,5 +586,44 @@ void InputMethodAbility::QuitWorkThread()
workThreadHandler.join();
}
}
int32_t InputMethodAbility::CreatePanel(const std::shared_ptr<AbilityRuntime::Context> &context,
const PanelInfo &panelInfo, std::shared_ptr<InputMethodPanel> &inputMethodPanel)
{
IMSA_HILOGI("InputMethodAbility::CreatePanel start.");
auto result = panels_.Find(panelInfo.panelType);
if (result.first) {
IMSA_HILOGE(" type of %{public}d panel already created, can not create another", panelInfo.panelType);
return ErrorCode::ERROR_OPERATE_PANEL;
}
inputMethodPanel = std::make_shared<InputMethodPanel>();
if (inputMethodPanel == nullptr) {
return ErrorCode::ERROR_BAD_PARAMETERS;
}
auto ret = inputMethodPanel->CreatePanel(context, panelInfo);
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("CreatePanel failed, ret = %{public}d", ret);
return ret;
}
IMSA_HILOGI("InputMethodAbility::CreatePanel ret = 0, success.");
if (!panels_.Insert(panelInfo.panelType, inputMethodPanel)) {
IMSA_HILOGE("insert inputMethodPanel fail.");
return ErrorCode::ERROR_OPERATE_PANEL;
}
return ErrorCode::NO_ERROR;
}
int32_t InputMethodAbility::DestroyPanel(const std::shared_ptr<InputMethodPanel> &inputMethodPanel)
{
if (inputMethodPanel == nullptr) {
return ErrorCode::ERROR_BAD_PARAMETERS;
}
PanelType panelType = inputMethodPanel->GetPanelType();
auto ret = inputMethodPanel->DestroyPanel();
if (ret == ErrorCode::NO_ERROR) {
panels_.Erase(panelType);
}
return ret;
}
} // namespace MiscServices
} // namespace OHOS

View File

@ -0,0 +1,263 @@
/*
* Copyright (C) 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_panel.h"
#include "display_manager.h"
#include "global.h"
#include "window.h"
#include "wm_common.h"
namespace OHOS {
namespace MiscServices {
using WMError = OHOS::Rosen::WMError;
using WindowGravity = OHOS::Rosen::WindowGravity;
using WindowState = OHOS::Rosen::WindowState;
std::atomic<uint32_t> InputMethodPanel::sequenceId_{ 0 };
InputMethodPanel::~InputMethodPanel() = default;
int32_t InputMethodPanel::CreatePanel(
const std::shared_ptr<AbilityRuntime::Context> &context, const PanelInfo &panelInfo)
{
IMSA_HILOGD("InputMethodPanel start to create panel.");
panelType_ = panelInfo.panelType;
panelFlag_ = panelInfo.panelFlag;
winOption_ = new (std::nothrow) OHOS::Rosen::WindowOption();
if (winOption_ == nullptr) {
return ErrorCode::ERROR_NULL_POINTER;
}
winOption_->SetWindowType(OHOS::Rosen::WindowType::WINDOW_TYPE_INPUT_METHOD_FLOAT);
WMError wmError = WMError::WM_OK;
WindowGravity gravity = WindowGravity::WINDOW_GRAVITY_FLOAT;
if (panelType_ == SOFT_KEYBOARD && panelFlag_ == FLG_FIXED) {
gravity = WindowGravity::WINDOW_GRAVITY_BOTTOM;
}
uint32_t sequenceId = GenerateSequenceId();
std::string windowName = panelType_ == SOFT_KEYBOARD ? "softKeyboard" + std::to_string(sequenceId)
: "statusBar" + std::to_string(sequenceId);
IMSA_HILOGD("InputMethodPanel, windowName = %{public}s", windowName.c_str());
window_ = OHOS::Rosen::Window::Create(windowName, winOption_, context, wmError);
if (wmError == WMError::WM_ERROR_INVALID_PERMISSION) {
return ErrorCode::ERROR_STATUS_PERMISSION_DENIED;
}
if (window_ == nullptr || wmError != WMError::WM_OK) {
return ErrorCode::ERROR_OPERATE_PANEL;
}
windowId_ = window_->GetWindowId();
IMSA_HILOGD("GetWindowId, windowId = %{public}u", windowId_);
wmError = window_->SetWindowGravity(gravity, invalidGravityPercent);
if (wmError == WMError::WM_OK) {
return ErrorCode::NO_ERROR;
}
wmError = window_->Destroy();
return wmError == WMError::WM_OK ? ErrorCode::NO_ERROR : ErrorCode::ERROR_OPERATE_PANEL;
}
int32_t InputMethodPanel::DestroyPanel()
{
auto ret = HidePanel();
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGI("InputMethodPanel, hide panel failed, ret = %{public}d.", ret);
return ret;
}
auto result = window_->Destroy();
if (result != WMError::WM_OK) {
IMSA_HILOGE("InputMethodPanel, destroy panel error, ret = %{public}d", result);
return ErrorCode::ERROR_OPERATE_PANEL;
}
return ErrorCode::NO_ERROR;
}
int32_t InputMethodPanel::Resize(uint32_t width, uint32_t height)
{
if (window_ == nullptr) {
return ErrorCode::ERROR_NULL_POINTER;
}
auto defaultDisplay = Rosen::DisplayManager::GetInstance().GetDefaultDisplay();
if (defaultDisplay == nullptr) {
IMSA_HILOGE("GetDefaultDisplay failed.");
return ErrorCode::ERROR_NULL_POINTER;
}
if (width > defaultDisplay->GetWidth() || height > (defaultDisplay->GetHeight()) / 2) {
IMSA_HILOGD("GetDefaultDisplay, defaultDisplay->width = %{public}d, defaultDisplay->height = %{public}d, "
"width = %{public}u, height = %{public}u",
defaultDisplay->GetWidth(), defaultDisplay->GetHeight(), width, height);
return ErrorCode::ERROR_BAD_PARAMETERS;
}
auto ret = window_->Resize(width, height);
return ret == WMError::WM_OK ? ErrorCode::NO_ERROR : ErrorCode::ERROR_OPERATE_PANEL;
}
int32_t InputMethodPanel::MoveTo(int32_t x, int32_t y)
{
if (panelType_ == SOFT_KEYBOARD && panelFlag_ == FLG_FIXED) {
IMSA_HILOGE("FLG_FIXED panel can not moveTo.");
return ErrorCode::NO_ERROR;
}
if (window_ == nullptr) {
IMSA_HILOGE("window_ is nullptr.");
return ErrorCode::ERROR_NULL_POINTER;
}
auto ret = window_->MoveTo(x, y);
if (ret != WMError::WM_OK) {
return ErrorCode::ERROR_OPERATE_PANEL;
}
return ErrorCode::NO_ERROR;
}
int32_t InputMethodPanel::ChangePanelFlag(PanelFlag panelFlag)
{
if (window_ == nullptr) {
IMSA_HILOGE("window_ is nullptr.");
return ErrorCode::ERROR_NULL_POINTER;
}
if (panelFlag_ == panelFlag) {
return ErrorCode::NO_ERROR;
}
if (panelType_ == STATUS_BAR) {
IMSA_HILOGE("STATUS_BAR cannot ChangePanelFlag.");
return ErrorCode::ERROR_BAD_PARAMETERS;
}
panelFlag_ = panelFlag;
WindowGravity gravity = WindowGravity::WINDOW_GRAVITY_FLOAT;
if (panelFlag == FLG_FIXED) {
gravity = WindowGravity::WINDOW_GRAVITY_BOTTOM;
}
auto ret = window_->SetWindowGravity(gravity, invalidGravityPercent);
return ret == WMError::WM_OK ? ErrorCode::NO_ERROR : ErrorCode::ERROR_OPERATE_PANEL;
}
PanelType InputMethodPanel::GetPanelType()
{
return panelType_;
}
int32_t InputMethodPanel::ShowPanel()
{
if (window_ == nullptr) {
IMSA_HILOGE("window_ is nullptr.");
return ErrorCode::ERROR_NULL_POINTER;
}
if (IsShowing()) {
IMSA_HILOGE("Panel already shown.");
return ErrorCode::NO_ERROR;
}
auto ret = window_->Show();
if (ret != WMError::WM_OK) {
IMSA_HILOGE("ShowPanel error, err = %{public}d, ERROR_SHOW_PANEL", ret);
return ErrorCode::ERROR_OPERATE_PANEL;
}
if (showRegistered_ && panelStatusListener_ != nullptr) {
IMSA_HILOGE("InputMethodPanel::ShowPanel panelStatusListener_ is not nullptr");
panelStatusListener_->OnPanelStatus(windowId_, true);
}
return ErrorCode::NO_ERROR;
}
int32_t InputMethodPanel::HidePanel()
{
if (window_ == nullptr) {
IMSA_HILOGE("window_ is nullptr.");
return ErrorCode::ERROR_NULL_POINTER;
}
if (IsHidden()) {
IMSA_HILOGE("Panel already hidden.");
return ErrorCode::NO_ERROR;
}
auto ret = window_->Hide();
if (ret != WMError::WM_OK) {
IMSA_HILOGE("HidePanel error, err = %{public}d, ERROR_HIDE_PANEL", ret);
return ErrorCode::ERROR_OPERATE_PANEL;
}
if (hideRegistered_ && panelStatusListener_ != nullptr) {
IMSA_HILOGE("InputMethodPanel::HidePanel panelStatusListener_ is not nullptr");
panelStatusListener_->OnPanelStatus(windowId_, false);
}
return ErrorCode::NO_ERROR;
}
bool InputMethodPanel::IsShowing()
{
WindowState windowState = window_->GetWindowState();
if (windowState == WindowState::STATE_SHOWN) {
return true;
}
IMSA_HILOGD("InputMethodPanel windowState = %{public}d", static_cast<int>(windowState));
return false;
}
bool InputMethodPanel::IsHidden()
{
WindowState windowState = window_->GetWindowState();
if (windowState == WindowState::STATE_HIDDEN) {
return true;
}
IMSA_HILOGD("InputMethodPanel windowState = %{public}d", static_cast<int>(windowState));
return false;
}
int32_t InputMethodPanel::SetUiContent(const std::string &contentInfo, NativeEngine *engine, NativeValue *storage)
{
if (window_ == nullptr) {
IMSA_HILOGE("window_ is nullptr, can not SetUiContent.");
return ErrorCode::ERROR_NULL_POINTER;
}
auto ret = window_->SetUIContent(contentInfo, engine, storage);
if (ret != WMError::WM_OK) {
return ErrorCode::ERROR_OPERATE_PANEL;
}
return ErrorCode::NO_ERROR;
}
void InputMethodPanel::SetPanelStatusListener(std::shared_ptr<PanelStatusListener> statusListener)
{
IMSA_HILOGD("SetPanelStatusListener start.");
if (panelStatusListener_ != nullptr) {
IMSA_HILOGE("PanelStatusListener already set.");
return;
}
panelStatusListener_ = std::move(statusListener);
}
void InputMethodPanel::RemovePanelListener(const std::string &type)
{
if (type == "show") {
showRegistered_ = false;
} else if (type == "hide") {
hideRegistered_ = false;
} else {
IMSA_HILOGE("type error.");
return;
}
if (panelStatusListener_ == nullptr) {
IMSA_HILOGE("PanelStatusListener not set, don't need to remove.");
return;
}
if (showRegistered_ || hideRegistered_) {
return;
}
panelStatusListener_ = nullptr;
}
uint32_t InputMethodPanel::GenerateSequenceId()
{
uint32_t seqId = ++sequenceId_;
if (seqId == std::numeric_limits<uint32_t>::max()) {
return ++sequenceId_;
}
return seqId;
}
} // namespace MiscServices
} // namespace OHOS

View File

@ -1,4 +1,4 @@
# Copyright (C) 2021 Huawei Device Co., Ltd.
# 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
@ -28,3 +28,7 @@ kits_path = "${inputmethod_path}/interfaces/kits"
innerkits_path = "${inputmethod_path}/interfaces/innerkits"
adapter_path = "${inputmethod_path}/adapter"
graphic_path = "//foundation/graphic/graphic_2d/rosen/modules"
windowmanager_path = "//foundation/window/window_manager"

View File

@ -91,6 +91,7 @@ enum {
ERROR_CLIENT_NOT_EDITABLE = 17,
ERROR_CLIENT_NOT_FOCUSED = 18,
ERROR_CLIENT_ADD_FAILED = 19,
ERROR_OPERATE_PANEL = 20,
};
}; // namespace ErrorCode

View File

@ -22,6 +22,7 @@ group("unittest") {
"cpp_test:InputMethodAbilityTest",
"cpp_test:InputMethodControllerTest",
"cpp_test:InputMethodDfxTest",
"cpp_test:InputMethodPanelTest",
"cpp_test:InputMethodPrivateMemberTest",
"cpp_test:InputMethodServiceTest",
"cpp_test:InputMethodSwitchTest",

View File

@ -38,6 +38,7 @@ ohos_unittest("InputMethodControllerTest") {
external_deps = [
"ability_base:want",
"ability_runtime:ability_context_native",
"ability_runtime:ability_manager",
"access_token:libaccesstoken_sdk",
"access_token:libnativetoken",
@ -63,7 +64,13 @@ ohos_unittest("InputMethodAbilityTest") {
configs = [ ":module_private_config" ]
include_dirs = [
"${windowmanager_path}/interfaces/innerkits/dm",
"${windowmanager_path}/interfaces/innerkits/wm",
]
deps = [
"${graphic_path}/render_service_client:librender_service_client",
"${inputmethod_path}/frameworks/native/inputmethod_ability:inputmethod_ability",
"${inputmethod_path}/interfaces/inner_api/inputmethod_controller:inputmethod_client_static",
"${inputmethod_path}/services:inputmethod_service",
@ -72,6 +79,7 @@ ohos_unittest("InputMethodAbilityTest") {
external_deps = [
"ability_base:want",
"ability_runtime:ability_context_native",
"access_token:libaccesstoken_sdk",
"access_token:libnativetoken",
"access_token:libtoken_setproc",
@ -82,6 +90,8 @@ ohos_unittest("InputMethodAbilityTest") {
"napi:ace_napi",
"safwk:system_ability_fwk",
"samgr:samgr_proxy",
"window_manager:libdm",
"window_manager:libwm",
]
}
@ -95,6 +105,11 @@ ohos_unittest("InputMethodServiceTest") {
configs = [ ":module_private_config" ]
include_dirs = [
"${windowmanager_path}/interfaces/innerkits/dm",
"${windowmanager_path}/interfaces/innerkits/wm",
]
deps = [
"${inputmethod_path}/frameworks/native/inputmethod_ability:inputmethod_ability",
"${inputmethod_path}/interfaces/inner_api/inputmethod_controller:inputmethod_client_static",
@ -104,6 +119,7 @@ ohos_unittest("InputMethodServiceTest") {
external_deps = [
"ability_base:want",
"ability_runtime:ability_context_native",
"access_token:libaccesstoken_sdk",
"access_token:libnativetoken",
"c_utils:utils",
@ -113,6 +129,8 @@ ohos_unittest("InputMethodServiceTest") {
"napi:ace_napi",
"safwk:system_ability_fwk",
"samgr:samgr_proxy",
"window_manager:libdm",
"window_manager:libwm",
]
}
@ -132,6 +150,35 @@ ohos_unittest("InputMethodDfxTest") {
]
}
ohos_unittest("InputMethodPanelTest") {
module_out_path = module_output_path
sources = [ "src/input_method_panel_test.cpp" ]
configs = [ ":module_private_config" ]
include_dirs = [
"${windowmanager_path}/interfaces/innerkits/dm",
"${windowmanager_path}/interfaces/innerkits/wm",
]
deps = [
"${graphic_path}/render_service_client:librender_service_client",
"${inputmethod_path}/frameworks/native/inputmethod_ability:inputmethod_ability",
"${inputmethod_path}/interfaces/inner_api/inputmethod_controller:inputmethod_client_static",
"${inputmethod_path}/services:inputmethod_service",
"//third_party/googletest:gtest_main",
]
external_deps = [
"ability_runtime:ability_context_native",
"c_utils:utils",
"hiviewdfx_hilog_native:libhilog",
"window_manager:libdm",
"window_manager:libwm",
]
}
ohos_unittest("InputMethodUtilsTest") {
module_out_path = module_output_path

View File

@ -36,6 +36,7 @@
#include "input_method_controller.h"
#include "input_method_core_proxy.h"
#include "input_method_core_stub.h"
#include "input_method_panel.h"
#include "message_handler.h"
#include "nativetoken_kit.h"
#include "token_setproc.h"
@ -718,5 +719,124 @@ HWTEST_F(InputMethodAbilityTest, testGetTextIndexAtCursor_002, TestSize.Level0)
EXPECT_EQ(ret, ErrorCode::NO_ERROR);
EXPECT_EQ(index, end);
}
/**
* @tc.name: testCreatePanel001
* @tc.desc: It's allowed to create one SOFT_KEYBOARD panel, but two is denied.
* @tc.type: FUNC
* @tc.require:
*/
HWTEST_F(InputMethodAbilityTest, testCreatePanel001, TestSize.Level0)
{
IMSA_HILOGI("InputMethodAbilityTest testCreatePanel001 START. You can not create two SOFT_KEYBOARD panel.");
std::shared_ptr<InputMethodPanel> softKeyboardPanel1 = nullptr;
PanelInfo panelInfo = { .panelType = SOFT_KEYBOARD, .panelFlag = FLG_FIXED };
auto ret = inputMethodAbility_->CreatePanel(nullptr, panelInfo, softKeyboardPanel1);
EXPECT_TRUE(softKeyboardPanel1 != nullptr);
EXPECT_EQ(ret, ErrorCode::NO_ERROR);
std::shared_ptr<InputMethodPanel> softKeyboardPanel2 = nullptr;
ret = inputMethodAbility_->CreatePanel(nullptr, panelInfo, softKeyboardPanel2);
EXPECT_TRUE(softKeyboardPanel2 == nullptr);
EXPECT_EQ(ret, ErrorCode::ERROR_OPERATE_PANEL);
ret = inputMethodAbility_->DestroyPanel(softKeyboardPanel1);
EXPECT_EQ(ret, ErrorCode::NO_ERROR);
ret = inputMethodAbility_->DestroyPanel(softKeyboardPanel2);
EXPECT_EQ(ret, ErrorCode::ERROR_BAD_PARAMETERS);
}
/**
* @tc.name: testCreatePanel002
* @tc.desc: It's allowed to create one STATUS_BAR panel, but two is denied.
* @tc.type: FUNC
* @tc.require:
*/
HWTEST_F(InputMethodAbilityTest, testCreatePanel002, TestSize.Level0)
{
IMSA_HILOGI("InputMethodAbilityTest testCreatePanel002 START. You can not create two STATUS_BAR panel.");
std::shared_ptr<InputMethodPanel> statusBar1 = nullptr;
PanelInfo panelInfo = { .panelType = STATUS_BAR };
auto ret = inputMethodAbility_->CreatePanel(nullptr, panelInfo, statusBar1);
EXPECT_TRUE(statusBar1 != nullptr);
EXPECT_EQ(ret, ErrorCode::NO_ERROR);
std::shared_ptr<InputMethodPanel> statusBar2 = nullptr;
ret = inputMethodAbility_->CreatePanel(nullptr, panelInfo, statusBar2);
EXPECT_TRUE(statusBar2 == nullptr);
EXPECT_EQ(ret, ErrorCode::ERROR_OPERATE_PANEL);
ret = inputMethodAbility_->DestroyPanel(statusBar1);
EXPECT_EQ(ret, ErrorCode::NO_ERROR);
ret = inputMethodAbility_->DestroyPanel(statusBar2);
EXPECT_EQ(ret, ErrorCode::ERROR_BAD_PARAMETERS);
}
/**
* @tc.name: testCreatePanel003
* @tc.desc: It's allowed to create one STATUS_BAR panel and one SOFT_KEYBOARD panel.
* @tc.type: FUNC
* @tc.require:
*/
HWTEST_F(InputMethodAbilityTest, testCreatePanel003, TestSize.Level0)
{
IMSA_HILOGI("InputMethodAbilityTest testCreatePanel006 START. Allowed to create one SOFT_KEYBOARD panel and "
"one STATUS_BAR panel.");
std::shared_ptr<InputMethodPanel> softKeyboardPanel = nullptr;
PanelInfo panelInfo1 = { .panelType = SOFT_KEYBOARD, .panelFlag = FLG_FIXED };
auto ret = inputMethodAbility_->CreatePanel(nullptr, panelInfo1, softKeyboardPanel);
EXPECT_TRUE(softKeyboardPanel != nullptr);
EXPECT_EQ(ret, ErrorCode::NO_ERROR);
PanelInfo panelInfo2 = { .panelType = STATUS_BAR };
std::shared_ptr<InputMethodPanel> statusBar = nullptr;
ret = inputMethodAbility_->CreatePanel(nullptr, panelInfo2, statusBar);
EXPECT_TRUE(statusBar != nullptr);
EXPECT_EQ(ret, ErrorCode::NO_ERROR);
ret = inputMethodAbility_->DestroyPanel(softKeyboardPanel);
EXPECT_EQ(ret, ErrorCode::NO_ERROR);
ret = inputMethodAbility_->DestroyPanel(statusBar);
EXPECT_EQ(ret, ErrorCode::NO_ERROR);
}
/**
* @tc.name: testCreatePanel004
* @tc.desc: It's allowed to create one STATUS_BAR panel and one SOFT_KEYBOARD panel.
* @tc.type: FUNC
* @tc.require:
*/
HWTEST_F(InputMethodAbilityTest, testCreatePanel004, TestSize.Level0)
{
IMSA_HILOGI("InputMethodAbilityTest testCreatePanel006 START. Allowed to create one SOFT_KEYBOARD panel and "
"one STATUS_BAR panel.");
std::shared_ptr<InputMethodPanel> inputMethodPanel = nullptr;
PanelInfo panelInfo1 = { .panelType = SOFT_KEYBOARD, .panelFlag = FLG_FIXED };
auto ret = inputMethodAbility_->CreatePanel(nullptr, panelInfo1, inputMethodPanel);
EXPECT_TRUE(inputMethodPanel != nullptr);
EXPECT_EQ(ret, ErrorCode::NO_ERROR);
ret = inputMethodAbility_->DestroyPanel(inputMethodPanel);
EXPECT_EQ(ret, ErrorCode::NO_ERROR);
PanelInfo panelInfo2 = { .panelType = STATUS_BAR };
ret = inputMethodAbility_->CreatePanel(nullptr, panelInfo2, inputMethodPanel);
EXPECT_TRUE(inputMethodPanel != nullptr);
EXPECT_EQ(ret, ErrorCode::NO_ERROR);
ret = inputMethodAbility_->DestroyPanel(inputMethodPanel);
EXPECT_EQ(ret, ErrorCode::NO_ERROR);
panelInfo1.panelFlag = FLG_FLOATING;
ret = inputMethodAbility_->CreatePanel(nullptr, panelInfo1, inputMethodPanel);
EXPECT_TRUE(inputMethodPanel != nullptr);
EXPECT_EQ(ret, ErrorCode::NO_ERROR);
ret = inputMethodAbility_->DestroyPanel(inputMethodPanel);
EXPECT_EQ(ret, ErrorCode::NO_ERROR);
}
} // namespace MiscServices
} // namespace OHOS

View File

@ -0,0 +1,321 @@
/*
* Copyright (c) 2021 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_panel.h"
#include <condition_variable>
#include <cstdint>
#include <gtest/gtest.h>
#include <string>
#include <sys/time.h>
#include <unistd.h>
#include "display_manager.h"
#include "global.h"
#include "panel_status_listener.h"
using namespace testing::ext;
namespace OHOS {
namespace MiscServices {
class InputMethodPanelTest : public testing::Test {
public:
static void SetUpTestCase(void);
static void TearDownTestCase(void);
void SetUp();
void TearDown();
class PanelStatusListenerImpl : public PanelStatusListener {
public:
~PanelStatusListenerImpl() = default;
void OnPanelStatus(uint32_t windowId, bool isShow)
{
showPanel_ = isShow;
hidePanel_ = !isShow;
InputMethodPanelTest::panelListenerCv_.notify_one();
IMSA_HILOGI("PanelStatusListenerImpl OnPanelStatus in, isShow is %{public}s", isShow ? "true" : "false");
}
};
static bool showPanel_;
static bool hidePanel_;
static std::condition_variable panelListenerCv_;
static std::mutex panelListenerLock_;
static constexpr uint32_t DEALY_TIME = 1;
};
bool InputMethodPanelTest::showPanel_ = false;
bool InputMethodPanelTest::hidePanel_ = false;
std::condition_variable InputMethodPanelTest::panelListenerCv_;
std::mutex InputMethodPanelTest::panelListenerLock_;
void InputMethodPanelTest::SetUpTestCase(void)
{
IMSA_HILOGI("InputMethodPanelTest::SetUpTestCase");
}
void InputMethodPanelTest::TearDownTestCase(void)
{
IMSA_HILOGI("InputMethodPanelTest::TearDownTestCase");
}
void InputMethodPanelTest::SetUp(void)
{
IMSA_HILOGI("InputMethodPanelTest::SetUp");
}
void InputMethodPanelTest::TearDown(void)
{
IMSA_HILOGI("InputMethodPanelTest::TearDown");
}
/**
* @tc.name: testSetUiContent
* @tc.desc: Test SetUiContent.
* @tc.type: FUNC
*/
HWTEST_F(InputMethodPanelTest, testCreatePanel, TestSize.Level0)
{
IMSA_HILOGI("InputMethodPanelTest::testCreatePanel start.");
auto inputMethodPanel = std::make_shared<InputMethodPanel>();
PanelInfo panelInfo = { .panelType = SOFT_KEYBOARD, .panelFlag = FLG_FLOATING };
auto ret = inputMethodPanel->CreatePanel(nullptr, panelInfo);
EXPECT_EQ(ret, ErrorCode::NO_ERROR);
ret = inputMethodPanel->DestroyPanel();
EXPECT_EQ(ret, ErrorCode::NO_ERROR);
}
/**
* @tc.name: testResizePanel
* @tc.desc: Test Resize panel. All panels can be resized.
* @tc.type: FUNC
*/
HWTEST_F(InputMethodPanelTest, testResizePanel, TestSize.Level0)
{
IMSA_HILOGI("InputMethodPanelTest::testResizePanel start.");
auto inputMethodPanel = std::make_shared<InputMethodPanel>();
PanelInfo panelInfo = { .panelType = SOFT_KEYBOARD, .panelFlag = FLG_FLOATING };
auto ret = inputMethodPanel->CreatePanel(nullptr, panelInfo);
EXPECT_EQ(ret, ErrorCode::NO_ERROR);
auto defaultDisplay = Rosen::DisplayManager::GetInstance().GetDefaultDisplay();
EXPECT_TRUE(defaultDisplay != nullptr);
int32_t width = defaultDisplay->GetWidth();
int32_t height = defaultDisplay->GetHeight();
ret = inputMethodPanel->Resize(width - 1, height / 2 - 1);
EXPECT_EQ(ret, ErrorCode::NO_ERROR);
ret = inputMethodPanel->Resize(width, height / 2);
EXPECT_EQ(ret, ErrorCode::NO_ERROR);
ret = inputMethodPanel->Resize(width + 1, height / 2);
EXPECT_EQ(ret, ErrorCode::ERROR_BAD_PARAMETERS);
ret = inputMethodPanel->Resize(width, height / 2 + 1);
EXPECT_EQ(ret, ErrorCode::ERROR_BAD_PARAMETERS);
ret = inputMethodPanel->DestroyPanel();
EXPECT_EQ(ret, ErrorCode::NO_ERROR);
}
/**
* @tc.name: testMovePanel
* @tc.desc: Test Move panel. SOFT_KEYBOARD panel with FLG_FIXED can not be moved.
* @tc.type: FUNC
*/
HWTEST_F(InputMethodPanelTest, testMovePanel, TestSize.Level0)
{
IMSA_HILOGI("InputMethodPanelTest::testMovePanel start.");
auto inputMethodPanel = std::make_shared<InputMethodPanel>();
PanelInfo panelInfo = { .panelType = SOFT_KEYBOARD, .panelFlag = FLG_FIXED };
auto ret = inputMethodPanel->CreatePanel(nullptr, panelInfo);
EXPECT_EQ(ret, ErrorCode::NO_ERROR);
ret = inputMethodPanel->MoveTo(10, 100);
EXPECT_EQ(ret, ErrorCode::NO_ERROR);
ret = inputMethodPanel->ChangePanelFlag(PanelFlag::FLG_FLOATING);
EXPECT_EQ(ret, ErrorCode::NO_ERROR);
ret = inputMethodPanel->MoveTo(10, 100);
EXPECT_EQ(ret, ErrorCode::NO_ERROR);
ret = inputMethodPanel->DestroyPanel();
EXPECT_EQ(ret, ErrorCode::NO_ERROR);
panelInfo.panelType = STATUS_BAR;
ret = inputMethodPanel->CreatePanel(nullptr, panelInfo);
EXPECT_EQ(ret, ErrorCode::NO_ERROR);
ret = inputMethodPanel->MoveTo(10, 100);
EXPECT_EQ(ret, ErrorCode::NO_ERROR);
ret = inputMethodPanel->DestroyPanel();
EXPECT_EQ(ret, ErrorCode::NO_ERROR);
}
/**
* @tc.name: testShowPanel
* @tc.desc: Test Show panel.
* @tc.type: FUNC
*/
HWTEST_F(InputMethodPanelTest, testShowPanel, TestSize.Level0)
{
IMSA_HILOGI("InputMethodPanelTest::testShowPanel start.");
auto inputMethodPanel = std::make_shared<InputMethodPanel>();
PanelInfo panelInfo = { .panelType = SOFT_KEYBOARD, .panelFlag = FLG_FIXED };
// 0、not create panel, show panel failed.
auto ret = inputMethodPanel->ShowPanel();
EXPECT_EQ(ret, ErrorCode::ERROR_NULL_POINTER);
ret = inputMethodPanel->CreatePanel(nullptr, panelInfo);
EXPECT_EQ(ret, ErrorCode::NO_ERROR);
ret = inputMethodPanel->ShowPanel();
EXPECT_EQ(ret, ErrorCode::NO_ERROR);
auto statusListener = std::make_shared<InputMethodPanelTest::PanelStatusListenerImpl>();
EXPECT_TRUE(statusListener != nullptr);
inputMethodPanel->SetPanelStatusListener(statusListener);
ret = inputMethodPanel->ShowPanel();
EXPECT_EQ(ret, ErrorCode::NO_ERROR);
// 2、show floating type panel.
ret = inputMethodPanel->ChangePanelFlag(PanelFlag::FLG_FLOATING);
EXPECT_EQ(ret, ErrorCode::NO_ERROR);
ret = inputMethodPanel->ShowPanel();
EXPECT_EQ(ret, ErrorCode::NO_ERROR);
ret = inputMethodPanel->DestroyPanel();
EXPECT_EQ(ret, ErrorCode::NO_ERROR);
// 4、show status bar.
panelInfo.panelType = STATUS_BAR;
ret = inputMethodPanel->CreatePanel(nullptr, panelInfo);
EXPECT_EQ(ret, ErrorCode::NO_ERROR);
ret = inputMethodPanel->ShowPanel();
EXPECT_EQ(ret, ErrorCode::NO_ERROR);
ret = inputMethodPanel->HidePanel();
EXPECT_EQ(ret, ErrorCode::NO_ERROR);
ret = inputMethodPanel->DestroyPanel();
EXPECT_EQ(ret, ErrorCode::NO_ERROR);
}
/**
* @tc.name: testSetPanelStatusListener
* @tc.desc: Test SetPanelStatusListener.
* @tc.type: FUNC
*/
HWTEST_F(InputMethodPanelTest, testSetPanelStatusListener, TestSize.Level0)
{
IMSA_HILOGI("InputMethodPanelTest::testSetPanelStatusListener start.");
auto inputMethodPanel = std::make_shared<InputMethodPanel>();
EXPECT_TRUE(inputMethodPanel != nullptr);
auto statusListener = std::make_shared<InputMethodPanelTest::PanelStatusListenerImpl>();
EXPECT_TRUE(statusListener != nullptr);
inputMethodPanel->SetPanelStatusListener(statusListener);
PanelInfo panelInfo = { .panelType = SOFT_KEYBOARD, .panelFlag = FLG_FIXED };
auto ret = inputMethodPanel->CreatePanel(nullptr, panelInfo);
EXPECT_EQ(ret, ErrorCode::NO_ERROR);
ret = inputMethodPanel->ShowPanel();
EXPECT_EQ(ret, ErrorCode::NO_ERROR);
{
std::unique_lock<std::mutex> lock(InputMethodPanelTest::panelListenerLock_);
InputMethodPanelTest::panelListenerCv_.wait_for(lock, std::chrono::seconds(InputMethodPanelTest::DEALY_TIME),
[] { return InputMethodPanelTest::showPanel_ == true; });
}
EXPECT_TRUE(InputMethodPanelTest::showPanel_);
ret = inputMethodPanel->HidePanel();
EXPECT_EQ(ret, ErrorCode::NO_ERROR);
{
std::unique_lock<std::mutex> lock(InputMethodPanelTest::panelListenerLock_);
InputMethodPanelTest::panelListenerCv_.wait_for(lock, std::chrono::seconds(InputMethodPanelTest::DEALY_TIME),
[] { return InputMethodPanelTest::showPanel_ == false; });
}
EXPECT_TRUE(!InputMethodPanelTest::showPanel_);
ret = inputMethodPanel->DestroyPanel();
EXPECT_EQ(ret, ErrorCode::NO_ERROR);
}
/**
* @tc.name: testGetPanelType
* @tc.desc: Test GetPanelType.
* @tc.type: FUNC
*/
HWTEST_F(InputMethodPanelTest, testGetPanelType, TestSize.Level0)
{
IMSA_HILOGI("InputMethodPanelTest::testSetUiContent start.");
auto inputMethodPanel = std::make_shared<InputMethodPanel>();
PanelInfo panelInfo = { .panelType = SOFT_KEYBOARD, .panelFlag = FLG_FLOATING };
auto ret = inputMethodPanel->CreatePanel(nullptr, panelInfo);
EXPECT_EQ(ret, ErrorCode::NO_ERROR);
auto type = inputMethodPanel->GetPanelType();
EXPECT_EQ(type, panelInfo.panelType);
ret = inputMethodPanel->DestroyPanel();
EXPECT_EQ(ret, ErrorCode::NO_ERROR);
}
/**
* @tc.name: testRemovePanelListener
* @tc.desc: Test RemovePanelListener.
* @tc.type: FUNC
*/
HWTEST_F(InputMethodPanelTest, testRemovePanelListener, TestSize.Level0)
{
IMSA_HILOGI("InputMethodPanelTest::testRemovePanelListener start.");
auto inputMethodPanel = std::make_shared<InputMethodPanel>();
PanelInfo panelInfo = { .panelType = SOFT_KEYBOARD, .panelFlag = FLG_FLOATING };
auto ret = inputMethodPanel->CreatePanel(nullptr, panelInfo);
EXPECT_EQ(ret, ErrorCode::NO_ERROR);
auto type = inputMethodPanel->GetPanelType();
EXPECT_EQ(type, panelInfo.panelType);
std::string subscribeType = "show";
inputMethodPanel->RemovePanelListener(subscribeType);
ret = inputMethodPanel->ShowPanel();
EXPECT_EQ(ret, ErrorCode::NO_ERROR);
{
std::unique_lock<std::mutex> lock(InputMethodPanelTest::panelListenerLock_);
InputMethodPanelTest::panelListenerCv_.wait_for(lock, std::chrono::seconds(InputMethodPanelTest::DEALY_TIME),
[] { return InputMethodPanelTest::showPanel_ == false; });
}
EXPECT_EQ(InputMethodPanelTest::showPanel_, false);
ret = inputMethodPanel->HidePanel();
EXPECT_EQ(ret, ErrorCode::NO_ERROR);
{
std::unique_lock<std::mutex> lock(InputMethodPanelTest::panelListenerLock_);
InputMethodPanelTest::panelListenerCv_.wait_for(lock, std::chrono::seconds(InputMethodPanelTest::DEALY_TIME),
[] { return InputMethodPanelTest::hidePanel_ == true; });
}
EXPECT_EQ(InputMethodPanelTest::hidePanel_, true);
InputMethodPanelTest::hidePanel_ = false;
subscribeType = "hide";
inputMethodPanel->RemovePanelListener(subscribeType);
ret = inputMethodPanel->ShowPanel();
EXPECT_EQ(ret, ErrorCode::NO_ERROR);
{
std::unique_lock<std::mutex> lock(InputMethodPanelTest::panelListenerLock_);
InputMethodPanelTest::panelListenerCv_.wait_for(lock, std::chrono::seconds(InputMethodPanelTest::DEALY_TIME),
[] { return InputMethodPanelTest::showPanel_ == false; });
}
EXPECT_EQ(InputMethodPanelTest::showPanel_, false);
ret = inputMethodPanel->HidePanel();
EXPECT_EQ(ret, ErrorCode::NO_ERROR);
{
std::unique_lock<std::mutex> lock(InputMethodPanelTest::panelListenerLock_);
InputMethodPanelTest::panelListenerCv_.wait_for(lock, std::chrono::seconds(InputMethodPanelTest::DEALY_TIME),
[] { return InputMethodPanelTest::hidePanel_ == false; });
}
EXPECT_EQ(InputMethodPanelTest::hidePanel_, false);
ret = inputMethodPanel->DestroyPanel();
EXPECT_EQ(ret, ErrorCode::NO_ERROR);
}
} // namespace MiscServices
} // namespace OHOS