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