1 /*
2 * Copyright (c) 2021 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_get_input_method_setting.h"
17
18 #include "event_checker.h"
19 #include "input_client_info.h"
20 #include "input_method_controller.h"
21 #include "input_method_status.h"
22 #include "js_callback_handler.h"
23 #include "js_input_method.h"
24 #include "js_util.h"
25 #include "js_utils.h"
26 #include "napi/native_api.h"
27 #include "napi/native_node_api.h"
28 #include "string_ex.h"
29
30 namespace OHOS {
31 namespace MiscServices {
32 int32_t MAX_TYPE_NUM = 128;
33 constexpr size_t ARGC_ZERO = 0;
34 constexpr size_t ARGC_ONE = 1;
35 constexpr size_t ARGC_TWO = 2;
36 thread_local napi_ref JsGetInputMethodSetting::IMSRef_ = nullptr;
37 const std::string JsGetInputMethodSetting::IMS_CLASS_NAME = "InputMethodSetting";
38 const std::map<InputWindowStatus, std::string> PANEL_STATUS{ { InputWindowStatus::SHOW, "imeShow" },
39 { InputWindowStatus::HIDE, "imeHide" } };
40 std::mutex JsGetInputMethodSetting::msMutex_;
41 std::shared_ptr<JsGetInputMethodSetting> JsGetInputMethodSetting::inputMethod_{ nullptr };
Init(napi_env env,napi_value exports)42 napi_value JsGetInputMethodSetting::Init(napi_env env, napi_value exports)
43 {
44 napi_value maxTypeNumber = nullptr;
45 napi_create_int32(env, MAX_TYPE_NUM, &maxTypeNumber);
46
47 napi_property_descriptor descriptor[] = {
48 DECLARE_NAPI_FUNCTION("getInputMethodSetting", GetInputMethodSetting),
49 DECLARE_NAPI_FUNCTION("getSetting", GetSetting),
50 DECLARE_NAPI_PROPERTY("MAX_TYPE_NUM", maxTypeNumber),
51 };
52 NAPI_CALL(
53 env, napi_define_properties(env, exports, sizeof(descriptor) / sizeof(napi_property_descriptor), descriptor));
54
55 napi_property_descriptor properties[] = {
56 DECLARE_NAPI_FUNCTION("listInputMethod", ListInputMethod),
57 DECLARE_NAPI_FUNCTION("listInputMethodSubtype", ListInputMethodSubtype),
58 DECLARE_NAPI_FUNCTION("listCurrentInputMethodSubtype", ListCurrentInputMethodSubtype),
59 DECLARE_NAPI_FUNCTION("getInputMethods", GetInputMethods),
60 DECLARE_NAPI_FUNCTION("displayOptionalInputMethod", DisplayOptionalInputMethod),
61 DECLARE_NAPI_FUNCTION("showOptionalInputMethods", ShowOptionalInputMethods),
62 DECLARE_NAPI_FUNCTION("on", Subscribe),
63 DECLARE_NAPI_FUNCTION("off", UnSubscribe),
64 };
65 napi_value cons = nullptr;
66 NAPI_CALL(env, napi_define_class(env, IMS_CLASS_NAME.c_str(), IMS_CLASS_NAME.size(), JsConstructor, nullptr,
67 sizeof(properties) / sizeof(napi_property_descriptor), properties, &cons));
68 NAPI_CALL(env, napi_create_reference(env, cons, 1, &IMSRef_));
69 NAPI_CALL(env, napi_set_named_property(env, exports, IMS_CLASS_NAME.c_str(), cons));
70 return exports;
71 }
72
JsConstructor(napi_env env,napi_callback_info cbinfo)73 napi_value JsGetInputMethodSetting::JsConstructor(napi_env env, napi_callback_info cbinfo)
74 {
75 IMSA_HILOGI("run in JsConstructor");
76 napi_value thisVar = nullptr;
77 NAPI_CALL(env, napi_get_cb_info(env, cbinfo, nullptr, nullptr, &thisVar, nullptr));
78
79 auto delegate = GetInputMethodSettingInstance();
80 if (delegate == nullptr) {
81 IMSA_HILOGE("settingObject is nullptr");
82 napi_value result = nullptr;
83 napi_get_null(env, &result);
84 return result;
85 }
86 napi_status status = napi_wrap(
87 env, thisVar, delegate.get(), [](napi_env env, void *data, void *hint) {}, nullptr, nullptr);
88 if (status != napi_ok) {
89 IMSA_HILOGE("JsGetInputMethodSetting napi_wrap failed: %{public}d", status);
90 return nullptr;
91 }
92 if (delegate->loop_ == nullptr) {
93 napi_get_uv_event_loop(env, &delegate->loop_);
94 }
95 return thisVar;
96 }
97
GetJsConstProperty(napi_env env,uint32_t num)98 napi_value JsGetInputMethodSetting::GetJsConstProperty(napi_env env, uint32_t num)
99 {
100 napi_value jsNumber = nullptr;
101 napi_create_int32(env, num, &jsNumber);
102 return jsNumber;
103 }
104
GetInputMethodSettingInstance()105 std::shared_ptr<JsGetInputMethodSetting> JsGetInputMethodSetting::GetInputMethodSettingInstance()
106 {
107 if (inputMethod_ == nullptr) {
108 std::lock_guard<std::mutex> lock(msMutex_);
109 if (inputMethod_ == nullptr) {
110 auto engine = std::make_shared<JsGetInputMethodSetting>();
111 if (engine == nullptr) {
112 IMSA_HILOGE("input method nullptr");
113 return nullptr;
114 }
115 inputMethod_ = engine;
116 }
117 }
118 return inputMethod_;
119 }
120
GetSetting(napi_env env,napi_callback_info info)121 napi_value JsGetInputMethodSetting::GetSetting(napi_env env, napi_callback_info info)
122 {
123 return GetIMSetting(env, info, true);
124 }
125
GetInputMethodSetting(napi_env env,napi_callback_info info)126 napi_value JsGetInputMethodSetting::GetInputMethodSetting(napi_env env, napi_callback_info info)
127 {
128 return GetIMSetting(env, info, false);
129 }
130
GetIMSetting(napi_env env,napi_callback_info info,bool needThrowException)131 napi_value JsGetInputMethodSetting::GetIMSetting(napi_env env, napi_callback_info info, bool needThrowException)
132 {
133 napi_value instance = nullptr;
134 napi_value cons = nullptr;
135 if (napi_get_reference_value(env, IMSRef_, &cons) != napi_ok) {
136 IMSA_HILOGE("GetSetting::napi_get_reference_value not ok");
137 if (needThrowException) {
138 JsUtils::ThrowException(env, IMFErrorCode::EXCEPTION_SETTINGS, "", TYPE_OBJECT);
139 }
140 return nullptr;
141 }
142 if (napi_new_instance(env, cons, 0, nullptr, &instance) != napi_ok) {
143 IMSA_HILOGE("GetSetting::napi_new_instance not ok");
144 if (needThrowException) {
145 JsUtils::ThrowException(env, IMFErrorCode::EXCEPTION_SETTINGS, "", TYPE_OBJECT);
146 }
147 return nullptr;
148 }
149 return instance;
150 }
151
GetInputMethodProperty(napi_env env,napi_value argv,std::shared_ptr<ListInputContext> ctxt)152 napi_status JsGetInputMethodSetting::GetInputMethodProperty(
153 napi_env env, napi_value argv, std::shared_ptr<ListInputContext> ctxt)
154 {
155 napi_valuetype valueType = napi_undefined;
156 napi_typeof(env, argv, &valueType);
157 PARAM_CHECK_RETURN(env, valueType == napi_object, "Parameter error.", TYPE_OBJECT, napi_invalid_arg);
158 napi_value result = nullptr;
159 napi_get_named_property(env, argv, "name", &result);
160 JsUtils::GetValue(env, result, ctxt->property.name);
161
162 result = nullptr;
163 napi_get_named_property(env, argv, "id", &result);
164 JsUtils::GetValue(env, result, ctxt->property.id);
165
166 if (ctxt->property.name.empty() || ctxt->property.id.empty()) {
167 result = nullptr;
168 napi_get_named_property(env, argv, "packageName", &result);
169 JsUtils::GetValue(env, result, ctxt->property.name);
170
171 result = nullptr;
172 napi_get_named_property(env, argv, "methodId", &result);
173 JsUtils::GetValue(env, result, ctxt->property.id);
174 }
175 PARAM_CHECK_RETURN(env, (!ctxt->property.name.empty() && !ctxt->property.id.empty()), "Parameter error.",
176 TYPE_NONE, napi_invalid_arg);
177 IMSA_HILOGD("methodId:%{public}s, packageName:%{public}s", ctxt->property.id.c_str(), ctxt->property.name.c_str());
178 return napi_ok;
179 }
180
ListInputMethod(napi_env env,napi_callback_info info)181 napi_value JsGetInputMethodSetting::ListInputMethod(napi_env env, napi_callback_info info)
182 {
183 IMSA_HILOGI("run in ListInputMethod");
184 auto ctxt = std::make_shared<ListInputContext>();
185 auto input = [ctxt](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
186 ctxt->inputMethodStatus = InputMethodStatus::ALL;
187 return napi_ok;
188 };
189 auto output = [ctxt](napi_env env, napi_value *result) -> napi_status {
190 *result = JsInputMethod::GetJSInputMethodProperties(env, ctxt->properties);
191 return napi_ok;
192 };
193 auto exec = [ctxt](AsyncCall::Context *ctx) {
194 int32_t errCode = InputMethodController::GetInstance()->ListInputMethod(ctxt->properties);
195 if (errCode == ErrorCode::NO_ERROR) {
196 IMSA_HILOGI("exec ---- ListInputMethod success");
197 ctxt->status = napi_ok;
198 ctxt->SetState(ctxt->status);
199 return;
200 }
201 ctxt->SetErrorCode(errCode);
202 };
203 ctxt->SetAction(std::move(input), std::move(output));
204 // 1 means JsAPI:listInputMethod has 1 params at most.
205 AsyncCall asyncCall(env, info, ctxt, 1);
206 return asyncCall.Call(env, exec, "listInputMethod");
207 }
208
GetInputMethods(napi_env env,napi_callback_info info)209 napi_value JsGetInputMethodSetting::GetInputMethods(napi_env env, napi_callback_info info)
210 {
211 IMSA_HILOGI("run in GetInputMethods");
212 auto ctxt = std::make_shared<ListInputContext>();
213 auto input = [ctxt](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
214 PARAM_CHECK_RETURN(env, argc > 0, "should has one parameter.", TYPE_NONE, napi_invalid_arg);
215 bool enable = false;
216 napi_status status = JsUtils::GetValue(env, argv[ARGC_ZERO], enable);
217 PARAM_CHECK_RETURN(env, status == napi_ok, "enable.", TYPE_NUMBER, napi_invalid_arg);
218 ctxt->inputMethodStatus = enable ? InputMethodStatus::ENABLE : InputMethodStatus::DISABLE;
219 return napi_ok;
220 };
221 auto output = [ctxt](napi_env env, napi_value *result) -> napi_status {
222 *result = JsInputMethod::GetJSInputMethodProperties(env, ctxt->properties);
223 return napi_ok;
224 };
225 auto exec = [ctxt](AsyncCall::Context *ctx) {
226 int32_t errCode =
227 InputMethodController::GetInstance()->ListInputMethod(ctxt->inputMethodStatus == ENABLE, ctxt->properties);
228 if (errCode == ErrorCode::NO_ERROR) {
229 IMSA_HILOGI("exec ---- GetInputMethods success");
230 ctxt->status = napi_ok;
231 ctxt->SetState(ctxt->status);
232 return;
233 }
234 ctxt->SetErrorCode(errCode);
235 };
236 ctxt->SetAction(std::move(input), std::move(output));
237 // 2 means JsAPI:getInputMethods has 2 params at most.
238 AsyncCall asyncCall(env, info, ctxt, 2);
239 return asyncCall.Call(env, exec, "getInputMethods");
240 }
241
DisplayOptionalInputMethod(napi_env env,napi_callback_info info)242 napi_value JsGetInputMethodSetting::DisplayOptionalInputMethod(napi_env env, napi_callback_info info)
243 {
244 IMSA_HILOGI("JsGetInputMethodSetting run in");
245 auto ctxt = std::make_shared<DisplayOptionalInputMethodContext>();
246 auto input = [ctxt](
247 napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status { return napi_ok; };
248 auto output = [ctxt](napi_env env, napi_value *result) -> napi_status { return napi_ok; };
249 auto exec = [ctxt](AsyncCall::Context *ctx) {
250 int32_t errCode = InputMethodController::GetInstance()->DisplayOptionalInputMethod();
251 if (errCode == ErrorCode::NO_ERROR) {
252 IMSA_HILOGI("exec ---- DisplayOptionalInputMethod success");
253 ctxt->status = napi_ok;
254 ctxt->SetState(ctxt->status);
255 }
256 };
257 ctxt->SetAction(std::move(input), std::move(output));
258 // 1 means JsAPI:displayOptionalInputMethod has 1 params at most.
259 AsyncCall asyncCall(env, info, ctxt, 1);
260 return asyncCall.Call(env, exec, "displayOptionalInputMethod");
261 }
262
ShowOptionalInputMethods(napi_env env,napi_callback_info info)263 napi_value JsGetInputMethodSetting::ShowOptionalInputMethods(napi_env env, napi_callback_info info)
264 {
265 IMSA_HILOGI("JsGetInputMethodSetting run in");
266 auto ctxt = std::make_shared<DisplayOptionalInputMethodContext>();
267 auto input = [ctxt](
268 napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status { return napi_ok; };
269 auto output = [ctxt](napi_env env, napi_value *result) -> napi_status {
270 napi_status status = napi_get_boolean(env, ctxt->isDisplayed, result);
271 IMSA_HILOGI("output napi_get_boolean != nullptr[%{public}d]", result != nullptr);
272 return status;
273 };
274 auto exec = [ctxt](AsyncCall::Context *ctx) {
275 int32_t errCode = InputMethodController::GetInstance()->DisplayOptionalInputMethod();
276 if (errCode == ErrorCode::NO_ERROR) {
277 IMSA_HILOGE("exec ---- DisplayOptionalInputMethod success");
278 ctxt->status = napi_ok;
279 ctxt->SetState(ctxt->status);
280 ctxt->isDisplayed = true;
281 return;
282 } else {
283 ctxt->SetErrorCode(errCode);
284 }
285 };
286 ctxt->SetAction(std::move(input), std::move(output));
287 // 1 means JsAPI:showOptionalInputMethods has 1 params at most.
288 AsyncCall asyncCall(env, info, ctxt, 1);
289 return asyncCall.Call(env, exec, "showOptionalInputMethods");
290 }
291
ListInputMethodSubtype(napi_env env,napi_callback_info info)292 napi_value JsGetInputMethodSetting::ListInputMethodSubtype(napi_env env, napi_callback_info info)
293 {
294 IMSA_HILOGI("run in ListInputMethodSubtype");
295 auto ctxt = std::make_shared<ListInputContext>();
296 auto input = [ctxt](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
297 PARAM_CHECK_RETURN(env, argc > 0, "should has one parameter.", TYPE_NONE, napi_invalid_arg);
298 napi_valuetype valueType = napi_undefined;
299 napi_typeof(env, argv[0], &valueType);
300 PARAM_CHECK_RETURN(env, valueType == napi_object, "inputMethodProperty", TYPE_OBJECT, napi_invalid_arg);
301 napi_status status = JsGetInputMethodSetting::GetInputMethodProperty(env, argv[0], ctxt);
302 return status;
303 };
304 auto output = [ctxt](napi_env env, napi_value *result) -> napi_status {
305 *result = JsInputMethod::GetJSInputMethodSubProperties(env, ctxt->subProperties);
306 return napi_ok;
307 };
308 auto exec = [ctxt](AsyncCall::Context *ctx) {
309 int32_t errCode =
310 InputMethodController::GetInstance()->ListInputMethodSubtype(ctxt->property, ctxt->subProperties);
311 if (errCode == ErrorCode::NO_ERROR) {
312 IMSA_HILOGI("exec ---- ListInputMethodSubtype success");
313 ctxt->status = napi_ok;
314 ctxt->SetState(ctxt->status);
315 return;
316 }
317 ctxt->SetErrorCode(errCode);
318 };
319 ctxt->SetAction(std::move(input), std::move(output));
320 // 2 means JsAPI:listInputMethodSubtype has 2 params at most.
321 AsyncCall asyncCall(env, info, ctxt, 2);
322 return asyncCall.Call(env, exec, "listInputMethodSubtype");
323 }
324
ListCurrentInputMethodSubtype(napi_env env,napi_callback_info info)325 napi_value JsGetInputMethodSetting::ListCurrentInputMethodSubtype(napi_env env, napi_callback_info info)
326 {
327 IMSA_HILOGI("run in ListCurrentInputMethodSubtype");
328 auto ctxt = std::make_shared<ListInputContext>();
329 auto input = [ctxt](
330 napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status { return napi_ok; };
331 auto output = [ctxt](napi_env env, napi_value *result) -> napi_status {
332 *result = JsInputMethod::GetJSInputMethodSubProperties(env, ctxt->subProperties);
333 return napi_ok;
334 };
335 auto exec = [ctxt](AsyncCall::Context *ctx) {
336 int32_t errCode = InputMethodController::GetInstance()->ListCurrentInputMethodSubtype(ctxt->subProperties);
337 if (errCode == ErrorCode::NO_ERROR) {
338 IMSA_HILOGI("exec ---- ListCurrentInputMethodSubtype success");
339 ctxt->status = napi_ok;
340 ctxt->SetState(ctxt->status);
341 return;
342 }
343 ctxt->SetErrorCode(errCode);
344 };
345 ctxt->SetAction(std::move(input), std::move(output));
346 // 1 means JsAPI:listCurrentInputMethodSubtype has 1 params at most.
347 AsyncCall asyncCall(env, info, ctxt, 1);
348 return asyncCall.Call(env, exec, "listCurrentInputMethodSubtype");
349 }
350
RegisterListener(napi_value callback,std::string type,std::shared_ptr<JSCallbackObject> callbackObj)351 int32_t JsGetInputMethodSetting::RegisterListener(
352 napi_value callback, std::string type, std::shared_ptr<JSCallbackObject> callbackObj)
353 {
354 IMSA_HILOGD("RegisterListener %{public}s", type.c_str());
355 std::lock_guard<std::recursive_mutex> lock(mutex_);
356 if (jsCbMap_.empty()) {
357 InputMethodController::GetInstance()->SetSettingListener(inputMethod_);
358 auto ret = InputMethodController::GetInstance()->UpdateListenEventFlag(type, true);
359 if (ret != ErrorCode::NO_ERROR) {
360 IMSA_HILOGE("UpdateListenEventFlag failed, ret: %{public}d, type: %{public}s", ret, type.c_str());
361 return ret;
362 }
363 }
364 if (!jsCbMap_.empty() && jsCbMap_.find(type) == jsCbMap_.end()) {
365 IMSA_HILOGI("start type: %{public}s listening.", type.c_str());
366 auto ret = InputMethodController::GetInstance()->UpdateListenEventFlag(type, true);
367 if (ret != ErrorCode::NO_ERROR) {
368 IMSA_HILOGE("UpdateListenEventFlag failed, ret: %{public}d, type: %{public}s", ret, type.c_str());
369 return ret;
370 }
371 }
372
373 auto callbacks = jsCbMap_[type];
374 bool ret = std::any_of(callbacks.begin(), callbacks.end(), [&callback](std::shared_ptr<JSCallbackObject> cb) {
375 return JsUtils::Equals(cb->env_, callback, cb->callback_, cb->threadId_);
376 });
377 if (ret) {
378 IMSA_HILOGE("JsGetInputMethodSetting::RegisterListener callback already registered!");
379 return ErrorCode::NO_ERROR;
380 }
381
382 IMSA_HILOGI("Add %{public}s callbackObj into jsCbMap_", type.c_str());
383 jsCbMap_[type].push_back(std::move(callbackObj));
384 return ErrorCode::NO_ERROR;
385 }
386
Subscribe(napi_env env,napi_callback_info info)387 napi_value JsGetInputMethodSetting::Subscribe(napi_env env, napi_callback_info info)
388 {
389 size_t argc = ARGC_TWO;
390 napi_value argv[ARGC_TWO] = { nullptr };
391 napi_value thisVar = nullptr;
392 void *data = nullptr;
393 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, &data));
394 std::string type;
395 // 2 means least param num.
396 if (argc < 2 || !JsUtil::GetValue(env, argv[0], type)
397 || !EventChecker::IsValidEventType(EventSubscribeModule::INPUT_METHOD_SETTING, type)
398 || JsUtil::GetType(env, argv[1]) != napi_function) {
399 IMSA_HILOGE("Subscribe failed, type:%{public}s", type.c_str());
400 return nullptr;
401 }
402 IMSA_HILOGD("Subscribe type:%{public}s.", type.c_str());
403 auto engine = reinterpret_cast<JsGetInputMethodSetting *>(JsUtils::GetNativeSelf(env, info));
404 if (engine == nullptr) {
405 return nullptr;
406 }
407 std::shared_ptr<JSCallbackObject> callback =
408 std::make_shared<JSCallbackObject>(env, argv[ARGC_ONE], std::this_thread::get_id());
409 auto ret = engine->RegisterListener(argv[ARGC_ONE], type, callback);
410 auto errCode = JsUtils::Convert(ret);
411 if (errCode == EXCEPTION_SYSTEM_PERMISSION) {
412 JsUtils::ThrowException(env, errCode, "", TYPE_NONE);
413 }
414 napi_value result = nullptr;
415 napi_get_null(env, &result);
416 return result;
417 }
418
UnRegisterListener(napi_value callback,std::string type)419 void JsGetInputMethodSetting::UnRegisterListener(napi_value callback, std::string type)
420 {
421 IMSA_HILOGI("UnRegisterListener %{public}s", type.c_str());
422 std::lock_guard<std::recursive_mutex> lock(mutex_);
423 if (jsCbMap_.empty() || jsCbMap_.find(type) == jsCbMap_.end()) {
424 IMSA_HILOGE("methodName: %{public}s already unRegistered!", type.c_str());
425 return;
426 }
427
428 if (callback == nullptr) {
429 jsCbMap_.erase(type);
430 IMSA_HILOGI("stop all type: %{public}s listening.", type.c_str());
431 InputMethodController::GetInstance()->UpdateListenEventFlag(type, false);
432 return;
433 }
434
435 for (auto item = jsCbMap_[type].begin(); item != jsCbMap_[type].end(); item++) {
436 if (JsUtils::Equals((*item)->env_, callback, (*item)->callback_, (*item)->threadId_)) {
437 jsCbMap_[type].erase(item);
438 break;
439 }
440 }
441
442 if (jsCbMap_[type].empty()) {
443 IMSA_HILOGI("stop last type: %{public}s listening.", type.c_str());
444 jsCbMap_.erase(type);
445 InputMethodController::GetInstance()->UpdateListenEventFlag(type, false);
446 }
447 }
448
UnSubscribe(napi_env env,napi_callback_info info)449 napi_value JsGetInputMethodSetting::UnSubscribe(napi_env env, napi_callback_info info)
450 {
451 size_t argc = ARGC_TWO;
452 napi_value argv[ARGC_TWO] = { nullptr };
453 napi_value thisVar = nullptr;
454 void *data = nullptr;
455 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, &data));
456 std::string type;
457 // 1 means least param num.
458 if (argc < 1 || !JsUtil::GetValue(env, argv[0], type)
459 || !EventChecker::IsValidEventType(EventSubscribeModule::INPUT_METHOD_SETTING, type)) {
460 IMSA_HILOGE("UnSubscribe failed, type:%{public}s", type.c_str());
461 return nullptr;
462 }
463 // If the type of optional parameter is wrong, make it nullptr
464 if (JsUtil::GetType(env, argv[1]) != napi_function) {
465 argv[1] = nullptr;
466 }
467 IMSA_HILOGD("UnSubscribe type:%{public}s.", type.c_str());
468
469 auto engine = reinterpret_cast<JsGetInputMethodSetting *>(JsUtils::GetNativeSelf(env, info));
470 if (engine == nullptr) {
471 return nullptr;
472 }
473 engine->UnRegisterListener(argv[ARGC_ONE], type);
474 napi_value result = nullptr;
475 napi_get_null(env, &result);
476 return result;
477 }
478
OnImeChange(const Property & property,const SubProperty & subProperty)479 void JsGetInputMethodSetting::OnImeChange(const Property &property, const SubProperty &subProperty)
480 {
481 IMSA_HILOGD("run in");
482 std::string type = "imeChange";
483 uv_work_t *work = GetUVwork(type, [&property, &subProperty](UvEntry &entry) {
484 entry.property = property;
485 entry.subProperty = subProperty;
486 });
487 if (work == nullptr) {
488 IMSA_HILOGD("failed to get uv entry");
489 return;
490 }
491 uv_queue_work_with_qos(
492 loop_, work, [](uv_work_t *work) {},
493 [](uv_work_t *work, int status) {
494 std::shared_ptr<UvEntry> entry(static_cast<UvEntry *>(work->data), [work](UvEntry *data) {
495 delete data;
496 delete work;
497 });
498 if (entry == nullptr) {
499 IMSA_HILOGE("OnInputStart:: entryptr is null");
500 return;
501 }
502 auto getImeChangeProperty = [entry](napi_env env, napi_value *args, uint8_t argc) -> bool {
503 if (argc < 2) {
504 return false;
505 }
506 napi_value subProperty = JsInputMethod::GetJsInputMethodSubProperty(env, entry->subProperty);
507 napi_value property = JsInputMethod::GetJsInputMethodProperty(env, entry->property);
508 if (subProperty == nullptr || property == nullptr) {
509 IMSA_HILOGE("get KBCins or TICins failed:");
510 return false;
511 }
512 // 0 means the first param of callback.
513 args[0] = property;
514 // 1 means the second param of callback.
515 args[1] = subProperty;
516 return true;
517 };
518 // 2 means callback has two params.
519 JsCallbackHandler::Traverse(entry->vecCopy, { 2, getImeChangeProperty });
520 },
521 uv_qos_user_initiated);
522 }
523
OnPanelStatusChange(const InputWindowStatus & status,const std::vector<InputWindowInfo> & windowInfo)524 void JsGetInputMethodSetting::OnPanelStatusChange(
525 const InputWindowStatus &status, const std::vector<InputWindowInfo> &windowInfo)
526 {
527 IMSA_HILOGI("status: %{public}u", static_cast<uint32_t>(status));
528 auto it = PANEL_STATUS.find(status);
529 if (it == PANEL_STATUS.end()) {
530 return;
531 }
532 auto type = it->second;
533 uv_work_t *work = GetUVwork(type, [&windowInfo](UvEntry &entry) { entry.windowInfo = windowInfo; });
534 if (work == nullptr) {
535 IMSA_HILOGD("failed to get uv entry");
536 return;
537 }
538 uv_queue_work_with_qos(
539 loop_, work, [](uv_work_t *work) {},
540 [](uv_work_t *work, int status) {
541 std::shared_ptr<UvEntry> entry(static_cast<UvEntry *>(work->data), [work](UvEntry *data) {
542 delete data;
543 delete work;
544 });
545 if (entry == nullptr) {
546 IMSA_HILOGE("OnInputStart:: entry is nullptr");
547 return;
548 }
549 auto getWindowInfo = [entry](napi_env env, napi_value *args, uint8_t argc) -> bool {
550 if (argc < 1) {
551 return false;
552 }
553 auto windowInfo = JsUtils::GetValue(env, entry->windowInfo);
554 if (windowInfo == nullptr) {
555 IMSA_HILOGE("converse windowInfo failed");
556 return false;
557 }
558 // 0 means the first param of callback.
559 args[0] = windowInfo;
560 return true;
561 };
562 // 1 means callback has one param.
563 JsCallbackHandler::Traverse(entry->vecCopy, { 1, getWindowInfo });
564 },
565 uv_qos_user_initiated);
566 }
567
GetUVwork(const std::string & type,EntrySetter entrySetter)568 uv_work_t *JsGetInputMethodSetting::GetUVwork(const std::string &type, EntrySetter entrySetter)
569 {
570 IMSA_HILOGD("run in, type: %{public}s", type.c_str());
571 UvEntry *entry = nullptr;
572 {
573 std::lock_guard<std::recursive_mutex> lock(mutex_);
574
575 if (jsCbMap_[type].empty()) {
576 IMSA_HILOGE("%{public}s cb-vector is empty", type.c_str());
577 return nullptr;
578 }
579 entry = new (std::nothrow) UvEntry(jsCbMap_[type], type);
580 if (entry == nullptr) {
581 IMSA_HILOGE("entry ptr is nullptr!");
582 return nullptr;
583 }
584 if (entrySetter != nullptr) {
585 entrySetter(*entry);
586 }
587 }
588 uv_work_t *work = new (std::nothrow) uv_work_t;
589 if (work == nullptr) {
590 IMSA_HILOGE("entry ptr is nullptr!");
591 return nullptr;
592 }
593 work->data = entry;
594 return work;
595 }
596 } // namespace MiscServices
597 } // namespace OHOS