1 /*
2 * Copyright (c) 2021-2025 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 "input_manager.h"
17 #include "js_register_util.h"
18 #include "napi_constants.h"
19 #include "util_napi_error.h"
20
21 #undef MMI_LOG_TAG
22 #define MMI_LOG_TAG "JSRegisterModule"
23
24 namespace OHOS {
25 namespace MMI {
26 namespace {
27 constexpr size_t EVENT_NAME_LEN { 64 };
28 constexpr size_t PRE_KEYS_SIZE { 4 };
29 constexpr size_t AT_LEAST_ONE_PARAMETER { 1 };
30 constexpr size_t INPUT_PARAMETER_MIDDLE { 2 };
31 constexpr size_t INPUT_PARAMETER_MAX { 3 };
32 constexpr size_t KEY_MONITOR_EXPECT_N_PARAMS { 3 };
33 constexpr size_t FIRST_PARAMETER { 0 };
34 constexpr size_t SECOND_PARAMETER { 1 };
35 constexpr size_t THIRD_PARAMETER { 2 };
36 constexpr int32_t INVALID_SUBSCRIBER_ID { -1 };
37 constexpr int32_t OCCUPIED_BY_SYSTEM { -3 };
38 constexpr int32_t OCCUPIED_BY_OTHER { -4 };
39 constexpr int32_t BOOLEAN_TRUE { 1 };
40 constexpr int32_t BOOLEAN_FALSE { 0 };
41 constexpr int32_t BOOLEAN_NONE { -1 };
42 constexpr uint32_t DEFAULT_REFERENCE_COUNT { 1 };
43 } // namespace
44
45 static Callbacks callbacks = {};
46 static Callbacks hotkeyCallbacks = {};
47 std::mutex sCallBacksMutex;
48 static const std::vector<int32_t> pressKeyCodes = {
49 KeyEvent::KEYCODE_ALT_LEFT,
50 KeyEvent::KEYCODE_ALT_RIGHT,
51 KeyEvent::KEYCODE_SHIFT_LEFT,
52 KeyEvent::KEYCODE_SHIFT_RIGHT,
53 KeyEvent::KEYCODE_CTRL_LEFT,
54 KeyEvent::KEYCODE_CTRL_RIGHT
55 };
56 static const std::vector<int32_t> finalKeyCodes = {
57 KeyEvent::KEYCODE_ALT_LEFT,
58 KeyEvent::KEYCODE_ALT_RIGHT,
59 KeyEvent::KEYCODE_SHIFT_LEFT,
60 KeyEvent::KEYCODE_SHIFT_RIGHT,
61 KeyEvent::KEYCODE_CTRL_LEFT,
62 KeyEvent::KEYCODE_CTRL_RIGHT,
63 KeyEvent::KEYCODE_META_LEFT,
64 KeyEvent::KEYCODE_META_RIGHT
65 };
TypeOf(napi_env env,napi_value value,napi_valuetype type)66 bool JsCommon::TypeOf(napi_env env, napi_value value, napi_valuetype type)
67 {
68 napi_valuetype valueType = napi_undefined;
69 CHKRF(napi_typeof(env, value, &valueType), TYPEOF);
70 if (valueType != type) {
71 return false;
72 }
73 return true;
74 }
75
ThrowError(napi_env env,int32_t code)76 void JsCommon::ThrowError(napi_env env, int32_t code)
77 {
78 int32_t errorCode = std::abs(code);
79 if (errorCode == COMMON_USE_SYSAPI_ERROR) {
80 MMI_HILOGE("Non system applications use system API");
81 THROWERR_CUSTOM(env, COMMON_USE_SYSAPI_ERROR, "Non system applications use system API");
82 } else if (errorCode == COMMON_PERMISSION_CHECK_ERROR) {
83 MMI_HILOGE("Shield api need ohos.permission.INPUT_CONTROL_DISPATCHING");
84 THROWERR_API9(env, COMMON_PERMISSION_CHECK_ERROR, "shiled API", "ohos.permission.INPUT_CONTROL_DISPATCHING");
85 } else {
86 MMI_HILOGE("Dispatch control failed");
87 }
88 }
89
EnvCleanUp(void * data)90 static void EnvCleanUp(void *data)
91 {
92 if (data == nullptr) {
93 return;
94 }
95 KeyEventMonitorInfo *info = reinterpret_cast<KeyEventMonitorInfo *>(data);
96 std::lock_guard<std::mutex> lock(info->envMutex_);
97 info->env = nullptr;
98 }
99
GetHotkeyEventInfo(napi_env env,napi_callback_info info,sptr<KeyEventMonitorInfo> event,std::shared_ptr<KeyOption> keyOption)100 napi_value GetHotkeyEventInfo(napi_env env, napi_callback_info info, sptr<KeyEventMonitorInfo> event,
101 std::shared_ptr<KeyOption> keyOption)
102 {
103 CALL_DEBUG_ENTER;
104 CHKPP(event);
105 CHKPP(keyOption);
106 size_t argc = 3;
107 napi_value argv[3] = { 0 };
108 CHKRP(napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr), GET_CB_INFO);
109 napi_value receiveValue = nullptr;
110 CHKRP(napi_get_named_property(env, argv[1], "preKeys", &receiveValue), GET_NAMED_PROPERTY);
111 if (receiveValue == nullptr) {
112 THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "PreKeys not found");
113 return nullptr;
114 }
115 std::set<int32_t> preKeys;
116 if (GetPreKeys(env, receiveValue, preKeys) == nullptr) {
117 MMI_HILOGE("Get preKeys failed");
118 return nullptr;
119 }
120 if (preKeys.size() > PRE_KEYS_SIZE) {
121 MMI_HILOGE("PreKeys size invalid");
122 THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "PreKeys size invalid");
123 return nullptr;
124 }
125 MMI_HILOGD("PreKeys size:%{public}zu", preKeys.size());
126 keyOption->SetPreKeys(preKeys);
127 std::string subKeyNames = "";
128 for (const auto &item : preKeys) {
129 auto it = std::find(pressKeyCodes.begin(), pressKeyCodes.end(), item);
130 if (it == pressKeyCodes.end()) {
131 MMI_HILOGE("PreKeys is not expect");
132 THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "PreKeys size invalid");
133 return nullptr;
134 }
135 subKeyNames += std::to_string(item);
136 subKeyNames += ",";
137 MMI_HILOGD("PreKeys:%{private}d", item);
138 }
139 std::optional<int32_t> finalKeyOption = GetNamedPropertyInt32(env, argv[1], "finalKey");
140 if (!finalKeyOption) {
141 MMI_HILOGE("GetNamedPropertyInt32 failed");
142 return nullptr;
143 }
144 int32_t finalKey = finalKeyOption.value();
145 if (finalKey < 0) {
146 MMI_HILOGE("FinalKey:%{private}d is less 0, can not process", finalKey);
147 THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "FinalKey must be greater than or equal to 0");
148 return nullptr;
149 }
150 auto it = std::find(finalKeyCodes.begin(), finalKeyCodes.end(), finalKey);
151 if (it != finalKeyCodes.end()) {
152 MMI_HILOGE("FinalKey is not expect");
153 THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "FinalKey is not expect");
154 return nullptr;
155 }
156 subKeyNames += std::to_string(finalKey);
157 subKeyNames += ",";
158 keyOption->SetFinalKey(finalKey);
159 MMI_HILOGD("FinalKey:%{private}d", finalKey);
160
161 bool isFinalKeyDown = true;
162 subKeyNames += std::to_string(isFinalKeyDown);
163 subKeyNames += ",";
164 keyOption->SetFinalKeyDown(isFinalKeyDown);
165 MMI_HILOGD("IsFinalKeyDown:%{private}d,", (isFinalKeyDown == true ? 1 : 0));
166
167 int32_t finalKeyDownDuration = 0;
168 subKeyNames += std::to_string(finalKeyDownDuration);
169 subKeyNames += ",";
170 keyOption->SetFinalKeyDownDuration(finalKeyDownDuration);
171
172 bool isRepeat = true;
173 if (!GetNamedPropertyBool(env, argv[1], "isRepeat", isRepeat)) {
174 MMI_HILOGD("IsRepeat field is default");
175 }
176 subKeyNames += std::to_string(isRepeat);
177 keyOption->SetRepeat(isRepeat);
178 MMI_HILOGD("IsRepeat:%{public}s", (isRepeat ? "true" : "false"));
179 event->eventType = subKeyNames;
180
181 napi_value ret;
182 CHKRP(napi_create_int32(env, RET_OK, &ret), CREATE_INT32);
183 return ret;
184 }
185
GetEventInfoAPI9(napi_env env,napi_callback_info info,sptr<KeyEventMonitorInfo> event,std::shared_ptr<KeyOption> keyOption)186 napi_value GetEventInfoAPI9(napi_env env, napi_callback_info info, sptr<KeyEventMonitorInfo> event,
187 std::shared_ptr<KeyOption> keyOption)
188 {
189 CALL_DEBUG_ENTER;
190 CHKPP(event);
191 CHKPP(keyOption);
192 size_t argc = 3;
193 napi_value argv[3] = { 0 };
194 CHKRP(napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr), GET_CB_INFO);
195 napi_value receiveValue = nullptr;
196 CHKRP(napi_get_named_property(env, argv[1], "preKeys", &receiveValue), GET_NAMED_PROPERTY);
197 if (receiveValue == nullptr) {
198 THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "preKeys not found");
199 return nullptr;
200 }
201 std::set<int32_t> preKeys;
202 if (GetPreKeys(env, receiveValue, preKeys) == nullptr) {
203 MMI_HILOGE("Get preKeys failed");
204 return nullptr;
205 }
206 if (preKeys.size() > PRE_KEYS_SIZE) {
207 MMI_HILOGE("PreKeys size invalid");
208 THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "preKeys size invalid");
209 return nullptr;
210 }
211 MMI_HILOGD("PreKeys size:%{public}zu", preKeys.size());
212 keyOption->SetPreKeys(preKeys);
213 std::string subKeyNames = "";
214 for (const auto &item : preKeys) {
215 subKeyNames += std::to_string(item);
216 subKeyNames += ",";
217 MMI_HILOGD("preKeys:%{private}d", item);
218 }
219 std::optional<int32_t> tempFinalKey = GetNamedPropertyInt32(env, argv[1], "finalKey");
220 if (!tempFinalKey) {
221 MMI_HILOGE("GetNamedPropertyInt32 failed");
222 return nullptr;
223 }
224 int32_t finalKey = tempFinalKey.value();
225 if (finalKey < 0) {
226 MMI_HILOGE("finalKey:%{private}d is less 0, can not process", finalKey);
227 THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "finalKey must be greater than or equal to 0");
228 return nullptr;
229 }
230 subKeyNames += std::to_string(finalKey);
231 subKeyNames += ",";
232 keyOption->SetFinalKey(finalKey);
233 MMI_HILOGD("FinalKey:%{private}d", finalKey);
234 bool isFinalKeyDown;
235 if (!GetNamedPropertyBool(env, argv[1], "isFinalKeyDown", isFinalKeyDown)) {
236 MMI_HILOGE("GetNamedPropertyBool failed");
237 return nullptr;
238 }
239 subKeyNames += std::to_string(isFinalKeyDown);
240 subKeyNames += ",";
241 keyOption->SetFinalKeyDown(isFinalKeyDown);
242 MMI_HILOGD("IsFinalKeyDown:%{private}d,map_key:%{private}s",
243 (isFinalKeyDown == true ? 1 : 0), subKeyNames.c_str());
244 std::optional<int32_t> tempKeyDownDuration = GetNamedPropertyInt32(env, argv[1], "finalKeyDownDuration");
245 if (!tempKeyDownDuration) {
246 MMI_HILOGE("GetNamedPropertyInt32 failed");
247 return nullptr;
248 }
249 int32_t finalKeyDownDuration = tempKeyDownDuration.value();
250 if (finalKeyDownDuration < 0) {
251 MMI_HILOGE("finalKeyDownDuration:%{public}d is less 0, can not process", finalKeyDownDuration);
252 THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "finalKeyDownDuration must be greater than or equal to 0");
253 return nullptr;
254 }
255 subKeyNames += std::to_string(finalKeyDownDuration);
256 subKeyNames += ",";
257 keyOption->SetFinalKeyDownDuration(finalKeyDownDuration);
258 MMI_HILOGD("FinalKeyDownDuration:%{public}d", finalKeyDownDuration);
259 bool isRepeat = true;
260 if (!GetNamedPropertyBool(env, argv[1], "isRepeat", isRepeat)) {
261 MMI_HILOGD("IsRepeat field is default");
262 }
263 subKeyNames += std::to_string(isRepeat);
264 keyOption->SetRepeat(isRepeat);
265 MMI_HILOGD("IsRepeat:%{public}s", (isRepeat ? "true" : "false"));
266 event->eventType = subKeyNames;
267 napi_value ret;
268 CHKRP(napi_create_int32(env, RET_OK, &ret), CREATE_INT32);
269 return ret;
270 }
271
IsMatchKeyAction(bool isFinalKeydown,int32_t keyAction)272 static bool IsMatchKeyAction(bool isFinalKeydown, int32_t keyAction)
273 {
274 CALL_DEBUG_ENTER;
275 MMI_HILOGD("isFinalKeydown:%{public}d, keyAction:%{public}d", isFinalKeydown, keyAction);
276 if (isFinalKeydown && keyAction == KeyEvent::KEY_ACTION_DOWN) {
277 return true;
278 }
279 if (!isFinalKeydown && keyAction == KeyEvent::KEY_ACTION_UP) {
280 return true;
281 }
282 MMI_HILOGE("isFinalKeydown not matched with keyAction");
283 return false;
284 }
285
MatchCombinationKeys(sptr<KeyEventMonitorInfo> monitorInfo,std::shared_ptr<KeyEvent> keyEvent)286 static bool MatchCombinationKeys(sptr<KeyEventMonitorInfo> monitorInfo, std::shared_ptr<KeyEvent> keyEvent)
287 {
288 CALL_DEBUG_ENTER;
289 CHKPF(monitorInfo);
290 CHKPF(keyEvent);
291 auto keyOption = monitorInfo->keyOption;
292 CHKPF(keyOption);
293 std::vector<KeyEvent::KeyItem> items = keyEvent->GetKeyItems();
294 int32_t infoFinalKey = keyOption->GetFinalKey();
295 int32_t keyEventFinalKey = keyEvent->GetKeyCode();
296 bool isFinalKeydown = keyOption->IsFinalKeyDown();
297 MMI_HILOGD("InfoFinalKey:%{private}d,keyEventFinalKey:%{private}d", infoFinalKey, keyEventFinalKey);
298 if (infoFinalKey != keyEventFinalKey || items.size() > PRE_KEYS_SIZE ||
299 !IsMatchKeyAction(isFinalKeydown, keyEvent->GetKeyAction())) {
300 MMI_HILOGD("key Param invalid");
301 return false;
302 }
303 std::set<int32_t> infoPreKeys = keyOption->GetPreKeys();
304 int32_t infoSize = 0;
305 for (auto it = infoPreKeys.begin(); it != infoPreKeys.end(); ++it) {
306 if (*it >= 0) {
307 infoSize++;
308 }
309 }
310 int32_t count = 0;
311 for (const auto &item : items) {
312 if (item.GetKeyCode() == keyEventFinalKey) {
313 continue;
314 }
315 auto iter = find(infoPreKeys.begin(), infoPreKeys.end(), item.GetKeyCode());
316 if (iter == infoPreKeys.end()) {
317 MMI_HILOGW("No keyCode in preKeys");
318 return false;
319 }
320 count++;
321 }
322 MMI_HILOGD("kevEventSize:%{public}d, infoSize:%{public}d", count, infoSize);
323 std::optional<KeyEvent::KeyItem> keyItem = keyEvent->GetKeyItem();
324 if (!keyItem) {
325 MMI_HILOGE("The keyItem is nullopt");
326 return false;
327 }
328 auto downTime = keyItem->GetDownTime();
329 auto upTime = keyEvent->GetActionTime();
330 auto curDurationTime = keyOption->GetFinalKeyDownDuration();
331 if (curDurationTime > 0 && (upTime - downTime >= (static_cast<int64_t>(curDurationTime) * 1000))) {
332 MMI_HILOGE("Skip, upTime - downTime >= duration");
333 return false;
334 }
335 return count == infoSize;
336 }
337
SubKeyEventCallback(std::shared_ptr<KeyEvent> keyEvent,const std::string & keyOptionKey)338 static void SubKeyEventCallback(std::shared_ptr<KeyEvent> keyEvent, const std::string& keyOptionKey)
339 {
340 CALL_DEBUG_ENTER;
341 CHKPV(keyEvent);
342 std::list<sptr<KeyEventMonitorInfo>> info;
343 {
344 std::lock_guard guard(sCallBacksMutex);
345 auto iter = callbacks.find(keyOptionKey);
346 if (iter != callbacks.end()) {
347 auto &list = iter->second;
348 MMI_HILOGD("list size:%{public}zu", list.size());
349 for (auto monitorInfo : list) {
350 if (MatchCombinationKeys(monitorInfo, keyEvent)) {
351 info.push_back(monitorInfo);
352 }
353 }
354 } else {
355 MMI_HILOGE("No Matches found for SubKeyEventCallback");
356 }
357 }
358 while (info.begin() != info.end()) {
359 auto it = info.front();
360 info.pop_front();
361 EmitAsyncCallbackWork(it);
362 }
363 }
364
SubHotkeyEventCallback(std::shared_ptr<KeyEvent> keyEvent)365 static void SubHotkeyEventCallback(std::shared_ptr<KeyEvent> keyEvent)
366 {
367 CALL_DEBUG_ENTER;
368 CHKPV(keyEvent);
369 std::list<sptr<KeyEventMonitorInfo>> info;
370 {
371 std::lock_guard guard(sCallBacksMutex);
372 auto iter = hotkeyCallbacks.begin();
373 while (iter != hotkeyCallbacks.end()) {
374 auto &list = iter->second;
375 ++iter;
376 MMI_HILOGD("Callback list size:%{public}zu", list.size());
377 auto infoIter = list.begin();
378 while (infoIter != list.end()) {
379 auto monitorInfo = *infoIter;
380 if (MatchCombinationKeys(monitorInfo, keyEvent)) {
381 info.push_back(monitorInfo);
382 }
383 ++infoIter;
384 }
385 }
386 }
387 while (info.begin() != info.end()) {
388 auto it = info.front();
389 info.pop_front();
390 EmitAsyncCallbackWork(it);
391 }
392 }
393
GenerateKeyOptionKey(const std::shared_ptr<KeyOption> & keyOption)394 std::string GenerateKeyOptionKey(const std::shared_ptr<KeyOption>& keyOption)
395 {
396 CHKPS(keyOption);
397 std::string subKeyNames;
398 const std::set<int32_t>& preKeys = keyOption->GetPreKeys();
399 int32_t finalKey = keyOption->GetFinalKey();
400 bool isFinalKeyDown = keyOption->IsFinalKeyDown();
401 int32_t finalKeyDownDuration = keyOption->GetFinalKeyDownDuration();
402 bool isRepeat = keyOption->IsRepeat();
403 for (const auto& key : preKeys) {
404 subKeyNames.append(std::to_string(key)).append(",");
405 }
406 subKeyNames.append(std::to_string(finalKey)).append(",");
407 subKeyNames.append(std::to_string(isFinalKeyDown)).append(",");
408 subKeyNames.append(std::to_string(finalKeyDownDuration)).append(",");
409 subKeyNames.append(std::to_string(isRepeat));
410 return subKeyNames;
411 }
412
SubscribeKey(napi_env env,napi_callback_info info,sptr<KeyEventMonitorInfo> event,std::shared_ptr<KeyOption> keyOption)413 napi_value SubscribeKey(napi_env env, napi_callback_info info, sptr<KeyEventMonitorInfo> event,
414 std::shared_ptr<KeyOption> keyOption)
415 {
416 CALL_DEBUG_ENTER;
417 CHKPP(event);
418 CHKPP(keyOption);
419 if (GetEventInfoAPI9(env, info, event, keyOption) == nullptr) {
420 MMI_HILOGE("GetEventInfoAPI9 failed");
421 return nullptr;
422 }
423 event->keyOption = keyOption;
424 int32_t preSubscribeId = GetPreSubscribeId(callbacks, event);
425 if (preSubscribeId < 0) {
426 MMI_HILOGD("EventType:%{private}s, eventName:%{public}s", event->eventType.c_str(), event->name.c_str());
427 int32_t subscribeId = -1;
428 subscribeId = InputManager::GetInstance()->SubscribeKeyEvent(keyOption,
429 [keyOption](std::shared_ptr<KeyEvent> keyEvent) {
430 std::string keyOptionKey = GenerateKeyOptionKey(keyOption);
431 SubKeyEventCallback(keyEvent, keyOptionKey);
432 });
433 if (subscribeId < 0) {
434 MMI_HILOGE("SubscribeId invalid:%{public}d", subscribeId);
435 return nullptr;
436 }
437 MMI_HILOGD("SubscribeId:%{public}d", subscribeId);
438 event->subscribeId = subscribeId;
439 } else {
440 event->subscribeId = preSubscribeId;
441 }
442 if (AddEventCallback(env, callbacks, event) < 0) {
443 MMI_HILOGE("AddEventCallback failed");
444 return nullptr;
445 }
446 napi_value ret;
447 CHKRP(napi_create_int32(env, RET_OK, &ret), CREATE_INT32);
448 return ret;
449 }
450
SubscribeHotkey(napi_env env,napi_callback_info info,sptr<KeyEventMonitorInfo> event,std::shared_ptr<KeyOption> keyOption)451 napi_value SubscribeHotkey(napi_env env, napi_callback_info info, sptr<KeyEventMonitorInfo> event,
452 std::shared_ptr<KeyOption> keyOption)
453 {
454 CALL_DEBUG_ENTER;
455 CHKPP(event);
456 CHKPP(keyOption);
457 if (GetHotkeyEventInfo(env, info, event, keyOption) == nullptr) {
458 MMI_HILOGE("GetHotkeyEventInfo failed");
459 return nullptr;
460 }
461 event->keyOption = keyOption;
462 int32_t preSubscribeId = GetPreSubscribeId(hotkeyCallbacks, event);
463 if (preSubscribeId < 0) {
464 MMI_HILOGD("EventType:%{private}s, eventName:%{public}s", event->eventType.c_str(), event->name.c_str());
465 int32_t subscribeId = -1;
466 subscribeId = InputManager::GetInstance()->SubscribeHotkey(keyOption, SubHotkeyEventCallback);
467 if (subscribeId == ERROR_UNSUPPORT) {
468 MMI_HILOGE("SubscribeId invalid:%{public}d", subscribeId);
469 THROWERR_CUSTOM(env, INPUT_DEVICE_NOT_SUPPORTED, "Hotkey occupied by other");
470 return nullptr;
471 }
472 if (subscribeId == OCCUPIED_BY_SYSTEM) {
473 MMI_HILOGE("SubscribeId invalid:%{public}d", subscribeId);
474 THROWERR_CUSTOM(env, INPUT_OCCUPIED_BY_SYSTEM, "Hotkey occupied by system");
475 return nullptr;
476 }
477 if (subscribeId == OCCUPIED_BY_OTHER) {
478 MMI_HILOGE("SubscribeId invalid:%{public}d", subscribeId);
479 THROWERR_CUSTOM(env, INPUT_OCCUPIED_BY_OTHER, "Hotkey occupied by other");
480 return nullptr;
481 }
482 MMI_HILOGD("SubscribeId:%{public}d", subscribeId);
483 event->subscribeId = subscribeId;
484 } else {
485 event->subscribeId = preSubscribeId;
486 }
487 if (AddEventCallback(env, hotkeyCallbacks, event) < 0) {
488 MMI_HILOGE("AddEventCallback failed");
489 THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "AddEventCallback failed");
490 return nullptr;
491 }
492 napi_value ret;
493 CHKRP(napi_create_int32(env, RET_OK, &ret), CREATE_INT32);
494 return ret;
495 }
496
GetEventType(napi_env env,napi_callback_info info,sptr<KeyEventMonitorInfo> event,std::string & keyType)497 bool GetEventType(napi_env env, napi_callback_info info, sptr<KeyEventMonitorInfo> event, std::string &keyType)
498 {
499 CALL_DEBUG_ENTER;
500 size_t argc = 3;
501 napi_value argv[3] = { 0 };
502 CHKRF(napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr), GET_CB_INFO);
503 if (argc < INPUT_PARAMETER_MIDDLE) {
504 MMI_HILOGE("Parameter number error argc:%{public}zu", argc);
505 THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "parameter number error");
506 return false;
507 }
508 if (!UtilNapi::TypeOf(env, argv[0], napi_string)) {
509 MMI_HILOGE("The first parameter is not string");
510 THROWERR_API9(env, COMMON_PARAMETER_ERROR, "type", "string");
511 return false;
512 }
513 if (!UtilNapi::TypeOf(env, argv[1], napi_object)) {
514 MMI_HILOGE("The second parameter is not napi_object");
515 THROWERR_API9(env, COMMON_PARAMETER_ERROR, "keyOptions", "object");
516 return false;
517 }
518 CHKPF(event);
519 if (argc == INPUT_PARAMETER_MAX) {
520 napi_valuetype valueType = napi_undefined;
521 CHKRF(napi_typeof(env, argv[INPUT_PARAMETER_MIDDLE], &valueType), TYPEOF);
522 if (valueType != napi_function) {
523 MMI_HILOGE("The third parameter is not napi_function");
524 THROWERR_API9(env, COMMON_PARAMETER_ERROR, "callback", "function");
525 return false;
526 }
527 CHKRF(napi_create_reference(env, argv[INPUT_PARAMETER_MIDDLE], 1, &event->callback), REFERENCE_REF);
528 } else {
529 event->callback = nullptr;
530 }
531
532 char eventType[EVENT_NAME_LEN] = { 0 };
533 size_t typeLen = 0;
534 CHKRF(napi_get_value_string_utf8(env, argv[0], eventType, EVENT_NAME_LEN - 1, &typeLen), GET_VALUE_STRING_UTF8);
535 keyType = eventType;
536 if (keyType != SUBSCRIBE_TYPE && keyType != HOTKEY_SUBSCRIBE_TYPE) {
537 MMI_HILOGE("Type is not key or hotkey");
538 THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "Type must be key or hotkeyChange");
539 return false;
540 }
541 return true;
542 }
543
ResolveEventType(napi_env env,napi_callback_info info)544 static std::optional<std::string> ResolveEventType(napi_env env, napi_callback_info info)
545 {
546 CALL_DEBUG_ENTER;
547 size_t argc { KEY_MONITOR_EXPECT_N_PARAMS };
548 napi_value argv[KEY_MONITOR_EXPECT_N_PARAMS] {};
549
550 auto ret = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
551 if (ret != napi_ok) {
552 MMI_HILOGE("napi_get_cb_info fail");
553 return std::nullopt;
554 }
555 if (argc < AT_LEAST_ONE_PARAMETER) {
556 MMI_HILOGE("Type of subscription is required");
557 THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "Type of subscription is required");
558 return std::nullopt;
559 }
560 if (!UtilNapi::TypeOf(env, argv[FIRST_PARAMETER], napi_string)) {
561 MMI_HILOGE("The first parameter is not string");
562 return std::nullopt;
563 }
564 char eventType[EVENT_NAME_LEN] {};
565 size_t typeLen { 0 };
566
567 ret = napi_get_value_string_utf8(env, argv[0], eventType, sizeof(eventType), &typeLen);
568 if (ret != napi_ok) {
569 MMI_HILOGE("napi_get_value_string_utf8 fail");
570 return std::nullopt;
571 }
572 return std::string(eventType);
573 }
574
JsOn(napi_env env,napi_callback_info info)575 static napi_value JsOn(napi_env env, napi_callback_info info)
576 {
577 CALL_DEBUG_ENTER;
578 auto etOpt = ResolveEventType(env, info);
579 if (etOpt && (*etOpt == KEY_MONITOR_SUBSCRIBE_TYPE)) {
580 JsInputConsumer::GetInstance()->SubscribeKeyMonitor(env, info);
581 return nullptr;
582 }
583 sptr<KeyEventMonitorInfo> event = new (std::nothrow) KeyEventMonitorInfo(env);
584 CHKPP(event);
585 auto keyOption = std::make_shared<KeyOption>();
586 std::string keyType;
587 size_t argc = 3;
588 napi_value argv[3] = { 0 };
589 if (napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr) != napi_ok) {
590 MMI_HILOGE("GET_CB_INFO failed");
591 return nullptr;
592 }
593 if (argc < INPUT_PARAMETER_MAX) {
594 MMI_HILOGE("Parameter number error argc:%{public}zu", argc);
595 THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "parameter number error");
596 return nullptr;
597 }
598 if (!GetEventType(env, info, event, keyType)) {
599 MMI_HILOGE("GetEventType fail, type must be key or hotkeyChange");
600 return nullptr;
601 }
602 event->name = keyType;
603 if (keyType == HOTKEY_SUBSCRIBE_TYPE) {
604 if (SubscribeHotkey(env, info, event, keyOption) == nullptr) {
605 MMI_HILOGE("SubscribeHotkey failed");
606 return nullptr;
607 }
608 } else {
609 if (SubscribeKey(env, info, event, keyOption) == nullptr) {
610 MMI_HILOGE("SubscribeKey failed");
611 return nullptr;
612 }
613 }
614 return nullptr;
615 }
616
JsOff(napi_env env,napi_callback_info info)617 static napi_value JsOff(napi_env env, napi_callback_info info)
618 {
619 CALL_DEBUG_ENTER;
620 auto etOpt = ResolveEventType(env, info);
621 if (etOpt && (*etOpt == KEY_MONITOR_SUBSCRIBE_TYPE)) {
622 JsInputConsumer::GetInstance()->UnsubscribeKeyMonitor(env, info);
623 return nullptr;
624 }
625 sptr<KeyEventMonitorInfo> event = new (std::nothrow) KeyEventMonitorInfo(env);
626 CHKPP(event);
627 auto keyOption = std::make_shared<KeyOption>();
628 std::string keyType;
629 if (!GetEventType(env, info, event, keyType)) {
630 MMI_HILOGE("GetEventType fail, type must be key or hotkeyChange");
631 return nullptr;
632 }
633 event->name = keyType;
634 int32_t subscribeId = -1;
635 if (keyType == HOTKEY_SUBSCRIBE_TYPE) {
636 if (GetHotkeyEventInfo(env, info, event, keyOption) == nullptr) {
637 MMI_HILOGE("GetHotkeyEventInfo failed");
638 return nullptr;
639 }
640 if (DelEventCallback(env, hotkeyCallbacks, event, subscribeId) < 0) {
641 MMI_HILOGE("DelEventCallback failed");
642 return nullptr;
643 }
644 MMI_HILOGI("Unsubscribe hot key(%{public}d)", subscribeId);
645 InputManager::GetInstance()->UnsubscribeHotkey(subscribeId);
646 } else {
647 if (GetEventInfoAPI9(env, info, event, keyOption) == nullptr) {
648 MMI_HILOGE("GetEventInfoAPI9 failed");
649 return nullptr;
650 }
651 if (DelEventCallback(env, callbacks, event, subscribeId) < 0) {
652 MMI_HILOGE("DelEventCallback failed");
653 return nullptr;
654 }
655 MMI_HILOGI("Unsubscribe key event(%{public}d)", subscribeId);
656 InputManager::GetInstance()->UnsubscribeKeyEvent(subscribeId);
657 }
658 return nullptr;
659 }
660
SetShieldStatus(napi_env env,napi_callback_info info)661 static napi_value SetShieldStatus(napi_env env, napi_callback_info info)
662 {
663 CALL_DEBUG_ENTER;
664 size_t argc = 2;
665 napi_value argv[2] = { 0 };
666 CHKRP(napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr), GET_CB_INFO);
667 if (argc < INPUT_PARAMETER_MIDDLE) {
668 MMI_HILOGE("At least two parameters is required");
669 THROWERR_API9(env, COMMON_PARAMETER_ERROR, "shieldMode", "number");
670 return nullptr;
671 }
672 if (!JsCommon::TypeOf(env, argv[0], napi_number)) {
673 MMI_HILOGE("shieldMode parameter type is invalid");
674 THROWERR_API9(env, COMMON_PARAMETER_ERROR, "shieldMode", "number");
675 return nullptr;
676 }
677 int32_t shieldMode = 0;
678 CHKRP(napi_get_value_int32(env, argv[0], &shieldMode), GET_VALUE_INT32);
679 if (shieldMode < FACTORY_MODE || shieldMode > OOBE_MODE) {
680 MMI_HILOGE("Undefined shield mode");
681 THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "Shield mode does not exist");
682 return nullptr;
683 }
684
685 if (!JsCommon::TypeOf(env, argv[1], napi_boolean)) {
686 MMI_HILOGE("isShield parameter type is invalid");
687 THROWERR_API9(env, COMMON_PARAMETER_ERROR, "isShield", "boolean");
688 return nullptr;
689 }
690 bool isShield = true;
691 CHKRP(napi_get_value_bool(env, argv[1], &isShield), GET_VALUE_BOOL);
692
693 int32_t errCode = InputManager::GetInstance()->SetShieldStatus(shieldMode, isShield);
694 JsCommon::ThrowError(env, errCode);
695 napi_value result = nullptr;
696 if (napi_get_undefined(env, &result) != napi_ok) {
697 MMI_HILOGE("Get undefined result is failed");
698 return nullptr;
699 }
700 return result;
701 }
702
GetShieldStatus(napi_env env,napi_callback_info info)703 static napi_value GetShieldStatus(napi_env env, napi_callback_info info)
704 {
705 CALL_DEBUG_ENTER;
706 size_t argc = 1;
707 napi_value argv[1] = { 0 };
708 CHKRP(napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr), GET_CB_INFO);
709 if (argc < 1) {
710 MMI_HILOGE("At least 1 parameter is required");
711 THROWERR_API9(env, COMMON_PARAMETER_ERROR, "shieldMode", "number");
712 return nullptr;
713 }
714 if (!JsCommon::TypeOf(env, argv[0], napi_number)) {
715 MMI_HILOGE("shieldMode parameter type is invalid");
716 THROWERR_API9(env, COMMON_PARAMETER_ERROR, "shieldMode", "number");
717 return nullptr;
718 }
719 int32_t shieldMode = 0;
720 CHKRP(napi_get_value_int32(env, argv[0], &shieldMode), GET_VALUE_INT32);
721 if (shieldMode < FACTORY_MODE || shieldMode > OOBE_MODE) {
722 MMI_HILOGE("Undefined shield mode");
723 THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "Shield mode does not exist");
724 return nullptr;
725 }
726 bool isShield { false };
727 auto errCode = InputManager::GetInstance()->GetShieldStatus(shieldMode, isShield);
728 JsCommon::ThrowError(env, errCode);
729 napi_value result = nullptr;
730 NAPI_CALL(env, napi_get_boolean(env, isShield, &result));
731 return result;
732 }
733
GetAllSystemHotkeys(napi_env env,napi_callback_info info)734 static napi_value GetAllSystemHotkeys(napi_env env, napi_callback_info info)
735 {
736 CALL_DEBUG_ENTER;
737 return GetSystemHotkey(env);
738 }
739
EnumConstructor(napi_env env,napi_callback_info info)740 static napi_value EnumConstructor(napi_env env, napi_callback_info info)
741 {
742 CALL_DEBUG_ENTER;
743 size_t argc = 0;
744 napi_value args[1] = { 0 };
745 napi_value ret = nullptr;
746 void *data = nullptr;
747 CHKRP(napi_get_cb_info(env, info, &argc, args, &ret, &data), GET_CB_INFO);
748 return ret;
749 }
750
CreateShieldMode(napi_env env,napi_value exports)751 static napi_value CreateShieldMode(napi_env env, napi_value exports)
752 {
753 CALL_DEBUG_ENTER;
754 napi_value factory_mode = nullptr;
755 CHKRP(napi_create_int32(env, SHIELD_MODE::FACTORY_MODE, &factory_mode), CREATE_INT32);
756 napi_value oobe_mode = nullptr;
757 CHKRP(napi_create_int32(env, SHIELD_MODE::OOBE_MODE, &oobe_mode), CREATE_INT32);
758
759 napi_property_descriptor desc[] = {
760 DECLARE_NAPI_STATIC_PROPERTY("FACTORY_MODE", factory_mode),
761 DECLARE_NAPI_STATIC_PROPERTY("OOBE_MODE", oobe_mode),
762 };
763 napi_value result = nullptr;
764 CHKRP(napi_define_class(env, "ShieldMode", NAPI_AUTO_LENGTH, EnumConstructor, nullptr,
765 sizeof(desc) / sizeof(*desc), desc, &result), DEFINE_CLASS);
766 CHKRP(napi_set_named_property(env, exports, "ShieldMode", result), SET_NAMED_PROPERTY);
767 return exports;
768 }
769
KeyEventMonitorInfo(napi_env env)770 KeyEventMonitorInfo::KeyEventMonitorInfo(napi_env env):env(env)
771 {
772 (void)napi_add_env_cleanup_hook(env, EnvCleanUp, this);
773 }
774
~KeyEventMonitorInfo()775 KeyEventMonitorInfo::~KeyEventMonitorInfo()
776 {
777 std::lock_guard<std::mutex> lock(envMutex_);
778 if (env == nullptr) {
779 return;
780 }
781 (void)napi_remove_env_cleanup_hook(env, EnvCleanUp, this);
782 if (callback == nullptr) {
783 return;
784 }
785 uint32_t refcount = 0;
786 CHKRV(napi_reference_unref(env, callback, &refcount), REFERENCE_UNREF);
787 if (refcount == 0) {
788 CHKRV(napi_delete_reference(env, callback), DELETE_REFERENCE);
789 }
790 callback = nullptr;
791 }
792
793 const std::set<int32_t> JsInputConsumer::allowedKeys_ {
794 KeyEvent::KEYCODE_VOLUME_DOWN,
795 KeyEvent::KEYCODE_VOLUME_UP,
796 };
797
GetInstance()798 std::shared_ptr<JsInputConsumer> JsInputConsumer::GetInstance()
799 {
800 static std::once_flag flag;
801 static std::shared_ptr<JsInputConsumer> instance_;
802
803 std::call_once(flag, []() {
804 instance_ = std::make_shared<JsInputConsumer>();
805 });
806 return instance_;
807 }
808
Parse(napi_env env,napi_callback_info info)809 bool JsInputConsumer::KeyMonitor::Parse(napi_env env, napi_callback_info info)
810 {
811 size_t argc { KEY_MONITOR_EXPECT_N_PARAMS };
812 napi_value argv[KEY_MONITOR_EXPECT_N_PARAMS] {};
813 CHKRF(napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr), GET_CB_INFO);
814
815 if (argc < KEY_MONITOR_EXPECT_N_PARAMS) {
816 MMI_HILOGE("Parameter number error argc:%{public}zu", argc);
817 THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "parameter number error");
818 return false;
819 }
820 if (!UtilNapi::TypeOf(env, argv[FIRST_PARAMETER], napi_string)) {
821 MMI_HILOGE("The first parameter is not string");
822 THROWERR_API9(env, COMMON_PARAMETER_ERROR, "type", "string");
823 return false;
824 }
825 if (!UtilNapi::TypeOf(env, argv[SECOND_PARAMETER], napi_object)) {
826 MMI_HILOGE("The second parameter is not object");
827 THROWERR_API9(env, COMMON_PARAMETER_ERROR, "options", "object");
828 return false;
829 }
830 if (!UtilNapi::TypeOf(env, argv[THIRD_PARAMETER], napi_function)) {
831 MMI_HILOGE("The third parameter is not function");
832 THROWERR_API9(env, COMMON_PARAMETER_ERROR, "callback", "function");
833 return false;
834 }
835 if (!ParseKeyMonitorOption(env, argv[SECOND_PARAMETER])) {
836 MMI_HILOGE("Invalid KeyMonitorOption");
837 return false;
838 }
839 auto ret = napi_create_reference(env, argv[THIRD_PARAMETER], DEFAULT_REFERENCE_COUNT, &callback_);
840 if (ret != napi_ok) {
841 MMI_HILOGE("napi_create_reference fail");
842 return false;
843 }
844 env_ = env;
845 return true;
846 }
847
ParseKeyMonitorOption(napi_env env,napi_value keyOption)848 bool JsInputConsumer::KeyMonitor::ParseKeyMonitorOption(napi_env env, napi_value keyOption)
849 {
850 CALL_DEBUG_ENTER;
851 auto optKey = GetNamedPropertyInt32(env, keyOption, "key");
852 if (!optKey) {
853 MMI_HILOGE("Expect 'key'");
854 THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "Expect 'key'");
855 return false;
856 }
857 auto optAction = GetNamedPropertyInt32(env, keyOption, "action");
858 if (!optAction) {
859 MMI_HILOGE("Expect 'action'");
860 THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "Expect 'action'");
861 return false;
862 }
863 bool isRepeat { true };
864 if (!GetNamedPropertyBool(env, keyOption, "isRepeat", isRepeat)) {
865 MMI_HILOGE("Expect 'isRepeat'");
866 THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "Expect 'isRepeat'");
867 return false;
868 }
869
870 keyOption_.SetKey(*optKey);
871 keyOption_.SetAction(JsInputConsumer::JsKeyAction2KeyAction(*optAction));
872 keyOption_.SetRepeat(isRepeat);
873
874 if (!JsInputConsumer::CheckKeyMonitorOption(keyOption_)) {
875 MMI_HILOGE("Input for KeyPressedConfig is invalid");
876 THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "Input for KeyPressedConfig is invalid");
877 return false;
878 }
879 return true;
880 }
881
ParseUnsubscription(napi_env env,napi_callback_info info)882 bool JsInputConsumer::KeyMonitor::ParseUnsubscription(napi_env env, napi_callback_info info)
883 {
884 size_t argc { KEY_MONITOR_EXPECT_N_PARAMS };
885 napi_value argv[KEY_MONITOR_EXPECT_N_PARAMS] {};
886
887 auto ret = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
888 if (ret != napi_ok) {
889 MMI_HILOGE("napi_get_cb_info fail");
890 return false;
891 }
892 if (argc < AT_LEAST_ONE_PARAMETER) {
893 MMI_HILOGE("Type of subscription is required");
894 THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "Type of subscription is required");
895 return false;
896 }
897 if (argc == AT_LEAST_ONE_PARAMETER) {
898 callback_ = nullptr;
899 return true;
900 }
901 if (!UtilNapi::TypeOf(env, argv[SECOND_PARAMETER], napi_function)) {
902 MMI_HILOGE("The second parameter is not function");
903 THROWERR_API9(env, COMMON_PARAMETER_ERROR, "callback", "function");
904 return false;
905 }
906 ret = napi_create_reference(env, argv[SECOND_PARAMETER], DEFAULT_REFERENCE_COUNT, &callback_);
907 if (ret != napi_ok) {
908 MMI_HILOGE("napi_create_reference fail");
909 return false;
910 }
911 env_ = env;
912 return true;
913 }
914
SubscribeKeyMonitor(napi_env env,napi_callback_info info)915 void JsInputConsumer::SubscribeKeyMonitor(napi_env env, napi_callback_info info)
916 {
917 std::lock_guard guard(mutex_);
918 KeyMonitor keyMonitor {};
919
920 if (!keyMonitor.Parse(env, info)) {
921 MMI_HILOGE("Unexpected key monitor");
922 return;
923 }
924 MMI_HILOGI("[NAPI] Subscribe key monitor");
925 if (!SubscribeKeyMonitor(env, keyMonitor)) {
926 CleanupKeyMonitor(env, keyMonitor);
927 }
928 }
929
UnsubscribeKeyMonitor(napi_env env,napi_callback_info info)930 void JsInputConsumer::UnsubscribeKeyMonitor(napi_env env, napi_callback_info info)
931 {
932 std::lock_guard guard(mutex_);
933 KeyMonitor keyMonitor {};
934
935 if (!keyMonitor.ParseUnsubscription(env, info)) {
936 MMI_HILOGE("Unexpected key monitor");
937 return;
938 }
939 if (keyMonitor.callback_ != nullptr) {
940 MMI_HILOGI("[NAPI] Unsubscribe key monitor");
941 UnsubscribeKeyMonitor(env, keyMonitor);
942 } else {
943 UnsubscribeKeyMonitors(env);
944 }
945 CleanupKeyMonitor(env, keyMonitor);
946 }
947
GenerateId()948 size_t JsInputConsumer::GenerateId()
949 {
950 return ++baseId_;
951 }
952
CleanupKeyMonitor(napi_env env,KeyMonitor & keyMonitor) const953 void JsInputConsumer::CleanupKeyMonitor(napi_env env, KeyMonitor &keyMonitor) const
954 {
955 if (keyMonitor.callback_ != nullptr) {
956 auto ret = napi_delete_reference(env, keyMonitor.callback_);
957 if (ret != napi_ok) {
958 MMI_HILOGE("napi_delete_reference fail");
959 }
960 keyMonitor.callback_ = nullptr;
961 }
962 }
963
IsIdentical(napi_env env,const KeyMonitor & sMonitor,const KeyMonitor & tMonitor) const964 int32_t JsInputConsumer::IsIdentical(napi_env env, const KeyMonitor &sMonitor, const KeyMonitor &tMonitor) const
965 {
966 napi_value sHandler { nullptr };
967 napi_value tHandler { nullptr };
968 bool isEqual { false };
969
970 auto ret = napi_get_reference_value(env, sMonitor.callback_, &sHandler);
971 if (ret != napi_ok) {
972 MMI_HILOGE("napi_get_reference_value fail");
973 return BOOLEAN_NONE;
974 }
975 ret = napi_get_reference_value(env, tMonitor.callback_, &tHandler);
976 if (ret != napi_ok) {
977 MMI_HILOGE("napi_get_reference_value fail");
978 return BOOLEAN_NONE;
979 }
980 ret = napi_strict_equals(env, sHandler, tHandler, &isEqual);
981 if (ret != napi_ok) {
982 MMI_HILOGE("napi_strict_equals fail");
983 return BOOLEAN_NONE;
984 }
985 return (isEqual ? BOOLEAN_TRUE : BOOLEAN_FALSE);
986 }
987
HasSubscribed(napi_env env,const KeyMonitor & keyMonitor) const988 int32_t JsInputConsumer::HasSubscribed(napi_env env, const KeyMonitor &keyMonitor) const
989 {
990 napi_value sHandler { nullptr };
991 auto ret = napi_get_reference_value(env, keyMonitor.callback_, &sHandler);
992 if (ret != napi_ok) {
993 MMI_HILOGE("napi_get_reference_value fail");
994 return BOOLEAN_NONE;
995 }
996 for (const auto &[_, monitor] : monitors_) {
997 napi_value tHandler { nullptr };
998 auto ret = napi_get_reference_value(env, monitor.callback_, &tHandler);
999 if (ret != napi_ok) {
1000 MMI_HILOGE("napi_get_reference_value fail");
1001 return BOOLEAN_NONE;
1002 }
1003 bool isEqual { false };
1004 ret = napi_strict_equals(env, sHandler, tHandler, &isEqual);
1005 if (ret != napi_ok) {
1006 MMI_HILOGE("napi_strict_equals fail");
1007 return BOOLEAN_NONE;
1008 }
1009 if (isEqual) {
1010 MMI_HILOGE("Callback already exist");
1011 return BOOLEAN_TRUE;
1012 }
1013 }
1014 return BOOLEAN_FALSE;
1015 }
1016
SubscribeKeyMonitor(napi_env env,KeyMonitor & keyMonitor)1017 bool JsInputConsumer::SubscribeKeyMonitor(napi_env env, KeyMonitor &keyMonitor)
1018 {
1019 auto hasSubscribed = HasSubscribed(env, keyMonitor);
1020 if (hasSubscribed < 0) {
1021 MMI_HILOGE("HasSubscribed fail");
1022 return false;
1023 }
1024 if (hasSubscribed) {
1025 MMI_HILOGE("Duplicate subscription of key monitor");
1026 return false;
1027 }
1028 auto keyMonitorId = GenerateId();
1029 auto subscriberId = InputManager::GetInstance()->SubscribeKeyMonitor(keyMonitor.keyOption_,
1030 [keyMonitorId](std::shared_ptr<KeyEvent> keyEvent) {
1031 JsInputConsumer::GetInstance()->OnSubscribeKeyMonitor(keyMonitorId, keyEvent);
1032 });
1033 if (subscriberId < 0) {
1034 if (subscriberId == -CAPABILITY_NOT_SUPPORTED) {
1035 MMI_HILOGE("Capability not supported");
1036 THROWERR_CUSTOM(env, INPUT_DEVICE_NOT_SUPPORTED, "Capability not supported.");
1037 } else if (subscriberId == -PARAM_INPUT_INVALID) {
1038 MMI_HILOGE("Input is invalid");
1039 THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "Input is invalid");
1040 } else {
1041 MMI_HILOGE("SubscribeKeyMonitor fail, error:%{public}d", subscriberId);
1042 }
1043 return false;
1044 }
1045 MMI_HILOGI("[NAPI] Subscribe key monitor(ID:%{public}zu, subscriberId:%{public}d)", keyMonitorId, subscriberId);
1046 keyMonitor.env_ = env;
1047 keyMonitor.subscriberId_ = subscriberId;
1048 monitors_.emplace(keyMonitorId, keyMonitor);
1049 return true;
1050 }
1051
UnsubscribeKeyMonitor(napi_env env,const KeyMonitor & keyMonitor)1052 void JsInputConsumer::UnsubscribeKeyMonitor(napi_env env, const KeyMonitor &keyMonitor)
1053 {
1054 for (auto mIter = monitors_.begin(); mIter != monitors_.end(); ++mIter) {
1055 auto identical = IsIdentical(env, keyMonitor, mIter->second);
1056 if (identical < 0) {
1057 MMI_HILOGE("IsIdentical fail");
1058 return;
1059 }
1060 if (identical) {
1061 auto &tMonitor = mIter->second;
1062 MMI_HILOGI("[NAPI] Unsubscribe key monitor(ID:%{public}zu, subscriberId:%{public}d)",
1063 mIter->first, tMonitor.subscriberId_);
1064 auto ret = InputManager::GetInstance()->UnsubscribeKeyMonitor(tMonitor.subscriberId_);
1065 if (ret == -CAPABILITY_NOT_SUPPORTED) {
1066 MMI_HILOGE("Capability not supported");
1067 THROWERR_CUSTOM(env, INPUT_DEVICE_NOT_SUPPORTED, "Capability not supported.");
1068 } else if (ret == -PARAM_INPUT_INVALID) {
1069 MMI_HILOGE("Input is invalid");
1070 THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "Input is invalid");
1071 } else if (ret != RET_OK) {
1072 MMI_HILOGE("UnsubscribeKeyMonitor fail, error:%{public}d", ret);
1073 }
1074 CleanupKeyMonitor(env, tMonitor);
1075 monitors_.erase(mIter);
1076 return;
1077 }
1078 }
1079 auto ret = InputManager::GetInstance()->UnsubscribeKeyMonitor(INVALID_SUBSCRIBER_ID);
1080 if (ret == -CAPABILITY_NOT_SUPPORTED) {
1081 MMI_HILOGE("Capability not supported");
1082 THROWERR_CUSTOM(env, INPUT_DEVICE_NOT_SUPPORTED, "Capability not supported.");
1083 } else {
1084 MMI_HILOGE("Input is invalid");
1085 THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "Input is invalid");
1086 }
1087 }
1088
UnsubscribeKeyMonitors(napi_env env)1089 void JsInputConsumer::UnsubscribeKeyMonitors(napi_env env)
1090 {
1091 if (monitors_.empty()) {
1092 auto ret = InputManager::GetInstance()->UnsubscribeKeyMonitor(INVALID_SUBSCRIBER_ID);
1093 if (ret == -CAPABILITY_NOT_SUPPORTED) {
1094 MMI_HILOGE("Capability not supported");
1095 THROWERR_CUSTOM(env, INPUT_DEVICE_NOT_SUPPORTED, "Capability not supported.");
1096 }
1097 return;
1098 }
1099 for (auto &[monitorId, monitor] : monitors_) {
1100 MMI_HILOGI("[NAPI] Unsubscribe key monitor(ID:%{public}zu, subscriberId:%{public}d)",
1101 monitorId, monitor.subscriberId_);
1102 auto ret = InputManager::GetInstance()->UnsubscribeKeyMonitor(monitor.subscriberId_);
1103 if (ret != RET_OK) {
1104 MMI_HILOGE("UnsubscribeKeyMonitor fail, error:%{public}d", ret);
1105 }
1106 CleanupKeyMonitor(env, monitor);
1107 }
1108 monitors_.clear();
1109 }
1110
OnSubscribeKeyMonitor(size_t keyMonitorId,std::shared_ptr<KeyEvent> keyEvent)1111 void JsInputConsumer::OnSubscribeKeyMonitor(size_t keyMonitorId, std::shared_ptr<KeyEvent> keyEvent)
1112 {
1113 CALL_DEBUG_ENTER;
1114 CHKPV(keyEvent);
1115 std::lock_guard guard(mutex_);
1116 auto mIter = monitors_.find(keyMonitorId);
1117 if (mIter == monitors_.end()) {
1118 MMI_HILOGE("No key monitor with ID(%{public}zu)", keyMonitorId);
1119 return;
1120 }
1121 auto &monitor = mIter->second;
1122 uv_loop_s *loop = nullptr;
1123 CHKRV(napi_get_uv_event_loop(monitor.env_, &loop), GET_UV_EVENT_LOOP);
1124
1125 auto work = std::make_shared<Work>();
1126 work->keyMonitorId_ = keyMonitorId;
1127 work->work_.data = work.get();
1128 work->keyEvent_ = keyEvent;
1129
1130 auto ret = uv_queue_work_with_qos(
1131 loop, &work->work_,
1132 [](uv_work_t *work) {
1133 MMI_HILOGD("uv_queue_work callback function is called");
1134 },
1135 JsInputConsumer::HandleKeyMonitor, uv_qos_user_initiated);
1136 if (ret != 0) {
1137 MMI_HILOGE("uv_queue_work_with_qos fail, error:%{public}d", ret);
1138 return;
1139 }
1140 pendingWorks_.emplace(&work->work_, work);
1141 }
1142
NotifyKeyMonitor(uv_work_t * work,int32_t status)1143 void JsInputConsumer::NotifyKeyMonitor(uv_work_t *work, int32_t status)
1144 {
1145 CALL_DEBUG_ENTER;
1146 std::lock_guard guard(mutex_);
1147 auto pwIter = pendingWorks_.find(work);
1148 if (pwIter == pendingWorks_.end()) {
1149 return;
1150 }
1151 auto keyMonitorId = pwIter->second->keyMonitorId_;
1152 auto keyEvent = pwIter->second->keyEvent_;
1153 pendingWorks_.erase(pwIter);
1154
1155 auto mIter = monitors_.find(keyMonitorId);
1156 if (mIter == monitors_.end()) {
1157 MMI_HILOGE("No key monitor with ID(%{public}zu)", keyMonitorId);
1158 return;
1159 }
1160 NotifyKeyMonitor(mIter->second, keyEvent);
1161 }
1162
NotifyKeyMonitor(const KeyMonitor & keyMonitor,std::shared_ptr<KeyEvent> keyEvent)1163 void JsInputConsumer::NotifyKeyMonitor(const KeyMonitor &keyMonitor, std::shared_ptr<KeyEvent> keyEvent)
1164 {
1165 napi_handle_scope scope { nullptr };
1166 napi_open_handle_scope(keyMonitor.env_, &scope);
1167 CHKPV(scope);
1168 NotifyKeyMonitorScoped(keyMonitor, keyEvent);
1169 napi_close_handle_scope(keyMonitor.env_, scope);
1170 }
1171
NotifyKeyMonitorScoped(const KeyMonitor & keyMonitor,std::shared_ptr<KeyEvent> keyEvent)1172 void JsInputConsumer::NotifyKeyMonitorScoped(const KeyMonitor &keyMonitor, std::shared_ptr<KeyEvent> keyEvent)
1173 {
1174 napi_value callback { nullptr };
1175 CHKRV(napi_get_reference_value(keyMonitor.env_, keyMonitor.callback_, &callback), GET_REFERENCE_VALUE);
1176 napi_value jsKeyEvent = JsInputConsumer::KeyEvent2JsKeyEvent(keyMonitor.env_, keyEvent);
1177 CHKPV(jsKeyEvent);
1178 napi_value result { nullptr };
1179 CHKRV(napi_call_function(keyMonitor.env_, nullptr, callback, 1, &jsKeyEvent, &result), CALL_FUNCTION);
1180 }
1181
CheckKeyMonitorOption(const KeyMonitorOption & keyOption)1182 bool JsInputConsumer::CheckKeyMonitorOption(const KeyMonitorOption &keyOption)
1183 {
1184 return ((allowedKeys_.find(keyOption.GetKey()) != allowedKeys_.cend()) &&
1185 (keyOption.GetAction() == KeyEvent::KEY_ACTION_DOWN));
1186 }
1187
KeyEvent2JsKeyEvent(napi_env env,std::shared_ptr<KeyEvent> keyEvent)1188 napi_value JsInputConsumer::KeyEvent2JsKeyEvent(napi_env env, std::shared_ptr<KeyEvent> keyEvent)
1189 {
1190 CHKPP(keyEvent);
1191 napi_value jsKeyEvent { nullptr };
1192 CHKRP(napi_create_object(env, &jsKeyEvent), CREATE_OBJECT);
1193
1194 SetNamedProperty(env, jsKeyEvent, std::string("id"), keyEvent->GetId());
1195 SetNamedProperty(env, jsKeyEvent, std::string("deviceId"), keyEvent->GetDeviceId());
1196 SetNamedProperty(env, jsKeyEvent, std::string("actionTime"), keyEvent->GetActionTime());
1197 SetNamedProperty(env, jsKeyEvent, std::string("screenId"), keyEvent->GetTargetDisplayId());
1198 SetNamedProperty(env, jsKeyEvent, std::string("windowId"), keyEvent->GetTargetWindowId());
1199 SetNamedProperty(env, jsKeyEvent, std::string("action"), KeyAction2JsKeyAction(keyEvent->GetKeyAction()));
1200
1201 auto keyItem = keyEvent->GetKeyItem();
1202 if (!keyItem) {
1203 MMI_HILOGE("No key item(No:%{public}d,KC:%{private}d)", keyEvent->GetId(), keyEvent->GetKeyCode());
1204 return nullptr;
1205 }
1206 napi_value jsKey = JsInputConsumer::KeyItem2JsKey(env, *keyItem);
1207 CHKPP(jsKey);
1208 CHKRP(napi_set_named_property(env, jsKeyEvent, "key", jsKey), SET_NAMED_PROPERTY);
1209 SetNamedProperty(env, jsKeyEvent, std::string("unicodeChar"), keyItem->GetUnicode());
1210
1211 napi_value jsKeys { nullptr };
1212 uint32_t index { 0 };
1213
1214 CHKRP(napi_create_array(env, &jsKeys), CREATE_ARRAY);
1215 auto keyItems = keyEvent->GetKeyItems();
1216
1217 for (const auto &keyItem : keyItems) {
1218 jsKey = JsInputConsumer::KeyItem2JsKey(env, keyItem);
1219 CHKPP(jsKey);
1220 CHKRP(napi_set_element(env, jsKeys, index++, jsKey), SET_ELEMENT);
1221 }
1222
1223 CHKRP(napi_set_named_property(env, jsKeyEvent, "keys", jsKeys), SET_NAMED_PROPERTY);
1224 SetNamedProperty(env, jsKeyEvent, std::string("ctrlKey"),
1225 (keyEvent->GetKeyItem(KeyEvent::KEYCODE_CTRL_LEFT) || keyEvent->GetKeyItem(KeyEvent::KEYCODE_CTRL_RIGHT)));
1226 SetNamedProperty(env, jsKeyEvent, std::string("altKey"),
1227 (keyEvent->GetKeyItem(KeyEvent::KEYCODE_ALT_LEFT) || keyEvent->GetKeyItem(KeyEvent::KEYCODE_ALT_RIGHT)));
1228 SetNamedProperty(env, jsKeyEvent, std::string("shiftKey"),
1229 (keyEvent->GetKeyItem(KeyEvent::KEYCODE_SHIFT_LEFT) || keyEvent->GetKeyItem(KeyEvent::KEYCODE_SHIFT_RIGHT)));
1230 SetNamedProperty(env, jsKeyEvent, std::string("logoKey"),
1231 (keyEvent->GetKeyItem(KeyEvent::KEYCODE_META_LEFT) || keyEvent->GetKeyItem(KeyEvent::KEYCODE_META_RIGHT)));
1232 SetNamedProperty(env, jsKeyEvent, std::string("fnKey"), keyEvent->GetKeyItem(KeyEvent::KEYCODE_FN).has_value());
1233 SetNamedProperty(env, jsKeyEvent, std::string("capsLock"),
1234 keyEvent->GetFunctionKey(KeyEvent::CAPS_LOCK_FUNCTION_KEY));
1235 SetNamedProperty(env, jsKeyEvent, std::string("numLock"),
1236 keyEvent->GetFunctionKey(KeyEvent::NUM_LOCK_FUNCTION_KEY));
1237 SetNamedProperty(env, jsKeyEvent, std::string("scrollLock"),
1238 keyEvent->GetFunctionKey(KeyEvent::SCROLL_LOCK_FUNCTION_KEY));
1239 return jsKeyEvent;
1240 }
1241
KeyItem2JsKey(napi_env env,const KeyEvent::KeyItem & keyItem)1242 napi_value JsInputConsumer::KeyItem2JsKey(napi_env env, const KeyEvent::KeyItem &keyItem)
1243 {
1244 napi_value jsKey { nullptr };
1245 CHKRP(napi_create_object(env, &jsKey), CREATE_OBJECT);
1246 SetNamedProperty(env, jsKey, std::string("code"), keyItem.GetKeyCode());
1247 SetNamedProperty(env, jsKey, std::string("pressedTime"), keyItem.GetDownTime());
1248 SetNamedProperty(env, jsKey, std::string("deviceId"), keyItem.GetDeviceId());
1249 return jsKey;
1250 }
1251
HandleKeyMonitor(uv_work_t * work,int32_t status)1252 void JsInputConsumer::HandleKeyMonitor(uv_work_t *work, int32_t status)
1253 {
1254 JsInputConsumer::GetInstance()->NotifyKeyMonitor(work, status);
1255 }
1256
JsKeyAction2KeyAction(int32_t action)1257 int32_t JsInputConsumer::JsKeyAction2KeyAction(int32_t action)
1258 {
1259 static const std::map<int32_t, int32_t> keyActionMap {
1260 { JsKeyAction::JS_KEY_ACTION_CANCEL, KeyEvent::KEY_ACTION_CANCEL },
1261 { JsKeyAction::JS_KEY_ACTION_DOWN, KeyEvent::KEY_ACTION_DOWN },
1262 { JsKeyAction::JS_KEY_ACTION_UP, KeyEvent::KEY_ACTION_UP },
1263 };
1264 if (auto iter = keyActionMap.find(action); iter != keyActionMap.cend()) {
1265 return iter->second;
1266 } else {
1267 return KeyEvent::KEY_ACTION_UNKNOWN;
1268 }
1269 }
1270
KeyAction2JsKeyAction(int32_t action)1271 int32_t JsInputConsumer::KeyAction2JsKeyAction(int32_t action)
1272 {
1273 static const std::map<int32_t, int32_t> keyActionMap {
1274 { KeyEvent::KEY_ACTION_CANCEL, JsKeyAction::JS_KEY_ACTION_CANCEL },
1275 { KeyEvent::KEY_ACTION_DOWN, JsKeyAction::JS_KEY_ACTION_DOWN },
1276 { KeyEvent::KEY_ACTION_UP, JsKeyAction::JS_KEY_ACTION_UP },
1277 };
1278 if (auto iter = keyActionMap.find(action); iter != keyActionMap.cend()) {
1279 return iter->second;
1280 } else {
1281 return JsKeyAction::JS_KEY_ACTION_CANCEL;
1282 }
1283 }
1284
1285 EXTERN_C_START
MmiInit(napi_env env,napi_value exports)1286 static napi_value MmiInit(napi_env env, napi_value exports)
1287 {
1288 CALL_DEBUG_ENTER;
1289 napi_property_descriptor desc[] = {
1290 DECLARE_NAPI_FUNCTION("on", JsOn),
1291 DECLARE_NAPI_FUNCTION("off", JsOff),
1292 DECLARE_NAPI_FUNCTION("setShieldStatus", SetShieldStatus),
1293 DECLARE_NAPI_FUNCTION("getShieldStatus", GetShieldStatus),
1294 DECLARE_NAPI_FUNCTION("getAllSystemHotkeys", GetAllSystemHotkeys)
1295 };
1296 NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc));
1297 if (CreateShieldMode(env, exports) == nullptr) {
1298 THROWERR(env, "Failed to create shield mode");
1299 return nullptr;
1300 }
1301 return exports;
1302 }
1303 EXTERN_C_END
1304
1305 static napi_module mmiModule = {
1306 .nm_version = 1,
1307 .nm_flags = 0,
1308 .nm_filename = nullptr,
1309 .nm_register_func = MmiInit,
1310 .nm_modname = "multimodalInput.inputConsumer",
1311 .nm_priv = ((void*)0),
1312 .reserved = { 0 },
1313 };
1314
RegisterModule(void)1315 extern "C" __attribute__((constructor)) void RegisterModule(void)
1316 {
1317 napi_module_register(&mmiModule);
1318 }
1319 } // namespace MMI
1320 } // namespace OHOS
1321