1 /*
2  * Copyright (c) 2023-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 "touchpad_event_fragment_mgr.h"
17 
18 #include <linux/input.h>
19 
20 #include "dinput_log.h"
21 #include "dinput_utils_tool.h"
22 
23 namespace OHOS {
24 namespace DistributedHardware {
25 namespace DistributedInput {
IsPositionEvent(const RawEvent & event)26 bool TouchPadEventFragmentMgr::IsPositionEvent(const RawEvent &event)
27 {
28     if (event.type == EV_ABS && (event.code == ABS_MT_POSITION_X || event.code == ABS_MT_POSITION_Y ||
29         event.code == ABS_X || event.code == ABS_Y)) {
30         return true;
31     }
32 
33     return false;
34 }
35 
IsSynEvent(const RawEvent & event)36 bool TouchPadEventFragmentMgr::IsSynEvent(const RawEvent &event)
37 {
38     return event.type == EV_SYN && event.code == SYN_REPORT;
39 }
40 
IsWholeTouchFragments(const std::vector<TouchPadEventFragment> & events)41 bool TouchPadEventFragmentMgr::IsWholeTouchFragments(const std::vector<TouchPadEventFragment> &events)
42 {
43     return events.front().IsTouchPadOptStart() && events.back().IsTouchPadOptFinish();
44 }
45 
PushEvent(const std::string & dhId,const RawEvent & event)46 std::pair<bool, std::vector<RawEvent>> TouchPadEventFragmentMgr::PushEvent(const std::string &dhId,
47     const RawEvent &event)
48 {
49     if (IsPositionEvent(event)) {
50         return {false, {}};
51     }
52     std::lock_guard<std::mutex> lock(fragmentsMtx_);
53     if (fragments_.find(dhId) == fragments_.end()) {
54         fragments_[dhId] = {{}};
55     }
56 
57     fragments_[dhId].back().PushEvent(event);
58     if (IsSynEvent(event)) {
59         return DealSynEvent(dhId);
60     }
61     return {false, {}};
62 }
63 
DealSynEvent(const std::string & dhId)64 std::pair<bool, std::vector<RawEvent>> TouchPadEventFragmentMgr::DealSynEvent(const std::string &dhId)
65 {
66     if (fragments_[dhId].back().IsTouchPadOptFinish()) {
67         bool needSim = false;
68         std::vector<RawEvent> allEvents = {};
69         if (!IsWholeTouchFragments(fragments_[dhId])) {
70             // If not whole touch events, this means the down event occurs on the other device,
71             // so we need simulate the up actions to the other side to reset the touchpad states.
72             for (auto &frag : fragments_[dhId]) {
73                 std::vector<RawEvent> fragEvents = frag.GetEvents();
74                 allEvents.insert(allEvents.end(), fragEvents.begin(), fragEvents.end());
75             }
76             needSim = true;
77             DHLOGI("Find NOT Whole touchpad events need send back, dhId: %{public}s", GetAnonyString(dhId).c_str());
78         }
79         fragments_[dhId].clear();
80         fragments_[dhId].push_back({});
81         return {needSim, allEvents};
82     }
83 
84     if (fragments_[dhId].back().IsShouldDrop()) {
85         fragments_[dhId].pop_back();
86     }
87     fragments_[dhId].push_back({});
88     return {false, {}};
89 }
90 
Clear(const std::string & dhId)91 void TouchPadEventFragmentMgr::Clear(const std::string &dhId)
92 {
93     std::lock_guard<std::mutex> lock(fragmentsMtx_);
94     fragments_.erase(dhId);
95 }
96 
GetAndClearEvents(const std::string & dhId)97 std::vector<RawEvent> TouchPadEventFragmentMgr::GetAndClearEvents(const std::string &dhId)
98 {
99     std::lock_guard<std::mutex> lock(fragmentsMtx_);
100     std::vector<RawEvent> allEvents;
101     if (fragments_.find(dhId) == fragments_.end()) {
102         return {};
103     }
104 
105     for (auto &frag : fragments_[dhId]) {
106         std::vector<RawEvent> fragEvents = frag.GetEvents();
107         allEvents.insert(allEvents.end(), fragEvents.begin(), fragEvents.end());
108     }
109 
110     fragments_.erase(dhId);
111     return allEvents;
112 }
113 } // namespace DistributedInput
114 } // namespace DistributedHardware
115 } // namespace OHOS