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