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