1/*
2 * Copyright (c) 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 "input_device_mgr.h"
17
18#include "device.h"
19#include "devicestatus_define.h"
20#include "utility.h"
21
22#undef LOG_TAG
23#define LOG_TAG "InputDeviceMgr"
24
25namespace OHOS {
26namespace Msdp {
27namespace DeviceStatus {
28namespace Cooperate {
29constexpr size_t MAX_INPUT_DEV_PER_DEVICE { 10 };
30
31InputDeviceMgr::InputDeviceMgr(IContext *context) : env_(context) {}
32
33void InputDeviceMgr::Enable()
34{
35    CALL_INFO_TRACE;
36    if (enable_) {
37        return;
38    }
39    FI_HILOGI("Enable InputDeviceMgr");
40    enable_ = true;
41}
42
43void InputDeviceMgr::Disable()
44{
45    CALL_INFO_TRACE;
46    if (enable_) {
47        enable_ = false;
48    }
49    FI_HILOGI("Disable InputDeviceMgr");
50}
51
52void InputDeviceMgr::OnSoftbusSessionOpened(const DSoftbusSessionOpened &notice)
53{
54    CALL_INFO_TRACE;
55    NotifyInputDeviceToRemote(notice.networkId);
56}
57
58void InputDeviceMgr::OnSoftbusSessionClosed(const DSoftbusSessionClosed &notice)
59{
60    CALL_INFO_TRACE;
61    RemoveAllRemoteInputDevice(notice.networkId);
62}
63
64void InputDeviceMgr::OnLocalHotPlug(const InputHotplugEvent &notice)
65{
66    CALL_INFO_TRACE;
67    BroadcastHotPlugToRemote(notice);
68}
69
70void InputDeviceMgr::OnRemoteInputDevice(const DSoftbusSyncInputDevice &notice)
71{
72    CALL_INFO_TRACE;
73    std::string networkId = notice.networkId;
74    for (const auto &device : notice.devices) {
75        DispDeviceInfo(device);
76        AddRemoteInputDevice(networkId, device);
77    }
78}
79
80void InputDeviceMgr::OnRemoteHotPlug(const DSoftbusHotPlugEvent &notice)
81{
82    CALL_INFO_TRACE;
83}
84
85void InputDeviceMgr::AddVirtualInputDevice(const std::string &networkId)
86{
87    CALL_INFO_TRACE;
88    FI_HILOGI("Add virtual device from %{public}s", Utility::Anonymize(networkId).c_str());
89    for (const auto &device : remoteDevices_[networkId]) {
90        CHKPC(device);
91        AddVirtualInputDevice(networkId, device->GetId());
92    }
93}
94
95void InputDeviceMgr::RemoveVirtualInputDevice(const std::string &networkId)
96{
97    CALL_INFO_TRACE;
98    FI_HILOGI("Remove virtual device from %{public}s", Utility::Anonymize(networkId).c_str());
99    for (const auto &device : remoteDevices_[networkId]) {
100        CHKPC(device);
101        RemoveVirtualInputDevice(networkId, device->GetId());
102    }
103}
104
105void InputDeviceMgr::HandleRemoteHotPlug(const DSoftbusHotPlugEvent &notice)
106{
107    CALL_INFO_TRACE;
108    CHKPV(notice.device);
109    auto remoteDeviceId = notice.device->GetId();
110    if (notice.type == InputHotplugType::UNPLUG) {
111        if (remote2VirtualIds_.find(remoteDeviceId) == remote2VirtualIds_.end()) {
112            FI_HILOGI("No virtual matches remote deviceId:%{public}d", remoteDeviceId);
113            return;
114        }
115        RemoveVirtualInputDevice(notice.networkId, remoteDeviceId);
116    }
117    if (notice.type == InputHotplugType::PLUG) {
118        AddVirtualInputDevice(notice.networkId, remoteDeviceId);
119    }
120}
121
122void InputDeviceMgr::NotifyInputDeviceToRemote(const std::string &remoteNetworkId)
123{
124    CALL_INFO_TRACE;
125    if (!env_->GetDeviceManager().HasKeyboard()) {
126        FI_HILOGE("Local device have no keyboard, skip");
127        return;
128    }
129    auto keyboards = env_->GetDeviceManager().GetKeyboard();
130    NetPacket packet(MessageId::DSOFTBUS_INPUT_DEV_SYNC);
131    int32_t keyboardNum = static_cast<int32_t>(keyboards.size());
132    packet << keyboardNum;
133    for (const auto &keyboard : keyboards) {
134        if (SerializeDevice(keyboard, packet) != RET_OK) {
135            FI_HILOGE("SerializeDevice failed");
136            return;
137        }
138        DispDeviceInfo(keyboard);
139    }
140    if (int32_t ret = env_->GetDSoftbus().SendPacket(remoteNetworkId, packet); ret != RET_OK) {
141        FI_HILOGE("SenPacket to networkId:%{public}s failed, ret:%{public}d",
142            Utility::Anonymize(remoteNetworkId).c_str(), ret);
143        return;
144    }
145    FI_HILOGI("NotifyInputDeviceToRemote networkId:%{public}s", Utility::Anonymize(remoteNetworkId).c_str());
146}
147
148void InputDeviceMgr::BroadcastHotPlugToRemote(const InputHotplugEvent &notice)
149{
150    CALL_INFO_TRACE;
151    FI_HILOGI("HotplugType%{public}d deviceId:%{public}d", static_cast<int32_t>(notice.type), notice.deviceId);
152    if (!notice.isKeyboard) {
153        FI_HILOGI("Not keyboard, skip");
154        return;
155    }
156    NetPacket packet(MessageId::DSOFTBUS_INPUT_DEV_HOT_PLUG);
157    packet << static_cast<int32_t>(notice.type);
158    if (notice.type == InputHotplugType::PLUG) {
159        auto device = env_->GetDeviceManager().GetDevice(notice.deviceId);
160        CHKPV(device);
161        DispDeviceInfo(device);
162        if (SerializeDevice(device, packet) != RET_OK) {
163            FI_HILOGE("SerializeDevice failed");
164            return;
165        }
166    }
167    if (notice.type == InputHotplugType::UNPLUG) {
168        packet << notice.deviceId;
169        if (packet.ChkRWError()) {
170            FI_HILOGE("Write packet failed");
171            return;
172        }
173    }
174    if (int32_t ret = env_->GetDSoftbus().BroadcastPacket(packet); ret != RET_OK) {
175        FI_HILOGE("BroadcastPacket failed");
176        return;
177    }
178}
179
180void InputDeviceMgr::RemoveRemoteInputDevice(const std::string &networkId, std::shared_ptr<IDevice> device)
181{
182    CALL_INFO_TRACE;
183    if (remoteDevices_.find(networkId) == remoteDevices_.end()) {
184        FI_HILOGE("NetworkId:%{public}s have no device existed", Utility::Anonymize(networkId).c_str());
185        return;
186    }
187    DispDeviceInfo(device);
188    remoteDevices_[networkId].erase(device);
189}
190
191void InputDeviceMgr::AddRemoteInputDevice(const std::string &networkId, std::shared_ptr<IDevice> device)
192{
193    CALL_INFO_TRACE;
194    DispDeviceInfo(device);
195    if (remoteDevices_.find(networkId) != remoteDevices_.end() &&
196        remoteDevices_[networkId].size() >= MAX_INPUT_DEV_PER_DEVICE) {
197        FI_HILOGE("Input device num from networkId:%{public}s exceeds limit", Utility::Anonymize(networkId).c_str());
198        return;
199    }
200    remoteDevices_[networkId].insert(device);
201}
202
203void InputDeviceMgr::RemoveAllRemoteInputDevice(const std::string &networkId)
204{
205    CALL_INFO_TRACE;
206    if (remoteDevices_.find(networkId) == remoteDevices_.end()) {
207        FI_HILOGE("NetworkId:%{public}s have no device existed", Utility::Anonymize(networkId).c_str());
208        return;
209    }
210    remoteDevices_.erase(networkId);
211}
212
213void InputDeviceMgr::DispDeviceInfo(std::shared_ptr<IDevice> device)
214{
215    CHKPV(device);
216    FI_HILOGI("  device %{public}d:%{public}s", device->GetId(), device->GetDevPath().c_str());
217    FI_HILOGI("  sysPath:       \"%{private}s\"", device->GetSysPath().c_str());
218    FI_HILOGI("  bus:           %{public}04x", device->GetBus());
219    FI_HILOGI("  vendor:        %{public}04x", device->GetVendor());
220    FI_HILOGI("  product:       %{public}04x", device->GetProduct());
221    FI_HILOGI("  version:       %{public}04x", device->GetVersion());
222    FI_HILOGI("  name:          \"%{public}s\"", device->GetName().c_str());
223    FI_HILOGI("  location:      \"%{public}s\"", device->GetPhys().c_str());
224    FI_HILOGI("  unique id:     \"%{public}s\"", device->GetUniq().c_str());
225    FI_HILOGI("  is pointer:    %{public}s, is keyboard:%{public}s",
226        device->IsPointerDevice() ? "True" : "False", device->IsKeyboard() ? "True" : "False");
227}
228
229void InputDeviceMgr::DumpRemoteInputDevice(const std::string &networkId)
230{
231    CALL_INFO_TRACE;
232    if (remoteDevices_.find(networkId) == remoteDevices_.end()) {
233        FI_HILOGE("NetworkId:%{public}s have no device existed", Utility::Anonymize(networkId).c_str());
234        return;
235    }
236    FI_HILOGI("NetworkId%{public}s, device mount:%{public}zu", Utility::Anonymize(networkId).c_str(),
237        remoteDevices_.size());
238    for (const auto &elem : remoteDevices_[networkId]) {
239        FI_HILOGI("DeviceId:%{public}d, deviceName:%{public}s", elem->GetId(), elem->GetName().c_str());
240    }
241}
242
243int32_t InputDeviceMgr::SerializeDevice(std::shared_ptr<IDevice> device, NetPacket &packet)
244{
245    CALL_INFO_TRACE;
246    packet << device->GetId() << device->GetDevPath() << device->GetSysPath() << device->GetBus() <<
247    device->GetVendor() << device->GetProduct() << device->GetVersion() << device->GetName() <<
248    device->GetPhys() << device->GetUniq() << device->IsPointerDevice() << device->IsKeyboard() <<
249    static_cast<int32_t> (device->GetKeyboardType());
250    if (packet.ChkRWError()) {
251        FI_HILOGE("Write packet failed");
252        return RET_ERR;
253    }
254    return RET_OK;
255}
256
257std::shared_ptr<MMI::InputDevice> InputDeviceMgr::Transform(std::shared_ptr<IDevice> device)
258{
259    CALL_DEBUG_ENTER;
260    CHKPP(device);
261    auto inputDevice = std::make_shared<MMI::InputDevice>();
262    inputDevice->SetId(device->GetId());
263    inputDevice->SetName(device->GetName());
264    inputDevice->SetBus(device->GetBus());
265    inputDevice->SetVersion(device->GetVersion());
266    inputDevice->SetProduct(device->GetProduct());
267    inputDevice->SetVendor(device->GetVendor());
268    inputDevice->SetPhys(device->GetPhys());
269    inputDevice->SetUniq(device->GetUniq());
270    if (device->IsKeyboard()) {
271        inputDevice->AddCapability(MMI::InputDeviceCapability::INPUT_DEV_CAP_KEYBOARD);
272    }
273    if (device->IsPointerDevice()) {
274        inputDevice->AddCapability(MMI::InputDeviceCapability::INPUT_DEV_CAP_POINTER);
275    }
276    return inputDevice;
277}
278
279void InputDeviceMgr::AddVirtualInputDevice(const std::string &networkId, int32_t remoteDeviceId)
280{
281    CALL_INFO_TRACE;
282    if (remote2VirtualIds_.find(remoteDeviceId) != remote2VirtualIds_.end()) {
283        FI_HILOGW("Remote device:%{public}d already added as virtual device:%{public}d",
284            remoteDeviceId, remote2VirtualIds_[remoteDeviceId]);
285            return;
286    }
287    auto device = GetRemoteDeviceById(networkId, remoteDeviceId);
288    CHKPV(device);
289    int32_t virtualDeviceId = -1;
290    if (env_->GetInput().AddVirtualInputDevice(Transform(device), virtualDeviceId) != RET_OK) {
291        FI_HILOGE("Add virtual device failed, remoteDeviceId:%{public}d, name:%{public}s", remoteDeviceId,
292            device->GetName().c_str());
293        return;
294    }
295    virtualInputDevicesAdded_[networkId].insert(virtualDeviceId);
296    remote2VirtualIds_[remoteDeviceId] = virtualDeviceId;
297    FI_HILOGI("Add virtual device success, virtualDeviceId:%{public}d", virtualDeviceId);
298}
299
300void InputDeviceMgr::RemoveVirtualInputDevice(const std::string &networkId, int32_t remoteDeviceId)
301{
302    CALL_INFO_TRACE;
303    if (remote2VirtualIds_.find(remoteDeviceId) == remote2VirtualIds_.end()) {
304        FI_HILOGE("No remote device from networkId%{public}s with id:%{public}d",
305            Utility::Anonymize(networkId).c_str(), remoteDeviceId);
306        return;
307    }
308    auto virtualDeviceId = remote2VirtualIds_[remoteDeviceId];
309    if (env_->GetInput().RemoveVirtualInputDevice(virtualDeviceId) != RET_OK) {
310        FI_HILOGE("Remove virtual device failed, virtualDeviceId:%{public}d", virtualDeviceId);
311        return;
312    }
313    virtualInputDevicesAdded_[networkId].erase(virtualDeviceId);
314    remote2VirtualIds_.erase(remoteDeviceId);
315    FI_HILOGI("Remove virtual device success, virtualDeviceId:%{public}d", virtualDeviceId);
316}
317
318std::shared_ptr<IDevice> InputDeviceMgr::GetRemoteDeviceById(const std::string &networkId, int32_t remoteDeviceId)
319{
320    std::shared_ptr<IDevice> dev = std::make_shared<Device>(remoteDeviceId);
321    if (remoteDevices_.find(networkId) == remoteDevices_.end()) {
322        FI_HILOGE("No remoteDevice from networkId:%{public}s", Utility::Anonymize(networkId).c_str());
323        return nullptr;
324    }
325    if (auto iter = remoteDevices_[networkId].find(dev); iter != remoteDevices_[networkId].end()) {
326        return *iter;
327    }
328    FI_HILOGW("No remote device with deviceId:%{public}d", remoteDeviceId);
329    return nullptr;
330}
331
332} // namespace Cooperate
333} // namespace DeviceStatus
334} // namespace Msdp
335} // namespace OHOS
336