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