• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  /*
2  * Copyright (c) 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_consumer.h"
17 #include <iostream>
18 
19 #include "define_multimodal.h"
20 #include "napi_constants.h"
21 #include "mmi_log.h"
22 #include "input_manager.h"
23 
24 
25 #undef MMI_LOG_TAG
26 #define MMI_LOG_TAG "AniInputConsumer"
27 
28 using namespace OHOS::MMI;
29 
30 namespace {
31 constexpr int32_t ANI_SCOPE_SIZE = 16;
32 constexpr int32_t MILLISECOND_FACTOR = 1000;
33 constexpr size_t PRE_KEYS_SIZE { 4 };
34 const double INT32_MAX_D = static_cast<double>(std::numeric_limits<int32_t>::max());
35 } // namespace
36 
37 static Callbacks callbacks = {};
38 static std::mutex sCallBacksMutex;
39 
~KeyEventMonitorInfo()40 KeyEventMonitorInfo::~KeyEventMonitorInfo()
41 {
42     if (env == nullptr) {
43         return;
44     }
45     if (callback != nullptr) {
46         env->GlobalReference_Delete(callback);
47     }
48     if (keyOptionsObj != nullptr) {
49         env->GlobalReference_Delete(keyOptionsObj);
50     }
51     callback = nullptr;
52     keyOptionsObj = nullptr;
53 }
54 
CreateAniError(ani_env * env,std::string && errMsg)55 static ani_error CreateAniError(ani_env *env, std::string &&errMsg)
56 {
57     static const char *errorClsName = "Lescompat/Error;";
58     ani_class cls {};
59     if (ANI_OK != env->FindClass(errorClsName, &cls)) {
60         MMI_HILOGE("%{public}s: Not found namespace %{public}s.", __func__, errorClsName);
61         return nullptr;
62     }
63     ani_method ctor;
64     if (ANI_OK != env->Class_FindMethod(cls, "<ctor>", "Lstd/core/String;:V", &ctor)) {
65         MMI_HILOGE("%{public}s: Not found <ctor> in %{public}s.", __func__, errorClsName);
66         return nullptr;
67     }
68     ani_string error_msg;
69     env->String_NewUTF8(errMsg.c_str(), 17U, &error_msg);
70     ani_object errorObject;
71     env->Object_New(cls, ctor, &errorObject, error_msg);
72     return static_cast<ani_error>(errorObject);
73 }
74 
GetIsRepeat(ani_env * env,ani_object keyOptionsObj)75 static std::optional<bool> GetIsRepeat(ani_env *env, ani_object keyOptionsObj)
76 {
77     ani_ref aniRef;
78     if (ANI_OK != env->Object_GetPropertyByName_Ref(keyOptionsObj, "isRepeat", &aniRef)) {
79         MMI_HILOGE("%{public}s: Object_GetPropertyByName_Ref isRepeat failed.", __func__);
80         return std::nullopt;
81     }
82 
83     ani_boolean isUndefined;
84     if (ANI_OK != env->Reference_IsUndefined(aniRef, &isUndefined)) {
85         MMI_HILOGE("%{public}s: Object_GetFieldByName_Ref isRepeat failed.", __func__);
86         return std::nullopt;
87     }
88 
89     if (isUndefined) {
90         MMI_HILOGE("%{public}s: Param 'isRepeat' is undefined.", __func__);
91         return std::nullopt;
92     }
93 
94     ani_boolean isRepeat;
95     auto ret = env->Object_CallMethodByName_Boolean(static_cast<ani_object>(aniRef), "unboxed", nullptr, &isRepeat);
96     if (ret != ANI_OK) {
97         MMI_HILOGE("%{public}s: Object_CallMethodByName_Boolean failed.", __func__);
98         return std::nullopt;
99     }
100     return static_cast<bool>(isRepeat);
101 }
102 
AniStringToString(ani_env * env,ani_string aniStr)103 static std::string AniStringToString(ani_env *env, ani_string aniStr)
104 {
105     ani_size strSize;
106     env->String_GetUTF8Size(aniStr, &strSize);
107 
108     std::vector<char> buffer(strSize + 1);
109     char* utf8Buffer = buffer.data();
110 
111     ani_size bytes_written = 0;
112     env->String_GetUTF8(aniStr, utf8Buffer, strSize + 1, &bytes_written);
113 
114     utf8Buffer[bytes_written] = '\0';
115     std::string content = std::string(utf8Buffer);
116     return content;
117 }
118 
GetPreKeys(ani_env * env,ani_object keyOptionsObj,std::set<int32_t> & preKeys)119 static bool GetPreKeys(ani_env *env, ani_object keyOptionsObj, std::set<int32_t> &preKeys)
120 {
121     CALL_DEBUG_ENTER;
122     ani_ref ref;
123     if (ANI_OK != env->Object_GetPropertyByName_Ref(keyOptionsObj, "preKeys", &ref)) {
124         MMI_HILOGE("Object_GetPropertyByName_Ref Failed");
125         return false;
126     }
127     ani_object arrayObj = static_cast<ani_object>(ref);
128     ani_double length;
129     if (ANI_OK != env->Object_GetPropertyByName_Double(arrayObj, "length", &length)) {
130         MMI_HILOGE("Object_GetPropertyByName_Double length Failed");
131         return false;
132     }
133     for (int i = 0; i < int(length); i++) {
134         ani_ref intArrayRef;
135         if (ANI_OK != env->Object_CallMethodByName_Ref(arrayObj, "$_get", "I:Lstd/core/Object;", &intArrayRef,
136             (ani_int)i)) {
137             MMI_HILOGE("Object_GetPropertyByName_Ref Failed");
138             return false;
139         }
140         ani_double doubleEntry;
141         if (ANI_OK != env->Object_CallMethodByName_Double(static_cast<ani_object>(intArrayRef), "unboxed", nullptr,
142             &doubleEntry)) {
143             MMI_HILOGE("Object_CallMethodByName_Double unbox Failed");
144             return false;
145         }
146         if (doubleEntry > INT32_MAX_D || doubleEntry < 0) {
147             ani_error error = CreateAniError(env, "preKeys must be between 0 and INT32_MAX");
148             env->ThrowError(error);
149             MMI_HILOGE("preKey:%{public}f is less 0 or greater than INT32_MAX, can not process", doubleEntry);
150             return false;
151         }
152         if (!preKeys.insert(static_cast<int32_t>(doubleEntry)).second) {
153             MMI_HILOGE("Params insert value failed");
154             return false;
155         }
156     }
157     return true;
158 }
159 
GenerateEventType(std::shared_ptr<KeyOption> & keyOptionPtr)160 static std::string GenerateEventType(std::shared_ptr<KeyOption> &keyOptionPtr)
161 {
162     CALL_DEBUG_ENTER;
163     std::string eventType;
164     for (const auto &preKey : keyOptionPtr->GetPreKeys()) {
165         eventType = eventType + std::to_string(preKey) + ",";
166     }
167     eventType = eventType + std::to_string(keyOptionPtr->GetFinalKey()) + "," +
168         std::to_string(keyOptionPtr->IsFinalKeyDown()) + "," +
169         std::to_string(keyOptionPtr->GetFinalKeyDownDuration()) + "," +
170         std::to_string(keyOptionPtr->IsRepeat());
171     return eventType;
172 }
173 
ParseKeyOptions(ani_env * env,ani_object keyOptionsObj)174 static std::shared_ptr<KeyOption> ParseKeyOptions(ani_env *env, ani_object keyOptionsObj)
175 {
176     CALL_DEBUG_ENTER;
177     std::shared_ptr<KeyOption> keyOptionPtr = std::make_shared<KeyOption>();
178 
179     std::set<int32_t> preKeys;
180     if (!GetPreKeys(env, keyOptionsObj, preKeys) || preKeys.size() > PRE_KEYS_SIZE) {
181         MMI_HILOGE("PreKeys is invalid");
182         ani_error error = CreateAniError(env, "PreKeys is invalid");
183         env->ThrowError(error);
184         return nullptr;
185     }
186     keyOptionPtr->SetPreKeys(preKeys);
187 
188     ani_double finalKey;
189     if (ANI_OK != env->Object_GetPropertyByName_Double(keyOptionsObj, "finalKey", &finalKey)) {
190         MMI_HILOGE("Object_GetPropertyByName_Double finalKey Failed");
191         return nullptr;
192     }
193     if (finalKey > INT32_MAX_D || finalKey < 0) {
194         MMI_HILOGE("finalKey:%{private}f is less 0 or greater than INT32_MAX, can not process", finalKey);
195         ani_error error = CreateAniError(env, "finalKey must be between 0 and INT32_MAX");
196         env->ThrowError(error);
197         return nullptr;
198     }
199     keyOptionPtr->SetFinalKey(static_cast<int32_t>(finalKey));
200 
201     ani_boolean isFinalKeyDown;
202     if (ANI_OK != env->Object_GetPropertyByName_Boolean(keyOptionsObj, "isFinalKeyDown", &isFinalKeyDown)) {
203         MMI_HILOGE("Object_GetPropertyByName_Boolean isFinalKeyDown Failed");
204         return nullptr;
205     }
206     keyOptionPtr->SetFinalKeyDown(static_cast<bool>(isFinalKeyDown));
207 
208     ani_double finalKeyDownDuration;
209     if (ANI_OK != env->Object_GetPropertyByName_Double(keyOptionsObj, "finalKeyDownDuration", &finalKeyDownDuration)) {
210         MMI_HILOGE("Object_GetPropertyByName_Double finalKeyDownDuration Failed");
211         return nullptr;
212     }
213     if (finalKeyDownDuration > INT32_MAX_D || finalKeyDownDuration < 0) {
214         MMI_HILOGE("finalKeyDownDuration:%{public}f is less 0 or greater INT32_MAX", finalKeyDownDuration);
215         ani_error error = CreateAniError(env, "finalKeyDownDuration must be between 0 and INT32_MAX");
216         env->ThrowError(error);
217         return nullptr;
218     }
219     keyOptionPtr->SetFinalKeyDownDuration(static_cast<int32_t>(finalKeyDownDuration));
220 
221     bool isRepeat = true;
222     auto isRepeatOpt = GetIsRepeat(env, keyOptionsObj);
223     if (isRepeatOpt.has_value()) {
224         isRepeat = isRepeatOpt.value();
225     }
226     keyOptionPtr->SetRepeat(isRepeat);
227 
228     return keyOptionPtr;
229 }
230 
IsMatchKeyAction(bool isFinalKeydown,int32_t keyAction)231 static bool IsMatchKeyAction(bool isFinalKeydown, int32_t keyAction)
232 {
233     CALL_DEBUG_ENTER;
234     MMI_HILOGD("isFinalKeydown:%{public}d, keyAction:%{public}d", isFinalKeydown, keyAction);
235     if (isFinalKeydown && keyAction == KeyEvent::KEY_ACTION_DOWN) {
236         return true;
237     }
238     if (!isFinalKeydown && keyAction == KeyEvent::KEY_ACTION_UP) {
239         return true;
240     }
241     MMI_HILOGE("isFinalKeydown not matched with keyAction");
242     return false;
243 }
244 
MatchCombinationKey(KeyOption & combinationKeyOption,KeyEvent & keyEvent)245 static bool MatchCombinationKey(KeyOption &combinationKeyOption, KeyEvent &keyEvent)
246 {
247     CALL_DEBUG_ENTER;
248     std::vector<KeyEvent::KeyItem> items = keyEvent.GetKeyItems();
249     int32_t infoFinalKey = combinationKeyOption.GetFinalKey();
250     int32_t keyEventFinalKey = keyEvent.GetKeyCode();
251     bool isFinalKeydown = combinationKeyOption.IsFinalKeyDown();
252     MMI_HILOGD("InfoFinalKey:%{private}d,keyEventFinalKey:%{private}d,isFinalKeydown:%{public}d",
253         infoFinalKey, keyEventFinalKey, isFinalKeydown);
254     if (infoFinalKey != keyEventFinalKey || items.size() > PRE_KEYS_SIZE ||
255         !IsMatchKeyAction(isFinalKeydown, keyEvent.GetKeyAction())) {
256         MMI_HILOGD("key Param invalid");
257         return false;
258     }
259 
260     std::set<int32_t> preKeys = combinationKeyOption.GetPreKeys();
261     int32_t infoSize = std::count_if(preKeys.begin(), preKeys.end(), [](int32_t preKey) { return preKey >= 0; });
262     int32_t count = 0;
263     for (const auto &item : items) {
264         if (item.GetKeyCode() == keyEventFinalKey) {
265             continue;
266         }
267         auto iter = find(preKeys.begin(), preKeys.end(), item.GetKeyCode());
268         if (iter == preKeys.end()) {
269             MMI_HILOGW("No keyCode in preKeys");
270             return false;
271         }
272         count++;
273     }
274     MMI_HILOGD("kevEventSize:%{public}d, infoSize:%{public}d", count, infoSize);
275     std::optional<KeyEvent::KeyItem> keyItem = keyEvent.GetKeyItem();
276     if (!keyItem) {
277         MMI_HILOGE("The keyItem is nullopt");
278         return false;
279     }
280     auto downTime = keyItem->GetDownTime();
281     auto upTime = keyEvent.GetActionTime();
282     auto curDurationTime = combinationKeyOption.GetFinalKeyDownDuration();
283     if (curDurationTime > 0 && (upTime - downTime >= (static_cast<int64_t>(curDurationTime) * MILLISECOND_FACTOR))) {
284         MMI_HILOGE("Skip, upTime - downTime >= duration");
285         return false;
286     }
287     return count == infoSize;
288 }
289 
SendEventToMainThread(const std::function<void ()> func)290 static bool SendEventToMainThread(const std::function<void()> func)
291 {
292     CALL_DEBUG_ENTER;
293     if (func == nullptr) {
294         MMI_HILOGE("%{public}s: func == nullptr", __func__);
295         return false;
296     }
297     auto runner = OHOS::AppExecFwk::EventRunner::GetMainEventRunner();
298     if (!runner) {
299         MMI_HILOGE("%{public}s: runner == nullptr", __func__);
300         return false;
301     }
302     auto handler = std::make_shared<OHOS::AppExecFwk::EventHandler>(runner);
303     handler->PostTask(func, "", 0, OHOS::AppExecFwk::EventQueue::Priority::HIGH, {});
304     MMI_HILOGD("%{public}s: PostTask success", __func__);
305     return true;
306 }
307 
IsInstanceOf(ani_env * env,const std::string & cls_name,ani_object obj)308 static ani_boolean IsInstanceOf(ani_env *env, const std::string &cls_name, ani_object obj)
309 {
310     ani_class cls;
311     if (ANI_OK != env->FindClass(cls_name.c_str(), &cls)) {
312         MMI_HILOGE("%{public}s: FindClass failed", __func__);
313         return ANI_FALSE;
314     }
315 
316     ani_boolean ret;
317     env->Object_InstanceOf(obj, cls, &ret);
318     return ret;
319 }
320 
EmitAsyncCallbackWork(std::shared_ptr<KeyEventMonitorInfo> reportEvent)321 static void EmitAsyncCallbackWork(std::shared_ptr<KeyEventMonitorInfo> reportEvent)
322 {
323     CALL_DEBUG_ENTER;
324     CHKPV(reportEvent);
325     auto task = [reportEvent]() {
326         MMI_HILOGD("%{public}s: Begin to call task", __func__);
327         ani_size nrRefs = ANI_SCOPE_SIZE;
328         AniLocalScopeGuard aniLocalScopeGuard(reportEvent->env, nrRefs);
329         if (!aniLocalScopeGuard.IsStatusOK()) {
330             MMI_HILOGE("%{public}s: CreateLocalScope failed", __func__);
331             return;
332         }
333         auto fnObj = reinterpret_cast<ani_fn_object>(reportEvent->callback);
334         std::vector<ani_ref> args = {reportEvent->keyOptionsObj};
335         ani_ref result;
336         MMI_HILOGD("%{public}s: Begin to call FunctionalObject_Call", __func__);
337         if (fnObj == nullptr || args.size() == 0) {
338             MMI_HILOGE("%{public}s: fnObj == nullptr", __func__);
339             return;
340         }
341         if (IsInstanceOf(reportEvent->env, "Lstd/core/Function1;", fnObj) == 0) {
342             MMI_HILOGE("%{public}s: fnObj is not instance Of function  ", __func__);
343             return;
344         }
345         const std::string className = "L@ohos/multimodalInput/inputConsumer/inputConsumer/KeyOptions;";
346         if (IsInstanceOf(reportEvent->env, className, static_cast<ani_object>(reportEvent->keyOptionsObj)) == 0) {
347             MMI_HILOGE("%{public}s: keyOptionsObj is not instance Of KeyOptions class", __func__);
348             return;
349         }
350 
351         if (ANI_OK != reportEvent->env->FunctionalObject_Call(fnObj, 1, args.data(), &result)) {
352             MMI_HILOGE("%{public}s: FunctionalObject_Call failed", __func__);
353             return;
354         }
355         MMI_HILOGD("%{public}s: FunctionalObject_Call success", __func__);
356     };
357     if (!SendEventToMainThread(task)) {
358         MMI_HILOGE("%{public}s: failed to send event", __func__);
359     }
360 }
361 
SubKeyEventCallback(std::shared_ptr<KeyEvent> keyEvent)362 static void SubKeyEventCallback(std::shared_ptr<KeyEvent> keyEvent)
363 {
364     CALL_DEBUG_ENTER;
365     CHKPV(keyEvent);
366     std::lock_guard guard(sCallBacksMutex);
367     auto iter = callbacks.begin();
368     while (iter != callbacks.end()) {
369         auto &list = iter->second;
370         ++iter;
371         MMI_HILOGD("list size:%{public}zu", list.size());
372         auto infoIter = list.begin();
373         while (infoIter != list.end()) {
374             auto monitorInfo = *infoIter;
375             if (MatchCombinationKey(*(monitorInfo->keyOption), *keyEvent)) {
376                 MMI_HILOGD("MatchCombinationKey success");
377                 EmitAsyncCallbackWork(monitorInfo);
378             }
379             ++infoIter;
380         }
381     }
382 }
383 
GetPreSubscribeId(const std::shared_ptr<KeyEventMonitorInfo> & event)384 static int32_t GetPreSubscribeId(const std::shared_ptr<KeyEventMonitorInfo> &event)
385 {
386     CHKPR(event, ERROR_NULL_POINTER);
387     std::lock_guard guard(sCallBacksMutex);
388     auto it = callbacks.find(event->eventType);
389     if (it == callbacks.end() || it->second.empty()) {
390         MMI_HILOGE("The callbacks is empty");
391         return JS_CALLBACK_EVENT_FAILED;
392     }
393     CHKPR(it->second.front(), ERROR_NULL_POINTER);
394     return it->second.front()->subscribeId;
395 }
396 
CheckCallbackEqual(ani_env * env,ani_ref fnRef,ani_env * iterEnv,ani_ref iterFn)397 static bool CheckCallbackEqual(ani_env *env, ani_ref fnRef, ani_env *iterEnv, ani_ref iterFn)
398 {
399     if (env != iterEnv) {
400         MMI_HILOGD("%{public}s: not the same env", __func__);
401         return false;
402     }
403     ani_boolean isEquals = false;
404     if (ANI_OK != env->Reference_StrictEquals(fnRef, iterFn, &isEquals)) {
405         MMI_HILOGD("%{public}s: check observer equal failed!", __func__);
406         return false;
407     }
408     return isEquals;
409 }
410 
AddEventCallback(std::shared_ptr<KeyEventMonitorInfo> event)411 static int32_t AddEventCallback(std::shared_ptr<KeyEventMonitorInfo> event)
412 {
413     CALL_DEBUG_ENTER;
414     std::lock_guard guard(sCallBacksMutex);
415     CHKPR(event, ERROR_NULL_POINTER);
416     if (callbacks.find(event->eventType) == callbacks.end()) {
417         MMI_HILOGD("No callback in %{public}s", event->eventType.c_str());
418         callbacks[event->eventType] = {};
419     }
420 
421     auto it = callbacks.find(event->eventType);
422     for (const auto &iter: it->second) {
423         if (CheckCallbackEqual(event->env, event->callback, iter->env, iter->callback)) {
424             MMI_HILOGE("Callback already exist");
425             return JS_CALLBACK_EVENT_FAILED;
426         }
427     }
428     it->second.push_back(event);
429     return JS_CALLBACK_EVENT_SUCCESS;
430 }
431 
SubscribeKey(ani_env * env,std::shared_ptr<KeyEventMonitorInfo> & event)432 static int32_t SubscribeKey(ani_env *env, std::shared_ptr<KeyEventMonitorInfo> &event)
433 {
434     CALL_DEBUG_ENTER;
435     std::string subKeyNames = "";
436     auto keyOptionsPtr = ParseKeyOptions(env, static_cast<ani_object>(event->keyOptionsObj));
437     if (keyOptionsPtr == nullptr) {
438         MMI_HILOGE("keyOptionsPtr is nullptr");
439         return ERROR_CODE;
440     }
441     event->keyOption = keyOptionsPtr;
442     event->eventType = GenerateEventType(keyOptionsPtr);
443 
444     int32_t preSubscribeId = GetPreSubscribeId(event);
445     if (preSubscribeId >= 0) {
446         event->subscribeId = preSubscribeId;
447         return AddEventCallback(event);
448     }
449 
450     MMI_HILOGD("EventType:%{private}s, eventName:%{public}s", event->eventType.c_str(), event->name.c_str());
451     int32_t subscribeId = -1;
452     subscribeId = InputManager::GetInstance()->SubscribeKeyEvent(event->keyOption, SubKeyEventCallback);
453     if (subscribeId < 0) {
454         MMI_HILOGE("SubscribeId invalid:%{public}d", subscribeId);
455         return subscribeId;
456     }
457     MMI_HILOGD("SubscribeId:%{public}d", subscribeId);
458     event->subscribeId = subscribeId;
459     return AddEventCallback(event);
460 }
461 
On(ani_env * env,ani_string strObj,ani_object keyOptionsObj,ani_object callback)462 static void On([[maybe_unused]] ani_env *env, ani_string strObj, ani_object keyOptionsObj, ani_object callback)
463 {
464     CALL_DEBUG_ENTER;
465     std::shared_ptr<KeyEventMonitorInfo> event = std::make_shared<KeyEventMonitorInfo>();
466     event->env = env;
467     if (ANI_OK != env->GlobalReference_Create(callback, &event->callback)) {
468         MMI_HILOGE("Create global reference 'callback' failed");
469         return;
470     }
471     if (ANI_OK != env->GlobalReference_Create(keyOptionsObj, &event->keyOptionsObj)) {
472         MMI_HILOGE("Create global reference 'keyOptionsObj' failed");
473         return;
474     }
475 
476     std::string keyType = AniStringToString(env, strObj);
477     event->name = keyType;
478 
479     if (keyType == HOTKEY_SUBSCRIBE_TYPE) {
480         MMI_HILOGD("%{public}s: Enter Hotkey.", __func__);
481     } else if (keyType == SUBSCRIBE_TYPE) {
482         int32_t ret = SubscribeKey(env, event);
483         MMI_HILOGD("%{public}s: Call SubscribeKey end ret = %{public}d", __func__, ret);
484     } else {
485         MMI_HILOGE("Type is not key or hotkey");
486         ani_error error = CreateAniError(env, "Type must be key or hotkeyChange");
487         env->ThrowError(error);
488     }
489 }
490 
DelEventCallbackRef(ani_env * env,std::list<std::shared_ptr<KeyEventMonitorInfo>> & info,ani_ref handler,int32_t & subscribeId)491 static int32_t DelEventCallbackRef(ani_env *env, std::list<std::shared_ptr<KeyEventMonitorInfo>> &info,
492     ani_ref handler, int32_t &subscribeId)
493 {
494     CALL_DEBUG_ENTER;
495     for (auto iter = info.begin(); iter != info.end();) {
496         if (*iter == nullptr) {
497             info.erase(iter++);
498             continue;
499         }
500         if (handler != nullptr) {
501             if (!CheckCallbackEqual(env, handler, (*iter)->env, (*iter)->callback)) {
502                 ++iter;
503                 continue;
504             }
505             std::shared_ptr<KeyEventMonitorInfo> monitorInfo = *iter;
506             info.erase(iter++);
507             if (info.empty()) {
508                 subscribeId = monitorInfo->subscribeId;
509             }
510             MMI_HILOGD("Callback has deleted, size:%{public}zu", info.size());
511             return JS_CALLBACK_EVENT_SUCCESS;
512         }
513         std::shared_ptr<KeyEventMonitorInfo> monitorInfo = *iter;
514         info.erase(iter++);
515         if (info.empty()) {
516             subscribeId = monitorInfo->subscribeId;
517         }
518         MMI_HILOGD("Callback has deleted, size:%{public}zu", info.size());
519     }
520     MMI_HILOGD("Callback size:%{public}zu", info.size());
521     return JS_CALLBACK_EVENT_SUCCESS;
522 }
523 
DelEventCallback(std::shared_ptr<KeyEventMonitorInfo> & event,int32_t & subscribeId)524 static int32_t DelEventCallback(std::shared_ptr<KeyEventMonitorInfo> &event, int32_t &subscribeId)
525 {
526     CALL_DEBUG_ENTER;
527     std::lock_guard guard(sCallBacksMutex);
528     CHKPR(event, ERROR_NULL_POINTER);
529     if (callbacks.count(event->eventType) <= 0) {
530         MMI_HILOGE("Callback doesn't exists, eventType:%{private}s", event->eventType.c_str());
531         return JS_CALLBACK_EVENT_FAILED;
532     }
533     auto &info = callbacks[event->eventType];
534     MMI_HILOGD("EventType:%{public}s, keyEventMonitorInfos:%{public}zu", event->eventType.c_str(), info.size());
535 
536     return DelEventCallbackRef(event->env, info, event->callback, subscribeId);
537 }
538 
Off(ani_env * env,ani_string strObj,ani_object keyOptionsObj,ani_object callback)539 static void Off([[maybe_unused]] ani_env *env, ani_string strObj, ani_object keyOptionsObj, ani_object callback)
540 {
541     CALL_DEBUG_ENTER;
542     std::shared_ptr<KeyEventMonitorInfo> event = std::make_shared<KeyEventMonitorInfo>();
543     event->env = env;
544     if (ANI_OK != env->GlobalReference_Create(keyOptionsObj, &event->keyOptionsObj)) {
545         MMI_HILOGE("Call GlobalReference_Create failed");
546         return;
547     }
548 
549     ani_boolean isUndefined;
550     if (ANI_OK != env->Reference_IsUndefined(callback, &isUndefined)) {
551         MMI_HILOGE("Call Reference_IsUndefined failed");
552         return;
553     }
554     if (isUndefined) {
555         MMI_HILOGD("%{public}s: callback is undefined", __func__);
556         event->callback = nullptr;
557     } else {
558         if (ANI_OK != env->GlobalReference_Create(callback, &event->callback)) {
559             MMI_HILOGE("%{public}s: Create global reference 'callback' failed", __func__);
560             return;
561         }
562     }
563 
564     std::string keyType = AniStringToString(env, strObj);
565     event->name = keyType;
566     int32_t subscribeId = -1;
567     if (keyType == HOTKEY_SUBSCRIBE_TYPE) {
568         MMI_HILOGD("%{public}s: Enter Hotkey.", __func__);
569     } else if (keyType == SUBSCRIBE_TYPE) {
570         std::string subKeyNames = "";
571         auto keyOptionsPtr = ParseKeyOptions(env, static_cast<ani_object>(event->keyOptionsObj));
572         if (keyOptionsPtr == nullptr) {
573             MMI_HILOGE("%{public}s: ParseKeyOptions failed", __func__);
574             return;
575         }
576         event->keyOption = keyOptionsPtr;
577         event->eventType = GenerateEventType(keyOptionsPtr);
578         if (DelEventCallback(event, subscribeId) < 0) {
579             MMI_HILOGE("DelEventCallback failed");
580             return;
581         }
582         MMI_HILOGI("Unsubscribe key event(%{public}d)", subscribeId);
583         InputManager::GetInstance()->UnsubscribeKeyEvent(subscribeId);
584     } else {
585         MMI_HILOGE("Type is not key or hotkey");
586         ani_error error = CreateAniError(env, "Type must be key or hotkeyChange");
587         env->ThrowError(error);
588     }
589 }
590 
ANI_Constructor(ani_vm * vm,uint32_t * result)591 ANI_EXPORT ani_status ANI_Constructor(ani_vm *vm, uint32_t *result)
592 {
593     ani_env *env;
594     if (ANI_OK != vm->GetEnv(ANI_VERSION_1, &env)) {
595         MMI_HILOGE("%{public}s: Unsupported ANI_VERSION_1", __func__);
596         return ANI_ERROR;
597     }
598 
599     static const char *name = "L@ohos/multimodalInput/inputConsumer/inputConsumer;";
600     ani_namespace ns;
601     if (ANI_OK != env->FindNamespace(name, &ns)) {
602         MMI_HILOGE("%{public}s: Not found %{public}s", __func__, name);
603         return ANI_NOT_FOUND;
604     }
605 
606     std::array methods = {
607         ani_native_function {"on", nullptr, reinterpret_cast<void *>(On)},
608         ani_native_function {"off", nullptr, reinterpret_cast<void *>(Off)},
609     };
610 
611     if (ANI_OK != env->Namespace_BindNativeFunctions(ns, methods.data(), methods.size())) {
612         MMI_HILOGE("%{public}s:Cannot bind native methods to '%{public}s'", __func__, name);
613         return ANI_ERROR;
614     };
615 
616     *result = ANI_VERSION_1;
617     return ANI_OK;
618 }