• 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 };
36 
GetInstance()37 JsInputMonitorManager& JsInputMonitorManager::GetInstance()
38 {
39     static JsInputMonitorManager instance;
40     return instance;
41 }
42 
AddMonitor(napi_env jsEnv,const std::string & typeName,std::vector<Rect> hotRectArea,int32_t rectTotal,napi_value callback,const int32_t fingers)43 void JsInputMonitorManager::AddMonitor(napi_env jsEnv, const std::string &typeName,
44     std::vector<Rect> hotRectArea, int32_t rectTotal, napi_value callback, const int32_t fingers)
45 {
46     CALL_DEBUG_ENTER;
47     std::lock_guard<std::mutex> guard(mutex_);
48     for (const auto &item : monitors_) {
49         if ((item != nullptr) && (item->IsMatch(jsEnv, callback) != RET_ERR)) {
50             MMI_HILOGW("Add js monitor failed");
51             return;
52         }
53     }
54     auto monitor = std::make_shared<JsInputMonitor>(jsEnv, typeName, hotRectArea,
55         rectTotal, callback, nextId_++, fingers);
56     int32_t ret = monitor->Start(typeName);
57     if (ret < 0) {
58         MMI_HILOGE("Js monitor startup failed");
59         ThrowError(jsEnv, ret);
60         return;
61     }
62     monitors_.push_back(monitor);
63 }
64 
AddMonitor(napi_env jsEnv,const std::string & typeName,napi_value callback,const int32_t fingers)65 void JsInputMonitorManager::AddMonitor(napi_env jsEnv, const std::string &typeName,
66     napi_value callback, const int32_t fingers)
67 {
68     CALL_DEBUG_ENTER;
69     std::lock_guard<std::mutex> guard(mutex_);
70     for (const auto &item : monitors_) {
71         if ((item != nullptr) && (item->IsMatch(jsEnv, callback) != RET_ERR)) {
72             MMI_HILOGW("Add js monitor failed");
73             return;
74         }
75     }
76     auto monitor = std::make_shared<JsInputMonitor>(jsEnv, typeName, callback, nextId_++, fingers);
77     int32_t ret = monitor->Start(typeName);
78     if (ret < 0) {
79         MMI_HILOGE("Js monitor startup failed");
80         ThrowError(jsEnv, ret);
81         return;
82     }
83     monitors_.push_back(monitor);
84 }
85 
AddPreMonitor(napi_env jsEnv,const std::string & typeName,napi_value callback,std::vector<int32_t> keys)86 void JsInputMonitorManager::AddPreMonitor(napi_env jsEnv, const std::string &typeName,
87     napi_value callback, std::vector<int32_t> keys)
88 {
89     CALL_DEBUG_ENTER;
90     std::lock_guard<std::mutex> guard(mutex_);
91     for (const auto &item : monitors_) {
92         if ((item != nullptr) && (item->IsMatch(jsEnv, callback) != RET_ERR)) {
93             MMI_HILOGW("Add js monitor failed");
94             return;
95         }
96     }
97     auto monitor = std::make_shared<JsInputMonitor>(jsEnv, typeName, callback, nextId_++, keys);
98     int32_t ret = monitor->Start(typeName);
99     if (ret < 0) {
100         MMI_HILOGE("Js monitor startup failed");
101         ThrowError(jsEnv, ret);
102         return;
103     }
104     monitors_.push_back(monitor);
105 }
106 
RemoveMonitor(napi_env jsEnv,const std::string & typeName,napi_value callback,const int32_t fingers)107 void JsInputMonitorManager::RemoveMonitor(napi_env jsEnv, const std::string &typeName, napi_value callback,
108     const int32_t fingers)
109 {
110     CALL_DEBUG_ENTER;
111     std::shared_ptr<JsInputMonitor> monitor = nullptr;
112     do {
113         std::lock_guard<std::mutex> guard(mutex_);
114         for (auto it = monitors_.begin(); it != monitors_.end();) {
115             if ((*it) == nullptr) {
116                 monitors_.erase(it++);
117                 continue;
118             }
119             if (IsFindJsInputMonitor(*it, jsEnv, typeName, callback, fingers)) {
120                 monitor = *it;
121                 monitors_.erase(it++);
122                 MMI_HILOGD("Found monitor");
123                 break;
124             }
125             ++it;
126         }
127     } while (0);
128     if (monitor != nullptr) {
129         monitor->Stop();
130     }
131 }
132 
RemoveMonitor(napi_env jsEnv,const std::string & typeName,const int32_t fingers)133 void JsInputMonitorManager::RemoveMonitor(napi_env jsEnv, const std::string &typeName, const int32_t fingers)
134 {
135     CALL_DEBUG_ENTER;
136     std::list<std::shared_ptr<JsInputMonitor>> monitors;
137     do {
138         std::lock_guard<std::mutex> guard(mutex_);
139         for (auto it = monitors_.begin(); it != monitors_.end();) {
140             if ((*it) == nullptr) {
141                 monitors_.erase(it++);
142                 continue;
143             }
144             if (IsFindJsInputMonitor(*it, jsEnv, typeName, fingers)) {
145                 monitors.push_back(*it);
146                 monitors_.erase(it++);
147                 continue;
148             }
149             ++it;
150         }
151     } while (0);
152 
153     for (const auto &item : monitors) {
154         if (item != nullptr) {
155             item->Stop();
156         }
157     }
158 }
159 
RemoveMonitor(napi_env jsEnv)160 void JsInputMonitorManager::RemoveMonitor(napi_env jsEnv)
161 {
162     CALL_DEBUG_ENTER;
163     std::list<std::shared_ptr<JsInputMonitor>> monitors;
164     do {
165         std::lock_guard<std::mutex> guard(mutex_);
166         for (auto it = monitors_.begin(); it != monitors_.end();) {
167             if ((*it) == nullptr) {
168                 monitors_.erase(it++);
169                 continue;
170             }
171             if ((*it)->IsMatch(jsEnv) == RET_OK) {
172                 monitors.push_back(*it);
173                 monitors_.erase(it++);
174                 continue;
175             }
176             ++it;
177         }
178     } while (0);
179 
180     for (const auto &item : monitors) {
181         if (item != nullptr) {
182             item->Stop();
183         }
184     }
185 }
186 
OnPointerEventByMonitorId(int32_t id,int32_t fingers,std::shared_ptr<PointerEvent> pointEvent)187 void JsInputMonitorManager::OnPointerEventByMonitorId(int32_t id, int32_t fingers,
188     std::shared_ptr<PointerEvent> pointEvent)
189 {
190     CALL_DEBUG_ENTER;
191     std::lock_guard<std::mutex> guard(mutex_);
192     for (const auto &item : monitors_) {
193         if ((item != nullptr) && (item->GetId() == id && item->GetFingers() == fingers)) {
194             item->OnPointerEvent(pointEvent);
195         }
196     }
197 }
198 
OnKeyEventByMonitorId(int32_t id,std::shared_ptr<KeyEvent> keyEvent)199 void JsInputMonitorManager::OnKeyEventByMonitorId(int32_t id, std::shared_ptr<KeyEvent> keyEvent)
200 {
201     CALL_DEBUG_ENTER;
202     std::lock_guard<std::mutex> guard(mutex_);
203     for (const auto &item : monitors_) {
204         if (item != nullptr && item->GetId() == id) {
205             item->OnKeyEvent(keyEvent);
206         }
207     }
208 }
209 
GetPreMonitor(int32_t id)210 const std::shared_ptr<JsInputMonitor> JsInputMonitorManager::GetPreMonitor(int32_t id)
211 {
212     CALL_DEBUG_ENTER;
213     std::lock_guard<std::mutex> guard(mutex_);
214     for (const auto &item : monitors_) {
215         if (item != nullptr && item->GetId() == id) {
216             return item;
217         }
218     }
219     MMI_HILOGD("No monitor found");
220     return nullptr;
221 }
222 
GetMonitor(int32_t id,int32_t fingers)223 const std::shared_ptr<JsInputMonitor> JsInputMonitorManager::GetMonitor(int32_t id, int32_t fingers)
224 {
225     CALL_DEBUG_ENTER;
226     std::lock_guard<std::mutex> guard(mutex_);
227     for (const auto &item : monitors_) {
228         if ((item != nullptr) && (item->GetId() == id && item->GetFingers() == fingers)) {
229             return item;
230         }
231     }
232     MMI_HILOGD("No monitor found");
233     return nullptr;
234 }
235 
GetMonitorTypeName(int32_t id,int32_t fingers)236 std::string JsInputMonitorManager::GetMonitorTypeName(int32_t id, int32_t fingers)
237 {
238     CALL_DEBUG_ENTER;
239     std::lock_guard<std::mutex> guard(mutex_);
240     for (const auto &item : monitors_) {
241         if ((item != nullptr) && (item->GetId() == id && item->GetFingers() == fingers)) {
242             return item->GetTypeName();
243         }
244     }
245     MMI_HILOGD("No monitor found");
246     return "";
247 }
248 
GetPreMonitorTypeName(int32_t id)249 std::string JsInputMonitorManager::GetPreMonitorTypeName(int32_t id)
250 {
251     CALL_DEBUG_ENTER;
252     std::lock_guard<std::mutex> guard(mutex_);
253     for (const auto &item : monitors_) {
254         if (item != nullptr && item->GetId() == id) {
255             return item->GetTypeName();
256         }
257     }
258     MMI_HILOGD("No monitor found");
259     return "";
260 }
261 
AddEnv(napi_env env,napi_callback_info cbInfo)262 bool JsInputMonitorManager::AddEnv(napi_env env, napi_callback_info cbInfo)
263 {
264     CALL_DEBUG_ENTER;
265     if (IsExisting(env)) {
266         MMI_HILOGD("Env is already existent");
267         return true;
268     }
269     napi_value thisVar = nullptr;
270     void *data = nullptr;
271     int32_t *id = new (std::nothrow) int32_t;
272     CHKPF(id);
273     *id = 0;
274     if (napi_get_cb_info(env, cbInfo, nullptr, nullptr, &thisVar, &data) != napi_ok) {
275         MMI_HILOGE("GET_CB_INFO failed");
276         auto infoTemp = std::string("AddEnv GET_CB_INFO failed");
277         napi_throw_error(env, nullptr, infoTemp.c_str());
278         delete id;
279         return false;
280     }
281     auto status = napi_wrap(env, thisVar, static_cast<void*>(id),
282                             [](napi_env env, void *data, void *hint) {
283                                 MMI_HILOGD("napi_wrap enter");
284                                 int32_t *id = static_cast<int32_t *>(data);
285                                 delete id;
286                                 id = nullptr;
287                                 JS_INPUT_MONITOR_MGR.RemoveMonitor(env);
288                                 JS_INPUT_MONITOR_MGR.RemoveEnv(env);
289                                 MMI_HILOGD("napi_wrap leave");
290                                 }, nullptr, nullptr);
291     if (status != napi_ok) {
292         MMI_HILOGE("napi_wrap failed");
293         delete id;
294         return false;
295     }
296     napi_ref ref = nullptr;
297     status = napi_create_reference(env, thisVar, 1, &ref);
298     if (status != napi_ok) {
299         MMI_HILOGE("napi_create_reference failed");
300         return false;
301     }
302     std::lock_guard<std::mutex> lock(envMutex_);
303     auto iter = envManager_.insert(std::pair<napi_env, napi_ref>(env, ref));
304     if (!iter.second) {
305         MMI_HILOGE("Insert value failed");
306         return false;
307     }
308     return true;
309 }
310 
RemoveEnv(napi_env env)311 void JsInputMonitorManager::RemoveEnv(napi_env env)
312 {
313     CALL_DEBUG_ENTER;
314     std::lock_guard<std::mutex> lock(envMutex_);
315     auto it = envManager_.find(env);
316     if (it == envManager_.end()) {
317         MMI_HILOGD("No env found");
318         return;
319     }
320     RemoveEnv(it);
321 }
322 
RemoveEnv(std::map<napi_env,napi_ref>::iterator it)323 void JsInputMonitorManager::RemoveEnv(std::map<napi_env, napi_ref>::iterator it)
324 {
325     CALL_DEBUG_ENTER;
326     uint32_t refCount = 0;
327     CHKRV(napi_reference_unref(it->first, it->second, &refCount), REFERENCE_UNREF);
328     envManager_.erase(it);
329 }
330 
RemoveAllEnv()331 void JsInputMonitorManager::RemoveAllEnv()
332 {
333     CALL_DEBUG_ENTER;
334     std::lock_guard<std::mutex> lock(envMutex_);
335     for (auto it = envManager_.begin(); it != envManager_.end();) {
336         RemoveEnv(it++);
337     }
338 }
339 
IsExisting(napi_env env)340 bool JsInputMonitorManager::IsExisting(napi_env env)
341 {
342     CALL_DEBUG_ENTER;
343     std::lock_guard<std::mutex> lock(envMutex_);
344     auto it = envManager_.find(env);
345     if (it == envManager_.end()) {
346         MMI_HILOGD("No env found");
347         return false;
348     }
349 
350     return true;
351 }
352 
ThrowError(napi_env env,int32_t code)353 void JsInputMonitorManager::ThrowError(napi_env env, int32_t code)
354 {
355     int32_t errorCode = -code;
356     if (errorCode == MONITOR_REGISTER_EXCEED_MAX) {
357         THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "Maximum number of listeners exceeded for a single process");
358     } else if (errorCode == COMMON_PERMISSION_CHECK_ERROR) {
359         THROWERR_API9(env, COMMON_PERMISSION_CHECK_ERROR, "monitor", "ohos.permission.INPUT_MONITORING");
360     } else {
361         MMI_HILOGE("Add monitor failed");
362     }
363 }
364 
GetHotRectAreaList(napi_env env,napi_value rectNapiValue,uint32_t rectListLength)365 std::vector<Rect> JsInputMonitorManager::GetHotRectAreaList(napi_env env,
366     napi_value rectNapiValue, uint32_t rectListLength)
367 {
368     std::vector<Rect> hotRectAreaList;
369     for (uint32_t i = 0; i < rectListLength; i++) {
370         napi_value napiElement;
371         CHKRR(napi_get_element(env, rectNapiValue, i, &napiElement), GET_ELEMENT, hotRectAreaList);
372         Rect rectItem;
373         napi_value napiX = nullptr;
374         CHKRR(napi_get_named_property(env, napiElement, "left", &napiX), GET_NAMED_PROPERTY, hotRectAreaList);
375         if (napiX == nullptr) {
376             THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "left not found");
377             return hotRectAreaList;
378         }
379         int32_t rectX = -1;
380         CHKRR(napi_get_value_int32(env, napiX, &rectX), GET_VALUE_INT32, hotRectAreaList);
381         rectItem.x = rectX;
382         napi_value napiY = nullptr;
383         CHKRR(napi_get_named_property(env, napiElement, "top", &napiY), GET_NAMED_PROPERTY, hotRectAreaList);
384         if (napiY == nullptr) {
385             THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "top not found");
386             return hotRectAreaList;
387         }
388         int32_t rectY = -1;
389         CHKRR(napi_get_value_int32(env, napiY, &rectY), GET_VALUE_INT32, hotRectAreaList);
390         rectItem.y = rectY;
391         napi_value napiWidth = nullptr;
392         CHKRR(napi_get_named_property(env, napiElement, "width", &napiWidth), GET_NAMED_PROPERTY, hotRectAreaList);
393         if (napiWidth == nullptr) {
394             THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "width not found");
395             return hotRectAreaList;
396         }
397         int32_t rectWidth = -1;
398         CHKRR(napi_get_value_int32(env, napiWidth, &rectWidth), GET_VALUE_INT32, hotRectAreaList);
399         rectItem.width = rectWidth;
400         napi_value napiHeight = nullptr;
401         CHKRR(napi_get_named_property(env, napiElement, "height", &napiHeight), GET_NAMED_PROPERTY, hotRectAreaList);
402         if (napiHeight == nullptr) {
403             THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "height not found");
404             return hotRectAreaList;
405         }
406         int32_t rectHeight = -1;
407         CHKRR(napi_get_value_int32(env, napiHeight, &rectHeight), GET_VALUE_INT32, hotRectAreaList);
408         rectItem.height = rectHeight;
409         if (rectX < 0 || rectY < 0 || rectHeight < 0 || rectWidth < 0) {
410             THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "Rect parameter can't be negative");
411             return hotRectAreaList;
412         }
413         hotRectAreaList.push_back(rectItem);
414     }
415     return hotRectAreaList;
416 }
417 
IsFindJsInputMonitor(const std::shared_ptr<JsInputMonitor> monitor,napi_env jsEnv,const std::string & typeName,napi_value callback,const int32_t fingers)418 bool JsInputMonitorManager::IsFindJsInputMonitor(const std::shared_ptr<JsInputMonitor> monitor,
419     napi_env jsEnv, const std::string &typeName, napi_value callback, const int32_t fingers)
420 {
421     if ((monitor->GetTypeName() == typeName) && (typeName == "keyPressed" || monitor->GetFingers() == fingers)) {
422         if (monitor->IsMatch(jsEnv, callback) == RET_OK) {
423             return true;
424         }
425     }
426     return false;
427 }
428 
IsFindJsInputMonitor(const std::shared_ptr<JsInputMonitor> monitor,napi_env jsEnv,const std::string & typeName,const int32_t fingers)429 bool JsInputMonitorManager::IsFindJsInputMonitor(const std::shared_ptr<JsInputMonitor> monitor,
430     napi_env jsEnv, const std::string &typeName, const int32_t fingers)
431 {
432     if ((monitor->GetTypeName() == typeName) && (typeName == "keyPressed" || monitor->GetFingers() == fingers)) {
433         if (monitor->IsMatch(jsEnv) == RET_OK) {
434             return true;
435         }
436     }
437     return false;
438 }
439 
GetKeysArray(napi_env env,napi_value keysNapiValue,uint32_t keysLength,std::vector<int32_t> & keys)440 bool JsInputMonitorManager::GetKeysArray(napi_env env, napi_value keysNapiValue, uint32_t keysLength,
441     std::vector<int32_t>& keys)
442 {
443     for (uint32_t i = 0; i < keysLength; i++) {
444         napi_value napiElement;
445         CHKRR(napi_get_element(env, keysNapiValue, i, &napiElement), GET_ELEMENT, false);
446         int32_t keycode;
447         CHKRR(napi_get_value_int32(env, napiElement, &keycode), GET_VALUE_INT32, false);
448         auto it = std::find(supportedKeyCodes.begin(), supportedKeyCodes.end(), keycode);
449         if (it == supportedKeyCodes.end()) {
450             MMI_HILOGE("PreKeys is not expect");
451             return false;
452         }
453         keys.push_back(keycode);
454     }
455     return true;
456 }
457 } // namespace MMI
458 } // namespace OHOS
459