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 "dinput_sink_state.h"
17
18#include <dirent.h>
19#include <fcntl.h>
20#include <pthread.h>
21#include <thread>
22#include <unistd.h>
23#include <vector>
24
25#include "dinput_errcode.h"
26#include "dinput_log.h"
27#include "dinput_utils_tool.h"
28#include "distributed_input_collector.h"
29#include "distributed_input_sink_transport.h"
30
31namespace OHOS {
32namespace DistributedHardware {
33namespace DistributedInput {
34IMPLEMENT_SINGLE_INSTANCE(DInputSinkState);
35DInputSinkState::~DInputSinkState()
36{
37    Release();
38}
39
40int32_t DInputSinkState::Init()
41{
42    DHLOGI("DInputSinkState Init.");
43    touchPadEventFragMgr_ = std::make_shared<TouchPadEventFragmentMgr>();
44    return DH_SUCCESS;
45}
46
47int32_t DInputSinkState::Release()
48{
49    DHLOGI("DInputSinkState Release.");
50    {
51        std::lock_guard<std::mutex> mapLock(operationMutex_);
52        dhIdStateMap_.clear();
53    }
54    ClearDeviceStates();
55    return DH_SUCCESS;
56}
57
58int32_t DInputSinkState::RecordDhIds(const std::vector<std::string> &dhIds, DhIdState state, const int32_t sessionId)
59{
60    DHLOGI("RecordDhIds dhIds size = %{public}zu", dhIds.size());
61    std::lock_guard<std::mutex> mapLock(operationMutex_);
62    for (const auto &dhid : dhIds) {
63        DHLOGD("add dhid : %{public}s, state : %{public}d.", GetAnonyString(dhid).c_str(), state);
64        dhIdStateMap_[dhid] = state;
65    }
66
67    if (state == DhIdState::THROUGH_OUT) {
68        SimulateEventInjectToSrc(sessionId, dhIds);
69    }
70    lastSessionId_ = sessionId;
71    return DH_SUCCESS;
72}
73
74int32_t DInputSinkState::RemoveDhIds(const std::vector<std::string> &dhIds)
75{
76    DHLOGI("RemoveDhIds dhIds size = %{public}zu", dhIds.size());
77    std::lock_guard<std::mutex> mapLock(operationMutex_);
78    for (const auto &dhid : dhIds) {
79        DHLOGD("delete dhid : %{public}s", GetAnonyString(dhid).c_str());
80        dhIdStateMap_.erase(dhid);
81    }
82    return DH_SUCCESS;
83}
84
85std::shared_ptr<TouchPadEventFragmentMgr> DInputSinkState::GetTouchPadEventFragMgr()
86{
87    return this->touchPadEventFragMgr_;
88}
89
90DhIdState DInputSinkState::GetStateByDhid(const std::string &dhId)
91{
92    std::lock_guard<std::mutex> mapLock(operationMutex_);
93    if (dhIdStateMap_.find(dhId) == dhIdStateMap_.end()) {
94        DHLOGE("dhId : %{public}s not exist.", GetAnonyString(dhId).c_str());
95        return DhIdState::THROUGH_IN;
96    }
97    return dhIdStateMap_[dhId];
98}
99
100void DInputSinkState::SimulateMouseBtnMouseUpState(const std::string &dhId, const struct RawEvent &event)
101{
102    DHLOGI("Sinmulate Mouse BTN_MOUSE UP state to source, dhId: %{public}s", GetAnonyString(dhId).c_str());
103    int32_t scanId = GetRandomInt32(0, INT32_MAX);
104    RawEvent mscScanEv = { event.when, EV_MSC, MSC_SCAN, scanId, dhId, event.path };
105    RawEvent btnMouseUpEv = { event.when, EV_KEY, BTN_MOUSE, KEY_UP_STATE, dhId, event.path };
106    RawEvent sycReportEv = { event.when, EV_SYN, SYN_REPORT, 0x0, dhId, event.path };
107
108    std::vector<RawEvent> simEvents = { mscScanEv, btnMouseUpEv, sycReportEv };
109    DistributedInputSinkTransport::GetInstance().SendKeyStateNodeMsgBatch(lastSessionId_, simEvents);
110}
111
112void DInputSinkState::SimulateTouchPadStateReset(const std::vector<RawEvent> &events)
113{
114    DHLOGI("SimulateTouchPadStateReset events size: %{public}zu", events.size());
115    DistributedInputSinkTransport::GetInstance().SendKeyStateNodeMsgBatch(lastSessionId_, events);
116}
117
118void DInputSinkState::SimulateEventInjectToSrc(const int32_t sessionId, const std::vector<std::string> &dhIds)
119{
120    DHLOGI("SimulateEventInject enter, sessionId %{public}d, dhIds size %{public}zu", sessionId, dhIds.size());
121    // mouse/keyboard/touchpad/touchscreen event send to remote device if these device pass through.
122    if (sessionId == -1) {
123        DHLOGE("SimulateEventInjectToSrc SessionId invalid");
124        return;
125    }
126
127    for (const std::string &dhId : dhIds) {
128        SimulateKeyDownEvents(sessionId, dhId);
129        SimulateTouchPadEvents(sessionId, dhId);
130    }
131}
132
133void DInputSinkState::SimulateKeyDownEvents(const int32_t sessionId, const std::string &dhId)
134{
135    // check if this device is key event
136    std::lock_guard<std::mutex> mapLock(keyDownStateMapMtx_);
137    auto iter = keyDownStateMap_.find(dhId);
138    if (iter == keyDownStateMap_.end()) {
139        DHLOGI("The shared Device not has down state key, dhId: %{public}s", GetAnonyString(dhId).c_str());
140        return;
141    }
142
143    for (const auto &event : iter->second) {
144        DHLOGI("Simulate Key event for device path: %{public}s, dhId: %{public}s",
145            event.path.c_str(), GetAnonyString(event.descriptor).c_str());
146        SimulateKeyDownEvent(sessionId, dhId, event);
147    }
148
149    keyDownStateMap_.erase(dhId);
150}
151
152void DInputSinkState::SimulateKeyDownEvent(const int32_t sessionId, const std::string &dhId,
153    const struct RawEvent &event)
154{
155    DistributedInputSinkTransport::GetInstance().SendKeyStateNodeMsg(sessionId, dhId,
156        EV_KEY, event.code, KEY_DOWN_STATE);
157    DistributedInputSinkTransport::GetInstance().SendKeyStateNodeMsg(sessionId, dhId,
158        EV_SYN, SYN_REPORT, 0x0);
159}
160
161void DInputSinkState::SimulateTouchPadEvents(const int32_t sessionId, const std::string &dhId)
162{
163    std::vector<RawEvent> events = this->touchPadEventFragMgr_->GetAndClearEvents(dhId);
164    if (events.empty()) {
165        return;
166    }
167
168    DHLOGI("SimulateTouchPadEvents dhId: %{public}s, event size: %{public}zu", GetAnonyString(dhId).c_str(),
169        events.size());
170    DistributedInputSinkTransport::GetInstance().SendKeyStateNodeMsgBatch(sessionId, events);
171}
172
173bool DInputSinkState::IsDhIdDown(const std::string &dhId)
174{
175    std::lock_guard<std::mutex> mapLock(keyDownStateMapMtx_);
176    auto iter = keyDownStateMap_.find(dhId);
177    return iter != keyDownStateMap_.end();
178}
179
180void DInputSinkState::AddKeyDownState(struct RawEvent event)
181{
182    std::lock_guard<std::mutex> mapLock(keyDownStateMapMtx_);
183    keyDownStateMap_[event.descriptor].push_back(event);
184}
185
186void DInputSinkState::RemoveKeyDownState(struct RawEvent event)
187{
188    std::lock_guard<std::mutex> mapLock(keyDownStateMapMtx_);
189    auto iter = keyDownStateMap_.find(event.descriptor);
190    if (iter == keyDownStateMap_.end()) {
191        return;
192    }
193
194    auto evIter = std::find(keyDownStateMap_[event.descriptor].begin(),
195        keyDownStateMap_[event.descriptor].end(), event);
196    if (evIter == keyDownStateMap_[event.descriptor].end()) {
197        return;
198    }
199
200    keyDownStateMap_[event.descriptor].erase(evIter);
201    if (keyDownStateMap_[event.descriptor].empty()) {
202        keyDownStateMap_.erase(event.descriptor);
203    }
204}
205
206void DInputSinkState::CheckAndSetLongPressedKeyOrder(struct RawEvent event)
207{
208    std::lock_guard<std::mutex> mapLock(keyDownStateMapMtx_);
209    auto iter = keyDownStateMap_.find(event.descriptor);
210    if (iter == keyDownStateMap_.end()) {
211        DHLOGI("Find new pressed key, save it, node id: %{public}s, type: %{public}d, key code: %{public}d, "
212            "value: %{public}d", GetAnonyString(event.descriptor).c_str(), event.type, event.code, event.value);
213        keyDownStateMap_[event.descriptor].push_back(event);
214        return;
215    }
216
217    auto evIter = std::find(keyDownStateMap_[event.descriptor].begin(),
218        keyDownStateMap_[event.descriptor].end(), event);
219    // If not find the cache key on pressing, save it
220    if (evIter == keyDownStateMap_[event.descriptor].end()) {
221        DHLOGI("Find new pressed key, save it, node id: %{public}s, type: %{public}d, key code: %{public}d, "
222            "value: %{public}d", GetAnonyString(event.descriptor).c_str(), event.type, event.code, event.value);
223        keyDownStateMap_[event.descriptor].push_back(event);
224        return;
225    }
226
227    // it is already the last one, just return
228    if (evIter == (keyDownStateMap_[event.descriptor].end() - 1)) {
229        DHLOGI("Pressed key already last one, node id: %{public}s, type: %{public}d, key code: %{public}d, "
230            "value: %{public}d", GetAnonyString(event.descriptor).c_str(), event.type, event.code, event.value);
231        return;
232    }
233
234    // Ohterwhise, move the key to the last cached position.
235    RawEvent backEv = *evIter;
236    keyDownStateMap_[event.descriptor].erase(evIter);
237    keyDownStateMap_[event.descriptor].push_back(backEv);
238    DHLOGI("Find long pressed key: %{public}d, move the cached pressed key: %{public}d to the last position",
239        event.code, backEv.code);
240}
241
242void DInputSinkState::ClearDeviceStates()
243{
244    std::lock_guard<std::mutex> mapLock(keyDownStateMapMtx_);
245    keyDownStateMap_.clear();
246}
247} // namespace DistributedInput
248} // namespace DistributedHardware
249} // namespace OHOSs