• 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 
GetEventInfoAPI9(napi_env env,napi_callback_info info,KeyEventMonitorInfo * event,std::shared_ptr<KeyOption> keyOption)40 napi_value GetEventInfoAPI9(napi_env env, napi_callback_info info, KeyEventMonitorInfo* event,
41     std::shared_ptr<KeyOption> keyOption)
42 {
43     CALL_DEBUG_ENTER;
44     CHKPP(event);
45     CHKPP(keyOption);
46     size_t argc = 3;
47     napi_value argv[3] = { 0 };
48     CHKRP(napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr), GET_CB_INFO);
49     napi_valuetype valueType = napi_undefined;
50     if (!UtilNapi::TypeOf(env, argv[0], napi_string)) {
51         THROWERR_API9(env, COMMON_PARAMETER_ERROR, "type", "string");
52         MMI_HILOGE("The first parameter is not string");
53         return nullptr;
54     }
55     if (!UtilNapi::TypeOf(env, argv[1], napi_object)) {
56         THROWERR_API9(env, COMMON_PARAMETER_ERROR, "keyOptions", "object");
57         MMI_HILOGE("The second parameter is not napi_object");
58         return nullptr;
59     }
60     char eventType[EVENT_NAME_LEN] = { 0 };
61     size_t typeLen = 0;
62     CHKRP(napi_get_value_string_utf8(env, argv[0], eventType, EVENT_NAME_LEN - 1, &typeLen), GET_VALUE_STRING_UTF8);
63     std::string type = eventType;
64     if (type != SUBSCRIBE_TYPE) {
65         MMI_HILOGE("Type is not key");
66         THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "type must be key");
67         return nullptr;
68     }
69     napi_value receiveValue = nullptr;
70     CHKRP(napi_get_named_property(env, argv[1], "preKeys", &receiveValue), GET_NAMED_PROPERTY);
71     if (receiveValue == nullptr) {
72         THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "preKeys not found");
73         return nullptr;
74     }
75     std::set<int32_t> preKeys;
76     if (GetPreKeys(env, receiveValue, preKeys) == nullptr) {
77         MMI_HILOGE("Get preKeys failed");
78         return nullptr;
79     }
80     if (preKeys.size() > PRE_KEYS_SIZE) {
81         MMI_HILOGE("preKeys size invalid");
82         THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "preKeys size invalid");
83         return nullptr;
84     }
85     MMI_HILOGD("PreKeys size:%{public}zu", preKeys.size());
86     keyOption->SetPreKeys(preKeys);
87     std::string subKeyNames = "";
88     for (const auto &item : preKeys) {
89         subKeyNames += std::to_string(item);
90         subKeyNames += ",";
91         MMI_HILOGD("preKeys:%{public}d", item);
92     }
93     std::optional<int32_t> tempFinalKey = GetNamedPropertyInt32(env, argv[1], "finalKey");
94     if (!tempFinalKey) {
95         MMI_HILOGE("GetNamedPropertyInt32 failed");
96         return nullptr;
97     }
98     int32_t finalKey = tempFinalKey.value();
99     if (finalKey < 0) {
100         MMI_HILOGE("finalKey:%{public}d is less 0, can not process", finalKey);
101         THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "finalKey must be greater than or equal to 0");
102         return nullptr;
103     }
104     subKeyNames += std::to_string(finalKey);
105     subKeyNames += ",";
106     keyOption->SetFinalKey(finalKey);
107     MMI_HILOGD("FinalKey:%{public}d", finalKey);
108     bool isFinalKeyDown;
109     if (!GetNamedPropertyBool(env, argv[1], "isFinalKeyDown", isFinalKeyDown)) {
110         MMI_HILOGE("GetNamedPropertyBool failed");
111         return nullptr;
112     }
113     subKeyNames += std::to_string(isFinalKeyDown);
114     subKeyNames += ",";
115     keyOption->SetFinalKeyDown(isFinalKeyDown);
116     MMI_HILOGD("IsFinalKeyDown:%{public}d,map_key:%{public}s",
117         (isFinalKeyDown == true ? 1 : 0), subKeyNames.c_str());
118     std::optional<int32_t> tempKeyDownDuration = GetNamedPropertyInt32(env, argv[1], "finalKeyDownDuration");
119     if (!tempKeyDownDuration) {
120         MMI_HILOGE("GetNamedPropertyInt32 failed");
121         return nullptr;
122     }
123     int32_t finalKeyDownDuration = tempKeyDownDuration.value();
124     if (finalKeyDownDuration < 0) {
125         MMI_HILOGE("finalKeyDownDuration:%{public}d is less 0, can not process", finalKeyDownDuration);
126         THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "finalKeyDownDuration must be greater than or equal to 0");
127         return nullptr;
128     }
129     subKeyNames += std::to_string(finalKeyDownDuration);
130     keyOption->SetFinalKeyDownDuration(finalKeyDownDuration);
131     event->eventType = subKeyNames;
132     MMI_HILOGD("FinalKeyDownDuration:%{public}d", finalKeyDownDuration);
133     if (argc == INPUT_PARAMETER_MAX) {
134         CHKRP(napi_typeof(env, argv[INPUT_PARAMETER_MIDDLE], &valueType), TYPEOF);
135         if (valueType != napi_function) {
136             MMI_HILOGE("the third parameter is not napi_function");
137             THROWERR_API9(env, COMMON_PARAMETER_ERROR, "callback", "function");
138             return nullptr;
139         }
140         CHKRP(napi_create_reference(env, argv[INPUT_PARAMETER_MIDDLE], 1, &event->callback[0]), REFERENCE_REF);
141     } else {
142         event->callback[0] = nullptr;
143     }
144     napi_value ret;
145     CHKRP(napi_create_int32(env, RET_OK, &ret), CREATE_INT32);
146     return ret;
147 }
148 
IsMatchKeyAction(bool isFinalKeydown,int32_t keyAction)149 static bool IsMatchKeyAction(bool isFinalKeydown, int32_t keyAction)
150 {
151     CALL_DEBUG_ENTER;
152     MMI_HILOGD("isFinalKeydown:%{public}d,keyAction:%{public}d", isFinalKeydown, keyAction);
153     if (isFinalKeydown && keyAction == KeyEvent::KEY_ACTION_DOWN) {
154         return true;
155     }
156 
157     if (!isFinalKeydown && keyAction == KeyEvent::KEY_ACTION_UP) {
158         return true;
159     }
160     MMI_HILOGE("isFinalKeydown not matched with keyAction");
161     return false;
162 }
163 
MatchCombinationKeys(KeyEventMonitorInfo * monitorInfo,std::shared_ptr<KeyEvent> keyEvent)164 static bool MatchCombinationKeys(KeyEventMonitorInfo* monitorInfo, std::shared_ptr<KeyEvent> keyEvent)
165 {
166     CALL_DEBUG_ENTER;
167     CHKPF(monitorInfo);
168     CHKPF(keyEvent);
169     auto keyOption = monitorInfo->keyOption;
170     CHKPF(keyOption);
171     std::vector<KeyEvent::KeyItem> items = keyEvent->GetKeyItems();
172     int32_t infoFinalKey = keyOption->GetFinalKey();
173     int32_t keyEventFinalKey = keyEvent->GetKeyCode();
174     bool isFinalKeydown = keyOption->IsFinalKeyDown();
175     MMI_HILOGD("infoFinalKey:%{public}d,keyEventFinalKey:%{public}d", infoFinalKey, keyEventFinalKey);
176     if (infoFinalKey != keyEventFinalKey || items.size() > PRE_KEYS_SIZE ||
177         !IsMatchKeyAction(isFinalKeydown, keyEvent->GetKeyAction())) {
178         MMI_HILOGD("Param invalid");
179         return false;
180     }
181     std::set<int32_t> infoPreKeys = keyOption->GetPreKeys();
182     int32_t infoSize = 0;
183     auto it = infoPreKeys.begin();
184     while (it != infoPreKeys.end()) {
185         if (*it >= 0) {
186             infoSize++;
187         }
188         ++it;
189     }
190     int32_t count = 0;
191     for (const auto &item : items) {
192         if (item.GetKeyCode() == keyEventFinalKey) {
193             continue;
194         }
195         auto iter = find(infoPreKeys.begin(), infoPreKeys.end(), item.GetKeyCode());
196         if (iter == infoPreKeys.end()) {
197             MMI_HILOGW("No keyCode in preKeys");
198             return false;
199         }
200         count++;
201     }
202     MMI_HILOGD("kevEventSize:%{public}d,infoSize:%{public}d", count, infoSize);
203     std::optional<KeyEvent::KeyItem> keyItem = keyEvent->GetKeyItem();
204     if (!keyItem) {
205         MMI_HILOGE("The keyItem is nullopt");
206         return false;
207     }
208     auto downTime = keyItem->GetDownTime();
209     auto upTime = keyEvent->GetActionTime();
210     auto curDurationTime = keyOption->GetFinalKeyDownDuration();
211     if (curDurationTime > 0 && (upTime - downTime >= (static_cast<int64_t>(curDurationTime) * 1000))) {
212         MMI_HILOGE("Skip, upTime - downTime >= duration");
213         return false;
214     }
215     return count == infoSize;
216 }
217 
SubKeyEventCallback(std::shared_ptr<KeyEvent> keyEvent)218 static void SubKeyEventCallback(std::shared_ptr<KeyEvent> keyEvent)
219 {
220     CALL_DEBUG_ENTER;
221     CHKPV(keyEvent);
222     std::lock_guard guard(sCallBacksMutex);
223     auto iter = callbacks.begin();
224     while (iter != callbacks.end()) {
225         auto &list = iter->second;
226         ++iter;
227         MMI_HILOGD("list size:%{public}zu", list.size());
228         auto infoIter = list.begin();
229         while (infoIter != list.end()) {
230             auto monitorInfo = *infoIter;
231             if (MatchCombinationKeys(monitorInfo, keyEvent)) {
232                 monitorInfo->keyEvent = keyEvent;
233                 EmitAsyncCallbackWork(monitorInfo);
234             }
235             ++infoIter;
236         }
237     }
238 }
239 
JsOn(napi_env env,napi_callback_info info)240 static napi_value JsOn(napi_env env, napi_callback_info info)
241 {
242     CALL_DEBUG_ENTER;
243     std::lock_guard guard(sCallBacksMutex);
244     size_t argc = 3;
245     napi_value argv[3] = { 0 };
246     CHKRP(napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr), GET_CB_INFO);
247     if (argc < INPUT_PARAMETER_MAX) {
248         THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "parameter number error");
249         return nullptr;
250     }
251     KeyEventMonitorInfo *event = new (std::nothrow) KeyEventMonitorInfo {
252         .env = env,
253         .asyncWork = nullptr,
254     };
255     CHKPP(event);
256     auto keyOption = std::make_shared<KeyOption>();
257     napi_valuetype valueType = napi_undefined;
258     if (napi_typeof(env, argv[0], &valueType) != napi_ok) {
259         delete event;
260         MMI_HILOGE("Napi typeof failed");
261         return nullptr;
262     }
263     if (GetEventInfoAPI9(env, info, event, keyOption) == nullptr) {
264         napi_delete_reference(env, event->callback[0]);
265         delete event;
266         MMI_HILOGE("GetEventInfo failed");
267         return nullptr;
268     }
269     event->keyOption = keyOption;
270     int32_t preSubscribeId = GetPreSubscribeId(callbacks, event);
271     if (preSubscribeId < 0) {
272         MMI_HILOGD("eventType:%{public}s,eventName:%{public}s", event->eventType.c_str(), event->name.c_str());
273         int32_t subscribeId = -1;
274         subscribeId = InputManager::GetInstance()->SubscribeKeyEvent(keyOption, SubKeyEventCallback);
275         if (subscribeId < 0) {
276             MMI_HILOGE("SubscribeId invalid:%{public}d", subscribeId);
277             napi_delete_reference(env, event->callback[0]);
278             delete event;
279             return nullptr;
280         }
281         MMI_HILOGD("SubscribeId:%{public}d", subscribeId);
282         event->subscribeId = subscribeId;
283     } else {
284         event->subscribeId = preSubscribeId;
285     }
286     if (AddEventCallback(env, callbacks, event) < 0) {
287         delete event;
288         MMI_HILOGE("AddEventCallback failed");
289         return nullptr;
290     }
291     return nullptr;
292 }
293 
JsOff(napi_env env,napi_callback_info info)294 static napi_value JsOff(napi_env env, napi_callback_info info)
295 {
296     CALL_DEBUG_ENTER;
297     std::lock_guard guard(sCallBacksMutex);
298     size_t argc = 3;
299     napi_value argv[3] = { 0 };
300     CHKRP(napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr), GET_CB_INFO);
301     if (argc < INPUT_PARAMETER_MIDDLE) {
302         THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "parameter number error");
303         return nullptr;
304     }
305     KeyEventMonitorInfo *event = new (std::nothrow) KeyEventMonitorInfo {
306         .env = env,
307         .asyncWork = nullptr,
308     };
309     CHKPP(event);
310     auto keyOption = std::make_shared<KeyOption>();
311     napi_valuetype valueType = napi_undefined;
312     if (napi_typeof(env, argv[0], &valueType) != napi_ok) {
313         delete event;
314         MMI_HILOGE("Napi typeof failed");
315         return nullptr;
316     }
317     if (GetEventInfoAPI9(env, info, event, keyOption) == nullptr) {
318         napi_delete_reference(env, event->callback[0]);
319         delete event;
320         MMI_HILOGE("GetEventInfo failed");
321         return nullptr;
322     }
323     int32_t subscribeId = -1;
324     if (DelEventCallback(env, callbacks, event, subscribeId) < 0) {
325         delete event;
326         MMI_HILOGE("DelEventCallback failed");
327         return nullptr;
328     }
329     MMI_HILOGD("SubscribeId:%{public}d", subscribeId);
330     if (subscribeId >= 0) {
331         InputManager::GetInstance()->UnsubscribeKeyEvent(subscribeId);
332     }
333     if (event->callback[0] != nullptr) {
334         napi_delete_reference(env, event->callback[0]);
335     }
336     delete event;
337     return nullptr;
338 }
339 
340 EXTERN_C_START
MmiInit(napi_env env,napi_value exports)341 static napi_value MmiInit(napi_env env, napi_value exports)
342 {
343     CALL_DEBUG_ENTER;
344     napi_property_descriptor desc[] = {
345         DECLARE_NAPI_FUNCTION("on", JsOn),
346         DECLARE_NAPI_FUNCTION("off", JsOff),
347     };
348     NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc));
349     return exports;
350 }
351 EXTERN_C_END
352 
353 static napi_module mmiModule = {
354     .nm_version = 1,
355     .nm_flags = 0,
356     .nm_filename = nullptr,
357     .nm_register_func = MmiInit,
358     .nm_modname = "multimodalInput.inputConsumer",
359     .nm_priv = ((void*)0),
360     .reserved = { 0 },
361 };
362 
RegisterModule(void)363 extern "C" __attribute__((constructor)) void RegisterModule(void)
364 {
365     napi_module_register(&mmiModule);
366 }
367 } // namespace MMI
368 } // namespace OHOS
369