• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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