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_keyboard_delegate_setting.h"
17
18 #include "event_checker.h"
19 #include "input_method_ability.h"
20 #include "inputmethod_trace.h"
21 #include "js_callback_handler.h"
22 #include "js_keyboard_controller_engine.h"
23 #include "js_text_input_client_engine.h"
24 #include "js_util.h"
25 #include "js_utils.h"
26 #include "key_event_napi.h"
27 #include "napi/native_api.h"
28 #include "napi/native_node_api.h"
29 namespace OHOS {
30 namespace MiscServices {
31 constexpr size_t ARGC_ONE = 1;
32 constexpr size_t ARGC_TWO = 2;
33 const std::string JsKeyboardDelegateSetting::KDS_CLASS_NAME = "KeyboardDelegate";
34 thread_local napi_ref JsKeyboardDelegateSetting::KDSRef_ = nullptr;
35
36 std::mutex JsKeyboardDelegateSetting::keyboardMutex_;
37 std::shared_ptr<JsKeyboardDelegateSetting> JsKeyboardDelegateSetting::keyboardDelegate_{ nullptr };
38
Init(napi_env env,napi_value exports)39 napi_value JsKeyboardDelegateSetting::Init(napi_env env, napi_value exports)
40 {
41 napi_property_descriptor descriptor[] = {
42 DECLARE_NAPI_PROPERTY("OPTION_ASCII", GetJsConstProperty(env, static_cast<uint32_t>(20))),
43 DECLARE_NAPI_PROPERTY("OPTION_NONE", GetJsConstProperty(env, static_cast<uint32_t>(0))),
44 DECLARE_NAPI_PROPERTY("OPTION_AUTO_CAP_CHARACTERS", GetJsConstProperty(env, static_cast<uint32_t>(2))),
45 DECLARE_NAPI_PROPERTY("OPTION_AUTO_CAP_SENTENCES", GetJsConstProperty(env, static_cast<uint32_t>(8))),
46 DECLARE_NAPI_PROPERTY("OPTION_AUTO_WORDS", GetJsConstProperty(env, static_cast<uint32_t>(4))),
47 DECLARE_NAPI_PROPERTY("OPTION_MULTI_LINE", GetJsConstProperty(env, static_cast<uint32_t>(1))),
48 DECLARE_NAPI_PROPERTY("OPTION_NO_FULLSCREEN", GetJsConstProperty(env, static_cast<uint32_t>(10))),
49 DECLARE_NAPI_PROPERTY("CURSOR_UP", GetJsConstProperty(env, static_cast<uint32_t>(1))),
50 DECLARE_NAPI_PROPERTY("CURSOR_DOWN", GetJsConstProperty(env, static_cast<uint32_t>(2))),
51 DECLARE_NAPI_PROPERTY("CURSOR_LEFT", GetJsConstProperty(env, static_cast<uint32_t>(3))),
52 DECLARE_NAPI_PROPERTY("CURSOR_RIGHT", GetJsConstProperty(env, static_cast<uint32_t>(4))),
53
54 DECLARE_NAPI_PROPERTY("FLAG_SELECTING", GetJsConstProperty(env, static_cast<uint32_t>(2))),
55 DECLARE_NAPI_PROPERTY("FLAG_SINGLE_LINE", GetJsConstProperty(env, static_cast<uint32_t>(1))),
56
57 DECLARE_NAPI_PROPERTY("DISPLAY_MODE_PART", GetJsConstProperty(env, static_cast<uint32_t>(0))),
58 DECLARE_NAPI_PROPERTY("DISPLAY_MODE_FULL", GetJsConstProperty(env, static_cast<uint32_t>(1))),
59 DECLARE_NAPI_PROPERTY("WINDOW_TYPE_INPUT_METHOD_FLOAT", GetJsConstProperty(env, static_cast<uint32_t>(2105))),
60
61 DECLARE_NAPI_FUNCTION("createKeyboardDelegate", CreateKeyboardDelegate),
62 DECLARE_NAPI_FUNCTION("getKeyboardDelegate", GetKeyboardDelegate),
63 };
64 NAPI_CALL(
65 env, napi_define_properties(env, exports, sizeof(descriptor) / sizeof(napi_property_descriptor), descriptor));
66
67 napi_property_descriptor properties[] = {
68 DECLARE_NAPI_FUNCTION("on", Subscribe),
69 DECLARE_NAPI_FUNCTION("off", UnSubscribe),
70 };
71 napi_value cons = nullptr;
72 NAPI_CALL(env, napi_define_class(env, KDS_CLASS_NAME.c_str(), KDS_CLASS_NAME.size(), JsConstructor, nullptr,
73 sizeof(properties) / sizeof(napi_property_descriptor), properties, &cons));
74 NAPI_CALL(env, napi_create_reference(env, cons, 1, &KDSRef_));
75 NAPI_CALL(env, napi_set_named_property(env, exports, KDS_CLASS_NAME.c_str(), cons));
76 return exports;
77 };
78
GetJsConstProperty(napi_env env,uint32_t num)79 napi_value JsKeyboardDelegateSetting::GetJsConstProperty(napi_env env, uint32_t num)
80 {
81 napi_value jsNumber = nullptr;
82 napi_create_int32(env, num, &jsNumber);
83 return jsNumber;
84 };
85
GetKeyboardDelegateSetting()86 std::shared_ptr<JsKeyboardDelegateSetting> JsKeyboardDelegateSetting::GetKeyboardDelegateSetting()
87 {
88 if (keyboardDelegate_ == nullptr) {
89 std::lock_guard<std::mutex> lock(keyboardMutex_);
90 if (keyboardDelegate_ == nullptr) {
91 auto delegate = std::make_shared<JsKeyboardDelegateSetting>();
92 if (delegate == nullptr) {
93 IMSA_HILOGE("keyboard delegate nullptr");
94 return nullptr;
95 }
96 keyboardDelegate_ = delegate;
97 }
98 }
99 return keyboardDelegate_;
100 }
101
InitKeyboardDelegate()102 bool JsKeyboardDelegateSetting::InitKeyboardDelegate()
103 {
104 if (InputMethodAbility::GetInstance()->SetCoreAndAgent() != ErrorCode::NO_ERROR) {
105 return false;
106 }
107 auto delegate = GetKeyboardDelegateSetting();
108 if (delegate == nullptr) {
109 return false;
110 }
111 InputMethodAbility::GetInstance()->SetKdListener(delegate);
112 return true;
113 }
114
JsConstructor(napi_env env,napi_callback_info cbinfo)115 napi_value JsKeyboardDelegateSetting::JsConstructor(napi_env env, napi_callback_info cbinfo)
116 {
117 IMSA_HILOGI("run in JsConstructor");
118 napi_value thisVar = nullptr;
119 NAPI_CALL(env, napi_get_cb_info(env, cbinfo, nullptr, nullptr, &thisVar, nullptr));
120 auto delegate = GetKeyboardDelegateSetting();
121 if (delegate == nullptr || !InitKeyboardDelegate()) {
122 IMSA_HILOGE("failed to get delegate");
123 napi_value result = nullptr;
124 napi_get_null(env, &result);
125 return result;
126 }
127 napi_status status = napi_wrap(
128 env, thisVar, delegate.get(), [](napi_env env, void *nativeObject, void *hint) {}, nullptr, nullptr);
129 if (status != napi_ok) {
130 IMSA_HILOGE("JsKeyboardDelegateSetting napi_wrap failed: %{public}d", status);
131 return nullptr;
132 }
133 if (delegate->loop_ == nullptr) {
134 napi_get_uv_event_loop(env, &delegate->loop_);
135 }
136 return thisVar;
137 };
138
CreateKeyboardDelegate(napi_env env,napi_callback_info info)139 napi_value JsKeyboardDelegateSetting::CreateKeyboardDelegate(napi_env env, napi_callback_info info)
140 {
141 return GetKDInstance(env, info);
142 }
143
GetKeyboardDelegate(napi_env env,napi_callback_info info)144 napi_value JsKeyboardDelegateSetting::GetKeyboardDelegate(napi_env env, napi_callback_info info)
145 {
146 return GetKDInstance(env, info);
147 }
148
GetKDInstance(napi_env env,napi_callback_info info)149 napi_value JsKeyboardDelegateSetting::GetKDInstance(napi_env env, napi_callback_info info)
150 {
151 napi_value instance = nullptr;
152 napi_value cons = nullptr;
153 if (napi_get_reference_value(env, KDSRef_, &cons) != napi_ok) {
154 IMSA_HILOGE("napi_get_reference_value(env, KDSRef_, &cons) != napi_ok");
155 return nullptr;
156 }
157 IMSA_HILOGE("Get a reference to the global variable appAccountRef_ complete");
158 if (napi_new_instance(env, cons, 0, nullptr, &instance) != napi_ok) {
159 IMSA_HILOGE("napi_new_instance(env, cons, 0, nullptr, &instance) != napi_ok");
160 return nullptr;
161 }
162 return instance;
163 }
164
RegisterListener(napi_value callback,std::string type,std::shared_ptr<JSCallbackObject> callbackObj)165 void JsKeyboardDelegateSetting::RegisterListener(
166 napi_value callback, std::string type, std::shared_ptr<JSCallbackObject> callbackObj)
167 {
168 IMSA_HILOGI("RegisterListener %{public}s", type.c_str());
169 std::lock_guard<std::recursive_mutex> lock(mutex_);
170 if (jsCbMap_.empty() || jsCbMap_.find(type) == jsCbMap_.end()) {
171 IMSA_HILOGE("methodName %{public}s not registered!", type.c_str());
172 }
173 auto callbacks = jsCbMap_[type];
174 bool ret = std::any_of(callbacks.begin(), callbacks.end(), [&callback](std::shared_ptr<JSCallbackObject> cb) {
175 return JsUtils::Equals(cb->env_, callback, cb->callback_, cb->threadId_);
176 });
177 if (ret) {
178 IMSA_HILOGE("JsKeyboardDelegateSetting::RegisterListener callback already registered!");
179 return;
180 }
181
182 IMSA_HILOGI("Add %{public}s callbackObj into jsCbMap_", type.c_str());
183 jsCbMap_[type].push_back(std::move(callbackObj));
184 }
185
UnRegisterListener(napi_value callback,std::string type)186 void JsKeyboardDelegateSetting::UnRegisterListener(napi_value callback, std::string type)
187 {
188 IMSA_HILOGI("UnRegisterListener %{public}s", type.c_str());
189 std::lock_guard<std::recursive_mutex> lock(mutex_);
190 if (jsCbMap_.empty() || jsCbMap_.find(type) == jsCbMap_.end()) {
191 IMSA_HILOGE("methodName %{public}s not unRegistered!", type.c_str());
192 return;
193 }
194
195 if (callback == nullptr) {
196 jsCbMap_.erase(type);
197 IMSA_HILOGE("callback is nullptr");
198 return;
199 }
200
201 for (auto item = jsCbMap_[type].begin(); item != jsCbMap_[type].end(); item++) {
202 if ((callback != nullptr) &&
203 (JsUtils::Equals((*item)->env_, callback, (*item)->callback_, (*item)->threadId_))) {
204 jsCbMap_[type].erase(item);
205 break;
206 }
207 }
208 if (jsCbMap_[type].empty()) {
209 jsCbMap_.erase(type);
210 }
211 }
212
Subscribe(napi_env env,napi_callback_info info)213 napi_value JsKeyboardDelegateSetting::Subscribe(napi_env env, napi_callback_info info)
214 {
215 size_t argc = ARGC_TWO;
216 napi_value argv[ARGC_TWO] = { nullptr };
217 napi_value thisVar = nullptr;
218 void *data = nullptr;
219 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, &data));
220 std::string type;
221 // 2 means least param num.
222 if (argc < 2 || !JsUtil::GetValue(env, argv[0], type)
223 || !EventChecker::IsValidEventType(EventSubscribeModule::KEYBOARD_DELEGATE, type)
224 || JsUtil::GetType(env, argv[1]) != napi_function) {
225 IMSA_HILOGE("Subscribe failed, type:%{public}s", type.c_str());
226 return nullptr;
227 }
228 IMSA_HILOGD("Subscribe type:%{public}s.", type.c_str());
229 auto engine = reinterpret_cast<JsKeyboardDelegateSetting *>(JsUtils::GetNativeSelf(env, info));
230 if (engine == nullptr) {
231 return nullptr;
232 }
233 std::shared_ptr<JSCallbackObject> callback =
234 std::make_shared<JSCallbackObject>(env, argv[1], std::this_thread::get_id());
235 engine->RegisterListener(argv[ARGC_ONE], type, callback);
236
237 napi_value result = nullptr;
238 napi_get_null(env, &result);
239 return result;
240 }
241
UnSubscribe(napi_env env,napi_callback_info info)242 napi_value JsKeyboardDelegateSetting::UnSubscribe(napi_env env, napi_callback_info info)
243 {
244 size_t argc = ARGC_TWO;
245 napi_value argv[ARGC_TWO] = { nullptr };
246 napi_value thisVar = nullptr;
247 void *data = nullptr;
248 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, &data));
249 std::string type;
250 // 1 means least param num.
251 if (argc < 1 || !JsUtil::GetValue(env, argv[0], type)
252 || !EventChecker::IsValidEventType(EventSubscribeModule::KEYBOARD_DELEGATE, type)) {
253 IMSA_HILOGE("UnSubscribe failed, type:%{public}s", type.c_str());
254 return nullptr;
255 }
256 // If the type of optional parameter is wrong, make it nullptr
257 if (JsUtil::GetType(env, argv[1]) != napi_function) {
258 argv[1] = nullptr;
259 }
260 IMSA_HILOGD("UnSubscribe type:%{public}s.", type.c_str());
261 auto delegate = reinterpret_cast<JsKeyboardDelegateSetting *>(JsUtils::GetNativeSelf(env, info));
262 if (delegate == nullptr) {
263 return nullptr;
264 }
265 delegate->UnRegisterListener(argv[ARGC_ONE], type);
266 napi_value result = nullptr;
267 napi_get_null(env, &result);
268 return result;
269 }
270
GetResultOnKeyEvent(napi_env env,int32_t keyCode,int32_t keyStatus)271 napi_value JsKeyboardDelegateSetting::GetResultOnKeyEvent(napi_env env, int32_t keyCode, int32_t keyStatus)
272 {
273 napi_value KeyboardDelegate = nullptr;
274 napi_create_object(env, &KeyboardDelegate);
275
276 napi_value jsKeyCode = nullptr;
277 napi_create_int32(env, keyCode, &jsKeyCode);
278 napi_set_named_property(env, KeyboardDelegate, "keyCode", jsKeyCode);
279
280 napi_value jsKeyAction = nullptr;
281 napi_create_int32(env, keyStatus, &jsKeyAction);
282 napi_set_named_property(env, KeyboardDelegate, "keyAction", jsKeyAction);
283
284 return KeyboardDelegate;
285 }
286
OnKeyEvent(const std::shared_ptr<MMI::KeyEvent> & keyEvent)287 bool JsKeyboardDelegateSetting::OnKeyEvent(const std::shared_ptr<MMI::KeyEvent> &keyEvent)
288 {
289 IMSA_HILOGD("run in");
290 std::string type = "keyEvent";
291 auto isDone = std::make_shared<BlockData<bool>>(MAX_TIMEOUT, false);
292 uv_work_t *work = GetUVwork(type, [keyEvent, isDone](UvEntry &entry) {
293 entry.pullKeyEventPara = keyEvent;
294 entry.isDone = isDone;
295 });
296 if (work == nullptr) {
297 IMSA_HILOGE("failed to get uv work");
298 return false;
299 }
300 StartAsync("OnFullKeyEvent", static_cast<int32_t>(TraceTaskId::ON_FULL_KEY_EVENT));
301 uv_queue_work_with_qos(
302 loop_, work, [](uv_work_t *work) {},
303 [](uv_work_t *work, int status) {
304 InputMethodSyncTrace trace("OnFullKeyEvent UV_QUEUE_WORK");
305 std::shared_ptr<UvEntry> entry(static_cast<UvEntry *>(work->data), [work](UvEntry *data) {
306 delete data;
307 delete work;
308 });
309 auto getKeyEventProperty = [entry](napi_env env, napi_value *args, uint8_t argc) -> bool {
310 InputMethodSyncTrace tracer("Create parameter");
311 if (argc == 0) {
312 return false;
313 }
314 napi_value keyEventObject{};
315 auto result = napi_create_object(env, &keyEventObject);
316 CHECK_RETURN((result == napi_ok) && (keyEventObject != nullptr), "create object", false);
317 result = MMI::KeyEventNapi::CreateKeyEvent(env, entry->pullKeyEventPara, keyEventObject);
318 CHECK_RETURN((result == napi_ok) && (keyEventObject != nullptr), "create key event object", false);
319 // 0 means the first param of callback.
320 args[0] = keyEventObject;
321 return true;
322 };
323 bool isConsumed = false;
324 // 1 means callback has one param.
325 JsCallbackHandler::Traverse(entry->vecCopy, { 1, getKeyEventProperty }, isConsumed);
326 entry->isDone->SetValue(isConsumed);
327 FinishAsync("OnFullKeyEvent", static_cast<int32_t>(TraceTaskId::ON_FULL_KEY_EVENT));
328 },
329 uv_qos_user_initiated);
330 bool isConsumed = isDone->GetValue();
331 IMSA_HILOGI("key event handle result: %{public}d", isConsumed);
332 return isConsumed;
333 }
334
OnKeyEvent(int32_t keyCode,int32_t keyStatus)335 bool JsKeyboardDelegateSetting::OnKeyEvent(int32_t keyCode, int32_t keyStatus)
336 {
337 IMSA_HILOGD("run in");
338 KeyEventPara para{ keyCode, keyStatus, false };
339 std::string type = (keyStatus == ARGC_TWO ? "keyDown" : "keyUp");
340 auto isDone = std::make_shared<BlockData<bool>>(MAX_TIMEOUT, false);
341 uv_work_t *work = GetUVwork(type, [¶, isDone](UvEntry &entry) {
342 entry.keyEventPara = { para.keyCode, para.keyStatus, para.isOnKeyEvent };
343 entry.isDone = isDone;
344 });
345 if (work == nullptr) {
346 IMSA_HILOGE("failed to get uv work");
347 return false;
348 }
349 StartAsync("OnKeyEvent", static_cast<int32_t>(TraceTaskId::ON_KEY_EVENT));
350 uv_queue_work_with_qos(
351 loop_, work, [](uv_work_t *work) {},
352 [](uv_work_t *work, int status) {
353 InputMethodSyncTrace tracer("OnkeyEvent UV_QUEUE_WORK");
354 std::shared_ptr<UvEntry> entry(static_cast<UvEntry *>(work->data), [work](UvEntry *data) {
355 delete data;
356 delete work;
357 });
358 auto getKeyEventProperty = [entry](napi_env env, napi_value *args, uint8_t argc) -> bool {
359 InputMethodSyncTrace tracer("Create parameter");
360 if (argc == 0) {
361 return false;
362 }
363 napi_value jsObject =
364 GetResultOnKeyEvent(env, entry->keyEventPara.keyCode, entry->keyEventPara.keyStatus);
365 if (jsObject == nullptr) {
366 IMSA_HILOGE("get GetResultOnKeyEvent failed: jsObject is nullptr");
367 return false;
368 }
369 // 0 means the first param of callback.
370 args[0] = jsObject;
371 return true;
372 };
373 bool isConsumed = false;
374 // 1 means callback has one param.
375 JsCallbackHandler::Traverse(entry->vecCopy, { 1, getKeyEventProperty }, isConsumed);
376 entry->isDone->SetValue(isConsumed);
377 FinishAsync("OnKeyEvent", static_cast<int32_t>(TraceTaskId::ON_KEY_EVENT));
378 },
379 uv_qos_user_initiated);
380 bool isConsumed = isDone->GetValue();
381 IMSA_HILOGI("key event handle result: %{public}d", isConsumed);
382 return isConsumed;
383 }
384
OnCursorUpdate(int32_t positionX,int32_t positionY,int32_t height)385 void JsKeyboardDelegateSetting::OnCursorUpdate(int32_t positionX, int32_t positionY, int32_t height)
386 {
387 IMSA_HILOGD("run in");
388 CursorPara para{ positionX, positionY, height };
389 std::string type = "cursorContextChange";
390 uv_work_t *work = GetUVwork(type, [¶](UvEntry &entry) {
391 entry.curPara.positionX = para.positionX;
392 entry.curPara.positionY = para.positionY;
393 entry.curPara.height = para.height;
394 });
395 if (work == nullptr) {
396 IMSA_HILOGD("failed to get uv entry");
397 return;
398 }
399 uv_queue_work_with_qos(
400 loop_, work, [](uv_work_t *work) {},
401 [](uv_work_t *work, int status) {
402 std::shared_ptr<UvEntry> entry(static_cast<UvEntry *>(work->data), [work](UvEntry *data) {
403 delete data;
404 delete work;
405 });
406
407 auto getCursorUpdateProperty = [entry](napi_env env, napi_value *args, uint8_t argc) -> bool {
408 if (argc < 3) {
409 return false;
410 }
411 // 0 means the first param of callback.
412 napi_create_int32(env, entry->curPara.positionX, &args[0]);
413 // 1 means the second param of callback.
414 napi_create_int32(env, entry->curPara.positionY, &args[1]);
415 // 2 means the third param of callback.
416 napi_create_int32(env, entry->curPara.height, &args[2]);
417 return true;
418 };
419 // 3 means callback has three params.
420 JsCallbackHandler::Traverse(entry->vecCopy, { 3, getCursorUpdateProperty });
421 },
422 uv_qos_user_initiated);
423 }
424
OnSelectionChange(int32_t oldBegin,int32_t oldEnd,int32_t newBegin,int32_t newEnd)425 void JsKeyboardDelegateSetting::OnSelectionChange(int32_t oldBegin, int32_t oldEnd, int32_t newBegin, int32_t newEnd)
426 {
427 IMSA_HILOGD("run in");
428 SelectionPara para{ oldBegin, oldEnd, newBegin, newEnd };
429 std::string type = "selectionChange";
430 uv_work_t *work = GetUVwork(type, [¶](UvEntry &entry) {
431 entry.selPara.oldBegin = para.oldBegin;
432 entry.selPara.oldEnd = para.oldEnd;
433 entry.selPara.newBegin = para.newBegin;
434 entry.selPara.newEnd = para.newEnd;
435 });
436 if (work == nullptr) {
437 IMSA_HILOGD("failed to get uv entry");
438 return;
439 }
440 uv_queue_work_with_qos(
441 loop_, work, [](uv_work_t *work) {},
442 [](uv_work_t *work, int status) {
443 std::shared_ptr<UvEntry> entry(static_cast<UvEntry *>(work->data), [work](UvEntry *data) {
444 delete data;
445 delete work;
446 });
447
448 auto getSelectionChangeProperty = [entry](napi_env env, napi_value *args, uint8_t argc) -> bool {
449 if (argc < 4) {
450 return false;
451 }
452 // 0 means the first param of callback.
453 napi_create_int32(env, entry->selPara.oldBegin, &args[0]);
454 // 1 means the second param of callback.
455 napi_create_int32(env, entry->selPara.oldEnd, &args[1]);
456 // 2 means the third param of callback.
457 napi_create_int32(env, entry->selPara.newBegin, &args[2]);
458 // 3 means the fourth param of callback.
459 napi_create_int32(env, entry->selPara.newEnd, &args[3]);
460 return true;
461 };
462 // 4 means callback has four params.
463 JsCallbackHandler::Traverse(entry->vecCopy, { 4, getSelectionChangeProperty });
464 },
465 uv_qos_user_initiated);
466 }
467
OnTextChange(const std::string & text)468 void JsKeyboardDelegateSetting::OnTextChange(const std::string &text)
469 {
470 IMSA_HILOGD("run in");
471 std::string type = "textChange";
472 uv_work_t *work = GetUVwork(type, [&text](UvEntry &entry) { entry.text = text; });
473 if (work == nullptr) {
474 IMSA_HILOGD("failed to get uv entry");
475 return;
476 }
477 uv_queue_work_with_qos(
478 loop_, work, [](uv_work_t *work) {},
479 [](uv_work_t *work, int status) {
480 std::shared_ptr<UvEntry> entry(static_cast<UvEntry *>(work->data), [work](UvEntry *data) {
481 delete data;
482 delete work;
483 });
484
485 auto getTextChangeProperty = [entry](napi_env env, napi_value *args, uint8_t argc) -> bool {
486 if (argc == 0) {
487 return false;
488 }
489 // 0 means the first param of callback.
490 napi_create_string_utf8(env, entry->text.c_str(), NAPI_AUTO_LENGTH, &args[0]);
491 return true;
492 };
493 // 1 means callback has one param.
494 JsCallbackHandler::Traverse(entry->vecCopy, { 1, getTextChangeProperty });
495 },
496 uv_qos_user_initiated);
497 }
498
OnEditorAttributeChange(const InputAttribute & inputAttribute)499 void JsKeyboardDelegateSetting::OnEditorAttributeChange(const InputAttribute &inputAttribute)
500 {
501 IMSA_HILOGI("run in");
502 std::string type = "editorAttributeChanged";
503 uv_work_t *work = JsKeyboardDelegateSetting::GetUVwork(type, [&inputAttribute](UvEntry &entry) {
504 entry.inputAttribute = inputAttribute;
505 });
506 if (work == nullptr) {
507 IMSA_HILOGD("failed to get uv entry");
508 return;
509 }
510 uv_queue_work_with_qos(
511 loop_, work, [](uv_work_t *work) {},
512 [](uv_work_t *work, int status) {
513 std::shared_ptr<UvEntry> entry(static_cast<UvEntry *>(work->data), [work](UvEntry *data) {
514 delete data;
515 delete work;
516 });
517
518 auto getEditorAttributeChangeProperty = [entry](napi_env env, napi_value *args, uint8_t argc) -> bool {
519 if (argc == 0) {
520 return false;
521 }
522
523 napi_value jsObject = JsUtils::GetValue(env, entry->inputAttribute);
524 if (jsObject == nullptr) {
525 IMSA_HILOGE("get GetAttribute failed: jsObject is nullptr");
526 return false;
527 }
528 // 0 means the first param of callback.
529 args[0] = jsObject;
530 return true;
531 };
532 // 1 means callback has one param.
533 JsCallbackHandler::Traverse(entry->vecCopy, { 1, getEditorAttributeChangeProperty });
534 },
535 uv_qos_user_initiated);
536 }
537
GetUVwork(const std::string & type,EntrySetter entrySetter)538 uv_work_t *JsKeyboardDelegateSetting::GetUVwork(const std::string &type, EntrySetter entrySetter)
539 {
540 IMSA_HILOGD("run in, type: %{public}s", type.c_str());
541 UvEntry *entry = nullptr;
542 {
543 std::lock_guard<std::recursive_mutex> lock(mutex_);
544
545 if (jsCbMap_[type].empty()) {
546 IMSA_HILOGE("%{public}s cb-vector is empty", type.c_str());
547 return nullptr;
548 }
549 entry = new (std::nothrow) UvEntry(jsCbMap_[type], type);
550 if (entry == nullptr) {
551 IMSA_HILOGE("entry ptr is nullptr!");
552 return nullptr;
553 }
554 if (entrySetter != nullptr) {
555 entrySetter(*entry);
556 }
557 }
558 uv_work_t *work = new (std::nothrow) uv_work_t;
559 if (work == nullptr) {
560 IMSA_HILOGE("entry ptr is nullptr!");
561 return nullptr;
562 }
563 work->data = entry;
564 return work;
565 }
566 } // namespace MiscServices
567 } // namespace OHOS
568