• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 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 "virtual_touchscreen.h"
17 
18 #include <linux/input.h>
19 
20 #include "devicestatus_define.h"
21 #include "fi_log.h"
22 #include "virtual_touchscreen_builder.h"
23 
24 namespace OHOS {
25 namespace Msdp {
26 namespace DeviceStatus {
27 namespace {
28 constexpr HiviewDFX::HiLogLabel LABEL { LOG_CORE, MSDP_DOMAIN_ID, "VirtualTouchScreen" };
29 constexpr int32_t MINIMUM_INTERVAL { 18 };
30 constexpr int32_t N_SLOTS_AVAILABLE { 10 };
31 constexpr int32_t STEP_LENGTH { 10 };
32 constexpr int32_t TWICE_STEP_LENGTH { 2 * STEP_LENGTH };
33 } // namespaces
34 
35 VirtualTouchScreen *VirtualTouchScreen::device_ = nullptr;
36 
GetDevice()37 VirtualTouchScreen *VirtualTouchScreen::GetDevice()
38 {
39     if (device_ == nullptr) {
40         std::string node;
41         if (VirtualDevice::FindDeviceNode(VirtualTouchScreenBuilder::GetDeviceName(), node)) {
42             auto vTouch = new (std::nothrow) VirtualTouchScreen(node);
43             CHKPP(vTouch);
44             if (vTouch->IsActive()) {
45                 device_ = vTouch;
46             }
47         }
48     }
49     return device_;
50 }
51 
VirtualTouchScreen(const std::string & node)52 VirtualTouchScreen::VirtualTouchScreen(const std::string &node) : VirtualDevice(node), slots_(N_SLOTS_AVAILABLE)
53 {
54     VirtualDevice::SetMinimumInterval(MINIMUM_INTERVAL);
55     QueryScreenSize();
56 }
57 
QueryScreenSize()58 void VirtualTouchScreen::QueryScreenSize()
59 {
60     struct input_absinfo absInfo {};
61 
62     if (QueryAbsInfo(ABS_X, absInfo)) {
63         screenWidth_ = (absInfo.maximum - absInfo.minimum + 1);
64     }
65     if (QueryAbsInfo(ABS_MT_POSITION_X, absInfo) &&
66         ((screenWidth_ == std::numeric_limits<int32_t>::max()) ||
67          ((absInfo.maximum - absInfo.minimum + 1) > screenWidth_))) {
68         screenWidth_ = (absInfo.maximum - absInfo.minimum + 1);
69     }
70 
71     if (QueryAbsInfo(ABS_Y, absInfo)) {
72         screenHeight_ = (absInfo.maximum - absInfo.minimum + 1);
73     }
74     if (QueryAbsInfo(ABS_MT_POSITION_Y, absInfo) &&
75         ((screenHeight_ == std::numeric_limits<int32_t>::max()) ||
76          ((absInfo.maximum - absInfo.minimum + 1) > screenHeight_))) {
77         screenHeight_ = (absInfo.maximum - absInfo.minimum + 1);
78     }
79 }
80 
SendTouchEvent()81 void VirtualTouchScreen::SendTouchEvent()
82 {
83     CALL_DEBUG_ENTER;
84     for (int32_t s = 0; s < N_SLOTS_AVAILABLE; ++s) {
85         if (!slots_[s].active) {
86             continue;
87         }
88         SendEvent(EV_ABS, ABS_MT_POSITION_X, slots_[s].coord.x);
89         SendEvent(EV_ABS, ABS_MT_POSITION_Y, slots_[s].coord.y);
90         SendEvent(EV_ABS, ABS_MT_TRACKING_ID, s);
91         SendEvent(EV_SYN, SYN_MT_REPORT, SYNC_VALUE);
92         FI_HILOGD("Send event [%{public}d], (%{public}d, %{public}d)", s, slots_[s].coord.x, slots_[s].coord.y);
93     }
94 }
95 
DownButton(int32_t slot,int32_t x,int32_t y)96 int32_t VirtualTouchScreen::DownButton(int32_t slot, int32_t x, int32_t y)
97 {
98     CALL_DEBUG_ENTER;
99     if (slot < 0 || slot >= N_SLOTS_AVAILABLE) {
100         FI_HILOGD("Slot out of range, slot:%{public}d", slot);
101         slot = N_SLOTS_AVAILABLE - 1;
102     }
103     bool firstTouchDown = std::none_of(slots_.cbegin(), slots_.cend(), [](const auto &slot) { return slot.active; });
104 
105     slots_[slot].coord.x = std::min(std::max(x, 0), screenWidth_ - 1);
106     slots_[slot].coord.y = std::min(std::max(y, 0), screenHeight_ - 1);
107     slots_[slot].active = true;
108     FI_HILOGD("Press down [%{public}d], (%{public}d, %{public}d)", slot, slots_[slot].coord.x, slots_[slot].coord.y);
109     SendTouchEvent();
110     if (firstTouchDown) {
111         FI_HILOGD("First touch down, send button touch down event");
112         SendEvent(EV_KEY, BTN_TOUCH, DOWN_VALUE);
113     }
114     SendEvent(EV_SYN, SYN_MT_REPORT, SYNC_VALUE);
115     FI_HILOGD("Send sync event");
116     SendEvent(EV_SYN, SYN_REPORT, SYNC_VALUE);
117     return RET_OK;
118 }
119 
UpButton(int32_t slot)120 int32_t VirtualTouchScreen::UpButton(int32_t slot)
121 {
122     CALL_DEBUG_ENTER;
123     if (slot < 0 || slot >= N_SLOTS_AVAILABLE) {
124         FI_HILOGD("Slot out of range, slot:%{public}d", slot);
125         slot = N_SLOTS_AVAILABLE - 1;
126     }
127     if (!slots_[slot].active) {
128         FI_HILOGE("Slot [%{public}d] is not active", slot);
129         return RET_ERR;
130     }
131     slots_[slot].active = false;
132     FI_HILOGD("Release [%{public}d]", slot);
133     SendTouchEvent();
134     SendEvent(EV_SYN, SYN_MT_REPORT, SYNC_VALUE);
135     FI_HILOGD("Send sync event");
136     SendEvent(EV_SYN, SYN_REPORT, SYNC_VALUE);
137 
138     bool lastTouchUp = std::none_of(slots_.cbegin(), slots_.cend(), [](const auto &slot) { return slot.active; });
139     if (lastTouchUp) {
140         FI_HILOGD("Last touch up, send button touch up event.");
141         SendEvent(EV_KEY, BTN_TOUCH, UP_VALUE);
142         SendEvent(EV_SYN, SYN_MT_REPORT, SYNC_VALUE);
143         SendEvent(EV_SYN, SYN_REPORT, SYNC_VALUE);
144     }
145     return RET_OK;
146 }
147 
Move(int32_t slot,int32_t dx,int32_t dy)148 int32_t VirtualTouchScreen::Move(int32_t slot, int32_t dx, int32_t dy)
149 {
150     CALL_DEBUG_ENTER;
151     if (slot < 0 || slot >= N_SLOTS_AVAILABLE) {
152         slot = N_SLOTS_AVAILABLE - 1;
153     }
154     if (!slots_[slot].active) {
155         FI_HILOGE("Slot [%{public}d] is not active", slot);
156         return RET_ERR;
157     }
158     Coordinate tcoord {
159         .x = std::min(std::max(slots_[slot].coord.x + dx, 0), screenWidth_ - 1),
160         .y = std::min(std::max(slots_[slot].coord.y + dy, 0), screenHeight_ - 1)
161     };
162     FI_HILOGD("Move [%{public}d] from (%{public}d, %{public}d) to (%{public}d, %{public}d)",
163         slot, slots_[slot].coord.x, slots_[slot].coord.y, tcoord.x, tcoord.y);
164 
165     while (tcoord.x != slots_[slot].coord.x || tcoord.y != slots_[slot].coord.y) {
166         double total = ::hypot(tcoord.x - slots_[slot].coord.x, tcoord.y - slots_[slot].coord.y);
167         if (total <= STEP_LENGTH) {
168             slots_[slot].coord.x = tcoord.x;
169             slots_[slot].coord.y = tcoord.y;
170         } else {
171             double step { STEP_LENGTH };
172             if (total < TWICE_STEP_LENGTH) {
173                 step = total / HALF_VALUE;
174             }
175             slots_[slot].coord.x += static_cast<int32_t>(round(step * (tcoord.x - slots_[slot].coord.x) / total));
176             slots_[slot].coord.y += static_cast<int32_t>(round(step * (tcoord.y - slots_[slot].coord.y) / total));
177         }
178         SendTouchEvent();
179         SendEvent(EV_SYN, SYN_MT_REPORT, SYNC_VALUE);
180         SendEvent(EV_SYN, SYN_REPORT, SYNC_VALUE);
181     }
182     return RET_OK;
183 }
184 
MoveTo(int32_t slot,int32_t x,int32_t y)185 int32_t VirtualTouchScreen::MoveTo(int32_t slot, int32_t x, int32_t y)
186 {
187     CALL_DEBUG_ENTER;
188     if (slot < 0 || slot >= N_SLOTS_AVAILABLE) {
189         slot = N_SLOTS_AVAILABLE - 1;
190     }
191     if (!slots_[slot].active) {
192         FI_HILOGE("Slot [%{public}d] is not active", slot);
193         return RET_ERR;
194     }
195     return Move(slot, x - slots_[slot].coord.x, y - slots_[slot].coord.y);
196 }
197 } // namespace DeviceStatus
198 } // namespace Msdp
199 } // namespace OHOS