KeyboardShortcutManager.cpp 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. // include required headers
  9. #include "KeyboardShortcutManager.h"
  10. #include <AzCore/std/algorithm.h>
  11. #include <AzCore/std/string/string_view.h>
  12. #include <AzCore/Casting/numeric_cast.h>
  13. #include <MCore/Source/LogManager.h>
  14. #include <MCore/Source/IDGenerator.h>
  15. #include <QtCore/QStringList>
  16. #include <QtCore/QSettings>
  17. #include <QtGui/QKeyEvent>
  18. namespace MysticQt
  19. {
  20. void KeyboardShortcutManager::Group::RemoveAction(QAction* qaction, bool local)
  21. {
  22. m_actions.erase(AZStd::find_if(begin(m_actions), end(m_actions), [&qaction, local](const AZStd::unique_ptr<Action>& action)
  23. {
  24. return action->m_local == local && action->m_qaction == qaction;
  25. }));
  26. }
  27. KeyboardShortcutManager::Action* KeyboardShortcutManager::Group::FindActionByName(const QString& actionName, bool local) const
  28. {
  29. const auto found = AZStd::find_if(begin(m_actions), end(m_actions), [&actionName, local](const AZStd::unique_ptr<Action>& action)
  30. {
  31. return action->m_local == local && action->m_qaction->text() == actionName;
  32. });
  33. return found != end(m_actions) ? found->get() : nullptr;
  34. }
  35. void KeyboardShortcutManager::RegisterKeyboardShortcut(QAction* qaction, AZStd::string_view groupName, bool local)
  36. {
  37. // find the group with the given name
  38. Group* group = FindGroupByName(groupName);
  39. // if there is no group with the given name, create it
  40. if (group == nullptr)
  41. {
  42. m_groups.emplace_back(AZStd::make_unique<Group>(groupName));
  43. group = m_groups.back().get();
  44. }
  45. // check if the action is already there to avoid adding it twice
  46. Action* action = group->FindActionByName(qaction->text(), local);
  47. if (action)
  48. {
  49. action->m_defaultKeySequence = qaction->shortcut();
  50. return;
  51. }
  52. // create the new action and add it to the group
  53. group->AddAction(AZStd::make_unique<Action>(qaction, local));
  54. QAction::connect(qaction, &QAction::destroyed, this, [this, groupName = AZStd::string(groupName), local](QObject* qaction)
  55. {
  56. UnregisterKeyboardShortcut(static_cast<QAction*>(qaction), groupName, local);
  57. });
  58. }
  59. void KeyboardShortcutManager::UnregisterKeyboardShortcut(QAction* qaction, AZStd::string_view groupName, bool local)
  60. {
  61. Group* group = FindGroupByName(groupName);
  62. if (!group)
  63. {
  64. return;
  65. }
  66. group->RemoveAction(qaction, local);
  67. }
  68. // find the action with the given name in the given group
  69. KeyboardShortcutManager::Action* KeyboardShortcutManager::FindAction(const QString& actionName, AZStd::string_view groupName) const
  70. {
  71. const Group* group = FindGroupByName(groupName);
  72. if (!group)
  73. {
  74. return nullptr;
  75. }
  76. Action* action = group->FindActionByName(actionName, false);
  77. if (action)
  78. {
  79. return action;
  80. }
  81. return group->FindActionByName(actionName, true);
  82. }
  83. // find a group by name
  84. KeyboardShortcutManager::Group* KeyboardShortcutManager::FindGroupByName(AZStd::string_view groupName) const
  85. {
  86. const auto found = AZStd::find_if(begin(m_groups), end(m_groups), [&groupName](const AZStd::unique_ptr<Group>& group)
  87. {
  88. return group->GetName() == groupName;
  89. });
  90. return found != end(m_groups) ? found->get() : nullptr;
  91. }
  92. // find the correspondng group for the given action
  93. KeyboardShortcutManager::Group* KeyboardShortcutManager::FindGroupForShortcut(Action* action) const
  94. {
  95. const auto foundGroup = AZStd::find_if(begin(m_groups), end(m_groups), [action](const AZStd::unique_ptr<Group>& group)
  96. {
  97. const auto foundAction = AZStd::find_if(begin(group->GetActions()), end(group->GetActions()), [action](const AZStd::unique_ptr<Action>& actionInGroup)
  98. {
  99. return action == actionInGroup.get();
  100. });
  101. return foundAction != end(group->GetActions()) ? foundAction->get() : nullptr;
  102. });
  103. return foundGroup != end(m_groups) ? foundGroup->get() : nullptr;
  104. }
  105. KeyboardShortcutManager::Action* KeyboardShortcutManager::FindShortcut(QKeySequence keySequence, Group* group) const
  106. {
  107. const auto findMatchingAction = [keySequence] (const Group* group, const bool local)
  108. {
  109. return AZStd::find_if(begin(group->GetActions()), end(group->GetActions()), [keySequence, local] (const AZStd::unique_ptr<Action>& action)
  110. {
  111. if (action->m_local != local)
  112. {
  113. return false;
  114. }
  115. return action->m_qaction->shortcut().matches(keySequence) == QKeySequence::ExactMatch;
  116. });
  117. };
  118. // first check the global shortcuts
  119. const auto globalAction = findMatchingAction(group, false);
  120. if (globalAction != end(group->GetActions()))
  121. {
  122. return globalAction->get();
  123. }
  124. const auto localAction = findMatchingAction(group, true);
  125. if (localAction != end(group->GetActions()))
  126. {
  127. return localAction->get();
  128. }
  129. return nullptr;
  130. }
  131. void KeyboardShortcutManager::Save(QSettings* settings)
  132. {
  133. // clear the settings before saving new data
  134. settings->clear();
  135. // iterate through the groups and save all actions for them
  136. for (const AZStd::unique_ptr<Group>& group : m_groups)
  137. {
  138. settings->beginGroup(QString::fromUtf8(group->GetName().data(), aznumeric_caster(group->GetName().size())));
  139. // iterate through the actions and save them
  140. for (const AZStd::unique_ptr<Action>& action : group->GetActions())
  141. {
  142. settings->beginGroup(action->m_qaction->text());
  143. settings->setValue("Key", action->m_qaction->shortcut());
  144. settings->setValue("Local", action->m_local);
  145. settings->endGroup();
  146. }
  147. settings->endGroup();
  148. }
  149. }
  150. void KeyboardShortcutManager::Load(QSettings* settings)
  151. {
  152. // iterate through the groups and load all actions
  153. const QStringList groupNames = settings->childGroups();
  154. for (const QString& groupName : groupNames)
  155. {
  156. Group* group = FindGroupByName(FromQtString(groupName));
  157. if (!group)
  158. {
  159. continue;
  160. }
  161. settings->beginGroup(groupName);
  162. const QStringList actionNames = settings->childGroups();
  163. // iterate through the actions and save them
  164. for (const QString& actionName : actionNames)
  165. {
  166. settings->beginGroup(actionName);
  167. const bool local = settings->value("Local", false).toBool();
  168. Action* action = group->FindActionByName(actionName, local);
  169. if (!action)
  170. {
  171. continue;
  172. }
  173. const QVariant keyValue = settings->value("Key", "");
  174. if (keyValue.canConvert<QKeySequence>())
  175. {
  176. const QKeySequence key = keyValue.value<QKeySequence>();
  177. action->m_qaction->setShortcut(key);
  178. }
  179. else if (keyValue.canConvert<int>())
  180. {
  181. const int key = keyValue.value<int>();
  182. const bool ctrlModifier = settings->value("Ctrl", false).value<bool>();
  183. const bool altModifier = settings->value("Alt", false).value<bool>();
  184. action->m_qaction->setShortcut(key | (ctrlModifier ? Qt::ControlModifier : 0) | (altModifier ? Qt::AltModifier : 0));
  185. }
  186. settings->endGroup();
  187. }
  188. settings->endGroup();
  189. }
  190. }
  191. } // namespace MysticQt