Rewrite shortcuts using QAction.

That way they don't depend on the main window.
This commit is contained in:
John Preston 2023-01-18 11:58:57 +04:00
parent 5154fe0044
commit 3e332ad8e7
4 changed files with 49 additions and 41 deletions

View file

@ -183,9 +183,6 @@ Application::~Application() {
Local::writeSettings(); Local::writeSettings();
} }
// Depend on primaryWindow() for now :(
Shortcuts::Finish();
_closingAsyncWindows.clear(); _closingAsyncWindows.clear();
_secondaryWindows.clear(); _secondaryWindows.clear();
_primaryWindows.clear(); _primaryWindows.clear();
@ -261,6 +258,7 @@ void Application::run() {
Ui::StartCachedCorners(); Ui::StartCachedCorners();
Ui::Emoji::Init(); Ui::Emoji::Init();
Ui::PreloadTextSpoilerMask(); Ui::PreloadTextSpoilerMask();
startShortcuts();
startEmojiImageLoader(); startEmojiImageLoader();
startSystemDarkModeViewer(); startSystemDarkModeViewer();
Media::Player::start(_audio.get()); Media::Player::start(_audio.get());
@ -329,10 +327,7 @@ void Application::run() {
DEBUG_LOG(("Application Info: window created...")); DEBUG_LOG(("Application Info: window created..."));
// Depend on primaryWindow() for now :(
startShortcuts();
startDomain(); startDomain();
startTray(); startTray();
_lastActivePrimaryWindow->widget()->show(); _lastActivePrimaryWindow->widget()->show();
@ -567,7 +562,7 @@ bool Application::eventFilter(QObject *object, QEvent *e) {
const auto event = static_cast<QShortcutEvent*>(e); const auto event = static_cast<QShortcutEvent*>(e);
DEBUG_LOG(("Shortcut event caught: %1" DEBUG_LOG(("Shortcut event caught: %1"
).arg(event->key().toString())); ).arg(event->key().toString()));
if (Shortcuts::HandleEvent(event)) { if (Shortcuts::HandleEvent(object, event)) {
return true; return true;
} }
} break; } break;

View file

@ -16,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "platform/platform_specific.h" #include "platform/platform_specific.h"
#include "base/parse_helper.h" #include "base/parse_helper.h"
#include <QAction>
#include <QShortcut> #include <QShortcut>
#include <QtCore/QJsonDocument> #include <QtCore/QJsonDocument>
#include <QtCore/QJsonObject> #include <QtCore/QJsonObject>
@ -143,11 +144,13 @@ public:
void fill(); void fill();
void clear(); void clear();
[[nodiscard]] std::vector<Command> lookup(int shortcutId) const; [[nodiscard]] std::vector<Command> lookup(
not_null<QObject*> object) const;
void toggleMedia(bool toggled); void toggleMedia(bool toggled);
void toggleSupport(bool toggled); void toggleSupport(bool toggled);
void listen(not_null<QWidget*> widget);
const QStringList &errors() const; [[nodiscard]] const QStringList &errors() const;
private: private:
void fillDefaults(); void fillDefaults();
@ -156,15 +159,15 @@ private:
void set(const QString &keys, Command command, bool replace = false); void set(const QString &keys, Command command, bool replace = false);
void remove(const QString &keys); void remove(const QString &keys);
void unregister(base::unique_qptr<QShortcut> shortcut); void unregister(base::unique_qptr<QAction> shortcut);
QStringList _errors; QStringList _errors;
base::flat_map<QKeySequence, base::unique_qptr<QShortcut>> _shortcuts; base::flat_map<QKeySequence, base::unique_qptr<QAction>> _shortcuts;
base::flat_multi_map<int, Command> _commandByShortcutId; base::flat_multi_map<not_null<QObject*>, Command> _commandByObject;
base::flat_set<QShortcut*> _mediaShortcuts; base::flat_set<QAction*> _mediaShortcuts;
base::flat_set<QShortcut*> _supportShortcuts; base::flat_set<QAction*> _supportShortcuts;
}; };
@ -227,7 +230,7 @@ void Manager::fill() {
void Manager::clear() { void Manager::clear() {
_errors.clear(); _errors.clear();
_shortcuts.clear(); _shortcuts.clear();
_commandByShortcutId.clear(); _commandByObject.clear();
_mediaShortcuts.clear(); _mediaShortcuts.clear();
_supportShortcuts.clear(); _supportShortcuts.clear();
} }
@ -236,11 +239,11 @@ const QStringList &Manager::errors() const {
return _errors; return _errors;
} }
std::vector<Command> Manager::lookup(int shortcutId) const { std::vector<Command> Manager::lookup(not_null<QObject*> object) const {
auto result = std::vector<Command>(); auto result = std::vector<Command>();
auto i = _commandByShortcutId.findFirst(shortcutId); auto i = _commandByObject.findFirst(object);
const auto end = _commandByShortcutId.end(); const auto end = _commandByObject.end();
for (; i != end && (i->first == shortcutId); ++i) { for (; i != end && (i->first == object); ++i) {
result.push_back(i->second); result.push_back(i->second);
} }
return result; return result;
@ -258,6 +261,12 @@ void Manager::toggleSupport(bool toggled) {
} }
} }
void Manager::listen(not_null<QWidget*> widget) {
for (const auto &[keys, shortcut] : _shortcuts) {
widget->addAction(shortcut.get());
}
}
bool Manager::readCustomFile() { bool Manager::readCustomFile() {
// read custom shortcuts from file if it exists or write an empty custom shortcuts file // read custom shortcuts from file if it exists or write an empty custom shortcuts file
QFile file(CustomFilePath()); QFile file(CustomFilePath());
@ -412,10 +421,10 @@ void Manager::writeDefaultFile() {
shortcuts.push_back(version); shortcuts.push_back(version);
for (const auto &[sequence, shortcut] : _shortcuts) { for (const auto &[sequence, shortcut] : _shortcuts) {
const auto shortcutId = shortcut->id(); const auto object = shortcut.get();
auto i = _commandByShortcutId.findFirst(shortcutId); auto i = _commandByObject.findFirst(object);
const auto end = _commandByShortcutId.end(); const auto end = _commandByObject.end();
for (; i != end && i->first == shortcutId; ++i) { for (; i != end && i->first == object; ++i) {
const auto j = CommandNames.find(i->second); const auto j = CommandNames.find(i->second);
if (j != CommandNames.end()) { if (j != CommandNames.end()) {
QJsonObject entry; QJsonObject entry;
@ -441,12 +450,9 @@ void Manager::set(const QString &keys, Command command, bool replace) {
_errors.push_back(u"Could not derive key sequence '%1'!"_q.arg(keys)); _errors.push_back(u"Could not derive key sequence '%1'!"_q.arg(keys));
return; return;
} }
auto shortcut = base::make_unique_q<QShortcut>( auto shortcut = base::make_unique_q<QAction>();
result, shortcut->setShortcut(result);
Core::App().activePrimaryWindow()->widget().get(), // #TODO windows shortcut->setShortcutContext(Qt::ApplicationShortcut);
nullptr,
nullptr,
Qt::ApplicationShortcut);
if (!AutoRepeatCommands.contains(command)) { if (!AutoRepeatCommands.contains(command)) {
shortcut->setAutoRepeat(false); shortcut->setAutoRepeat(false);
} }
@ -455,20 +461,16 @@ void Manager::set(const QString &keys, Command command, bool replace) {
if (isMediaShortcut || isSupportShortcut) { if (isMediaShortcut || isSupportShortcut) {
shortcut->setEnabled(false); shortcut->setEnabled(false);
} }
auto id = shortcut->id(); auto object = shortcut.get();
auto i = _shortcuts.find(result); auto i = _shortcuts.find(result);
if (i == end(_shortcuts)) { if (i == end(_shortcuts)) {
i = _shortcuts.emplace(result, std::move(shortcut)).first; i = _shortcuts.emplace(result, std::move(shortcut)).first;
} else if (replace) { } else if (replace) {
unregister(std::exchange(i->second, std::move(shortcut))); unregister(std::exchange(i->second, std::move(shortcut)));
} else { } else {
id = i->second->id(); object = i->second.get();
} }
if (!id) { _commandByObject.emplace(object, command);
_errors.push_back(u"Could not create shortcut '%1'!"_q.arg(keys));
return;
}
_commandByShortcutId.emplace(id, command);
if (!shortcut && isMediaShortcut) { if (!shortcut && isMediaShortcut) {
_mediaShortcuts.emplace(i->second.get()); _mediaShortcuts.emplace(i->second.get());
} }
@ -494,9 +496,9 @@ void Manager::remove(const QString &keys) {
} }
} }
void Manager::unregister(base::unique_qptr<QShortcut> shortcut) { void Manager::unregister(base::unique_qptr<QAction> shortcut) {
if (shortcut) { if (shortcut) {
_commandByShortcutId.erase(shortcut->id()); _commandByObject.erase(shortcut.get());
_mediaShortcuts.erase(shortcut.get()); _mediaShortcuts.erase(shortcut.get());
_supportShortcuts.erase(shortcut.get()); _supportShortcuts.erase(shortcut.get());
} }
@ -560,8 +562,10 @@ const QStringList &Errors() {
return Data.errors(); return Data.errors();
} }
bool HandleEvent(not_null<QShortcutEvent*> event) { bool HandleEvent(
return Launch(Data.lookup(event->shortcutId())); not_null<QObject*> object,
not_null<QShortcutEvent*> event) {
return Launch(Data.lookup(object));
} }
void ToggleMediaShortcuts(bool toggled) { void ToggleMediaShortcuts(bool toggled) {
@ -576,4 +580,8 @@ void Finish() {
Data.clear(); Data.clear();
} }
void Listen(not_null<QWidget*> widget) {
Data.listen(widget);
}
} // namespace Shortcuts } // namespace Shortcuts

View file

@ -100,8 +100,10 @@ rpl::producer<not_null<Request*>> Requests();
void Start(); void Start();
void Finish(); void Finish();
void Listen(not_null<QWidget*> widget);
bool Launch(Command command); bool Launch(Command command);
bool HandleEvent(not_null<QShortcutEvent*> event); bool HandleEvent(not_null<QObject*> object, not_null<QShortcutEvent*> event);
const QStringList &Errors(); const QStringList &Errors();

View file

@ -19,6 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "main/main_account.h" // Account::sessionValue. #include "main/main_account.h" // Account::sessionValue.
#include "core/application.h" #include "core/application.h"
#include "core/sandbox.h" #include "core/sandbox.h"
#include "core/shortcuts.h"
#include "lang/lang_keys.h" #include "lang/lang_keys.h"
#include "data/data_session.h" #include "data/data_session.h"
#include "data/data_forum_topic.h" #include "data/data_forum_topic.h"
@ -352,6 +353,8 @@ MainWindow::MainWindow(not_null<Controller*> controller)
updateControlsGeometry(); updateControlsGeometry();
}, _outdated->lifetime()); }, _outdated->lifetime());
} }
Shortcuts::Listen(this);
} }
Main::Account &MainWindow::account() const { Main::Account &MainWindow::account() const {