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