• 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 #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