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