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, ©Value);
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