Changeset View
Changeset View
Standalone View
Standalone View
autotests/integration/no_global_shortcuts_test.cpp
- This file was added.
1 | /******************************************************************** | ||||
---|---|---|---|---|---|
2 | KWin - the KDE window manager | ||||
3 | This file is part of the KDE project. | ||||
4 | | ||||
5 | Copyright (C) 2018 Martin Flöser <mgraesslin@kde.org> | ||||
6 | | ||||
7 | This program is free software; you can redistribute it and/or modify | ||||
8 | it under the terms of the GNU General Public License as published by | ||||
9 | the Free Software Foundation; either version 2 of the License, or | ||||
10 | (at your option) any later version. | ||||
11 | | ||||
12 | This program is distributed in the hope that it will be useful, | ||||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
15 | GNU General Public License for more details. | ||||
16 | | ||||
17 | You should have received a copy of the GNU General Public License | ||||
18 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||
19 | *********************************************************************/ | ||||
20 | #include "kwin_wayland_test.h" | ||||
21 | #include "cursor.h" | ||||
22 | #include "input.h" | ||||
23 | #include "keyboard_input.h" | ||||
24 | #include "platform.h" | ||||
25 | #include "screenedge.h" | ||||
26 | #include "screens.h" | ||||
27 | #include "wayland_server.h" | ||||
28 | #include "workspace.h" | ||||
29 | | ||||
30 | #include <KConfigGroup> | ||||
31 | #include <KGlobalAccel> | ||||
32 | | ||||
33 | #include <QDBusConnection> | ||||
34 | | ||||
35 | #include <linux/input.h> | ||||
36 | | ||||
37 | using namespace KWin; | ||||
38 | using namespace KWayland::Client; | ||||
39 | | ||||
40 | static const QString s_socketName = QStringLiteral("wayland_test_kwin_no_global_shortcuts-0"); | ||||
41 | static const QString s_serviceName = QStringLiteral("org.kde.KWin.Test.ModifierOnlyShortcut"); | ||||
42 | static const QString s_path = QStringLiteral("/Test"); | ||||
43 | | ||||
44 | Q_DECLARE_METATYPE(KWin::ElectricBorder) | ||||
45 | | ||||
46 | /** | ||||
47 | * This test verifies the NoGlobalShortcuts initialization flag | ||||
48 | **/ | ||||
49 | class NoGlobalShortcutsTest : public QObject | ||||
50 | { | ||||
51 | Q_OBJECT | ||||
52 | private Q_SLOTS: | ||||
53 | void initTestCase(); | ||||
54 | void init(); | ||||
55 | void cleanup(); | ||||
56 | | ||||
57 | void testTrigger_data(); | ||||
58 | void testTrigger(); | ||||
59 | void testKGlobalAccel(); | ||||
60 | void testPointerShortcut(); | ||||
61 | void testAxisShortcut_data(); | ||||
62 | void testAxisShortcut(); | ||||
63 | void testScreenEdge(); | ||||
64 | }; | ||||
65 | | ||||
66 | class Target : public QObject | ||||
67 | { | ||||
68 | Q_OBJECT | ||||
69 | Q_CLASSINFO("D-Bus Interface", "org.kde.KWin.Test.ModifierOnlyShortcut") | ||||
70 | | ||||
71 | public: | ||||
72 | Target(); | ||||
73 | virtual ~Target(); | ||||
74 | | ||||
75 | public Q_SLOTS: | ||||
76 | Q_SCRIPTABLE void shortcut(); | ||||
77 | | ||||
78 | Q_SIGNALS: | ||||
79 | void shortcutTriggered(); | ||||
80 | }; | ||||
81 | | ||||
82 | Target::Target() | ||||
83 | : QObject() | ||||
84 | { | ||||
85 | QDBusConnection::sessionBus().registerService(s_serviceName); | ||||
86 | QDBusConnection::sessionBus().registerObject(s_path, s_serviceName, this, QDBusConnection::ExportScriptableSlots); | ||||
87 | } | ||||
88 | | ||||
89 | Target::~Target() | ||||
90 | { | ||||
91 | QDBusConnection::sessionBus().unregisterObject(s_path); | ||||
92 | QDBusConnection::sessionBus().unregisterService(s_serviceName); | ||||
93 | } | ||||
94 | | ||||
95 | void Target::shortcut() | ||||
96 | { | ||||
97 | emit shortcutTriggered(); | ||||
98 | } | ||||
99 | | ||||
100 | void NoGlobalShortcutsTest::initTestCase() | ||||
101 | { | ||||
102 | qRegisterMetaType<KWin::ElectricBorder>("ElectricBorder"); | ||||
103 | QSignalSpy workspaceCreatedSpy(kwinApp(), &Application::workspaceCreated); | ||||
104 | QVERIFY(workspaceCreatedSpy.isValid()); | ||||
105 | kwinApp()->platform()->setInitialWindowSize(QSize(1280, 1024)); | ||||
106 | QVERIFY(waylandServer()->init(s_socketName.toLocal8Bit(), KWin::WaylandServer::InitalizationFlag::NoGlobalShortcuts)); | ||||
107 | | ||||
108 | kwinApp()->setConfig(KSharedConfig::openConfig(QString(), KConfig::SimpleConfig)); | ||||
109 | qputenv("KWIN_XKB_DEFAULT_KEYMAP", "1"); | ||||
110 | qputenv("XKB_DEFAULT_RULES", "evdev"); | ||||
111 | | ||||
112 | kwinApp()->start(); | ||||
113 | QVERIFY(workspaceCreatedSpy.wait()); | ||||
114 | waylandServer()->initWorkspace(); | ||||
115 | } | ||||
116 | | ||||
117 | void NoGlobalShortcutsTest::init() | ||||
118 | { | ||||
119 | screens()->setCurrent(0); | ||||
120 | KWin::Cursor::setPos(QPoint(640, 512)); | ||||
121 | } | ||||
122 | | ||||
123 | void NoGlobalShortcutsTest::cleanup() | ||||
124 | { | ||||
125 | } | ||||
126 | | ||||
127 | void NoGlobalShortcutsTest::testTrigger_data() | ||||
128 | { | ||||
129 | QTest::addColumn<QStringList>("metaConfig"); | ||||
130 | QTest::addColumn<QStringList>("altConfig"); | ||||
131 | QTest::addColumn<QStringList>("controlConfig"); | ||||
132 | QTest::addColumn<QStringList>("shiftConfig"); | ||||
133 | QTest::addColumn<int>("modifier"); | ||||
134 | QTest::addColumn<QList<int>>("nonTriggeringMods"); | ||||
135 | | ||||
136 | const QStringList trigger = QStringList{s_serviceName, s_path, s_serviceName, QStringLiteral("shortcut")}; | ||||
137 | const QStringList e = QStringList(); | ||||
138 | | ||||
139 | QTest::newRow("leftMeta") << trigger << e << e << e << KEY_LEFTMETA << QList<int>{KEY_LEFTALT, KEY_RIGHTALT, KEY_LEFTCTRL, KEY_RIGHTCTRL, KEY_LEFTSHIFT, KEY_RIGHTSHIFT}; | ||||
140 | QTest::newRow("rightMeta") << trigger << e << e << e << KEY_RIGHTMETA << QList<int>{KEY_LEFTALT, KEY_RIGHTALT, KEY_LEFTCTRL, KEY_RIGHTCTRL, KEY_LEFTSHIFT, KEY_RIGHTSHIFT}; | ||||
141 | QTest::newRow("leftAlt") << e << trigger << e << e << KEY_LEFTALT << QList<int>{KEY_LEFTMETA, KEY_RIGHTMETA, KEY_LEFTCTRL, KEY_RIGHTCTRL, KEY_LEFTSHIFT, KEY_RIGHTSHIFT}; | ||||
142 | QTest::newRow("rightAlt") << e << trigger << e << e << KEY_RIGHTALT << QList<int>{KEY_LEFTMETA, KEY_RIGHTMETA, KEY_LEFTCTRL, KEY_RIGHTCTRL, KEY_LEFTSHIFT, KEY_RIGHTSHIFT}; | ||||
143 | QTest::newRow("leftControl") << e << e << trigger << e << KEY_LEFTCTRL << QList<int>{KEY_LEFTALT, KEY_RIGHTALT, KEY_LEFTMETA, KEY_RIGHTMETA, KEY_LEFTSHIFT, KEY_RIGHTSHIFT}; | ||||
144 | QTest::newRow("rightControl") << e << e << trigger << e << KEY_RIGHTCTRL << QList<int>{KEY_LEFTALT, KEY_RIGHTALT, KEY_LEFTMETA, KEY_RIGHTMETA, KEY_LEFTSHIFT, KEY_RIGHTSHIFT}; | ||||
145 | QTest::newRow("leftShift") << e << e << e << trigger << KEY_LEFTSHIFT << QList<int>{KEY_LEFTALT, KEY_RIGHTALT, KEY_LEFTCTRL, KEY_RIGHTCTRL, KEY_LEFTMETA, KEY_RIGHTMETA}; | ||||
146 | QTest::newRow("rightShift") << e << e << e << trigger <<KEY_RIGHTSHIFT << QList<int>{KEY_LEFTALT, KEY_RIGHTALT, KEY_LEFTCTRL, KEY_RIGHTCTRL, KEY_LEFTMETA, KEY_RIGHTMETA}; | ||||
147 | } | ||||
148 | | ||||
149 | void NoGlobalShortcutsTest::testTrigger() | ||||
150 | { | ||||
151 | // test based on ModifierOnlyShortcutTest::testTrigger | ||||
152 | Target target; | ||||
153 | QSignalSpy triggeredSpy(&target, &Target::shortcutTriggered); | ||||
154 | QVERIFY(triggeredSpy.isValid()); | ||||
155 | | ||||
156 | KConfigGroup group = kwinApp()->config()->group("ModifierOnlyShortcuts"); | ||||
157 | QFETCH(QStringList, metaConfig); | ||||
158 | QFETCH(QStringList, altConfig); | ||||
159 | QFETCH(QStringList, shiftConfig); | ||||
160 | QFETCH(QStringList, controlConfig); | ||||
161 | group.writeEntry("Meta", metaConfig); | ||||
162 | group.writeEntry("Alt", altConfig); | ||||
163 | group.writeEntry("Shift", shiftConfig); | ||||
164 | group.writeEntry("Control", controlConfig); | ||||
165 | group.sync(); | ||||
166 | workspace()->slotReconfigure(); | ||||
167 | | ||||
168 | // configured shortcut should trigger | ||||
169 | quint32 timestamp = 1; | ||||
170 | QFETCH(int, modifier); | ||||
171 | kwinApp()->platform()->keyboardKeyPressed(modifier, timestamp++); | ||||
172 | kwinApp()->platform()->keyboardKeyReleased(modifier, timestamp++); | ||||
173 | QCOMPARE(triggeredSpy.count(), 0); | ||||
174 | | ||||
175 | // the other shortcuts should not trigger | ||||
176 | QFETCH(QList<int>, nonTriggeringMods); | ||||
177 | for (auto it = nonTriggeringMods.constBegin(), end = nonTriggeringMods.constEnd(); it != end; it++) { | ||||
178 | kwinApp()->platform()->keyboardKeyPressed(*it, timestamp++); | ||||
179 | kwinApp()->platform()->keyboardKeyReleased(*it, timestamp++); | ||||
180 | QCOMPARE(triggeredSpy.count(), 0); | ||||
181 | } | ||||
182 | } | ||||
183 | | ||||
184 | void NoGlobalShortcutsTest::testKGlobalAccel() | ||||
185 | { | ||||
186 | QScopedPointer<QAction> action(new QAction(nullptr)); | ||||
187 | action->setProperty("componentName", QStringLiteral(KWIN_NAME)); | ||||
188 | action->setObjectName(QStringLiteral("globalshortcuts-test-meta-shift-w")); | ||||
189 | QSignalSpy triggeredSpy(action.data(), &QAction::triggered); | ||||
190 | QVERIFY(triggeredSpy.isValid()); | ||||
191 | KGlobalAccel::self()->setShortcut(action.data(), QList<QKeySequence>{Qt::META + Qt::SHIFT + Qt::Key_W}, KGlobalAccel::NoAutoloading); | ||||
192 | input()->registerShortcut(Qt::META + Qt::SHIFT + Qt::Key_W, action.data()); | ||||
193 | | ||||
194 | // press meta+shift+w | ||||
195 | quint32 timestamp = 0; | ||||
196 | kwinApp()->platform()->keyboardKeyPressed(KEY_LEFTMETA, timestamp++); | ||||
197 | QCOMPARE(input()->keyboardModifiers(), Qt::MetaModifier); | ||||
198 | kwinApp()->platform()->keyboardKeyPressed(KEY_LEFTSHIFT, timestamp++); | ||||
199 | QCOMPARE(input()->keyboardModifiers(), Qt::ShiftModifier | Qt::MetaModifier); | ||||
200 | kwinApp()->platform()->keyboardKeyPressed(KEY_W, timestamp++); | ||||
201 | kwinApp()->platform()->keyboardKeyReleased(KEY_W, timestamp++); | ||||
202 | | ||||
203 | // release meta+shift | ||||
204 | kwinApp()->platform()->keyboardKeyReleased(KEY_LEFTSHIFT, timestamp++); | ||||
205 | kwinApp()->platform()->keyboardKeyReleased(KEY_LEFTMETA, timestamp++); | ||||
206 | | ||||
207 | QVERIFY(!triggeredSpy.wait()); | ||||
208 | QCOMPARE(triggeredSpy.count(), 0); | ||||
209 | } | ||||
210 | | ||||
211 | void NoGlobalShortcutsTest::testPointerShortcut() | ||||
212 | { | ||||
213 | // based on LockScreenTest::testPointerShortcut | ||||
214 | QScopedPointer<QAction> action(new QAction(nullptr)); | ||||
215 | QSignalSpy actionSpy(action.data(), &QAction::triggered); | ||||
216 | QVERIFY(actionSpy.isValid()); | ||||
217 | input()->registerPointerShortcut(Qt::MetaModifier, Qt::LeftButton, action.data()); | ||||
218 | | ||||
219 | // try to trigger the shortcut | ||||
220 | quint32 timestamp = 1; | ||||
221 | kwinApp()->platform()->keyboardKeyPressed(KEY_LEFTMETA, timestamp++); | ||||
222 | kwinApp()->platform()->pointerButtonPressed(BTN_LEFT, timestamp++); | ||||
223 | QCoreApplication::instance()->processEvents(); | ||||
224 | QCOMPARE(actionSpy.count(), 0); | ||||
225 | kwinApp()->platform()->pointerButtonReleased(BTN_LEFT, timestamp++); | ||||
226 | kwinApp()->platform()->keyboardKeyReleased(KEY_LEFTMETA, timestamp++); | ||||
227 | QCoreApplication::instance()->processEvents(); | ||||
228 | QCOMPARE(actionSpy.count(), 0); | ||||
229 | } | ||||
230 | | ||||
231 | void NoGlobalShortcutsTest::testAxisShortcut_data() | ||||
232 | { | ||||
233 | QTest::addColumn<Qt::Orientation>("direction"); | ||||
234 | QTest::addColumn<int>("sign"); | ||||
235 | | ||||
236 | QTest::newRow("up") << Qt::Vertical << 1; | ||||
237 | QTest::newRow("down") << Qt::Vertical << -1; | ||||
238 | QTest::newRow("left") << Qt::Horizontal << 1; | ||||
239 | QTest::newRow("right") << Qt::Horizontal << -1; | ||||
240 | } | ||||
241 | | ||||
242 | void NoGlobalShortcutsTest::testAxisShortcut() | ||||
243 | { | ||||
244 | // based on LockScreenTest::testAxisShortcut | ||||
245 | QScopedPointer<QAction> action(new QAction(nullptr)); | ||||
246 | QSignalSpy actionSpy(action.data(), &QAction::triggered); | ||||
247 | QVERIFY(actionSpy.isValid()); | ||||
248 | QFETCH(Qt::Orientation, direction); | ||||
249 | QFETCH(int, sign); | ||||
250 | PointerAxisDirection axisDirection = PointerAxisUp; | ||||
251 | if (direction == Qt::Vertical) { | ||||
252 | axisDirection = sign > 0 ? PointerAxisUp : PointerAxisDown; | ||||
253 | } else { | ||||
254 | axisDirection = sign > 0 ? PointerAxisLeft : PointerAxisRight; | ||||
255 | } | ||||
256 | input()->registerAxisShortcut(Qt::MetaModifier, axisDirection, action.data()); | ||||
257 | | ||||
258 | // try to trigger the shortcut | ||||
259 | quint32 timestamp = 1; | ||||
260 | kwinApp()->platform()->keyboardKeyPressed(KEY_LEFTMETA, timestamp++); | ||||
261 | if (direction == Qt::Vertical) | ||||
262 | kwinApp()->platform()->pointerAxisVertical(sign * 5.0, timestamp++); | ||||
263 | else | ||||
264 | kwinApp()->platform()->pointerAxisHorizontal(sign * 5.0, timestamp++); | ||||
265 | QCoreApplication::instance()->processEvents(); | ||||
266 | QCOMPARE(actionSpy.count(), 0); | ||||
267 | kwinApp()->platform()->keyboardKeyReleased(KEY_LEFTMETA, timestamp++); | ||||
268 | QCoreApplication::instance()->processEvents(); | ||||
269 | QCOMPARE(actionSpy.count(), 0); | ||||
270 | } | ||||
271 | | ||||
272 | void NoGlobalShortcutsTest::testScreenEdge() | ||||
273 | { | ||||
274 | // based on LockScreenTest::testScreenEdge | ||||
275 | QSignalSpy screenEdgeSpy(ScreenEdges::self(), &ScreenEdges::approaching); | ||||
276 | QVERIFY(screenEdgeSpy.isValid()); | ||||
277 | QCOMPARE(screenEdgeSpy.count(), 0); | ||||
278 | | ||||
279 | quint32 timestamp = 1; | ||||
280 | kwinApp()->platform()->pointerMotion({5, 5}, timestamp++); | ||||
281 | QCOMPARE(screenEdgeSpy.count(), 0); | ||||
282 | } | ||||
283 | | ||||
284 | WAYLANDTEST_MAIN(NoGlobalShortcutsTest) | ||||
285 | #include "no_global_shortcuts_test.moc" |