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, ©Value);
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