• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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