1 /*
2 * Copyright (c) 2021-2022 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.h"
17
18 #include <cinttypes>
19
20 #include "define_multimodal.h"
21 #include "error_multimodal.h"
22 #include "input_manager.h"
23 #include "js_input_monitor_manager.h"
24 #include "js_input_monitor_util.h"
25
26 namespace OHOS {
27 namespace MMI {
28 namespace {
29 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, MMI_LOG_DOMAIN, "JsInputMonitor" };
30 constexpr int32_t AXIS_TYPE_SCROLL_VERTICAL = 0;
31 constexpr int32_t AXIS_TYPE_SCROLL_HORIZONTAL = 1;
32 constexpr int32_t AXIS_TYPE_PINCH = 2;
33 constexpr int32_t NAPI_ERR = 3;
34 constexpr int32_t CANCEL = 0;
35 constexpr int32_t MOVE = 1;
36 constexpr int32_t BUTTON_DOWN = 2;
37 constexpr int32_t BUTTON_UP = 3;
38 constexpr int32_t AXIS_BEGIN = 4;
39 constexpr int32_t AXIS_UPDATE = 5;
40 constexpr int32_t AXIS_END = 6;
41 constexpr int32_t MIDDLE = 1;
42 constexpr int32_t RIGHT = 2;
43 constexpr int32_t MOUSE_FLOW = 15;
44 } // namespace
45
Start()46 int32_t InputMonitor::Start()
47 {
48 CALL_DEBUG_ENTER;
49 std::lock_guard<std::mutex> guard(mutex_);
50 if (monitorId_ < 0) {
51 monitorId_ = InputMgr->AddMonitor(shared_from_this());
52 }
53 return monitorId_;
54 }
55
Stop()56 void InputMonitor::Stop()
57 {
58 CALL_DEBUG_ENTER;
59 std::lock_guard<std::mutex> guard(mutex_);
60 if (monitorId_ < 0) {
61 MMI_HILOGE("Invalid values");
62 return;
63 }
64 InputMgr->RemoveMonitor(monitorId_);
65 monitorId_ = -1;
66 return;
67 }
68
SetCallback(std::function<void (std::shared_ptr<PointerEvent>)> callback)69 void InputMonitor::SetCallback(std::function<void(std::shared_ptr<PointerEvent>)> callback)
70 {
71 std::lock_guard<std::mutex> guard(mutex_);
72 callback_ = callback;
73 }
74
OnInputEvent(std::shared_ptr<PointerEvent> pointerEvent) const75 void InputMonitor::OnInputEvent(std::shared_ptr<PointerEvent> pointerEvent) const
76 {
77 CALL_DEBUG_ENTER;
78 CHKPV(pointerEvent);
79 if (JsInputMonMgr.GetMonitor(id_) == nullptr) {
80 MMI_HILOGE("Failed to process pointer event, id:%{public}d", id_);
81 return;
82 }
83 if (pointerEvent->GetSourceType() == PointerEvent::SOURCE_TYPE_MOUSE
84 && pointerEvent->GetPointerAction() == PointerEvent::POINTER_ACTION_MOVE) {
85 static int32_t count = MOUSE_FLOW;
86 if (++count < MOUSE_FLOW) {
87 pointerEvent->MarkProcessed();
88 return;
89 } else {
90 count = 0;
91 }
92 }
93 std::function<void(std::shared_ptr<PointerEvent>)> callback;
94 {
95 std::lock_guard<std::mutex> guard(mutex_);
96 if (pointerEvent->GetSourceType() == PointerEvent::SOURCE_TYPE_TOUCHSCREEN) {
97 if (JsInputMonMgr.GetMonitor(id_)->GetTypeName() != "touch") {
98 pointerEvent->MarkProcessed();
99 return;
100 }
101 if (pointerEvent->GetPointerIds().size() == 1) {
102 if (pointerEvent->GetPointerAction() == PointerEvent::POINTER_ACTION_DOWN) {
103 consumed_ = false;
104 }
105 }
106 }
107 if (pointerEvent->GetSourceType() == PointerEvent::SOURCE_TYPE_MOUSE) {
108 if (JsInputMonMgr.GetMonitor(id_)->GetTypeName() != "mouse") {
109 return;
110 }
111 if (pointerEvent->GetPointerIds().size() == 1) {
112 if (pointerEvent->GetPointerAction() == PointerEvent::POINTER_ACTION_DOWN) {
113 consumed_ = false;
114 }
115 }
116 }
117 callback = callback_;
118 }
119 CHKPV(callback);
120 callback(pointerEvent);
121 }
122
SetId(int32_t id)123 void InputMonitor::SetId(int32_t id)
124 {
125 id_ = id;
126 }
127
OnInputEvent(std::shared_ptr<KeyEvent> keyEvent) const128 void InputMonitor::OnInputEvent(std::shared_ptr<KeyEvent> keyEvent) const {}
129
OnInputEvent(std::shared_ptr<AxisEvent> axisEvent) const130 void InputMonitor::OnInputEvent(std::shared_ptr<AxisEvent> axisEvent) const {}
131
MarkConsumed(int32_t eventId)132 void InputMonitor::MarkConsumed(int32_t eventId)
133 {
134 std::lock_guard<std::mutex> guard(mutex_);
135 if (consumed_) {
136 MMI_HILOGD("The consumed_ is true");
137 return;
138 }
139 if (monitorId_ < 0) {
140 MMI_HILOGE("Invalid values");
141 return;
142 }
143 InputMgr->MarkConsumed(monitorId_, eventId);
144 consumed_ = true;
145 }
146
JsInputMonitor(napi_env jsEnv,const std::string & typeName,napi_value callback,int32_t id)147 JsInputMonitor::JsInputMonitor(napi_env jsEnv, const std::string &typeName, napi_value callback, int32_t id)
148 : monitor_(std::make_shared<InputMonitor>()),
149 jsEnv_(jsEnv),
150 typeName_(typeName),
151 monitorId_(id)
152 {
153 SetCallback(callback);
154 if (monitor_ == nullptr) {
155 MMI_HILOGE("The monitor is null");
156 return;
157 }
158 monitor_->SetCallback([jsId = id](std::shared_ptr<PointerEvent> pointerEvent) {
159 auto& jsMonitor {JsInputMonMgr.GetMonitor(jsId)};
160 CHKPV(jsMonitor);
161 jsMonitor->OnPointerEvent(pointerEvent);
162 });
163 monitor_->SetId(monitorId_);
164 }
165
SetCallback(napi_value callback)166 void JsInputMonitor::SetCallback(napi_value callback)
167 {
168 if (receiver_ == nullptr && jsEnv_ != nullptr) {
169 uint32_t refCount = 1;
170 auto status = napi_create_reference(jsEnv_, callback, refCount, &receiver_);
171 if (status != napi_ok) {
172 THROWERR(jsEnv_, "napi_create_reference is failed");
173 return;
174 }
175 }
176 }
177
MarkConsumed(int32_t eventId)178 void JsInputMonitor::MarkConsumed(int32_t eventId)
179 {
180 CHKPV(monitor_);
181 monitor_->MarkConsumed(eventId);
182 }
183
IsMatch(napi_env jsEnv,napi_value callback)184 int32_t JsInputMonitor::IsMatch(napi_env jsEnv, napi_value callback)
185 {
186 CHKPR(callback, ERROR_NULL_POINTER);
187 if (jsEnv_ == jsEnv) {
188 napi_value handlerTemp = nullptr;
189 auto status = napi_get_reference_value(jsEnv_, receiver_, &handlerTemp);
190 if (status != napi_ok) {
191 THROWERR(jsEnv_, "napi_get_reference_value is failed");
192 return NAPI_ERR;
193 }
194 bool isEquals = false;
195 status = napi_strict_equals(jsEnv_, handlerTemp, callback, &isEquals);
196 if (status != napi_ok) {
197 THROWERR(jsEnv_, "napi_strict_equals is failed");
198 return NAPI_ERR;
199 }
200 if (isEquals) {
201 MMI_HILOGI("Js callback match success");
202 return RET_OK;
203 }
204 MMI_HILOGI("Js callback match failed");
205 return RET_ERR;
206 }
207 MMI_HILOGI("Js callback match failed");
208 return RET_ERR;
209 }
210
IsMatch(napi_env jsEnv)211 int32_t JsInputMonitor::IsMatch(napi_env jsEnv)
212 {
213 if (jsEnv_ == jsEnv) {
214 MMI_HILOGI("Env match success");
215 return RET_OK;
216 }
217 MMI_HILOGI("Env match failed");
218 return RET_ERR;
219 }
220
GetAction(int32_t action) const221 std::string JsInputMonitor::GetAction(int32_t action) const
222 {
223 switch (action) {
224 case PointerEvent::POINTER_ACTION_CANCEL: {
225 return "cancel";
226 }
227 case PointerEvent::POINTER_ACTION_DOWN: {
228 return "down";
229 }
230 case PointerEvent::POINTER_ACTION_MOVE: {
231 return "move";
232 }
233 case PointerEvent::POINTER_ACTION_UP: {
234 return "up";
235 }
236 default: {
237 return "";
238 }
239 }
240 }
241
GetJsPointerItem(const PointerEvent::PointerItem & item,napi_value value) const242 int32_t JsInputMonitor::GetJsPointerItem(const PointerEvent::PointerItem &item, napi_value value) const
243 {
244 if (SetNameProperty(jsEnv_, value, "globalX", item.GetDisplayX()) != napi_ok) {
245 MMI_HILOGE("Set globalX property failed");
246 return RET_ERR;
247 }
248 if (SetNameProperty(jsEnv_, value, "globalY", item.GetDisplayY()) != napi_ok) {
249 MMI_HILOGE("Set globalY property failed");
250 return RET_ERR;
251 }
252 if (SetNameProperty(jsEnv_, value, "localX", 0) != napi_ok) {
253 MMI_HILOGE("Set localX property failed");
254 return RET_ERR;
255 }
256 if (SetNameProperty(jsEnv_, value, "localY", 0) != napi_ok) {
257 MMI_HILOGE("Set localY property failed");
258 return RET_ERR;
259 }
260 int32_t touchArea = (item.GetWidth() + item.GetHeight()) / 2;
261 if (SetNameProperty(jsEnv_, value, "size", touchArea) != napi_ok) {
262 MMI_HILOGE("Set size property failed");
263 return RET_ERR;
264 }
265 if (SetNameProperty(jsEnv_, value, "force", item.GetPressure()) != napi_ok) {
266 MMI_HILOGE("Set force property failed");
267 return RET_ERR;
268 }
269 return RET_OK;
270 }
271
TransformPointerEvent(const std::shared_ptr<PointerEvent> pointerEvent,napi_value result)272 int32_t JsInputMonitor::TransformPointerEvent(const std::shared_ptr<PointerEvent> pointerEvent, napi_value result)
273 {
274 CHKPR(pointerEvent, ERROR_NULL_POINTER);
275 if (SetNameProperty(jsEnv_, result, "type", GetAction(pointerEvent->GetPointerAction())) != napi_ok) {
276 MMI_HILOGE("Set type property failed");
277 return RET_ERR;
278 }
279 napi_value pointers = nullptr;
280 auto status = napi_create_array(jsEnv_, &pointers);
281 if (status != napi_ok) {
282 MMI_HILOGE("napi_create_array is failed");
283 return RET_ERR;
284 }
285 std::vector<PointerEvent::PointerItem> pointerItems;
286 for (const auto &item : pointerEvent->GetPointerIds()) {
287 PointerEvent::PointerItem pointerItem;
288 if (!pointerEvent->GetPointerItem(item, pointerItem)) {
289 MMI_HILOGE("Get pointer item failed");
290 return RET_ERR;
291 }
292 pointerItems.push_back(pointerItem);
293 }
294 uint32_t index = 0;
295 napi_value currentPointer = nullptr;
296 int32_t currentPointerId = pointerEvent->GetPointerId();
297 for (const auto &it : pointerItems) {
298 napi_value element = nullptr;
299 status = napi_create_object(jsEnv_, &element);
300 if (status != napi_ok) {
301 MMI_HILOGE("napi_create_object is failed");
302 return RET_ERR;
303 }
304 if (currentPointerId == it.GetPointerId()) {
305 status = napi_create_object(jsEnv_, ¤tPointer);
306 if (status != napi_ok) {
307 MMI_HILOGE("napi_create_object is failed");
308 return RET_ERR;
309 }
310 if (GetJsPointerItem(it, currentPointer) != RET_OK) {
311 MMI_HILOGE("Transform pointerItem failed");
312 return RET_ERR;
313 }
314 if (SetNameProperty(jsEnv_, result, "timestamp", pointerEvent->GetActionTime()) != napi_ok) {
315 MMI_HILOGE("Set timestamp property failed");
316 return RET_ERR;
317 }
318 if (SetNameProperty(jsEnv_, result, "deviceId", it.GetDeviceId()) != napi_ok) {
319 MMI_HILOGE("Set deviceId property failed");
320 return RET_ERR;
321 }
322 }
323 if (GetJsPointerItem(it, element) != RET_OK) {
324 MMI_HILOGE("Transform pointerItem failed");
325 return RET_ERR;
326 }
327 status = napi_set_element(jsEnv_, pointers, index, element);
328 if (status != napi_ok) {
329 MMI_HILOGE("napi_set_element is failed");
330 return RET_ERR;
331 }
332 ++index;
333 }
334 if (SetNameProperty(jsEnv_, result, "touches", pointers) != napi_ok) {
335 MMI_HILOGE("Set touches property failed");
336 return RET_ERR;
337 }
338 if (SetNameProperty(jsEnv_, result, "changedTouches", currentPointer) != napi_ok) {
339 MMI_HILOGE("Set changedTouches property failed");
340 return RET_ERR;
341 }
342 return RET_OK;
343 }
344
GetFuns(const std::shared_ptr<PointerEvent> pointerEvent,const PointerEvent::PointerItem & item)345 MapFun JsInputMonitor::GetFuns(const std::shared_ptr<PointerEvent> pointerEvent, const PointerEvent::PointerItem& item)
346 {
347 MapFun mapFun;
348 mapFun["actionTime"] = std::bind(&PointerEvent::GetActionTime, pointerEvent);
349 mapFun["screenId"] = std::bind(&PointerEvent::GetTargetDisplayId, pointerEvent);
350 mapFun["windowId"] = std::bind(&PointerEvent::GetTargetWindowId, pointerEvent);
351 mapFun["deviceId"] = std::bind(&PointerEvent::PointerItem::GetDeviceId, item);
352 mapFun["windowX"] = std::bind(&PointerEvent::PointerItem::GetDisplayX, item);
353 mapFun["windowY"] = std::bind(&PointerEvent::PointerItem::GetDisplayY, item);
354 mapFun["screenX"] = std::bind(&PointerEvent::PointerItem::GetWindowX, item);
355 mapFun["screenY"] = std::bind(&PointerEvent::PointerItem::GetWindowY, item);
356 #ifdef OHOS_BUILD_ENABLE_COOPERATE
357 mapFun["rawDeltaX"] = std::bind(&PointerEvent::PointerItem::GetRawDx, item);
358 mapFun["rawDeltaY"] = std::bind(&PointerEvent::PointerItem::GetRawDy, item);
359 #endif // OHOS_BUILD_ENABLE_COOPERATE
360 return mapFun;
361 }
362
SetMouseProperty(const std::shared_ptr<PointerEvent> pointerEvent,const PointerEvent::PointerItem & item,napi_value result)363 bool JsInputMonitor::SetMouseProperty(const std::shared_ptr<PointerEvent> pointerEvent,
364 const PointerEvent::PointerItem& item, napi_value result)
365 {
366 int32_t buttonId = pointerEvent->GetButtonId();
367 if (buttonId == PointerEvent::MOUSE_BUTTON_MIDDLE) {
368 buttonId = MIDDLE;
369 } else if (buttonId == PointerEvent::MOUSE_BUTTON_RIGHT) {
370 buttonId = RIGHT;
371 }
372 if (SetNameProperty(jsEnv_, result, "button", buttonId) != napi_ok) {
373 THROWERR(jsEnv_, "Set property failed");
374 return false;
375 }
376
377 auto mapFun = GetFuns(pointerEvent, item);
378 for (const auto &it : mapFun) {
379 if (SetNameProperty(jsEnv_, result, it.first, it.second()) != napi_ok) {
380 THROWERR(jsEnv_, "Set property failed");
381 return false;
382 }
383 }
384 return true;
385 }
386
GetAxesValue(const std::shared_ptr<PointerEvent> pointerEvent,napi_value element)387 bool JsInputMonitor::GetAxesValue(const std::shared_ptr<PointerEvent> pointerEvent, napi_value element)
388 {
389 CALL_DEBUG_ENTER;
390 CHKPF(pointerEvent);
391 double axisValue = -1.0;
392 int32_t axis = -1;
393 if (pointerEvent->HasAxis(PointerEvent::AXIS_TYPE_SCROLL_VERTICAL)) {
394 axisValue = pointerEvent->GetAxisValue(PointerEvent::AXIS_TYPE_SCROLL_VERTICAL);
395 axis = AXIS_TYPE_SCROLL_VERTICAL;
396 }
397 if (pointerEvent->HasAxis(PointerEvent::AXIS_TYPE_SCROLL_HORIZONTAL)) {
398 axisValue = pointerEvent->GetAxisValue(PointerEvent::AXIS_TYPE_SCROLL_HORIZONTAL);
399 axis = AXIS_TYPE_SCROLL_HORIZONTAL;
400 }
401 if (pointerEvent->HasAxis(PointerEvent::AXIS_TYPE_PINCH)) {
402 axisValue = pointerEvent->GetAxisValue(PointerEvent::AXIS_TYPE_PINCH);
403 axis = AXIS_TYPE_PINCH;
404 }
405 if (SetNameProperty(jsEnv_, element, "axis", axis) != napi_ok) {
406 THROWERR(jsEnv_, "Set property of axis failed");
407 return false;
408 }
409 if (SetNameProperty(jsEnv_, element, "value", axisValue) != napi_ok) {
410 THROWERR(jsEnv_, "Set property of value failed");
411 return false;
412 }
413 return true;
414 }
415
GetMousePointerItem(const std::shared_ptr<PointerEvent> pointerEvent,napi_value result)416 int32_t JsInputMonitor::GetMousePointerItem(const std::shared_ptr<PointerEvent> pointerEvent, napi_value result)
417 {
418 CALL_DEBUG_ENTER;
419 CHKPR(pointerEvent, ERROR_NULL_POINTER);
420 napi_value axes = nullptr;
421 napi_status status = napi_create_array(jsEnv_, &axes);
422 if (status != napi_ok || axes == nullptr) {
423 THROWERR(jsEnv_, "napi_create_array is failed");
424 return RET_ERR;
425 }
426 uint32_t index = 0;
427 int32_t currentPointerId = pointerEvent->GetPointerId();
428 std::vector<int32_t> pointerIds { pointerEvent->GetPointerIds() };
429 for (const auto& pointerId : pointerIds) {
430 if (pointerId == currentPointerId) {
431 PointerEvent::PointerItem item;
432 if (!pointerEvent->GetPointerItem(pointerId, item)) {
433 MMI_HILOGE("Invalid pointer:%{public}d", pointerId);
434 return RET_ERR;
435 }
436 if (SetNameProperty(jsEnv_, result, "id", currentPointerId) != napi_ok) {
437 THROWERR(jsEnv_, "Set property of id failed");
438 return false;
439 }
440 if (!SetMouseProperty(pointerEvent, item, result)) {
441 MMI_HILOGE("Set property of mouse failed");
442 return RET_ERR;
443 }
444 }
445 napi_value element = nullptr;
446 if (napi_create_object(jsEnv_, &element) != napi_ok) {
447 THROWERR(jsEnv_, "napi_create_object is failed");
448 return false;
449 }
450 if (!GetAxesValue(pointerEvent, element)) {
451 THROWERR(jsEnv_, "Get axesValue failed");
452 return RET_ERR;
453 }
454 status = napi_set_element(jsEnv_, axes, index, element);
455 if (status != napi_ok) {
456 THROWERR(jsEnv_, "Napi set element in axes failed");
457 return RET_ERR;
458 }
459 ++index;
460 }
461 if (SetNameProperty(jsEnv_, result, "axes", axes) != napi_ok) {
462 THROWERR(jsEnv_, "Set property of axes failed");
463 return RET_ERR;
464 }
465 return RET_OK;
466 }
467
GetPressedButtons(const std::set<int32_t> & pressedButtons,napi_value result)468 bool JsInputMonitor::GetPressedButtons(const std::set<int32_t>& pressedButtons, napi_value result)
469 {
470 CALL_DEBUG_ENTER;
471 napi_value value = nullptr;
472 napi_status status = napi_create_array(jsEnv_, &value);
473 if (status != napi_ok || value == nullptr) {
474 THROWERR(jsEnv_, "napi_create_array is failed");
475 return false;
476 }
477 uint32_t index = 0;
478 for (const auto &item : pressedButtons) {
479 int32_t buttonId = item;
480 if (buttonId == PointerEvent::MOUSE_BUTTON_MIDDLE) {
481 buttonId = MIDDLE;
482 } else if (buttonId == PointerEvent::MOUSE_BUTTON_RIGHT) {
483 buttonId = RIGHT;
484 }
485 napi_value element = nullptr;
486 if (napi_create_int32(jsEnv_, buttonId, &element) != napi_ok) {
487 THROWERR(jsEnv_, "Napi create int32 failed");
488 return false;
489 }
490 status = napi_set_element(jsEnv_, value, index, element);
491 if (status != napi_ok) {
492 THROWERR(jsEnv_, "Napi set element failed");
493 return false;
494 }
495 ++index;
496 }
497 if (SetNameProperty(jsEnv_, result, "pressedButtons", value) != napi_ok) {
498 THROWERR(jsEnv_, "Set property of pressedButtons failed");
499 return false;
500 }
501 return true;
502 }
503
GetPressedKeys(const std::vector<int32_t> & pressedKeys,napi_value result)504 bool JsInputMonitor::GetPressedKeys(const std::vector<int32_t>& pressedKeys, napi_value result)
505 {
506 CALL_DEBUG_ENTER;
507 napi_value value = nullptr;
508 napi_status status = napi_create_array(jsEnv_, &value);
509 if (status != napi_ok || value == nullptr) {
510 THROWERR(jsEnv_, "napi_create_array is failed");
511 return false;
512 }
513 uint32_t index = 0;
514 for (const auto &it : pressedKeys) {
515 napi_value element = nullptr;
516 if (napi_create_int32(jsEnv_, it, &element) != napi_ok) {
517 THROWERR(jsEnv_, "Napi create int32 failed");
518 return false;
519 }
520 status = napi_set_element(jsEnv_, value, index, element);
521 if (status != napi_ok) {
522 THROWERR(jsEnv_, "Napi set element failed");
523 return false;
524 }
525 ++index;
526 }
527 if (SetNameProperty(jsEnv_, result, "pressedKeys", value) != napi_ok) {
528 THROWERR(jsEnv_, "Set property of pressedKeys failed");
529 return false;
530 }
531 return true;
532 }
533
HasKeyCode(const std::vector<int32_t> & pressedKeys,int32_t keyCode)534 bool JsInputMonitor::HasKeyCode(const std::vector<int32_t>& pressedKeys, int32_t keyCode)
535 {
536 return std::find(pressedKeys.begin(), pressedKeys.end(), keyCode) != pressedKeys.end();
537 }
538
GetPressedKey(const std::vector<int32_t> & pressedKeys,napi_value result)539 bool JsInputMonitor::GetPressedKey(const std::vector<int32_t>& pressedKeys, napi_value result)
540 {
541 CALL_DEBUG_ENTER;
542 bool isExists = HasKeyCode(pressedKeys, KeyEvent::KEYCODE_CTRL_LEFT)
543 || HasKeyCode(pressedKeys, KeyEvent::KEYCODE_CTRL_RIGHT);
544 if (SetNameProperty(jsEnv_, result, "ctrlKey", isExists) != napi_ok) {
545 THROWERR(jsEnv_, "Set ctrlKey with failed");
546 return false;
547 }
548 isExists = HasKeyCode(pressedKeys, KeyEvent::KEYCODE_ALT_LEFT)
549 || HasKeyCode(pressedKeys, KeyEvent::KEYCODE_ALT_RIGHT);
550 if (SetNameProperty(jsEnv_, result, "altKey", isExists) != napi_ok) {
551 THROWERR(jsEnv_, "Set altKey failed");
552 return false;
553 }
554 isExists = HasKeyCode(pressedKeys, KeyEvent::KEYCODE_SHIFT_LEFT)
555 || HasKeyCode(pressedKeys, KeyEvent::KEYCODE_SHIFT_RIGHT);
556 if (SetNameProperty(jsEnv_, result, "shiftKey", isExists) != napi_ok) {
557 THROWERR(jsEnv_, "Set shiftKey failed");
558 return false;
559 }
560 isExists = HasKeyCode(pressedKeys, KeyEvent::KEYCODE_META_LEFT)
561 || HasKeyCode(pressedKeys, KeyEvent::KEYCODE_META_RIGHT);
562 if (SetNameProperty(jsEnv_, result, "logoKey", isExists) != napi_ok) {
563 THROWERR(jsEnv_, "Set logoKey failed");
564 return false;
565 }
566 isExists = HasKeyCode(pressedKeys, KeyEvent::KEYCODE_FN);
567 if (SetNameProperty(jsEnv_, result, "fnKey", isExists) != napi_ok) {
568 THROWERR(jsEnv_, "Set fnKey failed");
569 return false;
570 }
571 return true;
572 }
573
TransformTsActionValue(int32_t pointerAction)574 int32_t JsInputMonitor::TransformTsActionValue(int32_t pointerAction)
575 {
576 switch (pointerAction) {
577 case PointerEvent::POINTER_ACTION_CANCEL: {
578 return CANCEL;
579 }
580 case PointerEvent::POINTER_ACTION_MOVE: {
581 return MOVE;
582 }
583 case PointerEvent::POINTER_ACTION_BUTTON_DOWN: {
584 return BUTTON_DOWN;
585 }
586 case PointerEvent::POINTER_ACTION_BUTTON_UP: {
587 return BUTTON_UP;
588 }
589 case PointerEvent::POINTER_ACTION_AXIS_BEGIN: {
590 return AXIS_BEGIN;
591 }
592 case PointerEvent::POINTER_ACTION_AXIS_UPDATE: {
593 return AXIS_UPDATE;
594 }
595 case PointerEvent::POINTER_ACTION_AXIS_END: {
596 return AXIS_END;
597 }
598 default: {
599 MMI_HILOGE("Abnormal pointer action");
600 return RET_ERR;
601 }
602 }
603 }
604
TransformMousePointerEvent(const std::shared_ptr<PointerEvent> pointerEvent,napi_value result)605 int32_t JsInputMonitor::TransformMousePointerEvent(const std::shared_ptr<PointerEvent> pointerEvent, napi_value result)
606 {
607 CALL_DEBUG_ENTER;
608 CHKPR(pointerEvent, ERROR_NULL_POINTER);
609 int32_t actionValue = TransformTsActionValue(pointerEvent->GetPointerAction());
610 if (actionValue == RET_ERR) {
611 MMI_HILOGE("Transform Action Value failed");
612 return RET_ERR;
613 }
614 if (SetNameProperty(jsEnv_, result, "action", actionValue) != napi_ok) {
615 MMI_HILOGE("Set property of action failed");
616 return RET_ERR;
617 }
618 std::vector<int32_t> pressedKeys = pointerEvent->GetPressedKeys();
619 if (!GetPressedKeys(pressedKeys, result)) {
620 MMI_HILOGE("Get pressedButtons failed");
621 return RET_ERR;
622 }
623 if (!GetPressedKey(pressedKeys, result)) {
624 MMI_HILOGE("Get singlePressedKey failed");
625 return RET_ERR;
626 }
627 if (GetMousePointerItem(pointerEvent, result) != RET_OK) {
628 MMI_HILOGE("Get item of mousePointer failed");
629 return RET_ERR;
630 }
631 std::set<int32_t> pressedButtons = pointerEvent->GetPressedButtons();
632 if (!GetPressedButtons(pressedButtons, result)) {
633 MMI_HILOGE("Get pressedKeys failed");
634 return RET_ERR;
635 }
636 return RET_OK;
637 }
638
Start()639 int32_t JsInputMonitor::Start()
640 {
641 CALL_DEBUG_ENTER;
642 CHKPF(monitor_);
643 if (isMonitoring_) {
644 MMI_HILOGW("Js is monitoring");
645 return RET_OK;
646 }
647 int32_t ret = monitor_->Start();
648 if (ret >= 0) {
649 isMonitoring_ = true;
650 }
651 return ret;
652 }
653
~JsInputMonitor()654 JsInputMonitor::~JsInputMonitor()
655 {
656 CALL_DEBUG_ENTER;
657 if (isMonitoring_) {
658 isMonitoring_ = false;
659 if (monitor_ != nullptr) {
660 monitor_->Stop();
661 }
662 }
663 uint32_t refCount = 0;
664 auto status = napi_reference_unref(jsEnv_, receiver_, &refCount);
665 if (status != napi_ok) {
666 THROWERR(jsEnv_, "napi_reference_unref is failed");
667 return;
668 }
669 }
670
Stop()671 void JsInputMonitor::Stop()
672 {
673 CALL_DEBUG_ENTER;
674 CHKPV(monitor_);
675 if (isMonitoring_) {
676 isMonitoring_ = false;
677 if (monitor_ != nullptr) {
678 monitor_->Stop();
679 }
680 }
681 }
682
GetId() const683 int32_t JsInputMonitor::GetId() const
684 {
685 return monitorId_;
686 }
687
GetTypeName() const688 std::string JsInputMonitor::GetTypeName() const
689 {
690 return typeName_;
691 }
692
OnPointerEvent(std::shared_ptr<PointerEvent> pointerEvent)693 void JsInputMonitor::OnPointerEvent(std::shared_ptr<PointerEvent> pointerEvent)
694 {
695 CALL_DEBUG_ENTER;
696 if (!isMonitoring_) {
697 MMI_HILOGE("Js monitor stop");
698 return;
699 }
700 CHKPV(monitor_);
701 CHKPV(pointerEvent);
702 {
703 std::lock_guard<std::mutex> guard(mutex_);
704 if (!evQueue_.empty()) {
705 if (pointerEvent->GetPointerAction() == PointerEvent::POINTER_ACTION_DOWN ||
706 pointerEvent->GetPointerAction() == PointerEvent::POINTER_ACTION_UP) {
707 auto markProcessedEvent = evQueue_.front();
708 CHKPV(markProcessedEvent);
709 markProcessedEvent->MarkProcessed();
710 std::queue<std::shared_ptr<PointerEvent>> tmp;
711 std::swap(evQueue_, tmp);
712 evQueue_.push(pointerEvent);
713 }
714 } else {
715 evQueue_.push(pointerEvent);
716 }
717 jsTaskNum_ = 1;
718 }
719
720 if (!evQueue_.empty()) {
721 int32_t *id = &monitorId_;
722 uv_work_t *work = new (std::nothrow) uv_work_t;
723 CHKPV(work);
724 work->data = id;
725 uv_loop_s *loop = nullptr;
726 auto status = napi_get_uv_event_loop(jsEnv_, &loop);
727 if (status != napi_ok) {
728 THROWERR(jsEnv_, "napi_get_uv_event_loop is failed");
729 delete work;
730 {
731 std::lock_guard<std::mutex> guard(mutex_);
732 jsTaskNum_ = 0;
733 }
734 return;
735 }
736 uv_queue_work(loop, work, [](uv_work_t *work) {}, &JsInputMonitor::JsCallback);
737 }
738 }
739
JsCallback(uv_work_t * work,int32_t status)740 void JsInputMonitor::JsCallback(uv_work_t *work, int32_t status)
741 {
742 CALL_DEBUG_ENTER;
743 CHKPV(work);
744 int32_t *id = static_cast<int32_t *>(work->data);
745 delete work;
746 work = nullptr;
747 auto& jsMonitor {JsInputMonMgr.GetMonitor(*id)};
748 CHKPV(jsMonitor);
749 jsMonitor->OnPointerEventInJsThread(jsMonitor->GetTypeName());
750 id = nullptr;
751 }
752
OnPointerEventInJsThread(const std::string & typeName)753 void JsInputMonitor::OnPointerEventInJsThread(const std::string &typeName)
754 {
755 CALL_DEBUG_ENTER;
756 std::lock_guard<std::mutex> guard(mutex_);
757 jsTaskNum_ = 0;
758 if (!isMonitoring_) {
759 MMI_HILOGE("Js monitor stop");
760 return;
761 }
762 CHKPV(jsEnv_);
763 CHKPV(receiver_);
764 while (!evQueue_.empty()) {
765 if (!isMonitoring_) {
766 MMI_HILOGE("Js monitor stop handle callback");
767 break;
768 }
769 napi_handle_scope scope = nullptr;
770 napi_open_handle_scope(jsEnv_, &scope);
771 if (scope == nullptr) {
772 MMI_HILOGE("scope is nullptr");
773 return;
774 }
775 auto pointerEvent = evQueue_.front();
776 CHKPC(pointerEvent);
777 evQueue_.pop();
778 napi_value napiPointer = nullptr;
779 auto status = napi_create_object(jsEnv_, &napiPointer);
780 if (status != napi_ok) {
781 pointerEvent->MarkProcessed();
782 break;
783 }
784 auto ret = RET_ERR;
785 if (typeName == "touch") {
786 ret = TransformPointerEvent(pointerEvent, napiPointer);
787 } else {
788 ret = TransformMousePointerEvent(pointerEvent, napiPointer);
789 }
790 if (ret != RET_OK || napiPointer == nullptr) {
791 pointerEvent->MarkProcessed();
792 break;
793 }
794 napi_value callback = nullptr;
795 status = napi_get_reference_value(jsEnv_, receiver_, &callback);
796 if (status != napi_ok) {
797 pointerEvent->MarkProcessed();
798 break;
799 }
800 napi_value result = nullptr;
801 status = napi_call_function(jsEnv_, nullptr, callback, 1, &napiPointer, &result);
802 if (status != napi_ok) {
803 pointerEvent->MarkProcessed();
804 break;
805 }
806 if (typeName == "touch") {
807 pointerEvent->MarkProcessed();
808 bool retValue = false;
809 status = napi_get_value_bool(jsEnv_, result, &retValue);
810 if (status != napi_ok) {
811 return;
812 }
813 if (retValue) {
814 auto eventId = pointerEvent->GetId();
815 MarkConsumed(eventId);
816 }
817 }
818 napi_close_handle_scope(jsEnv_, scope);
819 }
820 }
821 } // namespace MMI
822 } // namespace OHOS
823