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 }