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