• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "js_get_input_method_setting.h"
17 
18 #include "event_checker.h"
19 #include "input_client_info.h"
20 #include "input_method_controller.h"
21 #include "input_method_status.h"
22 #include "js_callback_handler.h"
23 #include "js_input_method.h"
24 #include "js_util.h"
25 #include "js_utils.h"
26 #include "napi/native_api.h"
27 #include "napi/native_node_api.h"
28 #include "string_ex.h"
29 
30 namespace OHOS {
31 namespace MiscServices {
32 int32_t MAX_TYPE_NUM = 128;
33 constexpr size_t ARGC_ZERO = 0;
34 constexpr size_t ARGC_ONE = 1;
35 constexpr size_t ARGC_TWO = 2;
36 thread_local napi_ref JsGetInputMethodSetting::IMSRef_ = nullptr;
37 const std::string JsGetInputMethodSetting::IMS_CLASS_NAME = "InputMethodSetting";
38 const std::map<InputWindowStatus, std::string> PANEL_STATUS{ { InputWindowStatus::SHOW, "imeShow" },
39     { InputWindowStatus::HIDE, "imeHide" } };
40 std::mutex JsGetInputMethodSetting::msMutex_;
41 std::shared_ptr<JsGetInputMethodSetting> JsGetInputMethodSetting::inputMethod_{ nullptr };
Init(napi_env env,napi_value exports)42 napi_value JsGetInputMethodSetting::Init(napi_env env, napi_value exports)
43 {
44     napi_value maxTypeNumber = nullptr;
45     napi_create_int32(env, MAX_TYPE_NUM, &maxTypeNumber);
46 
47     napi_property_descriptor descriptor[] = {
48         DECLARE_NAPI_FUNCTION("getInputMethodSetting", GetInputMethodSetting),
49         DECLARE_NAPI_FUNCTION("getSetting", GetSetting),
50         DECLARE_NAPI_PROPERTY("MAX_TYPE_NUM", maxTypeNumber),
51     };
52     NAPI_CALL(
53         env, napi_define_properties(env, exports, sizeof(descriptor) / sizeof(napi_property_descriptor), descriptor));
54 
55     napi_property_descriptor properties[] = {
56         DECLARE_NAPI_FUNCTION("listInputMethod", ListInputMethod),
57         DECLARE_NAPI_FUNCTION("listInputMethodSubtype", ListInputMethodSubtype),
58         DECLARE_NAPI_FUNCTION("listCurrentInputMethodSubtype", ListCurrentInputMethodSubtype),
59         DECLARE_NAPI_FUNCTION("getInputMethods", GetInputMethods),
60         DECLARE_NAPI_FUNCTION("displayOptionalInputMethod", DisplayOptionalInputMethod),
61         DECLARE_NAPI_FUNCTION("showOptionalInputMethods", ShowOptionalInputMethods),
62         DECLARE_NAPI_FUNCTION("on", Subscribe),
63         DECLARE_NAPI_FUNCTION("off", UnSubscribe),
64     };
65     napi_value cons = nullptr;
66     NAPI_CALL(env, napi_define_class(env, IMS_CLASS_NAME.c_str(), IMS_CLASS_NAME.size(), JsConstructor, nullptr,
67                        sizeof(properties) / sizeof(napi_property_descriptor), properties, &cons));
68     NAPI_CALL(env, napi_create_reference(env, cons, 1, &IMSRef_));
69     NAPI_CALL(env, napi_set_named_property(env, exports, IMS_CLASS_NAME.c_str(), cons));
70     return exports;
71 }
72 
JsConstructor(napi_env env,napi_callback_info cbinfo)73 napi_value JsGetInputMethodSetting::JsConstructor(napi_env env, napi_callback_info cbinfo)
74 {
75     IMSA_HILOGI("run in JsConstructor");
76     napi_value thisVar = nullptr;
77     NAPI_CALL(env, napi_get_cb_info(env, cbinfo, nullptr, nullptr, &thisVar, nullptr));
78 
79     auto delegate = GetInputMethodSettingInstance();
80     if (delegate == nullptr) {
81         IMSA_HILOGE("settingObject is nullptr");
82         napi_value result = nullptr;
83         napi_get_null(env, &result);
84         return result;
85     }
86     napi_status status = napi_wrap(
87         env, thisVar, delegate.get(), [](napi_env env, void *data, void *hint) {}, nullptr, nullptr);
88     if (status != napi_ok) {
89         IMSA_HILOGE("JsGetInputMethodSetting napi_wrap failed: %{public}d", status);
90         return nullptr;
91     }
92     if (delegate->loop_ == nullptr) {
93         napi_get_uv_event_loop(env, &delegate->loop_);
94     }
95     return thisVar;
96 }
97 
GetJsConstProperty(napi_env env,uint32_t num)98 napi_value JsGetInputMethodSetting::GetJsConstProperty(napi_env env, uint32_t num)
99 {
100     napi_value jsNumber = nullptr;
101     napi_create_int32(env, num, &jsNumber);
102     return jsNumber;
103 }
104 
GetInputMethodSettingInstance()105 std::shared_ptr<JsGetInputMethodSetting> JsGetInputMethodSetting::GetInputMethodSettingInstance()
106 {
107     if (inputMethod_ == nullptr) {
108         std::lock_guard<std::mutex> lock(msMutex_);
109         if (inputMethod_ == nullptr) {
110             auto engine = std::make_shared<JsGetInputMethodSetting>();
111             if (engine == nullptr) {
112                 IMSA_HILOGE("input method nullptr");
113                 return nullptr;
114             }
115             inputMethod_ = engine;
116         }
117     }
118     return inputMethod_;
119 }
120 
GetSetting(napi_env env,napi_callback_info info)121 napi_value JsGetInputMethodSetting::GetSetting(napi_env env, napi_callback_info info)
122 {
123     return GetIMSetting(env, info, true);
124 }
125 
GetInputMethodSetting(napi_env env,napi_callback_info info)126 napi_value JsGetInputMethodSetting::GetInputMethodSetting(napi_env env, napi_callback_info info)
127 {
128     return GetIMSetting(env, info, false);
129 }
130 
GetIMSetting(napi_env env,napi_callback_info info,bool needThrowException)131 napi_value JsGetInputMethodSetting::GetIMSetting(napi_env env, napi_callback_info info, bool needThrowException)
132 {
133     napi_value instance = nullptr;
134     napi_value cons = nullptr;
135     if (napi_get_reference_value(env, IMSRef_, &cons) != napi_ok) {
136         IMSA_HILOGE("GetSetting::napi_get_reference_value not ok");
137         if (needThrowException) {
138             JsUtils::ThrowException(env, IMFErrorCode::EXCEPTION_SETTINGS, "", TYPE_OBJECT);
139         }
140         return nullptr;
141     }
142     if (napi_new_instance(env, cons, 0, nullptr, &instance) != napi_ok) {
143         IMSA_HILOGE("GetSetting::napi_new_instance not ok");
144         if (needThrowException) {
145             JsUtils::ThrowException(env, IMFErrorCode::EXCEPTION_SETTINGS, "", TYPE_OBJECT);
146         }
147         return nullptr;
148     }
149     return instance;
150 }
151 
GetInputMethodProperty(napi_env env,napi_value argv,std::shared_ptr<ListInputContext> ctxt)152 napi_status JsGetInputMethodSetting::GetInputMethodProperty(
153     napi_env env, napi_value argv, std::shared_ptr<ListInputContext> ctxt)
154 {
155     napi_valuetype valueType = napi_undefined;
156     napi_typeof(env, argv, &valueType);
157     PARAM_CHECK_RETURN(env, valueType == napi_object, "Parameter error.", TYPE_OBJECT, napi_invalid_arg);
158     napi_value result = nullptr;
159     napi_get_named_property(env, argv, "name", &result);
160     JsUtils::GetValue(env, result, ctxt->property.name);
161 
162     result = nullptr;
163     napi_get_named_property(env, argv, "id", &result);
164     JsUtils::GetValue(env, result, ctxt->property.id);
165 
166     if (ctxt->property.name.empty() || ctxt->property.id.empty()) {
167         result = nullptr;
168         napi_get_named_property(env, argv, "packageName", &result);
169         JsUtils::GetValue(env, result, ctxt->property.name);
170 
171         result = nullptr;
172         napi_get_named_property(env, argv, "methodId", &result);
173         JsUtils::GetValue(env, result, ctxt->property.id);
174     }
175     PARAM_CHECK_RETURN(env, (!ctxt->property.name.empty() && !ctxt->property.id.empty()), "Parameter error.",
176         TYPE_NONE, napi_invalid_arg);
177     IMSA_HILOGD("methodId:%{public}s, packageName:%{public}s", ctxt->property.id.c_str(), ctxt->property.name.c_str());
178     return napi_ok;
179 }
180 
ListInputMethod(napi_env env,napi_callback_info info)181 napi_value JsGetInputMethodSetting::ListInputMethod(napi_env env, napi_callback_info info)
182 {
183     IMSA_HILOGI("run in ListInputMethod");
184     auto ctxt = std::make_shared<ListInputContext>();
185     auto input = [ctxt](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
186         ctxt->inputMethodStatus = InputMethodStatus::ALL;
187         return napi_ok;
188     };
189     auto output = [ctxt](napi_env env, napi_value *result) -> napi_status {
190         *result = JsInputMethod::GetJSInputMethodProperties(env, ctxt->properties);
191         return napi_ok;
192     };
193     auto exec = [ctxt](AsyncCall::Context *ctx) {
194         int32_t errCode = InputMethodController::GetInstance()->ListInputMethod(ctxt->properties);
195         if (errCode == ErrorCode::NO_ERROR) {
196             IMSA_HILOGI("exec ---- ListInputMethod success");
197             ctxt->status = napi_ok;
198             ctxt->SetState(ctxt->status);
199             return;
200         }
201         ctxt->SetErrorCode(errCode);
202     };
203     ctxt->SetAction(std::move(input), std::move(output));
204     // 1 means JsAPI:listInputMethod has 1 params at most.
205     AsyncCall asyncCall(env, info, ctxt, 1);
206     return asyncCall.Call(env, exec, "listInputMethod");
207 }
208 
GetInputMethods(napi_env env,napi_callback_info info)209 napi_value JsGetInputMethodSetting::GetInputMethods(napi_env env, napi_callback_info info)
210 {
211     IMSA_HILOGI("run in GetInputMethods");
212     auto ctxt = std::make_shared<ListInputContext>();
213     auto input = [ctxt](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
214         PARAM_CHECK_RETURN(env, argc > 0, "should has one parameter.", TYPE_NONE, napi_invalid_arg);
215         bool enable = false;
216         napi_status status = JsUtils::GetValue(env, argv[ARGC_ZERO], enable);
217         PARAM_CHECK_RETURN(env, status == napi_ok, "enable.", TYPE_NUMBER, napi_invalid_arg);
218         ctxt->inputMethodStatus = enable ? InputMethodStatus::ENABLE : InputMethodStatus::DISABLE;
219         return napi_ok;
220     };
221     auto output = [ctxt](napi_env env, napi_value *result) -> napi_status {
222         *result = JsInputMethod::GetJSInputMethodProperties(env, ctxt->properties);
223         return napi_ok;
224     };
225     auto exec = [ctxt](AsyncCall::Context *ctx) {
226         int32_t errCode =
227             InputMethodController::GetInstance()->ListInputMethod(ctxt->inputMethodStatus == ENABLE, ctxt->properties);
228         if (errCode == ErrorCode::NO_ERROR) {
229             IMSA_HILOGI("exec ---- GetInputMethods success");
230             ctxt->status = napi_ok;
231             ctxt->SetState(ctxt->status);
232             return;
233         }
234         ctxt->SetErrorCode(errCode);
235     };
236     ctxt->SetAction(std::move(input), std::move(output));
237     // 2 means JsAPI:getInputMethods has 2 params at most.
238     AsyncCall asyncCall(env, info, ctxt, 2);
239     return asyncCall.Call(env, exec, "getInputMethods");
240 }
241 
DisplayOptionalInputMethod(napi_env env,napi_callback_info info)242 napi_value JsGetInputMethodSetting::DisplayOptionalInputMethod(napi_env env, napi_callback_info info)
243 {
244     IMSA_HILOGI("JsGetInputMethodSetting run in");
245     auto ctxt = std::make_shared<DisplayOptionalInputMethodContext>();
246     auto input = [ctxt](
247                      napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status { return napi_ok; };
248     auto output = [ctxt](napi_env env, napi_value *result) -> napi_status { return napi_ok; };
249     auto exec = [ctxt](AsyncCall::Context *ctx) {
250         int32_t errCode = InputMethodController::GetInstance()->DisplayOptionalInputMethod();
251         if (errCode == ErrorCode::NO_ERROR) {
252             IMSA_HILOGI("exec ---- DisplayOptionalInputMethod success");
253             ctxt->status = napi_ok;
254             ctxt->SetState(ctxt->status);
255         }
256     };
257     ctxt->SetAction(std::move(input), std::move(output));
258     // 1 means JsAPI:displayOptionalInputMethod has 1 params at most.
259     AsyncCall asyncCall(env, info, ctxt, 1);
260     return asyncCall.Call(env, exec, "displayOptionalInputMethod");
261 }
262 
ShowOptionalInputMethods(napi_env env,napi_callback_info info)263 napi_value JsGetInputMethodSetting::ShowOptionalInputMethods(napi_env env, napi_callback_info info)
264 {
265     IMSA_HILOGI("JsGetInputMethodSetting run in");
266     auto ctxt = std::make_shared<DisplayOptionalInputMethodContext>();
267     auto input = [ctxt](
268                      napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status { return napi_ok; };
269     auto output = [ctxt](napi_env env, napi_value *result) -> napi_status {
270         napi_status status = napi_get_boolean(env, ctxt->isDisplayed, result);
271         IMSA_HILOGI("output napi_get_boolean != nullptr[%{public}d]", result != nullptr);
272         return status;
273     };
274     auto exec = [ctxt](AsyncCall::Context *ctx) {
275         int32_t errCode = InputMethodController::GetInstance()->DisplayOptionalInputMethod();
276         if (errCode == ErrorCode::NO_ERROR) {
277             IMSA_HILOGE("exec ---- DisplayOptionalInputMethod success");
278             ctxt->status = napi_ok;
279             ctxt->SetState(ctxt->status);
280             ctxt->isDisplayed = true;
281             return;
282         } else {
283             ctxt->SetErrorCode(errCode);
284         }
285     };
286     ctxt->SetAction(std::move(input), std::move(output));
287     // 1 means JsAPI:showOptionalInputMethods has 1 params at most.
288     AsyncCall asyncCall(env, info, ctxt, 1);
289     return asyncCall.Call(env, exec, "showOptionalInputMethods");
290 }
291 
ListInputMethodSubtype(napi_env env,napi_callback_info info)292 napi_value JsGetInputMethodSetting::ListInputMethodSubtype(napi_env env, napi_callback_info info)
293 {
294     IMSA_HILOGI("run in ListInputMethodSubtype");
295     auto ctxt = std::make_shared<ListInputContext>();
296     auto input = [ctxt](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
297         PARAM_CHECK_RETURN(env, argc > 0, "should has one parameter.", TYPE_NONE, napi_invalid_arg);
298         napi_valuetype valueType = napi_undefined;
299         napi_typeof(env, argv[0], &valueType);
300         PARAM_CHECK_RETURN(env, valueType == napi_object, "inputMethodProperty", TYPE_OBJECT, napi_invalid_arg);
301         napi_status status = JsGetInputMethodSetting::GetInputMethodProperty(env, argv[0], ctxt);
302         return status;
303     };
304     auto output = [ctxt](napi_env env, napi_value *result) -> napi_status {
305         *result = JsInputMethod::GetJSInputMethodSubProperties(env, ctxt->subProperties);
306         return napi_ok;
307     };
308     auto exec = [ctxt](AsyncCall::Context *ctx) {
309         int32_t errCode =
310             InputMethodController::GetInstance()->ListInputMethodSubtype(ctxt->property, ctxt->subProperties);
311         if (errCode == ErrorCode::NO_ERROR) {
312             IMSA_HILOGI("exec ---- ListInputMethodSubtype success");
313             ctxt->status = napi_ok;
314             ctxt->SetState(ctxt->status);
315             return;
316         }
317         ctxt->SetErrorCode(errCode);
318     };
319     ctxt->SetAction(std::move(input), std::move(output));
320     // 2 means JsAPI:listInputMethodSubtype has 2 params at most.
321     AsyncCall asyncCall(env, info, ctxt, 2);
322     return asyncCall.Call(env, exec, "listInputMethodSubtype");
323 }
324 
ListCurrentInputMethodSubtype(napi_env env,napi_callback_info info)325 napi_value JsGetInputMethodSetting::ListCurrentInputMethodSubtype(napi_env env, napi_callback_info info)
326 {
327     IMSA_HILOGI("run in ListCurrentInputMethodSubtype");
328     auto ctxt = std::make_shared<ListInputContext>();
329     auto input = [ctxt](
330                      napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status { return napi_ok; };
331     auto output = [ctxt](napi_env env, napi_value *result) -> napi_status {
332         *result = JsInputMethod::GetJSInputMethodSubProperties(env, ctxt->subProperties);
333         return napi_ok;
334     };
335     auto exec = [ctxt](AsyncCall::Context *ctx) {
336         int32_t errCode = InputMethodController::GetInstance()->ListCurrentInputMethodSubtype(ctxt->subProperties);
337         if (errCode == ErrorCode::NO_ERROR) {
338             IMSA_HILOGI("exec ---- ListCurrentInputMethodSubtype success");
339             ctxt->status = napi_ok;
340             ctxt->SetState(ctxt->status);
341             return;
342         }
343         ctxt->SetErrorCode(errCode);
344     };
345     ctxt->SetAction(std::move(input), std::move(output));
346     // 1 means JsAPI:listCurrentInputMethodSubtype has 1 params at most.
347     AsyncCall asyncCall(env, info, ctxt, 1);
348     return asyncCall.Call(env, exec, "listCurrentInputMethodSubtype");
349 }
350 
RegisterListener(napi_value callback,std::string type,std::shared_ptr<JSCallbackObject> callbackObj)351 int32_t JsGetInputMethodSetting::RegisterListener(
352     napi_value callback, std::string type, std::shared_ptr<JSCallbackObject> callbackObj)
353 {
354     IMSA_HILOGD("RegisterListener %{public}s", type.c_str());
355     std::lock_guard<std::recursive_mutex> lock(mutex_);
356     if (jsCbMap_.empty()) {
357         InputMethodController::GetInstance()->SetSettingListener(inputMethod_);
358         auto ret = InputMethodController::GetInstance()->UpdateListenEventFlag(type, true);
359         if (ret != ErrorCode::NO_ERROR) {
360             IMSA_HILOGE("UpdateListenEventFlag failed, ret: %{public}d, type: %{public}s", ret, type.c_str());
361             return ret;
362         }
363     }
364     if (!jsCbMap_.empty() && jsCbMap_.find(type) == jsCbMap_.end()) {
365         IMSA_HILOGI("start type: %{public}s listening.", type.c_str());
366         auto ret = InputMethodController::GetInstance()->UpdateListenEventFlag(type, true);
367         if (ret != ErrorCode::NO_ERROR) {
368             IMSA_HILOGE("UpdateListenEventFlag failed, ret: %{public}d, type: %{public}s", ret, type.c_str());
369             return ret;
370         }
371     }
372 
373     auto callbacks = jsCbMap_[type];
374     bool ret = std::any_of(callbacks.begin(), callbacks.end(), [&callback](std::shared_ptr<JSCallbackObject> cb) {
375         return JsUtils::Equals(cb->env_, callback, cb->callback_, cb->threadId_);
376     });
377     if (ret) {
378         IMSA_HILOGE("JsGetInputMethodSetting::RegisterListener callback already registered!");
379         return ErrorCode::NO_ERROR;
380     }
381 
382     IMSA_HILOGI("Add %{public}s callbackObj into jsCbMap_", type.c_str());
383     jsCbMap_[type].push_back(std::move(callbackObj));
384     return ErrorCode::NO_ERROR;
385 }
386 
Subscribe(napi_env env,napi_callback_info info)387 napi_value JsGetInputMethodSetting::Subscribe(napi_env env, napi_callback_info info)
388 {
389     size_t argc = ARGC_TWO;
390     napi_value argv[ARGC_TWO] = { nullptr };
391     napi_value thisVar = nullptr;
392     void *data = nullptr;
393     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, &data));
394     std::string type;
395     // 2 means least param num.
396     if (argc < 2 || !JsUtil::GetValue(env, argv[0], type)
397         || !EventChecker::IsValidEventType(EventSubscribeModule::INPUT_METHOD_SETTING, type)
398         || JsUtil::GetType(env, argv[1]) != napi_function) {
399         IMSA_HILOGE("Subscribe failed, type:%{public}s", type.c_str());
400         return nullptr;
401     }
402     IMSA_HILOGD("Subscribe type:%{public}s.", type.c_str());
403     auto engine = reinterpret_cast<JsGetInputMethodSetting *>(JsUtils::GetNativeSelf(env, info));
404     if (engine == nullptr) {
405         return nullptr;
406     }
407     std::shared_ptr<JSCallbackObject> callback =
408         std::make_shared<JSCallbackObject>(env, argv[ARGC_ONE], std::this_thread::get_id());
409     auto ret = engine->RegisterListener(argv[ARGC_ONE], type, callback);
410     auto errCode = JsUtils::Convert(ret);
411     if (errCode == EXCEPTION_SYSTEM_PERMISSION) {
412         JsUtils::ThrowException(env, errCode, "", TYPE_NONE);
413     }
414     napi_value result = nullptr;
415     napi_get_null(env, &result);
416     return result;
417 }
418 
UnRegisterListener(napi_value callback,std::string type)419 void JsGetInputMethodSetting::UnRegisterListener(napi_value callback, std::string type)
420 {
421     IMSA_HILOGI("UnRegisterListener %{public}s", type.c_str());
422     std::lock_guard<std::recursive_mutex> lock(mutex_);
423     if (jsCbMap_.empty() || jsCbMap_.find(type) == jsCbMap_.end()) {
424         IMSA_HILOGE("methodName: %{public}s already unRegistered!", type.c_str());
425         return;
426     }
427 
428     if (callback == nullptr) {
429         jsCbMap_.erase(type);
430         IMSA_HILOGI("stop all type: %{public}s listening.", type.c_str());
431         InputMethodController::GetInstance()->UpdateListenEventFlag(type, false);
432         return;
433     }
434 
435     for (auto item = jsCbMap_[type].begin(); item != jsCbMap_[type].end(); item++) {
436         if (JsUtils::Equals((*item)->env_, callback, (*item)->callback_, (*item)->threadId_)) {
437             jsCbMap_[type].erase(item);
438             break;
439         }
440     }
441 
442     if (jsCbMap_[type].empty()) {
443         IMSA_HILOGI("stop last type: %{public}s listening.", type.c_str());
444         jsCbMap_.erase(type);
445         InputMethodController::GetInstance()->UpdateListenEventFlag(type, false);
446     }
447 }
448 
UnSubscribe(napi_env env,napi_callback_info info)449 napi_value JsGetInputMethodSetting::UnSubscribe(napi_env env, napi_callback_info info)
450 {
451     size_t argc = ARGC_TWO;
452     napi_value argv[ARGC_TWO] = { nullptr };
453     napi_value thisVar = nullptr;
454     void *data = nullptr;
455     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, &data));
456     std::string type;
457     // 1 means least param num.
458     if (argc < 1 || !JsUtil::GetValue(env, argv[0], type)
459         || !EventChecker::IsValidEventType(EventSubscribeModule::INPUT_METHOD_SETTING, type)) {
460         IMSA_HILOGE("UnSubscribe failed, type:%{public}s", type.c_str());
461         return nullptr;
462     }
463     // If the type of optional parameter is wrong, make it nullptr
464     if (JsUtil::GetType(env, argv[1]) != napi_function) {
465         argv[1] = nullptr;
466     }
467     IMSA_HILOGD("UnSubscribe type:%{public}s.", type.c_str());
468 
469     auto engine = reinterpret_cast<JsGetInputMethodSetting *>(JsUtils::GetNativeSelf(env, info));
470     if (engine == nullptr) {
471         return nullptr;
472     }
473     engine->UnRegisterListener(argv[ARGC_ONE], type);
474     napi_value result = nullptr;
475     napi_get_null(env, &result);
476     return result;
477 }
478 
OnImeChange(const Property & property,const SubProperty & subProperty)479 void JsGetInputMethodSetting::OnImeChange(const Property &property, const SubProperty &subProperty)
480 {
481     IMSA_HILOGD("run in");
482     std::string type = "imeChange";
483     uv_work_t *work = GetUVwork(type, [&property, &subProperty](UvEntry &entry) {
484         entry.property = property;
485         entry.subProperty = subProperty;
486     });
487     if (work == nullptr) {
488         IMSA_HILOGD("failed to get uv entry");
489         return;
490     }
491     uv_queue_work_with_qos(
492         loop_, work, [](uv_work_t *work) {},
493         [](uv_work_t *work, int status) {
494             std::shared_ptr<UvEntry> entry(static_cast<UvEntry *>(work->data), [work](UvEntry *data) {
495                 delete data;
496                 delete work;
497             });
498             if (entry == nullptr) {
499                 IMSA_HILOGE("OnInputStart:: entryptr is null");
500                 return;
501             }
502             auto getImeChangeProperty = [entry](napi_env env, napi_value *args, uint8_t argc) -> bool {
503                 if (argc < 2) {
504                     return false;
505                 }
506                 napi_value subProperty = JsInputMethod::GetJsInputMethodSubProperty(env, entry->subProperty);
507                 napi_value property = JsInputMethod::GetJsInputMethodProperty(env, entry->property);
508                 if (subProperty == nullptr || property == nullptr) {
509                     IMSA_HILOGE("get KBCins or TICins failed:");
510                     return false;
511                 }
512                 // 0 means the first param of callback.
513                 args[0] = property;
514                 // 1 means the second param of callback.
515                 args[1] = subProperty;
516                 return true;
517             };
518             // 2 means callback has two params.
519             JsCallbackHandler::Traverse(entry->vecCopy, { 2, getImeChangeProperty });
520         },
521         uv_qos_user_initiated);
522 }
523 
OnPanelStatusChange(const InputWindowStatus & status,const std::vector<InputWindowInfo> & windowInfo)524 void JsGetInputMethodSetting::OnPanelStatusChange(
525     const InputWindowStatus &status, const std::vector<InputWindowInfo> &windowInfo)
526 {
527     IMSA_HILOGI("status: %{public}u", static_cast<uint32_t>(status));
528     auto it = PANEL_STATUS.find(status);
529     if (it == PANEL_STATUS.end()) {
530         return;
531     }
532     auto type = it->second;
533     uv_work_t *work = GetUVwork(type, [&windowInfo](UvEntry &entry) { entry.windowInfo = windowInfo; });
534     if (work == nullptr) {
535         IMSA_HILOGD("failed to get uv entry");
536         return;
537     }
538     uv_queue_work_with_qos(
539         loop_, work, [](uv_work_t *work) {},
540         [](uv_work_t *work, int status) {
541             std::shared_ptr<UvEntry> entry(static_cast<UvEntry *>(work->data), [work](UvEntry *data) {
542                 delete data;
543                 delete work;
544             });
545             if (entry == nullptr) {
546                 IMSA_HILOGE("OnInputStart:: entry is nullptr");
547                 return;
548             }
549             auto getWindowInfo = [entry](napi_env env, napi_value *args, uint8_t argc) -> bool {
550                 if (argc < 1) {
551                     return false;
552                 }
553                 auto windowInfo = JsUtils::GetValue(env, entry->windowInfo);
554                 if (windowInfo == nullptr) {
555                     IMSA_HILOGE("converse windowInfo failed");
556                     return false;
557                 }
558                 // 0 means the first param of callback.
559                 args[0] = windowInfo;
560                 return true;
561             };
562             // 1 means callback has one param.
563             JsCallbackHandler::Traverse(entry->vecCopy, { 1, getWindowInfo });
564         },
565         uv_qos_user_initiated);
566 }
567 
GetUVwork(const std::string & type,EntrySetter entrySetter)568 uv_work_t *JsGetInputMethodSetting::GetUVwork(const std::string &type, EntrySetter entrySetter)
569 {
570     IMSA_HILOGD("run in, type: %{public}s", type.c_str());
571     UvEntry *entry = nullptr;
572     {
573         std::lock_guard<std::recursive_mutex> lock(mutex_);
574 
575         if (jsCbMap_[type].empty()) {
576             IMSA_HILOGE("%{public}s cb-vector is empty", type.c_str());
577             return nullptr;
578         }
579         entry = new (std::nothrow) UvEntry(jsCbMap_[type], type);
580         if (entry == nullptr) {
581             IMSA_HILOGE("entry ptr is nullptr!");
582             return nullptr;
583         }
584         if (entrySetter != nullptr) {
585             entrySetter(*entry);
586         }
587     }
588     uv_work_t *work = new (std::nothrow) uv_work_t;
589     if (work == nullptr) {
590         IMSA_HILOGE("entry ptr is nullptr!");
591         return nullptr;
592     }
593     work->data = entry;
594     return work;
595 }
596 } // namespace MiscServices
597 } // namespace OHOS