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