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_register_module.h"
17
18 #include <algorithm>
19 #include <cinttypes>
20
21 #include "input_manager.h"
22 #include "js_register_util.h"
23 #include "napi_constants.h"
24 #include "util_napi.h"
25 #include "util_napi_error.h"
26
27 namespace OHOS {
28 namespace MMI {
29 namespace {
30 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, MMI_LOG_DOMAIN, "JSRegisterModule" };
31 constexpr size_t EVENT_NAME_LEN = 64;
32 constexpr size_t PRE_KEYS_SIZE = 4;
33 constexpr size_t INPUT_PARAMETER_MIDDLE = 2;
34 constexpr size_t INPUT_PARAMETER_MAX = 3;
35 } // namespace
36
37 static Callbacks callbacks = {};
38 static std::mutex sCallBacksMutex;
39
TypeOf(napi_env env,napi_value value,napi_valuetype type)40 bool JsCommon::TypeOf(napi_env env, napi_value value, napi_valuetype type)
41 {
42 napi_valuetype valueType = napi_undefined;
43 CHKRF(napi_typeof(env, value, &valueType), TYPEOF);
44 if (valueType != type) {
45 return false;
46 }
47 return true;
48 }
49
ThrowError(napi_env env,int32_t code)50 void JsCommon::ThrowError(napi_env env, int32_t code)
51 {
52 int32_t errorCode = std::abs(code);
53 if (errorCode == COMMON_USE_SYSAPI_ERROR) {
54 MMI_HILOGE("Non system applications use system API");
55 THROWERR_CUSTOM(env, COMMON_USE_SYSAPI_ERROR, "Non system applications use system API");
56 } else if (errorCode == COMMON_PERMISSION_CHECK_ERROR) {
57 MMI_HILOGE("shield api need ohos.permission.INPUT_CONTROL_DISPATCHING");
58 THROWERR_API9(env, COMMON_PERMISSION_CHECK_ERROR, "shiled API", "ohos.permission.INPUT_CONTROL_DISPATCHING");
59 } else {
60 MMI_HILOGE("dispatch control failed");
61 }
62 }
63
GetEventInfoAPI9(napi_env env,napi_callback_info info,KeyEventMonitorInfo * event,std::shared_ptr<KeyOption> keyOption)64 napi_value GetEventInfoAPI9(napi_env env, napi_callback_info info, KeyEventMonitorInfo* event,
65 std::shared_ptr<KeyOption> keyOption)
66 {
67 CALL_DEBUG_ENTER;
68 CHKPP(event);
69 CHKPP(keyOption);
70 size_t argc = 3;
71 napi_value argv[3] = { 0 };
72 CHKRP(napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr), GET_CB_INFO);
73 napi_valuetype valueType = napi_undefined;
74 if (!UtilNapi::TypeOf(env, argv[0], napi_string)) {
75 THROWERR_API9(env, COMMON_PARAMETER_ERROR, "type", "string");
76 MMI_HILOGE("The first parameter is not string");
77 return nullptr;
78 }
79 if (!UtilNapi::TypeOf(env, argv[1], napi_object)) {
80 THROWERR_API9(env, COMMON_PARAMETER_ERROR, "keyOptions", "object");
81 MMI_HILOGE("The second parameter is not napi_object");
82 return nullptr;
83 }
84 char eventType[EVENT_NAME_LEN] = { 0 };
85 size_t typeLen = 0;
86 CHKRP(napi_get_value_string_utf8(env, argv[0], eventType, EVENT_NAME_LEN - 1, &typeLen), GET_VALUE_STRING_UTF8);
87 std::string type = eventType;
88 if (type != SUBSCRIBE_TYPE) {
89 MMI_HILOGE("Type is not key");
90 THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "type must be key");
91 return nullptr;
92 }
93 napi_value receiveValue = nullptr;
94 CHKRP(napi_get_named_property(env, argv[1], "preKeys", &receiveValue), GET_NAMED_PROPERTY);
95 if (receiveValue == nullptr) {
96 THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "preKeys not found");
97 return nullptr;
98 }
99 std::set<int32_t> preKeys;
100 if (GetPreKeys(env, receiveValue, preKeys) == nullptr) {
101 MMI_HILOGE("Get preKeys failed");
102 return nullptr;
103 }
104 if (preKeys.size() > PRE_KEYS_SIZE) {
105 MMI_HILOGE("preKeys size invalid");
106 THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "preKeys size invalid");
107 return nullptr;
108 }
109 MMI_HILOGD("PreKeys size:%{public}zu", preKeys.size());
110 keyOption->SetPreKeys(preKeys);
111 std::string subKeyNames = "";
112 for (const auto &item : preKeys) {
113 subKeyNames += std::to_string(item);
114 subKeyNames += ",";
115 MMI_HILOGD("preKeys:%{public}d", item);
116 }
117 std::optional<int32_t> tempFinalKey = GetNamedPropertyInt32(env, argv[1], "finalKey");
118 if (!tempFinalKey) {
119 MMI_HILOGE("GetNamedPropertyInt32 failed");
120 return nullptr;
121 }
122 int32_t finalKey = tempFinalKey.value();
123 if (finalKey < 0) {
124 MMI_HILOGE("finalKey:%{public}d is less 0, can not process", finalKey);
125 THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "finalKey must be greater than or equal to 0");
126 return nullptr;
127 }
128 subKeyNames += std::to_string(finalKey);
129 subKeyNames += ",";
130 keyOption->SetFinalKey(finalKey);
131 MMI_HILOGD("FinalKey:%{public}d", finalKey);
132 bool isFinalKeyDown;
133 if (!GetNamedPropertyBool(env, argv[1], "isFinalKeyDown", isFinalKeyDown)) {
134 MMI_HILOGE("GetNamedPropertyBool failed");
135 return nullptr;
136 }
137 subKeyNames += std::to_string(isFinalKeyDown);
138 subKeyNames += ",";
139 keyOption->SetFinalKeyDown(isFinalKeyDown);
140 MMI_HILOGD("IsFinalKeyDown:%{public}d,map_key:%{public}s",
141 (isFinalKeyDown == true ? 1 : 0), subKeyNames.c_str());
142 std::optional<int32_t> tempKeyDownDuration = GetNamedPropertyInt32(env, argv[1], "finalKeyDownDuration");
143 if (!tempKeyDownDuration) {
144 MMI_HILOGE("GetNamedPropertyInt32 failed");
145 return nullptr;
146 }
147 int32_t finalKeyDownDuration = tempKeyDownDuration.value();
148 if (finalKeyDownDuration < 0) {
149 MMI_HILOGE("finalKeyDownDuration:%{public}d is less 0, can not process", finalKeyDownDuration);
150 THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "finalKeyDownDuration must be greater than or equal to 0");
151 return nullptr;
152 }
153 subKeyNames += std::to_string(finalKeyDownDuration);
154 keyOption->SetFinalKeyDownDuration(finalKeyDownDuration);
155 event->eventType = subKeyNames;
156 MMI_HILOGD("FinalKeyDownDuration:%{public}d", finalKeyDownDuration);
157 if (argc == INPUT_PARAMETER_MAX) {
158 CHKRP(napi_typeof(env, argv[INPUT_PARAMETER_MIDDLE], &valueType), TYPEOF);
159 if (valueType != napi_function) {
160 MMI_HILOGE("the third parameter is not napi_function");
161 THROWERR_API9(env, COMMON_PARAMETER_ERROR, "callback", "function");
162 return nullptr;
163 }
164 CHKRP(napi_create_reference(env, argv[INPUT_PARAMETER_MIDDLE], 1, &event->callback[0]), REFERENCE_REF);
165 } else {
166 event->callback[0] = nullptr;
167 }
168 napi_value ret;
169 CHKRP(napi_create_int32(env, RET_OK, &ret), CREATE_INT32);
170 return ret;
171 }
172
IsMatchKeyAction(bool isFinalKeydown,int32_t keyAction)173 static bool IsMatchKeyAction(bool isFinalKeydown, int32_t keyAction)
174 {
175 CALL_DEBUG_ENTER;
176 MMI_HILOGD("isFinalKeydown:%{public}d,keyAction:%{public}d", isFinalKeydown, keyAction);
177 if (isFinalKeydown && keyAction == KeyEvent::KEY_ACTION_DOWN) {
178 return true;
179 }
180
181 if (!isFinalKeydown && keyAction == KeyEvent::KEY_ACTION_UP) {
182 return true;
183 }
184 MMI_HILOGE("isFinalKeydown not matched with keyAction");
185 return false;
186 }
187
MatchCombinationKeys(KeyEventMonitorInfo * monitorInfo,std::shared_ptr<KeyEvent> keyEvent)188 static bool MatchCombinationKeys(KeyEventMonitorInfo* monitorInfo, std::shared_ptr<KeyEvent> keyEvent)
189 {
190 CALL_DEBUG_ENTER;
191 CHKPF(monitorInfo);
192 CHKPF(keyEvent);
193 auto keyOption = monitorInfo->keyOption;
194 CHKPF(keyOption);
195 std::vector<KeyEvent::KeyItem> items = keyEvent->GetKeyItems();
196 int32_t infoFinalKey = keyOption->GetFinalKey();
197 int32_t keyEventFinalKey = keyEvent->GetKeyCode();
198 bool isFinalKeydown = keyOption->IsFinalKeyDown();
199 MMI_HILOGD("infoFinalKey:%{public}d,keyEventFinalKey:%{public}d", infoFinalKey, keyEventFinalKey);
200 if (infoFinalKey != keyEventFinalKey || items.size() > PRE_KEYS_SIZE ||
201 !IsMatchKeyAction(isFinalKeydown, keyEvent->GetKeyAction())) {
202 MMI_HILOGD("Param invalid");
203 return false;
204 }
205 std::set<int32_t> infoPreKeys = keyOption->GetPreKeys();
206 int32_t infoSize = 0;
207 auto it = infoPreKeys.begin();
208 while (it != infoPreKeys.end()) {
209 if (*it >= 0) {
210 infoSize++;
211 }
212 ++it;
213 }
214 int32_t count = 0;
215 for (const auto &item : items) {
216 if (item.GetKeyCode() == keyEventFinalKey) {
217 continue;
218 }
219 auto iter = find(infoPreKeys.begin(), infoPreKeys.end(), item.GetKeyCode());
220 if (iter == infoPreKeys.end()) {
221 MMI_HILOGW("No keyCode in preKeys");
222 return false;
223 }
224 count++;
225 }
226 MMI_HILOGD("kevEventSize:%{public}d,infoSize:%{public}d", count, infoSize);
227 std::optional<KeyEvent::KeyItem> keyItem = keyEvent->GetKeyItem();
228 if (!keyItem) {
229 MMI_HILOGE("The keyItem is nullopt");
230 return false;
231 }
232 auto downTime = keyItem->GetDownTime();
233 auto upTime = keyEvent->GetActionTime();
234 auto curDurationTime = keyOption->GetFinalKeyDownDuration();
235 if (curDurationTime > 0 && (upTime - downTime >= (static_cast<int64_t>(curDurationTime) * 1000))) {
236 MMI_HILOGE("Skip, upTime - downTime >= duration");
237 return false;
238 }
239 return count == infoSize;
240 }
241
SubKeyEventCallback(std::shared_ptr<KeyEvent> keyEvent)242 static void SubKeyEventCallback(std::shared_ptr<KeyEvent> keyEvent)
243 {
244 CALL_DEBUG_ENTER;
245 CHKPV(keyEvent);
246 std::lock_guard guard(sCallBacksMutex);
247 auto iter = callbacks.begin();
248 while (iter != callbacks.end()) {
249 auto &list = iter->second;
250 ++iter;
251 MMI_HILOGD("list size:%{public}zu", list.size());
252 auto infoIter = list.begin();
253 while (infoIter != list.end()) {
254 auto monitorInfo = *infoIter;
255 if (MatchCombinationKeys(monitorInfo, keyEvent)) {
256 monitorInfo->keyEvent = keyEvent;
257 EmitAsyncCallbackWork(monitorInfo);
258 }
259 ++infoIter;
260 }
261 }
262 }
263
JsOn(napi_env env,napi_callback_info info)264 static napi_value JsOn(napi_env env, napi_callback_info info)
265 {
266 CALL_DEBUG_ENTER;
267 std::lock_guard guard(sCallBacksMutex);
268 size_t argc = 3;
269 napi_value argv[3] = { 0 };
270 CHKRP(napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr), GET_CB_INFO);
271 if (argc < INPUT_PARAMETER_MAX) {
272 THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "parameter number error");
273 return nullptr;
274 }
275 KeyEventMonitorInfo *event = new (std::nothrow) KeyEventMonitorInfo {
276 .env = env,
277 .asyncWork = nullptr,
278 };
279 CHKPP(event);
280 auto keyOption = std::make_shared<KeyOption>();
281 napi_valuetype valueType = napi_undefined;
282 if (napi_typeof(env, argv[0], &valueType) != napi_ok) {
283 delete event;
284 MMI_HILOGE("Napi typeof failed");
285 return nullptr;
286 }
287 if (GetEventInfoAPI9(env, info, event, keyOption) == nullptr) {
288 napi_delete_reference(env, event->callback[0]);
289 delete event;
290 MMI_HILOGE("GetEventInfo failed");
291 return nullptr;
292 }
293 event->keyOption = keyOption;
294 int32_t preSubscribeId = GetPreSubscribeId(callbacks, event);
295 if (preSubscribeId < 0) {
296 MMI_HILOGD("eventType:%{public}s,eventName:%{public}s", event->eventType.c_str(), event->name.c_str());
297 int32_t subscribeId = -1;
298 subscribeId = InputManager::GetInstance()->SubscribeKeyEvent(keyOption, SubKeyEventCallback);
299 if (subscribeId < 0) {
300 MMI_HILOGE("SubscribeId invalid:%{public}d", subscribeId);
301 napi_delete_reference(env, event->callback[0]);
302 delete event;
303 return nullptr;
304 }
305 MMI_HILOGD("SubscribeId:%{public}d", subscribeId);
306 event->subscribeId = subscribeId;
307 } else {
308 event->subscribeId = preSubscribeId;
309 }
310 if (AddEventCallback(env, callbacks, event) < 0) {
311 delete event;
312 MMI_HILOGE("AddEventCallback failed");
313 return nullptr;
314 }
315 return nullptr;
316 }
317
JsOff(napi_env env,napi_callback_info info)318 static napi_value JsOff(napi_env env, napi_callback_info info)
319 {
320 CALL_DEBUG_ENTER;
321 std::lock_guard guard(sCallBacksMutex);
322 size_t argc = 3;
323 napi_value argv[3] = { 0 };
324 CHKRP(napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr), GET_CB_INFO);
325 if (argc < INPUT_PARAMETER_MIDDLE) {
326 THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "parameter number error");
327 return nullptr;
328 }
329 KeyEventMonitorInfo *event = new (std::nothrow) KeyEventMonitorInfo {
330 .env = env,
331 .asyncWork = nullptr,
332 };
333 CHKPP(event);
334 auto keyOption = std::make_shared<KeyOption>();
335 napi_valuetype valueType = napi_undefined;
336 if (napi_typeof(env, argv[0], &valueType) != napi_ok) {
337 delete event;
338 MMI_HILOGE("Napi typeof failed");
339 return nullptr;
340 }
341 if (GetEventInfoAPI9(env, info, event, keyOption) == nullptr) {
342 napi_delete_reference(env, event->callback[0]);
343 delete event;
344 MMI_HILOGE("GetEventInfo failed");
345 return nullptr;
346 }
347 int32_t subscribeId = -1;
348 if (DelEventCallback(env, callbacks, event, subscribeId) < 0) {
349 delete event;
350 MMI_HILOGE("DelEventCallback failed");
351 return nullptr;
352 }
353 MMI_HILOGD("SubscribeId:%{public}d", subscribeId);
354 if (subscribeId >= 0) {
355 InputManager::GetInstance()->UnsubscribeKeyEvent(subscribeId);
356 }
357 if (event->callback[0] != nullptr) {
358 napi_delete_reference(env, event->callback[0]);
359 }
360 delete event;
361 return nullptr;
362 }
363
SetShieldStatus(napi_env env,napi_callback_info info)364 static napi_value SetShieldStatus(napi_env env, napi_callback_info info)
365 {
366 CALL_DEBUG_ENTER;
367 size_t argc = 2;
368 napi_value argv[2];
369 CHKRP(napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr), GET_CB_INFO);
370 if (argc < INPUT_PARAMETER_MIDDLE) {
371 MMI_HILOGE("At least two parameters is required");
372 THROWERR_API9(env, COMMON_PARAMETER_ERROR, "shieldMode", "number");
373 return nullptr;
374 }
375 if (!JsCommon::TypeOf(env, argv[0], napi_number)) {
376 MMI_HILOGE("shieldMode parameter type is invalid");
377 THROWERR_API9(env, COMMON_PARAMETER_ERROR, "shieldMode", "number");
378 return nullptr;
379 }
380 int32_t shieldMode = 0;
381 CHKRP(napi_get_value_int32(env, argv[0], &shieldMode), GET_VALUE_INT32);
382 if (shieldMode < FACTORY_MODE || shieldMode > OOBE_MODE) {
383 MMI_HILOGE("Undefined shield mode");
384 THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "Shield mode does not exist");
385 return nullptr;
386 }
387
388 if (!JsCommon::TypeOf(env, argv[1], napi_boolean)) {
389 MMI_HILOGE("isShield parameter type is invalid");
390 THROWERR_API9(env, COMMON_PARAMETER_ERROR, "isShield", "boolean");
391 return nullptr;
392 }
393 bool isShield = true;
394 CHKRP(napi_get_value_bool(env, argv[1], &isShield), GET_VALUE_BOOL);
395
396 int32_t errCode = InputManager::GetInstance()->SetShieldStatus(shieldMode, isShield);
397 JsCommon::ThrowError(env, errCode);
398 napi_value result = nullptr;
399 if (napi_get_undefined(env, &result) != napi_ok) {
400 MMI_HILOGE("Get undefined result is failed");
401 return nullptr;
402 }
403 return result;
404 }
405
GetShieldStatus(napi_env env,napi_callback_info info)406 static napi_value GetShieldStatus(napi_env env, napi_callback_info info)
407 {
408 CALL_DEBUG_ENTER;
409 size_t argc = 1;
410 napi_value argv[1];
411 CHKRP(napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr), GET_CB_INFO);
412 if (argc == 0) {
413 MMI_HILOGE("At least 1 parameter is required");
414 THROWERR_API9(env, COMMON_PARAMETER_ERROR, "shieldMode", "number");
415 return nullptr;
416 }
417 if (!JsCommon::TypeOf(env, argv[0], napi_number)) {
418 MMI_HILOGE("shieldMode parameter type is invalid");
419 THROWERR_API9(env, COMMON_PARAMETER_ERROR, "shieldMode", "number");
420 return nullptr;
421 }
422 int32_t shieldMode = 0;
423 CHKRP(napi_get_value_int32(env, argv[0], &shieldMode), GET_VALUE_INT32);
424 if (shieldMode < FACTORY_MODE || shieldMode > OOBE_MODE) {
425 MMI_HILOGE("Undefined shield mode");
426 THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "Shield mode does not exist");
427 return nullptr;
428 }
429 bool isShield { false };
430 auto errCode = InputManager::GetInstance()->GetShieldStatus(shieldMode, isShield);
431 JsCommon::ThrowError(env, errCode);
432 napi_value result = nullptr;
433 NAPI_CALL(env, napi_get_boolean(env, isShield, &result));
434 return result;
435 }
436
EnumConstructor(napi_env env,napi_callback_info info)437 static napi_value EnumConstructor(napi_env env, napi_callback_info info)
438 {
439 CALL_DEBUG_ENTER;
440 size_t argc = 0;
441 napi_value args[1] = { 0 };
442 napi_value ret = nullptr;
443 void *data = nullptr;
444 CHKRP(napi_get_cb_info(env, info, &argc, args, &ret, &data), GET_CB_INFO);
445 return ret;
446 }
447
CreateShieldMode(napi_env env,napi_value exports)448 static napi_value CreateShieldMode(napi_env env, napi_value exports)
449 {
450 CALL_DEBUG_ENTER;
451 napi_value factory_mode = nullptr;
452 CHKRP(napi_create_int32(env, SHIELD_MODE::FACTORY_MODE, &factory_mode), CREATE_INT32);
453 napi_value oobe_mode = nullptr;
454 CHKRP(napi_create_int32(env, SHIELD_MODE::OOBE_MODE, &oobe_mode), CREATE_INT32);
455
456 napi_property_descriptor desc[] = {
457 DECLARE_NAPI_STATIC_PROPERTY("FACTORY_MODE", factory_mode),
458 DECLARE_NAPI_STATIC_PROPERTY("OOBE_MODE", oobe_mode),
459 };
460 napi_value result = nullptr;
461 CHKRP(napi_define_class(env, "ShieldMode", NAPI_AUTO_LENGTH, EnumConstructor, nullptr,
462 sizeof(desc) / sizeof(*desc), desc, &result), DEFINE_CLASS);
463 CHKRP(napi_set_named_property(env, exports, "ShieldMode", result), SET_NAMED_PROPERTY);
464 return exports;
465 }
466
467 EXTERN_C_START
MmiInit(napi_env env,napi_value exports)468 static napi_value MmiInit(napi_env env, napi_value exports)
469 {
470 CALL_DEBUG_ENTER;
471 napi_property_descriptor desc[] = {
472 DECLARE_NAPI_FUNCTION("on", JsOn),
473 DECLARE_NAPI_FUNCTION("off", JsOff),
474 DECLARE_NAPI_FUNCTION("setShieldStatus", SetShieldStatus),
475 DECLARE_NAPI_FUNCTION("getShieldStatus", GetShieldStatus)
476 };
477 NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc));
478 if (CreateShieldMode(env, exports) == nullptr) {
479 THROWERR(env, "Failed to create shield mode");
480 return nullptr;
481 }
482 return exports;
483 }
484 EXTERN_C_END
485
486 static napi_module mmiModule = {
487 .nm_version = 1,
488 .nm_flags = 0,
489 .nm_filename = nullptr,
490 .nm_register_func = MmiInit,
491 .nm_modname = "multimodalInput.inputConsumer",
492 .nm_priv = ((void*)0),
493 .reserved = { 0 },
494 };
495
RegisterModule(void)496 extern "C" __attribute__((constructor)) void RegisterModule(void)
497 {
498 napi_module_register(&mmiModule);
499 }
500 } // namespace MMI
501 } // namespace OHOS
502