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