Lomiri
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 
24 namespace {
25 QWindow* 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 
38 GlobalShortcutRegistry::GlobalShortcutRegistry(QObject *parent)
39  : QObject(parent)
40 {
41  connect(qGuiApp, &QGuiApplication::focusWindowChanged, this, &GlobalShortcutRegistry::setupFilterOnWindow);
42  setupFilterOnWindow(qGuiApp->focusWindow());
43 }
44 
45 GlobalShortcutList GlobalShortcutRegistry::shortcuts() const
46 {
47  return m_shortcuts;
48 }
49 
50 bool 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 
70 void 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 
85 bool 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 }
GlobalShortcut
The GlobalShortcut class.
Definition: globalshortcut.h:33
GlobalShortcutRegistry::hasShortcut
bool hasShortcut(const QVariant &seq) const
Definition: globalshortcutregistry.cpp:50
GlobalShortcutRegistry::shortcuts
GlobalShortcutList shortcuts() const
Definition: globalshortcutregistry.cpp:45
GlobalShortcutRegistry::setupFilterOnWindow
void setupFilterOnWindow(QWindow *window)
Definition: globalshortcutregistry.cpp:123
GlobalShortcutRegistry::addShortcut
void addShortcut(const QVariant &seq, GlobalShortcut *sc)
Definition: globalshortcutregistry.cpp:55