1f857971dSopenharmony_ci/* 2f857971dSopenharmony_ci * Copyright (c) 2023 Huawei Device Co., Ltd. 3f857971dSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 4f857971dSopenharmony_ci * you may not use this file except in compliance with the License. 5f857971dSopenharmony_ci * You may obtain a copy of the License at 6f857971dSopenharmony_ci * 7f857971dSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 8f857971dSopenharmony_ci * 9f857971dSopenharmony_ci * Unless required by applicable law or agreed to in writing, software 10f857971dSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 11f857971dSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12f857971dSopenharmony_ci * See the License for the specific language governing permissions and 13f857971dSopenharmony_ci * limitations under the License. 14f857971dSopenharmony_ci */ 15f857971dSopenharmony_ci 16f857971dSopenharmony_ci#include "virtual_touchscreen.h" 17f857971dSopenharmony_ci 18f857971dSopenharmony_ci#include <linux/input.h> 19f857971dSopenharmony_ci 20f857971dSopenharmony_ci#include "devicestatus_define.h" 21f857971dSopenharmony_ci#include "fi_log.h" 22f857971dSopenharmony_ci#include "virtual_touchscreen_builder.h" 23f857971dSopenharmony_ci 24f857971dSopenharmony_ci#undef LOG_TAG 25f857971dSopenharmony_ci#define LOG_TAG "VirtualTouchScreen" 26f857971dSopenharmony_ci 27f857971dSopenharmony_cinamespace OHOS { 28f857971dSopenharmony_cinamespace Msdp { 29f857971dSopenharmony_cinamespace DeviceStatus { 30f857971dSopenharmony_cinamespace { 31f857971dSopenharmony_ciconstexpr int32_t MINIMUM_INTERVAL { 18 }; 32f857971dSopenharmony_ciconstexpr int32_t N_SLOTS_AVAILABLE { 10 }; 33f857971dSopenharmony_ciconstexpr int32_t STEP_LENGTH { 10 }; 34f857971dSopenharmony_ciconstexpr int32_t TWICE_STEP_LENGTH { 2 * STEP_LENGTH }; 35f857971dSopenharmony_ci} // namespaces 36f857971dSopenharmony_ci 37f857971dSopenharmony_cistd::shared_ptr<VirtualTouchScreen> VirtualTouchScreen::device_ = nullptr; 38f857971dSopenharmony_ci 39f857971dSopenharmony_cistd::shared_ptr<VirtualTouchScreen> VirtualTouchScreen::GetDevice() 40f857971dSopenharmony_ci{ 41f857971dSopenharmony_ci if (device_ == nullptr) { 42f857971dSopenharmony_ci std::string node; 43f857971dSopenharmony_ci if (VirtualDevice::FindDeviceNode(VirtualTouchScreenBuilder::GetDeviceName(), node)) { 44f857971dSopenharmony_ci auto vTouch = std::make_shared<VirtualTouchScreen>(node); 45f857971dSopenharmony_ci CHKPP(vTouch); 46f857971dSopenharmony_ci if (vTouch->IsActive()) { 47f857971dSopenharmony_ci device_ = vTouch; 48f857971dSopenharmony_ci } 49f857971dSopenharmony_ci } 50f857971dSopenharmony_ci } 51f857971dSopenharmony_ci return device_; 52f857971dSopenharmony_ci} 53f857971dSopenharmony_ci 54f857971dSopenharmony_ciVirtualTouchScreen::VirtualTouchScreen(const std::string &node) : VirtualDevice(node), slots_(N_SLOTS_AVAILABLE) 55f857971dSopenharmony_ci{ 56f857971dSopenharmony_ci VirtualDevice::SetMinimumInterval(MINIMUM_INTERVAL); 57f857971dSopenharmony_ci QueryScreenSize(); 58f857971dSopenharmony_ci} 59f857971dSopenharmony_ci 60f857971dSopenharmony_civoid VirtualTouchScreen::QueryScreenSize() 61f857971dSopenharmony_ci{ 62f857971dSopenharmony_ci struct input_absinfo absInfo {}; 63f857971dSopenharmony_ci 64f857971dSopenharmony_ci if (QueryAbsInfo(ABS_X, absInfo)) { 65f857971dSopenharmony_ci screenWidth_ = (absInfo.maximum - absInfo.minimum + 1); 66f857971dSopenharmony_ci } 67f857971dSopenharmony_ci if (QueryAbsInfo(ABS_MT_POSITION_X, absInfo) && 68f857971dSopenharmony_ci ((screenWidth_ == std::numeric_limits<int32_t>::max()) || 69f857971dSopenharmony_ci ((absInfo.maximum - absInfo.minimum + 1) > screenWidth_))) { 70f857971dSopenharmony_ci screenWidth_ = (absInfo.maximum - absInfo.minimum + 1); 71f857971dSopenharmony_ci } 72f857971dSopenharmony_ci 73f857971dSopenharmony_ci if (QueryAbsInfo(ABS_Y, absInfo)) { 74f857971dSopenharmony_ci screenHeight_ = (absInfo.maximum - absInfo.minimum + 1); 75f857971dSopenharmony_ci } 76f857971dSopenharmony_ci if (QueryAbsInfo(ABS_MT_POSITION_Y, absInfo) && 77f857971dSopenharmony_ci ((screenHeight_ == std::numeric_limits<int32_t>::max()) || 78f857971dSopenharmony_ci ((absInfo.maximum - absInfo.minimum + 1) > screenHeight_))) { 79f857971dSopenharmony_ci screenHeight_ = (absInfo.maximum - absInfo.minimum + 1); 80f857971dSopenharmony_ci } 81f857971dSopenharmony_ci} 82f857971dSopenharmony_ci 83f857971dSopenharmony_civoid VirtualTouchScreen::SendTouchEvent() 84f857971dSopenharmony_ci{ 85f857971dSopenharmony_ci CALL_DEBUG_ENTER; 86f857971dSopenharmony_ci for (int32_t s = 0; s < N_SLOTS_AVAILABLE; ++s) { 87f857971dSopenharmony_ci if (!slots_[s].active) { 88f857971dSopenharmony_ci continue; 89f857971dSopenharmony_ci } 90f857971dSopenharmony_ci SendEvent(EV_ABS, ABS_MT_POSITION_X, slots_[s].coord.x); 91f857971dSopenharmony_ci SendEvent(EV_ABS, ABS_MT_POSITION_Y, slots_[s].coord.y); 92f857971dSopenharmony_ci SendEvent(EV_ABS, ABS_MT_TRACKING_ID, s); 93f857971dSopenharmony_ci SendEvent(EV_SYN, SYN_MT_REPORT, SYNC_VALUE); 94f857971dSopenharmony_ci FI_HILOGD("Send event [%{public}d], (%{public}d, %{public}d)", s, slots_[s].coord.x, slots_[s].coord.y); 95f857971dSopenharmony_ci } 96f857971dSopenharmony_ci} 97f857971dSopenharmony_ci 98f857971dSopenharmony_ciint32_t VirtualTouchScreen::DownButton(int32_t slot, int32_t x, int32_t y) 99f857971dSopenharmony_ci{ 100f857971dSopenharmony_ci CALL_DEBUG_ENTER; 101f857971dSopenharmony_ci if (slot < 0 || slot >= N_SLOTS_AVAILABLE) { 102f857971dSopenharmony_ci FI_HILOGD("Slot out of range, slot:%{public}d", slot); 103f857971dSopenharmony_ci slot = N_SLOTS_AVAILABLE - 1; 104f857971dSopenharmony_ci } 105f857971dSopenharmony_ci bool firstTouchDown = std::none_of(slots_.cbegin(), slots_.cend(), [](const auto &slot) { return slot.active; }); 106f857971dSopenharmony_ci if (slots_.size() <= static_cast<size_t>(slot)) { 107f857971dSopenharmony_ci FI_HILOGE("The index is out of bounds"); 108f857971dSopenharmony_ci return RET_ERR; 109f857971dSopenharmony_ci } 110f857971dSopenharmony_ci slots_[slot].coord.x = std::min(std::max(x, 0), screenWidth_ - 1); 111f857971dSopenharmony_ci slots_[slot].coord.y = std::min(std::max(y, 0), screenHeight_ - 1); 112f857971dSopenharmony_ci slots_[slot].active = true; 113f857971dSopenharmony_ci FI_HILOGD("Press down [%{public}d], (%{public}d, %{public}d)", slot, slots_[slot].coord.x, slots_[slot].coord.y); 114f857971dSopenharmony_ci SendTouchEvent(); 115f857971dSopenharmony_ci if (firstTouchDown) { 116f857971dSopenharmony_ci FI_HILOGD("First touch down, send button touch down event"); 117f857971dSopenharmony_ci SendEvent(EV_KEY, BTN_TOUCH, DOWN_VALUE); 118f857971dSopenharmony_ci } 119f857971dSopenharmony_ci SendEvent(EV_SYN, SYN_MT_REPORT, SYNC_VALUE); 120f857971dSopenharmony_ci FI_HILOGD("Send sync event"); 121f857971dSopenharmony_ci SendEvent(EV_SYN, SYN_REPORT, SYNC_VALUE); 122f857971dSopenharmony_ci return RET_OK; 123f857971dSopenharmony_ci} 124f857971dSopenharmony_ci 125f857971dSopenharmony_ciint32_t VirtualTouchScreen::UpButton(int32_t slot) 126f857971dSopenharmony_ci{ 127f857971dSopenharmony_ci CALL_DEBUG_ENTER; 128f857971dSopenharmony_ci if (slot < 0 || slot >= N_SLOTS_AVAILABLE) { 129f857971dSopenharmony_ci FI_HILOGD("Slot out of range, slot:%{public}d", slot); 130f857971dSopenharmony_ci slot = N_SLOTS_AVAILABLE - 1; 131f857971dSopenharmony_ci } 132f857971dSopenharmony_ci if (slots_.size() <= static_cast<size_t>(slot)) { 133f857971dSopenharmony_ci FI_HILOGE("The index is out of bounds"); 134f857971dSopenharmony_ci return RET_ERR; 135f857971dSopenharmony_ci } 136f857971dSopenharmony_ci if (!slots_[slot].active) { 137f857971dSopenharmony_ci FI_HILOGE("Slot [%{public}d] is not active", slot); 138f857971dSopenharmony_ci return RET_ERR; 139f857971dSopenharmony_ci } 140f857971dSopenharmony_ci slots_[slot].active = false; 141f857971dSopenharmony_ci FI_HILOGD("Release [%{public}d]", slot); 142f857971dSopenharmony_ci SendTouchEvent(); 143f857971dSopenharmony_ci SendEvent(EV_SYN, SYN_MT_REPORT, SYNC_VALUE); 144f857971dSopenharmony_ci FI_HILOGD("Send sync event"); 145f857971dSopenharmony_ci SendEvent(EV_SYN, SYN_REPORT, SYNC_VALUE); 146f857971dSopenharmony_ci 147f857971dSopenharmony_ci bool lastTouchUp = std::none_of(slots_.cbegin(), slots_.cend(), [](const auto &slot) { return slot.active; }); 148f857971dSopenharmony_ci if (lastTouchUp) { 149f857971dSopenharmony_ci FI_HILOGD("Last touch up, send button touch up event"); 150f857971dSopenharmony_ci SendEvent(EV_KEY, BTN_TOUCH, UP_VALUE); 151f857971dSopenharmony_ci SendEvent(EV_SYN, SYN_MT_REPORT, SYNC_VALUE); 152f857971dSopenharmony_ci SendEvent(EV_SYN, SYN_REPORT, SYNC_VALUE); 153f857971dSopenharmony_ci } 154f857971dSopenharmony_ci return RET_OK; 155f857971dSopenharmony_ci} 156f857971dSopenharmony_ci 157f857971dSopenharmony_ciint32_t VirtualTouchScreen::Move(int32_t slot, int32_t dx, int32_t dy) 158f857971dSopenharmony_ci{ 159f857971dSopenharmony_ci CALL_DEBUG_ENTER; 160f857971dSopenharmony_ci if (slot < 0 || slot >= N_SLOTS_AVAILABLE) { 161f857971dSopenharmony_ci slot = N_SLOTS_AVAILABLE - 1; 162f857971dSopenharmony_ci } 163f857971dSopenharmony_ci if (slots_.size() <= static_cast<size_t>(slot)) { 164f857971dSopenharmony_ci FI_HILOGE("The index is out of bounds"); 165f857971dSopenharmony_ci return RET_ERR; 166f857971dSopenharmony_ci } 167f857971dSopenharmony_ci if (!slots_[slot].active) { 168f857971dSopenharmony_ci FI_HILOGE("slot [%{public}d] is not active", slot); 169f857971dSopenharmony_ci return RET_ERR; 170f857971dSopenharmony_ci } 171f857971dSopenharmony_ci Coordinate tcoord { 172f857971dSopenharmony_ci .x = std::min(std::max(slots_[slot].coord.x + dx, 0), screenWidth_ - 1), 173f857971dSopenharmony_ci .y = std::min(std::max(slots_[slot].coord.y + dy, 0), screenHeight_ - 1) 174f857971dSopenharmony_ci }; 175f857971dSopenharmony_ci FI_HILOGD("Move [%{public}d] from (%{public}d, %{public}d) to (%{public}d, %{public}d)", 176f857971dSopenharmony_ci slot, slots_[slot].coord.x, slots_[slot].coord.y, tcoord.x, tcoord.y); 177f857971dSopenharmony_ci 178f857971dSopenharmony_ci while ((tcoord.x != slots_[slot].coord.x) || (tcoord.y != slots_[slot].coord.y)) { 179f857971dSopenharmony_ci double total = ::hypot(tcoord.x - slots_[slot].coord.x, tcoord.y - slots_[slot].coord.y); 180f857971dSopenharmony_ci if (total <= STEP_LENGTH) { 181f857971dSopenharmony_ci slots_[slot].coord.x = tcoord.x; 182f857971dSopenharmony_ci slots_[slot].coord.y = tcoord.y; 183f857971dSopenharmony_ci } else { 184f857971dSopenharmony_ci double step { STEP_LENGTH }; 185f857971dSopenharmony_ci if (total < TWICE_STEP_LENGTH) { 186f857971dSopenharmony_ci step = total / HALF_VALUE; 187f857971dSopenharmony_ci } 188f857971dSopenharmony_ci slots_[slot].coord.x += static_cast<int32_t>(round(step * (tcoord.x - slots_[slot].coord.x) / total)); 189f857971dSopenharmony_ci slots_[slot].coord.y += static_cast<int32_t>(round(step * (tcoord.y - slots_[slot].coord.y) / total)); 190f857971dSopenharmony_ci } 191f857971dSopenharmony_ci SendTouchEvent(); 192f857971dSopenharmony_ci SendEvent(EV_SYN, SYN_MT_REPORT, SYNC_VALUE); 193f857971dSopenharmony_ci SendEvent(EV_SYN, SYN_REPORT, SYNC_VALUE); 194f857971dSopenharmony_ci } 195f857971dSopenharmony_ci return RET_OK; 196f857971dSopenharmony_ci} 197f857971dSopenharmony_ci 198f857971dSopenharmony_ciint32_t VirtualTouchScreen::MoveTo(int32_t slot, int32_t x, int32_t y) 199f857971dSopenharmony_ci{ 200f857971dSopenharmony_ci CALL_DEBUG_ENTER; 201f857971dSopenharmony_ci if (slot < 0 || slot >= N_SLOTS_AVAILABLE) { 202f857971dSopenharmony_ci slot = N_SLOTS_AVAILABLE - 1; 203f857971dSopenharmony_ci } 204f857971dSopenharmony_ci if (slots_.size() <= static_cast<size_t>(slot)) { 205f857971dSopenharmony_ci FI_HILOGE("The index is out of bounds"); 206f857971dSopenharmony_ci return RET_ERR; 207f857971dSopenharmony_ci } 208f857971dSopenharmony_ci if (!slots_[slot].active) { 209f857971dSopenharmony_ci FI_HILOGE("slot [%{public}d] is not active", slot); 210f857971dSopenharmony_ci return RET_ERR; 211f857971dSopenharmony_ci } 212f857971dSopenharmony_ci return Move(slot, x - slots_[slot].coord.x, y - slots_[slot].coord.y); 213f857971dSopenharmony_ci} 214f857971dSopenharmony_ci} // namespace DeviceStatus 215f857971dSopenharmony_ci} // namespace Msdp 216f857971dSopenharmony_ci} // namespace OHOS