• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_, &currentPointer);
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