Lomiri
Loading...
Searching...
No Matches
globalshortcutregistry.cpp
1/*
2 * Copyright (C) 2015 Canonical Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include <QDebug>
18#include <QGuiApplication>
19#include <QKeyEvent>
20#include <QKeySequence>
21
22#include "globalshortcutregistry.h"
23
24namespace {
25QWindow* windowForShortcut(GlobalShortcut *sc) {
26 QObject* parent= sc;
27 while(parent) {
28 if (auto item = qobject_cast<QQuickItem*>(parent)) {
29 auto window = item->window();
30 if (window) return window;
31 }
32 parent = parent->parent();
33 }
34 return nullptr;
35}
36} // namespace
37
38GlobalShortcutRegistry::GlobalShortcutRegistry(QObject *parent)
39 : QObject(parent)
40{
41 connect(qGuiApp, &QGuiApplication::focusWindowChanged, this, &GlobalShortcutRegistry::setupFilterOnWindow);
42 setupFilterOnWindow(qGuiApp->focusWindow());
43}
44
45GlobalShortcutList GlobalShortcutRegistry::shortcuts() const
46{
47 return m_shortcuts;
48}
49
50bool GlobalShortcutRegistry::hasShortcut(const QVariant &seq) const
51{
52 return m_shortcuts.contains(seq);
53}
54
56{
57 if (sc) {
58 if (!m_shortcuts.contains(seq)) { // create a new entry
59 m_shortcuts.insert(seq, {sc});
60 } else { // append to an existing one
61 auto shortcuts = m_shortcuts[seq];
62 shortcuts.append(sc);
63 m_shortcuts.insert(seq, shortcuts);
64 }
65
66 connect(sc, &GlobalShortcut::destroyed, this, &GlobalShortcutRegistry::removeShortcut);
67 }
68}
69
70void GlobalShortcutRegistry::removeShortcut(QObject *obj)
71{
72 QMutableMapIterator<QVariant, QVector<QPointer<GlobalShortcut>>> it(m_shortcuts);
73 while (it.hasNext()) {
74 it.next();
75 GlobalShortcut * scObj = static_cast<GlobalShortcut *>(obj);
76 if (scObj && it.value().contains(scObj)) {
77 it.value().removeAll(scObj);
78 if (it.value().isEmpty()) {
79 it.remove();
80 }
81 }
82 }
83}
84
85bool GlobalShortcutRegistry::eventFilter(QObject *obj, QEvent *event)
86{
87 Q_ASSERT(m_filteredWindow);
88 Q_ASSERT(obj == static_cast<QObject*>(m_filteredWindow.data()));
89
90 if (event->type() == QEvent::KeyPress || event->type() == QEvent::KeyRelease) {
91
92 QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
93
94 // Make a copy of the event so we don't alter it for passing on.
95 QKeyEvent eCopy(keyEvent->type(),
96 keyEvent->key(),
97 keyEvent->modifiers(),
98 keyEvent->text(),
99 keyEvent->isAutoRepeat(),
100 keyEvent->count());
101
102 int seq = keyEvent->key() + keyEvent->modifiers();
103 bool acceptedAtLeastOnce = false;
104 if (m_shortcuts.contains(seq)) {
105 const auto shortcuts = m_shortcuts.value(seq);
106 Q_FOREACH(const auto &shortcut, shortcuts) {
107 if (shortcut) {
108 auto window = windowForShortcut(shortcut);
109 if (!window || window == obj) { // accept shortcut if it's not attached to a window or it's window is active.
110 qApp->sendEvent(shortcut, &eCopy);
111 acceptedAtLeastOnce = acceptedAtLeastOnce || eCopy.isAccepted();
112 }
113 }
114 }
115 }
116
117 return acceptedAtLeastOnce;
118 }
119
120 return QObject::eventFilter(obj, event);
121}
122
124{
125 if (m_filteredWindow) {
126 m_filteredWindow->removeEventFilter(this);
127 m_filteredWindow.clear();
128 }
129
130 if (window) {
131 m_filteredWindow = window;
132 window->installEventFilter(this);
133 }
134}
The GlobalShortcut class.
bool hasShortcut(const QVariant &seq) const
void setupFilterOnWindow(QWindow *window)
void addShortcut(const QVariant &seq, GlobalShortcut *sc)
GlobalShortcutList shortcuts() const