• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 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_input_method_engine_setting.h"
17 
18 #include <thread>
19 
20 #include "input_method_ability.h"
21 #include "input_method_property.h"
22 #include "input_method_utils.h"
23 #include "js_keyboard_controller_engine.h"
24 #include "js_text_input_client_engine.h"
25 #include "js_utils.h"
26 #include "napi/native_api.h"
27 #include "napi/native_node_api.h"
28 
29 namespace OHOS {
30 namespace MiscServices {
31 constexpr size_t ARGC_ZERO = 0;
32 constexpr size_t ARGC_ONE = 1;
33 constexpr size_t ARGC_TWO = 2;
34 constexpr size_t ARGC_MAX = 6;
35 const std::string JsInputMethodEngineSetting::IMES_CLASS_NAME = "InputMethodEngine";
36 thread_local napi_ref JsInputMethodEngineSetting::IMESRef_ = nullptr;
37 
38 std::mutex JsInputMethodEngineSetting::engineMutex_;
39 std::shared_ptr<JsInputMethodEngineSetting> JsInputMethodEngineSetting::inputMethodEngine_ { nullptr };
40 
Init(napi_env env,napi_value exports)41 napi_value JsInputMethodEngineSetting::Init(napi_env env, napi_value exports)
42 {
43     napi_property_descriptor descriptor[] = {
44         DECLARE_NAPI_PROPERTY("ENTER_KEY_TYPE_UNSPECIFIED",
45             GetJsConstProperty(env, static_cast<uint32_t>(EnterKeyType::UNSPECIFIED))),
46         DECLARE_NAPI_PROPERTY("ENTER_KEY_TYPE_GO",
47             GetJsConstProperty(env, static_cast<uint32_t>(EnterKeyType::GO))),
48         DECLARE_NAPI_PROPERTY("ENTER_KEY_TYPE_SEARCH",
49             GetJsConstProperty(env, static_cast<uint32_t>(EnterKeyType::SEARCH))),
50         DECLARE_NAPI_PROPERTY("ENTER_KEY_TYPE_SEND",
51             GetJsConstProperty(env, static_cast<uint32_t>(EnterKeyType::SEND))),
52         DECLARE_NAPI_PROPERTY("ENTER_KEY_TYPE_NEXT",
53             GetJsConstProperty(env, static_cast<uint32_t>(EnterKeyType::NEXT))),
54         DECLARE_NAPI_PROPERTY("ENTER_KEY_TYPE_DONE",
55             GetJsConstProperty(env, static_cast<uint32_t>(EnterKeyType::DONE))),
56         DECLARE_NAPI_PROPERTY("ENTER_KEY_TYPE_PREVIOUS",
57             GetJsConstProperty(env, static_cast<uint32_t>(EnterKeyType::PREVIOUS))),
58 
59         DECLARE_NAPI_PROPERTY("PATTERN_NULL",
60             GetIntJsConstProperty(env, static_cast<int32_t>(TextInputType::NONE))),
61         DECLARE_NAPI_PROPERTY("PATTERN_TEXT",
62             GetJsConstProperty(env, static_cast<uint32_t>(TextInputType::TEXT))),
63         DECLARE_NAPI_PROPERTY("PATTERN_NUMBER",
64             GetJsConstProperty(env, static_cast<uint32_t>(TextInputType::NUMBER))),
65         DECLARE_NAPI_PROPERTY("PATTERN_PHONE",
66             GetJsConstProperty(env, static_cast<uint32_t>(TextInputType::PHONE))),
67         DECLARE_NAPI_PROPERTY("PATTERN_DATETIME",
68             GetJsConstProperty(env, static_cast<uint32_t>(TextInputType::DATETIME))),
69         DECLARE_NAPI_PROPERTY("PATTERN_EMAIL",
70             GetJsConstProperty(env, static_cast<uint32_t>(TextInputType::EMAIL_ADDRESS))),
71         DECLARE_NAPI_PROPERTY("PATTERN_URI",
72             GetJsConstProperty(env, static_cast<uint32_t>(TextInputType::URL))),
73         DECLARE_NAPI_PROPERTY("PATTERN_PASSWORD",
74             GetJsConstProperty(env, static_cast<uint32_t>(TextInputType::VISIBLE_PASSWORD))),
75 
76         DECLARE_NAPI_FUNCTION("MoveCursor", MoveCursor),
77         DECLARE_NAPI_FUNCTION("getInputMethodEngine", GetInputMethodEngine),
78         DECLARE_NAPI_FUNCTION("getInputMethodAbility", GetInputMethodAbility),
79     };
80     NAPI_CALL(
81         env, napi_define_properties(env, exports, sizeof(descriptor) / sizeof(napi_property_descriptor), descriptor));
82 
83     napi_property_descriptor properties[] = {
84         DECLARE_NAPI_FUNCTION("on", Subscribe),
85         DECLARE_NAPI_FUNCTION("off", UnSubscribe),
86     };
87     napi_value cons = nullptr;
88     NAPI_CALL(env, napi_define_class(env, IMES_CLASS_NAME.c_str(), IMES_CLASS_NAME.size(),
89         JsConstructor, nullptr, sizeof(properties) / sizeof(napi_property_descriptor), properties, &cons));
90     NAPI_CALL(env, napi_create_reference(env, cons, 1, &IMESRef_));
91     NAPI_CALL(env, napi_set_named_property(env, exports, IMES_CLASS_NAME.c_str(), cons));
92     return exports;
93 };
94 
GetJsConstProperty(napi_env env,uint32_t num)95 napi_value JsInputMethodEngineSetting::GetJsConstProperty(napi_env env, uint32_t num)
96 {
97     napi_value jsNumber = nullptr;
98     napi_create_uint32(env, num, &jsNumber);
99     return jsNumber;
100 }
101 
GetIntJsConstProperty(napi_env env,int32_t num)102 napi_value JsInputMethodEngineSetting::GetIntJsConstProperty(napi_env env, int32_t num)
103 {
104     napi_value jsNumber = nullptr;
105     napi_create_int32(env, num, &jsNumber);
106     return jsNumber;
107 }
108 
GetInputMethodEngineSetting()109 std::shared_ptr<JsInputMethodEngineSetting> JsInputMethodEngineSetting::GetInputMethodEngineSetting()
110 {
111     if (inputMethodEngine_ == nullptr) {
112         std::lock_guard<std::mutex> lock(engineMutex_);
113         if (inputMethodEngine_ == nullptr) {
114             auto engine = std::make_shared<JsInputMethodEngineSetting>();
115             if (engine == nullptr) {
116                 IMSA_HILOGE("input method engine nullptr");
117                 return nullptr;
118             }
119             inputMethodEngine_ = engine;
120         }
121     }
122     return inputMethodEngine_;
123 }
124 
InitInputMethodSetting()125 bool JsInputMethodEngineSetting::InitInputMethodSetting()
126 {
127     if (InputMethodAbility::GetInstance()->SetCoreAndAgent() != ErrorCode::NO_ERROR) {
128         return false;
129     }
130     auto engine = GetInputMethodEngineSetting();
131     if (engine == nullptr) {
132         return false;
133     }
134     InputMethodAbility::GetInstance()->setImeListener(engine);
135     return true;
136 }
137 
JsConstructor(napi_env env,napi_callback_info info)138 napi_value JsInputMethodEngineSetting::JsConstructor(napi_env env, napi_callback_info info)
139 {
140     IMSA_HILOGI("run in JsConstructor");
141     napi_value thisVar = nullptr;
142     NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr));
143     auto setting = GetInputMethodEngineSetting();
144     if (setting == nullptr || !InitInputMethodSetting()) {
145         IMSA_HILOGE("get setting nullptr");
146         napi_value result = nullptr;
147         napi_get_null(env, &result);
148         return result;
149     }
150     napi_status status = napi_wrap(
151         env, thisVar, setting.get(), [](napi_env env, void *nativeObject, void *hint) {}, nullptr, nullptr);
152     if (status != napi_ok) {
153         IMSA_HILOGE("JsInputMethodEngineSetting napi_wrap failed: %{public}d", status);
154         return nullptr;
155     }
156     if (setting->loop_ == nullptr) {
157         napi_get_uv_event_loop(env, &setting->loop_);
158     }
159     return thisVar;
160 };
161 
GetInputMethodAbility(napi_env env,napi_callback_info info)162 napi_value JsInputMethodEngineSetting::GetInputMethodAbility(napi_env env, napi_callback_info info)
163 {
164     return GetIMEInstance(env, info);
165 }
166 
GetInputMethodEngine(napi_env env,napi_callback_info info)167 napi_value JsInputMethodEngineSetting::GetInputMethodEngine(napi_env env, napi_callback_info info)
168 {
169     return GetIMEInstance(env, info);
170 }
171 
GetIMEInstance(napi_env env,napi_callback_info info)172 napi_value JsInputMethodEngineSetting::GetIMEInstance(napi_env env, napi_callback_info info)
173 {
174     napi_value instance = nullptr;
175     napi_value cons = nullptr;
176     if (napi_get_reference_value(env, IMESRef_, &cons) != napi_ok) {
177         IMSA_HILOGE("failed to get reference value");
178         return nullptr;
179     }
180     if (napi_new_instance(env, cons, 0, nullptr, &instance) != napi_ok) {
181         IMSA_HILOGE("failed to new instance");
182         return nullptr;
183     }
184     return instance;
185 }
186 
MoveCursor(napi_env env,napi_callback_info info)187 napi_value JsInputMethodEngineSetting::MoveCursor(napi_env env, napi_callback_info info)
188 {
189     size_t argc = ARGC_MAX;
190     napi_value argv[ARGC_MAX] = { nullptr };
191     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
192     NAPI_ASSERT(env, argc == 1, "Wrong number of arguments, requires 1");
193 
194     napi_valuetype valuetype;
195     NAPI_CALL(env, napi_typeof(env, argv[ARGC_ZERO], &valuetype));
196     NAPI_ASSERT(env, valuetype == napi_number, "type is not a number");
197 
198     int32_t number;
199     if (napi_get_value_int32(env, argv[ARGC_ZERO], &number) != napi_ok) {
200         IMSA_HILOGE("GetNumberProperty error");
201     }
202 
203     InputMethodAbility::GetInstance()->MoveCursor(number);
204 
205     napi_value result = nullptr;
206     napi_get_null(env, &result);
207     return result;
208 }
209 
GetStringProperty(napi_env env,napi_value jsString)210 std::string JsInputMethodEngineSetting::GetStringProperty(napi_env env, napi_value jsString)
211 {
212     char propValue[MAX_VALUE_LEN] = {0};
213     size_t propLen;
214     if (napi_get_value_string_utf8(env, jsString, propValue, MAX_VALUE_LEN, &propLen) != napi_ok) {
215         IMSA_HILOGE("GetStringProperty error");
216         return "";
217     }
218     return std::string(propValue);
219 }
220 
RegisterListener(napi_value callback,std::string type,std::shared_ptr<JSCallbackObject> callbackObj)221 void JsInputMethodEngineSetting::RegisterListener(
222     napi_value callback, std::string type, std::shared_ptr<JSCallbackObject> callbackObj)
223 {
224     IMSA_HILOGI("RegisterListener %{public}s", type.c_str());
225     std::lock_guard<std::recursive_mutex> lock(mutex_);
226     if (jsCbMap_.empty() || jsCbMap_.find(type) == jsCbMap_.end()) {
227         IMSA_HILOGE("methodName: %{public}s not registertd!", type.c_str());
228     }
229     auto callbacks = jsCbMap_[type];
230     bool ret = std::any_of(callbacks.begin(), callbacks.end(), [&callback](std::shared_ptr<JSCallbackObject> cb) {
231         return Equals(cb->env_, callback, cb->callback_, cb->threadId_);
232     });
233     if (ret) {
234         IMSA_HILOGE("JsInputMethodEngineListener::RegisterListener callback already registered!");
235         return;
236     }
237 
238     IMSA_HILOGI("Add %{public}s callbackObj into jsCbMap_", type.c_str());
239     jsCbMap_[type].push_back(std::move(callbackObj));
240 }
241 
UnRegisterListener(napi_value callback,std::string type)242 void JsInputMethodEngineSetting::UnRegisterListener(napi_value callback, std::string type)
243 {
244     IMSA_HILOGI("UnRegisterListener %{public}s", type.c_str());
245     std::lock_guard<std::recursive_mutex> lock(mutex_);
246     if (jsCbMap_.empty() || jsCbMap_.find(type) == jsCbMap_.end()) {
247         IMSA_HILOGE("methodName: %{public}s already unRegisterted!", type.c_str());
248         return;
249     }
250 
251     if (callback == nullptr) {
252         jsCbMap_.erase(type);
253         IMSA_HILOGE("callback is nullptr");
254         return;
255     }
256 
257     for (auto item = jsCbMap_[type].begin(); item != jsCbMap_[type].end(); item++) {
258         if (Equals((*item)->env_, callback, (*item)->callback_, (*item)->threadId_)) {
259             jsCbMap_[type].erase(item);
260             break;
261         }
262     }
263 
264     if (jsCbMap_[type].empty()) {
265         jsCbMap_.erase(type);
266     }
267 }
268 
GetNative(napi_env env,napi_callback_info info)269 JsInputMethodEngineSetting *JsInputMethodEngineSetting::GetNative(napi_env env, napi_callback_info info)
270 {
271     size_t argc = ARGC_MAX;
272     void *native = nullptr;
273     napi_value self = nullptr;
274     napi_value argv[ARGC_MAX] = { nullptr };
275     napi_status status = napi_invalid_arg;
276     status = napi_get_cb_info(env, info, &argc, argv, &self, nullptr);
277     if (self == nullptr && argc >= ARGC_MAX) {
278         IMSA_HILOGE("napi_get_cb_info failed");
279         return nullptr;
280     }
281 
282     status = napi_unwrap(env, self, &native);
283     NAPI_ASSERT(env, (status == napi_ok && native != nullptr), "napi_unwrap failed!");
284     return reinterpret_cast<JsInputMethodEngineSetting*>(native);
285 }
286 
Subscribe(napi_env env,napi_callback_info info)287 napi_value JsInputMethodEngineSetting::Subscribe(napi_env env, napi_callback_info info)
288 {
289     size_t argc = ARGC_TWO;
290     napi_value argv[ARGC_TWO] = { nullptr };
291     napi_value thisVar = nullptr;
292     void *data = nullptr;
293     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, &data));
294     if (argc != ARGC_TWO) {
295         JsUtils::ThrowException(
296             env, IMFErrorCode::EXCEPTION_PARAMCHECK, "Wrong number of arguments, requires 2", TypeCode::TYPE_NONE);
297         return nullptr;
298     }
299 
300     napi_valuetype valuetype;
301     NAPI_CALL(env, napi_typeof(env, argv[ARGC_ZERO], &valuetype));
302     if (valuetype != napi_string) {
303         JsUtils::ThrowException(env, IMFErrorCode::EXCEPTION_PARAMCHECK, "'type'", TypeCode::TYPE_STRING);
304         return nullptr;
305     }
306     std::string type = GetStringProperty(env, argv[ARGC_ZERO]);
307     IMSA_HILOGE("event type is: %{public}s", type.c_str());
308 
309     valuetype = napi_undefined;
310     napi_typeof(env, argv[ARGC_ONE], &valuetype);
311     if (valuetype != napi_function) {
312         JsUtils::ThrowException(env, IMFErrorCode::EXCEPTION_PARAMCHECK, "'callback'", TypeCode::TYPE_FUNCTION);
313         return nullptr;
314     }
315 
316     auto engine = GetNative(env, info);
317     if (engine == nullptr) {
318         return nullptr;
319     }
320     std::shared_ptr<JSCallbackObject> callback =
321         std::make_shared<JSCallbackObject>(env, argv[ARGC_ONE], std::this_thread::get_id());
322     engine->RegisterListener(argv[ARGC_ONE], type, callback);
323 
324     napi_value result = nullptr;
325     napi_get_null(env, &result);
326     return result;
327 }
328 
UnSubscribe(napi_env env,napi_callback_info info)329 napi_value JsInputMethodEngineSetting::UnSubscribe(napi_env env, napi_callback_info info)
330 {
331     size_t argc = ARGC_TWO;
332     napi_value argv[ARGC_TWO] = {nullptr};
333     napi_value thisVar = nullptr;
334     void *data = nullptr;
335     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, &data));
336     if (argc != ARGC_ONE && argc != ARGC_TWO) {
337         JsUtils::ThrowException(env, IMFErrorCode::EXCEPTION_PARAMCHECK, "Wrong number of arguments, requires 1 or 2",
338             TypeCode::TYPE_NONE);
339         return nullptr;
340     }
341 
342     napi_valuetype valuetype;
343     NAPI_CALL(env, napi_typeof(env, argv[ARGC_ZERO], &valuetype));
344     if (valuetype != napi_string) {
345         JsUtils::ThrowException(env, IMFErrorCode::EXCEPTION_PARAMCHECK, "'type'", TypeCode::TYPE_STRING);
346         return nullptr;
347     }
348     std::string type = GetStringProperty(env, argv[ARGC_ZERO]);
349     IMSA_HILOGE("event type is: %{public}s", type.c_str());
350 
351     auto engine = GetNative(env, info);
352     if (engine == nullptr) {
353         return nullptr;
354     }
355 
356     if (argc == ARGC_TWO) {
357         valuetype = napi_undefined;
358         napi_typeof(env, argv[ARGC_ONE], &valuetype);
359         if (valuetype != napi_function) {
360             JsUtils::ThrowException(env, IMFErrorCode::EXCEPTION_PARAMCHECK, "'callback'", TypeCode::TYPE_FUNCTION);
361             return nullptr;
362         }
363     }
364     engine->UnRegisterListener(argv[ARGC_ONE], type);
365     napi_value result = nullptr;
366     napi_get_null(env, &result);
367     return result;
368 }
369 
Equals(napi_env env,napi_value value,napi_ref copy,std::thread::id threadId)370 bool JsInputMethodEngineSetting::Equals(napi_env env, napi_value value, napi_ref copy, std::thread::id threadId)
371 {
372     if (copy == nullptr) {
373         return (value == nullptr);
374     }
375 
376     if (threadId != std::this_thread::get_id()) {
377         IMSA_HILOGD("napi_value can not be compared");
378         return false;
379     }
380 
381     napi_value copyValue = nullptr;
382     napi_get_reference_value(env, copy, &copyValue);
383 
384     bool isEquals = false;
385     napi_strict_equals(env, value, copyValue, &isEquals);
386     IMSA_HILOGD("value compare result: %{public}d", isEquals);
387     return isEquals;
388 }
389 
GetResultOnSetSubtype(napi_env env,const SubProperty & property)390 napi_value JsInputMethodEngineSetting::GetResultOnSetSubtype(napi_env env, const SubProperty &property)
391 {
392     napi_value subType = nullptr;
393     napi_create_object(env, &subType);
394 
395     napi_value label = nullptr;
396     napi_create_string_utf8(env, property.label.c_str(), property.name.size(), &label);
397     napi_set_named_property(env, subType, "label", label);
398 
399     napi_value name = nullptr;
400     napi_create_string_utf8(env, property.name.c_str(), property.name.size(), &name);
401     napi_set_named_property(env, subType, "name", name);
402 
403     napi_value id = nullptr;
404     napi_create_string_utf8(env, property.id.c_str(), property.id.size(), &id);
405     napi_set_named_property(env, subType, "id", id);
406 
407     napi_value mode = nullptr;
408     napi_create_string_utf8(env, property.mode.c_str(), property.mode.size(), &mode);
409     napi_set_named_property(env, subType, "mode", mode);
410 
411     napi_value locale = nullptr;
412     napi_create_string_utf8(env, property.locale.c_str(), property.locale.size(), &locale);
413     napi_set_named_property(env, subType, "locale", locale);
414 
415     napi_value language = nullptr;
416     napi_create_string_utf8(env, property.language.c_str(), property.language.size(), &language);
417     napi_set_named_property(env, subType, "language", language);
418 
419     napi_value icon = nullptr;
420     napi_create_string_utf8(env, property.icon.c_str(), property.icon.size(), &icon);
421     napi_set_named_property(env, subType, "icon", icon);
422 
423     napi_value iconId = nullptr;
424     napi_create_int32(env, property.iconId, &iconId);
425     napi_set_named_property(env, subType, "iconId", iconId);
426 
427     napi_value extra = nullptr;
428     napi_create_object(env, &extra);
429     napi_set_named_property(env, subType, "extra", extra);
430 
431     return subType;
432 }
433 
OnInputStart()434 void JsInputMethodEngineSetting::OnInputStart()
435 {
436     IMSA_HILOGD("run in");
437     std::string type = "inputStart";
438     uv_work_t *work = GetUVwork(type);
439     if (work == nullptr) {
440         IMSA_HILOGD("failed to get uv entry");
441         return;
442     }
443     uv_queue_work(
444         loop_, work, [](uv_work_t *work) {},
445         [](uv_work_t *work, int status) {
446             std::shared_ptr<UvEntry> entry(static_cast<UvEntry *>(work->data), [work](UvEntry *data) {
447                 delete data;
448                 delete work;
449             });
450             if (entry == nullptr) {
451                 IMSA_HILOGE("OnInputStart:: entryptr is null");
452                 return;
453             }
454 
455             auto getInputStartProperty = [](napi_value *args, uint8_t argc,
456                                              std::shared_ptr<JSCallbackObject> item) -> bool {
457                 if (argc < 2) {
458                     return false;
459                 }
460                 napi_value textInput = JsTextInputClientEngine::GetTextInputClientInstance(item->env_);
461                 napi_value keyBoardController = JsKeyboardControllerEngine::GetKeyboardControllerInstance(item->env_);
462                 if (keyBoardController == nullptr || textInput == nullptr) {
463                     IMSA_HILOGE("get KBCins or TICins failed:");
464                     return false;
465                 }
466                 args[ARGC_ZERO] = keyBoardController;
467                 args[ARGC_ONE] = textInput;
468                 return true;
469             };
470             JsUtils::TraverseCallback(entry->vecCopy, ARGC_TWO, getInputStartProperty);
471         });
472 }
473 
OnKeyboardStatus(bool isShow)474 void JsInputMethodEngineSetting::OnKeyboardStatus(bool isShow)
475 {
476     std::string type = isShow ? "keyboardShow" : "keyboardHide";
477     IMSA_HILOGD("run in, %{public}s", type.c_str());
478     uv_work_t *work = GetUVwork(type);
479     if (work == nullptr) {
480         IMSA_HILOGD("failed to get uv entry");
481         return;
482     }
483     uv_queue_work(
484         loop_, work, [](uv_work_t *work) {},
485         [](uv_work_t *work, int status) {
486             std::shared_ptr<UvEntry> entry(static_cast<UvEntry *>(work->data), [work](UvEntry *data) {
487                 delete data;
488                 delete work;
489             });
490 
491             auto getKeyboardStatusProperty = [](napi_value *args, uint8_t argc,
492                                                  std::shared_ptr<JSCallbackObject> item) -> bool {
493                 if (argc == 0) {
494                     return false;
495                 }
496                 args[ARGC_ZERO] = nullptr;
497                 return true;
498             };
499             JsUtils::TraverseCallback(entry->vecCopy, ARGC_ZERO, getKeyboardStatusProperty);
500         });
501 }
502 
OnInputStop(const std::string & imeId)503 void JsInputMethodEngineSetting::OnInputStop(const std::string &imeId)
504 {
505     IMSA_HILOGD("run in");
506     std::string type = "inputStop";
507     uv_work_t *work = GetUVwork(type, [&imeId](UvEntry &entry) { entry.imeid = imeId; });
508     if (work == nullptr) {
509         IMSA_HILOGD("failed to get uv entry");
510         return;
511     }
512     uv_queue_work(
513         loop_, work, [](uv_work_t *work) {},
514         [](uv_work_t *work, int status) {
515             std::shared_ptr<UvEntry> entry(static_cast<UvEntry *>(work->data), [work](UvEntry *data) {
516                 delete data;
517                 delete work;
518             });
519             if (entry == nullptr) {
520                 IMSA_HILOGE("OnInputStop:: entryptr is null");
521                 return;
522             }
523 
524             auto getInputStopProperty = [entry](napi_value *args, uint8_t argc,
525                                             std::shared_ptr<JSCallbackObject> item) -> bool {
526                 if (argc == 0) {
527                     return false;
528                 }
529                 napi_create_string_utf8(item->env_, entry->imeid.c_str(), NAPI_AUTO_LENGTH, &args[ARGC_ZERO]);
530                 return true;
531             };
532             JsUtils::TraverseCallback(entry->vecCopy, ARGC_ONE, getInputStopProperty);
533         });
534 }
535 
OnSetCallingWindow(uint32_t windowId)536 void JsInputMethodEngineSetting::OnSetCallingWindow(uint32_t windowId)
537 {
538     IMSA_HILOGD("run in");
539     std::string type = "setCallingWindow";
540     uv_work_t *work = GetUVwork(type, [windowId](UvEntry &entry) { entry.windowid = windowId; });
541     if (work == nullptr) {
542         IMSA_HILOGD("failed to get uv entry");
543         return;
544     }
545     uv_queue_work(
546         loop_, work, [](uv_work_t *work) {},
547         [](uv_work_t *work, int status) {
548             std::shared_ptr<UvEntry> entry(static_cast<UvEntry *>(work->data), [work](UvEntry *data) {
549                 delete data;
550                 delete work;
551             });
552             if (entry == nullptr) {
553                 IMSA_HILOGE("setCallingWindow:: entryptr is null");
554                 return;
555             }
556 
557             auto getCallingWindowProperty = [entry](napi_value *args, uint8_t argc,
558                                                 std::shared_ptr<JSCallbackObject> item) -> bool {
559                 if (argc == 0) {
560                     return false;
561                 }
562                 napi_create_int32(item->env_, entry->windowid, &args[ARGC_ZERO]);
563                 return true;
564             };
565             JsUtils::TraverseCallback(entry->vecCopy, ARGC_ONE, getCallingWindowProperty);
566         });
567 }
568 
OnSetSubtype(const SubProperty & property)569 void JsInputMethodEngineSetting::OnSetSubtype(const SubProperty &property)
570 {
571     IMSA_HILOGD("run in");
572     std::string type = "setSubtype";
573     uv_work_t *work = GetUVwork(type, [&property](UvEntry &entry) { entry.subProperty = property; });
574     if (work == nullptr) {
575         IMSA_HILOGD("failed to get uv entry");
576         return;
577     }
578     uv_queue_work(
579         loop_, work, [](uv_work_t *work) {},
580         [](uv_work_t *work, int status) {
581             std::shared_ptr<UvEntry> entry(static_cast<UvEntry *>(work->data), [work](UvEntry *data) {
582                 delete data;
583                 delete work;
584             });
585             if (entry == nullptr) {
586                 IMSA_HILOGE("OnSetSubtype:: entryptr is null");
587                 return;
588             }
589 
590             auto getSubtypeProperty = [entry](napi_value *args, uint8_t argc,
591                                           std::shared_ptr<JSCallbackObject> item) -> bool {
592                 if (argc == 0) {
593                     return false;
594                 }
595                 napi_value jsObject = GetResultOnSetSubtype(item->env_, entry->subProperty);
596                 if (jsObject == nullptr) {
597                     IMSA_HILOGE("get GetResultOnSetSubtype failed: jsObject is nullptr");
598                     return false;
599                 }
600                 args[ARGC_ZERO] = { jsObject };
601                 return true;
602             };
603             JsUtils::TraverseCallback(entry->vecCopy, ARGC_ONE, getSubtypeProperty);
604         });
605 }
606 
GetUVwork(const std::string & type,EntrySetter entrySetter)607 uv_work_t *JsInputMethodEngineSetting::GetUVwork(const std::string &type, EntrySetter entrySetter)
608 {
609     IMSA_HILOGD("run in, type: %{public}s", type.c_str());
610     UvEntry *entry = nullptr;
611     {
612         std::lock_guard<std::recursive_mutex> lock(mutex_);
613 
614         if (jsCbMap_[type].empty()) {
615             IMSA_HILOGE("%{public}s cb-vector is empty", type.c_str());
616             return nullptr;
617         }
618         entry = new (std::nothrow) UvEntry(jsCbMap_[type], type);
619         if (entry == nullptr) {
620             IMSA_HILOGE("entry ptr is nullptr!");
621             return nullptr;
622         }
623         if (entrySetter != nullptr) {
624             entrySetter(*entry);
625         }
626     }
627     uv_work_t *work = new (std::nothrow) uv_work_t;
628     if (work == nullptr) {
629         IMSA_HILOGE("entry ptr is nullptr!");
630         return nullptr;
631     }
632     work->data = entry;
633     return work;
634 }
635 } // namespace MiscServices
636 } // namespace OHOS
637