1 /*
2 * Copyright (c) 2021-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_input_device_context.h"
17 #include "mmi_log.h"
18 #include "napi_constants.h"
19 #include "util_napi_error.h"
20
21 namespace OHOS {
22 namespace MMI {
23 namespace {
24 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, MMI_LOG_DOMAIN, "JsInputDeviceContext" };
25
26 enum KeyboardType {
27 NONE = 0,
28 UNKNOWN = 1,
29 ALPHABETIC_KEYBOARD = 2,
30 DIGITAL_KEYBOARD = 3,
31 HANDWRITING_PEN = 4,
32 REMOTE_CONTROL = 5,
33 };
34 } // namespace
35
JsInputDeviceContext()36 JsInputDeviceContext::JsInputDeviceContext()
37 {
38 mgr_ = std::make_shared<JsInputDeviceManager>();
39 }
40
~JsInputDeviceContext()41 JsInputDeviceContext::~JsInputDeviceContext()
42 {
43 std::lock_guard<std::mutex> guard(mtx_);
44 auto jsInputDeviceMgr = mgr_;
45 mgr_.reset();
46 if (jsInputDeviceMgr) {
47 jsInputDeviceMgr->ResetEnv();
48 }
49 }
50
CreateInstance(napi_env env)51 napi_value JsInputDeviceContext::CreateInstance(napi_env env)
52 {
53 CALL_DEBUG_ENTER;
54 napi_value global = nullptr;
55 CHKRP(env, napi_get_global(env, &global), GET_GLOBAL);
56
57 constexpr char className[] = "JsInputDeviceContext";
58 napi_value jsClass = nullptr;
59 napi_property_descriptor desc[] = {};
60 napi_status status = napi_define_class(env, className, sizeof(className), JsInputDeviceContext::JsConstructor,
61 nullptr, sizeof(desc) / sizeof(desc[0]), nullptr, &jsClass);
62 CHKRP(env, status, DEFINE_CLASS);
63
64 status = napi_set_named_property(env, global, "multimodalinput_input_device_class", jsClass);
65 CHKRP(env, status, SET_NAMED_PROPERTY);
66
67 napi_value jsInstance = nullptr;
68 CHKRP(env, napi_new_instance(env, jsClass, 0, nullptr, &jsInstance), NEW_INSTANCE);
69 CHKRP(env, napi_set_named_property(env, global, "multimodal_input_device", jsInstance), SET_NAMED_PROPERTY);
70
71 JsInputDeviceContext *jsContext = nullptr;
72 CHKRP(env, napi_unwrap(env, jsInstance, (void**)&jsContext), UNWRAP);
73 CHKPP(jsContext);
74 CHKRP(env, napi_create_reference(env, jsInstance, 1, &(jsContext->contextRef_)), CREATE_REFERENCE);
75
76 uint32_t refCount = 0;
77 CHKRP(env, napi_reference_ref(env, jsContext->contextRef_, &refCount), REFERENCE_REF);
78 return jsInstance;
79 }
80
JsConstructor(napi_env env,napi_callback_info info)81 napi_value JsInputDeviceContext::JsConstructor(napi_env env, napi_callback_info info)
82 {
83 CALL_DEBUG_ENTER;
84 napi_value thisVar = nullptr;
85 void *data = nullptr;
86 CHKRP(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, &data), GET_CB_INFO);
87
88 JsInputDeviceContext *jsContext = new (std::nothrow) JsInputDeviceContext();
89 CHKPP(jsContext);
90 napi_status status = napi_wrap(env, thisVar, jsContext, [](napi_env env, void* data, void* hin) {
91 MMI_HILOGI("jsvm ends");
92 JsInputDeviceContext *context = static_cast<JsInputDeviceContext*>(data);
93 delete context;
94 }, nullptr, nullptr);
95 if (status != napi_ok) {
96 delete jsContext;
97 MMI_HILOGE("Failed to wrap native instance");
98 return nullptr;
99 }
100 return thisVar;
101 }
102
GetInstance(napi_env env)103 JsInputDeviceContext* JsInputDeviceContext::GetInstance(napi_env env)
104 {
105 CALL_DEBUG_ENTER;
106 napi_value global = nullptr;
107 CHKRP(env, napi_get_global(env, &global), GET_GLOBAL);
108
109 bool result = false;
110 CHKRP(env, napi_has_named_property(env, global, "multimodal_input_device", &result), HAS_NAMED_PROPERTY);
111 if (!result) {
112 MMI_HILOGE("multimodal_input_device was not found");
113 return nullptr;
114 }
115
116 napi_value object = nullptr;
117 CHKRP(env, napi_get_named_property(env, global, "multimodal_input_device", &object), GET_NAMED_PROPERTY);
118 if (object == nullptr) {
119 MMI_HILOGE("object is nullptr");
120 return nullptr;
121 }
122
123 JsInputDeviceContext *instance = nullptr;
124 CHKRP(env, napi_unwrap(env, object, (void**)&instance), UNWRAP);
125 if (instance == nullptr) {
126 MMI_HILOGE("instance is nullptr");
127 return nullptr;
128 }
129 return instance;
130 }
131
GetJsInputDeviceMgr() const132 std::shared_ptr<JsInputDeviceManager> JsInputDeviceContext::GetJsInputDeviceMgr() const
133 {
134 return mgr_;
135 }
136
On(napi_env env,napi_callback_info info)137 napi_value JsInputDeviceContext::On(napi_env env, napi_callback_info info)
138 {
139 CALL_DEBUG_ENTER;
140 size_t argc = 2;
141 napi_value argv[2];
142 CHKRP(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr), GET_CB_INFO);
143 if (argc == 0) {
144 MMI_HILOGE("Require two parameters");
145 THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "Parameter count error");
146 return nullptr;
147 }
148 if (!JsUtil::TypeOf(env, argv[0], napi_string)) {
149 MMI_HILOGE("First parameter type error");
150 THROWERR_API9(env, COMMON_PARAMETER_ERROR, "type", "string");
151 return nullptr;
152 }
153
154 char eventType[MAX_STRING_LEN] = {0};
155 size_t ret = 0;
156 CHKRP(env, napi_get_value_string_utf8(env, argv[0], eventType, MAX_STRING_LEN - 1, &ret), GET_STRING_UTF8);
157 std::string type = eventType;
158 if (type != CHANGED_TYPE) {
159 MMI_HILOGE("Type is not change");
160 THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "type must be change");
161 return nullptr;
162 }
163 if (!JsUtil::TypeOf(env, argv[1], napi_function)) {
164 MMI_HILOGE("Second parameter type error");
165 THROWERR_API9(env, COMMON_PARAMETER_ERROR, "listener", "function");
166 return nullptr;
167 }
168
169 JsInputDeviceContext *jsIds = JsInputDeviceContext::GetInstance(env);
170 CHKPP(jsIds);
171 auto jsInputDeviceMgr = jsIds->GetJsInputDeviceMgr();
172 jsInputDeviceMgr->RegisterDevListener(env, type, argv[1]);
173 return nullptr;
174 }
175
Off(napi_env env,napi_callback_info info)176 napi_value JsInputDeviceContext::Off(napi_env env, napi_callback_info info)
177 {
178 CALL_DEBUG_ENTER;
179 size_t argc = 2;
180 napi_value argv[2];
181 CHKRP(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr), GET_CB_INFO);
182 if (argc == 0) {
183 MMI_HILOGE("Require two parameters");
184 THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "Parameter count error");
185 return nullptr;
186 }
187 if (!JsUtil::TypeOf(env, argv[0], napi_string)) {
188 MMI_HILOGE("First parameter type error");
189 THROWERR_API9(env, COMMON_PARAMETER_ERROR, "type", "string");
190 return nullptr;
191 }
192
193 char eventType[MAX_STRING_LEN] = {0};
194 size_t ret = 0;
195 CHKRP(env, napi_get_value_string_utf8(env, argv[0], eventType, MAX_STRING_LEN - 1, &ret), GET_STRING_UTF8);
196 std::string type = eventType;
197 if (type != CHANGED_TYPE) {
198 MMI_HILOGE("Type is not change");
199 THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "type must be change");
200 return nullptr;
201 }
202
203 JsInputDeviceContext *jsIds = JsInputDeviceContext::GetInstance(env);
204 CHKPP(jsIds);
205 auto jsInputDeviceMgr = jsIds->GetJsInputDeviceMgr();
206 if (argc == 1) {
207 jsInputDeviceMgr->UnregisterDevListener(env, type);
208 return nullptr;
209 }
210 if (!JsUtil::TypeOf(env, argv[1], napi_function)) {
211 MMI_HILOGE("Second parameter type error");
212 THROWERR_API9(env, COMMON_PARAMETER_ERROR, "listener", "function");
213 return nullptr;
214 }
215 jsInputDeviceMgr->UnregisterDevListener(env, type, argv[1]);
216 return nullptr;
217 }
218
GetDeviceIds(napi_env env,napi_callback_info info)219 napi_value JsInputDeviceContext::GetDeviceIds(napi_env env, napi_callback_info info)
220 {
221 CALL_DEBUG_ENTER;
222 size_t argc = 1;
223 napi_value argv[1];
224 CHKRP(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr), GET_CB_INFO);
225 if (argc > 1) {
226 THROWERR(env, "too many parameters");
227 return nullptr;
228 }
229
230 JsInputDeviceContext *jsIds = JsInputDeviceContext::GetInstance(env);
231 CHKPP(jsIds);
232 auto jsInputDeviceMgr = jsIds->GetJsInputDeviceMgr();
233 if (argc == 0) {
234 return jsInputDeviceMgr->GetDeviceIds(env);
235 }
236 if (!JsUtil::TypeOf(env, argv[0], napi_function)) {
237 THROWERR(env, "The first parameter type is wrong");
238 return nullptr;
239 }
240 return jsInputDeviceMgr->GetDeviceIds(env, argv[0]);
241 }
242
GetDevice(napi_env env,napi_callback_info info)243 napi_value JsInputDeviceContext::GetDevice(napi_env env, napi_callback_info info)
244 {
245 CALL_DEBUG_ENTER;
246 size_t argc = 2;
247 napi_value argv[2];
248 CHKRP(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr), GET_CB_INFO);
249 if (argc < 1 || argc > 2) {
250 THROWERR(env, "the number of parameters is not as expected");
251 return nullptr;
252 }
253 if (!JsUtil::TypeOf(env, argv[0], napi_number)) {
254 THROWERR(env, "The first parameter type is wrong");
255 return nullptr;
256 }
257 int32_t id = 0;
258 CHKRP(env, napi_get_value_int32(env, argv[0], &id), GET_INT32);
259 JsInputDeviceContext *jsDev = JsInputDeviceContext::GetInstance(env);
260 CHKPP(jsDev);
261 auto jsInputDeviceMgr = jsDev->GetJsInputDeviceMgr();
262 if (argc == 1) {
263 return jsInputDeviceMgr->GetDevice(env, id);
264 }
265 if (!JsUtil::TypeOf(env, argv[1], napi_function)) {
266 THROWERR(env, "The second parameter type is wrong");
267 return nullptr;
268 }
269 return jsInputDeviceMgr->GetDevice(env, id, argv[1]);
270 }
271
SupportKeys(napi_env env,napi_callback_info info)272 napi_value JsInputDeviceContext::SupportKeys(napi_env env, napi_callback_info info)
273 {
274 CALL_DEBUG_ENTER;
275 size_t argc = 3;
276 napi_value argv[3];
277 CHKRP(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr), GET_CB_INFO);
278 if (argc < 2) {
279 MMI_HILOGE("Require three parameters");
280 THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "Parameter count error");
281 return nullptr;
282 }
283
284 if (!JsUtil::TypeOf(env, argv[0], napi_number)) {
285 MMI_HILOGE("First parameter type error");
286 THROWERR_API9(env, COMMON_PARAMETER_ERROR, "deviceId", "number");
287 return nullptr;
288 }
289 int32_t deviceId = 0;
290 CHKRP(env, napi_get_value_int32(env, argv[0], &deviceId), GET_INT32);
291
292 if (!JsUtil::TypeOf(env, argv[1], napi_object)) {
293 MMI_HILOGE("Second parameter type error");
294 THROWERR_API9(env, COMMON_PARAMETER_ERROR, "keys", "array");
295 return nullptr;
296 }
297 uint32_t size = 0;
298 CHKRP(env, napi_get_array_length(env, argv[1], &size), GET_ARRAY_LENGTH);
299 static constexpr uint32_t minSupportKeys = 1;
300 static constexpr uint32_t maxSupportKeys = 5;
301 if (size < minSupportKeys || size > maxSupportKeys) {
302 MMI_HILOGE("Size range error");
303 THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "size range error");
304 return nullptr;
305 }
306
307 int32_t data = 0;
308 std::vector<int32_t> keyCodes;
309 for (uint32_t i = 0; i < size; ++i) {
310 napi_value keyValue = nullptr;
311 CHKRP(env, napi_get_element(env, argv[1], i, &keyValue), GET_ELEMENT);
312 if (!JsUtil::TypeOf(env, keyValue, napi_number)) {
313 MMI_HILOGE("Second parameter type error");
314 THROWERR_API9(env, COMMON_PARAMETER_ERROR, "KeyCode", "number");
315 return nullptr;
316 }
317 CHKRP(env, napi_get_value_int32(env, keyValue, &data), GET_INT32);
318 keyCodes.push_back(data);
319 }
320
321 JsInputDeviceContext *jsContext = JsInputDeviceContext::GetInstance(env);
322 auto jsInputDeviceMgr = jsContext->GetJsInputDeviceMgr();
323 if (argc == 2) {
324 return jsInputDeviceMgr->SupportKeys(env, deviceId, keyCodes);
325 }
326 if (!JsUtil::TypeOf(env, argv[2], napi_function)) {
327 MMI_HILOGE("Third parameter type error");
328 THROWERR_API9(env, COMMON_PARAMETER_ERROR, "callback", "function");
329 return nullptr;
330 }
331 return jsInputDeviceMgr->SupportKeys(env, deviceId, keyCodes, argv[2]);
332 }
333
GetKeyboardType(napi_env env,napi_callback_info info)334 napi_value JsInputDeviceContext::GetKeyboardType(napi_env env, napi_callback_info info)
335 {
336 CALL_DEBUG_ENTER;
337 size_t argc = 2;
338 napi_value argv[2];
339 CHKRP(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr), GET_CB_INFO);
340 if (argc == 0) {
341 MMI_HILOGE("Require two parameters");
342 THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "Parameter count error");
343 return nullptr;
344 }
345
346 if (!JsUtil::TypeOf(env, argv[0], napi_number)) {
347 MMI_HILOGE("First parameter type error");
348 THROWERR_API9(env, COMMON_PARAMETER_ERROR, "deviceId", "number");
349 return nullptr;
350 }
351 int32_t id = 0;
352 CHKRP(env, napi_get_value_int32(env, argv[0], &id), GET_INT32);
353
354 JsInputDeviceContext *jsDev = JsInputDeviceContext::GetInstance(env);
355 CHKPP(jsDev);
356 auto jsInputDeviceMgr = jsDev->GetJsInputDeviceMgr();
357 CHKPP(jsInputDeviceMgr);
358 if (argc == 1) {
359 return jsInputDeviceMgr->GetKeyboardType(env, id);
360 }
361 if (!JsUtil::TypeOf(env, argv[1], napi_function)) {
362 MMI_HILOGE("Second parameter type error");
363 THROWERR_API9(env, COMMON_PARAMETER_ERROR, "callback", "function");
364 return nullptr;
365 }
366 return jsInputDeviceMgr->GetKeyboardType(env, id, argv[1]);
367 }
368
GetDeviceList(napi_env env,napi_callback_info info)369 napi_value JsInputDeviceContext::GetDeviceList(napi_env env, napi_callback_info info)
370 {
371 CALL_DEBUG_ENTER;
372 size_t argc = 1;
373 napi_value argv[1];
374 CHKRP(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr), GET_CB_INFO);
375
376 JsInputDeviceContext *jsIds = JsInputDeviceContext::GetInstance(env);
377 CHKPP(jsIds);
378 auto jsInputDeviceMgr = jsIds->GetJsInputDeviceMgr();
379 if (argc == 0) {
380 return jsInputDeviceMgr->GetDeviceList(env);
381 }
382 if (!JsUtil::TypeOf(env, argv[0], napi_function)) {
383 MMI_HILOGE("First parameter type error");
384 THROWERR_API9(env, COMMON_PARAMETER_ERROR, "callback", "function");
385 return nullptr;
386 }
387 return jsInputDeviceMgr->GetDeviceList(env, argv[0]);
388 }
389
GetDeviceInfo(napi_env env,napi_callback_info info)390 napi_value JsInputDeviceContext::GetDeviceInfo(napi_env env, napi_callback_info info)
391 {
392 CALL_DEBUG_ENTER;
393 size_t argc = 2;
394 napi_value argv[2];
395 CHKRP(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr), GET_CB_INFO);
396 if (argc == 0) {
397 MMI_HILOGE("Require two parameters");
398 THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "Parameter count error");
399 return nullptr;
400 }
401 if (!JsUtil::TypeOf(env, argv[0], napi_number)) {
402 MMI_HILOGE("First parameter type error");
403 THROWERR_API9(env, COMMON_PARAMETER_ERROR, "deviceId", "number");
404 return nullptr;
405 }
406 int32_t id = 0;
407 CHKRP(env, napi_get_value_int32(env, argv[0], &id), GET_INT32);
408
409 JsInputDeviceContext *jsDev = JsInputDeviceContext::GetInstance(env);
410 CHKPP(jsDev);
411 auto jsInputDeviceMgr = jsDev->GetJsInputDeviceMgr();
412 if (argc == 1) {
413 return jsInputDeviceMgr->GetDeviceInfo(env, id);
414 }
415 if (!JsUtil::TypeOf(env, argv[1], napi_function)) {
416 MMI_HILOGE("Second parameter type error");
417 THROWERR_API9(env, COMMON_PARAMETER_ERROR, "callback", "function");
418 return nullptr;
419 }
420 return jsInputDeviceMgr->GetDeviceInfo(env, id, argv[1]);
421 }
422
EnumClassConstructor(napi_env env,napi_callback_info info)423 napi_value JsInputDeviceContext::EnumClassConstructor(napi_env env, napi_callback_info info)
424 {
425 CALL_DEBUG_ENTER;
426 size_t argc = 0;
427 napi_value args[1] = {0};
428 napi_value ret = nullptr;
429 void *data = nullptr;
430 CHKRP(env, napi_get_cb_info(env, info, &argc, args, &ret, &data), GET_CB_INFO);
431 return ret;
432 }
433
CreateEnumKeyboardType(napi_env env,napi_value exports)434 napi_value JsInputDeviceContext::CreateEnumKeyboardType(napi_env env, napi_value exports)
435 {
436 CALL_DEBUG_ENTER;
437 napi_value none = nullptr;
438 CHKRP(env, napi_create_int32(env, KeyboardType::NONE, &none), CREATE_INT32);
439 napi_value unknown = nullptr;
440 CHKRP(env, napi_create_int32(env, KeyboardType::UNKNOWN, &unknown), CREATE_INT32);
441 napi_value alphabeticKeyboard = nullptr;
442 CHKRP(env, napi_create_int32(env, KeyboardType::ALPHABETIC_KEYBOARD, &alphabeticKeyboard), CREATE_INT32);
443 napi_value digitalKeyboard = nullptr;
444 CHKRP(env, napi_create_int32(env, KeyboardType::DIGITAL_KEYBOARD, &digitalKeyboard), CREATE_INT32);
445 napi_value handwritingPen = nullptr;
446 CHKRP(env, napi_create_int32(env, KeyboardType::HANDWRITING_PEN, &handwritingPen), CREATE_INT32);
447 napi_value remoteControl = nullptr;
448 CHKRP(env, napi_create_int32(env, KeyboardType::REMOTE_CONTROL, &remoteControl), CREATE_INT32);
449 napi_property_descriptor desc[] = {
450 DECLARE_NAPI_STATIC_PROPERTY("NONE", none),
451 DECLARE_NAPI_STATIC_PROPERTY("UNKNOWN", unknown),
452 DECLARE_NAPI_STATIC_PROPERTY("ALPHABETIC_KEYBOARD", alphabeticKeyboard),
453 DECLARE_NAPI_STATIC_PROPERTY("DIGITAL_KEYBOARD", digitalKeyboard),
454 DECLARE_NAPI_STATIC_PROPERTY("HANDWRITING_PEN", handwritingPen),
455 DECLARE_NAPI_STATIC_PROPERTY("REMOTE_CONTROL", remoteControl),
456 };
457 napi_value result = nullptr;
458 CHKRP(env, napi_define_class(env, "KeyboardType", NAPI_AUTO_LENGTH, EnumClassConstructor, nullptr,
459 sizeof(desc) / sizeof(*desc), desc, &result), DEFINE_CLASS);
460 CHKRP(env, napi_set_named_property(env, exports, "KeyboardType", result), SET_NAMED_PROPERTY);
461 return exports;
462 }
463
Export(napi_env env,napi_value exports)464 napi_value JsInputDeviceContext::Export(napi_env env, napi_value exports)
465 {
466 CALL_DEBUG_ENTER;
467 auto instance = CreateInstance(env);
468 if (instance == nullptr) {
469 MMI_HILOGE("failed to create instance");
470 return nullptr;
471 }
472 napi_property_descriptor desc[] = {
473 DECLARE_NAPI_STATIC_FUNCTION("on", On),
474 DECLARE_NAPI_STATIC_FUNCTION("off", Off),
475 DECLARE_NAPI_STATIC_FUNCTION("getDevice", GetDevice),
476 DECLARE_NAPI_STATIC_FUNCTION("getDeviceIds", GetDeviceIds),
477 DECLARE_NAPI_STATIC_FUNCTION("supportKeys", SupportKeys),
478 DECLARE_NAPI_STATIC_FUNCTION("getKeyboardType", GetKeyboardType),
479 DECLARE_NAPI_STATIC_FUNCTION("getDeviceList", GetDeviceList),
480 DECLARE_NAPI_STATIC_FUNCTION("getDeviceInfo", GetDeviceInfo),
481 };
482 CHKRP(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc), DEFINE_PROPERTIES);
483 if (CreateEnumKeyboardType(env, exports) == nullptr) {
484 MMI_HILOGE("Failed to create keyboard type enum");
485 return nullptr;
486 }
487 return exports;
488 }
489 } // namespace MMI
490 } // namespace OHOS
491