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