1/* 2 * Copyright (C) 2022 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 "accessibility_touchEvent_injector.h" 17#include "accessible_ability_manager_service.h" 18#include "hilog_wrapper.h" 19#include "utils.h" 20#include <cinttypes> 21 22namespace OHOS { 23namespace Accessibility { 24namespace { 25 constexpr int32_t MS_TO_US = 1000; 26 constexpr int32_t MOVE_GESTURE_MIN_PATH_COUNT = 2; 27} // namespace 28 29TouchInjectHandler::TouchInjectHandler(const std::shared_ptr<AppExecFwk::EventRunner> &runner, 30 TouchEventInjector &server) : AppExecFwk::EventHandler(runner), server_(server) 31{ 32} 33 34void TouchInjectHandler::ProcessEvent(const AppExecFwk::InnerEvent::Pointer &event) 35{ 36 std::shared_ptr<SendEventArgs> parameters = nullptr; 37 if (!event) { 38 HILOG_ERROR("event is nullptr"); 39 return; 40 } 41 switch (event->GetInnerEventId()) { 42 case TouchEventInjector::SEND_TOUCH_EVENT_MSG: 43 parameters = event->GetSharedObject<SendEventArgs>(); 44 if (parameters == nullptr) { 45 HILOG_ERROR("parameters is nullptr"); 46 return; 47 } 48 if (!parameters->event_) { 49 HILOG_WARN("pointer event is nullptr"); 50 return; 51 } 52 server_.SendPointerEvent(*parameters->event_); 53 break; 54 default: 55 break; 56 } 57} 58 59TouchEventInjector::TouchEventInjector() 60{ 61 runner_ = Singleton<AccessibleAbilityManagerService>::GetInstance().GetMainRunner(); 62 if (!runner_) { 63 HILOG_ERROR("get runner failed"); 64 return; 65 } 66 handler_ = std::make_shared<TouchInjectHandler>(runner_, *this); 67 if (!handler_) { 68 HILOG_ERROR("create event handler failed"); 69 return; 70 } 71} 72 73bool TouchEventInjector::OnPointerEvent(MMI::PointerEvent &event) 74{ 75 HILOG_DEBUG(); 76 77 EventTransmission::OnPointerEvent(event); 78 return false; 79} 80 81void TouchEventInjector::DestroyEvents() 82{ 83 HILOG_DEBUG(); 84 CancelInjectedEvents(); 85 isDestroyEvent_ = true; 86 EventTransmission::DestroyEvents(); 87} 88 89void TouchEventInjector::SendPointerEvent(MMI::PointerEvent &event) 90{ 91 HILOG_DEBUG(); 92 if (GetNext() != nullptr) { 93 EventTransmission::OnPointerEvent(event); 94 if (event.GetPointerAction() == MMI::PointerEvent::POINTER_ACTION_DOWN) { 95 isGestureUnderway_ = true; 96 } 97 if (event.GetPointerAction() == MMI::PointerEvent::POINTER_ACTION_UP) { 98 isGestureUnderway_ = false; 99 } 100 } 101} 102 103void TouchEventInjector::CancelGesture() 104{ 105 HILOG_DEBUG(); 106 std::shared_ptr<MMI::PointerEvent> event; 107 MMI::PointerEvent::PointerItem pointer = {}; 108 int64_t time = GetSystemTime(); 109 pointer.SetDownTime(time); 110 pointer.SetPointerId(0); 111 if (GetNext() != nullptr && isGestureUnderway_) { 112 event = obtainTouchEvent(MMI::PointerEvent::POINTER_ACTION_CANCEL, pointer, time); 113 if (event == nullptr) { 114 HILOG_ERROR("event is nullptr"); 115 return; 116 } 117 118 SendPointerEvent(*event); 119 isGestureUnderway_ = false; 120 } 121} 122 123void TouchEventInjector::CancelInjectedEvents() 124{ 125 HILOG_DEBUG(); 126 if (handler_ == nullptr) { 127 HILOG_ERROR("handler_ is nullptr"); 128 return; 129 } 130 if (handler_->HasInnerEvent(SEND_TOUCH_EVENT_MSG)) { 131 handler_->RemoveEvent(SEND_TOUCH_EVENT_MSG); 132 CancelGesture(); 133 } 134} 135 136std::shared_ptr<MMI::PointerEvent> TouchEventInjector::obtainTouchEvent(int32_t action, 137 MMI::PointerEvent::PointerItem point, int64_t actionTime) 138{ 139 HILOG_DEBUG(); 140 std::shared_ptr<MMI::PointerEvent> pointerEvent = MMI::PointerEvent::Create(); 141 if (pointerEvent == nullptr) { 142 HILOG_ERROR("pointerEvent is nullptr"); 143 return nullptr; 144 } 145 146 pointerEvent->SetPointerId(point.GetPointerId()); 147 pointerEvent->SetTargetDisplayId(0); 148 pointerEvent->SetPointerAction(action); 149 pointerEvent->SetActionTime(actionTime); 150 pointerEvent->SetActionStartTime(point.GetDownTime()); 151 pointerEvent->AddPointerItem(point); 152 pointerEvent->SetSourceType(MMI::PointerEvent::SOURCE_TYPE_TOUCHSCREEN); 153 return pointerEvent; 154} 155 156int64_t TouchEventInjector::GetSystemTime() 157{ 158 HILOG_DEBUG(); 159 160 int64_t microsecond = Utils::GetSystemTime() * 1000; 161 return microsecond; 162} 163 164void TouchEventInjector::InjectEvents(const std::shared_ptr<AccessibilityGestureInjectPath>& gesturePath) 165{ 166 HILOG_DEBUG(); 167 168 int64_t curTime = GetSystemTime(); 169 if (isDestroyEvent_ || !GetNext()) { 170 HILOG_WARN("Inject gesture fail"); 171 return; 172 } 173 CancelInjectedEvents(); 174 CancelGesture(); 175 176 ParseTouchEventsFromGesturePath(curTime, gesturePath); 177 178 if (injectedEvents_.empty()) { 179 HILOG_WARN("No injected events"); 180 return; 181 } 182 for (size_t i = 0; i < injectedEvents_.size(); i++) { 183 std::shared_ptr<SendEventArgs> parameters = std::make_shared<SendEventArgs>(); 184 parameters->event_ = injectedEvents_[i]; 185 if (injectedEvents_[i]) { 186 int64_t timeout = (injectedEvents_[i]->GetActionTime() - curTime) / MS_TO_US; 187 if (timeout < 0) { 188 HILOG_WARN("timeout is error.%{public}" PRId64 "", timeout); 189 } else { 190 handler_->SendEvent(SEND_TOUCH_EVENT_MSG, parameters, timeout); 191 } 192 } 193 } 194 injectedEvents_.clear(); 195} 196 197void TouchEventInjector::ParseTapsEvents(int64_t startTime, 198 const std::shared_ptr<AccessibilityGestureInjectPath>& gesturePath) 199{ 200 HILOG_DEBUG(); 201 202 if (!gesturePath) { 203 HILOG_ERROR("gesturePath is null."); 204 return; 205 } 206 const std::vector<AccessibilityGesturePosition> &positions = gesturePath->GetPositions(); 207 size_t positionSize = positions.size(); 208 if (!positionSize) { 209 HILOG_WARN("PositionSize is zero."); 210 return; 211 } 212 int64_t durationTime = gesturePath->GetDurationTime(); 213 if (durationTime < 0) { 214 HILOG_WARN("DurationTime is wrong."); 215 return; 216 } 217 int64_t perDurationTime = static_cast<int64_t>(static_cast<uint64_t>(durationTime) / positionSize); 218 int64_t downTime = startTime; 219 for (size_t i = 0; i < positionSize; i++) { 220 std::shared_ptr<MMI::PointerEvent> event; 221 MMI::PointerEvent::PointerItem pointer = {}; 222 pointer.SetPointerId(0); 223 // Append down event 224 int32_t px = static_cast<int32_t>(positions[i].positionX_); 225 int32_t py = static_cast<int32_t>(positions[i].positionY_); 226 pointer.SetDisplayX(px); 227 pointer.SetDisplayY(py); 228 pointer.SetDownTime(downTime); 229 event = obtainTouchEvent(MMI::PointerEvent::POINTER_ACTION_DOWN, pointer, downTime); 230 if (event == nullptr) { 231 HILOG_ERROR("event is nullptr"); 232 return; 233 } 234 235 HILOG_DEBUG("append down event"); 236 injectedEvents_.push_back(event); 237 238 // Append up event 239 int64_t upTime = downTime + perDurationTime * MS_TO_US; 240 event = obtainTouchEvent(MMI::PointerEvent::POINTER_ACTION_UP, pointer, upTime); 241 if (event == nullptr) { 242 HILOG_ERROR("event is nullptr"); 243 return; 244 } 245 246 HILOG_DEBUG("append up event"); 247 injectedEvents_.push_back(event); 248 downTime = upTime + DOUBLE_TAP_MIN_TIME; 249 } 250} 251 252void TouchEventInjector::ParseMovesEvents(int64_t startTime, 253 const std::shared_ptr<AccessibilityGestureInjectPath>& gesturePath) 254{ 255 HILOG_DEBUG(); 256 257 if (!gesturePath) { 258 HILOG_ERROR("gesturePath is null."); 259 return; 260 } 261 std::vector<AccessibilityGesturePosition> positions = gesturePath->GetPositions(); 262 size_t positionSize = positions.size(); 263 if (positionSize < MOVE_GESTURE_MIN_PATH_COUNT) { 264 HILOG_WARN("PositionSize is wrong."); 265 return; 266 } 267 int64_t durationTime = gesturePath->GetDurationTime(); 268 if (durationTime < 0) { 269 HILOG_WARN("DurationTime is wrong."); 270 return; 271 } 272 int64_t perDurationTime = static_cast<int64_t>(static_cast<uint64_t>(durationTime) / (positionSize - 1)); 273 int64_t downTime = startTime; 274 int64_t nowTime = startTime; 275 for (size_t i = 0; i < positionSize; i++) { 276 std::shared_ptr<MMI::PointerEvent> event; 277 MMI::PointerEvent::PointerItem pointer = {}; 278 int32_t px = static_cast<int32_t>(positions[i].positionX_); 279 int32_t py = static_cast<int32_t>(positions[i].positionY_); 280 pointer.SetPointerId(0); 281 pointer.SetDisplayX(px); 282 pointer.SetDisplayY(py); 283 pointer.SetDownTime(downTime); 284 if (i == 0) { // Append down event 285 HILOG_DEBUG("append down event"); 286 event = obtainTouchEvent(MMI::PointerEvent::POINTER_ACTION_DOWN, pointer, downTime); 287 if (event == nullptr) { 288 HILOG_ERROR("event is nullptr"); 289 return; 290 } 291 292 injectedEvents_.push_back(event); 293 } else if (i < (positionSize - 1)) { // Append move event 294 HILOG_DEBUG("append move event"); 295 nowTime += perDurationTime * MS_TO_US; 296 event = obtainTouchEvent(MMI::PointerEvent::POINTER_ACTION_MOVE, pointer, nowTime); 297 if (event == nullptr) { 298 HILOG_ERROR("event is nullptr"); 299 return; 300 } 301 302 injectedEvents_.push_back(event); 303 } else { // Append up event 304 HILOG_DEBUG("append move event"); 305 nowTime += perDurationTime * MS_TO_US; 306 event = obtainTouchEvent(MMI::PointerEvent::POINTER_ACTION_MOVE, pointer, nowTime); 307 if (event == nullptr) { 308 HILOG_ERROR("event is nullptr"); 309 return; 310 } 311 312 injectedEvents_.push_back(event); 313 314 HILOG_DEBUG("append up event"); 315 event = obtainTouchEvent(MMI::PointerEvent::POINTER_ACTION_UP, pointer, nowTime); 316 if (event == nullptr) { 317 HILOG_ERROR("event is nullptr"); 318 return; 319 } 320 321 injectedEvents_.push_back(event); 322 } 323 } 324} 325 326void TouchEventInjector::ParseTouchEventsFromGesturePath(int64_t startTime, 327 const std::shared_ptr<AccessibilityGestureInjectPath>& gesturePath) 328{ 329 HILOG_DEBUG(); 330 if (!gesturePath) { 331 HILOG_ERROR("gesturePath is null."); 332 return; 333 } 334 const std::vector<AccessibilityGesturePosition> &positions = gesturePath->GetPositions(); 335 if (positions.size() == 0) { 336 HILOG_ERROR("position size is 0."); 337 return; 338 } 339 if ((positions.size() == 1) || 340 ((positions[0].positionX_ == positions[1].positionX_) && 341 (positions[0].positionY_ == positions[1].positionY_))) { 342 ParseTapsEvents(startTime, gesturePath); 343 } else { 344 ParseMovesEvents(startTime, gesturePath); 345 } 346} 347} // namespace Accessibility 348} // namespace OHOS