1 /*
2 * Copyright (c) 2024 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 <condition_variable>
17 #include <mutex>
18 #include <vector>
19
20 #include <gtest/gtest.h>
21
22 #include "input_manager.h"
23 #include "mmi_log.h"
24
25 #undef MMI_LOG_DOMAIN
26 #define MMI_LOG_DOMAIN MMI_LOG_HANDLER
27 #undef MMI_LOG_TAG
28 #define MMI_LOG_TAG "KeyShortcutRulesTest"
29
30 namespace OHOS {
31 namespace MMI {
32 namespace {
33 constexpr int32_t NO_LONG_PRESS { 0 };
34 constexpr int32_t DEFAULT_LONG_PRESS_TIME { 100 }; // 100ms
35 constexpr int32_t TWICE_LONG_PRESS_TIME { DEFAULT_LONG_PRESS_TIME + DEFAULT_LONG_PRESS_TIME };
36 constexpr int32_t DEFAULT_SAMPLING_PERIOD { 8 }; // 8ms
37 }
38
39 using namespace testing;
40 using namespace testing::ext;
41
42 class KeyShortcutRulesTest : public testing::Test {
43 public:
SetUpTestCase(void)44 static void SetUpTestCase(void) {}
TearDownTestCase(void)45 static void TearDownTestCase(void) {}
46
47 private:
48 std::shared_ptr<KeyEvent> TriggerSystemKey0101();
49 std::shared_ptr<KeyEvent> TriggerSystemKey0102();
50 std::shared_ptr<KeyEvent> TriggerSystemKey0301();
51 std::shared_ptr<KeyEvent> TriggerSystemKey0302();
52 };
53
TriggerSystemKey0101()54 std::shared_ptr<KeyEvent> KeyShortcutRulesTest::TriggerSystemKey0101()
55 {
56 std::shared_ptr<KeyEvent> keyEvent = KeyEvent::Create();
57 CHKPP(keyEvent);
58 int64_t now = GetSysClockTime();
59 KeyEvent::KeyItem keyItem {};
60 keyItem.SetKeyCode(KeyEvent::KEYCODE_CTRL_LEFT);
61 keyItem.SetDownTime(now - MS2US(DEFAULT_SAMPLING_PERIOD + DEFAULT_SAMPLING_PERIOD));
62 keyItem.SetPressed(true);
63 keyEvent->AddKeyItem(keyItem);
64
65 keyItem.SetKeyCode(KeyEvent::KEYCODE_SHIFT_LEFT);
66 keyItem.SetDownTime(now - MS2US(DEFAULT_SAMPLING_PERIOD));
67 keyEvent->AddKeyItem(keyItem);
68
69 keyItem.SetKeyCode(KeyEvent::KEYCODE_Q);
70 keyItem.SetDownTime(now);
71 keyEvent->AddKeyItem(keyItem);
72
73 keyEvent->SetKeyAction(KeyEvent::KEY_ACTION_DOWN);
74 keyEvent->SetKeyCode(KeyEvent::KEYCODE_Q);
75 keyEvent->SetActionTime(now);
76 return keyEvent;
77 }
78
TriggerSystemKey0102()79 std::shared_ptr<KeyEvent> KeyShortcutRulesTest::TriggerSystemKey0102()
80 {
81 std::shared_ptr<KeyEvent> keyEvent = KeyEvent::Create();
82 CHKPP(keyEvent);
83 int64_t now = GetSysClockTime();
84 KeyEvent::KeyItem keyItem {};
85 keyItem.SetKeyCode(KeyEvent::KEYCODE_SHIFT_LEFT);
86 keyItem.SetDownTime(now - MS2US(DEFAULT_SAMPLING_PERIOD + DEFAULT_SAMPLING_PERIOD));
87 keyItem.SetPressed(true);
88 keyEvent->AddKeyItem(keyItem);
89
90 keyItem.SetKeyCode(KeyEvent::KEYCODE_Q);
91 keyItem.SetDownTime(now - MS2US(DEFAULT_SAMPLING_PERIOD));
92 keyItem.SetPressed(false);
93 keyEvent->AddKeyItem(keyItem);
94
95 keyEvent->SetKeyAction(KeyEvent::KEY_ACTION_UP);
96 keyEvent->SetKeyCode(KeyEvent::KEYCODE_Q);
97 keyEvent->SetActionTime(now);
98 return keyEvent;
99 }
100
101 /**
102 * @tc.name: KeyShortcutRulesTest_TriggerSystemKey_01
103 * @tc.desc: If a shortcut was triggered when keys were pressed, shortcut would not be
104 checked when lifting up pressed keys.
105 * @tc.type: FUNC
106 * @tc.require:
107 */
HWTEST_F(KeyShortcutRulesTest, KeyShortcutRulesTest_TriggerSystemKey_01, TestSize.Level1)108 HWTEST_F(KeyShortcutRulesTest, KeyShortcutRulesTest_TriggerSystemKey_01, TestSize.Level1)
109 {
110 CALL_TEST_DEBUG;
111 int32_t keyCode1 = KeyEvent::KEYCODE_UNKNOWN;
112 int32_t keyCode2 = KeyEvent::KEYCODE_UNKNOWN;
113 std::mutex mutex;
114 std::condition_variable condVar;
115
116 auto keyOption1 = std::make_shared<KeyOption>();
117 keyOption1->SetPreKeys(std::set<int32_t> { KeyEvent::KEYCODE_CTRL_LEFT, KeyEvent::KEYCODE_SHIFT_LEFT });
118 keyOption1->SetFinalKey(KeyEvent::KEYCODE_Q);
119 keyOption1->SetFinalKeyDown(true);
120 keyOption1->SetFinalKeyDownDuration(NO_LONG_PRESS);
121
122 auto subscribe1 = InputManager::GetInstance()->SubscribeKeyEvent(keyOption1,
123 [&](std::shared_ptr<KeyEvent> keyEvent) {
124 std::unique_lock<std::mutex> guard { mutex };
125 keyCode1 = keyEvent->GetKeyCode();
126 condVar.notify_all();
127 });
128 EXPECT_TRUE(subscribe1 <= 0);
129
130 auto keyOption2 = std::make_shared<KeyOption>();
131 keyOption2->SetPreKeys(std::set<int32_t> { KeyEvent::KEYCODE_SHIFT_LEFT });
132 keyOption2->SetFinalKey(KeyEvent::KEYCODE_Q);
133 keyOption2->SetFinalKeyDown(false);
134 keyOption2->SetFinalKeyDownDuration(NO_LONG_PRESS);
135
136 auto subscribe2 = InputManager::GetInstance()->SubscribeKeyEvent(keyOption2,
137 [&](std::shared_ptr<KeyEvent> keyEvent) {
138 std::unique_lock<std::mutex> guard { mutex };
139 keyCode2 = keyEvent->GetKeyCode();
140 condVar.notify_all();
141 });
142 EXPECT_TRUE(subscribe2 <= 0);
143
144 std::unique_lock<std::mutex> guard { mutex };
145 auto keyEvent1 = TriggerSystemKey0101();
146 ASSERT_TRUE(keyEvent1 != nullptr);
147 InputManager::GetInstance()->SimulateInputEvent(keyEvent1);
148
149 EXPECT_FALSE(condVar.wait_for(guard, std::chrono::milliseconds(DEFAULT_LONG_PRESS_TIME),
150 [&keyCode1]() {
151 return (keyCode1 != KeyEvent::KEYCODE_UNKNOWN);
152 }));
153 EXPECT_NE(keyCode1, KeyEvent::KEYCODE_Q);
154
155 auto keyEvent2 = TriggerSystemKey0102();
156 ASSERT_TRUE(keyEvent2 != nullptr);
157 InputManager::GetInstance()->SimulateInputEvent(keyEvent2);
158
159 EXPECT_FALSE(condVar.wait_for(guard, std::chrono::milliseconds(DEFAULT_LONG_PRESS_TIME),
160 [&keyCode2]() {
161 return (keyCode2 != KeyEvent::KEYCODE_UNKNOWN);
162 }));
163 EXPECT_EQ(keyCode2, KeyEvent::KEYCODE_UNKNOWN);
164
165 InputManager::GetInstance()->UnsubscribeKeyEvent(subscribe1);
166 InputManager::GetInstance()->UnsubscribeKeyEvent(subscribe2);
167 }
168
169 /**
170 * @tc.name: KeyShortcutRulesTest_TriggerSystemKey_02
171 * @tc.desc: If a shortcut was triggered when keys were pressed, shortcut would not be
172 checked when lifting up pressed keys.
173 * @tc.type: FUNC
174 * @tc.require:
175 */
HWTEST_F(KeyShortcutRulesTest, KeyShortcutRulesTest_TriggerSystemKey_02, TestSize.Level1)176 HWTEST_F(KeyShortcutRulesTest, KeyShortcutRulesTest_TriggerSystemKey_02, TestSize.Level1)
177 {
178 CALL_TEST_DEBUG;
179 int32_t keyCode1 = KeyEvent::KEYCODE_UNKNOWN;
180 int32_t keyCode2 = KeyEvent::KEYCODE_UNKNOWN;
181 std::mutex mutex;
182 std::condition_variable condVar;
183
184 auto keyOption1 = std::make_shared<KeyOption>();
185 keyOption1->SetPreKeys(std::set<int32_t> { KeyEvent::KEYCODE_CTRL_LEFT, KeyEvent::KEYCODE_SHIFT_LEFT });
186 keyOption1->SetFinalKey(KeyEvent::KEYCODE_Q);
187 keyOption1->SetFinalKeyDown(true);
188 keyOption1->SetFinalKeyDownDuration(NO_LONG_PRESS);
189
190 auto subscribe1 = InputManager::GetInstance()->SubscribeKeyEvent(keyOption1,
191 [&](std::shared_ptr<KeyEvent> keyEvent) {
192 std::unique_lock<std::mutex> guard { mutex };
193 keyCode1 = keyEvent->GetKeyCode();
194 condVar.notify_all();
195 });
196 EXPECT_TRUE(subscribe1 <= 0);
197
198 auto keyOption2 = std::make_shared<KeyOption>();
199 keyOption2->SetPreKeys(std::set<int32_t> { KeyEvent::KEYCODE_SHIFT_LEFT });
200 keyOption2->SetFinalKey(KeyEvent::KEYCODE_Q);
201 keyOption2->SetFinalKeyDown(false);
202 keyOption2->SetFinalKeyDownDuration(NO_LONG_PRESS);
203
204 auto subscribe2 = InputManager::GetInstance()->SubscribeKeyEvent(keyOption2,
205 [&](std::shared_ptr<KeyEvent> keyEvent) {
206 std::unique_lock<std::mutex> guard { mutex };
207 keyCode2 = keyEvent->GetKeyCode();
208 condVar.notify_all();
209 });
210 EXPECT_TRUE(subscribe2 <= 0);
211
212 std::unique_lock<std::mutex> guard { mutex };
213 auto keyEvent2 = TriggerSystemKey0102();
214 ASSERT_TRUE(keyEvent2 != nullptr);
215 InputManager::GetInstance()->SimulateInputEvent(keyEvent2);
216
217 EXPECT_FALSE(condVar.wait_for(guard, std::chrono::milliseconds(DEFAULT_LONG_PRESS_TIME),
218 [&keyCode2]() {
219 return (keyCode2 != KeyEvent::KEYCODE_UNKNOWN);
220 }));
221 EXPECT_NE(keyCode2, KeyEvent::KEYCODE_Q);
222
223 InputManager::GetInstance()->UnsubscribeKeyEvent(subscribe1);
224 InputManager::GetInstance()->UnsubscribeKeyEvent(subscribe2);
225 }
226
TriggerSystemKey0301()227 std::shared_ptr<KeyEvent> KeyShortcutRulesTest::TriggerSystemKey0301()
228 {
229 std::shared_ptr<KeyEvent> keyEvent = KeyEvent::Create();
230 CHKPP(keyEvent);
231 int64_t now = GetSysClockTime();
232 KeyEvent::KeyItem keyItem {};
233 keyItem.SetKeyCode(KeyEvent::KEYCODE_SHIFT_LEFT);
234 keyItem.SetDownTime(now - MS2US(DEFAULT_SAMPLING_PERIOD));
235 keyItem.SetPressed(true);
236 keyEvent->AddKeyItem(keyItem);
237
238 keyItem.SetKeyCode(KeyEvent::KEYCODE_Q);
239 keyItem.SetDownTime(now);
240 keyEvent->AddKeyItem(keyItem);
241
242 keyEvent->SetKeyAction(KeyEvent::KEY_ACTION_DOWN);
243 keyEvent->SetKeyCode(KeyEvent::KEYCODE_Q);
244 keyEvent->SetActionTime(now);
245 return keyEvent;
246 }
247
TriggerSystemKey0302()248 std::shared_ptr<KeyEvent> KeyShortcutRulesTest::TriggerSystemKey0302()
249 {
250 std::shared_ptr<KeyEvent> keyEvent = KeyEvent::Create();
251 CHKPP(keyEvent);
252 int64_t now = GetSysClockTime();
253 KeyEvent::KeyItem keyItem {};
254 keyItem.SetKeyCode(KeyEvent::KEYCODE_SHIFT_LEFT);
255 keyItem.SetDownTime(now - MS2US(DEFAULT_SAMPLING_PERIOD + DEFAULT_SAMPLING_PERIOD));
256 keyItem.SetPressed(true);
257 keyEvent->AddKeyItem(keyItem);
258
259 keyItem.SetKeyCode(KeyEvent::KEYCODE_Q);
260 keyItem.SetDownTime(now - MS2US(DEFAULT_SAMPLING_PERIOD));
261 keyEvent->AddKeyItem(keyItem);
262
263 keyEvent->SetKeyAction(KeyEvent::KEY_ACTION_UP);
264 keyEvent->SetKeyCode(KeyEvent::KEYCODE_Q);
265 keyEvent->SetActionTime(now);
266 return keyEvent;
267 }
268
269 /**
270 * @tc.name: KeyShortcutRulesTest_TriggerSystemKey_03
271 * @tc.desc: If a shortcut was triggered when keys were pressed, shortcut would not be
272 checked when lifting up pressed keys.
273 * @tc.type: FUNC
274 * @tc.require:
275 */
HWTEST_F(KeyShortcutRulesTest, KeyShortcutRulesTest_TriggerSystemKey_03, TestSize.Level1)276 HWTEST_F(KeyShortcutRulesTest, KeyShortcutRulesTest_TriggerSystemKey_03, TestSize.Level1)
277 {
278 CALL_TEST_DEBUG;
279 int32_t keyCode1 = KeyEvent::KEYCODE_UNKNOWN;
280 int32_t keyCode2 = KeyEvent::KEYCODE_UNKNOWN;
281
282 auto keyOption1 = std::make_shared<KeyOption>();
283 keyOption1->SetPreKeys(std::set<int32_t> { KeyEvent::KEYCODE_SHIFT_LEFT });
284 keyOption1->SetFinalKey(KeyEvent::KEYCODE_Q);
285 keyOption1->SetFinalKeyDown(true);
286 keyOption1->SetFinalKeyDownDuration(DEFAULT_LONG_PRESS_TIME);
287
288 auto subscribe1 = InputManager::GetInstance()->SubscribeKeyEvent(keyOption1,
289 [&](std::shared_ptr<KeyEvent> keyEvent) {
290 keyCode1 = keyEvent->GetKeyCode();
291 });
292 EXPECT_TRUE(subscribe1 <= 0);
293
294 auto keyOption2 = std::make_shared<KeyOption>();
295 keyOption2->SetPreKeys(std::set<int32_t> { KeyEvent::KEYCODE_SHIFT_LEFT });
296 keyOption2->SetFinalKey(KeyEvent::KEYCODE_Q);
297 keyOption2->SetFinalKeyDown(false);
298 keyOption2->SetFinalKeyDownDuration(NO_LONG_PRESS);
299
300 auto subscribe2 = InputManager::GetInstance()->SubscribeKeyEvent(keyOption2,
301 [&](std::shared_ptr<KeyEvent> keyEvent) {
302 keyCode2 = keyEvent->GetKeyCode();
303 });
304 EXPECT_TRUE(subscribe2 <= 0);
305
306 auto keyEvent1 = TriggerSystemKey0301();
307 ASSERT_TRUE(keyEvent1 != nullptr);
308 InputManager::GetInstance()->SimulateInputEvent(keyEvent1);
309
310 auto keyEvent2 = TriggerSystemKey0302();
311 ASSERT_TRUE(keyEvent2 != nullptr);
312 InputManager::GetInstance()->SimulateInputEvent(keyEvent2);
313
314 std::this_thread::sleep_for(std::chrono::milliseconds(TWICE_LONG_PRESS_TIME));
315 EXPECT_EQ(keyCode1, KeyEvent::KEYCODE_UNKNOWN);
316 EXPECT_NE(keyCode2, KeyEvent::KEYCODE_Q);
317
318 InputManager::GetInstance()->UnsubscribeKeyEvent(subscribe1);
319 InputManager::GetInstance()->UnsubscribeKeyEvent(subscribe2);
320 }
321 } // namespace MMI
322 } // namespace OHOS
323