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_mouse_key.h"
17#include "hilog_wrapper.h"
18#include "utils.h"
19
20namespace OHOS {
21namespace Accessibility {
22struct MouseMoveOffset {
23    int32_t offsetX = 0;
24    int32_t offsetY = 0;
25};
26namespace {
27    // item count
28    constexpr size_t ITEM_COUNT_1 = 1;
29    constexpr size_t ITEM_COUNT_2 = 2;
30    constexpr size_t ITEM_COUNT_3 = 3;
31    // move offset
32    constexpr int32_t MOVE_LEFT_STEP = -5;
33    constexpr int32_t MOVE_RIGHT_STEP = 5;
34    constexpr int32_t MOVE_UP_STEP = -5;
35    constexpr int32_t MOVE_DOWN_STEP = 5;
36    // speed multiple
37    constexpr float SPEED_UP_MULTIPLE = 5.0f;
38    constexpr float SLOW_DOWN_MULTIPLE = 0.5f;
39    // result of parsing meta key
40    constexpr int32_t INVALID_KEY = -1;
41    constexpr int32_t NONE_KEY = 0;
42    constexpr int32_t CTRL_KEY = 1;
43    constexpr int32_t SHIFT_KEY = 2;
44    constexpr int32_t CTRL_SHIFT_KEY = 3;
45    // array(PRESSED_METAKEYS_TBL)'s length
46    constexpr int32_t ROW_COUNT = 21;
47    constexpr int32_t COLUMN_COUNT = 3;
48    const std::vector<int32_t> MOUSE_KEYCODE_V = {
49        MMI::KeyEvent::KEYCODE_NUMPAD_1, MMI::KeyEvent::KEYCODE_NUMPAD_2, MMI::KeyEvent::KEYCODE_NUMPAD_3,
50        MMI::KeyEvent::KEYCODE_NUMPAD_4, MMI::KeyEvent::KEYCODE_NUMPAD_5, MMI::KeyEvent::KEYCODE_NUMPAD_6,
51        MMI::KeyEvent::KEYCODE_NUMPAD_7, MMI::KeyEvent::KEYCODE_NUMPAD_8, MMI::KeyEvent::KEYCODE_NUMPAD_9,
52        MMI::KeyEvent::KEYCODE_NUMPAD_DIVIDE, MMI::KeyEvent::KEYCODE_NUMPAD_MULTIPLY,
53        MMI::KeyEvent::KEYCODE_NUMPAD_SUBTRACT, MMI::KeyEvent::KEYCODE_NUMPAD_ADD};
54    const std::vector<int32_t> MOUSE_MOVE_KEYCODE_V = {
55        MMI::KeyEvent::KEYCODE_NUMPAD_1, MMI::KeyEvent::KEYCODE_NUMPAD_2, MMI::KeyEvent::KEYCODE_NUMPAD_3,
56        MMI::KeyEvent::KEYCODE_NUMPAD_4, MMI::KeyEvent::KEYCODE_NUMPAD_6, MMI::KeyEvent::KEYCODE_NUMPAD_7,
57        MMI::KeyEvent::KEYCODE_NUMPAD_8, MMI::KeyEvent::KEYCODE_NUMPAD_9};
58    const std::vector<int32_t> CTRL_SHIFT_KEYCODE_V = {
59        MMI::KeyEvent::KEYCODE_CTRL_LEFT, MMI::KeyEvent::KEYCODE_CTRL_RIGHT,
60        MMI::KeyEvent::KEYCODE_SHIFT_LEFT, MMI::KeyEvent::KEYCODE_SHIFT_RIGHT};
61    const std::map<int32_t, MouseMoveOffset> MOUSE_MOVE_OFFSET_M = {
62        {MMI::KeyEvent::KEYCODE_NUMPAD_1, {MOVE_LEFT_STEP, MOVE_DOWN_STEP}},
63        {MMI::KeyEvent::KEYCODE_NUMPAD_2, {0, MOVE_DOWN_STEP}},
64        {MMI::KeyEvent::KEYCODE_NUMPAD_3, {MOVE_RIGHT_STEP, MOVE_DOWN_STEP}},
65        {MMI::KeyEvent::KEYCODE_NUMPAD_4, {MOVE_LEFT_STEP, 0}},
66        {MMI::KeyEvent::KEYCODE_NUMPAD_6, {MOVE_RIGHT_STEP, 0}},
67        {MMI::KeyEvent::KEYCODE_NUMPAD_7, {MOVE_LEFT_STEP, MOVE_UP_STEP}},
68        {MMI::KeyEvent::KEYCODE_NUMPAD_8, {0, MOVE_UP_STEP}},
69        {MMI::KeyEvent::KEYCODE_NUMPAD_9, {MOVE_RIGHT_STEP, MOVE_UP_STEP}}};
70    const int32_t PRESSED_METAKEYS_TBL[ROW_COUNT][COLUMN_COUNT] = {
71        {MMI::KeyEvent::KEYCODE_UNKNOWN, MMI::KeyEvent::KEYCODE_UNKNOWN, NONE_KEY},
72        {MMI::KeyEvent::KEYCODE_UNKNOWN, MMI::KeyEvent::KEYCODE_CTRL_LEFT, CTRL_KEY},
73        {MMI::KeyEvent::KEYCODE_UNKNOWN, MMI::KeyEvent::KEYCODE_CTRL_RIGHT, CTRL_KEY},
74        {MMI::KeyEvent::KEYCODE_UNKNOWN, MMI::KeyEvent::KEYCODE_SHIFT_LEFT, SHIFT_KEY},
75        {MMI::KeyEvent::KEYCODE_UNKNOWN, MMI::KeyEvent::KEYCODE_SHIFT_RIGHT, SHIFT_KEY},
76
77        {MMI::KeyEvent::KEYCODE_CTRL_LEFT, MMI::KeyEvent::KEYCODE_UNKNOWN, CTRL_KEY},
78        {MMI::KeyEvent::KEYCODE_CTRL_LEFT, MMI::KeyEvent::KEYCODE_CTRL_RIGHT, CTRL_KEY},
79        {MMI::KeyEvent::KEYCODE_CTRL_LEFT, MMI::KeyEvent::KEYCODE_SHIFT_LEFT, CTRL_SHIFT_KEY},
80        {MMI::KeyEvent::KEYCODE_CTRL_LEFT, MMI::KeyEvent::KEYCODE_SHIFT_RIGHT, CTRL_SHIFT_KEY},
81
82        {MMI::KeyEvent::KEYCODE_CTRL_RIGHT, MMI::KeyEvent::KEYCODE_UNKNOWN, CTRL_KEY},
83        {MMI::KeyEvent::KEYCODE_CTRL_RIGHT, MMI::KeyEvent::KEYCODE_CTRL_LEFT, CTRL_KEY},
84        {MMI::KeyEvent::KEYCODE_CTRL_RIGHT, MMI::KeyEvent::KEYCODE_SHIFT_LEFT, CTRL_SHIFT_KEY},
85        {MMI::KeyEvent::KEYCODE_CTRL_RIGHT, MMI::KeyEvent::KEYCODE_SHIFT_RIGHT, CTRL_SHIFT_KEY},
86
87        {MMI::KeyEvent::KEYCODE_SHIFT_LEFT, MMI::KeyEvent::KEYCODE_UNKNOWN, SHIFT_KEY},
88        {MMI::KeyEvent::KEYCODE_SHIFT_LEFT, MMI::KeyEvent::KEYCODE_CTRL_LEFT, CTRL_SHIFT_KEY},
89        {MMI::KeyEvent::KEYCODE_SHIFT_LEFT, MMI::KeyEvent::KEYCODE_CTRL_RIGHT, CTRL_SHIFT_KEY},
90        {MMI::KeyEvent::KEYCODE_SHIFT_LEFT, MMI::KeyEvent::KEYCODE_SHIFT_RIGHT, SHIFT_KEY},
91
92        {MMI::KeyEvent::KEYCODE_SHIFT_RIGHT, MMI::KeyEvent::KEYCODE_UNKNOWN, SHIFT_KEY},
93        {MMI::KeyEvent::KEYCODE_SHIFT_RIGHT, MMI::KeyEvent::KEYCODE_CTRL_LEFT, CTRL_SHIFT_KEY},
94        {MMI::KeyEvent::KEYCODE_SHIFT_RIGHT, MMI::KeyEvent::KEYCODE_CTRL_RIGHT, CTRL_SHIFT_KEY},
95        {MMI::KeyEvent::KEYCODE_SHIFT_RIGHT, MMI::KeyEvent::KEYCODE_SHIFT_LEFT, SHIFT_KEY},
96    };
97} // namespace
98
99bool AccessibilityMouseKey::OnPointerEvent(MMI::PointerEvent &event)
100{
101    HILOG_DEBUG();
102
103    int32_t sourceType = event.GetSourceType();
104    int32_t action = event.GetPointerAction();
105    std::vector<int32_t> pointers = event.GetPointerIds();
106    size_t pointerCount = pointers.size();
107    if ((sourceType == MMI::PointerEvent::SOURCE_TYPE_MOUSE) &&
108        (action == MMI::PointerEvent::POINTER_ACTION_MOVE) &&
109        (pointerCount == ITEM_COUNT_1)) {
110        UpdateLastMouseEvent(event);
111    }
112    return false;
113}
114
115bool AccessibilityMouseKey::OnKeyEvent(MMI::KeyEvent &event)
116{
117    HILOG_DEBUG();
118
119    int32_t actionKey = MMI::KeyEvent::KEYCODE_UNKNOWN;
120    int32_t metaKey1 = MMI::KeyEvent::KEYCODE_UNKNOWN;
121    int32_t metaKey2 = MMI::KeyEvent::KEYCODE_UNKNOWN;
122    std::vector<int32_t> pressedKeys = event.GetPressedKeys();
123    if (IsMouseKey(pressedKeys, actionKey, metaKey1, metaKey2)) {
124        return ExecuteMouseKey(actionKey, metaKey1, metaKey2);
125    }
126    return false;
127}
128
129void AccessibilityMouseKey::UpdateLastMouseEvent(const MMI::PointerEvent &event)
130{
131    HILOG_DEBUG();
132
133    lastMouseMoveEvent_ = std::make_shared<MMI::PointerEvent>(event);
134}
135
136bool AccessibilityMouseKey::IsMouseKey(const std::vector<int32_t> &pressedKeys, int32_t &actionKey,
137    int32_t &metaKey1, int32_t &metaKey2) const
138{
139    HILOG_DEBUG();
140
141    size_t pressedKeyCount = pressedKeys.size();
142    if (pressedKeyCount == ITEM_COUNT_1) {
143        if (std::find(MOUSE_KEYCODE_V.begin(), MOUSE_KEYCODE_V.end(), pressedKeys[0]) != MOUSE_KEYCODE_V.end()) {
144            actionKey = pressedKeys[0];
145            return true;
146        }
147    } else if (pressedKeyCount == ITEM_COUNT_2) {
148        for (size_t i = 0; i < ITEM_COUNT_2; i++) {
149            if (std::find(MOUSE_MOVE_KEYCODE_V.begin(), MOUSE_MOVE_KEYCODE_V.end(), pressedKeys[i]) ==
150                MOUSE_MOVE_KEYCODE_V.end()) {
151                continue;
152            }
153            actionKey = pressedKeys[i];
154            size_t Index = (i + 1) % ITEM_COUNT_2;
155            if (std::find(CTRL_SHIFT_KEYCODE_V.begin(), CTRL_SHIFT_KEYCODE_V.end(), pressedKeys[Index]) !=
156                CTRL_SHIFT_KEYCODE_V.end()) {
157                metaKey1 = pressedKeys[Index];
158                return true;
159            }
160        }
161    } else if (pressedKeyCount == ITEM_COUNT_3) {
162        for (size_t i = 0; i < ITEM_COUNT_3; i++) {
163            if (std::find(MOUSE_MOVE_KEYCODE_V.begin(), MOUSE_MOVE_KEYCODE_V.end(), pressedKeys[i]) ==
164                MOUSE_MOVE_KEYCODE_V.end()) {
165                continue;
166            }
167            actionKey = pressedKeys[i];
168            size_t Index1 = (i + 1) % ITEM_COUNT_3;
169            size_t Index2 = (i + 2) % ITEM_COUNT_3;
170            if ((std::find(CTRL_SHIFT_KEYCODE_V.begin(), CTRL_SHIFT_KEYCODE_V.end(), pressedKeys[Index1]) !=
171                CTRL_SHIFT_KEYCODE_V.end()) &&
172                (std::find(CTRL_SHIFT_KEYCODE_V.begin(), CTRL_SHIFT_KEYCODE_V.end(), pressedKeys[Index2]) !=
173                CTRL_SHIFT_KEYCODE_V.end())) {
174                metaKey1 = pressedKeys[Index1];
175                metaKey2 = pressedKeys[Index2];
176                return true;
177            }
178        }
179    }
180    return false;
181}
182
183int32_t AccessibilityMouseKey::ParseMetaKey(int32_t metaKey1, int32_t metaKey2) const
184{
185    HILOG_DEBUG();
186    for (int32_t i = 0; i < ROW_COUNT; i++) {
187        if ((metaKey1 == PRESSED_METAKEYS_TBL[i][0]) && (metaKey2 == PRESSED_METAKEYS_TBL[i][1])) {
188            return PRESSED_METAKEYS_TBL[i][COLUMN_COUNT - 1];
189        }
190    }
191    return INVALID_KEY;
192}
193
194bool AccessibilityMouseKey::ExecuteMouseKey(int32_t actionKey, int32_t metaKey1, int32_t metaKey2)
195{
196    HILOG_DEBUG("actionKey:%{public}d, metaKey1:%{public}d, metaKey2:%{public}d", actionKey, metaKey1, metaKey2);
197
198    if ((actionKey == MMI::KeyEvent::KEYCODE_NUMPAD_1) ||
199        (actionKey == MMI::KeyEvent::KEYCODE_NUMPAD_2) ||
200        (actionKey == MMI::KeyEvent::KEYCODE_NUMPAD_3) ||
201        (actionKey == MMI::KeyEvent::KEYCODE_NUMPAD_4) ||
202        (actionKey == MMI::KeyEvent::KEYCODE_NUMPAD_6) ||
203        (actionKey == MMI::KeyEvent::KEYCODE_NUMPAD_7) ||
204        (actionKey == MMI::KeyEvent::KEYCODE_NUMPAD_8) ||
205        (actionKey == MMI::KeyEvent::KEYCODE_NUMPAD_9)) {
206        auto iter = MOUSE_MOVE_OFFSET_M.find(actionKey);
207        if (iter != MOUSE_MOVE_OFFSET_M.end()) {
208            int32_t offsetX = iter->second.offsetX;
209            int32_t offsetY = iter->second.offsetY;
210            int32_t result = ParseMetaKey(metaKey1, metaKey2);
211            if ((result == INVALID_KEY) || (result == CTRL_SHIFT_KEY)) {
212                return false;
213            }
214            if (result == CTRL_KEY) {
215                offsetX = static_cast<int32_t>(iter->second.offsetX * SPEED_UP_MULTIPLE);
216                offsetY = static_cast<int32_t>(iter->second.offsetY * SPEED_UP_MULTIPLE);
217            } else if (result == SHIFT_KEY) {
218                offsetX = static_cast<int32_t>(iter->second.offsetX * SLOW_DOWN_MULTIPLE);
219                offsetY = static_cast<int32_t>(iter->second.offsetY * SLOW_DOWN_MULTIPLE);
220            }
221            MoveMousePointer(offsetX, offsetY);
222        }
223    } else if (actionKey == MMI::KeyEvent::KEYCODE_NUMPAD_5) {
224        SendMouseClickEvent(SINGLE_CLICK);
225    } else if (actionKey == MMI::KeyEvent::KEYCODE_NUMPAD_DIVIDE) {
226        selectedKeyType_ = LEFT_KEY;
227    } else if (actionKey == MMI::KeyEvent::KEYCODE_NUMPAD_MULTIPLY) {
228        selectedKeyType_ = BOOTH_KEY;
229    } else if (actionKey == MMI::KeyEvent::KEYCODE_NUMPAD_SUBTRACT) {
230        selectedKeyType_ = RIGHT_KEY;
231    } else if (actionKey == MMI::KeyEvent::KEYCODE_NUMPAD_ADD) {
232        SendMouseClickEvent(DOUBLE_CLICK);
233    }
234    return true;
235}
236
237void AccessibilityMouseKey::MoveMousePointer(int32_t offsetX, int32_t offsetY)
238{
239    HILOG_DEBUG("offsetX:%{public}d, offsetY:%{public}d", offsetX, offsetY);
240
241    EventTransmission::OnMoveMouse(offsetX, offsetY);
242}
243
244void AccessibilityMouseKey::SendMouseClickEvent(CLICK_TYPE clickType)
245{
246    HILOG_DEBUG();
247
248    if (!lastMouseMoveEvent_) {
249        HILOG_DEBUG("No mouse event to be sent.");
250        return;
251    }
252
253    int64_t nowTime = GetSystemTime();
254    // Update event information.
255    lastMouseMoveEvent_->SetActionTime(nowTime);
256    lastMouseMoveEvent_->SetActionStartTime(nowTime);
257
258    // Update pointer item information.
259    int32_t pointerId = lastMouseMoveEvent_->GetPointerId();
260    MMI::PointerEvent::PointerItem item;
261    lastMouseMoveEvent_->GetPointerItem(pointerId, item);
262    item.SetDownTime(nowTime);
263    item.SetPressed(true);
264    lastMouseMoveEvent_->UpdatePointerItem(pointerId, item);
265
266    for (uint32_t clickCount = 0; clickCount < clickType; clickCount ++) {
267        HILOG_DEBUG("selectedKeyType:%{public}u", selectedKeyType_);
268        if (selectedKeyType_ == LEFT_KEY) {
269            PerformMouseAction(MMI::PointerEvent::MOUSE_BUTTON_LEFT, MMI::PointerEvent::POINTER_ACTION_BUTTON_DOWN);
270            PerformMouseAction(MMI::PointerEvent::MOUSE_BUTTON_LEFT, MMI::PointerEvent::POINTER_ACTION_BUTTON_UP);
271        } else if (selectedKeyType_ == RIGHT_KEY) {
272            PerformMouseAction(MMI::PointerEvent::MOUSE_BUTTON_RIGHT, MMI::PointerEvent::POINTER_ACTION_BUTTON_DOWN);
273            PerformMouseAction(MMI::PointerEvent::MOUSE_BUTTON_RIGHT, MMI::PointerEvent::POINTER_ACTION_BUTTON_UP);
274        } else if (selectedKeyType_ == BOOTH_KEY) {
275            PerformMouseAction(MMI::PointerEvent::MOUSE_BUTTON_LEFT, MMI::PointerEvent::POINTER_ACTION_BUTTON_DOWN);
276            PerformMouseAction(MMI::PointerEvent::MOUSE_BUTTON_RIGHT, MMI::PointerEvent::POINTER_ACTION_BUTTON_DOWN);
277
278            PerformMouseAction(MMI::PointerEvent::MOUSE_BUTTON_LEFT, MMI::PointerEvent::POINTER_ACTION_BUTTON_UP);
279            PerformMouseAction(MMI::PointerEvent::MOUSE_BUTTON_RIGHT, MMI::PointerEvent::POINTER_ACTION_BUTTON_UP);
280        }
281    }
282}
283
284void AccessibilityMouseKey::PerformMouseAction(int32_t buttonId, int32_t actionType)
285{
286    HILOG_DEBUG();
287
288    if (!lastMouseMoveEvent_) {
289        HILOG_DEBUG("No mouse event to be sent.");
290        return;
291    }
292    lastMouseMoveEvent_->SetButtonId(buttonId);
293    lastMouseMoveEvent_->SetButtonPressed(buttonId);
294    lastMouseMoveEvent_->SetPointerAction(actionType);
295    EventTransmission::OnPointerEvent(*lastMouseMoveEvent_);
296}
297
298int64_t AccessibilityMouseKey::GetSystemTime() const
299{
300    HILOG_DEBUG();
301
302    int64_t microsecond = Utils::GetSystemTime() * 1000;
303    return microsecond;
304}
305} // namespace Accessibility
306} // namespace OHOS