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(env,
68 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 return thisVar;
140 };
141
CreateKeyboardDelegate(napi_env env,napi_callback_info info)142 napi_value JsKeyboardDelegateSetting::CreateKeyboardDelegate(napi_env env, napi_callback_info info)
143 {
144 return GetKDInstance(env, info);
145 }
146
GetKeyboardDelegate(napi_env env,napi_callback_info info)147 napi_value JsKeyboardDelegateSetting::GetKeyboardDelegate(napi_env env, napi_callback_info info)
148 {
149 return GetKDInstance(env, info);
150 }
151
GetKDInstance(napi_env env,napi_callback_info info)152 napi_value JsKeyboardDelegateSetting::GetKDInstance(napi_env env, napi_callback_info info)
153 {
154 napi_value instance = nullptr;
155 napi_value cons = nullptr;
156 if (napi_get_reference_value(env, KDSRef_, &cons) != napi_ok) {
157 IMSA_HILOGE("failed to get reference value!");
158 return nullptr;
159 }
160 if (napi_new_instance(env, cons, 0, nullptr, &instance) != napi_ok) {
161 IMSA_HILOGE("failed to new instance!");
162 return nullptr;
163 }
164 return instance;
165 }
166
RegisterListener(napi_value callback,std::string type,std::shared_ptr<JSCallbackObject> callbackObj)167 void JsKeyboardDelegateSetting::RegisterListener(napi_value callback, std::string type,
168 std::shared_ptr<JSCallbackObject> callbackObj)
169 {
170 IMSA_HILOGD("RegisterListener %{public}s", type.c_str());
171 std::lock_guard<std::recursive_mutex> lock(mutex_);
172 if (jsCbMap_.empty() || jsCbMap_.find(type) == jsCbMap_.end()) {
173 IMSA_HILOGD("methodName %{public}s is not registered!", type.c_str());
174 }
175 auto callbacks = jsCbMap_[type];
176 bool ret = std::any_of(callbacks.begin(), callbacks.end(), [&callback](std::shared_ptr<JSCallbackObject> cb) {
177 if (cb == nullptr) {
178 return false;
179 }
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 AppExecFwk::EventHandler::Current());
241 engine->RegisterListener(argv[ARGC_ONE], type, callback);
242
243 napi_value result = nullptr;
244 napi_get_null(env, &result);
245 return result;
246 }
247
UnSubscribe(napi_env env,napi_callback_info info)248 napi_value JsKeyboardDelegateSetting::UnSubscribe(napi_env env, napi_callback_info info)
249 {
250 size_t argc = ARGC_TWO;
251 napi_value argv[ARGC_TWO] = { nullptr };
252 napi_value thisVar = nullptr;
253 void *data = nullptr;
254 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, &data));
255 std::string type;
256 // 1 means least param num.
257 if (argc < 1 || !JsUtil::GetValue(env, argv[0], type) ||
258 !EventChecker::IsValidEventType(EventSubscribeModule::KEYBOARD_DELEGATE, type)) {
259 IMSA_HILOGE("unsubscribe failed, type: %{public}s!", type.c_str());
260 return nullptr;
261 }
262
263 // if the second param is not napi_function/napi_null/napi_undefined, return
264 auto paramType = JsUtil::GetType(env, argv[1]);
265 if (paramType != napi_function && paramType != napi_null && paramType != napi_undefined) {
266 return nullptr;
267 }
268 // if the second param is napi_function, delete it, else delete all
269 argv[1] = paramType == napi_function ? argv[1] : nullptr;
270
271 IMSA_HILOGD("unsubscribe type: %{public}s.", type.c_str());
272 auto delegate = reinterpret_cast<JsKeyboardDelegateSetting *>(JsUtils::GetNativeSelf(env, info));
273 if (delegate == nullptr) {
274 return nullptr;
275 }
276 delegate->UnRegisterListener(argv[ARGC_ONE], type);
277 napi_value result = nullptr;
278 napi_get_null(env, &result);
279 return result;
280 }
281
GetResultOnKeyEvent(napi_env env,int32_t keyCode,int32_t keyStatus)282 napi_value JsKeyboardDelegateSetting::GetResultOnKeyEvent(napi_env env, int32_t keyCode, int32_t keyStatus)
283 {
284 napi_value KeyboardDelegate = nullptr;
285 NAPI_CALL(env, napi_create_object(env, &KeyboardDelegate));
286
287 napi_value jsKeyCode = nullptr;
288 NAPI_CALL(env, napi_create_int32(env, keyCode, &jsKeyCode));
289 NAPI_CALL(env, napi_set_named_property(env, KeyboardDelegate, "keyCode", jsKeyCode));
290
291 napi_value jsKeyAction = nullptr;
292 NAPI_CALL(env, napi_create_int32(env, keyStatus, &jsKeyAction));
293 NAPI_CALL(env, napi_set_named_property(env, KeyboardDelegate, "keyAction", jsKeyAction));
294
295 return KeyboardDelegate;
296 }
297
OnDealKeyEvent(const std::shared_ptr<MMI::KeyEvent> & keyEvent,uint64_t cbId,const sptr<IRemoteObject> & channelObject)298 bool JsKeyboardDelegateSetting::OnDealKeyEvent(
299 const std::shared_ptr<MMI::KeyEvent> &keyEvent, uint64_t cbId, const sptr<IRemoteObject> &channelObject)
300 {
301 if (keyEvent == nullptr) {
302 IMSA_HILOGE("keyEvent is nullptr");
303 return false;
304 }
305 auto eventHandler = GetEventHandler();
306 if (eventHandler == nullptr) {
307 IMSA_HILOGE("eventHandler is nullptr!");
308 return false;
309 }
310 auto keyEventEntry = GetEntry("keyEvent", [keyEvent](UvEntry &entry) { entry.fullKeyEventPara = keyEvent; });
311 KeyEventPara para{ keyEvent->GetKeyCode(), keyEvent->GetKeyAction(), false };
312 std::string type = (keyEvent->GetKeyAction() == ARGC_TWO ? "keyDown" : "keyUp");
313 auto keyCodeEntry = GetEntry(type, [¶](UvEntry &entry) {
314 entry.keyEventPara = { para.keyCode, para.keyStatus, para.isOnKeyEvent };
315 });
316 if (keyEventEntry == nullptr && keyCodeEntry == nullptr) {
317 IMSA_HILOGW("key event callback is not registered.");
318 return false;
319 }
320 IMSA_HILOGD("run in.");
321 auto task = [keyEvent, keyEventEntry, keyCodeEntry, cbId, channelObject]() {
322 DealKeyEvent(keyEvent, keyEventEntry, keyCodeEntry, cbId, channelObject);
323 };
324 eventHandler->PostTask(task, "OnDealKeyEvent", 0, AppExecFwk::EventQueue::Priority::VIP);
325 return true;
326 }
327
DealKeyEvent(const std::shared_ptr<MMI::KeyEvent> & keyEvent,const std::shared_ptr<UvEntry> & keyEventEntry,const std::shared_ptr<UvEntry> & keyCodeEntry,uint64_t cbId,const sptr<IRemoteObject> & channelObject)328 void JsKeyboardDelegateSetting::DealKeyEvent(const std::shared_ptr<MMI::KeyEvent> &keyEvent,
329 const std::shared_ptr<UvEntry> &keyEventEntry, const std::shared_ptr<UvEntry> &keyCodeEntry, uint64_t cbId,
330 const sptr<IRemoteObject> &channelObject)
331 {
332 bool isKeyEventConsumed = false;
333 bool isKeyCodeConsumed = false;
334 if (keyEventEntry != nullptr) {
335 auto getKeyEventProperty = [keyEventEntry](napi_env env, napi_value *args, uint8_t argc) -> bool {
336 if (argc == 0) {
337 return false;
338 }
339 napi_value keyEventObject{};
340 auto result = napi_create_object(env, &keyEventObject);
341 CHECK_RETURN((result == napi_ok) && (keyEventObject != nullptr), "create object", false);
342 result = MMI::KeyEventNapi::CreateKeyEvent(env, keyEventEntry->fullKeyEventPara, keyEventObject);
343 CHECK_RETURN((result == napi_ok) && (keyEventObject != nullptr), "create key event object", false);
344 // 0 means the first param of callback.
345 args[0] = keyEventObject;
346 return true;
347 };
348 // 1 means callback has one param.
349 JsCallbackHandler::Traverse(keyEventEntry->vecCopy, { 1, getKeyEventProperty }, isKeyEventConsumed);
350 }
351 if (keyCodeEntry != nullptr) {
352 auto getKeyEventProperty = [keyCodeEntry](napi_env env, napi_value *args, uint8_t argc) -> bool {
353 InputMethodSyncTrace tracer("Create parameter");
354 if (argc == 0) {
355 return false;
356 }
357 napi_value jsObject =
358 GetResultOnKeyEvent(env, keyCodeEntry->keyEventPara.keyCode, keyCodeEntry->keyEventPara.keyStatus);
359 if (jsObject == nullptr) {
360 IMSA_HILOGE("jsObject is nullptr!");
361 return false;
362 }
363 // 0 means the first param of callback.
364 args[0] = jsObject;
365 return true;
366 };
367 // 1 means callback has one param.
368 JsCallbackHandler::Traverse(keyCodeEntry->vecCopy, { 1, getKeyEventProperty }, isKeyCodeConsumed);
369 }
370 bool consumeResult = isKeyEventConsumed || isKeyCodeConsumed;
371 if (!consumeResult) {
372 if (keyEvent != nullptr && keyEvent->GetKeyAction() == MMI::KeyEvent::KEY_ACTION_DOWN) {
373 IMSA_HILOGW("keyEvent is not consumed by ime");
374 }
375 consumeResult = InputMethodAbility::GetInstance().HandleUnconsumedKey(keyEvent);
376 }
377 auto ret = InputMethodAbility::GetInstance().HandleKeyEventResult(cbId, consumeResult, channelObject);
378 if (ret != ErrorCode::NO_ERROR) {
379 IMSA_HILOGE("handle keyEvent failed:%{public}d", ret);
380 }
381 }
382
OnKeyEvent(const std::shared_ptr<MMI::KeyEvent> & keyEvent,sptr<KeyEventConsumerProxy> & consumer)383 bool JsKeyboardDelegateSetting::OnKeyEvent(const std::shared_ptr<MMI::KeyEvent> &keyEvent,
384 sptr<KeyEventConsumerProxy> &consumer)
385 {
386 std::string type = "keyEvent";
387 auto entry = GetEntry(type, [keyEvent, &consumer](UvEntry &entry) {
388 entry.fullKeyEventPara = keyEvent;
389 entry.keyEvenetConsumer = consumer;
390 });
391 if (entry == nullptr) {
392 return false;
393 }
394 auto eventHandler = GetEventHandler();
395 if (eventHandler == nullptr) {
396 IMSA_HILOGE("eventHandler is nullptr!");
397 return false;
398 }
399
400 IMSA_HILOGI("run in.");
401 StartAsync("OnFullKeyEvent", static_cast<int32_t>(TraceTaskId::ON_FULL_KEY_EVENT));
402 auto task = [entry, this]() {
403 auto getKeyEventProperty = [entry](napi_env env, napi_value *args, uint8_t argc) -> bool {
404 InputMethodSyncTrace tracer("Create parameter");
405 if (argc == 0) {
406 return false;
407 }
408 napi_value keyEventObject{};
409 auto result = napi_create_object(env, &keyEventObject);
410 CHECK_RETURN((result == napi_ok) && (keyEventObject != nullptr), "create object", false);
411 result = MMI::KeyEventNapi::CreateKeyEvent(env, entry->fullKeyEventPara, keyEventObject);
412 CHECK_RETURN((result == napi_ok) && (keyEventObject != nullptr), "create key event object", false);
413 // 0 means the first param of callback.
414 args[0] = keyEventObject;
415 return true;
416 };
417 bool isConsumed = false;
418 // 1 means callback has one param.
419 JsCallbackHandler::Traverse(entry->vecCopy, { 1, getKeyEventProperty }, isConsumed);
420 auto consumer = entry->keyEvenetConsumer;
421 if (consumer != nullptr) {
422 IMSA_HILOGE("consumer result: %{public}d!", isConsumed);
423 OnKeyEventConsumeResult(isConsumed, consumer);
424 }
425 FinishAsync("OnFullKeyEvent", static_cast<int32_t>(TraceTaskId::ON_FULL_KEY_EVENT));
426 };
427 eventHandler->PostTask(task, type, 0, AppExecFwk::EventQueue::Priority::VIP);
428 return true;
429 }
430
OnKeyEvent(int32_t keyCode,int32_t keyStatus,sptr<KeyEventConsumerProxy> & consumer)431 bool JsKeyboardDelegateSetting::OnKeyEvent(int32_t keyCode, int32_t keyStatus, sptr<KeyEventConsumerProxy> &consumer)
432 {
433 KeyEventPara para{ keyCode, keyStatus, false };
434 std::string type = (keyStatus == ARGC_TWO ? "keyDown" : "keyUp");
435 auto entry = GetEntry(type, [¶, &consumer](UvEntry &entry) {
436 entry.keyEventPara = { para.keyCode, para.keyStatus, para.isOnKeyEvent };
437 entry.keyEvenetConsumer = consumer;
438 });
439 if (entry == nullptr) {
440 return false;
441 }
442 auto eventHandler = GetEventHandler();
443 if (eventHandler == nullptr) {
444 IMSA_HILOGE("eventHandler is nullptr!");
445 return false;
446 }
447
448 IMSA_HILOGI("run in.");
449 StartAsync("OnKeyEvent", static_cast<int32_t>(TraceTaskId::ON_KEY_EVENT));
450 auto task = [entry, this]() {
451 InputMethodSyncTrace tracer("OnkeyEvent UV_QUEUE_WORK");
452 auto getKeyEventProperty = [entry](napi_env env, napi_value *args, uint8_t argc) -> bool {
453 InputMethodSyncTrace tracer("Create parameter");
454 if (argc == 0) {
455 return false;
456 }
457 napi_value jsObject = GetResultOnKeyEvent(env, entry->keyEventPara.keyCode, entry->keyEventPara.keyStatus);
458 if (jsObject == nullptr) {
459 IMSA_HILOGE("jsObject is nullptr!");
460 return false;
461 }
462 // 0 means the first param of callback.
463 args[0] = jsObject;
464 return true;
465 };
466 bool isConsumed = false;
467 // 1 means callback has one param.
468 JsCallbackHandler::Traverse(entry->vecCopy, { 1, getKeyEventProperty }, isConsumed);
469 auto consumer = entry->keyEvenetConsumer;
470 if (consumer != nullptr) {
471 IMSA_HILOGE("consumer result: %{public}d!", isConsumed);
472 OnKeyCodeConsumeResult(isConsumed, consumer);
473 }
474 FinishAsync("OnKeyEvent", static_cast<int32_t>(TraceTaskId::ON_KEY_EVENT));
475 };
476 eventHandler->PostTask(task, type, 0, AppExecFwk::EventQueue::Priority::VIP);
477 return true;
478 }
479
OnKeyEventConsumeResult(bool isConsumed,sptr<KeyEventConsumerProxy> consumer)480 void JsKeyboardDelegateSetting::OnKeyEventConsumeResult(bool isConsumed, sptr<KeyEventConsumerProxy> consumer)
481 {
482 IMSA_HILOGI("result: %{public}d.", isConsumed);
483 keyEventConsume_ = true;
484 keyEventResult_ = isConsumed;
485 if (keyCodeConsume_) {
486 consumer->OnKeyEventResult(keyCodeResult_ || keyEventResult_);
487 keyEventConsume_ = false;
488 keyEventResult_ = false;
489 }
490 }
491
OnKeyCodeConsumeResult(bool isConsumed,sptr<KeyEventConsumerProxy> consumer)492 void JsKeyboardDelegateSetting::OnKeyCodeConsumeResult(bool isConsumed, sptr<KeyEventConsumerProxy> consumer)
493 {
494 IMSA_HILOGI("result: %{public}d.", isConsumed);
495 keyCodeConsume_ = true;
496 keyCodeResult_ = isConsumed;
497 if (keyEventConsume_) {
498 consumer->OnKeyEventResult(keyCodeResult_ || keyEventResult_);
499 keyCodeConsume_ = false;
500 keyCodeResult_ = false;
501 }
502 }
503
OnCursorUpdate(int32_t positionX,int32_t positionY,int32_t height)504 void JsKeyboardDelegateSetting::OnCursorUpdate(int32_t positionX, int32_t positionY, int32_t height)
505 {
506 CursorPara para{ positionX, positionY, height };
507 std::string type = "cursorContextChange";
508 auto entry = GetEntry(type, [¶](UvEntry &entry) {
509 entry.curPara.positionX = para.positionX;
510 entry.curPara.positionY = para.positionY;
511 entry.curPara.height = para.height;
512 });
513 if (entry == nullptr) {
514 return;
515 }
516 auto eventHandler = GetEventHandler();
517 if (eventHandler == nullptr) {
518 IMSA_HILOGE("eventHandler is nullptr!");
519 return;
520 }
521 IMSA_HILOGD("the cursor for x: %{public}d, y: %{public}d, height: %{public}d.", positionX, positionY,
522 height);
523 auto task = [entry]() {
524 auto paramGetter = [&entry](napi_env env, napi_value *args, uint8_t argc) -> bool {
525 if (argc < 3) {
526 return false;
527 }
528 // 0 means the first param of callback.
529 napi_create_int32(env, entry->curPara.positionX, &args[0]);
530 // 1 means the second param of callback.
531 napi_create_int32(env, entry->curPara.positionY, &args[1]);
532 // 2 means the third param of callback.
533 napi_create_int32(env, entry->curPara.height, &args[2]);
534 return true;
535 };
536 // 3 means callback has three params.
537 JsCallbackHandler::Traverse(entry->vecCopy, { 3, paramGetter });
538 };
539 eventHandler->PostTask(task, type, 0, AppExecFwk::EventQueue::Priority::VIP);
540 }
541
OnSelectionChange(int32_t oldBegin,int32_t oldEnd,int32_t newBegin,int32_t newEnd)542 void JsKeyboardDelegateSetting::OnSelectionChange(int32_t oldBegin, int32_t oldEnd, int32_t newBegin, int32_t newEnd)
543 {
544 SelectionPara para{ oldBegin, oldEnd, newBegin, newEnd };
545 std::string type = "selectionChange";
546 auto entry = GetEntry(type, [¶](UvEntry &entry) {
547 entry.selPara.oldBegin = para.oldBegin;
548 entry.selPara.oldEnd = para.oldEnd;
549 entry.selPara.newBegin = para.newBegin;
550 entry.selPara.newEnd = para.newEnd;
551 });
552 if (entry == nullptr) {
553 return;
554 }
555 auto eventHandler = GetEventHandler();
556 if (eventHandler == nullptr) {
557 IMSA_HILOGE("eventHandler is nullptr!");
558 return;
559 }
560 IMSA_HILOGD("the selection for oldBegin: %{public}d, oldEnd: %{public}d, newBegin: %{public}d, newEnd: "
561 "%{public}d.", oldBegin, oldEnd, newBegin, newEnd);
562 auto task = [entry]() {
563 auto paramGetter = [entry](napi_env env, napi_value *args, uint8_t argc) -> bool {
564 if (argc < 4) {
565 return false;
566 }
567 // 0 means the first param of callback.
568 napi_create_int32(env, entry->selPara.oldBegin, &args[0]);
569 // 1 means the second param of callback.
570 napi_create_int32(env, entry->selPara.oldEnd, &args[1]);
571 // 2 means the third param of callback.
572 napi_create_int32(env, entry->selPara.newBegin, &args[2]);
573 // 3 means the fourth param of callback.
574 napi_create_int32(env, entry->selPara.newEnd, &args[3]);
575 return true;
576 };
577 // 4 means callback has four params.
578 JsCallbackHandler::Traverse(entry->vecCopy, { 4, paramGetter });
579 };
580 eventHandler->PostTask(task, type, 0, AppExecFwk::EventQueue::Priority::VIP);
581 }
582
OnTextChange(const std::string & text)583 void JsKeyboardDelegateSetting::OnTextChange(const std::string &text)
584 {
585 std::string type = "textChange";
586 auto entry = GetEntry(type, [&text](UvEntry &entry) { entry.text = text; });
587 if (entry == nullptr) {
588 IMSA_HILOGE("failed to get uv entry!");
589 return;
590 }
591 auto eventHandler = GetEventHandler();
592 if (eventHandler == nullptr) {
593 IMSA_HILOGE("eventHandler is nullptr!");
594 return;
595 }
596 IMSA_HILOGD("run in.");
597
598 auto task = [entry]() {
599 auto getTextChangeProperty = [entry](napi_env env, napi_value *args, uint8_t argc) -> bool {
600 if (argc == 0) {
601 return false;
602 }
603 // 0 means the first param of callback.
604 napi_create_string_utf8(env, entry->text.c_str(), NAPI_AUTO_LENGTH, &args[0]);
605 return true;
606 };
607 // 1 means callback has one param.
608 JsCallbackHandler::Traverse(entry->vecCopy, { 1, getTextChangeProperty });
609 };
610 eventHandler->PostTask(task, type, 0, AppExecFwk::EventQueue::Priority::VIP);
611 }
612
OnEditorAttributeChange(const InputAttribute & inputAttribute)613 void JsKeyboardDelegateSetting::OnEditorAttributeChange(const InputAttribute &inputAttribute)
614 {
615 std::string type = "editorAttributeChanged";
616 auto entry = GetEntry(type, [&inputAttribute](UvEntry &entry) { entry.inputAttribute = inputAttribute; });
617 if (entry == nullptr) {
618 return;
619 }
620 auto eventHandler = GetEventHandler();
621 if (eventHandler == nullptr) {
622 IMSA_HILOGE("eventHandler is nullptr!");
623 return;
624 }
625 IMSA_HILOGD("enterKeyType: %{public}d, inputPattern: %{public}d, previewSupport: %{public}d",
626 inputAttribute.enterKeyType, inputAttribute.inputPattern, inputAttribute.isTextPreviewSupported);
627 auto task = [entry]() {
628 auto paramGetter = [entry](napi_env env, napi_value *args, uint8_t argc) -> bool {
629 if (argc == 0) {
630 return false;
631 }
632 napi_value jsObject = JsInputAttribute::Write(env, entry->inputAttribute);
633 if (jsObject == JsUtil::Const::Null(env)) {
634 IMSA_HILOGE("jsObject is nullptr!");
635 return false;
636 }
637 // 0 means the first param of callback.
638 args[0] = jsObject;
639 return true;
640 };
641 // 1 means callback has one param.
642 JsCallbackHandler::Traverse(entry->vecCopy, { 1, paramGetter });
643 };
644 eventHandler->PostTask(task, type, 0, AppExecFwk::EventQueue::Priority::VIP);
645 }
646
GetEventHandler()647 std::shared_ptr<AppExecFwk::EventHandler> JsKeyboardDelegateSetting::GetEventHandler()
648 {
649 std::lock_guard<std::mutex> lock(eventHandlerMutex_);
650 return handler_;
651 }
652
GetEntry(const std::string & type,EntrySetter entrySetter)653 std::shared_ptr<JsKeyboardDelegateSetting::UvEntry> JsKeyboardDelegateSetting::GetEntry(const std::string &type,
654 EntrySetter entrySetter)
655 {
656 IMSA_HILOGD("start, type: %{public}s", type.c_str());
657 std::shared_ptr<UvEntry> entry = nullptr;
658 {
659 std::lock_guard<std::recursive_mutex> lock(mutex_);
660 if (jsCbMap_[type].empty()) {
661 IMSA_HILOGD("%{public}s cb-vector is empty.", type.c_str());
662 return nullptr;
663 }
664 entry = std::make_shared<UvEntry>(jsCbMap_[type], type);
665 }
666 if (entrySetter != nullptr) {
667 entrySetter(*entry);
668 }
669 return entry;
670 }
671 } // namespace MiscServices
672 } // namespace OHOS
673