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
30 namespace OHOS {
31 namespace MiscServices {
32 constexpr size_t ARGC_ONE = 1;
33 constexpr size_t ARGC_TWO = 2;
34 const std::string JsKeyboardDelegateSetting::KDS_CLASS_NAME = "KeyboardDelegate";
35 thread_local napi_ref JsKeyboardDelegateSetting::KDSRef_ = nullptr;
36
37 std::mutex JsKeyboardDelegateSetting::keyboardMutex_;
38 std::shared_ptr<JsKeyboardDelegateSetting> JsKeyboardDelegateSetting::keyboardDelegate_{ nullptr };
39 std::mutex JsKeyboardDelegateSetting::eventHandlerMutex_;
40 std::shared_ptr<AppExecFwk::EventHandler> JsKeyboardDelegateSetting::handler_{ nullptr };
41
Init(napi_env env,napi_value exports)42 napi_value JsKeyboardDelegateSetting::Init(napi_env env, napi_value exports)
43 {
44 napi_property_descriptor descriptor[] = {
45 DECLARE_NAPI_PROPERTY("OPTION_ASCII", GetJsConstProperty(env, static_cast<uint32_t>(20))),
46 DECLARE_NAPI_PROPERTY("OPTION_NONE", GetJsConstProperty(env, static_cast<uint32_t>(0))),
47 DECLARE_NAPI_PROPERTY("OPTION_AUTO_CAP_CHARACTERS", GetJsConstProperty(env, static_cast<uint32_t>(2))),
48 DECLARE_NAPI_PROPERTY("OPTION_AUTO_CAP_SENTENCES", GetJsConstProperty(env, static_cast<uint32_t>(8))),
49 DECLARE_NAPI_PROPERTY("OPTION_AUTO_WORDS", GetJsConstProperty(env, static_cast<uint32_t>(4))),
50 DECLARE_NAPI_PROPERTY("OPTION_MULTI_LINE", GetJsConstProperty(env, static_cast<uint32_t>(1))),
51 DECLARE_NAPI_PROPERTY("OPTION_NO_FULLSCREEN", GetJsConstProperty(env, static_cast<uint32_t>(10))),
52 DECLARE_NAPI_PROPERTY("CURSOR_UP", GetJsConstProperty(env, static_cast<uint32_t>(1))),
53 DECLARE_NAPI_PROPERTY("CURSOR_DOWN", GetJsConstProperty(env, static_cast<uint32_t>(2))),
54 DECLARE_NAPI_PROPERTY("CURSOR_LEFT", GetJsConstProperty(env, static_cast<uint32_t>(3))),
55 DECLARE_NAPI_PROPERTY("CURSOR_RIGHT", GetJsConstProperty(env, static_cast<uint32_t>(4))),
56
57 DECLARE_NAPI_PROPERTY("FLAG_SELECTING", GetJsConstProperty(env, static_cast<uint32_t>(2))),
58 DECLARE_NAPI_PROPERTY("FLAG_SINGLE_LINE", GetJsConstProperty(env, static_cast<uint32_t>(1))),
59
60 DECLARE_NAPI_PROPERTY("DISPLAY_MODE_PART", GetJsConstProperty(env, static_cast<uint32_t>(0))),
61 DECLARE_NAPI_PROPERTY("DISPLAY_MODE_FULL", GetJsConstProperty(env, static_cast<uint32_t>(1))),
62 DECLARE_NAPI_PROPERTY("WINDOW_TYPE_INPUT_METHOD_FLOAT", GetJsConstProperty(env, static_cast<uint32_t>(2105))),
63
64 DECLARE_NAPI_FUNCTION("createKeyboardDelegate", CreateKeyboardDelegate),
65 DECLARE_NAPI_FUNCTION("getKeyboardDelegate", GetKeyboardDelegate),
66 };
67 NAPI_CALL(
68 env, napi_define_properties(env, exports, sizeof(descriptor) / sizeof(napi_property_descriptor), descriptor));
69
70 napi_property_descriptor properties[] = {
71 DECLARE_NAPI_FUNCTION("on", Subscribe),
72 DECLARE_NAPI_FUNCTION("off", UnSubscribe),
73 };
74 napi_value cons = nullptr;
75 NAPI_CALL(env, napi_define_class(env, KDS_CLASS_NAME.c_str(), KDS_CLASS_NAME.size(), JsConstructor, nullptr,
76 sizeof(properties) / sizeof(napi_property_descriptor), properties, &cons));
77 NAPI_CALL(env, napi_create_reference(env, cons, 1, &KDSRef_));
78 NAPI_CALL(env, napi_set_named_property(env, exports, KDS_CLASS_NAME.c_str(), cons));
79 return exports;
80 };
81
GetJsConstProperty(napi_env env,uint32_t num)82 napi_value JsKeyboardDelegateSetting::GetJsConstProperty(napi_env env, uint32_t num)
83 {
84 napi_value jsNumber = nullptr;
85 napi_create_int32(env, num, &jsNumber);
86 return jsNumber;
87 };
88
GetKeyboardDelegateSetting()89 std::shared_ptr<JsKeyboardDelegateSetting> JsKeyboardDelegateSetting::GetKeyboardDelegateSetting()
90 {
91 if (keyboardDelegate_ == nullptr) {
92 std::lock_guard<std::mutex> lock(keyboardMutex_);
93 if (keyboardDelegate_ == nullptr) {
94 auto delegate = std::make_shared<JsKeyboardDelegateSetting>();
95 if (delegate == nullptr) {
96 IMSA_HILOGE("keyboard delegate is nullptr!");
97 return nullptr;
98 }
99 keyboardDelegate_ = delegate;
100 }
101 }
102 return keyboardDelegate_;
103 }
104
InitKeyboardDelegate()105 bool JsKeyboardDelegateSetting::InitKeyboardDelegate()
106 {
107 if (!InputMethodAbility::GetInstance()->IsCurrentIme()) {
108 return false;
109 }
110 auto delegate = GetKeyboardDelegateSetting();
111 if (delegate == nullptr) {
112 return false;
113 }
114 InputMethodAbility::GetInstance()->SetKdListener(delegate);
115 {
116 std::lock_guard<std::mutex> lock(eventHandlerMutex_);
117 handler_ = AppExecFwk::EventHandler::Current();
118 }
119 return true;
120 }
121
JsConstructor(napi_env env,napi_callback_info cbinfo)122 napi_value JsKeyboardDelegateSetting::JsConstructor(napi_env env, napi_callback_info cbinfo)
123 {
124 napi_value thisVar = nullptr;
125 NAPI_CALL(env, napi_get_cb_info(env, cbinfo, nullptr, nullptr, &thisVar, nullptr));
126 auto delegate = GetKeyboardDelegateSetting();
127 if (delegate == nullptr || !InitKeyboardDelegate()) {
128 IMSA_HILOGE("failed to get delegate!");
129 napi_value result = nullptr;
130 napi_get_null(env, &result);
131 return result;
132 }
133 napi_status status = napi_wrap(
134 env, thisVar, delegate.get(), [](napi_env env, void *nativeObject, void *hint) {}, nullptr, nullptr);
135 if (status != napi_ok) {
136 IMSA_HILOGE("failed to wrap: %{public}d!", status);
137 return nullptr;
138 }
139 if (delegate->loop_ == nullptr) {
140 napi_get_uv_event_loop(env, &delegate->loop_);
141 }
142 return thisVar;
143 };
144
CreateKeyboardDelegate(napi_env env,napi_callback_info info)145 napi_value JsKeyboardDelegateSetting::CreateKeyboardDelegate(napi_env env, napi_callback_info info)
146 {
147 return GetKDInstance(env, info);
148 }
149
GetKeyboardDelegate(napi_env env,napi_callback_info info)150 napi_value JsKeyboardDelegateSetting::GetKeyboardDelegate(napi_env env, napi_callback_info info)
151 {
152 return GetKDInstance(env, info);
153 }
154
GetKDInstance(napi_env env,napi_callback_info info)155 napi_value JsKeyboardDelegateSetting::GetKDInstance(napi_env env, napi_callback_info info)
156 {
157 napi_value instance = nullptr;
158 napi_value cons = nullptr;
159 if (napi_get_reference_value(env, KDSRef_, &cons) != napi_ok) {
160 IMSA_HILOGE("failed to get reference value!");
161 return nullptr;
162 }
163 if (napi_new_instance(env, cons, 0, nullptr, &instance) != napi_ok) {
164 IMSA_HILOGE("failed to new instance!");
165 return nullptr;
166 }
167 return instance;
168 }
169
RegisterListener(napi_value callback,std::string type,std::shared_ptr<JSCallbackObject> callbackObj)170 void JsKeyboardDelegateSetting::RegisterListener(
171 napi_value callback, std::string type, std::shared_ptr<JSCallbackObject> callbackObj)
172 {
173 IMSA_HILOGD("RegisterListener %{public}s", type.c_str());
174 std::lock_guard<std::recursive_mutex> lock(mutex_);
175 if (jsCbMap_.empty() || jsCbMap_.find(type) == jsCbMap_.end()) {
176 IMSA_HILOGD("methodName %{public}s is not registered!", type.c_str());
177 }
178 auto callbacks = jsCbMap_[type];
179 bool ret = std::any_of(callbacks.begin(), callbacks.end(), [&callback](std::shared_ptr<JSCallbackObject> cb) {
180 return JsUtils::Equals(cb->env_, callback, cb->callback_, cb->threadId_);
181 });
182 if (ret) {
183 IMSA_HILOGD("JsKeyboardDelegateSetting callback already registered!");
184 return;
185 }
186
187 IMSA_HILOGI("add %{public}s callbackObj into jsCbMap_.", type.c_str());
188 jsCbMap_[type].push_back(std::move(callbackObj));
189 }
190
UnRegisterListener(napi_value callback,std::string type)191 void JsKeyboardDelegateSetting::UnRegisterListener(napi_value callback, std::string type)
192 {
193 IMSA_HILOGI("unregister listener: %{public}s.", type.c_str());
194 std::lock_guard<std::recursive_mutex> lock(mutex_);
195 if (jsCbMap_.empty() || jsCbMap_.find(type) == jsCbMap_.end()) {
196 IMSA_HILOGE("methodName %{public}s is not unregistered!", type.c_str());
197 return;
198 }
199
200 if (callback == nullptr) {
201 jsCbMap_.erase(type);
202 IMSA_HILOGE("callback is nullptr");
203 return;
204 }
205
206 for (auto item = jsCbMap_[type].begin(); item != jsCbMap_[type].end(); item++) {
207 if ((callback != nullptr)
208 && (JsUtils::Equals((*item)->env_, callback, (*item)->callback_, (*item)->threadId_))) {
209 jsCbMap_[type].erase(item);
210 break;
211 }
212 }
213 if (jsCbMap_[type].empty()) {
214 jsCbMap_.erase(type);
215 }
216 }
217
Subscribe(napi_env env,napi_callback_info info)218 napi_value JsKeyboardDelegateSetting::Subscribe(napi_env env, napi_callback_info info)
219 {
220 size_t argc = ARGC_TWO;
221 napi_value argv[ARGC_TWO] = { nullptr };
222 napi_value thisVar = nullptr;
223 void *data = nullptr;
224 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, &data));
225 std::string type;
226 // 2 means least param num.
227 if (argc < 2 || !JsUtil::GetValue(env, argv[0], type) ||
228 !EventChecker::IsValidEventType(EventSubscribeModule::KEYBOARD_DELEGATE, type) ||
229 JsUtil::GetType(env, argv[1]) != napi_function) {
230 IMSA_HILOGE("subscribe failed, type: %{public}s!", type.c_str());
231 return nullptr;
232 }
233 IMSA_HILOGD("subscribe type: %{public}s.", type.c_str());
234 auto engine = reinterpret_cast<JsKeyboardDelegateSetting *>(JsUtils::GetNativeSelf(env, info));
235 if (engine == nullptr) {
236 return nullptr;
237 }
238 std::shared_ptr<JSCallbackObject> callback =
239 std::make_shared<JSCallbackObject>(env, argv[1], std::this_thread::get_id());
240 engine->RegisterListener(argv[ARGC_ONE], type, callback);
241
242 napi_value result = nullptr;
243 napi_get_null(env, &result);
244 return result;
245 }
246
UnSubscribe(napi_env env,napi_callback_info info)247 napi_value JsKeyboardDelegateSetting::UnSubscribe(napi_env env, napi_callback_info info)
248 {
249 size_t argc = ARGC_TWO;
250 napi_value argv[ARGC_TWO] = { nullptr };
251 napi_value thisVar = nullptr;
252 void *data = nullptr;
253 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, &data));
254 std::string type;
255 // 1 means least param num.
256 if (argc < 1 || !JsUtil::GetValue(env, argv[0], type) ||
257 !EventChecker::IsValidEventType(EventSubscribeModule::KEYBOARD_DELEGATE, type)) {
258 IMSA_HILOGE("unsubscribe failed, type: %{public}s!", type.c_str());
259 return nullptr;
260 }
261
262 // if the second param is not napi_function/napi_null/napi_undefined, return
263 auto paramType = JsUtil::GetType(env, argv[1]);
264 if (paramType != napi_function && paramType != napi_null && paramType != napi_undefined) {
265 return nullptr;
266 }
267 // if the second param is napi_function, delete it, else delete all
268 argv[1] = paramType == napi_function ? argv[1] : nullptr;
269
270 IMSA_HILOGD("unsubscribe type: %{public}s.", type.c_str());
271 auto delegate = reinterpret_cast<JsKeyboardDelegateSetting *>(JsUtils::GetNativeSelf(env, info));
272 if (delegate == nullptr) {
273 return nullptr;
274 }
275 delegate->UnRegisterListener(argv[ARGC_ONE], type);
276 napi_value result = nullptr;
277 napi_get_null(env, &result);
278 return result;
279 }
280
GetResultOnKeyEvent(napi_env env,int32_t keyCode,int32_t keyStatus)281 napi_value JsKeyboardDelegateSetting::GetResultOnKeyEvent(napi_env env, int32_t keyCode, int32_t keyStatus)
282 {
283 napi_value KeyboardDelegate = nullptr;
284 napi_create_object(env, &KeyboardDelegate);
285
286 napi_value jsKeyCode = nullptr;
287 napi_create_int32(env, keyCode, &jsKeyCode);
288 napi_set_named_property(env, KeyboardDelegate, "keyCode", jsKeyCode);
289
290 napi_value jsKeyAction = nullptr;
291 napi_create_int32(env, keyStatus, &jsKeyAction);
292 napi_set_named_property(env, KeyboardDelegate, "keyAction", jsKeyAction);
293
294 return KeyboardDelegate;
295 }
296
OnDealKeyEvent(const std::shared_ptr<MMI::KeyEvent> & keyEvent,sptr<KeyEventConsumerProxy> & consumer)297 bool JsKeyboardDelegateSetting::OnDealKeyEvent(
298 const std::shared_ptr<MMI::KeyEvent> &keyEvent, sptr<KeyEventConsumerProxy> &consumer)
299 {
300 auto eventHandler = GetEventHandler();
301 if (eventHandler == nullptr) {
302 IMSA_HILOGE("eventHandler is nullptr!");
303 return false;
304 }
305 auto keyEventEntry =
306 GetEntry("keyEvent", [keyEvent](UvEntry &entry) { entry.pullKeyEventPara = keyEvent; });
307 KeyEventPara para{ keyEvent->GetKeyCode(), keyEvent->GetKeyAction(), false };
308 std::string type = (keyEvent->GetKeyAction() == ARGC_TWO ? "keyDown" : "keyUp");
309 auto keyCodeEntry = GetEntry(type, [¶](UvEntry &entry) {
310 entry.keyEventPara = { para.keyCode, para.keyStatus, para.isOnKeyEvent };
311 });
312 if (keyEventEntry == nullptr && keyCodeEntry == nullptr) {
313 IMSA_HILOGW("key event callback is not registered.");
314 return false;
315 }
316 IMSA_HILOGD("run in.");
317 auto task = [keyEventEntry, keyCodeEntry, consumer]() { DealKeyEvent(keyEventEntry, keyCodeEntry, consumer); };
318 eventHandler->PostTask(task, "OnDealKeyEvent");
319 return true;
320 }
321
DealKeyEvent(const std::shared_ptr<UvEntry> & keyEventEntry,const std::shared_ptr<UvEntry> & keyCodeEntry,const sptr<KeyEventConsumerProxy> & consumer)322 void JsKeyboardDelegateSetting::DealKeyEvent(const std::shared_ptr<UvEntry> &keyEventEntry,
323 const std::shared_ptr<UvEntry> &keyCodeEntry, const sptr<KeyEventConsumerProxy> &consumer)
324 {
325 bool isKeyEventConsumed = false;
326 bool isKeyCodeConsumed = false;
327 if (keyEventEntry != nullptr) {
328 auto getKeyEventProperty = [keyEventEntry](napi_env env, napi_value *args, uint8_t argc) -> bool {
329 if (argc == 0) {
330 return false;
331 }
332 napi_value keyEventObject{};
333 auto result = napi_create_object(env, &keyEventObject);
334 CHECK_RETURN((result == napi_ok) && (keyEventObject != nullptr), "create object", false);
335 result = MMI::KeyEventNapi::CreateKeyEvent(env, keyEventEntry->pullKeyEventPara, keyEventObject);
336 CHECK_RETURN((result == napi_ok) && (keyEventObject != nullptr), "create key event object", false);
337 // 0 means the first param of callback.
338 args[0] = keyEventObject;
339 return true;
340 };
341 // 1 means callback has one param.
342 JsCallbackHandler::Traverse(keyEventEntry->vecCopy, { 1, getKeyEventProperty }, isKeyEventConsumed);
343 }
344 if (keyCodeEntry != nullptr) {
345 auto getKeyEventProperty = [keyCodeEntry](napi_env env, napi_value *args, uint8_t argc) -> bool {
346 InputMethodSyncTrace tracer("Create parameter");
347 if (argc == 0) {
348 return false;
349 }
350 napi_value jsObject =
351 GetResultOnKeyEvent(env, keyCodeEntry->keyEventPara.keyCode, keyCodeEntry->keyEventPara.keyStatus);
352 if (jsObject == nullptr) {
353 IMSA_HILOGE("jsObject is nullptr!");
354 return false;
355 }
356 // 0 means the first param of callback.
357 args[0] = jsObject;
358 return true;
359 };
360 // 1 means callback has one param.
361 JsCallbackHandler::Traverse(keyCodeEntry->vecCopy, { 1, getKeyEventProperty }, isKeyCodeConsumed);
362 }
363 bool consumeResult = isKeyEventConsumed || isKeyCodeConsumed;
364 if (consumer != nullptr) {
365 consumer->OnKeyEventResult(consumeResult);
366 if (!consumeResult) {
367 IMSA_HILOGW("ime is not consumed, result: %{public}d.", consumeResult);
368 }
369 }
370 }
371
OnKeyEvent(const std::shared_ptr<MMI::KeyEvent> & keyEvent,sptr<KeyEventConsumerProxy> & consumer)372 bool JsKeyboardDelegateSetting::OnKeyEvent(
373 const std::shared_ptr<MMI::KeyEvent> &keyEvent, sptr<KeyEventConsumerProxy> &consumer)
374 {
375 std::string type = "keyEvent";
376 auto entry = GetEntry(type, [keyEvent, &consumer](UvEntry &entry) {
377 entry.pullKeyEventPara = keyEvent;
378 entry.keyEvenetConsumer = consumer;
379 });
380 if (entry == nullptr) {
381 return false;
382 }
383 auto eventHandler = GetEventHandler();
384 if (eventHandler == nullptr) {
385 IMSA_HILOGE("eventHandler is nullptr!");
386 return false;
387 }
388
389 IMSA_HILOGI("run in.");
390 StartAsync("OnFullKeyEvent", static_cast<int32_t>(TraceTaskId::ON_FULL_KEY_EVENT));
391 auto task = [entry]() {
392 auto getKeyEventProperty = [entry](napi_env env, napi_value *args, uint8_t argc) -> bool {
393 InputMethodSyncTrace tracer("Create parameter");
394 if (argc == 0) {
395 return false;
396 }
397 napi_value keyEventObject{};
398 auto result = napi_create_object(env, &keyEventObject);
399 CHECK_RETURN((result == napi_ok) && (keyEventObject != nullptr), "create object", false);
400 result = MMI::KeyEventNapi::CreateKeyEvent(env, entry->pullKeyEventPara, keyEventObject);
401 CHECK_RETURN((result == napi_ok) && (keyEventObject != nullptr), "create key event object", false);
402 // 0 means the first param of callback.
403 args[0] = keyEventObject;
404 return true;
405 };
406 bool isConsumed = false;
407 // 1 means callback has one param.
408 JsCallbackHandler::Traverse(entry->vecCopy, { 1, getKeyEventProperty }, isConsumed);
409 auto consumer = entry->keyEvenetConsumer;
410 if (consumer != nullptr) {
411 IMSA_HILOGE("consumer result: %{public}d!", isConsumed);
412 consumer->OnKeyEventConsumeResult(isConsumed);
413 }
414 FinishAsync("OnFullKeyEvent", static_cast<int32_t>(TraceTaskId::ON_FULL_KEY_EVENT));
415 };
416 eventHandler->PostTask(task, type);
417 return true;
418 }
419
OnKeyEvent(int32_t keyCode,int32_t keyStatus,sptr<KeyEventConsumerProxy> & consumer)420 bool JsKeyboardDelegateSetting::OnKeyEvent(int32_t keyCode, int32_t keyStatus, sptr<KeyEventConsumerProxy> &consumer)
421 {
422 KeyEventPara para{ keyCode, keyStatus, false };
423 std::string type = (keyStatus == ARGC_TWO ? "keyDown" : "keyUp");
424 auto entry = GetEntry(type, [¶, &consumer](UvEntry &entry) {
425 entry.keyEventPara = { para.keyCode, para.keyStatus, para.isOnKeyEvent };
426 entry.keyEvenetConsumer = consumer;
427 });
428 if (entry == nullptr) {
429 return false;
430 }
431 auto eventHandler = GetEventHandler();
432 if (eventHandler == nullptr) {
433 IMSA_HILOGE("eventHandler is nullptr!");
434 return false;
435 }
436
437 IMSA_HILOGI("run in.");
438 StartAsync("OnKeyEvent", static_cast<int32_t>(TraceTaskId::ON_KEY_EVENT));
439 auto task = [entry]() {
440 InputMethodSyncTrace tracer("OnkeyEvent UV_QUEUE_WORK");
441 auto getKeyEventProperty = [entry](napi_env env, napi_value *args, uint8_t argc) -> bool {
442 InputMethodSyncTrace tracer("Create parameter");
443 if (argc == 0) {
444 return false;
445 }
446 napi_value jsObject = GetResultOnKeyEvent(env, entry->keyEventPara.keyCode, entry->keyEventPara.keyStatus);
447 if (jsObject == nullptr) {
448 IMSA_HILOGE("jsObject is nullptr!");
449 return false;
450 }
451 // 0 means the first param of callback.
452 args[0] = jsObject;
453 return true;
454 };
455 bool isConsumed = false;
456 // 1 means callback has one param.
457 JsCallbackHandler::Traverse(entry->vecCopy, { 1, getKeyEventProperty }, isConsumed);
458 auto consumer = entry->keyEvenetConsumer;
459 if (consumer != nullptr) {
460 IMSA_HILOGE("consumer result: %{public}d", isConsumed);
461 consumer->OnKeyCodeConsumeResult(isConsumed);
462 }
463 FinishAsync("OnKeyEvent", static_cast<int32_t>(TraceTaskId::ON_KEY_EVENT));
464 };
465 eventHandler->PostTask(task, type);
466 return true;
467 }
468
OnCursorUpdate(int32_t positionX,int32_t positionY,int32_t height)469 void JsKeyboardDelegateSetting::OnCursorUpdate(int32_t positionX, int32_t positionY, int32_t height)
470 {
471 CursorPara para{ positionX, positionY, height };
472 std::string type = "cursorContextChange";
473 auto entry = GetEntry(type, [¶](UvEntry &entry) {
474 entry.curPara.positionX = para.positionX;
475 entry.curPara.positionY = para.positionY;
476 entry.curPara.height = para.height;
477 });
478 if (entry == nullptr) {
479 return;
480 }
481 auto eventHandler = GetEventHandler();
482 if (eventHandler == nullptr) {
483 IMSA_HILOGE("eventHandler is nullptr!");
484 return;
485 }
486 IMSA_HILOGD("the cursor for x: %{public}d, y: %{public}d, height: %{public}d.", positionX, positionY,
487 height);
488 auto task = [entry]() {
489 auto paramGetter = [&entry](napi_env env, napi_value *args, uint8_t argc) -> bool {
490 if (argc < 3) {
491 return false;
492 }
493 // 0 means the first param of callback.
494 napi_create_int32(env, entry->curPara.positionX, &args[0]);
495 // 1 means the second param of callback.
496 napi_create_int32(env, entry->curPara.positionY, &args[1]);
497 // 2 means the third param of callback.
498 napi_create_int32(env, entry->curPara.height, &args[2]);
499 return true;
500 };
501 // 3 means callback has three params.
502 JsCallbackHandler::Traverse(entry->vecCopy, { 3, paramGetter });
503 };
504 handler_->PostTask(task, type);
505 }
506
OnSelectionChange(int32_t oldBegin,int32_t oldEnd,int32_t newBegin,int32_t newEnd)507 void JsKeyboardDelegateSetting::OnSelectionChange(int32_t oldBegin, int32_t oldEnd, int32_t newBegin, int32_t newEnd)
508 {
509 SelectionPara para{ oldBegin, oldEnd, newBegin, newEnd };
510 std::string type = "selectionChange";
511 auto entry = GetEntry(type, [¶](UvEntry &entry) {
512 entry.selPara.oldBegin = para.oldBegin;
513 entry.selPara.oldEnd = para.oldEnd;
514 entry.selPara.newBegin = para.newBegin;
515 entry.selPara.newEnd = para.newEnd;
516 });
517 if (entry == nullptr) {
518 return;
519 }
520 auto eventHandler = GetEventHandler();
521 if (eventHandler == nullptr) {
522 IMSA_HILOGE("eventHandler is nullptr!");
523 return;
524 }
525 IMSA_HILOGD("the selection for oldBegin: %{public}d, oldEnd: %{public}d, newBegin: %{public}d, newEnd: "
526 "%{public}d.", oldBegin, oldEnd, newBegin, newEnd);
527 auto task = [entry]() {
528 auto paramGetter = [entry](napi_env env, napi_value *args, uint8_t argc) -> bool {
529 if (argc < 4) {
530 return false;
531 }
532 // 0 means the first param of callback.
533 napi_create_int32(env, entry->selPara.oldBegin, &args[0]);
534 // 1 means the second param of callback.
535 napi_create_int32(env, entry->selPara.oldEnd, &args[1]);
536 // 2 means the third param of callback.
537 napi_create_int32(env, entry->selPara.newBegin, &args[2]);
538 // 3 means the fourth param of callback.
539 napi_create_int32(env, entry->selPara.newEnd, &args[3]);
540 return true;
541 };
542 // 4 means callback has four params.
543 JsCallbackHandler::Traverse(entry->vecCopy, { 4, paramGetter });
544 };
545 eventHandler->PostTask(task, type);
546 }
547
OnTextChange(const std::string & text)548 void JsKeyboardDelegateSetting::OnTextChange(const std::string &text)
549 {
550 std::string type = "textChange";
551 auto entry = GetEntry(type, [&text](UvEntry &entry) { entry.text = text; });
552 if (entry == nullptr) {
553 IMSA_HILOGE("failed to get uv entry!");
554 return;
555 }
556 auto eventHandler = GetEventHandler();
557 if (eventHandler == nullptr) {
558 IMSA_HILOGE("eventHandler is nullptr!");
559 return;
560 }
561 IMSA_HILOGD("run in.");
562
563 auto task = [entry]() {
564 auto getTextChangeProperty = [entry](napi_env env, napi_value *args, uint8_t argc) -> bool {
565 if (argc == 0) {
566 return false;
567 }
568 // 0 means the first param of callback.
569 napi_create_string_utf8(env, entry->text.c_str(), NAPI_AUTO_LENGTH, &args[0]);
570 return true;
571 };
572 // 1 means callback has one param.
573 JsCallbackHandler::Traverse(entry->vecCopy, { 1, getTextChangeProperty });
574 };
575 eventHandler->PostTask(task, type);
576 }
577
OnEditorAttributeChange(const InputAttribute & inputAttribute)578 void JsKeyboardDelegateSetting::OnEditorAttributeChange(const InputAttribute &inputAttribute)
579 {
580 std::string type = "editorAttributeChanged";
581 auto entry = GetEntry(type, [&inputAttribute](UvEntry &entry) { entry.inputAttribute = inputAttribute; });
582 if (entry == nullptr) {
583 return;
584 }
585 auto eventHandler = GetEventHandler();
586 if (eventHandler == nullptr) {
587 IMSA_HILOGE("eventHandler is nullptr!");
588 return;
589 }
590 IMSA_HILOGD("enterKeyType: %{public}d, inputPattern: %{public}d, previewSupport: %{public}d",
591 inputAttribute.enterKeyType, inputAttribute.inputPattern, inputAttribute.isTextPreviewSupported);
592 auto task = [entry]() {
593 auto paramGetter = [entry](napi_env env, napi_value *args, uint8_t argc) -> bool {
594 if (argc == 0) {
595 return false;
596 }
597 napi_value jsObject = JsInputAttribute::Write(env, entry->inputAttribute);
598 if (jsObject == JsUtil::Const::Null(env)) {
599 IMSA_HILOGE("jsObject is nullptr!");
600 return false;
601 }
602 // 0 means the first param of callback.
603 args[0] = jsObject;
604 return true;
605 };
606 // 1 means callback has one param.
607 JsCallbackHandler::Traverse(entry->vecCopy, { 1, paramGetter });
608 };
609 eventHandler->PostTask(task, type);
610 }
611
GetUVwork(const std::string & type,EntrySetter entrySetter)612 uv_work_t *JsKeyboardDelegateSetting::GetUVwork(const std::string &type, EntrySetter entrySetter)
613 {
614 IMSA_HILOGD("start, type: %{public}s", type.c_str());
615 UvEntry *entry = nullptr;
616 {
617 std::lock_guard<std::recursive_mutex> lock(mutex_);
618
619 if (jsCbMap_[type].empty()) {
620 IMSA_HILOGD("%{public}s cb-vector is empty.", type.c_str());
621 return nullptr;
622 }
623 entry = new (std::nothrow) UvEntry(jsCbMap_[type], type);
624 if (entry == nullptr) {
625 IMSA_HILOGE("entry is nullptr!");
626 return nullptr;
627 }
628 if (entrySetter != nullptr) {
629 entrySetter(*entry);
630 }
631 }
632 uv_work_t *work = new (std::nothrow) uv_work_t;
633 if (work == nullptr) {
634 IMSA_HILOGE("work is nullptr!");
635 delete entry;
636 return nullptr;
637 }
638 work->data = entry;
639 return work;
640 }
641
GetEventHandler()642 std::shared_ptr<AppExecFwk::EventHandler> JsKeyboardDelegateSetting::GetEventHandler()
643 {
644 std::lock_guard<std::mutex> lock(eventHandlerMutex_);
645 return handler_;
646 }
647
GetEntry(const std::string & type,EntrySetter entrySetter)648 std::shared_ptr<JsKeyboardDelegateSetting::UvEntry> JsKeyboardDelegateSetting::GetEntry(
649 const std::string &type, EntrySetter entrySetter)
650 {
651 IMSA_HILOGD("start, type: %{public}s", type.c_str());
652 std::shared_ptr<UvEntry> entry = nullptr;
653 {
654 std::lock_guard<std::recursive_mutex> lock(mutex_);
655 if (jsCbMap_[type].empty()) {
656 IMSA_HILOGD("%{public}s cb-vector is empty.", type.c_str());
657 return nullptr;
658 }
659 entry = std::make_shared<UvEntry>(jsCbMap_[type], type);
660 }
661 if (entrySetter != nullptr) {
662 entrySetter(*entry);
663 }
664 return entry;
665 }
666 } // namespace MiscServices
667 } // namespace OHOS