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