1/*
2 * Copyright (c) 2020-2021 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 "dfx/event_injector.h"
17#if ENABLE_DEBUG
18#include "common/input_device_manager.h"
19#include "dfx/key_event_injector.h"
20#include "dfx/point_event_injector.h"
21#include "gfx_utils/graphic_log.h"
22
23namespace OHOS {
24EventInjector::~EventInjector()
25{
26    InputDeviceManager* inputDeviceManager = InputDeviceManager::GetInstance();
27    if (pointEventInjector_ != nullptr) {
28        inputDeviceManager->Remove(pointEventInjector_);
29        delete pointEventInjector_;
30        pointEventInjector_ = nullptr;
31    }
32    if (keyEventInjector_ != nullptr) {
33        inputDeviceManager->Remove(keyEventInjector_);
34        delete keyEventInjector_;
35        keyEventInjector_ = nullptr;
36    }
37}
38
39EventInjector* EventInjector::GetInstance()
40{
41    static EventInjector instance;
42    return &instance;
43}
44
45bool EventInjector::RegisterEventInjector(EventDataType type)
46{
47    switch (type) {
48        case EventDataType::POINT_TYPE:
49            if (pointEventInjector_ == nullptr) {
50                pointEventInjector_ = new PointEventInjector();
51                if (pointEventInjector_ == nullptr) {
52                    GRAPHIC_LOGE("EventInjector::RegisterEventInjector register pointEventInjector failed Err!\n");
53                    return false;
54                }
55                InputDeviceManager::GetInstance()->Add(pointEventInjector_);
56            }
57            return true;
58        case EventDataType::KEY_TYPE:
59            if (keyEventInjector_ == nullptr) {
60                keyEventInjector_ = new KeyEventInjector();
61                if (keyEventInjector_ == nullptr) {
62                    GRAPHIC_LOGE("EventInjector::RegisterEventInjector register keyEventInjector failed Err!\n");
63                    return false;
64                }
65                InputDeviceManager::GetInstance()->Add(keyEventInjector_);
66            }
67            return true;
68        default:
69            break;
70    }
71    return false;
72}
73
74void EventInjector::UnregisterEventInjector(EventDataType type)
75{
76    switch (type) {
77        case EventDataType::POINT_TYPE:
78            if (pointEventInjector_ != nullptr) {
79                InputDeviceManager::GetInstance()->Remove(pointEventInjector_);
80                delete pointEventInjector_;
81                pointEventInjector_ = nullptr;
82            }
83            break;
84        case EventDataType::KEY_TYPE:
85            if (keyEventInjector_ != nullptr) {
86                InputDeviceManager::GetInstance()->Remove(keyEventInjector_);
87                delete keyEventInjector_;
88                keyEventInjector_ = nullptr;
89            }
90            break;
91        default:
92            break;
93    }
94}
95
96bool EventInjector::IsEventInjectorRegistered(EventDataType type) const
97{
98    switch (type) {
99        case EventDataType::POINT_TYPE:
100            if (pointEventInjector_ != nullptr) {
101                return true;
102            }
103            break;
104        case EventDataType::KEY_TYPE:
105            if (keyEventInjector_ != nullptr) {
106                return true;
107            }
108            break;
109        default:
110            break;
111    }
112    return false;
113}
114
115bool EventInjector::SetInjectEvent(const DeviceData* dataArray, uint16_t arrayLength, EventDataType type)
116{
117    if (dataArray == nullptr) {
118        return false;
119    }
120    switch (type) {
121        case EventDataType::POINT_TYPE:
122            if (pointEventInjector_ == nullptr) {
123                return false;
124            }
125            for (uint16_t i = 0; i < arrayLength; i++) {
126                if (!pointEventInjector_->SetPointEvent(dataArray[i])) {
127                    return false;
128                }
129            }
130            break;
131        case EventDataType::KEY_TYPE:
132            if (keyEventInjector_ == nullptr) {
133                return false;
134            }
135            for (uint16_t i = 0; i < arrayLength; i++) {
136                if (!keyEventInjector_->SetKey(dataArray[i])) {
137                    return false;
138                }
139            }
140            break;
141        default:
142            return false;
143    }
144    return true;
145}
146
147bool EventInjector::SetClickEvent(const Point& clickPoint)
148{
149    uint16_t clickArrayLen = 2; /* 2:click event point */
150    if (clickArrayLen > pointEventInjector_->GetLeftSize()) {
151        GRAPHIC_LOGE("front points need to be read.(left size in pointer queue is not enough)");
152        return false;
153    }
154    bool setResult = true;
155    DeviceData* dataArray = new DeviceData[clickArrayLen];
156    if (dataArray == nullptr) {
157        return false;
158    }
159    dataArray[0].point = clickPoint;
160    dataArray[0].state = InputDevice::STATE_PRESS;
161    dataArray[1].point = clickPoint;
162    dataArray[1].state = InputDevice::STATE_RELEASE;
163    if (!SetInjectEvent(dataArray, clickArrayLen, EventDataType::POINT_TYPE)) {
164        setResult = false;
165    }
166    delete[] dataArray;
167    return setResult;
168}
169
170bool EventInjector::SetLongPressEvent(const Point& longPressPoint)
171{
172    uint16_t pointCount = INDEV_LONG_PRESS_TIME / INDEV_READ_PERIOD + 1;
173    if (pointCount > pointEventInjector_->GetLeftSize()) {
174        GRAPHIC_LOGE("front points need to be read.(left size in pointer queue is not enough)");
175        return false;
176    }
177    bool setResult = true;
178    DeviceData* dataArray = new DeviceData[pointCount];
179    if (dataArray == nullptr) {
180        return false;
181    }
182    for (uint16_t i = 0; i < pointCount; i++) {
183        dataArray[i].point = longPressPoint;
184        dataArray[i].state = InputDevice::STATE_PRESS;
185    }
186    dataArray[pointCount - 1].state = InputDevice::STATE_RELEASE;
187    if (!SetInjectEvent(dataArray, pointCount, EventDataType::POINT_TYPE)) {
188        setResult = false;
189    }
190    delete[] dataArray;
191    return setResult;
192}
193
194bool EventInjector::SetDragEvent(const Point& startPoint, const Point& endPoint, uint32_t dragTime)
195{
196    uint16_t pointCount = (dragTime / INDEV_READ_PERIOD) + 1;
197    /* 3: at least 3 points in drag event */
198    if (pointCount < 3) {
199        GRAPHIC_LOGE("dragTime is too short.(drag event needs at least 3 points)");
200        return false;
201    }
202    if (pointCount > pointEventInjector_->GetLeftSize()) {
203        GRAPHIC_LOGE("dragTime is too long or front points need to be read.(left size in pointer queue is not enough)");
204        return false;
205    }
206    bool setResult = true;
207    int16_t negativeFlag = 1; /* 1:represent the coordinate (x, y) of endPoint is larger than startPoint. */
208    DeviceData* dataArray = new DeviceData[pointCount];
209    if (dataArray == nullptr) {
210        return false;
211    }
212    if (startPoint.x == endPoint.x) {
213        float pointStep = static_cast<float>(MATH_ABS(endPoint.y - startPoint.y)) / (pointCount - 1);
214        if (endPoint.y < startPoint.y) {
215            negativeFlag = -1; /* -1:represent the coordinate y of endPoint is smaller than startPoint. */
216        }
217        for (uint16_t i = 0; i < pointCount; i++) {
218            dataArray[i].point.x = startPoint.x;
219            dataArray[i].point.y = startPoint.y + static_cast<int16_t>(i * negativeFlag * pointStep);
220            dataArray[i].state = InputDevice::STATE_PRESS;
221        }
222    } else {
223        float slope = static_cast<float>(endPoint.y - startPoint.y) / (endPoint.x - startPoint.x);
224        int16_t constPara = startPoint.y - static_cast<int16_t>(slope * startPoint.x);
225        float pointStep = static_cast<float>(MATH_ABS(endPoint.x - startPoint.x)) / (pointCount - 1);
226        if (endPoint.x < startPoint.x) {
227            negativeFlag = -1; /* -1:represent the coordinate x of endPoint is smaller than startPoint. */
228        }
229        for (uint16_t i = 0; i < pointCount; i++) {
230            dataArray[i].point.x = startPoint.x + static_cast<int16_t>(i * negativeFlag * pointStep);
231            dataArray[i].point.y = static_cast<int16_t>(slope * (dataArray[i].point.x)) + constPara;
232            dataArray[i].state = InputDevice::STATE_PRESS;
233        }
234    }
235    dataArray[pointCount - 1].point = endPoint;
236    dataArray[pointCount - 1].state = InputDevice::STATE_RELEASE;
237    if (!SetInjectEvent(dataArray, pointCount, EventDataType::POINT_TYPE)) {
238        setResult = false;
239    }
240    delete[] dataArray;
241    return setResult;
242}
243
244bool EventInjector::SetKeyEvent(uint16_t keyId, uint16_t state)
245{
246    uint16_t kevArrayLen = 1;
247    if (kevArrayLen > keyEventInjector_->GetLeftSize()) {
248        GRAPHIC_LOGE("front key event need to be read.(left size in key event queue is not enough)");
249        return false;
250    }
251    bool setResult = true;
252    DeviceData* dataArray = new DeviceData[kevArrayLen];
253    if (dataArray == nullptr) {
254        return false;
255    }
256    for (uint16_t i = 0; i < kevArrayLen; i++) {
257        dataArray[i].keyId = keyId;
258        dataArray[i].state = state;
259    }
260    if (!SetInjectEvent(dataArray, kevArrayLen, EventDataType::KEY_TYPE)) {
261        setResult = false;
262    }
263    delete[] dataArray;
264    return setResult;
265}
266
267#if ENABLE_WINDOW
268void EventInjector::SetWindowId(uint8_t windowId)
269{
270    if (pointEventInjector_ != nullptr) {
271        pointEventInjector_->SetWindowId(windowId);
272    }
273}
274#endif
275} // namespace OHOS
276#endif // ENABLE_DEBUG