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