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 "key_shortcut_manager.h"
17 
18 #include <config_policy_utils.h>
19 
20 #include "app_state_observer.h"
21 #include "define_multimodal.h"
22 #include "key_command_handler_util.h"
23 
24 #undef MMI_LOG_DOMAIN
25 #define MMI_LOG_DOMAIN MMI_LOG_HANDLER
26 #undef MMI_LOG_TAG
27 #define MMI_LOG_TAG "KeyShortcutManager"
28 
29 namespace OHOS {
30 namespace MMI {
31 namespace {
32 constexpr size_t SINGLE_MODIFIER { 1 };
33 constexpr size_t MAX_N_PRINTABLE_ITEMS { 3 };
34 constexpr int32_t MAXIMUM_LONG_PRESS_TIME { 60000 }; // 60s
35 constexpr int32_t REPEAT_ONCE { 1 };
36 }
37 
38 std::mutex KeyShortcutManager::mutex_;
39 std::shared_ptr<KeyShortcutManager> KeyShortcutManager::instance_;
40 
41 const std::map<int32_t, uint32_t> KeyShortcutManager::modifiers_ {
42     { KeyEvent::KEYCODE_ALT_LEFT, SHORTCUT_MODIFIER_ALT },
43     { KeyEvent::KEYCODE_ALT_RIGHT, SHORTCUT_MODIFIER_ALT },
44     { KeyEvent::KEYCODE_SHIFT_LEFT, SHORTCUT_MODIFIER_SHIFT },
45     { KeyEvent::KEYCODE_SHIFT_RIGHT, SHORTCUT_MODIFIER_SHIFT },
46     { KeyEvent::KEYCODE_CTRL_LEFT, SHORTCUT_MODIFIER_CTRL },
47     { KeyEvent::KEYCODE_CTRL_RIGHT, SHORTCUT_MODIFIER_CTRL },
48     { KeyEvent::KEYCODE_META_LEFT, SHORTCUT_MODIFIER_LOGO },
49     { KeyEvent::KEYCODE_META_RIGHT, SHORTCUT_MODIFIER_LOGO }
50 };
51 
operator <(const SystemKey &other) const52 bool KeyShortcutManager::SystemKey::operator<(const SystemKey &other) const
53 {
54     uint32_t modifier1 = (modifiers & SHORTCUT_MODIFIER_MASK);
55     uint32_t modifier2 = (other.modifiers & SHORTCUT_MODIFIER_MASK);
56     if (modifier1 != modifier2) {
57         return (modifier1 < modifier2);
58     }
59     return (finalKey < other.finalKey);
60 }
61 
operator <(const ExceptionalSystemKey &other) const62 bool KeyShortcutManager::ExceptionalSystemKey::operator<(const ExceptionalSystemKey &other) const
63 {
64     if (finalKey != other.finalKey) {
65         return (finalKey < other.finalKey);
66     }
67     if (longPressTime != other.longPressTime) {
68         return (longPressTime < other.longPressTime);
69     }
70     if (triggerType != other.triggerType) {
71         return (triggerType < other.triggerType);
72     }
73     return (preKeys < other.preKeys);
74 }
75 
operator <(const SystemHotkey &other) const76 bool KeyShortcutManager::SystemHotkey::operator<(const SystemHotkey &other) const
77 {
78     if (finalKey != other.finalKey) {
79         return (finalKey < other.finalKey);
80     }
81     return (preKeys < other.preKeys);
82 }
83 
GetInstance()84 std::shared_ptr<KeyShortcutManager> KeyShortcutManager::GetInstance()
85 {
86     if (instance_ == nullptr) {
87         std::lock_guard<std::mutex> guard(mutex_);
88         if (instance_ == nullptr) {
89             instance_ = std::make_shared<KeyShortcutManager>();
90         }
91     }
92     return instance_;
93 }
94 
KeyShortcutManager()95 KeyShortcutManager::KeyShortcutManager()
96 {
97     LoadSystemKeys();
98     LoadExceptionalSystemKeys();
99     LoadHotkeys();
100 }
101 
RegisterSystemKey(const SystemShortcutKey &key)102 int32_t KeyShortcutManager::RegisterSystemKey(const SystemShortcutKey &key)
103 {
104     KeyShortcut shortcut {};
105     ExceptionalSystemKey eSysKey {
106         .preKeys = key.modifiers,
107         .finalKey = key.finalKey,
108         .longPressTime = key.longPressTime,
109         .triggerType = key.triggerType,
110     };
111 
112     if (!CheckSystemKey(key, shortcut)) {
113         MMI_HILOGE("Not system key ([%{public}s],FinalKey:%{public}d,PressTime:%{public}d,TriggerType:%{public}d)",
114             FormatModifiers(key.modifiers).c_str(), key.finalKey, key.longPressTime, key.triggerType);
115         if (IsExceptionalSystemKey(eSysKey)) {
116             auto shortcutId = GenerateId();
117             MMI_HILOGI("Register exceptional system key [No.%{public}d]"
118                 "([%{public}s],FinalKey:%{public}d,PressTime:%{public}d,TriggerType:%{public}d)",
119                 shortcutId, FormatModifiers(key.modifiers).c_str(), key.finalKey, key.longPressTime, key.triggerType);
120             return shortcutId;
121         }
122         return KEY_SHORTCUT_ERROR_COMBINATION_KEY;
123     }
124     if (!IsReservedSystemKey(shortcut)) {
125         if (IsExceptionalSystemKey(eSysKey)) {
126             auto shortcutId = GenerateId();
127             MMI_HILOGI("Register exceptional system key [No.%{public}d]"
128                 "([%{public}s],FinalKey:%{public}d,PressTime:%{public}d,TriggerType:%{public}d)",
129                 shortcutId, FormatModifiers(key.modifiers).c_str(), key.finalKey, key.longPressTime, key.triggerType);
130             return shortcutId;
131         }
132         MMI_HILOGE("The system application can only subscribe to reserved shortcuts");
133         return KEY_SHORTCUT_ERROR_COMBINATION_KEY;
134     }
135     auto [iter, _] = shortcuts_.emplace(GenerateId(), shortcut);
136     MMI_HILOGI("Register system key [No.%{public}d](0x%{public}x,%{public}d,%{public}d,%{public}d,%{public}d)",
137         iter->first, shortcut.modifiers, shortcut.finalKey, shortcut.longPressTime,
138         shortcut.triggerType, shortcut.session);
139     return iter->first;
140 }
141 
UnregisterSystemKey(int32_t shortcutId)142 void KeyShortcutManager::UnregisterSystemKey(int32_t shortcutId)
143 {
144     auto iter = shortcuts_.find(shortcutId);
145     if (iter == shortcuts_.end()) {
146         MMI_HILOGI("There is no system key(%{public}d)", shortcutId);
147         return;
148     }
149     const KeyShortcut &key = iter->second;
150     MMI_HILOGI("Unregister system key(0x%{public}x,%{public}d,%{public}d,%{public}d,SESSION:%{public}d)",
151         key.modifiers, key.finalKey, key.longPressTime, key.triggerType, key.session);
152     ResetTriggering(shortcutId);
153     shortcuts_.erase(iter);
154 }
155 
RegisterHotKey(const HotKey &key)156 int32_t KeyShortcutManager::RegisterHotKey(const HotKey &key)
157 {
158     KeyShortcut globalKey {};
159 
160     if (!CheckGlobalKey(key, globalKey)) {
161         MMI_HILOGE("Not global shortcut key");
162         return KEY_SHORTCUT_ERROR_COMBINATION_KEY;
163     }
164     if (HaveRegisteredGlobalKey(globalKey)) {
165         MMI_HILOGE("Global key (0x%{public}x, %{public}d) has been taken", globalKey.modifiers, globalKey.finalKey);
166         return KEY_SHORTCUT_ERROR_TAKEN;
167     }
168     if (IsReservedSystemKey(globalKey)) {
169         MMI_HILOGE("Can not register reserved system key ([%{public}s],%{public}d)",
170             FormatModifiers(key.modifiers).c_str(), key.finalKey);
171         return KEY_SHORTCUT_ERROR_COMBINATION_KEY;
172     }
173     auto [iter, _] = shortcuts_.emplace(GenerateId(), globalKey);
174     MMI_HILOGI("Register global key [No.%{public}d](0x%{public}x,%{public}d,SESSION:%{public}d)",
175         iter->first, globalKey.modifiers, globalKey.finalKey, globalKey.session);
176     return iter->first;
177 }
178 
UnregisterHotKey(int32_t shortcutId)179 void KeyShortcutManager::UnregisterHotKey(int32_t shortcutId)
180 {
181     auto iter = shortcuts_.find(shortcutId);
182     if (iter == shortcuts_.end()) {
183         MMI_HILOGI("There is no global key(%{public}d)", shortcutId);
184         return;
185     }
186     const KeyShortcut &key = iter->second;
187     MMI_HILOGI("Unregister global key(0x%{public}x,%{public}d,SESSION:%{public}d)",
188         key.modifiers, key.finalKey, key.session);
189     shortcuts_.erase(iter);
190 }
191 
HandleEvent(std::shared_ptr<KeyEvent> keyEvent)192 bool KeyShortcutManager::HandleEvent(std::shared_ptr<KeyEvent> keyEvent)
193 {
194     CHKPF(keyEvent);
195     MMI_HILOGI("Handle key event(No.%{public}d,KC:%{public}d,KA:%{public}d,PressedKeys:[%{public}s])",
196         keyEvent->GetId(), keyEvent->GetKeyCode(), keyEvent->GetKeyAction(), FormatPressedKeys(keyEvent).c_str());
197     ResetTriggering(keyEvent);
198     if (keyEvent->GetKeyAction() == KeyEvent::KEY_ACTION_DOWN) {
199         return HandleKeyDown(keyEvent);
200     } else if (keyEvent->GetKeyAction() == KeyEvent::KEY_ACTION_UP) {
201         return HandleKeyUp(keyEvent);
202     } else if (keyEvent->GetKeyAction() == KeyEvent::KEY_ACTION_CANCEL) {
203         return HandleKeyCancel(keyEvent);
204     }
205     return false;
206 }
207 
LoadSystemKeys()208 void KeyShortcutManager::LoadSystemKeys()
209 {
210     char cfgName[] { "etc/multimodalinput/system_keys_config.json" };
211     char buf[MAX_PATH_LEN] {};
212     char *cfgPath = ::GetOneCfgFile(cfgName, buf, sizeof(buf));
213 
214     if (cfgPath == nullptr) {
215         MMI_HILOGE("No '%{public}s' was found", cfgPath);
216         return;
217     }
218     MMI_HILOGI("Config of system keys:%{public}s", cfgPath);
219     ReadSystemKeys(std::string(cfgPath));
220 }
221 
ReadSystemKeys(const std::string &cfgPath)222 void KeyShortcutManager::ReadSystemKeys(const std::string &cfgPath)
223 {
224     std::string cfg = ReadJsonFile(cfgPath);
225     JsonParser parser;
226     parser.json_ = cJSON_Parse(cfg.c_str());
227     if (!cJSON_IsObject(parser.json_)) {
228         MMI_HILOGE("Not json format");
229         return;
230     }
231     cJSON* jsonSysKeys = cJSON_GetObjectItemCaseSensitive(parser.json_, "SystemKeys");
232     if (!cJSON_IsArray(jsonSysKeys)) {
233         MMI_HILOGE("jsonSysKeys is not array");
234         return;
235     }
236     int32_t nSysKeys = cJSON_GetArraySize(jsonSysKeys);
237     for (int32_t index = 0; index < nSysKeys; ++index) {
238         cJSON *jsonSysKey = cJSON_GetArrayItem(jsonSysKeys, index);
239         ReadSystemKey(jsonSysKey);
240     }
241 }
242 
ReadSystemKey(cJSON *jsonSysKey)243 int32_t KeyShortcutManager::ReadSystemKey(cJSON *jsonSysKey)
244 {
245     if (!cJSON_IsObject(jsonSysKey)) {
246         MMI_HILOGE("Not json object");
247         return KEY_SHORTCUT_ERROR_CONFIG;
248     }
249     cJSON *jsonPreKeys = cJSON_GetObjectItem(jsonSysKey, "preKeys");
250     if (!cJSON_IsArray(jsonPreKeys)) {
251         MMI_HILOGE("Expect array for PreKeys");
252         return KEY_SHORTCUT_ERROR_CONFIG;
253     }
254     std::set<int32_t> preKeys;
255     int32_t nPreKeys = cJSON_GetArraySize(jsonPreKeys);
256 
257     for (int32_t index = 0; index < nPreKeys; ++index) {
258         cJSON *jsonPreKey = cJSON_GetArrayItem(jsonPreKeys, index);
259         if (!cJSON_IsNumber(jsonPreKey)) {
260             MMI_HILOGE("Expect number for PreKey");
261             return KEY_SHORTCUT_ERROR_CONFIG;
262         }
263         preKeys.insert(static_cast<int32_t>(cJSON_GetNumberValue(jsonPreKey)));
264     }
265     cJSON *jsonFinalKey = cJSON_GetObjectItem(jsonSysKey, "finalKey");
266     if (!cJSON_IsNumber(jsonFinalKey)) {
267         MMI_HILOGE("Expect number for FinalKey");
268         return KEY_SHORTCUT_ERROR_CONFIG;
269     }
270     int32_t finalKey = static_cast<int32_t>(cJSON_GetNumberValue(jsonFinalKey));
271     return AddSystemKey(preKeys, finalKey);
272 }
273 
AddSystemKey(const std::set<int32_t> &preKeys, int32_t finalKey)274 int32_t KeyShortcutManager::AddSystemKey(const std::set<int32_t> &preKeys, int32_t finalKey)
275 {
276     SystemShortcutKey sysKey {
277         .modifiers = preKeys,
278         .finalKey = finalKey,
279     };
280     KeyShortcut shortcut {};
281 
282     if (!CheckSystemKey(sysKey, shortcut)) {
283         MMI_HILOGE("Not system key ([%{public}s],%{public}d)", FormatModifiers(preKeys).c_str(), finalKey);
284         return KEY_SHORTCUT_ERROR_COMBINATION_KEY;
285     }
286     systemKeys_.emplace(SystemKey {
287         .modifiers = shortcut.modifiers,
288         .finalKey = shortcut.finalKey,
289     });
290     return RET_OK;
291 }
292 
LoadExceptionalSystemKeys()293 void KeyShortcutManager::LoadExceptionalSystemKeys()
294 {
295     char cfgName[] { "etc/multimodalinput/exceptional_system_keys_config.json" };
296     char buf[MAX_PATH_LEN] {};
297     char *cfgPath = ::GetOneCfgFile(cfgName, buf, sizeof(buf));
298 
299     if (cfgPath == nullptr) {
300         MMI_HILOGE("No '%{public}s' was found", cfgPath);
301         return;
302     }
303     MMI_HILOGI("Config of exceptional system keys:%{public}s", cfgPath);
304     ReadExceptionalSystemKeys(std::string(cfgPath));
305 }
306 
ReadExceptionalSystemKeys(const std::string &cfgPath)307 void KeyShortcutManager::ReadExceptionalSystemKeys(const std::string &cfgPath)
308 {
309     std::string cfg = ReadJsonFile(cfgPath);
310     JsonParser parser;
311     parser.json_ = cJSON_Parse(cfg.c_str());
312     if (!cJSON_IsObject(parser.json_)) {
313         MMI_HILOGE("Not json format");
314         return;
315     }
316     cJSON* jsonSysKeys = cJSON_GetObjectItemCaseSensitive(parser.json_, "ExceptionalSystemKeys");
317     if (!cJSON_IsArray(jsonSysKeys)) {
318         MMI_HILOGE("jsonSysKeys is not array");
319         return;
320     }
321     int32_t nSysKeys = cJSON_GetArraySize(jsonSysKeys);
322     for (int32_t index = 0; index < nSysKeys; ++index) {
323         cJSON *jsonSysKey = cJSON_GetArrayItem(jsonSysKeys, index);
324         ReadExceptionalSystemKey(jsonSysKey);
325     }
326 }
327 
ReadExceptionalSystemKey(cJSON *jsonSysKey)328 int32_t KeyShortcutManager::ReadExceptionalSystemKey(cJSON *jsonSysKey)
329 {
330     if (!cJSON_IsObject(jsonSysKey)) {
331         MMI_HILOGE("Not json object");
332         return KEY_SHORTCUT_ERROR_CONFIG;
333     }
334     ExceptionalSystemKey sysKey {};
335     cJSON *jsonPreKeys = cJSON_GetObjectItem(jsonSysKey, "preKeys");
336     if (!cJSON_IsArray(jsonPreKeys)) {
337         MMI_HILOGE("Expect array for PreKeys");
338         return KEY_SHORTCUT_ERROR_CONFIG;
339     }
340     int32_t nPreKeys = cJSON_GetArraySize(jsonPreKeys);
341 
342     for (int32_t index = 0; index < nPreKeys; ++index) {
343         cJSON *jsonPreKey = cJSON_GetArrayItem(jsonPreKeys, index);
344         if (!cJSON_IsNumber(jsonPreKey)) {
345             MMI_HILOGE("Expect number for PreKey");
346             return KEY_SHORTCUT_ERROR_CONFIG;
347         }
348         sysKey.preKeys.insert(static_cast<int32_t>(cJSON_GetNumberValue(jsonPreKey)));
349     }
350     cJSON *jsonFinalKey = cJSON_GetObjectItem(jsonSysKey, "finalKey");
351     if (!cJSON_IsNumber(jsonFinalKey)) {
352         MMI_HILOGE("Expect number for FinalKey");
353         return KEY_SHORTCUT_ERROR_CONFIG;
354     }
355     sysKey.finalKey = static_cast<int32_t>(cJSON_GetNumberValue(jsonFinalKey));
356 
357     cJSON *jsonPressTime = cJSON_GetObjectItem(jsonSysKey, "longPressTime");
358     if (!cJSON_IsNumber(jsonPressTime)) {
359         MMI_HILOGE("Expect number for LongPressTime");
360         return KEY_SHORTCUT_ERROR_CONFIG;
361     }
362     sysKey.longPressTime = static_cast<int32_t>(cJSON_GetNumberValue(jsonPressTime));
363 
364     cJSON *jsonTriggerType = cJSON_GetObjectItem(jsonSysKey, "triggerType");
365     char *triggerType = cJSON_GetStringValue(jsonTriggerType);
366     if ((triggerType == nullptr) ||
367         ((std::strcmp(triggerType, "down") != 0) && (std::strcmp(triggerType, "up") != 0))) {
368         MMI_HILOGE("Expect down/up for TriggerType");
369         return KEY_SHORTCUT_ERROR_CONFIG;
370     }
371     sysKey.triggerType = (std::strcmp(triggerType, "down") == 0 ?
372                           SHORTCUT_TRIGGER_TYPE_DOWN : SHORTCUT_TRIGGER_TYPE_UP);
373 
374     AddExceptionalSystemKey(sysKey);
375     return RET_OK;
376 }
377 
AddExceptionalSystemKey(const ExceptionalSystemKey &sysKey)378 void KeyShortcutManager::AddExceptionalSystemKey(const ExceptionalSystemKey &sysKey)
379 {
380     MMI_HILOGI("Add exceptional system key ([%{public}s],FinalKey:%{public}d,PressTime:%{public}d,%{public}s)",
381         FormatModifiers(sysKey.preKeys).c_str(), sysKey.finalKey, sysKey.longPressTime,
382         (sysKey.triggerType == SHORTCUT_TRIGGER_TYPE_DOWN ? "down" : "up"));
383     exceptSysKeys_.emplace(sysKey);
384 }
385 
FormatModifiers(const std::set<int32_t> &modifiers) const386 std::string KeyShortcutManager::FormatModifiers(const std::set<int32_t> &modifiers) const
387 {
388     std::ostringstream sModifiers;
389     size_t nModifiers = 0;
390 
391     if (auto iter = modifiers.cbegin(); iter != modifiers.cend()) {
392         sModifiers << *iter;
393         ++nModifiers;
394 
395         for (++iter; iter != modifiers.cend(); ++iter) {
396             if (nModifiers > MAX_N_PRINTABLE_ITEMS) {
397                 sModifiers << ",...";
398                 break;
399             }
400             sModifiers << "," << *iter;
401             ++nModifiers;
402         }
403     }
404     return sModifiers.str();
405 }
406 
GenerateId() const407 int32_t KeyShortcutManager::GenerateId() const
408 {
409     static int32_t baseId {};
410     return ++baseId;
411 }
412 
IsExceptionalSystemKey(const ExceptionalSystemKey &sysKey) const413 bool KeyShortcutManager::IsExceptionalSystemKey(const ExceptionalSystemKey &sysKey) const
414 {
415     return (exceptSysKeys_.find(sysKey) != exceptSysKeys_.cend());
416 }
417 
IsModifier(int32_t keyCode) const418 bool KeyShortcutManager::IsModifier(int32_t keyCode) const
419 {
420     return (modifiers_.find(keyCode) != modifiers_.cend());
421 }
422 
IsValid(const ShortcutTriggerType triggerType) const423 bool KeyShortcutManager::IsValid(const ShortcutTriggerType triggerType) const
424 {
425     return ((triggerType == SHORTCUT_TRIGGER_TYPE_DOWN) ||
426             (triggerType == SHORTCUT_TRIGGER_TYPE_UP));
427 }
428 
IsReservedSystemKey(const KeyShortcut &shortcut) const429 bool KeyShortcutManager::IsReservedSystemKey(const KeyShortcut &shortcut) const
430 {
431     return (systemKeys_.find(SystemKey {
432         .modifiers = shortcut.modifiers,
433         .finalKey = shortcut.finalKey,
434     }) != systemKeys_.cend());
435 }
436 
CheckSystemKey(const SystemShortcutKey &key, KeyShortcut &shortcut) const437 bool KeyShortcutManager::CheckSystemKey(const SystemShortcutKey &key, KeyShortcut &shortcut) const
438 {
439     size_t nModifiers = 0;
440     uint32_t modifiers = 0U;
441 
442     for (auto keyCode : key.modifiers) {
443         auto iter = modifiers_.find(keyCode);
444         if (iter == modifiers_.end()) {
445             MMI_HILOGE("Key code (%{public}d) is not modifier", keyCode);
446             return false;
447         }
448         if ((modifiers & iter->second) != iter->second) {
449             modifiers |= iter->second;
450             ++nModifiers;
451         }
452     }
453     if (nModifiers < SINGLE_MODIFIER) {
454         MMI_HILOGE("Require modifier(s)");
455         return false;
456     }
457     if (key.finalKey == SHORTCUT_PURE_MODIFIERS) {
458         if ((nModifiers == SINGLE_MODIFIER) && (modifiers != SHORTCUT_MODIFIER_LOGO)) {
459             MMI_HILOGE("Only 'Logo' can be one-key shortcut");
460             return false;
461         }
462     } else if (IsModifier(key.finalKey)) {
463         MMI_HILOGE("Modifier as final key");
464         return false;
465     }
466     if (!IsValid(key.triggerType)) {
467         MMI_HILOGE("Invalid trigger type(%{public}d)", key.triggerType);
468         return false;
469     }
470     if ((key.longPressTime < 0) || (key.longPressTime > MAXIMUM_LONG_PRESS_TIME)) {
471         MMI_HILOGE("Long-press time(%{public}d) is out of range [0,%{public}d]",
472             key.longPressTime, MAXIMUM_LONG_PRESS_TIME);
473         return false;
474     }
475     shortcut = KeyShortcut {
476         .modifiers = modifiers,
477         .finalKey = key.finalKey,
478         .longPressTime = key.longPressTime,
479         .triggerType = key.triggerType,
480         .session = key.session,
481         .callback = key.callback,
482     };
483     return true;
484 }
485 
CheckGlobalKey(const HotKey &key, KeyShortcut &shortcut) const486 bool KeyShortcutManager::CheckGlobalKey(const HotKey &key, KeyShortcut &shortcut) const
487 {
488     size_t nModifiers = 0;
489     uint32_t modifiers = 0U;
490 
491     for (auto keyCode : key.modifiers) {
492         auto iter = modifiers_.find(keyCode);
493         if (iter == modifiers_.end()) {
494             MMI_HILOGE("Key code (%{public}d) is not modifier", keyCode);
495             return false;
496         }
497         if ((modifiers & iter->second) != iter->second) {
498             modifiers |= iter->second;
499             ++nModifiers;
500         }
501     }
502     if (IsModifier(key.finalKey)) {
503         MMI_HILOGE("FinalKey(%{public}d) should not be modifier", key.finalKey);
504         return false;
505     }
506     if (key.finalKey == SHORTCUT_PURE_MODIFIERS) {
507         MMI_HILOGE("Expect FinalKey");
508         return false;
509     }
510     if (modifiers & SHORTCUT_MODIFIER_LOGO) {
511         MMI_HILOGE("'LOGO' is not allowed for GlobalKey");
512         return false;
513     }
514     if (nModifiers < SINGLE_MODIFIER) {
515         MMI_HILOGE("Require modifier(s)");
516         return false;
517     }
518     shortcut = KeyShortcut {
519         .modifiers = modifiers,
520         .finalKey = key.finalKey,
521         .triggerType = SHORTCUT_TRIGGER_TYPE_DOWN,
522         .session = key.session,
523         .callback = key.callback,
524     };
525     return true;
526 }
527 
HaveRegisteredGlobalKey(const KeyShortcut &key) const528 bool KeyShortcutManager::HaveRegisteredGlobalKey(const KeyShortcut &key) const
529 {
530     auto iter = std::find_if(shortcuts_.cbegin(), shortcuts_.cend(),
531         [&key](const auto &item) {
532             return ((item.second.modifiers == key.modifiers) &&
533                     (item.second.finalKey == key.finalKey));
534         });
535     // We met the problem: key-shortcut does not differentiate left/right CTRL/SHIFT/ALT/LOGO.
536     // but the implementation of key-shortcut reuse the logic of key-subscription, which
537     // treat left/right CTRL/SHIFT/ALT/LOGO as different keys. That means, for 'CTRL+A' etc
538     // to work as expected, we have to subscribe both 'LEFT-CTRL+A' and 'RIGHT-CTRL+A'.
539     // But duplicate global key registration will fail according to key-shortcut rules.
540     // We relax this retriction here to allow duplicate global key registration from same application.
541     return (iter != shortcuts_.cend() ? (iter->second.session != key.session) : false);
542 }
543 
FormatPressedKeys(std::shared_ptr<KeyEvent> keyEvent) const544 std::string KeyShortcutManager::FormatPressedKeys(std::shared_ptr<KeyEvent> keyEvent) const
545 {
546     auto pressedKeys = keyEvent->GetPressedKeys();
547     std::ostringstream sPressedKeys;
548     size_t nPressedKeys = 0;
549 
550     if (auto iter = pressedKeys.cbegin(); iter != pressedKeys.cend()) {
551         sPressedKeys << *iter;
552         ++nPressedKeys;
553 
554         for (++iter; iter != pressedKeys.cend(); ++iter) {
555             if (nPressedKeys > MAX_N_PRINTABLE_ITEMS) {
556                 sPressedKeys << ",...";
557                 break;
558             }
559             sPressedKeys << "," << *iter;
560             ++nPressedKeys;
561         }
562     }
563     return sPressedKeys.str();
564 }
565 
GetForegroundPids() const566 std::set<int32_t> KeyShortcutManager::GetForegroundPids() const
567 {
568     std::vector<AppExecFwk::AppStateData> foregroundApps = APP_OBSERVER_MGR->GetForegroundAppData();
569     std::set<int32_t> foregroundPids;
570 
571     for (auto &item : foregroundApps) {
572         foregroundPids.insert(item.pid);
573     }
574     std::set<int32_t> tForegroundPids;
575 
576     for (const auto &shortcut : shortcuts_) {
577         if (foregroundPids.find(shortcut.second.session) != foregroundPids.cend()) {
578             tForegroundPids.insert(shortcut.second.session);
579         }
580     }
581     std::ostringstream sPids;
582 
583     if (auto iter = tForegroundPids.cbegin(); iter != tForegroundPids.cend()) {
584         sPids << *iter;
585         for (++iter; iter != tForegroundPids.cend(); ++iter) {
586             sPids << "," << *iter;
587         }
588     }
589     MMI_HILOGI("Foreground pids: [%{public}s]", sPids.str().c_str());
590     return tForegroundPids;
591 }
592 
HandleKeyDown(std::shared_ptr<KeyEvent> keyEvent)593 bool KeyShortcutManager::HandleKeyDown(std::shared_ptr<KeyEvent> keyEvent)
594 {
595     bool handled = false;
596     std::set<int32_t> foregroundPids = GetForegroundPids();
597 
598     for (auto &item : shortcuts_) {
599         KeyShortcut &shortcut = item.second;
600         if (shortcut.triggerType != SHORTCUT_TRIGGER_TYPE_DOWN) {
601             continue;
602         }
603         if (!foregroundPids.empty() &&
604             (foregroundPids.find(shortcut.session) == foregroundPids.cend())) {
605             continue;
606         }
607         if (!CheckCombination(keyEvent, shortcut)) {
608             continue;
609         }
610         MMI_HILOGI("Matched shortcut[No.%{public}d]"
611             "(0x%{public}x,%{public}d,%{public}d,%{public}d,SESSION:%{public}d)",
612             item.first, shortcut.modifiers, shortcut.finalKey, shortcut.longPressTime,
613             shortcut.triggerType, shortcut.session);
614         TriggerDown(keyEvent, item.first, shortcut);
615         handled = true;
616     }
617     return handled;
618 }
619 
HandleKeyUp(std::shared_ptr<KeyEvent> keyEvent)620 bool KeyShortcutManager::HandleKeyUp(std::shared_ptr<KeyEvent> keyEvent)
621 {
622     bool handled = false;
623     std::set<int32_t> foregroundPids = GetForegroundPids();
624 
625     for (auto &item : shortcuts_) {
626         KeyShortcut &shortcut = item.second;
627         if (shortcut.triggerType != SHORTCUT_TRIGGER_TYPE_UP) {
628             continue;
629         }
630         if (!foregroundPids.empty() &&
631             (foregroundPids.find(shortcut.session) == foregroundPids.cend())) {
632             continue;
633         }
634         if (!CheckCombination(keyEvent, shortcut)) {
635             continue;
636         }
637         MMI_HILOGI("Matched shortcut(0x%{public}x,%{public}d,%{public}d,%{public}d,SESSION:%{public}d)",
638             shortcut.modifiers, shortcut.finalKey, shortcut.longPressTime, shortcut.triggerType, shortcut.session);
639         TriggerUp(keyEvent, item.first, shortcut);
640         handled = true;
641     }
642     return handled;
643 }
644 
HandleKeyCancel(std::shared_ptr<KeyEvent> keyEvent)645 bool KeyShortcutManager::HandleKeyCancel(std::shared_ptr<KeyEvent> keyEvent)
646 {
647     ResetAll();
648     return false;
649 }
650 
CheckCombination(std::shared_ptr<KeyEvent> keyEvent, const KeyShortcut &shortcut) const651 bool KeyShortcutManager::CheckCombination(std::shared_ptr<KeyEvent> keyEvent, const KeyShortcut &shortcut) const
652 {
653     return (((shortcut.finalKey == SHORTCUT_PURE_MODIFIERS) && CheckPureModifiers(keyEvent, shortcut)) ||
654             ((shortcut.finalKey == keyEvent->GetKeyCode()) && CheckModifiers(keyEvent, shortcut)));
655 }
656 
CheckPureModifiers(std::shared_ptr<KeyEvent> keyEvent, const KeyShortcut &shortcut) const657 bool KeyShortcutManager::CheckPureModifiers(std::shared_ptr<KeyEvent> keyEvent, const KeyShortcut &shortcut) const
658 {
659     auto iter = modifiers_.find(keyEvent->GetKeyCode());
660     if (iter == modifiers_.cend()) {
661         return false;
662     }
663     uint32_t modifiers = (shortcut.modifiers & ~iter->second);
664     auto pressedKeys = keyEvent->GetPressedKeys();
665 
666     for (auto keyCode : pressedKeys) {
667         if (auto iter = modifiers_.find(keyCode); iter != modifiers_.cend()) {
668             modifiers &= ~iter->second;
669         }
670     }
671     return (modifiers == 0U);
672 }
673 
CheckModifiers(std::shared_ptr<KeyEvent> keyEvent, const KeyShortcut &shortcut) const674 bool KeyShortcutManager::CheckModifiers(std::shared_ptr<KeyEvent> keyEvent, const KeyShortcut &shortcut) const
675 {
676     uint32_t modifiers = shortcut.modifiers;
677     auto pressedKeys = keyEvent->GetPressedKeys();
678 
679     for (auto keyCode : pressedKeys) {
680         if (auto iter = modifiers_.find(keyCode); iter != modifiers_.cend()) {
681             modifiers &= ~iter->second;
682         }
683     }
684     return (modifiers == 0U);
685 }
686 
TriggerDown( std::shared_ptr<KeyEvent> keyEvent, int32_t shortcutId, const KeyShortcut &shortcut)687 void KeyShortcutManager::TriggerDown(
688     std::shared_ptr<KeyEvent> keyEvent, int32_t shortcutId, const KeyShortcut &shortcut)
689 {
690     if (shortcut.longPressTime <= 0) {
691         MMI_HILOGI("Run shortcut[No.%{public}d]", shortcutId);
692         if (shortcut.callback != nullptr) {
693             shortcut.callback(keyEvent);
694         }
695     } else {
696         if (triggering_.find(shortcutId) != triggering_.cend()) {
697             MMI_HILOGI("Shortcut[No.%{public}d]"
698                 "(0x%{public}x,%{public}d,%{public}d,%{public}d,SESSION:%{public}d) is pending",
699                 shortcutId, shortcut.modifiers, shortcut.finalKey, shortcut.longPressTime,
700                 shortcut.triggerType, shortcut.session);
701             return;
702         }
703         auto timerId = TimerMgr->AddTimer(shortcut.longPressTime, REPEAT_ONCE,
704             [this, tKeyEvent = KeyEvent::Clone(keyEvent), shortcutId]() {
705                 triggering_.erase(shortcutId);
706                 RunShortcut(tKeyEvent, shortcutId);
707             });
708         if (timerId < 0) {
709             MMI_HILOGE("AddTimer fail");
710             return;
711         }
712         triggering_.emplace(shortcutId, timerId);
713     }
714 }
715 
RunShortcut(std::shared_ptr<KeyEvent> keyEvent, int32_t shortcutId)716 void KeyShortcutManager::RunShortcut(std::shared_ptr<KeyEvent> keyEvent, int32_t shortcutId)
717 {
718     if (auto iter = shortcuts_.find(shortcutId); iter != shortcuts_.end()) {
719         std::set<int32_t> foregroundPids = GetForegroundPids();
720         if (!foregroundPids.empty() &&
721             (foregroundPids.find(iter->second.session) == foregroundPids.cend())) {
722             MMI_HILOGI("Session(%{public}d) is not foreground, skip running shortcut[%{public}d]",
723                 iter->second.session, shortcutId);
724             return;
725         }
726         MMI_HILOGI("Run shortcut[No.%{public}d]", shortcutId);
727         if (iter->second.callback != nullptr) {
728             iter->second.callback(keyEvent);
729         }
730     }
731 }
732 
TriggerUp( std::shared_ptr<KeyEvent> keyEvent, int32_t shortcutId, const KeyShortcut &shortcut)733 void KeyShortcutManager::TriggerUp(
734     std::shared_ptr<KeyEvent> keyEvent, int32_t shortcutId, const KeyShortcut &shortcut)
735 {
736     if (shortcut.longPressTime > 0) {
737         std::optional<KeyEvent::KeyItem> keyItem = keyEvent->GetKeyItem();
738         if (!keyItem) {
739             MMI_HILOGE("Corrupted key event");
740             return;
741         }
742         auto upTime = keyEvent->GetActionTime();
743         auto downTime = keyItem->GetDownTime();
744         if (upTime - downTime < MS2US(shortcut.longPressTime)) {
745             MMI_HILOGE("upTime - downTime < duration");
746             return;
747         }
748     }
749     if (shortcut.callback != nullptr) {
750         shortcut.callback(keyEvent);
751     }
752 }
753 
ResetAll()754 void KeyShortcutManager::ResetAll()
755 {
756     for (auto &item : triggering_) {
757         TimerMgr->RemoveTimer(item.second);
758     }
759     triggering_.clear();
760 }
761 
ResetCheckState()762 void KeyShortcutManager::ResetCheckState()
763 {
764     isCheckShortcut_ = true;
765 }
766 
767 static const std::vector<int32_t> specialKeyCodes = {
768     KeyEvent::KEYCODE_ALT_LEFT,
769     KeyEvent::KEYCODE_ALT_RIGHT,
770     KeyEvent::KEYCODE_TAB,
771     KeyEvent::KEYCODE_VOLUME_UP,
772     KeyEvent::KEYCODE_VOLUME_DOWN,
773     KeyEvent::KEYCODE_POWER
774 };
775 
IsCheckUpShortcut(const std::shared_ptr<KeyEvent> &keyEvent)776 bool KeyShortcutManager::IsCheckUpShortcut(const std::shared_ptr<KeyEvent> &keyEvent)
777 {
778     auto it = std::find(specialKeyCodes.begin(), specialKeyCodes.end(), keyEvent->GetKeyCode());
779     if (it != specialKeyCodes.end() && keyEvent->GetKeyAction() == KeyEvent::KEY_ACTION_UP) {
780         return true;
781     }
782     if (isCheckShortcut_) {
783         isCheckShortcut_ = false;
784         return true;
785     }
786     return false;
787 }
788 
GetAllSystemHotkeys(std::vector<std::unique_ptr<KeyOption>> &sysKeys)789 int32_t KeyShortcutManager::GetAllSystemHotkeys(std::vector<std::unique_ptr<KeyOption>> &sysKeys)
790 {
791     CALL_DEBUG_ENTER;
792     for (const auto &item : hotkeys_) {
793         std::unique_ptr<KeyOption> keyOptionPtr = std::make_unique<KeyOption>();
794         keyOptionPtr->SetPreKeys(item.preKeys);
795         keyOptionPtr->SetFinalKey(item.finalKey);
796         sysKeys.push_back(std::move(keyOptionPtr));
797     }
798     return RET_OK;
799 }
800 
HaveShortcutConsumed(std::shared_ptr<KeyEvent> keyEvent)801 bool KeyShortcutManager::HaveShortcutConsumed(std::shared_ptr<KeyEvent> keyEvent)
802 {
803     auto it = std::find(specialKeyCodes.begin(), specialKeyCodes.end(), keyEvent->GetKeyCode());
804     if (it != specialKeyCodes.end() && keyEvent->GetKeyAction() == KeyEvent::KEY_ACTION_UP) {
805         return false;
806     }
807     return (shortcutConsumed_.find(keyEvent->GetKeyCode()) != shortcutConsumed_.cend());
808 }
809 
UpdateShortcutConsumed(std::shared_ptr<KeyEvent> keyEvent)810 void KeyShortcutManager::UpdateShortcutConsumed(std::shared_ptr<KeyEvent> keyEvent)
811 {
812     if (keyEvent->GetKeyAction() == KeyEvent::KEY_ACTION_UP) {
813         shortcutConsumed_.erase(keyEvent->GetKeyCode());
814     }
815 }
816 
MarkShortcutConsumed(const ShortcutKey &shortcut)817 void KeyShortcutManager::MarkShortcutConsumed(const ShortcutKey &shortcut)
818 {
819     std::for_each(shortcut.preKeys.cbegin(), shortcut.preKeys.cend(),
820         [this](auto keyCode) {
821             shortcutConsumed_.emplace(keyCode);
822         });
823     if (shortcut.triggerType == KeyEvent::KEY_ACTION_DOWN) {
824         shortcutConsumed_.emplace(shortcut.finalKey);
825     }
826     isCheckShortcut_ = false;
827 }
828 
MarkShortcutConsumed(const KeyOption &shortcut)829 void KeyShortcutManager::MarkShortcutConsumed(const KeyOption &shortcut)
830 {
831     auto preKeys = shortcut.GetPreKeys();
832 
833     std::for_each(preKeys.cbegin(), preKeys.cend(),
834         [this](auto keyCode) {
835             shortcutConsumed_.emplace(keyCode);
836         });
837     if (shortcut.IsFinalKeyDown()) {
838         shortcutConsumed_.emplace(shortcut.GetFinalKey());
839     }
840     shortcutConsumed_.erase(KeyEvent::KEYCODE_VOLUME_UP);
841     shortcutConsumed_.erase(KeyEvent::KEYCODE_VOLUME_DOWN);
842     shortcutConsumed_.erase(KeyEvent::KEYCODE_POWER);
843     isCheckShortcut_ = false;
844 }
845 
ResetTriggering(std::shared_ptr<KeyEvent> keyEvent)846 void KeyShortcutManager::ResetTriggering(std::shared_ptr<KeyEvent> keyEvent)
847 {
848     if (keyEvent->GetKeyAction() == KeyEvent::KEY_ACTION_DOWN) {
849         for (auto iter = triggering_.cbegin(); iter != triggering_.cend();) {
850             auto shortcutIter = shortcuts_.find(iter->first);
851             if ((shortcutIter != shortcuts_.cend()) &&
852                 WillResetOnKeyDown(keyEvent->GetKeyCode(), shortcutIter->second)) {
853                 MMI_HILOGI("Reset triggering shortcut[%{public}d]", iter->first);
854                 TimerMgr->RemoveTimer(iter->second);
855                 iter = triggering_.erase(iter);
856             } else {
857                 ++iter;
858             }
859         }
860     } else {
861         for (auto iter = triggering_.cbegin(); iter != triggering_.cend();) {
862             auto shortcutIter = shortcuts_.find(iter->first);
863             if ((shortcutIter != shortcuts_.cend()) &&
864                 WillResetOnKeyUp(keyEvent->GetKeyCode(), shortcutIter->second)) {
865                 MMI_HILOGI("Reset triggering shortcut[%{public}d]", iter->first);
866                 TimerMgr->RemoveTimer(iter->second);
867                 iter = triggering_.erase(iter);
868             } else {
869                 ++iter;
870             }
871         }
872     }
873 }
874 
WillResetOnKeyDown(int32_t keyCode, const KeyShortcut &shortcut) const875 bool KeyShortcutManager::WillResetOnKeyDown(int32_t keyCode, const KeyShortcut &shortcut) const
876 {
877     if (keyCode == shortcut.finalKey) {
878         return false;
879     }
880     auto modIter = modifiers_.find(keyCode);
881     return ((modIter == modifiers_.cend()) || ((modIter->second & shortcut.modifiers) == 0U));
882 }
883 
WillResetOnKeyUp(int32_t keyCode, const KeyShortcut &shortcut) const884 bool KeyShortcutManager::WillResetOnKeyUp(int32_t keyCode, const KeyShortcut &shortcut) const
885 {
886     if (keyCode == shortcut.finalKey) {
887         return true;
888     }
889     auto modIter = modifiers_.find(keyCode);
890     return ((modIter != modifiers_.cend()) && ((modIter->second & shortcut.modifiers) != 0U));
891 }
892 
ResetTriggering(int32_t shortcutId)893 void KeyShortcutManager::ResetTriggering(int32_t shortcutId)
894 {
895     if (auto iter = triggering_.find(shortcutId); iter != triggering_.cend()) {
896         TimerMgr->RemoveTimer(iter->second);
897         triggering_.erase(iter);
898     }
899 }
900 
LoadHotkeys()901 void KeyShortcutManager::LoadHotkeys()
902 {
903     char cfgName[] { "etc/multimodalinput/system_hotkeys_config.json" };
904     char buf[MAX_PATH_LEN] {};
905     char *cfgPath = ::GetOneCfgFile(cfgName, buf, sizeof(buf));
906 
907     if ((cfgPath == nullptr) || (cfgPath[0] == '\0') || (strlen(cfgPath) > MAX_PATH_LEN)) {
908         MMI_HILOGE("No '%{public}s' was found", cfgPath);
909         return;
910     }
911     MMI_HILOGI("Config of hotkey:%{public}s", cfgPath);
912     ReadHotkeys(std::string(cfgPath));
913 }
914 
ReadHotkeys(const std::string &cfgPath)915 void KeyShortcutManager::ReadHotkeys(const std::string &cfgPath)
916 {
917     std::string cfg = ReadJsonFile(cfgPath);
918     JsonParser parser;
919     parser.json_ = cJSON_Parse(cfg.c_str());
920     if (!cJSON_IsObject(parser.json_)) {
921         MMI_HILOGE("Not json format");
922         return;
923     }
924     cJSON* jsonHotkeys = cJSON_GetObjectItemCaseSensitive(parser.json_, "Hotkeys");
925     if (!cJSON_IsArray(jsonHotkeys)) {
926         MMI_HILOGE("JsonHotkeys is not array");
927         return;
928     }
929     int32_t nSysKeys = cJSON_GetArraySize(jsonHotkeys);
930     for (int32_t index = 0; index < nSysKeys; ++index) {
931         cJSON *jsonHotkey = cJSON_GetArrayItem(jsonHotkeys, index);
932         if (ReadHotkey(jsonHotkey) != RET_OK) {
933             MMI_HILOGE("Read hotkey failed");
934             return;
935         }
936     }
937 }
938 
ReadHotkey(cJSON *jsonHotkey)939 int32_t KeyShortcutManager::ReadHotkey(cJSON *jsonHotkey)
940 {
941     if (!cJSON_IsObject(jsonHotkey)) {
942         MMI_HILOGE("Not json object");
943         return RET_ERR;
944     }
945     cJSON *jsonPreKeys = cJSON_GetObjectItem(jsonHotkey, "preKeys");
946     if (!cJSON_IsArray(jsonPreKeys)) {
947         MMI_HILOGE("Expect array for PreKeys");
948         return RET_ERR;
949     }
950     std::set<int32_t> preKeys;
951     int32_t nPreKeys = cJSON_GetArraySize(jsonPreKeys);
952 
953     for (int32_t index = 0; index < nPreKeys; ++index) {
954         cJSON *jsonPreKey = cJSON_GetArrayItem(jsonPreKeys, index);
955         if (!cJSON_IsNumber(jsonPreKey)) {
956             MMI_HILOGE("Expect number for PreKey");
957             return RET_ERR;
958         }
959         preKeys.insert(static_cast<int32_t>(cJSON_GetNumberValue(jsonPreKey)));
960     }
961     cJSON *jsonFinalKey = cJSON_GetObjectItem(jsonHotkey, "finalKey");
962     if (!cJSON_IsNumber(jsonFinalKey)) {
963         MMI_HILOGE("Expect number for FinalKey");
964         return RET_ERR;
965     }
966     int32_t finalKey = static_cast<int32_t>(cJSON_GetNumberValue(jsonFinalKey));
967     return AddHotkey(preKeys, finalKey);
968 }
969 
AddHotkey(const std::set<int32_t> &preKeys, int32_t finalKey)970 int32_t KeyShortcutManager::AddHotkey(const std::set<int32_t> &preKeys, int32_t finalKey)
971 {
972     SystemHotkey hotkey {
973         .preKeys = preKeys,
974         .finalKey = finalKey,
975     };
976     for (const auto &item : hotkey.preKeys) {
977         if ((modifiers_.find(item) == modifiers_.cend()) && (item != KeyEvent::KEYCODE_SYSRQ)) {
978             MMI_HILOGE("Not hotkeys");
979             return RET_ERR;
980         }
981     }
982 
983     if (IsModifier(hotkey.finalKey)) {
984         MMI_HILOGE("FinalKey is modifier");
985         return RET_ERR;
986     }
987     hotkeys_.emplace(hotkey);
988     return RET_OK;
989 }
990 } // namespace MMI
991 } // namespace OHOS
992