diff --git a/src/ui/form/opt/pages/optionspage.cpp b/src/ui/form/opt/pages/optionspage.cpp index 017f65af..89092630 100644 --- a/src/ui/form/opt/pages/optionspage.cpp +++ b/src/ui/form/opt/pages/optionspage.cpp @@ -754,9 +754,8 @@ void OptionsPage::setupHotKeysBox() void OptionsPage::refreshEditShortcut() { const auto &key = HotKey::list[m_comboHotKey->currentIndex()]; - const auto &defaultValue = HotKey::defaultValue(key); - m_editShortcut->setKeySequence(iniUser()->hotKeyValue(key, defaultValue)); + m_editShortcut->setKeySequence(iniUser()->hotKeyValue(key)); } QLayout *OptionsPage::setupComboHotKeyLayout() diff --git a/src/ui/form/tray/trayicon.cpp b/src/ui/form/tray/trayicon.cpp index 2535745c..5958b495 100644 --- a/src/ui/form/tray/trayicon.cpp +++ b/src/ui/form/tray/trayicon.cpp @@ -27,6 +27,8 @@ namespace { +constexpr int MaxFKeyCount = 12; + const QString eventSingleClick = QStringLiteral("singleClick"); const QString eventCtrlSingleClick = QStringLiteral("ctrlSingleClick"); const QString eventAltSingleClick = QStringLiteral("altSingleClick"); @@ -279,8 +281,9 @@ void TrayIcon::updateTrayMenu(bool onlyFlags) updateTrayMenuFlags(); updateTrayIconShape(); - updateHotKeys(); updateClickActions(); + updateActionHotKeys(); + updateHotKeys(); } void TrayIcon::quitProgram() @@ -372,11 +375,11 @@ void TrayIcon::setupTrayMenu() m_homeAction = addAction( m_menu, ":/icons/fort.png", windowManager(), SLOT(showHomeWindow()), ActionShowHome); - addHotKey(m_homeAction, iniUser()->hotKeyValue(HotKey::home)); + addHotKey(m_homeAction, HotKey::home); m_programsAction = addAction(m_menu, ":/icons/application.png", windowManager(), SLOT(showProgramsWindow()), ActionShowPrograms); - addHotKey(m_programsAction, iniUser()->hotKeyValue(HotKey::programs)); + addHotKey(m_programsAction, HotKey::programs); m_programsOrAlertAction = addAction( m_menu, QString(), this, SLOT(showProgramsOrAlertWindow()), ActionShowProgramsOrAlert); @@ -387,27 +390,26 @@ void TrayIcon::setupTrayMenu() m_statisticsAction = addAction(m_menu, ":/icons/chart_bar.png", windowManager(), SLOT(showStatisticsWindow()), ActionShowStatistics); - addHotKey(m_statisticsAction, iniUser()->hotKeyValue(HotKey::statistics)); + addHotKey(m_statisticsAction, HotKey::statistics); m_graphAction = addAction(m_menu, ":/icons/action_log.png", windowManager(), SLOT(switchGraphWindow()), ActionShowTrafficGraph, /*checkable=*/true, windowManager()->isWindowOpen(WindowGraph)); - addHotKey(m_graphAction, iniUser()->hotKeyValue(HotKey::graph)); + addHotKey(m_graphAction, HotKey::graph); m_menu->addSeparator(); m_filterEnabledAction = addAction(m_menu, QString(), this, SLOT(switchTrayFlag(bool)), ActionSwitchFilterEnabled, /*checkable=*/true); - addHotKey( - m_filterEnabledAction, iniUser()->hotKeyValue(HotKey::filter, HotKey::Default::filter)); + addHotKey(m_filterEnabledAction, HotKey::filter); m_blockTrafficAction = addAction(m_menu, QString(), this, SLOT(switchTrayFlag(bool)), ActionSwitchBlockTraffic, /*checkable=*/true); - addHotKey(m_blockTrafficAction, iniUser()->hotKeyValue(HotKey::blockTraffic)); + addHotKey(m_blockTrafficAction, HotKey::blockTraffic); m_blockInetTrafficAction = addAction(m_menu, QString(), this, SLOT(switchTrayFlag(bool)), ActionSwitchBlockInetTraffic, /*checkable=*/true); - addHotKey(m_blockInetTrafficAction, iniUser()->hotKeyValue(HotKey::blockInetTraffic)); + addHotKey(m_blockInetTrafficAction, HotKey::blockInetTraffic); m_filterModeMenuAction = addAction( m_menu, QString(), this, SLOT(switchFilterModeMenu(bool)), ActionShowFilterModeMenu); @@ -418,19 +420,12 @@ void TrayIcon::setupTrayMenu() m_menu->addSeparator(); - const QString hotKeyAppGroupModifier = - iniUser()->hotKeyValue(HotKey::appGroupModifier, HotKey::Default::appGroupModifier) - + "+F"; - for (int i = 0; i < MAX_APP_GROUP_COUNT; ++i) { QAction *a = addAction(m_menu, QString(), this, SLOT(switchTrayFlag(bool)), ActionNone, /*checkable=*/true); - constexpr int maxFKeyCount = 12; - if (i < maxFKeyCount) { - const QString shortcutText = hotKeyAppGroupModifier + QString::number(i + 1); - - addHotKey(a, shortcutText); + if (i < MaxFKeyCount) { + addHotKey(a, HotKey::appGroupModifier); } m_appGroupActions.append(a); @@ -439,7 +434,7 @@ void TrayIcon::setupTrayMenu() m_menu->addSeparator(); m_quitAction = addAction(m_menu, ":/icons/standby.png", this, SLOT(quitProgram())); - addHotKey(m_quitAction, iniUser()->hotKeyValue(HotKey::quit)); + addHotKey(m_quitAction, HotKey::quit); m_trayMenuAction = addAction(m_menu, QString(), this, SLOT(switchTrayMenu(bool)), ActionShowTrayMenu); @@ -453,25 +448,25 @@ void TrayIcon::setupTrayMenuOptions() m_optionsAction = addAction(m_optionsMenu, ":/icons/cog.png", windowManager(), SLOT(showOptionsWindow())); - addHotKey(m_optionsAction, iniUser()->hotKeyValue(HotKey::options)); + addHotKey(m_optionsAction, HotKey::options); connect(m_optionsMenu, &ClickableMenu::clicked, m_optionsAction, &QAction::trigger); m_rulesAction = addAction( m_optionsMenu, ":/icons/script.png", windowManager(), SLOT(showRulesWindow())); - addHotKey(m_rulesAction, iniUser()->hotKeyValue(HotKey::rules)); + addHotKey(m_rulesAction, HotKey::rules); // TODO: Implement Rules m_rulesAction->setEnabled(false); m_zonesAction = addAction( m_optionsMenu, ":/icons/ip_class.png", windowManager(), SLOT(showZonesWindow())); - addHotKey(m_zonesAction, iniUser()->hotKeyValue(HotKey::zones)); + addHotKey(m_zonesAction, HotKey::zones); } void TrayIcon::setupTrayMenuFilterMode() { - static const char *const filterModeHotKeys[] = { + static const char *const filterModeIniKeys[] = { HotKey::filterModeAutoLearn, HotKey::filterModeAskToConnect, HotKey::filterModeBlock, @@ -487,13 +482,13 @@ void TrayIcon::setupTrayMenuFilterMode() const QStringList iconPaths = FirewallConf::filterModeIconPaths(); for (const QString &name : FirewallConf::filterModeNames()) { const QString iconPath = iconPaths.at(index); - const QString hotKey = filterModeHotKeys[index]; + const auto &iniKey = filterModeIniKeys[index]; QAction *a = addAction(m_filterModeMenu, iconPath, /*receiver=*/nullptr, /*member=*/nullptr, ActionNone, /*checkable=*/true); a->setText(name); - addHotKey(a, iniUser()->hotKeyValue(hotKey)); + addHotKey(a, iniKey); // TODO: Implement Ask to Connect a->setEnabled(index != 1); @@ -706,13 +701,31 @@ void TrayIcon::switchFilterMode(QAction *action) } } -void TrayIcon::addHotKey(QAction *action, const QString &shortcutText) +void TrayIcon::updateActionHotKeys() { - if (shortcutText.isEmpty()) - return; + int groupIndex = 0; + int index = 0; + for (auto action : hotKeyManager()->actions()) { + const auto &iniKey = m_actionIniKeys[index]; - const QKeySequence shortcut = QKeySequence::fromString(shortcutText); - hotKeyManager()->addAction(action, shortcut); + QString shortcutText = iniUser()->hotKeyValue(iniKey); + + if (iniKey == HotKey::appGroupModifier) { + shortcutText += "+F" + QString::number(++groupIndex); + } + + const QKeySequence shortcut = QKeySequence::fromString(shortcutText); + action->setShortcut(shortcut); + + ++index; + } +} + +void TrayIcon::addHotKey(QAction *action, const char *iniKey) +{ + hotKeyManager()->addAction(action); + + m_actionIniKeys.append(iniKey); } void TrayIcon::updateHotKeys() @@ -720,11 +733,6 @@ void TrayIcon::updateHotKeys() hotKeyManager()->initialize(iniUser()->hotKeyEnabled(), iniUser()->hotKeyGlobal()); } -void TrayIcon::removeHotKeys() -{ - hotKeyManager()->removeActions(); -} - TrayIcon::ActionType TrayIcon::clickEventActionType(IniUser *iniUser, ClickType clickType) { const QString eventName = clickNameByType(clickType); diff --git a/src/ui/form/tray/trayicon.h b/src/ui/form/tray/trayicon.h index 1d0a190b..21bf437b 100644 --- a/src/ui/form/tray/trayicon.h +++ b/src/ui/form/tray/trayicon.h @@ -115,9 +115,10 @@ private: void updateTrayIconShape(); - void addHotKey(QAction *action, const QString &shortcutText); + void updateActionHotKeys(); + + void addHotKey(QAction *action, const char *iniKey); void updateHotKeys(); - void removeHotKeys(); void updateClickActions(); @@ -145,9 +146,9 @@ private: ClickableMenu *m_optionsMenu = nullptr; QAction *m_optionsAction = nullptr; QAction *m_rulesAction = nullptr; + QAction *m_zonesAction = nullptr; QAction *m_statisticsAction = nullptr; QAction *m_graphAction = nullptr; - QAction *m_zonesAction = nullptr; QAction *m_filterEnabledAction = nullptr; QAction *m_blockTrafficAction = nullptr; QAction *m_blockInetTrafficAction = nullptr; @@ -157,6 +158,7 @@ private: QAction *m_quitAction = nullptr; QAction *m_trayMenuAction = nullptr; QList m_appGroupActions; + QVector m_actionIniKeys; QAction *m_clickActions[ClickTypeCount] = { nullptr }; diff --git a/src/ui/manager/hotkeymanager.cpp b/src/ui/manager/hotkeymanager.cpp index 8c5a1be3..8e295727 100644 --- a/src/ui/manager/hotkeymanager.cpp +++ b/src/ui/manager/hotkeymanager.cpp @@ -9,11 +9,22 @@ #include "nativeeventfilter.h" +namespace { + +QKeyCombination getActionKey(QAction *action) +{ + const QKeySequence keySequence = action->shortcut(); + + return keySequence.isEmpty() ? QKeyCombination() : keySequence[0]; +} + +} + HotKeyManager::HotKeyManager(QObject *parent) : QObject(parent) { } void HotKeyManager::initialize(bool enabled, bool global) { - if (m_enabled == enabled && m_global == global) + if (m_enabled == enabled && m_global == global && !checkShortcutsChanged()) return; m_enabled = enabled; @@ -33,19 +44,16 @@ void HotKeyManager::setUp() void HotKeyManager::tearDown() { disconnect(IoC()); + + removeActions(); } -bool HotKeyManager::addAction(QAction *action, const QKeySequence &shortcut) +bool HotKeyManager::addAction(QAction *action) { - action->setText(action->text()); - - action->setShortcut(shortcut); action->setShortcutVisibleInContextMenu(false); - const int hotKeyId = m_actions.size(); - action->setData(hotKeyId); - m_actions.append(action); + m_keys.append(getActionKey(action)); return true; } @@ -55,6 +63,7 @@ void HotKeyManager::removeActions() IoC()->unregisterHotKeys(); m_actions.clear(); + m_keys.clear(); } void HotKeyManager::updateActions() @@ -63,36 +72,45 @@ void HotKeyManager::updateActions() eventFilter->unregisterHotKeys(); + int hotKeyId = 0; for (QAction *action : std::as_const(m_actions)) { action->setShortcutVisibleInContextMenu(enabled()); + + const auto key = getActionKey(action); + m_keys[hotKeyId] = key; + if (enabled() && global()) { - registerHotKey(eventFilter, action); + eventFilter->registerHotKey(hotKeyId, key); } + + ++hotKeyId; } } +bool HotKeyManager::checkShortcutsChanged() const +{ + int hotKeyId = 0; + for (QAction *action : std::as_const(m_actions)) { + const auto oldKey = getActionKey(action); + const auto key = m_keys[hotKeyId]; + + if (key != oldKey) + return true; + + ++hotKeyId; + } + + return false; +} + void HotKeyManager::onHotKeyPressed(int hotKeyId) { if (WindowManager::activateModalWidget()) return; - if (hotKeyId >= m_actions.size()) - return; - - QAction *action = m_actions.at(hotKeyId); - if (action->isEnabled()) { + QAction *action = m_actions.value(hotKeyId); + if (action && action->isEnabled()) { action->trigger(); OsUtil::beep(); } } - -void HotKeyManager::registerHotKey(NativeEventFilter *eventFilter, QAction *action) const -{ - const QKeySequence shortcut = action->shortcut(); - const int hotKeyId = action->data().toInt(); - - const auto keyCombination = shortcut[0]; - const int key = keyCombination.toCombined(); - - eventFilter->registerHotKey(hotKeyId, key); -} diff --git a/src/ui/manager/hotkeymanager.h b/src/ui/manager/hotkeymanager.h index 00c6f3a7..feb10b7e 100644 --- a/src/ui/manager/hotkeymanager.h +++ b/src/ui/manager/hotkeymanager.h @@ -18,12 +18,14 @@ public: bool enabled() const { return m_enabled; } bool global() const { return m_global; } + const QList &actions() const { return m_actions; } + void initialize(bool enabled, bool global); void setUp() override; void tearDown() override; - bool addAction(QAction *action, const QKeySequence &shortcut); + bool addAction(QAction *action); void removeActions(); @@ -33,13 +35,14 @@ private slots: private: void updateActions(); - void registerHotKey(NativeEventFilter *eventFilter, QAction *action) const; + bool checkShortcutsChanged() const; private: bool m_enabled = false; bool m_global = false; QList m_actions; + QVector m_keys; }; #endif // HOTKEYMANAGER_H diff --git a/src/ui/manager/nativeeventfilter.cpp b/src/ui/manager/nativeeventfilter.cpp index ae9ac475..93500533 100644 --- a/src/ui/manager/nativeeventfilter.cpp +++ b/src/ui/manager/nativeeventfilter.cpp @@ -126,7 +126,7 @@ bool NativeEventFilter::registerHotKey( return true; } -bool NativeEventFilter::registerHotKey(int hotKeyId, int key) +bool NativeEventFilter::registerHotKey(int hotKeyId, QKeyCombination key) { return registerHotKey(hotKeyId, Qt::Key(key & ~Qt::KeyboardModifierMask), Qt::KeyboardModifiers(key & Qt::KeyboardModifierMask)); diff --git a/src/ui/manager/nativeeventfilter.h b/src/ui/manager/nativeeventfilter.h index 79d34f98..ba7a3a42 100644 --- a/src/ui/manager/nativeeventfilter.h +++ b/src/ui/manager/nativeeventfilter.h @@ -20,7 +20,7 @@ public: bool nativeEventFilter(const QByteArray &eventType, void *message, qintptr *result) override; bool registerHotKey(int hotKeyId, Qt::Key keyCode, Qt::KeyboardModifiers modifiers); - bool registerHotKey(int hotKeyId, int key); + bool registerHotKey(int hotKeyId, QKeyCombination key); void unregisterHotKeys(); diff --git a/src/ui/user/iniuser.cpp b/src/ui/user/iniuser.cpp index 6fbaf642..e4429d69 100644 --- a/src/ui/user/iniuser.cpp +++ b/src/ui/user/iniuser.cpp @@ -39,6 +39,18 @@ const char *const defaultValue(const char *key) IniUser::IniUser(Settings *settings) : MapSettings(settings) { } +QString IniUser::hotKeyValue(const QString &key) const +{ + const auto &defaultValue = HotKey::defaultValue(key.toLatin1()); + + return valueText("hotKey/" + key, defaultValue); +} + +void IniUser::setHotKeyValue(const QString &key, const QString &v) +{ + setValue("hotKey/" + key, v); +} + void IniUser::saveDefaultIni() { setLanguage(defaultLanguage()); diff --git a/src/ui/user/iniuser.h b/src/ui/user/iniuser.h index 9fb7911b..2fe848e8 100644 --- a/src/ui/user/iniuser.h +++ b/src/ui/user/iniuser.h @@ -58,11 +58,8 @@ public: bool hotKeyGlobal() const { return valueBool("hotKey/global", true); } void setHotKeyGlobal(bool v) { setValue("hotKey/global", v, true); } - QString hotKeyValue(const QString &key, const QString &defaultValue = {}) const - { - return valueText("hotKey/" + key, defaultValue); - } - void setHotKeyValue(const QString &key, const QString &v) { setValue("hotKey/" + key, v); } + QString hotKeyValue(const QString &key) const; + void setHotKeyValue(const QString &key, const QString &v); bool splashWindowVisible() const { return valueBool("splashWindow/visible", true); } void setSplashWindowVisible(bool on) { setValue("splashWindow/visible", on, true); }