• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "js_input_monitor_manager.h"
17 
18 #include "define_multimodal.h"
19 #include "napi_constants.h"
20 #include "util_napi_error.h"
21 
22 #undef MMI_LOG_TAG
23 #define MMI_LOG_TAG "JsInputMonitorManager"
24 
25 namespace OHOS {
26 namespace MMI {
27 namespace {
28 constexpr int32_t MONITOR_REGISTER_EXCEED_MAX { 4100001 };
29 } // namespace
30 static const std::vector<int32_t> supportedKeyCodes = {
31     KeyEvent::KEYCODE_POWER,
32     KeyEvent::KEYCODE_META_LEFT,
33     KeyEvent::KEYCODE_VOLUME_UP,
34     KeyEvent::KEYCODE_VOLUME_DOWN,
35     KeyEvent::KEYCODE_META_RIGHT
36 };
37 
GetInstance()38 JsInputMonitorManager& JsInputMonitorManager::GetInstance()
39 {
40     static JsInputMonitorManager instance;
41     return instance;
42 }
43 
AddMonitor(napi_env jsEnv,const std::string & typeName,std::vector<Rect> hotRectArea,int32_t rectTotal,napi_value callback,const int32_t fingers)44 void JsInputMonitorManager::AddMonitor(napi_env jsEnv, const std::string &typeName,
45     std::vector<Rect> hotRectArea, int32_t rectTotal, napi_value callback, const int32_t fingers)
46 {
47     CALL_DEBUG_ENTER;
48     std::lock_guard<std::mutex> guard(mutex_);
49     for (const auto &item : monitors_) {
50         if ((item != nullptr) && (item->IsMatch(jsEnv, callback) != RET_ERR)) {
51             MMI_HILOGW("Add js monitor failed");
52             return;
53         }
54     }
55     auto monitor = std::make_shared<JsInputMonitor>(jsEnv, typeName, hotRectArea,
56         rectTotal, callback, nextId_++, fingers);
57     int32_t ret = monitor->Start(typeName);
58     if (ret < 0) {
59         MMI_HILOGE("Js monitor startup failed");
60         ThrowError(jsEnv, ret);
61         return;
62     }
63     monitors_.push_back(monitor);
64 }
65 
AddMonitor(napi_env jsEnv,const std::string & typeName,napi_value callback,const int32_t fingers)66 void JsInputMonitorManager::AddMonitor(napi_env jsEnv, const std::string &typeName,
67     napi_value callback, const int32_t fingers)
68 {
69     CALL_DEBUG_ENTER;
70     std::lock_guard<std::mutex> guard(mutex_);
71     for (const auto &item : monitors_) {
72         if ((item != nullptr) && (item->IsMatch(jsEnv, callback) != RET_ERR)) {
73             MMI_HILOGW("Add js monitor failed");
74             return;
75         }
76     }
77     auto monitor = std::make_shared<JsInputMonitor>(jsEnv, typeName, callback, nextId_++, fingers);
78     int32_t ret = monitor->Start(typeName);
79     if (ret < 0) {
80         MMI_HILOGE("Js monitor startup failed");
81         ThrowError(jsEnv, ret);
82         return;
83     }
84     monitors_.push_back(monitor);
85 }
86 
AddPreMonitor(napi_env jsEnv,const std::string & typeName,napi_value callback,std::vector<int32_t> keys)87 void JsInputMonitorManager::AddPreMonitor(napi_env jsEnv, const std::string &typeName,
88     napi_value callback, std::vector<int32_t> keys)
89 {
90     CALL_DEBUG_ENTER;
91     std::lock_guard<std::mutex> guard(mutex_);
92     for (const auto &item : monitors_) {
93         if ((item != nullptr) && (item->IsMatch(jsEnv, callback) != RET_ERR)) {
94             MMI_HILOGW("Add js monitor failed");
95             return;
96         }
97     }
98     auto monitor = std::make_shared<JsInputMonitor>(jsEnv, typeName, callback, nextId_++, keys);
99     int32_t ret = monitor->Start(typeName);
100     if (ret < 0) {
101         MMI_HILOGE("Js monitor startup failed");
102         ThrowError(jsEnv, ret);
103         return;
104     }
105     monitors_.push_back(monitor);
106 }
107 
RemoveMonitor(napi_env jsEnv,const std::string & typeName,napi_value callback,const int32_t fingers)108 void JsInputMonitorManager::RemoveMonitor(napi_env jsEnv, const std::string &typeName, napi_value callback,
109     const int32_t fingers)
110 {
111     CALL_DEBUG_ENTER;
112     std::shared_ptr<JsInputMonitor> monitor = nullptr;
113     do {
114         std::lock_guard<std::mutex> guard(mutex_);
115         for (auto it = monitors_.begin(); it != monitors_.end();) {
116             if ((*it) == nullptr) {
117                 monitors_.erase(it++);
118                 continue;
119             }
120             if (IsFindJsInputMonitor(*it, jsEnv, typeName, callback, fingers)) {
121                 monitor = *it;
122                 monitors_.erase(it++);
123                 MMI_HILOGD("Found monitor");
124                 break;
125             }
126             ++it;
127         }
128     } while (0);
129     if (monitor != nullptr) {
130         monitor->Stop();
131     }
132 }
133 
RemoveMonitor(napi_env jsEnv,const std::string & typeName,const int32_t fingers)134 void JsInputMonitorManager::RemoveMonitor(napi_env jsEnv, const std::string &typeName, const int32_t fingers)
135 {
136     CALL_DEBUG_ENTER;
137     std::list<std::shared_ptr<JsInputMonitor>> monitors;
138     do {
139         std::lock_guard<std::mutex> guard(mutex_);
140         for (auto it = monitors_.begin(); it != monitors_.end();) {
141             if ((*it) == nullptr) {
142                 monitors_.erase(it++);
143                 continue;
144             }
145             if (IsFindJsInputMonitor(*it, jsEnv, typeName, fingers)) {
146                 monitors.push_back(*it);
147                 monitors_.erase(it++);
148                 continue;
149             }
150             ++it;
151         }
152     } while (0);
153 
154     for (const auto &item : monitors) {
155         if (item != nullptr) {
156             item->Stop();
157         }
158     }
159 }
160 
RemoveMonitor(napi_env jsEnv)161 void JsInputMonitorManager::RemoveMonitor(napi_env jsEnv)
162 {
163     CALL_DEBUG_ENTER;
164     std::list<std::shared_ptr<JsInputMonitor>> monitors;
165     do {
166         std::lock_guard<std::mutex> guard(mutex_);
167         for (auto it = monitors_.begin(); it != monitors_.end();) {
168             if ((*it) == nullptr) {
169                 monitors_.erase(it++);
170                 continue;
171             }
172             if ((*it)->IsMatch(jsEnv) == RET_OK) {
173                 monitors.push_back(*it);
174                 monitors_.erase(it++);
175                 continue;
176             }
177             ++it;
178         }
179     } while (0);
180 
181     for (const auto &item : monitors) {
182         if (item != nullptr) {
183             item->Stop();
184         }
185     }
186 }
187 
OnPointerEventByMonitorId(int32_t id,int32_t fingers,std::shared_ptr<PointerEvent> pointEvent)188 void JsInputMonitorManager::OnPointerEventByMonitorId(int32_t id, int32_t fingers,
189     std::shared_ptr<PointerEvent> pointEvent)
190 {
191     CALL_DEBUG_ENTER;
192     std::lock_guard<std::mutex> guard(mutex_);
193     for (const auto &item : monitors_) {
194         if ((item != nullptr) && (item->GetId() == id && item->GetFingers() == fingers)) {
195             item->OnPointerEvent(pointEvent);
196         }
197     }
198 }
199 
OnKeyEventByMonitorId(int32_t id,std::shared_ptr<KeyEvent> keyEvent)200 void JsInputMonitorManager::OnKeyEventByMonitorId(int32_t id, std::shared_ptr<KeyEvent> keyEvent)
201 {
202     CALL_DEBUG_ENTER;
203     std::lock_guard<std::mutex> guard(mutex_);
204     for (const auto &item : monitors_) {
205         if (item != nullptr && item->GetId() == id) {
206             item->OnKeyEvent(keyEvent);
207         }
208     }
209 }
210 
GetPreMonitor(int32_t id)211 const std::shared_ptr<JsInputMonitor> JsInputMonitorManager::GetPreMonitor(int32_t id)
212 {
213     CALL_DEBUG_ENTER;
214     std::lock_guard<std::mutex> guard(mutex_);
215     for (const auto &item : monitors_) {
216         if (item != nullptr && item->GetId() == id) {
217             return item;
218         }
219     }
220     MMI_HILOGD("No monitor found");
221     return nullptr;
222 }
223 
GetMonitor(int32_t id,int32_t fingers)224 const std::shared_ptr<JsInputMonitor> JsInputMonitorManager::GetMonitor(int32_t id, int32_t fingers)
225 {
226     CALL_DEBUG_ENTER;
227     std::lock_guard<std::mutex> guard(mutex_);
228     for (const auto &item : monitors_) {
229         if ((item != nullptr) && (item->GetId() == id && item->GetFingers() == fingers)) {
230             return item;
231         }
232     }
233     MMI_HILOGD("No monitor found");
234     return nullptr;
235 }
236 
GetMonitorTypeName(int32_t id,int32_t fingers)237 std::string JsInputMonitorManager::GetMonitorTypeName(int32_t id, int32_t fingers)
238 {
239     CALL_DEBUG_ENTER;
240     std::lock_guard<std::mutex> guard(mutex_);
241     for (const auto &item : monitors_) {
242         if ((item != nullptr) && (item->GetId() == id && item->GetFingers() == fingers)) {
243             return item->GetTypeName();
244         }
245     }
246     MMI_HILOGD("No monitor found");
247     return "";
248 }
249 
GetPreMonitorTypeName(int32_t id)250 std::string JsInputMonitorManager::GetPreMonitorTypeName(int32_t id)
251 {
252     CALL_DEBUG_ENTER;
253     std::lock_guard<std::mutex> guard(mutex_);
254     for (const auto &item : monitors_) {
255         if (item != nullptr && item->GetId() == id) {
256             return item->GetTypeName();
257         }
258     }
259     MMI_HILOGD("No monitor found");
260     return "";
261 }
262 
AddEnv(napi_env env,napi_callback_info cbInfo)263 bool JsInputMonitorManager::AddEnv(napi_env env, napi_callback_info cbInfo)
264 {
265     CALL_DEBUG_ENTER;
266     if (IsExisting(env)) {
267         MMI_HILOGD("Env is already existent");
268         return true;
269     }
270     napi_value thisVar = nullptr;
271     void *data = nullptr;
272     int32_t *id = new (std::nothrow) int32_t;
273     CHKPF(id);
274     *id = 0;
275     if (napi_get_cb_info(env, cbInfo, nullptr, nullptr, &thisVar, &data) != napi_ok) {
276         MMI_HILOGE("GET_CB_INFO failed");
277         auto infoTemp = std::string("AddEnv GET_CB_INFO failed");
278         napi_throw_error(env, nullptr, infoTemp.c_str());
279         delete id;
280         id = nullptr;
281         return false;
282     }
283     auto status = napi_wrap(env, thisVar, static_cast<void*>(id),
284                             [](napi_env env, void *data, void *hint) {
285                                 MMI_HILOGD("napi_wrap enter");
286                                 int32_t *id = static_cast<int32_t *>(data);
287                                 delete id;
288                                 id = nullptr;
289                                 JS_INPUT_MONITOR_MGR.RemoveMonitor(env);
290                                 JS_INPUT_MONITOR_MGR.RemoveEnv(env);
291                                 MMI_HILOGD("napi_wrap leave");
292                                 }, nullptr, nullptr);
293     if (status != napi_ok) {
294         MMI_HILOGE("napi_wrap failed");
295         delete id;
296         return false;
297     }
298     napi_ref ref = nullptr;
299     status = napi_create_reference(env, thisVar, 1, &ref);
300     if (status != napi_ok) {
301         MMI_HILOGE("napi_create_reference failed");
302         return false;
303     }
304     std::lock_guard<std::mutex> lock(envMutex_);
305     auto iter = envManager_.insert(std::pair<napi_env, napi_ref>(env, ref));
306     if (!iter.second) {
307         MMI_HILOGE("Insert value failed");
308         return false;
309     }
310     return true;
311 }
312 
RemoveEnv(napi_env env)313 void JsInputMonitorManager::RemoveEnv(napi_env env)
314 {
315     CALL_DEBUG_ENTER;
316     std::lock_guard<std::mutex> lock(envMutex_);
317     auto it = envManager_.find(env);
318     if (it == envManager_.end()) {
319         MMI_HILOGD("No env found");
320         return;
321     }
322     RemoveEnv(it);
323 }
324 
RemoveEnv(std::map<napi_env,napi_ref>::iterator it)325 void JsInputMonitorManager::RemoveEnv(std::map<napi_env, napi_ref>::iterator it)
326 {
327     CALL_DEBUG_ENTER;
328     uint32_t refCount = 0;
329     CHKRV(napi_reference_unref(it->first, it->second, &refCount), REFERENCE_UNREF);
330     envManager_.erase(it);
331 }
332 
RemoveAllEnv()333 void JsInputMonitorManager::RemoveAllEnv()
334 {
335     CALL_DEBUG_ENTER;
336     std::lock_guard<std::mutex> lock(envMutex_);
337     for (auto it = envManager_.begin(); it != envManager_.end();) {
338         RemoveEnv(it++);
339     }
340 }
341 
IsExisting(napi_env env)342 bool JsInputMonitorManager::IsExisting(napi_env env)
343 {
344     CALL_DEBUG_ENTER;
345     std::lock_guard<std::mutex> lock(envMutex_);
346     auto it = envManager_.find(env);
347     if (it == envManager_.end()) {
348         MMI_HILOGD("No env found");
349         return false;
350     }
351 
352     return true;
353 }
354 
ThrowError(napi_env env,int32_t code)355 void JsInputMonitorManager::ThrowError(napi_env env, int32_t code)
356 {
357     int32_t errorCode = -code;
358     if (errorCode == MONITOR_REGISTER_EXCEED_MAX) {
359         THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "Maximum number of listeners exceeded for a single process");
360     } else if (errorCode == COMMON_PERMISSION_CHECK_ERROR) {
361         THROWERR_API9(env, COMMON_PERMISSION_CHECK_ERROR, "monitor", "ohos.permission.INPUT_MONITORING");
362     } else {
363         MMI_HILOGE("Add monitor failed");
364     }
365 }
366 
GetHotRectAreaList(napi_env env,napi_value rectNapiValue,uint32_t rectListLength)367 std::vector<Rect> JsInputMonitorManager::GetHotRectAreaList(napi_env env,
368     napi_value rectNapiValue, uint32_t rectListLength)
369 {
370     std::vector<Rect> hotRectAreaList;
371     for (uint32_t i = 0; i < rectListLength; i++) {
372         napi_value napiElement;
373         CHKRR(napi_get_element(env, rectNapiValue, i, &napiElement), GET_ELEMENT, hotRectAreaList);
374         Rect rectItem;
375         napi_value napiX = nullptr;
376         CHKRR(napi_get_named_property(env, napiElement, "left", &napiX), GET_NAMED_PROPERTY, hotRectAreaList);
377         if (napiX == nullptr) {
378             THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "left not found");
379             return hotRectAreaList;
380         }
381         int32_t rectX = -1;
382         CHKRR(napi_get_value_int32(env, napiX, &rectX), GET_VALUE_INT32, hotRectAreaList);
383         rectItem.x = rectX;
384         napi_value napiY = nullptr;
385         CHKRR(napi_get_named_property(env, napiElement, "top", &napiY), GET_NAMED_PROPERTY, hotRectAreaList);
386         if (napiY == nullptr) {
387             THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "top not found");
388             return hotRectAreaList;
389         }
390         int32_t rectY = -1;
391         CHKRR(napi_get_value_int32(env, napiY, &rectY), GET_VALUE_INT32, hotRectAreaList);
392         rectItem.y = rectY;
393         napi_value napiWidth = nullptr;
394         CHKRR(napi_get_named_property(env, napiElement, "width", &napiWidth), GET_NAMED_PROPERTY, hotRectAreaList);
395         if (napiWidth == nullptr) {
396             THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "width not found");
397             return hotRectAreaList;
398         }
399         int32_t rectWidth = -1;
400         CHKRR(napi_get_value_int32(env, napiWidth, &rectWidth), GET_VALUE_INT32, hotRectAreaList);
401         rectItem.width = rectWidth;
402         napi_value napiHeight = nullptr;
403         CHKRR(napi_get_named_property(env, napiElement, "height", &napiHeight), GET_NAMED_PROPERTY, hotRectAreaList);
404         if (napiHeight == nullptr) {
405             THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "height not found");
406             return hotRectAreaList;
407         }
408         int32_t rectHeight = -1;
409         CHKRR(napi_get_value_int32(env, napiHeight, &rectHeight), GET_VALUE_INT32, hotRectAreaList);
410         rectItem.height = rectHeight;
411         if (rectX < 0 || rectY < 0 || rectHeight < 0 || rectWidth < 0) {
412             THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "Rect parameter can't be negative");
413             return hotRectAreaList;
414         }
415         hotRectAreaList.push_back(rectItem);
416     }
417     return hotRectAreaList;
418 }
419 
IsFindJsInputMonitor(const std::shared_ptr<JsInputMonitor> monitor,napi_env jsEnv,const std::string & typeName,napi_value callback,const int32_t fingers)420 bool JsInputMonitorManager::IsFindJsInputMonitor(const std::shared_ptr<JsInputMonitor> monitor,
421     napi_env jsEnv, const std::string &typeName, napi_value callback, const int32_t fingers)
422 {
423     CHKPF(monitor);
424     if ((monitor->GetTypeName() == typeName) && (typeName == "keyPressed" || monitor->GetFingers() == fingers)) {
425         if (monitor->IsMatch(jsEnv, callback) == RET_OK) {
426             return true;
427         }
428     }
429     return false;
430 }
431 
IsFindJsInputMonitor(const std::shared_ptr<JsInputMonitor> monitor,napi_env jsEnv,const std::string & typeName,const int32_t fingers)432 bool JsInputMonitorManager::IsFindJsInputMonitor(const std::shared_ptr<JsInputMonitor> monitor,
433     napi_env jsEnv, const std::string &typeName, const int32_t fingers)
434 {
435     CHKPF(monitor);
436     if ((monitor->GetTypeName() == typeName) && (typeName == "keyPressed" || monitor->GetFingers() == fingers)) {
437         if (monitor->IsMatch(jsEnv) == RET_OK) {
438             return true;
439         }
440     }
441     return false;
442 }
443 
GetKeysArray(napi_env env,napi_value keysNapiValue,uint32_t keysLength,std::vector<int32_t> & keys)444 bool JsInputMonitorManager::GetKeysArray(napi_env env, napi_value keysNapiValue, uint32_t keysLength,
445     std::vector<int32_t>& keys)
446 {
447     for (uint32_t i = 0; i < keysLength; i++) {
448         napi_value napiElement;
449         CHKRR(napi_get_element(env, keysNapiValue, i, &napiElement), GET_ELEMENT, false);
450         int32_t keycode;
451         CHKRR(napi_get_value_int32(env, napiElement, &keycode), GET_VALUE_INT32, false);
452         auto it = std::find(supportedKeyCodes.begin(), supportedKeyCodes.end(), keycode);
453         if (it == supportedKeyCodes.end()) {
454             MMI_HILOGE("PreKeys is not expect");
455             return false;
456         }
457         keys.push_back(keycode);
458     }
459     return true;
460 }
461 
JsQueryTouchEvents(napi_env env,int32_t count)462 napi_value JsInputMonitorManager::JsQueryTouchEvents(napi_env env, int32_t count)
463 {
464     CALL_DEBUG_ENTER;
465     sptr<JsInputMonitor::CallbackInfo> cb = new (std::nothrow) JsInputMonitor::CallbackInfo();
466     CHKPP(cb);
467     cb->env = env;
468     napi_value promise = nullptr;
469     CHKRP(napi_create_promise(env, &cb->deferred, &promise), CREATE_PROMISE);
470     EmitJsQueryTouchEvents(cb, count);
471     return promise;
472 }
473 
EmitJsQueryTouchEvents(sptr<JsInputMonitor::CallbackInfo> cb,int32_t count)474 void JsInputMonitorManager::EmitJsQueryTouchEvents(sptr<JsInputMonitor::CallbackInfo> cb, int32_t count)
475 {
476     CALL_DEBUG_ENTER;
477     CHKPV(cb);
478     CHKPV(cb->env);
479     std::vector<std::shared_ptr<PointerEvent>> touchEventList {};
480     cb->data.count = count;
481     cb->data.touchEventList = touchEventList;
482     cb->errCode = RET_OK;
483     uv_loop_s *loop = nullptr;
484     CHKRV(napi_get_uv_event_loop(cb->env, &loop), GET_UV_EVENT_LOOP);
485     uv_work_t *work = new (std::nothrow) uv_work_t;
486     CHKPV(work);
487     cb->IncStrongRef(nullptr);
488     work->data = cb.GetRefPtr();
489     int32_t ret = -1;
490     ret = uv_queue_work_with_qos(
491         loop,
492         work,
493         [](uv_work_t *work) {
494             MMI_HILOGD("uv_queue_work callback function is called");
495             JsInputMonitor::CallJsQueryTouchEventsTask(work);
496         },
497         JsInputMonitor::CallJsQueryTouchEventsPromise,
498         uv_qos_user_initiated);
499     if (ret != 0) {
500         MMI_HILOGE("uv_queue_work_with_qos failed");
501         cb->DecStrongRef(nullptr);
502         JsInputMonitor::DeletePtr<uv_work_t *>(work);
503     }
504 }
505 } // namespace MMI
506 } // namespace OHOS
507